release 0.9.6
[debian/openrocket] / src / net / sf / openrocket / simulation / listeners / haisu / RollControlListener.java
1 package net.sf.openrocket.simulation.listeners.haisu;
2
3 import java.util.Collection;
4
5 import net.sf.openrocket.aerodynamics.FlightConditions;
6 import net.sf.openrocket.rocketcomponent.FinSet;
7 import net.sf.openrocket.rocketcomponent.RocketComponent;
8 import net.sf.openrocket.simulation.FlightEvent;
9 import net.sf.openrocket.simulation.SimulationStatus;
10 import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
11 import net.sf.openrocket.util.MathUtil;
12
13
14 public class RollControlListener extends AbstractSimulationListener {
15
16         private static final double DELTA_T = 0.01;
17         private static final double START_TIME = 0.5;
18         
19         private static final double MACH = 0.9;
20         
21         private static final double SETPOINT = 0.0;
22         
23         private static final double TURNRATE = 10 * Math.PI/180;  // per second
24
25         
26         /*
27          * At M=0.3 KP oscillation threshold between 0.35 and 0.4.    Good KI=3
28          * At M=0.6 KP oscillation threshold between 0.07 and 0.08    Good KI=2
29          * At M=0.9 KP oscillation threshold between 0.013 and 0.014  Good KI=0.5
30          */
31         private static final double KP = 0.007;
32         private static final double KI = 0.2;
33         
34         
35         private static final double MAX_ANGLE = 15 * Math.PI/180;
36         
37         
38         
39         
40         private double rollrate;
41         
42         private double intState = 0;
43         
44         private double finPosition = 0;
45         
46         
47         public RollControlListener() {
48         }
49
50         @Override
51         public void flightConditions(SimulationStatus status, FlightConditions conditions) {
52                 rollrate = conditions.getRollRate();
53         }
54         
55         @Override
56         public Collection<FlightEvent> stepTaken(SimulationStatus status) {
57                 
58                 if (status.time < START_TIME)
59                         return null;
60
61                 // PID controller
62                 FinSet finset = null;
63                 for (RocketComponent c: status.configuration) {
64                         if ((c instanceof FinSet) && (c.getName().equals("CONTROL"))) {
65                                 finset = (FinSet)c;
66                                 break;
67                         }
68                 }
69                 if (finset==null) {
70                         throw new RuntimeException("CONTROL fin not found");
71                 }
72                 
73                 
74                 double error = SETPOINT - rollrate;
75                 
76                 
77                 error = Math.signum(error) * error * error;    ////  pow2(error)
78
79                 double p = KP * error;
80                 intState += error * DELTA_T;
81                 double i = KI * intState;
82                 
83                 double value = p+i;
84                 
85                                 
86                 if (Math.abs(value) > MAX_ANGLE) {
87                         System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n", 
88                                         value*180/Math.PI, status.time);
89                         value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE);
90                 }
91                 
92                 
93                 if (finPosition < value) {
94                         finPosition = Math.min(finPosition + TURNRATE*DELTA_T, value);
95                 } else {
96                         finPosition = Math.max(finPosition - TURNRATE*DELTA_T, value);
97                 }
98
99                 if (MathUtil.equals(status.time*10, Math.rint(status.time*10))) {
100                         System.err.printf("t=%.3f  angle=%.1f  current=%.1f\n",status.time, 
101                                         value*180/Math.PI, finPosition*180/Math.PI);
102                 }
103
104                 finset.setCantAngle(finPosition);
105                                 
106                 return null;
107         }
108         
109         
110 }