First revision of openRocket sim.
[sw/motorsim] / gui / com / billkuker / rocketry / motorsim / visual / openRocket / OneMotorDatabase.java
1 package com.billkuker.rocketry.motorsim.visual.openRocket;\r
2 import java.util.List;\r
3 import java.util.Vector;\r
4 \r
5 import javax.measure.quantity.Duration;\r
6 import javax.measure.unit.SI;\r
7 \r
8 import net.sf.openrocket.database.MotorDatabase;\r
9 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;\r
10 import net.sf.openrocket.motor.Motor;\r
11 import net.sf.openrocket.motor.MotorInstance;\r
12 import net.sf.openrocket.util.BugException;\r
13 import net.sf.openrocket.util.Coordinate;\r
14 import net.sf.openrocket.util.Inertia;\r
15 import net.sf.openrocket.util.MathUtil;\r
16 \r
17 import org.jscience.physics.amount.Amount;\r
18 \r
19 import com.billkuker.rocketry.motorsim.Burn;\r
20 import com.billkuker.rocketry.motorsim.Burn.Interval;\r
21 import com.billkuker.rocketry.motorsim.BurnSummary;\r
22 import com.billkuker.rocketry.motorsim.ICylindricalChamber;\r
23 import com.billkuker.rocketry.motorsim.RocketScience;\r
24 \r
25 public class OneMotorDatabase implements MotorDatabase {\r
26 \r
27         static Burn burn;\r
28         static BurnSummary bs;\r
29         static Coordinate cg[];\r
30         static double[] time;\r
31         static double[] thrust;\r
32 \r
33         static Motor motor = new Motor() {\r
34 \r
35                 @Override\r
36                 public Type getMotorType() {\r
37                         return Type.SINGLE;\r
38                 }\r
39 \r
40                 @Override\r
41                 public String getDesignation() {\r
42                         return bs.getRating();\r
43                 }\r
44 \r
45                 @Override\r
46                 public String getDesignation(double delay) {\r
47                         return bs.getRating() + "-" + ((int) delay);\r
48                 }\r
49 \r
50                 @Override\r
51                 public String getDescription() {\r
52                         if ( burn == null )\r
53                                 return "NO MOTOR YET";\r
54                         return burn.getMotor().getName();\r
55                 }\r
56 \r
57                 @Override\r
58                 public double getDiameter() {\r
59                         return ((ICylindricalChamber) burn.getMotor().getChamber()).getOD()\r
60                                         .doubleValue(SI.METER);\r
61                 }\r
62 \r
63                 @Override\r
64                 public double getLength() {\r
65                         return ((ICylindricalChamber) burn.getMotor().getChamber())\r
66                                         .getLength().doubleValue(SI.METER);\r
67                 }\r
68 \r
69                 @Override\r
70                 public String getDigest() {\r
71                         return "WTF";\r
72                 }\r
73 \r
74                 @Override\r
75                 public MotorInstance getInstance() {\r
76 \r
77                         return new MotorInstance() {\r
78 \r
79                                 private int position;\r
80 \r
81                                 // Previous time step value\r
82                                 private double prevTime;\r
83 \r
84                                 // Average thrust during previous step\r
85                                 private double stepThrust;\r
86                                 // Instantaneous thrust at current time point\r
87                                 private double instThrust;\r
88 \r
89                                 // Average CG during previous step\r
90                                 private Coordinate stepCG;\r
91                                 // Instantaneous CG at current time point\r
92                                 private Coordinate instCG;\r
93 \r
94                                 private final double unitRotationalInertia;\r
95                                 private final double unitLongitudinalInertia;\r
96 \r
97                                 private int modID = 0;\r
98 \r
99                                 {\r
100                                         position = 0;\r
101                                         prevTime = 0;\r
102                                         instThrust = 0;\r
103                                         stepThrust = 0;\r
104                                         instCG = cg[0];\r
105                                         stepCG = cg[0];\r
106                                         unitRotationalInertia = Inertia\r
107                                                         .filledCylinderRotational(getDiameter() / 2);\r
108                                         unitLongitudinalInertia = Inertia\r
109                                                         .filledCylinderLongitudinal(getDiameter() / 2,\r
110                                                                         getLength());\r
111                                 }\r
112 \r
113                                 @Override\r
114                                 public double getTime() {\r
115                                         return prevTime;\r
116                                 }\r
117 \r
118                                 @Override\r
119                                 public Coordinate getCG() {\r
120                                         return stepCG;\r
121                                 }\r
122 \r
123                                 @Override\r
124                                 public double getLongitudinalInertia() {\r
125                                         return unitLongitudinalInertia * stepCG.weight;\r
126                                 }\r
127 \r
128                                 @Override\r
129                                 public double getRotationalInertia() {\r
130                                         return unitRotationalInertia * stepCG.weight;\r
131                                 }\r
132 \r
133                                 @Override\r
134                                 public double getThrust() {\r
135                                         return stepThrust;\r
136                                 }\r
137 \r
138                                 @Override\r
139                                 public boolean isActive() {\r
140                                         return prevTime < time[time.length - 1];\r
141                                 }\r
142 \r
143                                 @Override\r
144                                 public void step(double nextTime, double acceleration,\r
145                                                 AtmosphericConditions cond) {\r
146 \r
147                                         if (!(nextTime >= prevTime)) {\r
148                                                 // Also catches NaN\r
149                                                 throw new IllegalArgumentException(\r
150                                                                 "Stepping backwards in time, current="\r
151                                                                                 + prevTime + " new=" + nextTime);\r
152                                         }\r
153                                         if (MathUtil.equals(prevTime, nextTime)) {\r
154                                                 return;\r
155                                         }\r
156 \r
157                                         modID++;\r
158 \r
159                                         if (position >= time.length - 1) {\r
160                                                 // Thrust has ended\r
161                                                 prevTime = nextTime;\r
162                                                 stepThrust = 0;\r
163                                                 instThrust = 0;\r
164                                                 stepCG = cg[cg.length - 1];\r
165                                                 return;\r
166                                         }\r
167 \r
168                                         // Compute average & instantaneous thrust\r
169                                         if (nextTime < time[position + 1]) {\r
170 \r
171                                                 // Time step between time points\r
172                                                 double nextF = MathUtil.map(nextTime, time[position],\r
173                                                                 time[position + 1], thrust[position],\r
174                                                                 thrust[position + 1]);\r
175                                                 stepThrust = (instThrust + nextF) / 2;\r
176                                                 instThrust = nextF;\r
177 \r
178                                         } else {\r
179 \r
180                                                 // Portion of previous step\r
181                                                 stepThrust = (instThrust + thrust[position + 1]) / 2\r
182                                                                 * (time[position + 1] - prevTime);\r
183 \r
184                                                 // Whole steps\r
185                                                 position++;\r
186                                                 while ((position < time.length - 1)\r
187                                                                 && (nextTime >= time[position + 1])) {\r
188                                                         stepThrust += (thrust[position] + thrust[position + 1])\r
189                                                                         / 2 * (time[position + 1] - time[position]);\r
190                                                         position++;\r
191                                                 }\r
192 \r
193                                                 // End step\r
194                                                 if (position < time.length - 1) {\r
195                                                         instThrust = MathUtil.map(nextTime, time[position],\r
196                                                                         time[position + 1], thrust[position],\r
197                                                                         thrust[position + 1]);\r
198                                                         stepThrust += (thrust[position] + instThrust) / 2\r
199                                                                         * (nextTime - time[position]);\r
200                                                 } else {\r
201                                                         // Thrust ended during this step\r
202                                                         instThrust = 0;\r
203                                                 }\r
204 \r
205                                                 stepThrust /= (nextTime - prevTime);\r
206 \r
207                                         }\r
208 \r
209                                         // Compute average and instantaneous CG (simple average\r
210                                         // between points)\r
211                                         Coordinate nextCG;\r
212                                         if (position < time.length - 1) {\r
213                                                 nextCG = MathUtil.map(nextTime, time[position],\r
214                                                                 time[position + 1], cg[position],\r
215                                                                 cg[position + 1]);\r
216                                         } else {\r
217                                                 nextCG = cg[cg.length - 1];\r
218                                         }\r
219                                         stepCG = instCG.add(nextCG).multiply(0.5);\r
220                                         instCG = nextCG;\r
221 \r
222                                         // Update time\r
223                                         prevTime = nextTime;\r
224                                 }\r
225 \r
226                                 @Override\r
227                                 public MotorInstance clone() {\r
228                                         try {\r
229                                                 return (MotorInstance) super.clone();\r
230                                         } catch (CloneNotSupportedException e) {\r
231                                                 throw new BugException("CloneNotSupportedException", e);\r
232                                         }\r
233                                 }\r
234 \r
235                                 @Override\r
236                                 public int getModID() {\r
237                                         return modID;\r
238                                 }\r
239                         };\r
240 \r
241                 }\r
242 \r
243                 @Override\r
244                 public Coordinate getLaunchCG() {\r
245                         return new Coordinate();\r
246                 }\r
247 \r
248                 @Override\r
249                 public Coordinate getEmptyCG() {\r
250                         return new Coordinate();\r
251                 }\r
252 \r
253                 @Override\r
254                 public double getBurnTimeEstimate() {\r
255                         return bs.thrustTime().doubleValue(SI.SECOND);\r
256                 }\r
257 \r
258                 @Override\r
259                 public double getAverageThrustEstimate() {\r
260                         return bs.averageThrust().doubleValue(SI.NEWTON);\r
261                 }\r
262 \r
263                 @Override\r
264                 public double getMaxThrustEstimate() {\r
265                         return bs.maxThrust().doubleValue(SI.NEWTON);\r
266                 }\r
267 \r
268                 @Override\r
269                 public double getTotalImpulseEstimate() {\r
270                         return bs.totalImpulse().doubleValue(RocketScience.NEWTON_SECOND);\r
271                 }\r
272 \r
273                 @Override\r
274                 public double[] getTimePoints() {\r
275                         return time;\r
276                 }\r
277 \r
278                 @Override\r
279                 public double[] getThrustPoints() {\r
280                         return thrust;\r
281                 }\r
282 \r
283                 @Override\r
284                 public Coordinate[] getCGPoints() {\r
285                         return cg;\r
286                 }\r
287 \r
288         };\r
289 \r
290         static void setBurn(Burn b) {\r
291                 burn = b;\r
292                 bs = new BurnSummary(b);\r
293 \r
294                 cg = new Coordinate[burn.getData().size()];\r
295                 time = new double[burn.getData().size()];\r
296                 thrust = new double[burn.getData().size()];\r
297                 \r
298                 Coordinate c = new Coordinate();\r
299 \r
300                 for (int i = 0; i < cg.length; i++) {\r
301                         cg[i] = c;\r
302                 }\r
303 \r
304                 int i = 0;\r
305                 for (Amount<Duration> t : burn.getData().keySet()) {\r
306                         time[i++] = t.doubleValue(SI.SECOND);\r
307                 }\r
308 \r
309                 i = 0;\r
310                 for (Interval d : burn.getData().values()) {\r
311                         double t = d.thrust.doubleValue(SI.NEWTON);\r
312                         t = Math.max(t, 0.0001);\r
313                         thrust[i++] = t;\r
314                 }\r
315                 thrust[0] = 0;\r
316                 thrust[thrust.length - 1] = 0;\r
317         }\r
318 \r
319         public OneMotorDatabase() {\r
320                 super();\r
321         }\r
322 \r
323         public List<? extends Motor> findMotors(Motor.Type type,\r
324                         String manufacturer, String designation, double diameter,\r
325                         double length) {\r
326                 List<Motor> ret = new Vector<Motor>();\r
327                 System.err.println("Returning " + motor.getDescription());\r
328                 ret.add(motor);\r
329                 return ret;\r
330         }\r
331 \r
332 }\r