1 package com.billkuker.rocketry.motorsim.visual.openRocket;
\r
2 import java.util.List;
\r
3 import java.util.Vector;
\r
5 import javax.measure.quantity.Duration;
\r
6 import javax.measure.unit.SI;
\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
17 import org.jscience.physics.amount.Amount;
\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
25 public class OneMotorDatabase implements MotorDatabase {
\r
28 static BurnSummary bs;
\r
29 static Coordinate cg[];
\r
30 static double[] time;
\r
31 static double[] thrust;
\r
33 static Motor motor = new Motor() {
\r
36 public Type getMotorType() {
\r
41 public String getDesignation() {
\r
42 return bs.getRating();
\r
46 public String getDesignation(double delay) {
\r
47 return bs.getRating() + "-" + ((int) delay);
\r
51 public String getDescription() {
\r
53 return "NO MOTOR YET";
\r
54 return burn.getMotor().getName();
\r
58 public double getDiameter() {
\r
59 return ((ICylindricalChamber) burn.getMotor().getChamber()).getOD()
\r
60 .doubleValue(SI.METER);
\r
64 public double getLength() {
\r
65 return ((ICylindricalChamber) burn.getMotor().getChamber())
\r
66 .getLength().doubleValue(SI.METER);
\r
70 public String getDigest() {
\r
75 public MotorInstance getInstance() {
\r
77 return new MotorInstance() {
\r
79 private int position;
\r
81 // Previous time step value
\r
82 private double prevTime;
\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
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
94 private final double unitRotationalInertia;
\r
95 private final double unitLongitudinalInertia;
\r
97 private int modID = 0;
\r
106 unitRotationalInertia = Inertia
\r
107 .filledCylinderRotational(getDiameter() / 2);
\r
108 unitLongitudinalInertia = Inertia
\r
109 .filledCylinderLongitudinal(getDiameter() / 2,
\r
114 public double getTime() {
\r
119 public Coordinate getCG() {
\r
124 public double getLongitudinalInertia() {
\r
125 return unitLongitudinalInertia * stepCG.weight;
\r
129 public double getRotationalInertia() {
\r
130 return unitRotationalInertia * stepCG.weight;
\r
134 public double getThrust() {
\r
139 public boolean isActive() {
\r
140 return prevTime < time[time.length - 1];
\r
144 public void step(double nextTime, double acceleration,
\r
145 AtmosphericConditions cond) {
\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
153 if (MathUtil.equals(prevTime, nextTime)) {
\r
159 if (position >= time.length - 1) {
\r
160 // Thrust has ended
\r
161 prevTime = nextTime;
\r
164 stepCG = cg[cg.length - 1];
\r
168 // Compute average & instantaneous thrust
\r
169 if (nextTime < time[position + 1]) {
\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
180 // Portion of previous step
\r
181 stepThrust = (instThrust + thrust[position + 1]) / 2
\r
182 * (time[position + 1] - prevTime);
\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
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
201 // Thrust ended during this step
\r
205 stepThrust /= (nextTime - prevTime);
\r
209 // Compute average and instantaneous CG (simple average
\r
212 if (position < time.length - 1) {
\r
213 nextCG = MathUtil.map(nextTime, time[position],
\r
214 time[position + 1], cg[position],
\r
217 nextCG = cg[cg.length - 1];
\r
219 stepCG = instCG.add(nextCG).multiply(0.5);
\r
223 prevTime = nextTime;
\r
227 public MotorInstance clone() {
\r
229 return (MotorInstance) super.clone();
\r
230 } catch (CloneNotSupportedException e) {
\r
231 throw new BugException("CloneNotSupportedException", e);
\r
236 public int getModID() {
\r
244 public Coordinate getLaunchCG() {
\r
245 return new Coordinate();
\r
249 public Coordinate getEmptyCG() {
\r
250 return new Coordinate();
\r
254 public double getBurnTimeEstimate() {
\r
255 return bs.thrustTime().doubleValue(SI.SECOND);
\r
259 public double getAverageThrustEstimate() {
\r
260 return bs.averageThrust().doubleValue(SI.NEWTON);
\r
264 public double getMaxThrustEstimate() {
\r
265 return bs.maxThrust().doubleValue(SI.NEWTON);
\r
269 public double getTotalImpulseEstimate() {
\r
270 return bs.totalImpulse().doubleValue(RocketScience.NEWTON_SECOND);
\r
274 public double[] getTimePoints() {
\r
279 public double[] getThrustPoints() {
\r
284 public Coordinate[] getCGPoints() {
\r
290 static void setBurn(Burn b) {
\r
292 bs = new BurnSummary(b);
\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
298 Coordinate c = new Coordinate();
\r
300 for (int i = 0; i < cg.length; i++) {
\r
305 for (Amount<Duration> t : burn.getData().keySet()) {
\r
306 time[i++] = t.doubleValue(SI.SECOND);
\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
316 thrust[thrust.length - 1] = 0;
\r
319 public OneMotorDatabase() {
\r
323 public List<? extends Motor> findMotors(Motor.Type type,
\r
324 String manufacturer, String designation, double diameter,
\r
326 List<Motor> ret = new Vector<Motor>();
\r
327 System.err.println("Returning " + motor.getDescription());
\r