[Refactor ] Refactored motor state in preparation for debugging the simulation itself
- Created MotorState as an enum describing discrete states a motor may be in - moved ThrustCurveMotorState info back into MotorSimulation -- MotorSimulation will be used by the simulation code. -- tracks simulation-time info, such as event times, and current state ( <MotorState> ) - MotorConfiguration no longer have any knowledge about their simulation info - moved functionality (BUT NOT STATE) into ThrustCurveMotor -- can query about thrust(t), mass(t), cgx(t)
This commit is contained in:
parent
438f58c438
commit
28689825a4
@ -25,25 +25,37 @@ public class MassCalculator implements Monitorable {
|
||||
public static enum MassCalcType {
|
||||
NO_MOTORS {
|
||||
@Override
|
||||
public Coordinate getCG(Motor motor) {
|
||||
return Coordinate.NUL;
|
||||
public double getCGx(Motor motor) {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public double getMass(Motor motor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
},
|
||||
LAUNCH_MASS {
|
||||
@Override
|
||||
public Coordinate getCG(Motor motor) {
|
||||
return motor.getLaunchCG();
|
||||
public double getCGx(Motor motor) {
|
||||
return motor.getLaunchCGx();
|
||||
}
|
||||
@Override
|
||||
public double getMass(Motor motor) {
|
||||
return motor.getLaunchMass();
|
||||
}
|
||||
},
|
||||
BURNOUT_MASS {
|
||||
@Override
|
||||
public Coordinate getCG(Motor motor) {
|
||||
return motor.getEmptyCG();
|
||||
public double getCGx(Motor motor) {
|
||||
return motor.getBurnoutCGx();
|
||||
}
|
||||
@Override
|
||||
public double getMass(Motor motor) {
|
||||
return motor.getBurnoutMass();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract Coordinate getCG(Motor motor);
|
||||
public abstract double getMass(Motor motor);
|
||||
public abstract double getCGx(Motor motor);
|
||||
|
||||
/**
|
||||
* Compute the cg contribution of the motor relative to the rocket's coordinates
|
||||
@ -52,16 +64,21 @@ public class MassCalculator implements Monitorable {
|
||||
* @return
|
||||
*/
|
||||
public Coordinate getCG(MotorConfiguration motorConfig) {
|
||||
Coordinate cg = getCG(motorConfig.getMotor());
|
||||
cg = cg.add(motorConfig.getPosition());
|
||||
Motor mtr = motorConfig.getMotor();
|
||||
double mass = getMass(mtr);
|
||||
Coordinate cg = motorConfig.getPosition().add( getCGx(mtr), 0, 0, mass);
|
||||
|
||||
RocketComponent motorMount = (RocketComponent) motorConfig.getMount();
|
||||
Coordinate totalCG = new Coordinate();
|
||||
Coordinate totalCM = new Coordinate();
|
||||
for (Coordinate cord : motorMount.toAbsolute(cg) ) {
|
||||
totalCG = totalCG.average(cord);
|
||||
totalCM = totalCM.average(cord);
|
||||
}
|
||||
|
||||
return totalCG;
|
||||
return totalCM;
|
||||
}
|
||||
|
||||
public Coordinate getCM( Motor motor ){
|
||||
return new Coordinate( getCGx(motor), 0, 0, getMass(motor));
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +185,7 @@ public class MassCalculator implements Monitorable {
|
||||
double motorXPosition = mtrConfig.getX(); // location of motor from mount
|
||||
|
||||
|
||||
Coordinate localCM = type.getCG( mtr ); // CoM from beginning of motor
|
||||
Coordinate localCM = type.getCM( mtr ); // CoM from beginning of motor
|
||||
localCM = localCM.setWeight( localCM.weight * instanceCount);
|
||||
// a *bit* hacky :P
|
||||
Coordinate curMotorCM = localCM.setX( localCM.x + locations[0].x + motorXPosition );
|
||||
|
@ -1,9 +1,6 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
public interface Motor {
|
||||
public interface Motor extends Cloneable {
|
||||
|
||||
/**
|
||||
* Enum of rocket motor types.
|
||||
@ -118,12 +115,19 @@ public interface Motor {
|
||||
|
||||
public String getDigest();
|
||||
|
||||
public MotorState getNewInstance();
|
||||
public Motor clone();
|
||||
|
||||
public Coordinate getLaunchCG();
|
||||
// this is probably a badly-designed way to expose the thrust, but it's not worth worrying about until
|
||||
// there's a second (non-trivial) type of motor to support...
|
||||
public double getThrustAtMotorTime( final double motorTimeDelta );
|
||||
|
||||
public double getLaunchCGx();
|
||||
|
||||
public Coordinate getEmptyCG();
|
||||
public double getBurnoutCGx();
|
||||
|
||||
public double getLaunchMass();
|
||||
|
||||
public double getBurnoutMass();
|
||||
|
||||
/**
|
||||
* Return an estimate of the burn time of this motor, or NaN if an estimate is unavailable.
|
||||
|
@ -4,7 +4,6 @@ import net.sf.openrocket.rocketcomponent.FlightConfigurableParameter;
|
||||
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Inertia;
|
||||
|
||||
@ -15,7 +14,8 @@ import net.sf.openrocket.util.Inertia;
|
||||
public class MotorConfiguration implements FlightConfigurableParameter<MotorConfiguration> {
|
||||
|
||||
public static final String EMPTY_DESCRIPTION = "Empty Configuration";
|
||||
|
||||
|
||||
// set at config time
|
||||
protected MotorMount mount = null;
|
||||
protected Motor motor = null;
|
||||
protected double ejectionDelay = 0.0;
|
||||
@ -41,30 +41,10 @@ public class MotorConfiguration implements FlightConfigurableParameter<MotorConf
|
||||
modID++;
|
||||
}
|
||||
|
||||
public MotorState getSimulationState() {
|
||||
MotorState state = motor.getNewInstance();
|
||||
state.setEjectionDelay( this.ejectionDelay );
|
||||
if( ignitionOveride ) {
|
||||
state.setIgnitionEvent( this.ignitionEvent );
|
||||
state.setIgnitionDelay( this.ignitionDelay );
|
||||
} else {
|
||||
MotorConfiguration defInstance = mount.getDefaultMotorInstance();
|
||||
state.setIgnitionEvent( defInstance.ignitionEvent );
|
||||
state.setIgnitionDelay( defInstance.ignitionDelay );
|
||||
}
|
||||
state.setMount( mount );
|
||||
state.setId( id );
|
||||
return state;
|
||||
}
|
||||
|
||||
public boolean hasIgnitionOverride() {
|
||||
return ignitionOveride;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return motor != null;
|
||||
}
|
||||
|
||||
public String getDescription(){
|
||||
if( motor == null ){
|
||||
return EMPTY_DESCRIPTION;
|
||||
@ -164,7 +144,7 @@ public class MotorConfiguration implements FlightConfigurableParameter<MotorConf
|
||||
|
||||
public double getPropellantMass(){
|
||||
if ( motor != null ) {
|
||||
return (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
|
||||
return (motor.getLaunchMass() - motor.getBurnoutMass());
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
@ -8,18 +8,15 @@ import java.util.Locale;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.util.ArrayUtils;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Inertia;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
|
||||
public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
// NECESSARY field, for this class -- this class is serialized in the motor database, and loaded directly.
|
||||
private static final long serialVersionUID = -1490333207132694479L;
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final Logger log = LoggerFactory.getLogger(ThrustCurveMotor.class);
|
||||
|
||||
@ -45,13 +42,18 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
private final double length;
|
||||
private final double[] time;
|
||||
private final double[] thrust;
|
||||
private final Coordinate[] cg;
|
||||
|
||||
// private final double[] cgx; // cannot add without rebuilding the motor database ... automatically on every user's install.
|
||||
// private final double[] mass; // cannot add without rebuilding the motor database ... on every user's install.
|
||||
private final Coordinate[] cg; /// @deprecated, but required b/c the motor database is serialized java classes.
|
||||
private double maxThrust;
|
||||
private double burnTime;
|
||||
private double averageThrust;
|
||||
private double totalImpulse;
|
||||
|
||||
private final double unitRotationalInertia;
|
||||
private final double unitLongitudinalInertia;
|
||||
|
||||
|
||||
/**
|
||||
* Deep copy constructor.
|
||||
* Constructs a new ThrustCurveMotor from an existing ThrustCurveMotor.
|
||||
@ -63,19 +65,22 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
this.designation = m.designation;
|
||||
this.description = m.description;
|
||||
this.type = m.type;
|
||||
this.delays = ArrayUtils.copyOf(m.delays, m.delays.length);
|
||||
this.delays = Arrays.copyOf(m.delays, m.delays.length);
|
||||
this.diameter = m.diameter;
|
||||
this.length = m.length;
|
||||
this.time = ArrayUtils.copyOf(m.time, m.time.length);
|
||||
this.thrust = ArrayUtils.copyOf(m.thrust, m.thrust.length);
|
||||
this.cg = new Coordinate[m.cg.length];
|
||||
for (int i = 0; i < cg.length; i++) {
|
||||
this.cg[i] = m.cg[i].clone();
|
||||
}
|
||||
this.time = Arrays.copyOf(m.time, m.time.length);
|
||||
this.thrust = Arrays.copyOf(m.thrust, m.thrust.length);
|
||||
this.cg = m.getCGPoints().clone();
|
||||
// this.cgx = Arrays.copyOf(m.cgx, m.cgx.length);
|
||||
// this.mass = Arrays.copyOf(m.mass, m.mass.length);
|
||||
this.maxThrust = m.maxThrust;
|
||||
this.burnTime = m.burnTime;
|
||||
this.averageThrust = m.averageThrust;
|
||||
this.totalImpulse = m.totalImpulse;
|
||||
|
||||
this.unitRotationalInertia = m.unitRotationalInertia;
|
||||
this.unitLongitudinalInertia = m.unitLongitudinalInertia;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,8 +167,19 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
this.time = time.clone();
|
||||
this.thrust = thrust.clone();
|
||||
this.cg = cg.clone();
|
||||
|
||||
// this.cgx = new double[ cg.length];
|
||||
// this.mass = new double[ cg.length];
|
||||
// for (int cgIndex = 0; cgIndex < cg.length; ++cgIndex){
|
||||
// this.cgx[cgIndex] = cg[cgIndex].x;
|
||||
// this.mass[cgIndex] = cg[cgIndex].weight;
|
||||
// }
|
||||
unitRotationalInertia = Inertia.filledCylinderRotational( this.diameter / 2);
|
||||
unitLongitudinalInertia = Inertia.filledCylinderLongitudinal( this.diameter / 2, this.length);
|
||||
|
||||
computeStatistics();
|
||||
|
||||
// This constructor is not called upon serialized data constructor.
|
||||
//System.err.println("loading motor: "+designation);
|
||||
}
|
||||
|
||||
|
||||
@ -186,6 +202,65 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
return time.clone();
|
||||
}
|
||||
|
||||
/*
|
||||
* find the index to data that corresponds to the given time:
|
||||
*
|
||||
* Pseudo Index is two parts:
|
||||
* integer : simple index into the array
|
||||
* fractional part: [0,1]: weighting to interpolate between the given index and the next index.
|
||||
*
|
||||
* @param is time after motor ignition, in seconds
|
||||
* @return a pseudo index to this motor's data.
|
||||
*/
|
||||
public double getPseudoIndex( final double motorTime ){
|
||||
final double SNAP_DISTANCE = 0.001;
|
||||
|
||||
if( time.length == 0 ){
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
if( 0 > motorTime ){
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int lowerBoundIndex=0;
|
||||
int upperBoundIndex=0;
|
||||
while( ( upperBoundIndex < time.length ) && ( motorTime >= time[upperBoundIndex] )){
|
||||
++upperBoundIndex;
|
||||
}
|
||||
lowerBoundIndex = upperBoundIndex-1;
|
||||
if( upperBoundIndex == time.length ){
|
||||
return time.length - 1;
|
||||
}
|
||||
|
||||
if ( SNAP_DISTANCE > Math.abs( motorTime - time[lowerBoundIndex])){
|
||||
return lowerBoundIndex;
|
||||
}
|
||||
|
||||
double lowerBoundTime = time[lowerBoundIndex];
|
||||
double upperBoundTime = time[upperBoundIndex];
|
||||
double timeFraction = motorTime - lowerBoundTime;
|
||||
double indexFraction = ( timeFraction ) / ( upperBoundTime - lowerBoundTime );
|
||||
|
||||
if( indexFraction < SNAP_DISTANCE ){
|
||||
// round down to last index
|
||||
return lowerBoundIndex;
|
||||
}else if( indexFraction > (1-SNAP_DISTANCE)){
|
||||
// round up to next index
|
||||
return ++lowerBoundIndex;
|
||||
}else{
|
||||
// general case
|
||||
return lowerBoundIndex + indexFraction;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getThrustAtMotorTime( final double searchTime ){
|
||||
double pseudoIndex = getPseudoIndex( searchTime );
|
||||
return getThrustAtIndex( pseudoIndex );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the array of thrust points for this thrust curve.
|
||||
* @return an array of thrust samples
|
||||
@ -194,14 +269,26 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
return thrust.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of CG points for this thrust curve.
|
||||
* @return an array of CG samples
|
||||
*/
|
||||
public Coordinate[] getCGPoints() {
|
||||
// /**
|
||||
// * Returns the array of CG points for this thrust curve.
|
||||
// * @return an array of CG samples
|
||||
// */
|
||||
// public double[] getCGxPoints() {
|
||||
// return cgx;
|
||||
// }
|
||||
|
||||
public Coordinate[] getCGPoints(){
|
||||
return cg.clone();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns the array of Mass values for this thrust curve.
|
||||
// * @return an array of Masses
|
||||
// */
|
||||
// public double[] getMassPoints() {
|
||||
// return mass;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Return a list of standard delays defined for this motor.
|
||||
* @return a list of standard delays
|
||||
@ -221,6 +308,25 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
return type;
|
||||
}
|
||||
|
||||
public double getUnitLongitudinalInertia() {
|
||||
return this.unitLongitudinalInertia;
|
||||
}
|
||||
|
||||
public double getUnitRotationalInertia() {
|
||||
return this.unitRotationalInertia;
|
||||
}
|
||||
|
||||
public double getIxxAtTime( final double searchTime) {
|
||||
final double index = getPseudoIndex( searchTime);
|
||||
//return this.unitLongitudinalInertia * this.getMassAtIndex( index);
|
||||
return this.unitLongitudinalInertia * this.getCGAtIndex( index).weight;
|
||||
}
|
||||
|
||||
public double getIyyAtTime( final double searchTime) {
|
||||
final double index = getPseudoIndex( searchTime);
|
||||
//return this.unitRotationalInertia * this.getMassAtIndex( index);
|
||||
return this.unitRotationalInertia * this.getCGAtIndex( index).weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesignation() {
|
||||
@ -248,29 +354,104 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ThrustCurveMotorState getNewInstance() {
|
||||
return new ThrustCurveMotorState(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Coordinate getLaunchCG() {
|
||||
return cg[0];
|
||||
public ThrustCurveMotor clone() {
|
||||
return new ThrustCurveMotor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate getEmptyCG() {
|
||||
return cg[cg.length - 1];
|
||||
public double getLaunchCGx() {
|
||||
return cg[0].x;//cgx[0];
|
||||
}
|
||||
|
||||
// Coordinate getCG(int index)
|
||||
// double getThrust( int index)
|
||||
// double getTime( int index)
|
||||
@Override
|
||||
public double getBurnoutCGx() {
|
||||
return cg[cg.length - 1].x;// cgx[ cg.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLaunchMass() {
|
||||
return cg[0].weight;//mass[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurnoutMass() {
|
||||
return cg[cg.length-1].weight; //mass[mass.length - 1];
|
||||
}
|
||||
|
||||
private static double interpolateValueAtIndex( final double[] values, final double pseudoIndex ){
|
||||
final double SNAP_TOLERANCE = 0.0001;
|
||||
|
||||
final double upperFrac = pseudoIndex%1;
|
||||
final double lowerFrac = 1-upperFrac;
|
||||
final int lowerIndex = (int)pseudoIndex;
|
||||
final int upperIndex= lowerIndex+1;
|
||||
|
||||
// if the pseudo
|
||||
if( SNAP_TOLERANCE > (1-lowerFrac) ){
|
||||
// index ~= int ... therefore:
|
||||
return values[ (int) pseudoIndex ];
|
||||
}else if( SNAP_TOLERANCE > upperFrac ){
|
||||
return values[ (int)upperIndex ];
|
||||
}
|
||||
|
||||
final double lowerValue = values[lowerIndex];
|
||||
final double upperValue = values[upperIndex];
|
||||
|
||||
// return simple linear interpolation
|
||||
return ( lowerValue*lowerFrac + upperValue*upperFrac );
|
||||
}
|
||||
|
||||
public double getThrustAtIndex( final double pseudoIndex ){
|
||||
return interpolateValueAtIndex( this.thrust, pseudoIndex );
|
||||
}
|
||||
|
||||
public double getMotorTimeAtIndex( final double index ){
|
||||
return interpolateValueAtIndex( this.time, index );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Coordinate getCGAtIndex( final double pseudoIndex ){
|
||||
final double SNAP_TOLERANCE = 0.0001;
|
||||
|
||||
final double upperFrac = pseudoIndex%1;
|
||||
final double lowerFrac = 1-upperFrac;
|
||||
final int lowerIndex = (int)pseudoIndex;
|
||||
final int upperIndex= lowerIndex+1;
|
||||
|
||||
// if the pseudo
|
||||
if( SNAP_TOLERANCE > (1-lowerFrac) ){
|
||||
// index ~= int ... therefore:
|
||||
return cg[ (int) pseudoIndex ];
|
||||
}else if( SNAP_TOLERANCE > upperFrac ){
|
||||
return cg[ (int)upperIndex ];
|
||||
}
|
||||
|
||||
final Coordinate lowerValue = cg[lowerIndex].multiply(lowerFrac);
|
||||
final Coordinate upperValue = cg[upperIndex].multiply(upperFrac);
|
||||
|
||||
// return simple linear interpolation
|
||||
return lowerValue.add( upperValue );
|
||||
}
|
||||
|
||||
|
||||
// public double getCGxAtIndex( final double index){
|
||||
// //return interpolateValueAtIndex( this.cgx, index );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public double getMassAtIndex( final double index){
|
||||
// //return interpolateValueAtIndex( this.mass, index );
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// int getCutoffIndex();
|
||||
|
||||
// double getCutoffTime()
|
||||
// int getCutoffIndex();
|
||||
// double interpolateThrust(...)
|
||||
|
||||
// Coordinate interpolateCG( ... )
|
||||
|
||||
//
|
||||
@ -304,7 +485,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor>, Se
|
||||
}
|
||||
|
||||
public double getCutOffTime() {
|
||||
return this.time[this.time.length - 1];
|
||||
return time[time.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,6 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
public class ThrustCurveMotorPlaceholder implements Motor {
|
||||
|
||||
@ -75,20 +73,10 @@ public class ThrustCurveMotorPlaceholder implements Motor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MotorState getNewInstance() {
|
||||
public Motor clone() {
|
||||
throw new BugException("Called getInstance on PlaceholderMotor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate getLaunchCG() {
|
||||
return new Coordinate(length / 2, 0, 0, launchMass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate getEmptyCG() {
|
||||
return new Coordinate(length / 2, 0, 0, emptyMass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurnTimeEstimate() {
|
||||
return Double.NaN;
|
||||
@ -184,4 +172,30 @@ public class ThrustCurveMotorPlaceholder implements Motor {
|
||||
+ ", designation=" + designation + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLaunchCGx() {
|
||||
return length / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurnoutCGx() {
|
||||
return length / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLaunchMass() {
|
||||
return launchMass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurnoutMass() {
|
||||
return emptyMass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double getThrustAtMotorTime(double pseudoIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,257 +0,0 @@
|
||||
package net.sf.openrocket.motor;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Inertia;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
public class ThrustCurveMotorState implements MotorState {
|
||||
// private static final Logger log = LoggerFactory.getLogger(ThrustCurveMotorInstance.class);
|
||||
|
||||
private int timeIndex = -1;
|
||||
|
||||
protected MotorMount mount = null;
|
||||
protected MotorInstanceId id = null;
|
||||
private double ignitionTime = -1;
|
||||
private double ignitionDelay;
|
||||
private IgnitionEvent ignitionEvent;
|
||||
private double ejectionDelay;
|
||||
|
||||
|
||||
protected ThrustCurveMotor motor = null;
|
||||
|
||||
// Previous time step value
|
||||
private double prevTime = Double.NaN;
|
||||
|
||||
// Average thrust during previous step
|
||||
private double stepThrust = Double.NaN;
|
||||
// Instantaneous thrust at current time point
|
||||
private double instThrust = Double.NaN;
|
||||
|
||||
// Average CG during previous step
|
||||
private Coordinate stepCG = Coordinate.ZERO;
|
||||
// Instantaneous CG at current time point
|
||||
private Coordinate instCG = Coordinate.ZERO;
|
||||
|
||||
private final double unitRotationalInertia;
|
||||
private final double unitLongitudinalInertia;
|
||||
|
||||
// // please use the Motor Constructor below, instead.
|
||||
// @SuppressWarnings("unused")
|
||||
// private ThrustCurveMotorInstance() {
|
||||
// unitRotationalInertia = Double.NaN;
|
||||
// unitLongitudinalInertia = Double.NaN;
|
||||
// }
|
||||
|
||||
public ThrustCurveMotorState(final ThrustCurveMotor source) {
|
||||
//log.debug( Creating motor instance of " + ThrustCurveMotor.this);
|
||||
this.motor = source;
|
||||
this.reset();
|
||||
|
||||
unitRotationalInertia = Inertia.filledCylinderRotational(source.getDiameter() / 2);
|
||||
unitLongitudinalInertia = Inertia.filledCylinderLongitudinal(source.getDiameter() / 2, source.getLength());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThrustCurveMotorState clone() {
|
||||
try {
|
||||
return (ThrustCurveMotorState) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new BugException("CloneNotSupportedException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIgnitionTime() {
|
||||
return ignitionTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIgnitionTime(double ignitionTime) {
|
||||
this.ignitionTime = ignitionTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MotorMount getMount() {
|
||||
return mount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMount(MotorMount mount) {
|
||||
this.mount = mount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IgnitionEvent getIgnitionEvent() {
|
||||
return ignitionEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIgnitionEvent(IgnitionEvent event) {
|
||||
this.ignitionEvent = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIgnitionDelay() {
|
||||
return ignitionDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIgnitionDelay(double delay) {
|
||||
this.ignitionDelay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getEjectionDelay() {
|
||||
return ejectionDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEjectionDelay(double delay) {
|
||||
this.ejectionDelay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(MotorInstanceId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MotorInstanceId getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public double getTime() {
|
||||
return prevTime;
|
||||
}
|
||||
|
||||
public Coordinate getCG() {
|
||||
return stepCG;
|
||||
}
|
||||
|
||||
public Coordinate getCM() {
|
||||
return stepCG;
|
||||
}
|
||||
|
||||
public double getPropellantMass(){
|
||||
return (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
|
||||
}
|
||||
|
||||
public double getLongitudinalInertia() {
|
||||
return unitLongitudinalInertia * stepCG.weight;
|
||||
}
|
||||
|
||||
public double getRotationalInertia() {
|
||||
return unitRotationalInertia * stepCG.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getThrust() {
|
||||
return stepThrust;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return prevTime < motor.getCutOffTime();
|
||||
}
|
||||
|
||||
public Motor getMotor(){
|
||||
return this.motor;
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void step(double nextTime, double acceleration, AtmosphericConditions cond) {
|
||||
if (MathUtil.equals(prevTime, nextTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double[] time = motor.getTimePoints();
|
||||
double[] thrust = motor.getThrustPoints();
|
||||
Coordinate[] cg = motor.getCGPoints();
|
||||
|
||||
if (timeIndex >= (motor.getDataSize() - 1)) {
|
||||
// Thrust has ended
|
||||
prevTime = nextTime;
|
||||
stepThrust = 0;
|
||||
instThrust = 0;
|
||||
stepCG = motor.getEmptyCG();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Compute average & instantaneous thrust
|
||||
if (nextTime < time[timeIndex + 1]) {
|
||||
|
||||
// Time step between time points
|
||||
double nextF = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
thrust[timeIndex], thrust[timeIndex + 1]);
|
||||
stepThrust = (instThrust + nextF) / 2;
|
||||
instThrust = nextF;
|
||||
|
||||
} else {
|
||||
|
||||
// Portion of previous step
|
||||
stepThrust = (instThrust + thrust[timeIndex + 1]) / 2 * (time[timeIndex + 1] - prevTime);
|
||||
|
||||
// Whole steps
|
||||
timeIndex++;
|
||||
while ((timeIndex < time.length - 1) && (nextTime >= time[timeIndex + 1])) {
|
||||
stepThrust += (thrust[timeIndex] + thrust[timeIndex + 1]) / 2 *
|
||||
(time[timeIndex + 1] - time[timeIndex]);
|
||||
timeIndex++;
|
||||
}
|
||||
|
||||
// End step
|
||||
if (timeIndex < time.length - 1) {
|
||||
instThrust = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
thrust[timeIndex], thrust[timeIndex + 1]);
|
||||
stepThrust += (thrust[timeIndex] + instThrust) / 2 *
|
||||
(nextTime - time[timeIndex]);
|
||||
} else {
|
||||
// Thrust ended during this step
|
||||
instThrust = 0;
|
||||
}
|
||||
|
||||
stepThrust /= (nextTime - prevTime);
|
||||
|
||||
}
|
||||
|
||||
// Compute average and instantaneous CG (simple average between points)
|
||||
Coordinate nextCG;
|
||||
if (timeIndex < time.length - 1) {
|
||||
nextCG = MathUtil.map(nextTime, time[timeIndex], time[timeIndex + 1],
|
||||
cg[timeIndex], cg[timeIndex + 1]);
|
||||
} else {
|
||||
nextCG = cg[cg.length - 1];
|
||||
}
|
||||
stepCG = instCG.add(nextCG).multiply(0.5);
|
||||
instCG = nextCG;
|
||||
|
||||
// Update time
|
||||
prevTime = nextTime;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
timeIndex = 0;
|
||||
prevTime = 0;
|
||||
instThrust = 0;
|
||||
stepThrust = 0;
|
||||
instCG = motor.getLaunchCG();
|
||||
stepCG = instCG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.motor.getDesignation();
|
||||
}
|
||||
|
||||
}
|
@ -528,12 +528,11 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(String.format("\nDumping %2d Motors for configuration %s: (#: %s)\n", this.motors.size(), this, this.instanceNumber));
|
||||
final String fmt = " ..[%-8s] <%6s> %-12s %-20s\n";
|
||||
buf.append(String.format(fmt, "Motor Id", "?active", "Mtr Desig","Mount"));
|
||||
buf.append(String.format(fmt, "Motor Id", "Mtr Desig","Mount"));
|
||||
for( MotorConfiguration curConfig : this.motors.values() ){
|
||||
MotorMount mount = curConfig.getMount();
|
||||
|
||||
String motorId = curConfig.getID().toShortKey();
|
||||
String activeDescr = (curConfig.isActive()? "active": "inactv");
|
||||
String motorDesig;
|
||||
if( curConfig.isEmpty() ){
|
||||
motorDesig = "(empty)";
|
||||
@ -542,7 +541,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
}
|
||||
String mountName = ((RocketComponent)mount).getName();
|
||||
|
||||
buf.append(String.format( fmt, motorId, activeDescr, motorDesig, mountName));
|
||||
buf.append(String.format( fmt, motorId, motorDesig, mountName));
|
||||
}
|
||||
buf.append("\n");
|
||||
return buf.toString();
|
||||
|
@ -170,19 +170,13 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
|
||||
|
||||
thrust = 0;
|
||||
final double currentTime = status.getSimulationTime() + timestep;
|
||||
Collection<MotorState> activeMotorList = status.getActiveMotors();
|
||||
for (MotorState currentMotorInstance : activeMotorList ) {
|
||||
Collection<MotorSimulation> activeMotorList = status.getMotors();
|
||||
for (MotorSimulation currentMotorState : activeMotorList ) {
|
||||
if ( !stepMotors ) {
|
||||
currentMotorInstance = currentMotorInstance.clone();
|
||||
currentMotorState = currentMotorState.clone();
|
||||
}
|
||||
// old: transplanted from MotorInstanceConfiguration
|
||||
double instanceTime = currentTime - currentMotorInstance.getIgnitionTime();
|
||||
if (instanceTime >= 0) {
|
||||
currentMotorInstance.step(instanceTime, acceleration, atmosphericConditions);
|
||||
}
|
||||
|
||||
// old: from here
|
||||
thrust += currentMotorInstance.getThrust();
|
||||
|
||||
thrust += currentMotorState.getThrust( currentTime, atmosphericConditions );
|
||||
}
|
||||
|
||||
// Post-listeners
|
||||
|
@ -194,11 +194,19 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
// Check for burnt out motors
|
||||
for( MotorState motor : currentStatus.getAllMotors()){
|
||||
MotorInstanceId motorId = motor.getID();
|
||||
if (!motor.isActive() && currentStatus.addBurntOutMotor(motorId)) {
|
||||
for( MotorSimulation state : currentStatus.getAllMotors()){
|
||||
|
||||
state.isFinishedThrusting( );
|
||||
|
||||
MotorInstanceId motorId = state.getID();
|
||||
|
||||
if ( state.isFinishedThrusting()){
|
||||
// TODO : implement me!
|
||||
//currentStatus.moveBurntOutMotor( motorId);
|
||||
currentStatus.addBurntOutMotor(motorId);
|
||||
|
||||
addEvent(new FlightEvent(FlightEvent.Type.BURNOUT, currentStatus.getSimulationTime(),
|
||||
(RocketComponent) motor.getMount(), motorId));
|
||||
(RocketComponent) state.getMount(), motorId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,7 +283,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
if (event.getType() == FlightEvent.Type.IGNITION) {
|
||||
MotorMount mount = (MotorMount) event.getSource();
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorState instance = currentStatus.getMotor(motorId);
|
||||
MotorSimulation instance = currentStatus.getMotor(motorId);
|
||||
if (!SimulationListenerHelper.fireMotorIgnition(currentStatus, motorId, mount, instance)) {
|
||||
continue;
|
||||
}
|
||||
@ -288,7 +296,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
}
|
||||
|
||||
// Check for motor ignition events, add ignition events to queue
|
||||
for (MotorState inst : currentStatus.getActiveMotors() ){
|
||||
for (MotorSimulation inst : currentStatus.getAllMotors() ){
|
||||
IgnitionEvent ignitionEvent = inst.getIgnitionEvent();
|
||||
MotorMount mount = inst.getMount();
|
||||
RocketComponent component = (RocketComponent) mount;
|
||||
@ -296,7 +304,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
if (ignitionEvent.isActivationEvent(event, component)) {
|
||||
double ignitionDelay = inst.getIgnitionDelay();
|
||||
// TODO: this event seems to get enque'd multiple times -- more than necessary...
|
||||
//System.err.println("Queing ignition of mtr:"+inst.getMotor().getDesignation()+" @"+currentStatus.getSimulationTime());
|
||||
//System.err.println("Queueing ignition of mtr:"+inst.getMotor().getDesignation()+" @"+currentStatus.getSimulationTime());
|
||||
addEvent(new FlightEvent(FlightEvent.Type.IGNITION,
|
||||
currentStatus.getSimulationTime() + ignitionDelay,
|
||||
component, inst.getID() ));
|
||||
@ -341,8 +349,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
case IGNITION: {
|
||||
// Ignite the motor
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorState inst = currentStatus.getMotor( motorId);
|
||||
inst.setIgnitionTime(event.getTime());
|
||||
MotorSimulation inst = currentStatus.getMotor( motorId);
|
||||
inst.ignite( event.getTime());
|
||||
//System.err.println("Igniting motor: "+inst.getMotor().getDesignation()+" @"+currentStatus.getSimulationTime());
|
||||
|
||||
currentStatus.setMotorIgnited(true);
|
||||
@ -370,10 +378,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
if (!currentStatus.isLiftoff()) {
|
||||
throw new SimulationLaunchException(trans.get("BasicEventSimulationEngine.error.earlyMotorBurnout"));
|
||||
}
|
||||
|
||||
// Add ejection charge event
|
||||
MotorInstanceId motorId = (MotorInstanceId) event.getData();
|
||||
MotorState motor = currentStatus.getMotor( motorId);
|
||||
double delay = motor.getEjectionDelay();
|
||||
MotorSimulation state = currentStatus.getMotor( motorId);
|
||||
double delay = state.getEjectionDelay();
|
||||
if (delay != Motor.PLUGGED) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, currentStatus.getSimulationTime() + delay,
|
||||
event.getSource(), event.getData()));
|
||||
|
160
core/src/net/sf/openrocket/simulation/MotorSimulation.java
Normal file
160
core/src/net/sf/openrocket/simulation/MotorSimulation.java
Normal file
@ -0,0 +1,160 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorConfiguration;
|
||||
import net.sf.openrocket.motor.MotorInstanceId;
|
||||
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
|
||||
public class MotorSimulation {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MotorSimulation.class);
|
||||
|
||||
// for reference: set at initialization ONLY.
|
||||
final protected Motor motor;
|
||||
final protected MotorConfiguration config;
|
||||
final protected double thrustDuration;
|
||||
|
||||
// for state:
|
||||
protected double ignitionTime = Double.NaN;
|
||||
protected double cutoffTime = Double.NaN;
|
||||
protected double ejectionTime = Double.NaN;
|
||||
protected MotorState currentState = MotorState.PREFLIGHT;
|
||||
|
||||
public MotorSimulation(final MotorConfiguration _config) {
|
||||
log.debug(" Creating motor instance of " + _config.getDescription());
|
||||
this.config = _config;
|
||||
this.motor = _config.getMotor();
|
||||
thrustDuration = this.motor.getBurnTimeEstimate();
|
||||
|
||||
this.resetToPreflight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MotorSimulation clone() {
|
||||
try {
|
||||
return (MotorSimulation) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new BugException("CloneNotSupportedException", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void arm( final double _armTime ){
|
||||
if( MotorState.PREFLIGHT == currentState ){
|
||||
log.info( "igniting motor: "+this.toString()+" at t="+_armTime);
|
||||
//this.ignitionTime = _ignitionTime;
|
||||
this.currentState = this.currentState.getNext();
|
||||
}else{
|
||||
throw new IllegalStateException("Attempted to arm a motor with status="+this.currentState.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFinishedThrusting(){
|
||||
return currentState.isAfter( MotorState.THRUSTING );
|
||||
}
|
||||
|
||||
public double getIgnitionTime() {
|
||||
return ignitionTime;
|
||||
}
|
||||
|
||||
public IgnitionEvent getIgnitionEvent() {
|
||||
return config.getIgnitionEvent();
|
||||
}
|
||||
|
||||
|
||||
public void ignite( final double _ignitionTime ){
|
||||
if( MotorState.ARMED == currentState ){
|
||||
log.info( "igniting motor: "+this.toString()+" at t="+_ignitionTime);
|
||||
this.ignitionTime = _ignitionTime;
|
||||
this.currentState = this.currentState.getNext();
|
||||
}else{
|
||||
throw new IllegalStateException("Attempted to ignite a motor state with status="+this.currentState.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void burnOut( final double _burnOutTime ){
|
||||
if( MotorState.THRUSTING == currentState ){
|
||||
log.info( "igniting motor: "+this.toString()+" at t="+_burnOutTime);
|
||||
this.ignitionTime = _burnOutTime;
|
||||
this.currentState = this.currentState.getNext();
|
||||
}else{
|
||||
throw new IllegalStateException("Attempted to stop thrust (burn-out) a motor state with status="+this.currentState.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void fireEjectionCharge( final double _ejectionTime ){
|
||||
if( MotorState.DELAYING == currentState ){
|
||||
log.info( "igniting motor: "+this.toString()+" at t="+_ejectionTime);
|
||||
this.ejectionTime = _ejectionTime;
|
||||
this.currentState = this.currentState.getNext();
|
||||
}else{
|
||||
throw new IllegalStateException("Attempted to fire an ejection charge in motor state: "+this.currentState.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Alias for "burnOut(double)"
|
||||
*/
|
||||
public void cutOff( final double _cutoffTime ){
|
||||
burnOut( _cutoffTime );
|
||||
}
|
||||
|
||||
public double getIgnitionDelay() {
|
||||
return config.getEjectionDelay();
|
||||
}
|
||||
|
||||
public double getEjectionDelay() {
|
||||
return config.getEjectionDelay();
|
||||
}
|
||||
|
||||
public MotorInstanceId getID() {
|
||||
return config.getID();
|
||||
}
|
||||
|
||||
public double getPropellantMass(){
|
||||
return (motor.getLaunchMass() - motor.getBurnoutMass());
|
||||
}
|
||||
|
||||
// public boolean isActive( ) {
|
||||
// return this.currentState.isActive();
|
||||
// }
|
||||
|
||||
public MotorMount getMount(){
|
||||
return config.getMount();
|
||||
}
|
||||
|
||||
public Motor getMotor(){
|
||||
return this.motor;
|
||||
}
|
||||
|
||||
double getCutOffTime(){
|
||||
return this.cutoffTime;
|
||||
}
|
||||
|
||||
public double getThrust( final double simTime, final AtmosphericConditions cond){
|
||||
if( this.currentState.isThrusting() ){
|
||||
return motor.getThrustAtMotorTime( simTime - this.getIgnitionTime());
|
||||
}else{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetToPreflight(){
|
||||
ignitionTime = Double.NaN;
|
||||
cutoffTime = Double.NaN;
|
||||
ejectionTime = Double.NaN;
|
||||
currentState = MotorState.PREFLIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.motor.getDesignation();
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +1,104 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.motor.MotorInstanceId;
|
||||
import net.sf.openrocket.rocketcomponent.IgnitionEvent;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
|
||||
public interface MotorState extends Cloneable {
|
||||
|
||||
public void step(double nextTime, double acceleration, AtmosphericConditions cond);
|
||||
public double getThrust();
|
||||
public boolean isActive();
|
||||
|
||||
public double getIgnitionTime();
|
||||
public void setIgnitionTime( double ignitionTime );
|
||||
public enum MotorState {
|
||||
FINISHED("Finished with sequence.", "Finished Producing thrust.", null)
|
||||
,DELAYING("Delaying", " After Burnout, but before ejection", FINISHED){
|
||||
@Override
|
||||
public boolean needsSimulation(){ return true;}
|
||||
}
|
||||
,THRUSTING("Thrusting", "Currently Producing thrust", DELAYING){
|
||||
@Override
|
||||
public boolean isThrusting(){ return true; }
|
||||
@Override
|
||||
public boolean needsSimulation(){ return true;}
|
||||
}
|
||||
,ARMED("Armed", "Armed, but not yet lit.", FINISHED)
|
||||
,PREFLIGHT("Pre-Launch", "Safed and inactive, prior to launch.", FINISHED)
|
||||
;
|
||||
|
||||
public void setMount(MotorMount mount);
|
||||
public MotorMount getMount();
|
||||
|
||||
public void setId(MotorInstanceId id);
|
||||
public MotorInstanceId getID();
|
||||
private final static int SEQUENCE_NUMBER_END = 10; // arbitrary number
|
||||
|
||||
public IgnitionEvent getIgnitionEvent();
|
||||
public void setIgnitionEvent( IgnitionEvent event );
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final int sequenceNumber;
|
||||
private final MotorState nextState;
|
||||
|
||||
public double getIgnitionDelay();
|
||||
public void setIgnitionDelay( double delay );
|
||||
MotorState( final String name, final String description, final MotorState _nextState) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
if( null == _nextState ){
|
||||
this.sequenceNumber = SEQUENCE_NUMBER_END;
|
||||
this.nextState = null;
|
||||
}else{
|
||||
this.sequenceNumber = -1 + _nextState.getSequenceNumber() ;
|
||||
this.nextState = _nextState;
|
||||
}
|
||||
}
|
||||
|
||||
public double getEjectionDelay();
|
||||
public void setEjectionDelay( double delay);
|
||||
/**
|
||||
* Return a short name of this motor type.
|
||||
* @return a short name of the motor type.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public MotorState clone();
|
||||
|
||||
/*
|
||||
*
|
||||
* @Return a MotorState enum telling what state should follow this one.
|
||||
*/
|
||||
public MotorState getNext( ){
|
||||
return this.nextState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a long description of this motor type.
|
||||
* @return a description of the motor type.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequence numbers have no intrinsic meaning, but their sequence (and relative value)
|
||||
* indicate which states occur before other states.
|
||||
* @see isAfter(MotorState)
|
||||
* @see isBefore(MotorState)
|
||||
* @return integer indicating this state's place in the allowable sequence
|
||||
*/
|
||||
public int getSequenceNumber(){
|
||||
return this.sequenceNumber;
|
||||
}
|
||||
|
||||
public boolean isAfter( final MotorState other ){
|
||||
return this.getSequenceNumber() > other.getSequenceNumber();
|
||||
}
|
||||
public boolean isBefore( final MotorState other ){
|
||||
return this.getSequenceNumber() < other.getSequenceNumber();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If this motor is in a state which produces thrust
|
||||
*/
|
||||
public boolean isThrusting(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This flag determines whether the motor has its state updated, and updates of cg and thrust updated.
|
||||
* A motor instance will always receive events -- which may affect the simulation yes/no state
|
||||
*
|
||||
* @return should this motor be simulated
|
||||
*/
|
||||
public boolean needsSimulation(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ public class SimulationStatus implements Monitorable {
|
||||
private double effectiveLaunchRodLength;
|
||||
|
||||
// Set of burnt out motors
|
||||
Set<MotorInstanceId> motorBurntOut = new HashSet<MotorInstanceId>();
|
||||
Set<MotorInstanceId> spentMotors = new HashSet<MotorInstanceId>();
|
||||
|
||||
List<MotorState> motorState = new ArrayList<MotorState>();
|
||||
List<MotorSimulation> motorStateList = new ArrayList<MotorSimulation>();
|
||||
|
||||
/** Nanosecond time when the simulation was started. */
|
||||
private long simulationStartWallTime = Long.MIN_VALUE;
|
||||
@ -148,11 +148,10 @@ public class SimulationStatus implements Monitorable {
|
||||
this.launchRodCleared = false;
|
||||
this.apogeeReached = false;
|
||||
|
||||
for( MotorConfiguration motorInstance : this.configuration.getActiveMotors() ) {
|
||||
this.motorState.add( motorInstance.getSimulationState() );
|
||||
for( MotorConfiguration motorConfig : this.configuration.getActiveMotors() ) {
|
||||
this.motorStateList.add( new MotorSimulation( motorConfig) );
|
||||
}
|
||||
this.warnings = new WarningSet();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,14 +184,14 @@ public class SimulationStatus implements Monitorable {
|
||||
this.launchRodCleared = orig.launchRodCleared;
|
||||
this.apogeeReached = orig.apogeeReached;
|
||||
this.tumbling = orig.tumbling;
|
||||
this.motorBurntOut = orig.motorBurntOut;
|
||||
this.spentMotors = orig.spentMotors;
|
||||
|
||||
this.deployedRecoveryDevices.clear();
|
||||
this.deployedRecoveryDevices.addAll(orig.deployedRecoveryDevices);
|
||||
|
||||
// FIXME - is this right?
|
||||
this.motorState.clear();
|
||||
this.motorState.addAll(orig.motorState);
|
||||
this.motorStateList.clear();
|
||||
this.motorStateList.addAll(orig.motorStateList);
|
||||
|
||||
this.eventQueue.clear();
|
||||
this.eventQueue.addAll(orig.eventQueue);
|
||||
@ -225,21 +224,25 @@ public class SimulationStatus implements Monitorable {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public Collection<MotorState> getAllMotors() {
|
||||
return motorState;
|
||||
public Collection<MotorSimulation> getMotors() {
|
||||
return motorStateList;
|
||||
}
|
||||
|
||||
public Collection<MotorState> getActiveMotors() {
|
||||
List<MotorState> activeList = new ArrayList<MotorState>();
|
||||
for( MotorState inst : this.motorState ){
|
||||
if( inst.isActive() ){
|
||||
activeList.add( inst );
|
||||
}
|
||||
}
|
||||
|
||||
return activeList;
|
||||
public Collection<MotorSimulation> getAllMotors() {
|
||||
return motorStateList;
|
||||
}
|
||||
|
||||
// public Collection<MotorInstance> getActiveMotors() {
|
||||
// List<MotorInstance> activeList = new ArrayList<MotorInstance>();
|
||||
// for( MotorInstance inst : this.motorStateList ){
|
||||
// if( inst.isActive() ){
|
||||
// activeList.add( inst );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return activeList;
|
||||
// }
|
||||
|
||||
public FlightConfiguration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
@ -260,8 +263,8 @@ public class SimulationStatus implements Monitorable {
|
||||
return flightData;
|
||||
}
|
||||
|
||||
public MotorState getMotor( final MotorInstanceId motorId ){
|
||||
for( MotorState state : motorState ) {
|
||||
public MotorSimulation getMotor( final MotorInstanceId motorId ){
|
||||
for( MotorSimulation state : motorStateList ) {
|
||||
if ( motorId.equals(state.getID() )) {
|
||||
return state;
|
||||
}
|
||||
@ -310,8 +313,15 @@ public class SimulationStatus implements Monitorable {
|
||||
}
|
||||
|
||||
|
||||
public boolean moveBurntOutMotor( final MotorInstanceId motor) {
|
||||
// get motor from normal list
|
||||
// remove motor from 'normal' list
|
||||
// add to spent list
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean addBurntOutMotor(MotorInstanceId motor) {
|
||||
return motorBurntOut.add(motor);
|
||||
return spentMotors.add(motor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.simulation.AccelerationData;
|
||||
import net.sf.openrocket.simulation.FlightEvent;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.simulation.MotorSimulation;
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.exception.SimulationListenerException;
|
||||
@ -105,7 +105,7 @@ public class ScriptingSimulationListener implements SimulationListener, Simulati
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorState instance) throws SimulationException {
|
||||
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorSimulation instance) throws SimulationException {
|
||||
return invoke(Boolean.class, true, "motorIgnition", status, motorId, mount, instance);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.simulation.AccelerationData;
|
||||
import net.sf.openrocket.simulation.FlightEvent;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.simulation.MotorSimulation;
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
@ -72,7 +72,7 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorState instance) throws SimulationException {
|
||||
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount, MotorSimulation instance) throws SimulationException {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import net.sf.openrocket.motor.MotorInstanceId;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.simulation.FlightEvent;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.simulation.MotorSimulation;
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
|
||||
@ -44,7 +44,7 @@ public interface SimulationEventListener {
|
||||
* @return <code>true</code> to ignite the motor, <code>false</code> to abort ignition
|
||||
*/
|
||||
public boolean motorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount,
|
||||
MotorState instance) throws SimulationException;
|
||||
MotorSimulation instance) throws SimulationException;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.simulation.AccelerationData;
|
||||
import net.sf.openrocket.simulation.FlightEvent;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.simulation.MotorSimulation;
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -168,7 +168,7 @@ public class SimulationListenerHelper {
|
||||
* @return <code>true</code> to handle the event normally, <code>false</code> to skip event.
|
||||
*/
|
||||
public static boolean fireMotorIgnition(SimulationStatus status, MotorInstanceId motorId, MotorMount mount,
|
||||
MotorState instance) throws SimulationException {
|
||||
MotorSimulation instance) throws SimulationException {
|
||||
boolean b;
|
||||
int modID = status.getModID(); // Contains also motor instance
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class DampingMoment extends AbstractSimulationListener {
|
||||
FlightConfiguration config = status.getConfiguration();
|
||||
for (MotorConfiguration inst : config.getActiveMotors()) {
|
||||
double x_position= inst.getX();
|
||||
double x = x_position + inst.getMotor().getLaunchCG().x;
|
||||
double x = x_position + inst.getMotor().getLaunchCGx();
|
||||
if (x > nozzleDistance) {
|
||||
nozzleDistance = x;
|
||||
}
|
||||
|
@ -55,10 +55,10 @@ public class MotorCheck {
|
||||
// sum += m.getTotalTime();
|
||||
sum += m.getDiameter();
|
||||
sum += m.getLength();
|
||||
sum += m.getEmptyCG().weight;
|
||||
sum += m.getEmptyCG().x;
|
||||
sum += m.getLaunchCG().weight;
|
||||
sum += m.getLaunchCG().x;
|
||||
sum += m.getBurnoutMass();
|
||||
sum += m.getBurnoutCGx();
|
||||
sum += m.getLaunchMass();
|
||||
sum += m.getLaunchCGx();
|
||||
sum += m.getMaxThrustEstimate();
|
||||
if (Double.isInfinite(sum) || Double.isNaN(sum)) {
|
||||
System.out.println("ERROR: Invalid motor values");
|
||||
|
@ -211,7 +211,7 @@ public class MotorCompare {
|
||||
min = Double.MAX_VALUE;
|
||||
System.out.printf("Init mass :");
|
||||
for (Motor m : motors) {
|
||||
double f = m.getLaunchCG().weight;
|
||||
double f = m.getLaunchMass();
|
||||
System.out.printf("\t%.2f", f * 1000);
|
||||
max = Math.max(max, f);
|
||||
min = Math.min(min, f);
|
||||
@ -229,7 +229,7 @@ public class MotorCompare {
|
||||
min = Double.MAX_VALUE;
|
||||
System.out.printf("Empty mass :");
|
||||
for (Motor m : motors) {
|
||||
double f = m.getEmptyCG().weight;
|
||||
double f = m.getBurnoutMass();
|
||||
System.out.printf("\t%.2f", f * 1000);
|
||||
max = Math.max(max, f);
|
||||
min = Math.min(min, f);
|
||||
|
@ -8,10 +8,8 @@ import java.util.List;
|
||||
|
||||
import net.sf.openrocket.file.motor.GeneralMotorLoader;
|
||||
import net.sf.openrocket.file.motor.MotorLoader;
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||
import net.sf.openrocket.simulation.MotorState;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
@ -60,30 +58,23 @@ public class MotorCorrelation {
|
||||
* @param motor2 the second motor.
|
||||
* @return the scaled cross-correlation of the two thrust curves.
|
||||
*/
|
||||
public static double crossCorrelation(Motor motor1, Motor motor2) {
|
||||
MotorState m1 = motor1.getNewInstance();
|
||||
MotorState m2 = motor2.getNewInstance();
|
||||
|
||||
AtmosphericConditions cond = new AtmosphericConditions();
|
||||
|
||||
public static double crossCorrelation(Motor motor1, Motor motor2) {
|
||||
double t;
|
||||
double auto1 = 0;
|
||||
double auto2 = 0;
|
||||
double cross = 0;
|
||||
for (t = 0; t < 1000; t += 0.01) {
|
||||
m1.step(t, 0, cond);
|
||||
m2.step(t, 0, cond);
|
||||
|
||||
double t1 = m1.getThrust();
|
||||
double t2 = m2.getThrust();
|
||||
double thrust1 = motor1.getThrustAtMotorTime( t);
|
||||
double thrust2 = motor2.getThrustAtMotorTime( t);
|
||||
|
||||
if (t1 < 0 || t2 < 0) {
|
||||
throw new BugException("Negative thrust, t1=" + t1 + " t2=" + t2);
|
||||
if ( thrust1 < 0 || thrust2 < 0) {
|
||||
throw new BugException("Negative thrust, t1=" + thrust1 + " t2=" + thrust2);
|
||||
}
|
||||
|
||||
auto1 += t1 * t1;
|
||||
auto2 += t2 * t2;
|
||||
cross += t1 * t2;
|
||||
auto1 += thrust1 * thrust1;
|
||||
auto2 += thrust2 * thrust2;
|
||||
cross += thrust1 * thrust2;
|
||||
}
|
||||
|
||||
double auto = Math.max(auto1, auto2);
|
||||
|
@ -304,8 +304,8 @@ public class MassCalculatorTest extends BaseTestCase {
|
||||
|
||||
double expLaunchMass = 0.0164; // kg
|
||||
double expSpentMass = 0.0131; // kg
|
||||
assertEquals(" Motor Mass "+desig+" is incorrect: ", expLaunchMass, activeMotor.getLaunchCG().weight, EPSILON);
|
||||
assertEquals(" Motor Mass "+desig+" is incorrect: ", expSpentMass, activeMotor.getEmptyCG().weight, EPSILON);
|
||||
assertEquals(" Motor Mass "+desig+" is incorrect: ", expLaunchMass, activeMotor.getLaunchMass(), EPSILON);
|
||||
assertEquals(" Motor Mass "+desig+" is incorrect: ", expSpentMass, activeMotor.getBurnoutMass(), EPSILON);
|
||||
|
||||
// Validate Booster Launch Mass
|
||||
MassCalculator mc = new MassCalculator();
|
||||
|
@ -5,16 +5,13 @@ import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Inertia;
|
||||
|
||||
public class ThrustCurveMotorTest {
|
||||
|
||||
private final double EPS = 0.000001;
|
||||
// private final double EPSILON = 0.000001;
|
||||
|
||||
private final double radius = 0.025;
|
||||
private final double length = 0.10;
|
||||
private final double longitudinal = Inertia.filledCylinderLongitudinal(radius, length);
|
||||
private final double rotational = Inertia.filledCylinderRotational(radius);
|
||||
|
||||
private final ThrustCurveMotor motor =
|
||||
new ThrustCurveMotor(Manufacturer.getManufacturer("foo"),
|
||||
@ -38,38 +35,118 @@ public class ThrustCurveMotorTest {
|
||||
assertEquals(Motor.Type.RELOAD, motor.getMotorType());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeIndexingNegative(){
|
||||
// attempt to retrieve for a time before the motor ignites
|
||||
assertEquals( 0.0, motor.getPseudoIndex( -1 ), 0.001 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeRetrieval(){
|
||||
// attempt to retrieve an integer index:
|
||||
assertEquals( 0.0, motor.getMotorTimeAtIndex( 0 ), 0.001 );
|
||||
assertEquals( 1.0, motor.getMotorTimeAtIndex( 1 ), 0.001 );
|
||||
assertEquals( 4.0, motor.getMotorTimeAtIndex( 3 ), 0.001 );
|
||||
|
||||
final double searchTime = 0.2;
|
||||
assertEquals( searchTime, motor.getMotorTimeAtIndex( motor.getPseudoIndex(searchTime)), 0.001 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstance() {
|
||||
ThrustCurveMotorState instance = motor.getNewInstance();
|
||||
|
||||
verify(instance, 0, 0.05, 0.02);
|
||||
instance.step(0.0, 0, null);
|
||||
verify(instance, 0, 0.05, 0.02);
|
||||
instance.step(0.5, 0, null);
|
||||
verify(instance, 0.5, 0.05, 0.02);
|
||||
instance.step(1.5, 0, null);
|
||||
verify(instance, (1.5 + 2.125)/2, 0.05, 0.02);
|
||||
instance.step(2.5, 0, null);
|
||||
verify(instance, (2.125 + 2.875)/2, 0.05, 0.02);
|
||||
instance.step(3.0, 0, null);
|
||||
verify(instance, (2+3.0/4 + 3)/2, 0.05, 0.02);
|
||||
instance.step(3.5, 0, null);
|
||||
verify(instance, (1.5 + 3)/2, 0.045, 0.0225);
|
||||
instance.step(4.5, 0, null);
|
||||
// mass and cg is simply average of the end points
|
||||
verify(instance, 1.5/4, 0.035, 0.0275);
|
||||
instance.step(5.0, 0, null);
|
||||
verify(instance, 0, 0.03, 0.03);
|
||||
public void testThrustRetrieval(){
|
||||
// attempt to retrieve an integer index:
|
||||
assertEquals( 2.0, motor.getThrustAtIndex( 1 ), 0.001 );
|
||||
assertEquals( 3.0, motor.getThrustAtIndex( 2 ), 0.001 );
|
||||
assertEquals( 0.0, motor.getThrustAtIndex( 3 ), 0.001 );
|
||||
}
|
||||
|
||||
private void verify(ThrustCurveMotorState instance, double thrust, double mass, double cgx) {
|
||||
assertEquals("Testing thrust", thrust, instance.getThrust(), EPS);
|
||||
assertEquals("Testing mass", mass, instance.getCG().weight, EPS);
|
||||
assertEquals("Testing cg x", cgx, instance.getCG().x, EPS);
|
||||
assertEquals("Testing longitudinal inertia", mass*longitudinal, instance.getLongitudinalInertia(), EPS);
|
||||
assertEquals("Testing rotational inertia", mass*rotational, instance.getRotationalInertia(), EPS);
|
||||
// using better interface
|
||||
// @Test
|
||||
// public void testCGRetrievalByDouble(){
|
||||
// final double actCGx0 = motor.getCGxAtIndex( 0.0 );
|
||||
// assertEquals( 0.02, actCGx0, 0.001 );
|
||||
// final double actMass0 = motor.getMassAtIndex( 0.0 );
|
||||
// assertEquals( 0.05, actMass0, 0.001 );
|
||||
//
|
||||
// final double actCGx25 = motor.getCGxAtIndex( 2.5 );
|
||||
// assertEquals( 0.025, actCGx25, 0.001 );
|
||||
// final double actMass25 = motor.getMassAtIndex( 2.5 );
|
||||
// assertEquals( 0.04, actMass25, 0.001 );
|
||||
// }
|
||||
|
||||
// deprecated version.
|
||||
// delete this method upon change to new function signatures
|
||||
@Test
|
||||
public void testCGRetrieval(){
|
||||
final double actCGx0 = motor.getCGAtIndex( 0.0 ).x;
|
||||
assertEquals( 0.02, actCGx0, 0.001 );
|
||||
final double actMass0 = motor.getCGAtIndex( 0.0 ).weight;
|
||||
assertEquals( 0.05, actMass0, 0.001 );
|
||||
|
||||
final double actCGx25 = motor.getCGAtIndex( 2.5 ).x;
|
||||
assertEquals( 0.025, actCGx25, 0.001 );
|
||||
final double actMass25 = motor.getCGAtIndex( 2.5 ).weight;
|
||||
assertEquals( 0.04, actMass25, 0.001 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeIndexingPastEnd(){
|
||||
// attempt to retrieve for a time after motor cutoff
|
||||
assertEquals( 3.0, motor.getPseudoIndex( 5.0), 0.001 );
|
||||
}
|
||||
@Test
|
||||
public void testTimeIndexingAtEnd(){
|
||||
// attempt to retrieve for a time just at motor cutoff
|
||||
assertEquals( 3.0, motor.getPseudoIndex( 4.0), 0.001 );
|
||||
}
|
||||
@Test
|
||||
public void testTimeIndexingDuring(){
|
||||
// attempt to retrieve for a generic time during the motor's burn
|
||||
assertEquals( 1.6, motor.getPseudoIndex( 2.2), 0.001 );
|
||||
}
|
||||
@Test
|
||||
public void testTimeIndexingSnapUp(){
|
||||
// attempt to retrieve for a generic time during the motor's burn
|
||||
assertEquals( 3.0, motor.getPseudoIndex( 3.9999), 0.001 );
|
||||
}
|
||||
@Test
|
||||
public void testTimeIndexingSnapDown(){
|
||||
// attempt to retrieve for a generic time during the motor's burn
|
||||
assertEquals( 2.0, motor.getPseudoIndex( 3.0001), 0.001 );
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testInstance() {
|
||||
// ThrustCurveMotorState instance = motor.getNewInstance();
|
||||
//
|
||||
// verify(instance, 0, 0.05, 0.02);
|
||||
// instance.step(0.0, null);
|
||||
// verify(instance, 0, 0.05, 0.02);
|
||||
// instance.step(0.5, null);
|
||||
// verify(instance, 0.5, 0.05, 0.02);
|
||||
// instance.step(1.5, null);
|
||||
// verify(instance, (1.5 + 2.125)/2, 0.05, 0.02);
|
||||
// instance.step(2.5, null);
|
||||
// verify(instance, (2.125 + 2.875)/2, 0.05, 0.02);
|
||||
// instance.step(3.0, null);
|
||||
// verify(instance, (2+3.0/4 + 3)/2, 0.05, 0.02);
|
||||
// instance.step(3.5, null);
|
||||
// verify(instance, (1.5 + 3)/2, 0.045, 0.0225);
|
||||
// instance.step(4.5, null);
|
||||
// // mass and cg is simply average of the end points
|
||||
// verify(instance, 1.5/4, 0.035, 0.0275);
|
||||
// instance.step(5.0, null);
|
||||
// verify(instance, 0, 0.03, 0.03);
|
||||
// }
|
||||
//
|
||||
// private void verify(ThrustCurveMotorState instance, double thrust, double mass, double cgx) {
|
||||
// assertEquals("Testing thrust", thrust, instance.getThrust(), EPS);
|
||||
// assertEquals("Testing mass", mass, instance.getCG().weight, EPS);
|
||||
// assertEquals("Testing cg x", cgx, instance.getCG().x, EPS);
|
||||
// assertEquals("Testing longitudinal inertia", mass*longitudinal, instance.getMotor().getLongitudinalInertia(), EPS);
|
||||
// assertEquals("Testing rotational inertia", mass*rotational, instance.getMotor().getRotationalInertia(), EPS);
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
|
||||
import net.sf.openrocket.file.iterator.DirectoryIterator;
|
||||
import net.sf.openrocket.file.iterator.FileIterator;
|
||||
@ -20,9 +23,6 @@ import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Pair;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An asynchronous database loader that loads the internal thrust curves
|
||||
* and external user-supplied thrust curves to a ThrustCurveMotorSetDatabase.
|
||||
|
@ -21,9 +21,8 @@ import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class MotorChooserDialog extends JDialog implements CloseableDialog {
|
||||
|
||||
private static final long serialVersionUID = 6903386330489783515L;
|
||||
|
||||
private final ThrustCurveMotorSelectionPanel selectionPanel;
|
||||
|
||||
|
@ -16,14 +16,6 @@ import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.gui.util.GUIUtil;
|
||||
import net.sf.openrocket.gui.util.Icons;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
@ -34,6 +26,14 @@ import org.jfree.chart.title.TextTitle;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.gui.util.GUIUtil;
|
||||
import net.sf.openrocket.gui.util.Icons;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class MotorInformationPanel extends JPanel {
|
||||
|
||||
@ -230,7 +230,7 @@ class MotorInformationPanel extends JPanel {
|
||||
|
||||
this.selectedMotorSet = motors;
|
||||
this.selectedMotor = selectedMotor;
|
||||
|
||||
|
||||
// Update thrust curve data
|
||||
double impulse = selectedMotor.getTotalImpulseEstimate();
|
||||
MotorClass mc = MotorClass.getMotorClass(impulse);
|
||||
@ -246,9 +246,9 @@ class MotorInformationPanel extends JPanel {
|
||||
burnTimeLabel.setText(UnitGroup.UNITS_SHORT_TIME.getDefaultUnit().toStringUnit(
|
||||
selectedMotor.getBurnTimeEstimate()));
|
||||
launchMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
|
||||
selectedMotor.getLaunchCG().weight));
|
||||
selectedMotor.getLaunchMass()));
|
||||
emptyMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
|
||||
selectedMotor.getEmptyCG().weight));
|
||||
selectedMotor.getBurnoutMass()));
|
||||
dataPointsLabel.setText("" + (selectedMotor.getTimePoints().length - 1));
|
||||
if (digestLabel != null) {
|
||||
digestLabel.setText(selectedMotor.getDigest());
|
||||
|
@ -151,11 +151,11 @@ enum ThrustCurveMotorColumns {
|
||||
UnitGroup.UNITS_IMPULSE.getDefaultUnit()
|
||||
.toStringUnit(m.getTotalImpulseEstimate()) + "<br>");
|
||||
tip += (trans.get("TCurveMotor.ttip.launchMass") + " " +
|
||||
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(m.getLaunchCG().weight) +
|
||||
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(m.getLaunchMass()) +
|
||||
"<br>");
|
||||
tip += (trans.get("TCurveMotor.ttip.emptyMass") + " " +
|
||||
UnitGroup.UNITS_MASS.getDefaultUnit()
|
||||
.toStringUnit(m.getEmptyCG().weight));
|
||||
.toStringUnit(m.getBurnoutMass()));
|
||||
return tip;
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ public class DesignReport {
|
||||
motorTable.addCell(ITextHelper.createCell(
|
||||
ttwFormat.format(ttw) + ":1", border));
|
||||
|
||||
double propMass = (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
|
||||
double propMass = (motor.getLaunchMass() - motor.getBurnoutMass());
|
||||
motorTable.addCell(ITextHelper.createCell(
|
||||
UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user