simulation listener enhancements
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 26 Jun 2011 16:01:26 +0000 (16:01 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 26 Jun 2011 16:01:26 +0000 (16:01 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@131 180e2498-e6e9-4542-8430-84ac67f01cd8

ChangeLog
src-extra/AirStart.java [new file with mode: 0644]
src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
src/net/sf/openrocket/simulation/GUISimulationConditions.java
src/net/sf/openrocket/simulation/listeners/example/AirStart.java [new file with mode: 0644]
src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java [new file with mode: 0644]
src/net/sf/openrocket/simulation/listeners/haisu/RollControlListener.java [deleted file]

index 78c5cf604971a1b68470f0c086d5c07be3b0931b..467384adb8203bb2312da5411f4f579c7b9ee45d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-06-26  Sampo Niskanen
+
+       * [BUG] Original rocket was modified when sim.listener modified rocket
+
+2011-06-18  Sampo Niskanen
+
+       * Merged l10n branch into trunk, initial l10n support
+
 2011-06-10  Sampo Niskanen
 
        * Released version 1.1.5
diff --git a/src-extra/AirStart.java b/src-extra/AirStart.java
new file mode 100644 (file)
index 0000000..9334c0d
--- /dev/null
@@ -0,0 +1,21 @@
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.util.Coordinate;
+
+/**
+ * Simulation listener that launches a rocket from a specific altitude.
+ */
+public class AirStart extends AbstractSimulationListener {
+       
+       /** Launch altitude */
+       private static final double ALTITUDE = 1000.0;
+       
+       @Override
+       public void startSimulation(SimulationStatus status) throws SimulationException {
+               Coordinate position = status.getRocketPosition();
+               position = position.add(0, 0, ALTITUDE);
+               status.setRocketPosition(position);
+       }
+       
+}
index 2740ca432d72741c7247663d1561f74f72e4eaaa..21ccb2665391a491ca4a9148335526dea3133392 100644 (file)
@@ -61,8 +61,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
                
 
                SimulationListenerHelper.fireStartSimulation(status);
+               // Get originating position (in case listener has modified launch position)
+               Coordinate origin = status.getRocketPosition();
+               Coordinate originVelocity = status.getRocketVelocity();
                
                try {
+                       double maxAlt = Double.NEGATIVE_INFINITY;
                        
                        // Start the simulation
                        while (handleEvents()) {
@@ -91,17 +95,24 @@ public class BasicEventSimulationEngine implements SimulationEngine {
                                                status.getConfiguration().getRocket(),
                                                new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
                                
+                               if (status.getRocketPosition().z > maxAlt) {
+                                       maxAlt = status.getRocketPosition().z;
+                               }
+                               
 
+                               // Position relative to start location
+                               Coordinate relativePosition = status.getRocketPosition().sub(origin);
+                               
                                // Add appropriate events
                                if (!status.isLiftoff()) {
                                        
                                        // Avoid sinking into ground before liftoff
-                                       if (status.getRocketPosition().z < 0) {
-                                               status.setRocketPosition(Coordinate.NUL);
-                                               status.setRocketVelocity(Coordinate.NUL);
+                                       if (relativePosition.z < 0) {
+                                               status.setRocketPosition(origin);
+                                               status.setRocketVelocity(originVelocity);
                                        }
                                        // Detect lift-off
-                                       if (status.getRocketPosition().z > 0.01) {
+                                       if (relativePosition.z > 0.02) {
                                                addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
                                        }
                                        
@@ -118,13 +129,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
                                
                                // Check for launch guide clearance
                                if (!status.isLaunchRodCleared() &&
-                                               status.getRocketPosition().length() > status.getSimulationConditions().getLaunchRodLength()) {
+                                               relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
                                        addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
                                }
                                
 
                                // Check for apogee
-                               if (!status.isApogeeReached() && status.getRocketPosition().z < oldAlt - 0.001) {
+                               if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
                                        addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
                                                        status.getConfiguration().getRocket()));
                                }
index 837b8c10e252a5a26716eecdc20c3d79c4623e1a..7ffc2dd4105811b91b3e8a7cd62cb252dfb52613 100644 (file)
@@ -436,7 +436,7 @@ public class GUISimulationConditions implements ChangeSource, Cloneable {
        public SimulationConditions toSimulationConditions() {
                SimulationConditions conditions = new SimulationConditions();
                
-               conditions.setRocket(getRocket());
+               conditions.setRocket((Rocket) getRocket().copy());
                conditions.setMotorConfigurationID(getMotorConfigurationID());
                conditions.setLaunchRodLength(getLaunchRodLength());
                conditions.setLaunchRodAngle(getLaunchRodAngle());
diff --git a/src/net/sf/openrocket/simulation/listeners/example/AirStart.java b/src/net/sf/openrocket/simulation/listeners/example/AirStart.java
new file mode 100644 (file)
index 0000000..97ce93a
--- /dev/null
@@ -0,0 +1,38 @@
+package net.sf.openrocket.simulation.listeners.example;
+
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.util.Coordinate;
+
+/**
+ * Simulation listener that launches a rocket from a specific altitude.
+ * <p>
+ * The altitude is read from the system property "openrocket.airstart.altitude"
+ * if defined, otherwise a default altitude of 1000 meters is used.
+ */
+public class AirStart extends AbstractSimulationListener {
+       
+       /** Default launch altitude */
+       private static final double DEFAULT_ALTITUDE = 1000.0;
+       
+       @Override
+       public void startSimulation(SimulationStatus status) throws SimulationException {
+               
+               // Get the launch altitude
+               double altitude;
+               String arg = System.getProperty("openrocket.airstart.altitude");
+               try {
+                       altitude = Double.parseDouble(arg);
+               } catch (RuntimeException e) {
+                       altitude = DEFAULT_ALTITUDE;
+               }
+               
+               // Modify launch position
+               Coordinate position = status.getRocketPosition();
+               position = position.add(0, 0, altitude);
+               status.setRocketPosition(position);
+               
+       }
+       
+}
diff --git a/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java b/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java
new file mode 100644 (file)
index 0000000..8099321
--- /dev/null
@@ -0,0 +1,128 @@
+package net.sf.openrocket.simulation.listeners.example;
+
+import net.sf.openrocket.aerodynamics.FlightConditions;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.MathUtil;
+
+/**
+ * An example listener that applies a PI-controller to adjust the cant of fins
+ * named "CONTROL" to stop the rocket from rolling.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class RollControlListener extends AbstractSimulationListener {
+       
+       // Name of control fin set
+       private static final String CONTROL_FIN_NAME = "CONTROL";
+       
+       // Define custom flight data type
+       private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant",
+                       UnitGroup.UNITS_ANGLE);
+       
+       // Simulation time at which PID controller is activated
+       private static final double START_TIME = 0.5;
+       
+       // Desired roll rate (rad/sec)
+       private static final double SETPOINT = 0.0;
+       
+       // Maximum control fin turn rate (rad/sec)
+       private static final double TURNRATE = 10 * Math.PI / 180;
+       
+       // Maximum control fin angle (rad)
+       private static final double MAX_ANGLE = 15 * Math.PI / 180;
+       
+
+       /*
+        * PID parameters
+        * 
+        * At M=0.3 KP oscillation threshold between 0.35 and 0.4.    Good KI=3
+        * At M=0.6 KP oscillation threshold between 0.07 and 0.08    Good KI=2
+        * At M=0.9 KP oscillation threshold between 0.013 and 0.014  Good KI=0.5
+        */
+       private static final double KP = 0.007;
+       private static final double KI = 0.2;
+       
+
+
+
+       private double rollrate;
+       
+       private double prevTime = 0;
+       private double intState = 0;
+       
+       private double finPosition = 0;
+       
+       
+
+       @Override
+       public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) {
+               // Store the current roll rate for later use
+               rollrate = flightConditions.getRollRate();
+               return null;
+       }
+       
+       
+       @Override
+       public void postStep(SimulationStatus status) throws SimulationException {
+               
+               // Activate PID controller only after a specific time
+               if (status.getSimulationTime() < START_TIME) {
+                       prevTime = status.getSimulationTime();
+                       return;
+               }
+               
+               // Find the fin set named CONTROL
+               FinSet finset = null;
+               for (RocketComponent c : status.getConfiguration()) {
+                       if ((c instanceof FinSet) && (c.getName().equals(CONTROL_FIN_NAME))) {
+                               finset = (FinSet) c;
+                               break;
+                       }
+               }
+               if (finset == null) {
+                       throw new SimulationException("A fin set with name '" + CONTROL_FIN_NAME + "' was not found");
+               }
+               
+
+               // Determine time step
+               double deltaT = status.getSimulationTime() - prevTime;
+               prevTime = status.getSimulationTime();
+               
+
+               // PID controller
+               double error = SETPOINT - rollrate;
+               
+               double p = KP * error;
+               intState += error * deltaT;
+               double i = KI * intState;
+               
+               double value = p + i;
+               
+
+               // Clamp the fin angle between -MAX_ANGLE and MAX_ANGLE
+               if (Math.abs(value) > MAX_ANGLE) {
+                       System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n",
+                                       value * 180 / Math.PI, status.getSimulationTime());
+                       value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE);
+               }
+               
+
+               // Limit the fin turn rate
+               if (finPosition < value) {
+                       finPosition = Math.min(finPosition + TURNRATE * deltaT, value);
+               } else {
+                       finPosition = Math.max(finPosition - TURNRATE * deltaT, value);
+               }
+               
+               // Set the control fin cant and store the data
+               finset.setCantAngle(finPosition);
+               status.getFlightData().setValue(FIN_CANT_TYPE, finPosition);
+               
+       }
+}
diff --git a/src/net/sf/openrocket/simulation/listeners/haisu/RollControlListener.java b/src/net/sf/openrocket/simulation/listeners/haisu/RollControlListener.java
deleted file mode 100644 (file)
index b29e7d9..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-package net.sf.openrocket.simulation.listeners.haisu;
-
-import net.sf.openrocket.aerodynamics.FlightConditions;
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.simulation.SimulationStatus;
-import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
-import net.sf.openrocket.util.MathUtil;
-
-/**
- * An example listener that applies a PI-controller to adjust the cant of fins
- * named "CONTROL" to stop the rocket from rolling.
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class RollControlListener extends AbstractSimulationListener {
-       
-       private static final double DELTA_T = 0.01;
-       private static final double START_TIME = 0.5;
-       
-       private static final double SETPOINT = 0.0;
-       
-       private static final double TURNRATE = 10 * Math.PI / 180; // per second
-       
-
-       /*
-        * At M=0.3 KP oscillation threshold between 0.35 and 0.4.    Good KI=3
-        * At M=0.6 KP oscillation threshold between 0.07 and 0.08    Good KI=2
-        * At M=0.9 KP oscillation threshold between 0.013 and 0.014  Good KI=0.5
-        */
-       private static final double KP = 0.007;
-       private static final double KI = 0.2;
-       
-
-       private static final double MAX_ANGLE = 15 * Math.PI / 180;
-       
-
-
-
-       private double rollrate;
-       
-       private double intState = 0;
-       
-       private double finPosition = 0;
-       
-       
-       public RollControlListener() {
-       }
-       
-       @Override
-       public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) {
-               rollrate = flightConditions.getRollRate();
-               return null;
-       }
-       
-       @Override
-       public void postStep(SimulationStatus status) {
-               
-               if (status.getSimulationTime() < START_TIME)
-                       return;
-               
-               // PID controller
-               FinSet finset = null;
-               for (RocketComponent c : status.getConfiguration()) {
-                       if ((c instanceof FinSet) && (c.getName().equals("CONTROL"))) {
-                               finset = (FinSet) c;
-                               break;
-                       }
-               }
-               if (finset == null) {
-                       throw new RuntimeException("CONTROL fin not found");
-               }
-               
-
-               double error = SETPOINT - rollrate;
-               
-
-               error = Math.signum(error) * error * error; ////  pow2(error)
-               
-               double p = KP * error;
-               intState += error * DELTA_T;
-               double i = KI * intState;
-               
-               double value = p + i;
-               
-
-               if (Math.abs(value) > MAX_ANGLE) {
-                       System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n",
-                                       value * 180 / Math.PI, status.getSimulationTime());
-                       value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE);
-               }
-               
-
-               if (finPosition < value) {
-                       finPosition = Math.min(finPosition + TURNRATE * DELTA_T, value);
-               } else {
-                       finPosition = Math.max(finPosition - TURNRATE * DELTA_T, value);
-               }
-               
-               if (MathUtil.equals(status.getSimulationTime() * 10, Math.rint(status.getSimulationTime() * 10))) {
-                       System.err.printf("t=%.3f  angle=%.1f  current=%.1f\n", status.getSimulationTime(),
-                                       value * 180 / Math.PI, finPosition * 180 / Math.PI);
-               }
-               
-               finset.setCantAngle(finPosition);
-               
-       }
-       
-}