- Implemented a DampingMoment simulation listener example
- Added ability for simulation listeners to reserve their own data types. To support this: -- All data types can now be found from just the OpenRocketDocument (reduces some code duplication also). -- Custom expressions rebuilt after loading from file in case they use a listeners reserved type - Fixed (possibly unrelated) issue where datatypes would be deleted and re-made each step if a customexpression used a range or index subexpression
This commit is contained in:
parent
3fea838fab
commit
c9d04f5e0a
@ -1,8 +1,12 @@
|
|||||||
package net.sf.openrocket.document;
|
package net.sf.openrocket.document;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.sf.openrocket.document.events.DocumentChangeEvent;
|
import net.sf.openrocket.document.events.DocumentChangeEvent;
|
||||||
import net.sf.openrocket.document.events.DocumentChangeListener;
|
import net.sf.openrocket.document.events.DocumentChangeListener;
|
||||||
@ -13,7 +17,10 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
|||||||
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.customexpression.CustomExpression;
|
import net.sf.openrocket.simulation.customexpression.CustomExpression;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationListenerException;
|
||||||
|
import net.sf.openrocket.simulation.listeners.SimulationListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.util.ArrayList;
|
import net.sf.openrocket.util.ArrayList;
|
||||||
|
|
||||||
@ -121,6 +128,43 @@ public class OpenRocketDocument implements ComponentChangeListener {
|
|||||||
return customExpressions;
|
return customExpressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a set of all the flight data types defined or available in any way in the rocket document
|
||||||
|
*/
|
||||||
|
public Set<FlightDataType> getFlightDataTypes(){
|
||||||
|
Set<FlightDataType> allTypes = new LinkedHashSet<FlightDataType>();
|
||||||
|
|
||||||
|
// built in
|
||||||
|
Collections.addAll(allTypes, FlightDataType.ALL_TYPES);
|
||||||
|
|
||||||
|
// custom expressions
|
||||||
|
for (CustomExpression exp : customExpressions){
|
||||||
|
allTypes.add(exp.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulation listeners
|
||||||
|
for (Simulation sim : simulations){
|
||||||
|
for (String className : sim.getSimulationListeners()) {
|
||||||
|
SimulationListener l = null;
|
||||||
|
try {
|
||||||
|
Class<?> c = Class.forName(className);
|
||||||
|
l = (SimulationListener) c.newInstance();
|
||||||
|
|
||||||
|
Collections.addAll(allTypes, l.getFlightDataTypes());
|
||||||
|
//System.out.println("This document has expression datatype from "+l.getName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Could not instantiate listener: " + className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// imported data
|
||||||
|
/// not implemented yet
|
||||||
|
|
||||||
|
|
||||||
|
return allTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Rocket getRocket() {
|
public Rocket getRocket() {
|
||||||
return rocket;
|
return rocket;
|
||||||
|
|||||||
@ -704,8 +704,6 @@ class OpenRocketContentHandler extends AbstractElementHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DatatypeHandler extends AbstractElementHandler {
|
class DatatypeHandler extends AbstractElementHandler {
|
||||||
private final DocumentLoadingContext context;
|
private final DocumentLoadingContext context;
|
||||||
private final OpenRocketContentHandler contentHandler;
|
private final OpenRocketContentHandler contentHandler;
|
||||||
@ -1288,10 +1286,14 @@ class SimulationsHandler extends AbstractElementHandler {
|
|||||||
public void closeElement(String element, HashMap<String, String> attributes,
|
public void closeElement(String element, HashMap<String, String> attributes,
|
||||||
String content, WarningSet warnings) throws SAXException {
|
String content, WarningSet warnings) throws SAXException {
|
||||||
attributes.remove("status");
|
attributes.remove("status");
|
||||||
|
|
||||||
|
//Finished loading. Rebuilding custom expressions in case something has changed such as listener variable come available.
|
||||||
|
for (CustomExpression exp : doc.getCustomExpressions()){
|
||||||
|
exp.setExpression(exp.getExpressionString());
|
||||||
|
}
|
||||||
|
|
||||||
super.closeElement(element, attributes, content, warnings);
|
super.closeElement(element, attributes, content, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SingleSimulationHandler extends AbstractElementHandler {
|
class SingleSimulationHandler extends AbstractElementHandler {
|
||||||
|
|||||||
@ -269,8 +269,8 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
|||||||
if (type != null) {
|
if (type != null) {
|
||||||
// found it from symbol
|
// found it from symbol
|
||||||
|
|
||||||
// if name was not give (empty string), can use the one we found name
|
// if name was not given (empty string), can use the one we found
|
||||||
if ( s.equals("") || s == null ){
|
if ( s == null || s.isEmpty()){
|
||||||
s = type.getName();
|
s = type.getName();
|
||||||
}
|
}
|
||||||
if ( u == null ){
|
if ( u == null ){
|
||||||
@ -279,14 +279,19 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
|||||||
|
|
||||||
// if something has changed, then we need to remove the old one
|
// if something has changed, then we need to remove the old one
|
||||||
// otherwise, just return what we found
|
// otherwise, just return what we found
|
||||||
if ( !u.equals(type.getUnitGroup()) ||
|
if ( !u.equals(type.getUnitGroup()) )
|
||||||
!s.equals(type.getName())
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
oldPriority = type.priority;
|
oldPriority = type.priority;
|
||||||
|
|
||||||
EXISTING_TYPES.remove(type);
|
EXISTING_TYPES.remove(type);
|
||||||
log.info("Something changed with the type "+type.getName()+", removed old version.");
|
log.info("Unitgroup of type "+type.getName() +
|
||||||
|
", has changed from "+type.getUnitGroup().toString() +
|
||||||
|
" to "+u.toString() +
|
||||||
|
". Removing old version.");
|
||||||
|
}
|
||||||
|
else if (!s.equals(type.getName())) {
|
||||||
|
oldPriority = type.priority;
|
||||||
|
EXISTING_TYPES.remove(type);
|
||||||
|
log.info("Name of type "+type.getName()+", has changed to "+s+". Removing old version.");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return type;
|
return type;
|
||||||
|
|||||||
@ -34,11 +34,12 @@ public class CustomExpression implements Cloneable{
|
|||||||
private List<CustomExpression> subExpressions = new ArrayList<CustomExpression>();
|
private List<CustomExpression> subExpressions = new ArrayList<CustomExpression>();
|
||||||
|
|
||||||
public CustomExpression(OpenRocketDocument doc){
|
public CustomExpression(OpenRocketDocument doc){
|
||||||
|
this.doc = doc;
|
||||||
|
|
||||||
setName("");
|
setName("");
|
||||||
setSymbol("");
|
setSymbol("");
|
||||||
setUnit("");
|
setUnit("");
|
||||||
setExpression("");
|
setExpression("");
|
||||||
this.doc = doc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomExpression(OpenRocketDocument doc,
|
public CustomExpression(OpenRocketDocument doc,
|
||||||
@ -171,6 +172,7 @@ public class CustomExpression implements Cloneable{
|
|||||||
// get a list of all the names of all the available variables
|
// get a list of all the names of all the available variables
|
||||||
protected ArrayList<String> getAllNames(){
|
protected ArrayList<String> getAllNames(){
|
||||||
ArrayList<String> names = new ArrayList<String>();
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
|
/*
|
||||||
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
||||||
names.add(type.getName());
|
names.add(type.getName());
|
||||||
|
|
||||||
@ -181,12 +183,22 @@ public class CustomExpression implements Cloneable{
|
|||||||
names.add(exp.getName());
|
names.add(exp.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
for (FlightDataType type : doc.getFlightDataTypes()){
|
||||||
|
String symb = type.getName();
|
||||||
|
if (name == null) continue;
|
||||||
|
|
||||||
|
if (!name.equals( this.getName() )){
|
||||||
|
names.add(symb);
|
||||||
|
}
|
||||||
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a list of all the symbols of the available variables ignoring this one
|
// get a list of all the symbols of the available variables ignoring this one
|
||||||
protected ArrayList<String> getAllSymbols(){
|
protected ArrayList<String> getAllSymbols(){
|
||||||
ArrayList<String> symbols = new ArrayList<String>();
|
ArrayList<String> symbols = new ArrayList<String>();
|
||||||
|
/*
|
||||||
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
||||||
symbols.add(type.getSymbol());
|
symbols.add(type.getSymbol());
|
||||||
|
|
||||||
@ -196,6 +208,14 @@ public class CustomExpression implements Cloneable{
|
|||||||
symbols.add(exp.getSymbol());
|
symbols.add(exp.getSymbol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
for (FlightDataType type : doc.getFlightDataTypes()){
|
||||||
|
String symb = type.getSymbol();
|
||||||
|
if (!symb.equals( this.getSymbol() )){
|
||||||
|
symbols.add(symb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +325,7 @@ public class CustomExpression implements Cloneable{
|
|||||||
|
|
||||||
//// Define the available variables as empty
|
//// Define the available variables as empty
|
||||||
// The built in data types
|
// The built in data types
|
||||||
|
/*
|
||||||
for (FlightDataType type : FlightDataType.ALL_TYPES){
|
for (FlightDataType type : FlightDataType.ALL_TYPES){
|
||||||
builder.withVariable(new Variable(type.getSymbol()));
|
builder.withVariable(new Variable(type.getSymbol()));
|
||||||
}
|
}
|
||||||
@ -312,12 +333,16 @@ public class CustomExpression implements Cloneable{
|
|||||||
for (String symb : getAllSymbols()){
|
for (String symb : getAllSymbols()){
|
||||||
builder.withVariable(new Variable(symb));
|
builder.withVariable(new Variable(symb));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
for (FlightDataType type : doc.getFlightDataTypes()){
|
||||||
|
builder.withVariable(new Variable(type.getSymbol()));
|
||||||
|
}
|
||||||
|
|
||||||
// Try to build
|
// Try to build
|
||||||
try {
|
try {
|
||||||
builder.build();
|
builder.build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.user("Custom expression invalid : " + e.toString());
|
log.user("Custom expression " + this.toString() + " invalid : " + e.toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,14 +366,14 @@ public class CustomExpression implements Cloneable{
|
|||||||
* Builds a specified expression, log any errors and returns null in case of error.
|
* Builds a specified expression, log any errors and returns null in case of error.
|
||||||
*/
|
*/
|
||||||
protected Calculable buildExpression(ExpressionBuilder b){
|
protected Calculable buildExpression(ExpressionBuilder b){
|
||||||
Calculable calc;
|
Calculable calc = null;
|
||||||
try {
|
try {
|
||||||
calc = b.build();
|
calc = b.build();
|
||||||
} catch (UnknownFunctionException e1) {
|
} catch (UnknownFunctionException e1) {
|
||||||
log.user("Unknown function. Could not build custom expression "+name);
|
log.user("Unknown function. Could not build custom expression "+this.toString());
|
||||||
return null;
|
return null;
|
||||||
} catch (UnparsableExpressionException e1) {
|
} catch (UnparsableExpressionException e1) {
|
||||||
log.user("Unparsable expression. Could not build custom expression "+name+". "+e1.getMessage());
|
log.user("Unparsable expression. Could not build custom expression "+this.toString()+". "+e1.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,10 +421,13 @@ public class CustomExpression implements Cloneable{
|
|||||||
*/
|
*/
|
||||||
public FlightDataType getType(){
|
public FlightDataType getType(){
|
||||||
|
|
||||||
|
|
||||||
UnitGroup ug = UnitGroup.SIUNITS.get(unit);
|
UnitGroup ug = UnitGroup.SIUNITS.get(unit);
|
||||||
if ( ug == null ){
|
if ( ug == null ){
|
||||||
|
log.debug("SI unit not found for "+unit+" in expression "+toString()+". Making a new fixed unit.");
|
||||||
ug = new FixedUnitGroup(unit);
|
ug = new FixedUnitGroup(unit);
|
||||||
}
|
}
|
||||||
|
//UnitGroup ug = new FixedUnitGroup(unit);
|
||||||
|
|
||||||
FlightDataType type = FlightDataType.getType(name, symbol, ug);
|
FlightDataType type = FlightDataType.getType(name, symbol, ug);
|
||||||
|
|
||||||
@ -442,7 +470,7 @@ public class CustomExpression implements Cloneable{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "Custom expression : "+this.name.toString()+ " " + this.expression.toString();
|
return "[Expression name="+this.name.toString()+ " expression=" + this.expression+" unit="+this.unit+"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -3,13 +3,16 @@ package net.sf.openrocket.simulation.customexpression;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
|
|
||||||
public class CustomExpressionSimulationListener extends AbstractSimulationListener {
|
public class CustomExpressionSimulationListener extends AbstractSimulationListener {
|
||||||
|
|
||||||
|
private static final LogHelper log = Application.getLogger();
|
||||||
private final List<CustomExpression> expressions;
|
private final List<CustomExpression> expressions;
|
||||||
|
|
||||||
public CustomExpressionSimulationListener(List<CustomExpression> expressions) {
|
public CustomExpressionSimulationListener(List<CustomExpression> expressions) {
|
||||||
@ -25,10 +28,17 @@ public class CustomExpressionSimulationListener extends AbstractSimulationListen
|
|||||||
// Calculate values for custom expressions
|
// Calculate values for custom expressions
|
||||||
FlightDataBranch data = status.getFlightData();
|
FlightDataBranch data = status.getFlightData();
|
||||||
for (CustomExpression expression : expressions ) {
|
for (CustomExpression expression : expressions ) {
|
||||||
data.setValue(expression.getType(), expression.evaluateDouble(status));
|
double value = expression.evaluateDouble(status);
|
||||||
|
//log.debug("Setting value of custom expression "+expression.toString()+" = "+value);
|
||||||
|
data.setValue(expression.getType(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSystemListener(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,6 @@ public class IndexExpression extends CustomExpression {
|
|||||||
setExpression(indexText);
|
setExpression(indexText);
|
||||||
this.setName("");
|
this.setName("");
|
||||||
this.setSymbol(typeText);
|
this.setSymbol(typeText);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -35,7 +34,10 @@ public class IndexExpression extends CustomExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From the given datatype, get the time and function values and make an interpolator
|
// From the given datatype, get the time and function values and make an interpolator
|
||||||
FlightDataType type = getType();
|
|
||||||
|
//Note: must get in a way that flight data system will figure out units. Otherwise there will be a type conflict when we get the new data.
|
||||||
|
FlightDataType type = FlightDataType.getType(null, getSymbol(), null);
|
||||||
|
|
||||||
List<Double> data = status.getFlightData().get(type);
|
List<Double> data = status.getFlightData().get(type);
|
||||||
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
|
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
|
||||||
LinearInterpolator interp = new LinearInterpolator(time, data);
|
LinearInterpolator interp = new LinearInterpolator(time, data);
|
||||||
|
|||||||
@ -40,7 +40,6 @@ public class RangeExpression extends CustomExpression {
|
|||||||
this.expression = variableType+startTime+endTime; // this is used just for generating the hash
|
this.expression = variableType+startTime+endTime; // this is used just for generating the hash
|
||||||
|
|
||||||
log.info("New range expression, "+startTime + " to "+endTime);
|
log.info("New range expression, "+startTime + " to "+endTime);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -73,7 +72,9 @@ public class RangeExpression extends CustomExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From the given datatype, get the time and function values and make an interpolator
|
// From the given datatype, get the time and function values and make an interpolator
|
||||||
FlightDataType type = getType();
|
|
||||||
|
//Note: must get in a way that flight data system will figure out units. Otherwise there will be a type conflict when we get the new data.
|
||||||
|
FlightDataType type = FlightDataType.getType(null, getSymbol(), null);
|
||||||
|
|
||||||
List<Double> data = status.getFlightData().get(type);
|
List<Double> data = status.getFlightData().get(type);
|
||||||
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
|
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package net.sf.openrocket.simulation.listeners;
|
package net.sf.openrocket.simulation.listeners;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||||
@ -8,6 +10,7 @@ import net.sf.openrocket.motor.MotorInstance;
|
|||||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||||
import net.sf.openrocket.simulation.AccelerationData;
|
import net.sf.openrocket.simulation.AccelerationData;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.FlightEvent;
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
import net.sf.openrocket.simulation.MassData;
|
import net.sf.openrocket.simulation.MassData;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
@ -67,7 +70,13 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of any flight data types this listener creates.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FlightDataType[] getFlightDataTypes(){
|
||||||
|
return new FlightDataType[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// SimulationEventListener ////
|
//// SimulationEventListener ////
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package net.sf.openrocket.simulation.listeners;
|
package net.sf.openrocket.simulation.listeners;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||||
import net.sf.openrocket.simulation.AccelerationData;
|
import net.sf.openrocket.simulation.AccelerationData;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.MassData;
|
import net.sf.openrocket.simulation.MassData;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
@ -64,4 +67,5 @@ public interface SimulationComputationListener extends SimulationListener {
|
|||||||
|
|
||||||
public double postSimpleThrustCalculation(SimulationStatus status, double thrust) throws SimulationException;
|
public double postSimpleThrustCalculation(SimulationStatus status, double thrust) throws SimulationException;
|
||||||
|
|
||||||
|
public FlightDataType[] getFlightDataTypes();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package net.sf.openrocket.simulation.listeners;
|
package net.sf.openrocket.simulation.listeners;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.motor.MotorId;
|
import net.sf.openrocket.motor.MotorId;
|
||||||
import net.sf.openrocket.motor.MotorInstance;
|
import net.sf.openrocket.motor.MotorInstance;
|
||||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.FlightEvent;
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
@ -56,6 +59,10 @@ public interface SimulationEventListener {
|
|||||||
*/
|
*/
|
||||||
public boolean recoveryDeviceDeployment(SimulationStatus status, RecoveryDevice recoveryDevice)
|
public boolean recoveryDeviceDeployment(SimulationStatus status, RecoveryDevice recoveryDevice)
|
||||||
throws SimulationException;
|
throws SimulationException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public FlightDataType[] getFlightDataTypes();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package net.sf.openrocket.simulation.listeners;
|
package net.sf.openrocket.simulation.listeners;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.SimulationStatus;
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
|
|
||||||
@ -76,4 +79,11 @@ public interface SimulationListener {
|
|||||||
*/
|
*/
|
||||||
public boolean isSystemListener();
|
public boolean isSystemListener();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of any flight data types this listener creates.
|
||||||
|
*/
|
||||||
|
public FlightDataType[] getFlightDataTypes();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,129 @@
|
|||||||
|
package net.sf.openrocket.simulation.listeners.example;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
|
import net.sf.openrocket.motor.MotorId;
|
||||||
|
import net.sf.openrocket.motor.MotorInstance;
|
||||||
|
import net.sf.openrocket.motor.MotorInstanceConfiguration;
|
||||||
|
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
|
import net.sf.openrocket.simulation.SimulationStatus;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
|
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||||
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
import net.sf.openrocket.util.ArrayList;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
import net.sf.openrocket.util.PolyInterpolator;
|
||||||
|
|
||||||
|
public class DampingMoment extends AbstractSimulationListener {
|
||||||
|
|
||||||
|
private static final FlightDataType type = FlightDataType.getType("Damping moment coefficient", "Cdm", UnitGroup.UNITS_COEFFICIENT);
|
||||||
|
private static final FlightDataType[] typeList = {type};
|
||||||
|
|
||||||
|
public String getName(){
|
||||||
|
return "Damping moment listener";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of any flight data types this listener creates.
|
||||||
|
*/
|
||||||
|
public FlightDataType[] getFlightDataTypes(){
|
||||||
|
return typeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) throws SimulationException {
|
||||||
|
|
||||||
|
// Save it as a flightdatatype
|
||||||
|
|
||||||
|
//status.getFlightData().setValue(type, aerodynamicPart + propulsivePart);
|
||||||
|
status.getFlightData().setValue(type, calculate(status, flightConditions));
|
||||||
|
|
||||||
|
return flightConditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calculate(SimulationStatus status, FlightConditions flightConditions){
|
||||||
|
|
||||||
|
// Work out the propulsive/jet damping part of the moment.
|
||||||
|
|
||||||
|
// dm/dt = (thrust - ma)/v
|
||||||
|
FlightDataBranch data = status.getFlightData();
|
||||||
|
|
||||||
|
List<Double> mpAll = data.get(FlightDataType.TYPE_PROPELLANT_MASS);
|
||||||
|
List<Double> time = data.get(FlightDataType.TYPE_TIME);
|
||||||
|
if (mpAll == null || time == null){
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = mpAll.size();
|
||||||
|
|
||||||
|
// This isn't as accurate as I would like
|
||||||
|
double mdot=Double.NaN;
|
||||||
|
if (len > 2){
|
||||||
|
// Using polynomial interpolator for derivative. Doesn't help much
|
||||||
|
//double[] x = { time.get(len-5), time.get(len-4), time.get(len-3), time.get(len-2), time.get(len-1) };
|
||||||
|
//double[] y = { mpAll.get(len-5), mpAll.get(len-4), mpAll.get(len-3), mpAll.get(len-2), mpAll.get(len-1) };
|
||||||
|
//PolyInterpolator interp = new PolyInterpolator(x);
|
||||||
|
//double[] coeff = interp.interpolator(y);
|
||||||
|
//double dt = .01;
|
||||||
|
//mdot = (interp.eval(x[4], coeff) - interp.eval(x[4]-dt, coeff))/dt;
|
||||||
|
|
||||||
|
mdot = (mpAll.get(len-1) - mpAll.get(len-2)) / (time.get(len-1) - time.get(len-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
double cg = data.getLast(FlightDataType.TYPE_CG_LOCATION);
|
||||||
|
|
||||||
|
// find the maximum distance from nose to nozzle.
|
||||||
|
double nozzleDistance = 0;
|
||||||
|
for (MotorId id: status.getMotorConfiguration().getMotorIDs()){
|
||||||
|
MotorInstanceConfiguration config = status.getMotorConfiguration();
|
||||||
|
Coordinate position = config.getMotorPosition(id);
|
||||||
|
|
||||||
|
double x = position.x + config.getMotorInstance(id).getParentMotor().getLength();
|
||||||
|
if (x > nozzleDistance){
|
||||||
|
nozzleDistance = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now can get the propulsive part
|
||||||
|
double propulsivePart = mdot * Math.pow(nozzleDistance - cg, 2);
|
||||||
|
|
||||||
|
// Work out the aerodynamic part of the moment.
|
||||||
|
double aerodynamicPart = 0;
|
||||||
|
|
||||||
|
AerodynamicCalculator aerocalc = status.getSimulationConditions().getAerodynamicCalculator();
|
||||||
|
|
||||||
|
// Must go through each component ...
|
||||||
|
Map<RocketComponent, AerodynamicForces> forces = aerocalc.getForceAnalysis(status.getConfiguration(), flightConditions, null);
|
||||||
|
for (Map.Entry<RocketComponent, AerodynamicForces> entry : forces.entrySet()){
|
||||||
|
|
||||||
|
RocketComponent comp = entry.getKey();
|
||||||
|
|
||||||
|
if (!comp.isAerodynamic()) continue;
|
||||||
|
|
||||||
|
//System.out.println(comp.toString());
|
||||||
|
|
||||||
|
double CNa = entry.getValue().getCNa(); //?
|
||||||
|
double Cp = entry.getValue().getCP().length();
|
||||||
|
double z = comp.getPositionValue(); //?
|
||||||
|
|
||||||
|
aerodynamicPart += CNa*Math.pow(z-Cp, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double v = flightConditions.getVelocity();
|
||||||
|
double rho = flightConditions.getAtmosphericConditions().getDensity();
|
||||||
|
double ar = flightConditions.getRefArea();
|
||||||
|
|
||||||
|
aerodynamicPart = aerodynamicPart * .5 * rho * v * ar;
|
||||||
|
|
||||||
|
return aerodynamicPart + propulsivePart;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user