diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 69fdf3d3d..c17daff2d 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -173,7 +173,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { } else { // Check ground hit after liftoff - if ((currentStatus.getRocketPosition().z < 0) && !currentStatus.isLanded()) { + if ((currentStatus.getRocketPosition().z < MathUtil.EPSILON) && !currentStatus.isLanded()) { addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, currentStatus.getSimulationTime())); // addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime())); diff --git a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java index a111d1227..f6fe081a0 100644 --- a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java +++ b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java @@ -8,7 +8,11 @@ import net.sf.openrocket.util.GeodeticComputationStrategy; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.WorldCoordinate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class BasicLandingStepper extends AbstractSimulationStepper { + private static final Logger log = LoggerFactory.getLogger(BasicLandingStepper.class); private static final double RECOVERY_TIME_STEP = 0.5; @@ -65,13 +69,35 @@ public class BasicLandingStepper extends AbstractSimulationStepper { - // Select time step + // Select tentative time step double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP); // Perform Euler integration - status.setRocketPosition(status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)). - add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2))); + Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)). + add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)); + + // If I've hit the ground, recalculate time step and position + if (newPosition.z < 0) { + + final double a = linearAcceleration.z; + final double v = status.getRocketVelocity().z; + final double z0 = status.getRocketPosition().z; + + // The new timestep is the solution of + // 1/2 at^2 + vt + z0 = 0 + timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a; + + newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)). + add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)); + + // avoid rounding error in new altitude + newPosition = newPosition.setZ(0); + } + + status.setRocketPosition(newPosition); + status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep))); + airSpeed = status.getRocketVelocity().add(windSpeed); status.setSimulationTime(status.getSimulationTime() + timeStep); @@ -139,6 +165,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper { data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep); data.setValue(FlightDataType.TYPE_COMPUTATION_TIME, (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0); + log.debug("time " + data.getLast(FlightDataType.TYPE_TIME) + ", altitude " + data.getLast(FlightDataType.TYPE_ALTITUDE) + ", velocity " + data.getLast(FlightDataType.TYPE_VELOCITY_Z)); } } diff --git a/core/src/net/sf/openrocket/simulation/GroundStepper.java b/core/src/net/sf/openrocket/simulation/GroundStepper.java index db9ea466d..49c8b5b4f 100644 --- a/core/src/net/sf/openrocket/simulation/GroundStepper.java +++ b/core/src/net/sf/openrocket/simulation/GroundStepper.java @@ -20,70 +20,5 @@ public class GroundStepper extends AbstractSimulationStepper { @Override public void step(SimulationStatus status, double timeStep) throws SimulationException { log.trace("step: position=" + status.getRocketPosition() + ", velocity=" + status.getRocketVelocity()); - - status.setRocketVelocity(Coordinate.ZERO); - status.setRocketRotationVelocity(Coordinate.ZERO); - status.setRocketPosition(status.getRocketPosition().setZ(0)); - - // Store data - FlightDataBranch data = status.getFlightData(); - boolean extra = status.getSimulationConditions().isCalculateExtras(); - data.addPoint(); - - data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime()); - data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z); - data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x); - data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y); - if (extra) { - data.setValue(FlightDataType.TYPE_POSITION_XY, - MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y)); - data.setValue(FlightDataType.TYPE_POSITION_DIRECTION, - Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x)); - - data.setValue(FlightDataType.TYPE_VELOCITY_XY, - MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y)); - data.setValue(FlightDataType.TYPE_ACCELERATION_XY, 0.0); - - data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, 0.0); - - data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Double.POSITIVE_INFINITY); - } - - data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad()); - data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad()); - data.setValue(FlightDataType.TYPE_GRAVITY, modelGravity(status)); - - data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, 0.0); - - data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z); - data.setValue(FlightDataType.TYPE_ACCELERATION_Z, 0.0); - - data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, 0.0); - data.setValue(FlightDataType.TYPE_MACH_NUMBER, 0.0); - - - // Calculate mass data - double rocketMass = calculateStructureMass(status).getMass(); - double motorMass = calculateMotorMass(status).getMass(); - - double mass = rocketMass + motorMass; - data.setValue(FlightDataType.TYPE_MASS, mass); - data.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass); - - data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0.0); - data.setValue(FlightDataType.TYPE_DRAG_FORCE, 0.0); - - data.setValue(FlightDataType.TYPE_WIND_VELOCITY, modelWindVelocity(status).length()); - - AtmosphericConditions atmosphere = modelAtmosphericConditions(status); - data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature()); - data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure()); - data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed()); - - data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep); - data.setValue(FlightDataType.TYPE_COMPUTATION_TIME, - (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0); - - status.setSimulationTime(status.getSimulationTime() + timeStep); } } diff --git a/core/src/net/sf/openrocket/util/MathUtil.java b/core/src/net/sf/openrocket/util/MathUtil.java index e1ae86c12..e948ee8d5 100644 --- a/core/src/net/sf/openrocket/util/MathUtil.java +++ b/core/src/net/sf/openrocket/util/MathUtil.java @@ -331,13 +331,13 @@ public class MathUtil { } int length = domain.size(); - if (length <= 1 || t < domain.get(0) || t > domain.get(length - 1)) { + if (length <= 1 || t < domain.get(0) || t > domain.get(length - 1) + EPSILON) { return Double.NaN; } // Look for the index of the right end point. int right = 1; - while (t > domain.get(right)) { + while (t > domain.get(right) + EPSILON) { right++; } int left = right - 1; diff --git a/swing/resources-src/datafiles/components b/swing/resources-src/datafiles/components index c9bd1a6f5..8304c0fd3 160000 --- a/swing/resources-src/datafiles/components +++ b/swing/resources-src/datafiles/components @@ -1 +1 @@ -Subproject commit c9bd1a6f539aab4bb724ecbdb54e65100a33e701 +Subproject commit 8304c0fd3dc80d65c40af4da83268ec1b32931d6