[#2137] Import mass and CG from RASAero sims
This commit is contained in:
parent
6490b08847
commit
b302718211
@ -112,15 +112,29 @@ public class RASAeroCommonConstants {
|
|||||||
public static final String SIMULATION_LIST = "SimulationList";
|
public static final String SIMULATION_LIST = "SimulationList";
|
||||||
public static final String SIMULATION = "Simulation";
|
public static final String SIMULATION = "Simulation";
|
||||||
public static final String SUSTAINER_ENGINE = "SustainerEngine";
|
public static final String SUSTAINER_ENGINE = "SustainerEngine";
|
||||||
// TODO: SustainerLaunchWt, SustainerCG?
|
public static final String SUSTAINER_LAUNCH_WT = "SustainerLaunchWt";
|
||||||
|
public static final String SUSTAINER_NOZZLE_DIAMETER = "SustainerNozzleDiameter";
|
||||||
|
public static final String SUSTAINER_CG = "SustainerCG";
|
||||||
public static final String SUSTAINER_IGNITION_DELAY = "SustainerIgnitionDelay";
|
public static final String SUSTAINER_IGNITION_DELAY = "SustainerIgnitionDelay";
|
||||||
public static final String BOOSTER1_ENGINE = "Booster1Engine";
|
public static final String BOOSTER1_ENGINE = "Booster1Engine";
|
||||||
public static final String BOOSTER1_SEPARATION_DELAY = "Booster1SeparationDelay"; // Delay after booster burnout to separate
|
public static final String BOOSTER1_SEPARATION_DELAY = "Booster1SeparationDelay"; // Delay after booster burnout to separate
|
||||||
public static final String BOOSTER1_IGNITION_DELAY = "Booster1IgnitionDelay";
|
public static final String BOOSTER1_IGNITION_DELAY = "Booster1IgnitionDelay";
|
||||||
|
public static final String BOOSTER1_LAUNCH_WT = "Booster1LaunchWt";
|
||||||
|
public static final String BOOSTER1_NOZZLE_DIAMETER = "Booster1NozzleDiameter";
|
||||||
|
public static final String BOOSTER1_CG = "Booster1CG";
|
||||||
public static final String INCLUDE_BOOSTER1 = "IncludeBooster1";
|
public static final String INCLUDE_BOOSTER1 = "IncludeBooster1";
|
||||||
public static final String BOOSTER2_ENGINE = "Booster2Engine";
|
public static final String BOOSTER2_ENGINE = "Booster2Engine";
|
||||||
public static final String BOOSTER2_SEPARATION_DELAY = "Booster2Delay"; // Delay after booster burnout to separate
|
public static final String BOOSTER2_SEPARATION_DELAY = "Booster2Delay"; // Delay after booster burnout to separate
|
||||||
|
public static final String BOOSTER2_LAUNCH_WT = "Booster2LaunchWt";
|
||||||
|
public static final String BOOSTER2_NOZZLE_DIAMETER = "Booster2NozzleDiameter";
|
||||||
|
public static final String BOOSTER2_CG = "Booster2CG";
|
||||||
public static final String INCLUDE_BOOSTER2 = "IncludeBooster2";
|
public static final String INCLUDE_BOOSTER2 = "IncludeBooster2";
|
||||||
|
public static final String FLIGHT_TIME = "FlightTime";
|
||||||
|
public static final String TIME_TO_APOGEE = "TimetoApogee";
|
||||||
|
public static final String MAX_ALTITUDE = "MaxAltitude";
|
||||||
|
public static final String MAX_VELOCITY = "MaxVelocity";
|
||||||
|
public static final String OPTIMUM_WT = "OptimumWt";
|
||||||
|
public static final String OPTIMUM_MAX_ALT = "OptimumMaxAlt";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,6 +157,10 @@ public class RASAeroCommonConstants {
|
|||||||
* Angle conversion. RASAero is in degrees, OpenRocket in rad.
|
* Angle conversion. RASAero is in degrees, OpenRocket in rad.
|
||||||
*/
|
*/
|
||||||
public static final double RASAERO_TO_OPENROCKET_ANGLE = 180 / Math.PI;
|
public static final double RASAERO_TO_OPENROCKET_ANGLE = 180 / Math.PI;
|
||||||
|
/**
|
||||||
|
* Weight conversion from OpenRocket units to RASAero units. RASAero is in pounds (lb), OpenRocket in kilograms (kg).
|
||||||
|
*/
|
||||||
|
public static final double OPENROCKET_TO_RASAERO_WEIGHT = 2.20462262;
|
||||||
/**
|
/**
|
||||||
* Temperature conversion. RASAero is in Fahrenheit, OpenRocket in Kelvin.
|
* Temperature conversion. RASAero is in Fahrenheit, OpenRocket in Kelvin.
|
||||||
*/
|
*/
|
||||||
|
@ -10,12 +10,14 @@ import net.sf.openrocket.motor.IgnitionEvent;
|
|||||||
import net.sf.openrocket.motor.Motor;
|
import net.sf.openrocket.motor.Motor;
|
||||||
import net.sf.openrocket.motor.MotorConfiguration;
|
import net.sf.openrocket.motor.MotorConfiguration;
|
||||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||||
|
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
|
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
|
||||||
import net.sf.openrocket.simulation.SimulationOptions;
|
import net.sf.openrocket.simulation.SimulationOptions;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -33,12 +35,18 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
// Motor information
|
// Motor information
|
||||||
private ThrustCurveMotor sustainerEngine;
|
private ThrustCurveMotor sustainerEngine;
|
||||||
private Double sustainerIgnitionDelay;
|
private Double sustainerIgnitionDelay;
|
||||||
|
private Double sustainerLaunchWt;
|
||||||
|
private Double sustainerCG;
|
||||||
private ThrustCurveMotor booster1Engine;
|
private ThrustCurveMotor booster1Engine;
|
||||||
private Double booster1IgnitionDelay;
|
private Double booster1IgnitionDelay;
|
||||||
private Double booster1SeparationDelay;
|
private Double booster1SeparationDelay;
|
||||||
|
private Double booster1LaunchWt;
|
||||||
|
private Double booster1CG;
|
||||||
private Boolean includeBooster1;
|
private Boolean includeBooster1;
|
||||||
private ThrustCurveMotor booster2Engine;
|
private ThrustCurveMotor booster2Engine;
|
||||||
private Double booster2SeparationDelay;
|
private Double booster2SeparationDelay;
|
||||||
|
private Double booster2LaunchWt;
|
||||||
|
private Double booster2CG;
|
||||||
private Boolean includeBooster2;
|
private Boolean includeBooster2;
|
||||||
|
|
||||||
public SimulationHandler(DocumentLoadingContext context, Rocket rocket, SimulationOptions launchSiteSettings, int simulationNr) {
|
public SimulationHandler(DocumentLoadingContext context, Rocket rocket, SimulationOptions launchSiteSettings, int simulationNr) {
|
||||||
@ -51,9 +59,12 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
@Override
|
@Override
|
||||||
public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) throws SAXException {
|
public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) throws SAXException {
|
||||||
if (RASAeroCommonConstants.SUSTAINER_ENGINE.equals(element) || RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element)
|
if (RASAeroCommonConstants.SUSTAINER_ENGINE.equals(element) || RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element)
|
||||||
|
|| RASAeroCommonConstants.SUSTAINER_LAUNCH_WT.equals(element) || RASAeroCommonConstants.SUSTAINER_CG.equals(element)
|
||||||
|| RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element)
|
|| RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element)
|
||||||
|| RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element) || RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element)
|
|| RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element) || RASAeroCommonConstants.BOOSTER1_LAUNCH_WT.equals(element)
|
||||||
|
|| RASAeroCommonConstants.BOOSTER1_CG.equals(element) ||RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element)
|
||||||
|| RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element)
|
|| RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element)
|
||||||
|
|| RASAeroCommonConstants.BOOSTER2_LAUNCH_WT.equals(element) || RASAeroCommonConstants.BOOSTER2_CG.equals(element)
|
||||||
|| RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) {
|
|| RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) {
|
||||||
return PlainTextHandler.INSTANCE;
|
return PlainTextHandler.INSTANCE;
|
||||||
}
|
}
|
||||||
@ -66,18 +77,30 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
sustainerEngine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
sustainerEngine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
||||||
} else if (RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element)) {
|
} else if (RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element)) {
|
||||||
sustainerIgnitionDelay = Double.parseDouble(content);
|
sustainerIgnitionDelay = Double.parseDouble(content);
|
||||||
|
} else if (RASAeroCommonConstants.SUSTAINER_LAUNCH_WT.equals(element)) {
|
||||||
|
sustainerLaunchWt = Double.parseDouble(content) / RASAeroCommonConstants.OPENROCKET_TO_RASAERO_WEIGHT;
|
||||||
|
} else if (RASAeroCommonConstants.SUSTAINER_CG.equals(element)) {
|
||||||
|
sustainerCG = Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_LENGTH;
|
||||||
} else if (RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element)) {
|
} else if (RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element)) {
|
||||||
booster1Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
booster1Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
||||||
} else if (RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element)) {
|
} else if (RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element)) {
|
||||||
booster1IgnitionDelay = Double.parseDouble(content);
|
booster1IgnitionDelay = Double.parseDouble(content);
|
||||||
} else if (RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element)) {
|
} else if (RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element)) {
|
||||||
booster1SeparationDelay = Double.parseDouble(content);
|
booster1SeparationDelay = Double.parseDouble(content);
|
||||||
|
} else if (RASAeroCommonConstants.BOOSTER1_LAUNCH_WT.equals(element)) {
|
||||||
|
booster1LaunchWt = Double.parseDouble(content) / RASAeroCommonConstants.OPENROCKET_TO_RASAERO_WEIGHT;
|
||||||
|
} else if (RASAeroCommonConstants.BOOSTER1_CG.equals(element)) {
|
||||||
|
booster1CG = Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_LENGTH;
|
||||||
} else if (RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element)) {
|
} else if (RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element)) {
|
||||||
includeBooster1 = Boolean.parseBoolean(content);
|
includeBooster1 = Boolean.parseBoolean(content);
|
||||||
} else if (RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element)) {
|
} else if (RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element)) {
|
||||||
booster2Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
booster2Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings);
|
||||||
} else if (RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element)) {
|
} else if (RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element)) {
|
||||||
booster2SeparationDelay = Double.parseDouble(content);
|
booster2SeparationDelay = Double.parseDouble(content);
|
||||||
|
} else if (RASAeroCommonConstants.BOOSTER2_LAUNCH_WT.equals(element)) {
|
||||||
|
booster2LaunchWt = Double.parseDouble(content) / RASAeroCommonConstants.OPENROCKET_TO_RASAERO_WEIGHT;
|
||||||
|
} else if (RASAeroCommonConstants.BOOSTER2_CG.equals(element)) {
|
||||||
|
booster2CG = Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_LENGTH;
|
||||||
} else if (RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) {
|
} else if (RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) {
|
||||||
includeBooster2 = Boolean.parseBoolean(content);
|
includeBooster2 = Boolean.parseBoolean(content);
|
||||||
}
|
}
|
||||||
@ -85,48 +108,63 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
|
public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
|
||||||
FlightConfigurationId id = new FlightConfigurationId();
|
FlightConfigurationId fcid = new FlightConfigurationId();
|
||||||
rocket.createFlightConfiguration(id);
|
rocket.createFlightConfiguration(fcid);
|
||||||
// Select if this is the first config
|
// Select if this is the first config
|
||||||
if (rocket.getSelectedConfiguration().getId().equals(FlightConfigurationId.DEFAULT_VALUE_FCID)) {
|
if (rocket.getSelectedConfiguration().getId().equals(FlightConfigurationId.DEFAULT_VALUE_FCID)) {
|
||||||
rocket.setSelectedConfiguration(id);
|
rocket.setSelectedConfiguration(fcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add motors to the rocket
|
// Add motors to the rocket
|
||||||
addMotorToStage(0, sustainerEngine, sustainerIgnitionDelay, id, warnings);
|
MotorMount sustainerMount = addMotorToStage(0, sustainerEngine, sustainerIgnitionDelay, fcid, warnings);
|
||||||
|
MotorMount booster1Mount = null;
|
||||||
if (includeBooster1) {
|
if (includeBooster1) {
|
||||||
addMotorToStage(1, booster1Engine, booster1IgnitionDelay, id, warnings);
|
booster1Mount = addMotorToStage(1, booster1Engine, booster1IgnitionDelay, fcid, warnings);
|
||||||
}
|
}
|
||||||
|
MotorMount booster2Mount = null;
|
||||||
if (includeBooster2) {
|
if (includeBooster2) {
|
||||||
addMotorToStage(2, booster2Engine, 0.0, id, warnings);
|
booster2Mount = addMotorToStage(2, booster2Engine, 0.0, fcid, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set separation settings
|
// Set separation settings
|
||||||
setSeparationDelay(0, 0.0, id);
|
setSeparationDelay(0, 0.0, fcid);
|
||||||
if (includeBooster1) {
|
if (includeBooster1) {
|
||||||
setSeparationDelay(1, booster1SeparationDelay, id);
|
setSeparationDelay(1, booster1SeparationDelay, fcid);
|
||||||
}
|
}
|
||||||
if (includeBooster2) {
|
if (includeBooster2) {
|
||||||
setSeparationDelay(2, booster2SeparationDelay, id);
|
setSeparationDelay(2, booster2SeparationDelay, fcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new simulation
|
// Add a new simulation
|
||||||
Simulation sim = new Simulation(rocket);
|
Simulation sim = new Simulation(rocket);
|
||||||
sim.setFlightConfigurationId(id);
|
sim.setFlightConfigurationId(fcid);
|
||||||
sim.setName("Simulation " + simulationNr);
|
sim.setName("Simulation " + simulationNr);
|
||||||
sim.copySimulationOptionsFrom(launchSiteSettings);
|
sim.copySimulationOptionsFrom(launchSiteSettings);
|
||||||
context.getOpenRocketDocument().addSimulation(sim);
|
context.getOpenRocketDocument().addSimulation(sim);
|
||||||
|
|
||||||
|
// Set the weight and CG overrides
|
||||||
|
applyMassOverrides();
|
||||||
|
applyCGOverrides(sustainerMount, booster1Mount, booster2Mount, fcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMotorToStage(final int stageNr, final Motor motor, final Double ignitionDelay,
|
/**
|
||||||
|
* Adds a motor to the specified stage.
|
||||||
|
* @param stageNr The stage number
|
||||||
|
* @param motor The motor to add
|
||||||
|
* @param ignitionDelay The ignition delay
|
||||||
|
* @param id The flight configuration id
|
||||||
|
* @param warnings The warning set
|
||||||
|
* @return The motor mount in which the motor is added, or null if no motor was added
|
||||||
|
*/
|
||||||
|
private MotorMount addMotorToStage(final int stageNr, final Motor motor, final Double ignitionDelay,
|
||||||
final FlightConfigurationId id, final WarningSet warnings) {
|
final FlightConfigurationId id, final WarningSet warnings) {
|
||||||
if (motor == null || rocket.getStage(stageNr) == null) {
|
if (motor == null || rocket.getStage(stageNr) == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
MotorMount mount = getMotorMountForStage(stageNr);
|
MotorMount mount = getMotorMountForStage(stageNr);
|
||||||
if (mount == null) {
|
if (mount == null) {
|
||||||
warnings.add("No motor mount found for stage " + stageNr + ". Ignoring motor.");
|
warnings.add("No motor mount found for stage " + stageNr + ". Ignoring motor.");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
MotorConfiguration motorConfig = new MotorConfiguration(mount, id);
|
MotorConfiguration motorConfig = new MotorConfiguration(mount, id);
|
||||||
motorConfig.setMotor(motor);
|
motorConfig.setMotor(motor);
|
||||||
@ -145,6 +183,8 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
motorConfig.setIgnitionEvent(IgnitionEvent.AUTOMATIC);
|
motorConfig.setIgnitionEvent(IgnitionEvent.AUTOMATIC);
|
||||||
}
|
}
|
||||||
mount.setMotorConfig(motorConfig, id);
|
mount.setMotorConfig(motorConfig, id);
|
||||||
|
|
||||||
|
return mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSeparationDelay(final int stageNr, Double separationDelay,
|
private void setSeparationDelay(final int stageNr, Double separationDelay,
|
||||||
@ -176,4 +216,252 @@ public class SimulationHandler extends AbstractElementHandler {
|
|||||||
}
|
}
|
||||||
return mount;
|
return mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyMassOverrides() {
|
||||||
|
// Don't do anything if the mass has already been overridden by a previous simulation
|
||||||
|
if (rocket.getStage(0).isMassOverridden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sustainerMass = applySustainerMassOverride();
|
||||||
|
double booster1Mass = applyBooster1MassOverride(sustainerMass);
|
||||||
|
applyBooster2MassOverride(sustainerMass, booster1Mass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the mass from the RASAero simulation to the sustainer as an override, and returns the final sustainer mass.
|
||||||
|
* Note: the sustainer motor mass is subtracted from the RASAero mass to get the final mass.
|
||||||
|
* @return the final sustainer mass
|
||||||
|
*/
|
||||||
|
private double applySustainerMassOverride() {
|
||||||
|
if (sustainerLaunchWt == null || sustainerLaunchWt == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the sustainer motor weight
|
||||||
|
double sustainerMotorWt = 0;
|
||||||
|
if (sustainerEngine != null) {
|
||||||
|
sustainerMotorWt = sustainerEngine.getLaunchMass();
|
||||||
|
}
|
||||||
|
|
||||||
|
double sustainerWt = sustainerLaunchWt - sustainerMotorWt;
|
||||||
|
AxialStage sustainer = rocket.getStage(0);
|
||||||
|
sustainer.setMassOverridden(true);
|
||||||
|
sustainer.setSubcomponentsOverriddenMass(true);
|
||||||
|
sustainer.setOverrideMass(sustainerWt);
|
||||||
|
|
||||||
|
return sustainerWt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the mass from the RASAero simulation to booster1 as an override, and returns the final booster1 mass.
|
||||||
|
* Note: the sustainer mass and booster1 motor mass is subtracted from the RASAero mass to get the final mass.
|
||||||
|
* @param sustainerMass the sustainer mass
|
||||||
|
* @return the final booster1 mass
|
||||||
|
*/
|
||||||
|
private double applyBooster1MassOverride(double sustainerMass) {
|
||||||
|
if (!includeBooster1 || booster1LaunchWt == null || booster1LaunchWt == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the booster motor weight
|
||||||
|
double boosterMotorWt = 0;
|
||||||
|
if (booster1Engine != null) {
|
||||||
|
boosterMotorWt = booster1Engine.getLaunchMass();
|
||||||
|
}
|
||||||
|
|
||||||
|
double boosterWt = booster1LaunchWt - boosterMotorWt - sustainerMass;
|
||||||
|
AxialStage booster = rocket.getStage(1);
|
||||||
|
booster.setMassOverridden(true);
|
||||||
|
booster.setSubcomponentsOverriddenMass(true);
|
||||||
|
booster.setOverrideMass(boosterWt);
|
||||||
|
|
||||||
|
return boosterWt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the mass from the RASAero simulation to booster2 as an override, and returns the final booster2 mass.
|
||||||
|
* Note: the sustainer mass, booster1 mass, and booster2 motor mass is subtracted from the RASAero mass to get the final mass.
|
||||||
|
* @param sustainerMass the sustainer mass
|
||||||
|
* @param booster1Mass the booster1 mass
|
||||||
|
* @return the final booster2 mass
|
||||||
|
*/
|
||||||
|
private double applyBooster2MassOverride(double sustainerMass, double booster1Mass) {
|
||||||
|
if (!includeBooster2 || booster2LaunchWt == null || booster2LaunchWt == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the booster motor weight
|
||||||
|
double boosterMotorWt = 0;
|
||||||
|
if (booster2Engine != null) {
|
||||||
|
boosterMotorWt = booster2Engine.getLaunchMass();
|
||||||
|
}
|
||||||
|
|
||||||
|
double boosterWt = booster2LaunchWt - boosterMotorWt - sustainerMass - booster1Mass;
|
||||||
|
AxialStage booster = rocket.getStage(2);
|
||||||
|
booster.setMassOverridden(true);
|
||||||
|
booster.setSubcomponentsOverriddenMass(true);
|
||||||
|
booster.setOverrideMass(boosterWt);
|
||||||
|
|
||||||
|
return boosterWt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the CG extracted from the simulation to the sustainer, booster1, and booster2.
|
||||||
|
* @param sustainerMount the sustainer motor mount
|
||||||
|
* @param booster1Mount the booster1 motor mount
|
||||||
|
* @param booster2Mount the booster2 motor mount
|
||||||
|
* @param fcid the flight configuration ID of this simulation
|
||||||
|
*/
|
||||||
|
private void applyCGOverrides(MotorMount sustainerMount, MotorMount booster1Mount, MotorMount booster2Mount,
|
||||||
|
FlightConfigurationId fcid) {
|
||||||
|
// Don't do anything if the CG has already been overridden by a previous simulation
|
||||||
|
if (rocket.getStage(0).isCGOverridden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applySustainerCGOverride(sustainerMount, fcid);
|
||||||
|
applyBooster1CGOverride(booster1Mount, fcid);
|
||||||
|
applyBooster2CGOverride(booster2Mount, fcid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the CG from the RASAero simulation to the sustainer as an override.
|
||||||
|
* This CG value can be applied directly.
|
||||||
|
* @param sustainerMount the sustainer motor mount
|
||||||
|
* @param fcid the flight configuration ID of this simulation
|
||||||
|
* @return the CG of the sustainer
|
||||||
|
*/
|
||||||
|
private Double applySustainerCGOverride(MotorMount sustainerMount, FlightConfigurationId fcid) {
|
||||||
|
if (sustainerCG == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxialStage sustainer = rocket.getStage(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
sustainerCG is the combined CG of the sustainer and its motor (if present),
|
||||||
|
so we need to calculate the CG of the sustainer without the motor CG
|
||||||
|
*/
|
||||||
|
Double CG = getStageCGWithoutMotorCG(sustainer, sustainerCG, sustainerMount, sustainerEngine, fcid);
|
||||||
|
|
||||||
|
sustainer.setCGOverridden(true);
|
||||||
|
sustainer.setSubcomponentsOverriddenCG(true);
|
||||||
|
sustainer.setOverrideCGX(CG);
|
||||||
|
|
||||||
|
return CG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the CG from the RASAero simulation to booster1 as an override.
|
||||||
|
* The CG value returned by RASAero is the aggregate CG of the sustainer and booster1.
|
||||||
|
* To calculate the CG of booster1, we use the following formula:
|
||||||
|
* booster1 CG = [booster1 mass x (distance between CG of sustainer and combined CG)] / (sustainer mass)
|
||||||
|
* @param booster1Mount the booster1 motor mount
|
||||||
|
* @param fcid the flight configuration ID of this simulation
|
||||||
|
* @return the CG of booster1
|
||||||
|
*/
|
||||||
|
private Double applyBooster1CGOverride(MotorMount booster1Mount, FlightConfigurationId fcid) {
|
||||||
|
if (!includeBooster1 || booster1CG == null || sustainerCG == null || booster1LaunchWt == null || sustainerLaunchWt == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxialStage booster = rocket.getStage(1);
|
||||||
|
|
||||||
|
// Do a back-transform of the combined CG of the sustainer and booster1 to get the CG of booster1
|
||||||
|
Double CG = getCGFromCombinedCG(booster1CG, sustainerCG, sustainerLaunchWt, booster1LaunchWt - sustainerLaunchWt);
|
||||||
|
// ! this CG is relative to the front of the sustainer, we need it referenced to the front of the booster
|
||||||
|
CG = CG - booster.getPosition().x;
|
||||||
|
|
||||||
|
/*
|
||||||
|
the above CG is the combined CG of booster1 and its motor (if present),
|
||||||
|
so we need to calculate the CG of booster1 without the motor CG
|
||||||
|
*/
|
||||||
|
CG = getStageCGWithoutMotorCG(booster, CG, booster1Mount, booster1Engine, fcid);
|
||||||
|
|
||||||
|
booster.setCGOverridden(true);
|
||||||
|
booster.setSubcomponentsOverriddenCG(true);
|
||||||
|
booster.setOverrideCGX(CG);
|
||||||
|
|
||||||
|
return CG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the CG from the RASAero simulation to booster2 as an override.
|
||||||
|
* The CG value returned by RASAero is the aggregate CG of the sustainer, booster1, and booster2.
|
||||||
|
* To calculate the CG of booster2, we use the following formula:
|
||||||
|
* booster2 CG = [booster2 mass x (distance between CG of sustainer and combined CG)] / (sustainer mass + booster1 mass)
|
||||||
|
* @param booster2Mount the booster1 motor mount
|
||||||
|
* @param fcid the flight configuration ID of this simulation
|
||||||
|
* @return the CG of booster2
|
||||||
|
*/
|
||||||
|
private Double applyBooster2CGOverride(MotorMount booster2Mount, FlightConfigurationId fcid) {
|
||||||
|
if (!includeBooster2 || booster2CG == null || booster1CG == null || sustainerCG == null ||
|
||||||
|
booster2LaunchWt == null || booster1LaunchWt == null || sustainerLaunchWt == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxialStage booster = rocket.getStage(2);
|
||||||
|
|
||||||
|
// Do a back-transform of the combined CG of the sustainer, booster1, and booster2 to get the CG of booster2
|
||||||
|
Double CG = getCGFromCombinedCG(booster2CG, booster1CG, booster1LaunchWt, booster2LaunchWt - booster1LaunchWt);
|
||||||
|
// ! this CG is relative to the front of the sustainer, we need it referenced to the front of the booster
|
||||||
|
CG = CG - booster.getPosition().x;
|
||||||
|
|
||||||
|
/*
|
||||||
|
the above CG is the combined CG of booster2 and its motor (if present),
|
||||||
|
so we need to calculate the CG of booster2 without the motor CG
|
||||||
|
*/
|
||||||
|
CG = getStageCGWithoutMotorCG(booster, CG, booster2Mount, booster2Engine, fcid);
|
||||||
|
|
||||||
|
booster.setCGOverridden(true);
|
||||||
|
booster.setSubcomponentsOverriddenCG(true);
|
||||||
|
booster.setOverrideCGX(CG);
|
||||||
|
|
||||||
|
return CG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the CG of object B from the CG of object A, the combined CG of A and B, and the masses of A and B.
|
||||||
|
* @param combinedCG the combined CG of A and B
|
||||||
|
* @param objACG the CG of object A
|
||||||
|
* @param objAMass the mass of object A
|
||||||
|
* @param objBMass the mass of object B
|
||||||
|
* @return the CG of object B
|
||||||
|
*/
|
||||||
|
private Double getCGFromCombinedCG(Double combinedCG, Double objACG, Double objAMass, Double objBMass) {
|
||||||
|
if (combinedCG == null || objACG == null || objAMass == null || objBMass == null) {
|
||||||
|
return combinedCG;
|
||||||
|
}
|
||||||
|
return combinedCG * (1 + objAMass / objBMass) - objACG * (objAMass / objBMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the CG of a stage from a combined CG of the stage and stage motor.
|
||||||
|
* @param stage the stage
|
||||||
|
* @param combinedCG the combiend CG of the stage and its motor
|
||||||
|
* @param mount the motor mount of the stage that holds the motor
|
||||||
|
* @param motor the motor
|
||||||
|
* @param fcid the flight configuration ID of this simulation
|
||||||
|
* @return the CG of the stage without the motor CG
|
||||||
|
*/
|
||||||
|
private Double getStageCGWithoutMotorCG(AxialStage stage, Double combinedCG, MotorMount mount, ThrustCurveMotor motor,
|
||||||
|
FlightConfigurationId fcid) {
|
||||||
|
if (motor == null || mount == null || stage == null || combinedCG == null) {
|
||||||
|
return combinedCG;
|
||||||
|
}
|
||||||
|
double stageMass = stage.getMass(); // Should be overridden by now, so don't use getSectionMass()
|
||||||
|
double motorMass = motor.getLaunchMass();
|
||||||
|
|
||||||
|
Coordinate[] CGPoints = motor.getCGPoints();
|
||||||
|
if (CGPoints != null && CGPoints.length > 1) {
|
||||||
|
double motorPositionXRel = mount.getMotorPosition(fcid).x; // Motor position relative to the mount
|
||||||
|
double mountLocationX = mount.getLocations()[0].x;
|
||||||
|
double motorLocationX = mountLocationX + motorPositionXRel;
|
||||||
|
double motorCG = motor.getCGPoints()[0].x + motorLocationX;
|
||||||
|
return combinedCG * (1 + motorMass / stageMass)
|
||||||
|
- motorCG * (motorMass / stageMass);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user