Merge pull request #769 from teyrana/fix/755/cg-error

[fixes #755] Correctly calculate cg.x override
This commit is contained in:
Daniel Williams 2020-09-05 15:11:47 -04:00 committed by GitHub
commit 3f7009b9f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 181 additions and 57 deletions

View File

@ -53,12 +53,10 @@ public class MassCalculation {
// =========== Instance Functions ========================
public void merge( final MassCalculation other ) {
if( MIN_MASS < other.getMass()) {
// Adjust Center-of-mass
this.addMass( other.getCM() );
this.bodies.addAll( other.bodies );
}
}
public void addInertia( final RigidBody data ) {
this.bodies.add( data );
@ -320,53 +318,13 @@ public class MassCalculation {
}
}
if( MIN_MASS < 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()) {
compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS));
// // vvv DEBUG
// System.err.println(String.format( "%s....mass overridden to: %s", prefix, compCM.toPreciseString()));
}
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 );
if(null != analysisMap){
if( component instanceof ComponentAssembly) {
// For ComponentAssemblies, record the _assembly_ information
CMAnalysisEntry entry = analysisMap.get(component.hashCode());
entry.updateEachMass(children.getMass() / component.getInstanceCount());
entry.updateAverageCM(this.centerOfMass);
}else{
// For actual components, record the mass of the component, and disregard children
CMAnalysisEntry entry = analysisMap.get(component.hashCode());
entry.updateEachMass(compCM.weight);
entry.updateAverageCM(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);
@ -375,10 +333,39 @@ public class MassCalculation {
}
if (component.isCGOverridden()) {
Coordinate newCM = this.getCM().setX( component.getOverrideCGX() );
this.setCM( newCM );
this.setCM( this.getCM().setX( compCM.x + component.getOverrideCGX()));
}
}else {
if (component.isMassOverridden()) {
compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS));
}
if (component.isCGOverridden()) {
compCM = compCM.setXYZ(component.getOverrideCG());
}
this.addMass( compCM );
}
if(null != analysisMap){
final CMAnalysisEntry entry = analysisMap.get(component.hashCode());
if( component instanceof ComponentAssembly) {
// For ComponentAssemblies, record the _assembly_ information
entry.updateEachMass(children.getMass() / component.getInstanceCount());
entry.updateAverageCM(this.centerOfMass);
}else{
// For actual components, record the mass of the component, and disregard children
entry.updateEachMass(compCM.weight);
entry.updateAverageCM(compCM);
}
}
final double compIx = component.getRotationalUnitInertia() * compCM.weight;
final double compIt = component.getLongitudinalUnitInertia() * compCM.weight;
final 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() ));
// }
}
// // vvv DEBUG

View File

