commit
48adb703d3
@ -246,6 +246,108 @@ public class MassCalculation {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* package-scope */ MassCalculation calculateAssembly(){
|
/* package-scope */ MassCalculation calculateAssembly(){
|
||||||
|
|
||||||
|
if (this.type.includesStructure) {
|
||||||
|
MassCalculation structureCalc = this.copy(this.root, this.transform);
|
||||||
|
structureCalc.calculateStructure();
|
||||||
|
this.merge(structureCalc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type.includesMotorCasing || this.type.includesPropellant) {
|
||||||
|
MassCalculation motorCalc = this.copy(this.root, this.transform);
|
||||||
|
motorCalc.calculateMotors();
|
||||||
|
this.merge(motorCalc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MassCalculation calculateStructure() {
|
||||||
|
final RocketComponent component = this.root;
|
||||||
|
final Transformation parentTransform = this.transform;
|
||||||
|
final int instanceCount = component.getInstanceCount();
|
||||||
|
Coordinate[] instanceLocations = component.getInstanceLocations();
|
||||||
|
|
||||||
|
// // vvv DEBUG
|
||||||
|
// if( this.config.isComponentActive(component) ){
|
||||||
|
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// iterate over the aggregated instances for the whole tree.
|
||||||
|
MassCalculation children = this.copy(component, parentTransform );
|
||||||
|
for( int instanceNumber = 0; instanceNumber < instanceCount; ++instanceNumber) {
|
||||||
|
Coordinate currentLocation = instanceLocations[instanceNumber];
|
||||||
|
Transformation currentTransform = parentTransform.applyTransformation( Transformation.getTranslationTransform( currentLocation ));
|
||||||
|
|
||||||
|
for (RocketComponent child : component.getChildren()) {
|
||||||
|
// child data, relative to rocket reference frame
|
||||||
|
MassCalculation eachChild = copy( child, currentTransform);
|
||||||
|
|
||||||
|
eachChild.prefix = prefix + "....";
|
||||||
|
eachChild.calculateStructure();
|
||||||
|
|
||||||
|
// accumulate children's data
|
||||||
|
children.merge( eachChild );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( 0 < children.getMass() ) {
|
||||||
|
this.merge( children );
|
||||||
|
// // vvv DEBUG
|
||||||
|
// System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.config.isComponentActive(component) ){
|
||||||
|
Coordinate compCM = component.getComponentCG();
|
||||||
|
|
||||||
|
if (!component.getOverrideSubcomponents()) {
|
||||||
|
if (component.isMassOverridden()) {
|
||||||
|
// System.err.println("mass override=" + component.getOverrideMass());
|
||||||
|
compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS));
|
||||||
|
}
|
||||||
|
if (component.isCGOverridden())
|
||||||
|
compCM = compCM.setXYZ(component.getOverrideCG());
|
||||||
|
}
|
||||||
|
|
||||||
|
// mass data for *this component only* in the rocket-frame
|
||||||
|
compCM = parentTransform.transform( compCM.add(component.getPosition()) );
|
||||||
|
this.addMass( compCM );
|
||||||
|
|
||||||
|
double compIx = component.getRotationalUnitInertia() * compCM.weight;
|
||||||
|
double compIt = component.getLongitudinalUnitInertia() * compCM.weight;
|
||||||
|
RigidBody componentInertia = new RigidBody( compCM, compIx, compIt, compIt );
|
||||||
|
|
||||||
|
this.addInertia( componentInertia );
|
||||||
|
// vvv DEBUG
|
||||||
|
// if( 0 < compCM.weight ) {
|
||||||
|
// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (component.getOverrideSubcomponents()) {
|
||||||
|
if (component.isMassOverridden()) {
|
||||||
|
double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS);
|
||||||
|
Coordinate newCM = this.getCM().setWeight( newMass );
|
||||||
|
this.setCM( newCM );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.isCGOverridden()) {
|
||||||
|
Coordinate newCM = this.getCM().setX( component.getOverrideCGX() );
|
||||||
|
this.setCM( newCM );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // vvv DEBUG
|
||||||
|
// if( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
||||||
|
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
||||||
|
// }
|
||||||
|
// // ^^^ DEBUG
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MassCalculation calculateMotors() {
|
||||||
|
|
||||||
final RocketComponent component = this.root;
|
final RocketComponent component = this.root;
|
||||||
final Transformation parentTransform = this.transform;
|
final Transformation parentTransform = this.transform;
|
||||||
|
|
||||||
@ -257,37 +359,14 @@ public class MassCalculation {
|
|||||||
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
|
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if( this.type.includesStructure && this.config.isComponentActive(component) ){
|
if (component.isMotorMount()) {
|
||||||
Coordinate compCM = component.getCG();
|
|
||||||
double compIx = component.getRotationalUnitInertia() * compCM.weight;
|
|
||||||
double compIt = component.getLongitudinalUnitInertia() * compCM.weight;
|
|
||||||
|
|
||||||
if (!component.getOverrideSubcomponents()) {
|
|
||||||
if (component.isMassOverridden())
|
|
||||||
compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS));
|
|
||||||
if (component.isCGOverridden())
|
|
||||||
compCM = compCM.setXYZ(component.getOverrideCG());
|
|
||||||
}
|
|
||||||
|
|
||||||
// mass data for *this component only* in the rocket-frame
|
|
||||||
compCM = parentTransform.transform( compCM.add(component.getPosition()) );
|
|
||||||
this.addMass( compCM );
|
|
||||||
|
|
||||||
RigidBody componentInertia = new RigidBody( compCM, compIx, compIt, compIt );
|
|
||||||
this.addInertia( componentInertia );
|
|
||||||
|
|
||||||
// if( 0 < compCM.weight ) { // vvv DEBUG
|
|
||||||
// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() ));
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
if( component.isMotorMount() && ( this.type.includesMotorCasing || this.type.includesPropellant )) {
|
|
||||||
MassCalculation propellant = this.copy(component, parentTransform);
|
MassCalculation propellant = this.copy(component, parentTransform);
|
||||||
|
|
||||||
propellant.calculateMountData();
|
propellant.calculateMountData();
|
||||||
|
|
||||||
this.merge( propellant );
|
this.merge( propellant );
|
||||||
|
|
||||||
|
// // vvv DEBUG
|
||||||
// if( 0 < propellant.getMass() ) {
|
// if( 0 < propellant.getMass() ) {
|
||||||
// System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug()));
|
// System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug()));
|
||||||
// }
|
// }
|
||||||
@ -304,7 +383,7 @@ public class MassCalculation {
|
|||||||
MassCalculation eachChild = copy( child, currentTransform);
|
MassCalculation eachChild = copy( child, currentTransform);
|
||||||
|
|
||||||
eachChild.prefix = prefix + "....";
|
eachChild.prefix = prefix + "....";
|
||||||
eachChild.calculateAssembly();
|
eachChild.calculateMotors();
|
||||||
|
|
||||||
// accumulate children's data
|
// accumulate children's data
|
||||||
children.merge( eachChild );
|
children.merge( eachChild );
|
||||||
@ -316,23 +395,9 @@ public class MassCalculation {
|
|||||||
//System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug()));
|
//System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override total data
|
// // vvv DEBUG
|
||||||
if (component.getOverrideSubcomponents()) {
|
|
||||||
if (component.isMassOverridden()) {
|
|
||||||
double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS);
|
|
||||||
Coordinate newCM = this.getCM().setWeight( newMass );
|
|
||||||
this.setCM( newCM );
|
|
||||||
}
|
|
||||||
if (component.isCGOverridden()) {
|
|
||||||
Coordinate newCM = this.getCM().setX( component.getOverrideCGX() );
|
|
||||||
this.setCM( newCM );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// vvv DEBUG
|
|
||||||
// if( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
// if( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
||||||
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
||||||
// System.err.println(String.format( "%s Ixx = %.8f Iyy = %.8f", prefix, getIxx(), getIyy() ));
|
|
||||||
// }
|
// }
|
||||||
// ^^^ DEBUG
|
// ^^^ DEBUG
|
||||||
|
|
||||||
@ -350,7 +415,6 @@ public class MassCalculation {
|
|||||||
double Ir=0, It=0;
|
double Ir=0, It=0;
|
||||||
for( final RigidBody eachLocal : this.bodies ){
|
for( final RigidBody eachLocal : this.bodies ){
|
||||||
final RigidBody eachGlobal = eachLocal.rebase( this.centerOfMass );
|
final RigidBody eachGlobal = eachLocal.rebase( this.centerOfMass );
|
||||||
|
|
||||||
Ir += eachGlobal.Ixx;
|
Ir += eachGlobal.Ixx;
|
||||||
It += eachGlobal.Iyy;
|
It += eachGlobal.Iyy;
|
||||||
}
|
}
|
||||||
|
@ -34,13 +34,13 @@ public class MassCalculator implements Monitorable {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates mass data of the rocket's burnout mass
|
* Calculates mass data of the rocket's structure
|
||||||
* - includes structure
|
* - includes structure
|
||||||
* - includes motors
|
* - excludes motors
|
||||||
* - for Black Powder & Composite motors, this generally *excludes* propellant
|
* - excludes propellant
|
||||||
*
|
*
|
||||||
* @param config the rocket configuration to calculate for
|
* @param config the rocket configuration to calculate for
|
||||||
* @return the MassData struct of the motors at burnout
|
* @return the MassData struct of the rocket
|
||||||
*/
|
*/
|
||||||
public static RigidBody calculateStructure( final FlightConfiguration config) {
|
public static RigidBody calculateStructure( final FlightConfiguration config) {
|
||||||
return calculate( MassCalculation.Type.STRUCTURE, config, Motor.PSEUDO_TIME_EMPTY );
|
return calculate( MassCalculation.Type.STRUCTURE, config, Motor.PSEUDO_TIME_EMPTY );
|
||||||
@ -53,29 +53,42 @@ public class MassCalculator implements Monitorable {
|
|||||||
* - for Black Powder & Composite motors, this generally *excludes* propellant
|
* - for Black Powder & Composite motors, this generally *excludes* propellant
|
||||||
*
|
*
|
||||||
* @param config the rocket configuration to calculate for
|
* @param config the rocket configuration to calculate for
|
||||||
* @return the MassData struct of the motors at burnout
|
* @return the MassData struct of the rocket at burnout
|
||||||
*/
|
*/
|
||||||
public static RigidBody calculateBurnout( final FlightConfiguration config) {
|
public static RigidBody calculateBurnout( final FlightConfiguration config) {
|
||||||
return calculate( MassCalculation.Type.BURNOUT, config, Motor.PSEUDO_TIME_BURNOUT );
|
return calculate( MassCalculation.Type.BURNOUT, config, Motor.PSEUDO_TIME_BURNOUT );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates mass data of the rocket's motor(s) at launch
|
||||||
|
* - excludes structure
|
||||||
|
* - includes motors
|
||||||
|
* - includes propellant
|
||||||
|
*
|
||||||
|
* @param config the rocket configuration to calculate for
|
||||||
|
* @return the MassData struct of the motors at launch
|
||||||
|
*/
|
||||||
public static RigidBody calculateMotor( final FlightConfiguration config) {
|
public static RigidBody calculateMotor( final FlightConfiguration config) {
|
||||||
return calculate( MassCalculation.Type.MOTOR, config, Motor.PSEUDO_TIME_LAUNCH );
|
return calculate( MassCalculation.Type.MOTOR, config, Motor.PSEUDO_TIME_LAUNCH );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the burnout mass properties all motors, given a configuration
|
* Compute the rocket's launch mass properties, given a configuration
|
||||||
*
|
* - includes structure
|
||||||
* Will calculate data for: MassCalcType.BURNOUT_MASS
|
* - includes motors
|
||||||
|
* - includes propellant
|
||||||
*
|
*
|
||||||
* @param config the rocket configuration
|
* @param config the rocket configuration
|
||||||
* @return the MassData struct of the motors at burnout
|
* @return the MassData struct of the rocket at launch
|
||||||
*/
|
*/
|
||||||
public static RigidBody calculateLaunch( final FlightConfiguration config ){
|
public static RigidBody calculateLaunch( final FlightConfiguration config ){
|
||||||
return calculate( MassCalculation.Type.LAUNCH, config, Motor.PSEUDO_TIME_LAUNCH );
|
return calculate( MassCalculation.Type.LAUNCH, config, Motor.PSEUDO_TIME_LAUNCH );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** calculates the massdata for all propellant in the rocket given the simulation status.
|
/** calculates the massdata for all motors in the rocket given the simulation status.
|
||||||
|
* - excludes structure
|
||||||
|
* - includes motors
|
||||||
|
* - includes propellant
|
||||||
*
|
*
|
||||||
* @param status CurrentSimulation status to calculate data with
|
* @param status CurrentSimulation status to calculate data with
|
||||||
* @return combined mass data for all propellant
|
* @return combined mass data for all propellant
|
||||||
|
@ -32,6 +32,7 @@ public class MassCalculatorTest extends BaseTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAlphaIIIStructure() {
|
public void testAlphaIIIStructure() {
|
||||||
|
System.err.println("testing AlphaIII structure");
|
||||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||||
rocket.setName("AlphaIII."+Thread.currentThread().getStackTrace()[1].getMethodName());
|
rocket.setName("AlphaIII."+Thread.currentThread().getStackTrace()[1].getMethodName());
|
||||||
|
|
||||||
@ -51,6 +52,33 @@ public class MassCalculatorTest extends BaseTestCase {
|
|||||||
assertEquals("Simple Rocket CM.y is incorrect: ", expCM.y, actualRocketDryCM.y, EPSILON);
|
assertEquals("Simple Rocket CM.y is incorrect: ", expCM.y, actualRocketDryCM.y, EPSILON);
|
||||||
assertEquals("Simple Rocket CM.z is incorrect: ", expCM.z, actualRocketDryCM.z, EPSILON);
|
assertEquals("Simple Rocket CM.z is incorrect: ", expCM.z, actualRocketDryCM.z, EPSILON);
|
||||||
assertEquals("Simple Rocket CM is incorrect: ", expCM, actualRocketDryCM);
|
assertEquals("Simple Rocket CM is incorrect: ", expCM, actualRocketDryCM);
|
||||||
|
|
||||||
|
|
||||||
|
double expMOIrot = 5.441190348849436E-5;
|
||||||
|
double expMOIlong = 3.03467093714368E-4;
|
||||||
|
|
||||||
|
double actualMOIrot = actualStructure.getRotationalInertia();
|
||||||
|
double actualMOIlong = actualStructure.getLongitudinalInertia();
|
||||||
|
assertEquals("Alpha III Rotational MOI calculated incorrectly: ", expMOIrot, actualMOIrot, EPSILON);
|
||||||
|
assertEquals("Alpha III Longitudinal MOI calculated incorrectly: ", expMOIlong, actualMOIlong, EPSILON);
|
||||||
|
|
||||||
|
// if we use a mass override, setting to same mass, we should get same result
|
||||||
|
System.err.println("calculating AlphaIII with mass override");
|
||||||
|
AxialStage sustainer = (AxialStage) rocket.getChild(0);
|
||||||
|
|
||||||
|
sustainer.setOverrideSubcomponents(true);
|
||||||
|
sustainer.setMassOverridden(true);
|
||||||
|
sustainer.setOverrideMass(actualRocketDryMass);
|
||||||
|
|
||||||
|
final RigidBody overrideStructure = MassCalculator.calculateStructure( config );
|
||||||
|
final Coordinate overrideRocketDryCM = overrideStructure.cm;
|
||||||
|
|
||||||
|
assertEquals("Simple Rocket Override CM is incorrect: ", actualRocketDryCM, overrideRocketDryCM);
|
||||||
|
|
||||||
|
double overrideMOIrot = overrideStructure.getRotationalInertia();
|
||||||
|
double overrideMOIlong = overrideStructure.getLongitudinalInertia();
|
||||||
|
assertEquals("Alpha III Rotational MOI calculated incorrectly: ", actualMOIrot, overrideMOIrot, EPSILON);
|
||||||
|
assertEquals("Alpha III Longitudinal MOI calculated incorrectly: ", actualMOIlong, overrideMOIlong, EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -714,7 +742,7 @@ public class MassCalculatorTest extends BaseTestCase {
|
|||||||
double boosterMOI_xx= burnout.getRotationalInertia();
|
double boosterMOI_xx= burnout.getRotationalInertia();
|
||||||
assertEquals(" Booster x-axis MOI is incorrect: ", expMOI_axial, boosterMOI_xx, EPSILON);
|
assertEquals(" Booster x-axis MOI is incorrect: ", expMOI_axial, boosterMOI_xx, EPSILON);
|
||||||
|
|
||||||
double expMOI_tr = 16.163954943504205;
|
double expMOI_tr = 16.046826943504207;
|
||||||
double boosterMOI_tr= burnout.getLongitudinalInertia();
|
double boosterMOI_tr= burnout.getLongitudinalInertia();
|
||||||
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
|
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
|
||||||
}
|
}
|
||||||
@ -734,17 +762,24 @@ public class MassCalculatorTest extends BaseTestCase {
|
|||||||
NoseCone nose = (NoseCone)boosters.getChild(0);
|
NoseCone nose = (NoseCone)boosters.getChild(0);
|
||||||
nose.setMassOverridden(true);
|
nose.setMassOverridden(true);
|
||||||
nose.setOverrideMass( 0.71 );
|
nose.setOverrideMass( 0.71 );
|
||||||
|
// cm= 0.71000000g @[0.53971058,0.07700000,0.00000000]
|
||||||
|
|
||||||
BodyTube body = (BodyTube)boosters.getChild(1);
|
BodyTube body = (BodyTube)boosters.getChild(1);
|
||||||
body.setMassOverridden(true);
|
body.setMassOverridden(true);
|
||||||
body.setOverrideMass( 0.622 );
|
body.setOverrideMass( 0.622 );
|
||||||
|
// cm= 0.62200000g @[0.96400000,0.07700000,0.00000000]
|
||||||
|
|
||||||
InnerTube mmt = (InnerTube)boosters.getChild(1).getChild(0);
|
InnerTube mmt = (InnerTube)boosters.getChild(1).getChild(0);
|
||||||
mmt.setMassOverridden(true);
|
mmt.setMassOverridden(true);
|
||||||
mmt.setOverrideMass( 0.213 );
|
mmt.setOverrideMass( 0.213 );
|
||||||
|
// cm= 0.21300000g @[1.28900000,0.07700000,0.00000000]
|
||||||
|
|
||||||
|
// Fin mass is not overriden
|
||||||
|
// cm= 0.15995232g @[1.23793939,0.07700000,0.00000000]
|
||||||
|
|
||||||
RigidBody boosterData = MassCalculator.calculateStructure( config );
|
RigidBody boosterData = MassCalculator.calculateStructure( config );
|
||||||
Coordinate boosterCM = boosterData.getCM();
|
Coordinate boosterCM = boosterData.getCM();
|
||||||
|
// cm= 3.409905g@[0.853614,-0.000000,0.000000]
|
||||||
|
|
||||||
double expTotalMass = 3.40990464;
|
double expTotalMass = 3.40990464;
|
||||||
assertEquals(" Booster Launch Mass is incorrect: ", expTotalMass, boosterData.getMass(), EPSILON);
|
assertEquals(" Booster Launch Mass is incorrect: ", expTotalMass, boosterData.getMass(), EPSILON);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user