diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 78ffce980..be5724c5d 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1539,6 +1539,8 @@ Warning.PARALLEL_FINS = Too many parallel fins Warning.SUPERSONIC = Body calculations may not be entirely accurate at supersonic speeds. Warning.RECOVERY_LAUNCH_ROD = Recovery device device deployed while on the launch guide. Warning.RECOVERY_HIGH_SPEED = Recovery device deployment at high speed +Warning.TUMBLE_UNDER_THRUST = Stage began to tumble under thrust. +Warning.TUMBLE_BEFORE_APOGEE = Sustainer became unstable before apogee. ! Scale dialog diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index 72df1ec49..44b0a3d85 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -325,4 +325,10 @@ public abstract class Warning { public static final Warning RECOVERY_LAUNCH_ROD = new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); + + public static final Warning TUMBLE_UNDER_THRUST = + new Other(trans.get("Warning.TUMBLE_UNDER_THRUST")); + + public static final Warning TUMBLE_BEFORE_APOGEE = + new Other(trans.get("Warning.TUMBLE_BEFORE_APOGEE")); } diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 22f7bcbb1..fb8d32020 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -42,10 +42,14 @@ public class BasicEventSimulationEngine implements SimulationEngine { private SimulationStepper landingStepper = new BasicLandingStepper(); private SimulationStepper tumbleStepper = new BasicTumbleStepper(); - // Constant holding 10 degress in radians. This is the AOA condition + // Constant holding 20 degress in radians. This is the AOA condition // necessary to transistion to tumbling. private final static double AOA_TUMBLE_CONDITION = Math.PI / 9.0; + // The thrust must be below this value for the transition to tumbling. + // TODO: this is an arbitrary value + private final static double THRUST_TUMBLE_CONDITION = 0.01; + private SimulationStepper currentStepper; private SimulationStatus status; @@ -202,18 +206,32 @@ public class BasicEventSimulationEngine implements SimulationEngine { // Check for Tumbling // Conditions for transision are: - // apogee reached + // apogee reached (if sustainer stage) // and is not already tumbling // and not stable (cg > cp) - // and aoa > 30 + // and aoa > AOA_TUMBLE_CONDITION threshold + // and thrust < THRUST_TUMBLE_CONDITION threshold - if (status.isApogeeReached() && !status.isTumbling()) { - double cp = status.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION); - double cg = status.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION); - double aoa = status.getFlightData().getLast(FlightDataType.TYPE_AOA); - if (cg > cp && aoa > AOA_TUMBLE_CONDITION) { - addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, status.getSimulationTime())); - status.setTumbling(true); + if (!status.isTumbling()) { + final double t = status.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE); + final double cp = status.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION); + final double cg = status.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION); + final double aoa = status.getFlightData().getLast(FlightDataType.TYPE_AOA); + + final boolean wantToTumble = (cg > cp && aoa > AOA_TUMBLE_CONDITION); + + if (wantToTumble) { + final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION; + final boolean isSustainer = status.getConfiguration().isStageActive(0); + final boolean notUntilApogee = isSustainer && !status.isApogeeReached(); + if (tooMuchThrust) { + status.getWarnings().add(Warning.TUMBLE_UNDER_THRUST); + } else if (notUntilApogee) { + status.getWarnings().add(Warning.TUMBLE_BEFORE_APOGEE); + } else { + addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, status.getSimulationTime())); + status.setTumbling(true); + } } } diff --git a/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java b/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java index dfb44a1ad..1993c5aaf 100644 --- a/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java +++ b/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java @@ -18,19 +18,21 @@ public class BasicTumbleStatus extends SimulationStatus { // offset the indexes so finEff[1] is the coefficient for one fin from the table in techdoc.pdf private final static double[] finEff = { 0.0, 0.5, 1.0, 1.41, 1.81, 1.73, 1.90, 1.85 }; - private double drag; + private final double drag; public BasicTumbleStatus(Configuration configuration, MotorInstanceConfiguration motorConfiguration, SimulationConditions simulationConditions) { super(configuration, motorConfiguration, simulationConditions); - computeTumbleDrag(); + this.drag = computeTumbleDrag(); } public BasicTumbleStatus(SimulationStatus orig) { super(orig); if (orig instanceof BasicTumbleStatus) { this.drag = ((BasicTumbleStatus) orig).drag; + } else { + this.drag = computeTumbleDrag(); } } @@ -39,7 +41,7 @@ public class BasicTumbleStatus extends SimulationStatus { } - public void computeTumbleDrag() { + private double computeTumbleDrag() { // Computed based on Sampo's experimentation as documented in the pdf. @@ -69,6 +71,6 @@ public class BasicTumbleStatus extends SimulationStatus { } } - drag = (cDFin * aFins + cDBt * aBt); + return (cDFin * aFins + cDBt * aBt); } } diff --git a/swing/src/net/sf/openrocket/gui/plot/EventGraphics.java b/swing/src/net/sf/openrocket/gui/plot/EventGraphics.java index 7a09ae910..3443e9be5 100644 --- a/swing/src/net/sf/openrocket/gui/plot/EventGraphics.java +++ b/swing/src/net/sf/openrocket/gui/plot/EventGraphics.java @@ -39,6 +39,7 @@ public class EventGraphics { EVENT_COLORS.put(FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, new Color(0, 0, 128)); EVENT_COLORS.put(FlightEvent.Type.GROUND_HIT, new Color(0, 0, 0)); EVENT_COLORS.put(FlightEvent.Type.SIMULATION_END, new Color(128, 0, 0)); + EVENT_COLORS.put(FlightEvent.Type.TUMBLE, new Color(196, 0, 255)); } private static final Map EVENT_IMAGES = new HashMap();