@ -638,6 +638,41 @@ public class TestRockets {
return rocket;
}
// This is not a production rocket -- it is construction, purely for testing Mass Overrides
// This function is used for unit, integration tests, DO NOT CHANGE (without updating tests).
public static final Rocket makeSimple2Stage(){
Rocket rocket = new Rocket();
rocket.createFlightConfiguration( TEST_FCID_0 );
rocket.setName("Simple 2-Stage Rocket");
final double bodytubeLength = 0.10;
final double bodytubeRadius = 0.01;
final double bodytubeThickness = 0.001;
{
final AxialStage sustainerStage = new AxialStage();
sustainerStage.setName("Sustainer Stage");
rocket.addChild(sustainerStage);
final BodyTube bodytube = new BodyTube(bodytubeLength, bodytubeRadius, bodytubeThickness);
bodytube.setName("Sustainer Body Tube");
sustainerStage.addChild(bodytube);
}{
final AxialStage boosterStage = new AxialStage();
boosterStage.setName("Booster Stage");
rocket.addChild(boosterStage);
final BodyTube boosterBody = new BodyTube(bodytubeLength, bodytubeRadius, bodytubeThickness);
boosterBody.setName("Booster Body Tube");
boosterStage.addChild(boosterBody);
}
rocket.setSelectedConfiguration( TEST_FCID_0 );
rocket.getSelectedConfiguration().setAllStages();
rocket.enableEvents();
return rocket;
}
public static Rocket makeBigBlue() {
Rocket rocket;
AxialStage stage;

View File

@ -22,7 +22,6 @@ 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());
@ -54,7 +53,6 @@ public class MassCalculatorTest extends BaseTestCase {
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);
@ -161,6 +159,110 @@ public class MassCalculatorTest extends BaseTestCase {
}
}
@Test
public void testStageCMxOverride() {
final Rocket rocket = TestRockets.makeSimple2Stage();
final AxialStage sustainerStage = (AxialStage) rocket.getChild(0);
final AxialStage boosterStage = (AxialStage) rocket.getChild(1);
final FlightConfiguration config = rocket.getSelectedConfiguration();
{ // [0] verify / document structure
final BodyTube sustainerBody = (BodyTube) sustainerStage.getChild(0);
assertEquals(0.0, sustainerBody.getPosition().x, EPSILON);
assertEquals(0.1, sustainerBody.getLength(), EPSILON);
final BodyTube boosterBody = (BodyTube) boosterStage.getChild(0);
assertEquals(0.10, boosterBody.getComponentLocations()[0].x, EPSILON);
assertEquals(0.10, boosterBody.getLength(), EPSILON);
}
{ // [1] test Rocket CM, before:
final RigidBody actualStructure = MassCalculator.calculateStructure(config);
final double actualRocketDryMass = actualStructure.cm.weight;
final double expRocketDryMass = 0.0081178754;
assertEquals(expRocketDryMass, actualRocketDryMass, EPSILON);
final Coordinate actualRocketDryCM = actualStructure.cm;
final double expCMx = 0.10;
assertEquals(expCMx, actualRocketDryCM.x, EPSILON);
}
boosterStage.setOverrideSubcomponents(true);
boosterStage.setCGOverridden(true);
boosterStage.setOverrideCGX(0.0);
{ // [1] test Rocket CM, before:
final RigidBody actualStructure = MassCalculator.calculateStructure(config);
final double actualRocketDryMass = actualStructure.cm.weight;
final double expRocketDryMass = 0.0081178754;
assertEquals(expRocketDryMass, actualRocketDryMass, EPSILON);
final Coordinate actualRocketDryCM = actualStructure.cm;
final double expCMx = 0.075;
assertEquals(expCMx, actualRocketDryCM.x, EPSILON);
}
}
@Test
public void testStageMassOverride() {
final Rocket rocket = TestRockets.makeSimple2Stage();
final AxialStage sustainerStage = (AxialStage) rocket.getChild(0);
final AxialStage boosterStage = (AxialStage) rocket.getChild(1);
final FlightConfiguration config = rocket.getSelectedConfiguration();
{ // [0] verify / document structure
final double expMass = 0.0040589377;
final BodyTube sustainerBody = (BodyTube) sustainerStage.getChild(0);
assertEquals(0.0, sustainerBody.getPosition().x, EPSILON);
assertEquals(0.1, sustainerBody.getLength(), EPSILON);
assertEquals(expMass, sustainerBody.getMass(), EPSILON);
final BodyTube boosterBody = (BodyTube) boosterStage.getChild(0);
assertEquals(0.10, boosterBody.getComponentLocations()[0].x, EPSILON);
assertEquals(0.10, boosterBody.getLength(), EPSILON);
assertEquals(expMass, sustainerBody.getMass(), EPSILON);
}
{ // [1] test Rocket CM, before:
final RigidBody actualStructure = MassCalculator.calculateStructure(config);
final double actualRocketDryMass = actualStructure.cm.weight;
final double expRocketDryMass = 0.0081178754;
assertEquals(expRocketDryMass, actualRocketDryMass, EPSILON);
final Coordinate actualRocketDryCM = actualStructure.cm;
final double expCMx = 0.10;
assertEquals(expCMx, actualRocketDryCM.x, EPSILON);
}
final BodyTube boosterBody = (BodyTube) boosterStage.getChild(0);
final double bodyMass = boosterBody.getMass();
assertEquals(0.0040589377, bodyMass, EPSILON);
boosterStage.setOverrideSubcomponents(true);
boosterStage.setMassOverridden(true);
boosterStage.setOverrideMass(bodyMass);
boosterBody.setOverrideSubcomponents(false);
boosterBody.setMassOverridden(true);
boosterBody.setOverrideMass(0.0);
{ // [1] test Rocket CM, before:
final RigidBody actualStructure = MassCalculator.calculateStructure(config);
final double actualRocketDryMass = actualStructure.cm.weight;
final double expRocketDryMass = 0.0081178754;
assertEquals(expRocketDryMass, actualRocketDryMass, EPSILON);
final Coordinate actualRocketDryCM = actualStructure.cm;
final double expCMx = 0.10;
assertEquals(expCMx, actualRocketDryCM.x, EPSILON);
}
}
@Test
public void testFalcon9HComponentMasses() {
Rocket rkt = TestRockets.makeFalcon9Heavy();
@ -723,7 +825,7 @@ public class MassCalculatorTest extends BaseTestCase {
double expTotalMass = overrideMass;
assertEquals(" Booster Launch Mass is incorrect: ", expTotalMass, calcTotalMass, EPSILON);
double expCMx = 6.0;
double expCMx = 6.484;
Coordinate expCM = new Coordinate(expCMx, 0, 0, expTotalMass);
assertEquals(" Booster Launch CM.x is incorrect: ", expCM.x, boosterSetCM.x, EPSILON);
assertEquals(" Booster Launch CM.y is incorrect: ", expCM.y, boosterSetCM.y, EPSILON);
@ -735,7 +837,7 @@ public class MassCalculatorTest extends BaseTestCase {
double boosterMOI_xx = burnout.getRotationalInertia();
assertEquals(" Booster x-axis MOI is incorrect: ", expMOI_axial, boosterMOI_xx, EPSILON);
double expMOI_tr = 14.815925423036177;
double expMOI_tr = 17.86133586701;
double boosterMOI_tr = burnout.getLongitudinalInertia();
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
}
@ -824,7 +926,7 @@ public class MassCalculatorTest extends BaseTestCase {
double calcTotalMass = structure.getMass();
assertEquals(" Booster Launch Mass is incorrect: ", expMass, calcTotalMass, EPSILON);
final double expCMx = 1.1191303646;
final double expCMx = 0.76762318688;
Coordinate expCM = new Coordinate(expCMx, 0, 0, expMass);
assertEquals(" Booster Launch CM.x is incorrect: ", expCM.x, structure.getCM().x, EPSILON);
assertEquals(" Booster Launch CM.y is incorrect: ", expCM.y, structure.getCM().y, EPSILON);
@ -832,11 +934,11 @@ public class MassCalculatorTest extends BaseTestCase {
assertEquals(" Booster Launch CM is incorrect: ", expCM, structure.getCM());
// Validate MOI
final double expMOI_axial = 0.005885793421431532;
final double expMOI_axial = 0.0038576236;
double boosterMOI_xx = structure.getRotationalInertia();
assertEquals(" Booster x-axis MOI is incorrect: ", expMOI_axial, boosterMOI_xx, EPSILON);
final double expMOI_tr = 0.04098909591063;
final double expMOI_tr = 0.123258667252;
double boosterMOI_tr = structure.getLongitudinalInertia();
assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON);
}