diff --git a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java index ca809dcbb..d11a9c788 100644 --- a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java +++ b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java @@ -79,7 +79,8 @@ public class BasicLandingStepper extends AbstractSimulationStepper { } // but don't let it get *too* small timeStep = Math.max(timeStep, MIN_TIME_STEP); - + log.debug("timeStep is " + timeStep); + // Perform Euler integration Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)). add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)); @@ -94,6 +95,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper { // The new timestep is the solution of // 1/2 at^2 + vt + z0 = 0 timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a; + log.debug("ground hit changes timeStep to " + timeStep); newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)). add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)); @@ -101,7 +103,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper { // avoid rounding error in new altitude newPosition = newPosition.setZ(0); } - + status.setSimulationTime(status.getSimulationTime() + timeStep); status.setPreviousTimeStep(timeStep); @@ -113,7 +115,6 @@ public class BasicLandingStepper extends AbstractSimulationStepper { WorldCoordinate w = status.getSimulationConditions().getLaunchSite(); w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition()); status.setRocketWorldPosition(w); - // Store data FlightDataBranch data = status.getFlightData(); diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java index fd8dc025e..bb1f11147 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java @@ -270,13 +270,15 @@ public class SimulationRunDialog extends JDialog { private final int index; private final double burnoutTimeEstimate; private volatile double burnoutVelocity; - private volatile double apogeeAltitude; private final CustomExpressionSimulationListener exprListener; /* - * -2 = time from 0 ... burnoutTimeEstimate -1 = velocity from - * v(burnoutTimeEstimate) ... 0 0 ... n = stages from alt(max) ... 0 + * Keep track of current phase ("stage") of simulation + * -2: Boost. Estimate progress using time from 0 to burnoutTimeEstimate + * -1: Coast. Estimate progress using velocity from v(burnoutTimeEstimate) to 0 + * 0 ... n: Landing. Estimate progress using altitude from alt(max) ... 0 + * (it appears as if the idea is to use values above 0 to support multiple stages, but this is not implemented) */ private volatile int simulationStage = -2; @@ -322,50 +324,57 @@ public class SimulationRunDialog extends JDialog { @Override protected void process(List chunks) { - // Update max. altitude and velocity + // Update max. altitude and velocity of sustainer. Because parts of the simulation may be run more than once + // in order to calculate things like optimal coast time, we'll keep updating max altitude + // whenever we see that the rocket is going upwards. The last apogee found is the real one. for (SimulationStatus s : chunks) { - simulationMaxAltitude[index] = Math.max(simulationMaxAltitude[index], s.getRocketPosition().z); - simulationMaxVelocity[index] = Math.max(simulationMaxVelocity[index], s.getRocketVelocity().length()); + if (s.getConfiguration().isStageActive(0) && (s.getRocketVelocity().z > 0)) { + log.debug("updating simulationMaxAltitude[" + index + "] to " + s.getRocketPosition().z); + simulationMaxAltitude[index] = s.getRocketPosition().z; + simulationMaxVelocity[index] = Math.max(simulationMaxVelocity[index], s.getRocketVelocity().length()); + } } // Calculate the progress SimulationStatus status = chunks.get(chunks.size() - 1); simulationStatuses[index] = status; - // 1. time = 0 ... burnoutTimeEstimate + // -2: Boost. time = 0 ... burnoutTimeEstimate if (simulationStage == -2 && status.getSimulationTime() < burnoutTimeEstimate) { - log.debug("Method 1: t=" + status.getSimulationTime() + " est=" + burnoutTimeEstimate); + log.debug("simulationStage boost: t=" + status.getSimulationTime() + " est=" + burnoutTimeEstimate); setSimulationProgress( MathUtil.map(status.getSimulationTime(), 0, burnoutTimeEstimate, 0.0, BURNOUT_PROGRESS)); updateProgress(); return; } + // Past burnout time estimate, switch to coast. if (simulationStage == -2) { simulationStage++; burnoutVelocity = MathUtil.max(status.getRocketVelocity().z, 0.1); - log.debug("CHANGING to Method 2, vel=" + burnoutVelocity); + log.debug("CHANGING to simulationStage " + simulationStage + ", vel=" + burnoutVelocity); } - // 2. z-velocity from burnout velocity to zero + // -1: Coast. z-velocity from burnout velocity to zero if (simulationStage == -1 && status.getRocketVelocity().z >= 0) { - log.debug("Method 2: vel=" + status.getRocketVelocity().z + " burnout=" + burnoutVelocity); + log.debug("simulationStage coast: vel=" + status.getRocketVelocity().z + " burnout=" + burnoutVelocity); setSimulationProgress(MathUtil.map(status.getRocketVelocity().z, burnoutVelocity, 0, BURNOUT_PROGRESS, APOGEE_PROGRESS)); updateProgress(); return; } + // Past apogee, switch to landing if (simulationStage == -1 && status.getRocketVelocity().z < 0) { simulationStage++; - apogeeAltitude = MathUtil.max(status.getRocketPosition().z, 1); - log.debug("CHANGING to Method 3, apogee=" + apogeeAltitude); + log.debug("CHANGING to simulationStage " + simulationStage + ", apogee=" + simulationMaxAltitude[index]); } - // 3. z-position from apogee to zero + // >= 0 Landing. z-position from apogee to zero // TODO: MEDIUM: several stages - log.debug("Method 3: alt=" + status.getRocketPosition().z + " apogee=" + apogeeAltitude); - setSimulationProgress(MathUtil.map(status.getRocketPosition().z, apogeeAltitude, 0, APOGEE_PROGRESS, 1.0)); + System.out.flush(); + log.debug("simulationStage landing (" + simulationStage + "): alt=" + status.getRocketPosition().z + " apogee=" + simulationMaxAltitude[index]); + setSimulationProgress(MathUtil.map(status.getRocketPosition().z, simulationMaxAltitude[index], 0, APOGEE_PROGRESS, 1.0)); updateProgress(); } @@ -439,10 +448,7 @@ public class SimulationRunDialog extends JDialog { public boolean handleFlightEvent(SimulationStatus status, FlightEvent event) { switch (event.getType()) { case APOGEE: - simulationStage = 0; - apogeeAltitude = status.getRocketPosition().z; - log.debug("APOGEE, setting progress"); - setSimulationProgress(APOGEE_PROGRESS); + log.debug("APOGEE"); publish(status); break; @@ -451,8 +457,8 @@ public class SimulationRunDialog extends JDialog { break; case SIMULATION_END: - log.debug("END, setting progress"); - setSimulationProgress(1.0); + log.debug("END"); + publish(status); break; default: