Merge pull request #577 from wolsen/issue-576

Fix ground hit velocity calculation
This commit is contained in:
Daniel Williams 2020-03-14 00:14:54 -04:00 committed by GitHub
commit 59a01b3877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 292 additions and 9 deletions

View File

@ -101,7 +101,7 @@ public class FlightData {
for (FlightDataBranch b : branches)
this.addBranch(b);
calculateIntrestingValues();
calculateInterestingValues();
}
@ -126,7 +126,7 @@ public class FlightData {
branches.add(branch);
if (branches.size() == 1) {
calculateIntrestingValues();
calculateInterestingValues();
}
}
@ -185,7 +185,7 @@ public class FlightData {
* Calculate the max. altitude/velocity/acceleration, time to apogee, flight time
* and ground hit velocity.
*/
private void calculateIntrestingValues() {
private void calculateInterestingValues() {
if (branches.isEmpty())
return;
@ -195,13 +195,7 @@ public class FlightData {
maxMachNumber = branch.getMaximum(FlightDataType.TYPE_MACH_NUMBER);
flightTime = branch.getLast(FlightDataType.TYPE_TIME);
if (branch.getLast(FlightDataType.TYPE_ALTITUDE) < 10) {
groundHitVelocity = branch.getLast(FlightDataType.TYPE_VELOCITY_TOTAL);
} else {
groundHitVelocity = Double.NaN;
}
// Time to apogee
List<Double> time = branch.get(FlightDataType.TYPE_TIME);
List<Double> altitude = branch.get(FlightDataType.TYPE_ALTITUDE);
@ -236,6 +230,10 @@ public class FlightData {
double t = event.getTime();
List<Double> velocity = branch.get(FlightDataType.TYPE_VELOCITY_TOTAL);
deploymentVelocity = MathUtil.interpolate( time, velocity, t);
} else if (event.getType() == FlightEvent.Type.GROUND_HIT) {
double t = event.getTime();
List<Double> velocity = branch.get(FlightDataType.TYPE_VELOCITY_TOTAL);
groundHitVelocity = MathUtil.interpolate( time, velocity, t);
}
}

View File

@ -0,0 +1,285 @@
package net.sf.openrocket.simulation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import net.sf.openrocket.aerodynamics.WarningSet;
/**
* Tests the FlightData object.
*
* @author Billy Olsen
*/
public class TestFlightData {
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#FlightData()}.
*/
@Test
public void testFlightData() {
FlightData data = new FlightData();
WarningSet warnings = data.getWarningSet();
assertNotNull(warnings);
assertTrue(warnings.isEmpty());
assertEquals(0, data.getBranchCount());
assertEquals(Double.NaN, data.getDeploymentVelocity(), 0.00);
assertEquals(Double.NaN, data.getFlightTime(), 0.00);
assertEquals(Double.NaN, data.getGroundHitVelocity(), 0.00);
assertEquals(Double.NaN, data.getLaunchRodVelocity(), 0.00);
assertEquals(Double.NaN, data.getMaxAcceleration(), 0.00);
assertEquals(Double.NaN, data.getMaxAltitude(), 0.00);
assertEquals(Double.NaN, data.getMaxMachNumber(), 0.00);
assertEquals(Double.NaN, data.getTimeToApogee(), 0.00);
}
/**
* Tests flight data created from summary data.
*/
@Test
public void testFlightDataFromSummaryData() {
double deploymentVelocity = 14.8;
double flightTime = 69.1;
double groundHitVelocity = 3.4;
double launchRodVelocity = 17.5;
double maxAcceleration = 156.2;
double maxVelocity = 105.9;
double maxAltitude = 355.1;
double maxMachNumber = 0.31;
double timeToApogee = 7.96;
FlightData data = new FlightData(maxAltitude, maxVelocity, maxAcceleration,
maxMachNumber, timeToApogee, flightTime,
groundHitVelocity, launchRodVelocity,
deploymentVelocity);
WarningSet warnings = data.getWarningSet();
assertNotNull(warnings);
assertTrue(warnings.isEmpty());
assertEquals(0, data.getBranchCount());
assertEquals(deploymentVelocity, data.getDeploymentVelocity(), 0.00);
assertEquals(flightTime, data.getFlightTime(), 0.00);
assertEquals(groundHitVelocity, data.getGroundHitVelocity(), 0.00);
assertEquals(launchRodVelocity, data.getLaunchRodVelocity(), 0.00);
assertEquals(maxAcceleration, data.getMaxAcceleration(), 0.00);
assertEquals(maxAltitude, data.getMaxAltitude(), 0.00);
assertEquals(maxMachNumber, data.getMaxMachNumber(), 0.00);
assertEquals(timeToApogee, data.getTimeToApogee(), 0.00);
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#FlightData(net.sf.openrocket.simulation.FlightDataBranch[])}.
*/
@Test
public void testFlightDataFlightDataBranchArray() {
FlightData data = new FlightData(new FlightDataBranch("Test", FlightDataType.TYPE_TIME));
WarningSet warnings = data.getWarningSet();
assertNotNull(warnings);
assertTrue(warnings.isEmpty());
assertEquals(1, data.getBranchCount());
data = new FlightData(new FlightDataBranch("Test 1", FlightDataType.TYPE_TIME),
new FlightDataBranch("Test 2", FlightDataType.TYPE_TIME));
warnings = data.getWarningSet();
assertNotNull(warnings);
assertTrue(warnings.isEmpty());
assertEquals(2, data.getBranchCount());
}
private FlightDataBranch createFlightDataBranch(final String name, final FlightDataType dataType, final double[] values) {
final FlightDataBranch branch = new FlightDataBranch(name, dataType);
addDataPoints(branch, dataType, values);
return branch;
}
private void addDataPoints(final FlightDataBranch branch, final FlightDataType dataType, final double[] values) {
for (int i=0; i < values.length; i++) {
branch.addPoint();
branch.setValue(dataType, values[i]);
}
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#getMaxAltitude()}.
*/
@Test
public void testGetMaxAltitudeCalculated() {
final double[] altitudes = new double[] {
10.5,
37.771,
37.5,
5.1,
0.0
};
FlightDataBranch branch =
createFlightDataBranch("Test Max Alt", FlightDataType.TYPE_ALTITUDE, altitudes);
FlightData data = new FlightData(branch);
assertEquals(37.771, data.getMaxAltitude(), 0.000);
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#getMaxVelocity()}.
*/
@Test
public void testGetMaxVelocityCalculated() {
final double[] velocities = new double[] {
10.5,
23.7,
35.5,
30.1,
0.0
};
FlightDataBranch branch =
createFlightDataBranch("Test Max Velocity", FlightDataType.TYPE_VELOCITY_TOTAL, velocities);
FlightData data = new FlightData(branch);
assertEquals(35.5, data.getMaxVelocity(), 0.000);
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#getMaxMachNumber()}.
*/
@Test
public void testGetMaxMachNumberCalculated() {
final double[] machs = new double[] {
0.1,
0.2,
0.333,
0.3,
0.1
};
FlightDataBranch branch =
createFlightDataBranch("Test Max Mach", FlightDataType.TYPE_MACH_NUMBER, machs);
FlightData data = new FlightData(branch);
assertEquals(0.333, data.getMaxMachNumber(), 0.000);
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#getFlightTime()}.
*/
@Test
public void testGetFlightTime() {
final double[] times = new double[] {
1.0,
5.0,
15.0,
20.1,
30.2
};
FlightDataBranch branch =
createFlightDataBranch("Test Flight Time", FlightDataType.TYPE_TIME, times);
// Flight time is calculated as the last time entry
FlightData data = new FlightData(branch);
assertEquals(30.2, data.getFlightTime(), 0.000);
}
/**
* Test method for {@link net.sf.openrocket.simulation.FlightData#getGroundHitVelocity()}.
*/
@Test
public void testGetGroundHitVelocity() {
/*
* Setup a flight profile where there is data logged for every second.
* The time events will start at 1, rather than 0 so the time into the
* data log is the index + 1.0 seconds.
*
* i.e. at second 1, the velocity becomes 1.2 m/s, the altitude of the
* rocket is 1.2, and the LiftOff event is saved.
*
* This loosely approximates a flight of about 21 seconds where it
* flies up quickly and comes down quickly. The actual flight profile
* is not as important as the fact that a profile exists.
*
* Each array is stored as
*/
final double[] velocities = new double[] {
// launch to burn out
1.2, 15.0, 31.1, 45.6,
// burn out to apogee
33.6, 21.2, 14.1, 6.8, 0.0,
// apogee to ejection charge
2.4, 4.7, 8.6, 9.23,
// ejection charge to parachute deployment
7.1, 6.2, 6.2, 6.2, 6.2,
// parachute deployment to ground hit
6.2, 0.0, 0.0
};
final double[] altitudes = new double[] {
// launch to burn out
1.2, 16.2, 47.3, 92.9,
// burn out to apogee
126.5, 147.7, 161.8, 168.6, 168.6,
// apogee to ejection charge
166.2, 161.5, 152.9, 143.67,
// ejection charge to parachute deployment
136.57, 113.81, 91.05, 68.29, 45.53,
// parachute deployment to ground hit
22.77, 0.0, 0.0
};
final FlightEvent.Type[] eventTypes = new FlightEvent.Type[] {
// launch to burn out
FlightEvent.Type.LIFTOFF, FlightEvent.Type.LAUNCHROD,
FlightEvent.Type.ALTITUDE, FlightEvent.Type.BURNOUT,
// burn out to apogee
FlightEvent.Type.ALTITUDE, FlightEvent.Type.ALTITUDE,
FlightEvent.Type.ALTITUDE, FlightEvent.Type.ALTITUDE,
FlightEvent.Type.APOGEE,
// apogee to ejection charge
FlightEvent.Type.ALTITUDE, FlightEvent.Type.ALTITUDE,
FlightEvent.Type.ALTITUDE, FlightEvent.Type.EJECTION_CHARGE,
// ejection charge to parachute deployment
FlightEvent.Type.ALTITUDE, FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT,
FlightEvent.Type.ALTITUDE, FlightEvent.Type.ALTITUDE,
FlightEvent.Type.ALTITUDE,
// parachute deployment to ground hit
FlightEvent.Type.GROUND_HIT, FlightEvent.Type.ALTITUDE,
FlightEvent.Type.SIMULATION_END
};
assertEquals(velocities.length, eventTypes.length);
assertEquals(velocities.length, altitudes.length);
// This flight data branch only needs to record for time,
// altitude and velocity.
FlightDataBranch branch =
new FlightDataBranch("Ground Hit Velocities",
FlightDataType.TYPE_TIME,
FlightDataType.TYPE_ALTITUDE,
FlightDataType.TYPE_VELOCITY_TOTAL);
for (int i = 0; i < velocities.length; i++) {
branch.addPoint();
// the data entries are 1 second ahead of the index
double time = i + 1.0;
branch.setValue(FlightDataType.TYPE_TIME, time);
branch.setValue(FlightDataType.TYPE_ALTITUDE, altitudes[i]);
branch.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, velocities[i]);
branch.addEvent(new FlightEvent(eventTypes[i], time));
}
FlightData data = new FlightData(branch);
assertEquals(6.2, data.getGroundHitVelocity(), 0.000);
}
}