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:
parent
fc5ef54d9d
commit
efacebf5d8
@ -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,25 +395,11 @@ 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( this.config.isComponentActive(component) && 0 < this.getMass() ) {
|
||||||
if (component.isMassOverridden()) {
|
// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() ));
|
||||||
double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS);
|
// }
|
||||||
Coordinate newCM = this.getCM().setWeight( newMass );
|
// ^^^ DEBUG
|
||||||
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
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -350,11 +415,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RigidBody( centerOfMass, Ir, It, It );
|
return new RigidBody( centerOfMass, Ir, It, It );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -713,10 +741,10 @@ public class MassCalculatorTest extends BaseTestCase {
|
|||||||
double expMOI_axial = 0.01261079;
|
double expMOI_axial = 0.01261079;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -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