Refactored MassCalculation.calculateAssembly() to separate calculation

of structure from calculation of motors, so mass and CG overrides
don't affect motors

Modified structure calculation so that when an override is in effect
and children are also being overridden, don't include root of tree as
an element in its own right when computing MOI.

Modified MassCalculatorTest to look for correct MOI value.
This commit is contained in:
JoePfeiffer 2019-03-07 18:05:44 -07:00
parent fc5ef54d9d
commit efacebf5d8
2 changed files with 152 additions and 53 deletions

View File

@ -246,6 +246,108 @@ public class MassCalculation {
*
*/
/* 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 Transformation parentTransform = this.transform;
@ -257,37 +359,14 @@ public class MassCalculation {
// System.err.println(String.format( "%s[%s]....", prefix, component.getName()));
// }
if( this.type.includesStructure && this.config.isComponentActive(component) ){
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 )) {
if (component.isMotorMount()) {
MassCalculation propellant = this.copy(component, parentTransform);
propellant.calculateMountData();
this.merge( propellant );
// // vvv DEBUG
// if( 0 < propellant.getMass() ) {
// System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug()));
// }
@ -304,7 +383,7 @@ public class MassCalculation {
MassCalculation eachChild = copy( child, currentTransform);
eachChild.prefix = prefix + "....";
eachChild.calculateAssembly();
eachChild.calculateMotors();
// accumulate children's data
children.merge( eachChild );
@ -316,25 +395,11 @@ public class MassCalculation {
//System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug()));
}
// Override total data
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() ));
// System.err.println(String.format( "%s Ixx = %.8f Iyy = %.8f", prefix, getIxx(), getIyy() ));
//}
// ^^^ DEBUG
// // 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;
}
@ -350,11 +415,10 @@ public class MassCalculation {
double Ir=0, It=0;
for( final RigidBody eachLocal : this.bodies ){
final RigidBody eachGlobal = eachLocal.rebase( this.centerOfMass );
Ir += eachGlobal.Ixx;
It += eachGlobal.Iyy;
}
return new RigidBody( centerOfMass, Ir, It, It );
}

View File

@ -32,6 +32,7 @@ public class MassCalculatorTest extends BaseTestCase {
@Test
public void testAlphaIIIStructure() {
System.err.println("testing AlphaIII structure");
Rocket rocket = TestRockets.makeEstesAlphaIII();
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.z is incorrect: ", expCM.z, actualRocketDryCM.z, EPSILON);
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
@ -713,10 +741,10 @@ public class MassCalculatorTest extends BaseTestCase {
double expMOI_axial = 0.01261079;
double boosterMOI_xx= burnout.getRotationalInertia();
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();
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
}
@Test
@ -734,17 +762,24 @@ public class MassCalculatorTest extends BaseTestCase {
NoseCone nose = (NoseCone)boosters.getChild(0);
nose.setMassOverridden(true);
nose.setOverrideMass( 0.71 );
// cm= 0.71000000g @[0.53971058,0.07700000,0.00000000]
BodyTube body = (BodyTube)boosters.getChild(1);
body.setMassOverridden(true);
body.setOverrideMass( 0.622 );
// cm= 0.62200000g @[0.96400000,0.07700000,0.00000000]
InnerTube mmt = (InnerTube)boosters.getChild(1).getChild(0);
mmt.setMassOverridden(true);
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 );
Coordinate boosterCM = boosterData.getCM();
// cm= 3.409905g@[0.853614,-0.000000,0.000000]
double expTotalMass = 3.40990464;
assertEquals(" Booster Launch Mass is incorrect: ", expTotalMass, boosterData.getMass(), EPSILON);