Search in sources :

Example 1 with Engine

use of com.chrisali.javaflightsim.simulation.propulsion.Engine in project j6dof-flight-sim by chris-ali.

the class AccelAndMoments method calculateLinearAccelerations.

/**
 * Calculates the total linear acceleration experienced by the aircraft (ft/sec^2)
 *
 * @param windParameters
 * @param angularRates
 * @param environmentParameters
 * @param controls
 * @param alphaDot
 * @param engineList
 * @param aircraft
 * @param groundReaction
 * @param heightAGL
 * @return linearAccelerations
 */
public static double[] calculateLinearAccelerations(double[] windParameters, double[] angularRates, Map<EnvironmentParameters, Double> environmentParameters, Map<FlightControl, Double> controls, double alphaDot, Set<Engine> engineList, Aircraft aircraft, IntegrateGroundReaction groundReaction, double heightAGL) {
    Vector3D aeroForceVector = new Vector3D(aero.calculateBodyForces(windParameters, angularRates, environmentParameters, controls, alphaDot, heightAGL));
    Vector3D groundForceVector = new Vector3D(groundReaction.getTotalGroundForces());
    // Create a vector of engine force, iterate through engineList and add the thrust of each engine in list
    Vector3D engineForceVector = Vector3D.ZERO;
    for (Engine engine : engineList) engineForceVector = engineForceVector.add(new Vector3D(engine.getEngineThrust()));
    linearAccelerations = aeroForceVector.add(engineForceVector).add(groundForceVector).scalarMultiply(1 / aircraft.getMassProperty(MassProperties.TOTAL_MASS)).toArray();
    return SaturationUtilities.limitLinearAccelerations(linearAccelerations);
}
Also used : Vector3D(org.apache.commons.math3.geometry.euclidean.threed.Vector3D) Engine(com.chrisali.javaflightsim.simulation.propulsion.Engine)

Example 2 with Engine

use of com.chrisali.javaflightsim.simulation.propulsion.Engine in project j6dof-flight-sim by chris-ali.

the class Integrate6DOFEquations method updateDataMembers.

/**
 *  Runs various helper methods to update data members in {@link Integrate6DOFEquations}. It updates the 6DOF states, environment parameters, controls, engine state, and finally
 *  calculates accelerations and moments to be used in {@link Integrate6DOFEquations#updateDerivatives(double[])}
 */
private void updateDataMembers() {
    // Assign indices in yTemp array to 6DOF state arrays
    for (int i = 0; i < linearVelocities.length; i++) {
        linearVelocities[i] = y[i];
        NEDPosition[i] = y[i + 3];
        eulerAngles[i] = y[i + 6];
        angularRates[i] = y[i + 9];
    }
    // Implement saturation and (2)pi bounding to keep states within realistic limits
    linearVelocities = SaturationUtilities.limitLinearVelocities(linearVelocities);
    NEDPosition = SaturationUtilities.limitNEDPosition(NEDPosition, terrainHeight);
    eulerAngles = SaturationUtilities.piBounding(eulerAngles, angularRates);
    angularRates = SaturationUtilities.limitAngularRates(angularRates);
    // Update wind parameters
    windParameters = SixDOFUtilities.calculateWindParameters(linearVelocities);
    // Update environment
    environmentParameters = Environment.getAndUpdateEnvironmentParams(NEDPosition);
    // Update all engines in engine list
    for (Engine engine : engineList) engine.updateEngineState(controlsMap, environmentParameters, windParameters);
    // Update alphaDot
    alphaDot = SixDOFUtilities.calculateAlphaDot(linearVelocities, sixDOFDerivatives);
    // Update mach
    mach = SixDOFUtilities.calculateMach(windParameters, environmentParameters);
    // Integrate another step of ground reaction only if within 100 ft of ground
    double heightAGL = NEDPosition[2] - terrainHeight;
    if (heightAGL < 100)
        groundReaction.integrateStep(terrainHeight);
    // System.out.println(groundReaction);
    // Update accelerations
    linearAccelerations = AccelAndMoments.calculateLinearAccelerations(windParameters, angularRates, environmentParameters, controlsMap, alphaDot, engineList, aircraft, groundReaction, heightAGL);
    // Update moments
    totalMoments = AccelAndMoments.calculateTotalMoments(windParameters, angularRates, environmentParameters, controlsMap, alphaDot, engineList, aircraft, groundReaction, heightAGL);
    // Recalculates derivatives for next step
    updateDerivatives(y);
}
Also used : Engine(com.chrisali.javaflightsim.simulation.propulsion.Engine)

Example 3 with Engine

use of com.chrisali.javaflightsim.simulation.propulsion.Engine in project j6dof-flight-sim by chris-ali.

the class Integrate6DOFEquations method logData.

/**
 *  Adds simulation data to the ArrayList {@link Integrate6DOFEquations#getLogsOut()} after each successful step of integration
 *  for plotting and outputs to the console, if set in {@link Integrate6DOFEquations#options}.
 *  The data calculated in each step of integration is available in the EnumMap {@link Integrate6DOFEquations#getSimOut()}. All
 *  collections are synchronized to mitigate data access problems from threading
 */
private void logData() {
    // Need to initialize within logData(), else plots won't display correctly
    simOut = Collections.synchronizedMap(new EnumMap<SimOuts, Double>(SimOuts.class));
    synchronized (simOut) {
        // Assign EnumMap with data members from integration
        simOut.put(SimOuts.TIME, t);
        // 6DOF States
        simOut.put(SimOuts.U, linearVelocities[0]);
        simOut.put(SimOuts.V, linearVelocities[1]);
        simOut.put(SimOuts.W, linearVelocities[2]);
        simOut.put(SimOuts.NORTH, NEDPosition[0]);
        simOut.put(SimOuts.EAST, NEDPosition[1]);
        simOut.put(SimOuts.ALT, NEDPosition[2]);
        simOut.put(SimOuts.PHI, eulerAngles[0]);
        simOut.put(SimOuts.THETA, eulerAngles[1]);
        simOut.put(SimOuts.PSI, eulerAngles[2]);
        simOut.put(SimOuts.P, angularRates[0]);
        simOut.put(SimOuts.Q, angularRates[1]);
        simOut.put(SimOuts.R, angularRates[2]);
        // Earth Position/Velocity
        simOut.put(SimOuts.LAT, y[12]);
        simOut.put(SimOuts.LAT_DOT, sixDOFDerivatives[12]);
        simOut.put(SimOuts.LON, y[13]);
        simOut.put(SimOuts.LON_DOT, sixDOFDerivatives[13]);
        // Wind Parameters
        simOut.put(SimOuts.TAS, windParameters[0]);
        simOut.put(SimOuts.BETA, windParameters[1]);
        simOut.put(SimOuts.ALPHA, windParameters[2] * -1);
        simOut.put(SimOuts.ALPHA_DOT, alphaDot);
        simOut.put(SimOuts.MACH, mach);
        // Accelerations
        simOut.put(SimOuts.A_X, linearAccelerations[0]);
        simOut.put(SimOuts.A_Y, linearAccelerations[1]);
        simOut.put(SimOuts.A_Z, linearAccelerations[2]);
        simOut.put(SimOuts.AN_X, (sixDOFDerivatives[0] / gravity));
        simOut.put(SimOuts.AN_Y, (sixDOFDerivatives[1] / gravity));
        simOut.put(SimOuts.AN_Z, ((sixDOFDerivatives[2] / gravity) + 1.0));
        // Moments
        simOut.put(SimOuts.L, totalMoments[0]);
        simOut.put(SimOuts.M, totalMoments[1]);
        simOut.put(SimOuts.N, totalMoments[2]);
        // 6DOF Derivatives
        simOut.put(SimOuts.U_DOT, sixDOFDerivatives[0]);
        simOut.put(SimOuts.V_DOT, sixDOFDerivatives[1]);
        simOut.put(SimOuts.W_DOT, sixDOFDerivatives[2]);
        simOut.put(SimOuts.NORTH_DOT, sixDOFDerivatives[3]);
        simOut.put(SimOuts.EAST_DOT, sixDOFDerivatives[4]);
        simOut.put(SimOuts.ALT_DOT, (sixDOFDerivatives[5] * 60));
        simOut.put(SimOuts.PHI_DOT, sixDOFDerivatives[6]);
        simOut.put(SimOuts.THETA_DOT, sixDOFDerivatives[7]);
        simOut.put(SimOuts.PSI_DOT, sixDOFDerivatives[8]);
        simOut.put(SimOuts.P_DOT, sixDOFDerivatives[9]);
        simOut.put(SimOuts.Q_DOT, sixDOFDerivatives[10]);
        simOut.put(SimOuts.R_DOT, sixDOFDerivatives[11]);
        // Engine(s)
        simOut.put(SimOuts.THRUST_1, 0.0);
        simOut.put(SimOuts.RPM_1, 0.0);
        simOut.put(SimOuts.FUEL_FLOW_1, 0.0);
        simOut.put(SimOuts.THRUST_2, 0.0);
        simOut.put(SimOuts.RPM_2, 0.0);
        simOut.put(SimOuts.FUEL_FLOW_2, 0.0);
        simOut.put(SimOuts.THRUST_3, 0.0);
        simOut.put(SimOuts.RPM_3, 0.0);
        simOut.put(SimOuts.FUEL_FLOW_3, 0.0);
        simOut.put(SimOuts.THRUST_4, 0.0);
        simOut.put(SimOuts.RPM_4, 0.0);
        simOut.put(SimOuts.FUEL_FLOW_4, 0.0);
        for (Engine engine : engineList) {
            int engineNumber = engine.getEngineNumber();
            simOut.put(Enum.valueOf(SimOuts.class, "THRUST_" + engineNumber), engine.getEngineThrust()[0]);
            simOut.put(Enum.valueOf(SimOuts.class, "RPM_" + engineNumber), engine.getRPM());
            simOut.put(Enum.valueOf(SimOuts.class, "FUEL_FLOW_" + engineNumber), engine.getFuelFlow());
        }
        // Controls
        simOut.put(SimOuts.ELEVATOR, controlsMap.get(FlightControl.ELEVATOR));
        simOut.put(SimOuts.AILERON, controlsMap.get(FlightControl.AILERON));
        simOut.put(SimOuts.RUDDER, controlsMap.get(FlightControl.RUDDER));
        simOut.put(SimOuts.THROTTLE_1, controlsMap.get(FlightControl.THROTTLE_1));
        simOut.put(SimOuts.THROTTLE_2, controlsMap.get(FlightControl.THROTTLE_2));
        simOut.put(SimOuts.THROTTLE_3, controlsMap.get(FlightControl.THROTTLE_3));
        simOut.put(SimOuts.THROTTLE_4, controlsMap.get(FlightControl.THROTTLE_4));
        simOut.put(SimOuts.PROPELLER_1, controlsMap.get(FlightControl.PROPELLER_1));
        simOut.put(SimOuts.PROPELLER_2, controlsMap.get(FlightControl.PROPELLER_2));
        simOut.put(SimOuts.PROPELLER_3, controlsMap.get(FlightControl.PROPELLER_3));
        simOut.put(SimOuts.PROPELLER_4, controlsMap.get(FlightControl.PROPELLER_4));
        simOut.put(SimOuts.MIXTURE_1, controlsMap.get(FlightControl.MIXTURE_1));
        simOut.put(SimOuts.MIXTURE_2, controlsMap.get(FlightControl.MIXTURE_2));
        simOut.put(SimOuts.MIXTURE_3, controlsMap.get(FlightControl.MIXTURE_3));
        simOut.put(SimOuts.MIXTURE_4, controlsMap.get(FlightControl.MIXTURE_4));
        simOut.put(SimOuts.FLAPS, controlsMap.get(FlightControl.FLAPS));
        simOut.put(SimOuts.GEAR, controlsMap.get(FlightControl.GEAR));
    }
    synchronized (logsOut) {
        // Removes the first entry in logsOut to keep a maximum of 100 sec of flight data in UNLIMITED_FLIGHT
        if (options.contains(Options.UNLIMITED_FLIGHT) & t >= 100 & logsOut.size() > 0)
            logsOut.remove(0);
        // Add output step to logging arrayList
        logsOut.add(simOut);
    }
}
Also used : EnumMap(java.util.EnumMap) Engine(com.chrisali.javaflightsim.simulation.propulsion.Engine)

Example 4 with Engine

use of com.chrisali.javaflightsim.simulation.propulsion.Engine in project j6dof-flight-sim by chris-ali.

the class Trimming method trimSim.

/**
 * Trims an aircraft longitudinally for a forward velocity and altitude specified in
 *
 * <p> SimConfig/InitialConditions.txt </p>
 *
 * by setting the elevator, throttle and pitch attitude. These values are calculated by statically equating forces and moments.
 * If unable to reach a given trim condition, the method will return the maximum values for each control and pitch attitude.
 * These values are then saved to
 *
 * <p> SimConfig/InitialConditions.txt </p>
 * and
 * <p> SimConfig/InitialControls.txt </p>
 *
 * as long as the test mode boolean flag is false; otherwise the results will be displayed in the console
 *
 * @param configuration
 * @param testMode
 */
public static void trimSim(SimulationConfiguration configuration, boolean testMode) {
    Aircraft aircraft = FileUtilities.readAircraftConfiguration(configuration.getSelectedAircraft());
    aero = new Aerodynamics(aircraft);
    initialConditions = configuration.getInitialConditions();
    initialControls = configuration.getInitialControls();
    environmentParams = Environment.getAndUpdateEnvironmentParams(new double[] { 0, 0, initialConditions.get(InitialConditions.INITD) });
    double alphaMin = -0.18, alphaMax = 0.18, throttleMin = 0.0, throttleMax = 1.0, alphaTrim = 0.0, thetaTrim = 0.0, elevTrim = 0.0, throttleTrim = 0.0, wVelocityTrim = 0.0, lift = 0.0, drag = 0.0, totalThrust = 0.0, zForce = 100.0;
    double trueAirspeed = Math.sqrt(Math.pow(initialConditions.get(InitialConditions.INITU), 2) + Math.pow(initialConditions.get(InitialConditions.INITW), 2));
    double weight = aircraft.getMassProperty(MassProperties.TOTAL_MASS) * Environment.getGravity();
    double q = environmentParams.get(EnvironmentParameters.RHO) * Math.pow(trueAirspeed, 2) / 2;
    double s = aircraft.getWingGeometry(WingGeometry.S_WING);
    int counter = 0;
    logger.debug("Finding trim pitch and elevator...");
    do {
        alphaTrim = (alphaMin + alphaMax) / 2;
        // Break out of loop if trim condition not satisfied after 100 attempts
        if (counter == 100) {
            logger.error("Unable to trim elevator and pitch for given conditions!");
            break;
        }
        // =============================================== Pitch ================================================================
        // Calculate trim pitch by using (theta = alpha + FPA)
        // FPA is zero in level flight
        thetaTrim = alphaTrim + 0;
        double[] windParameters = new double[] { trueAirspeed, 0, alphaTrim };
        double CL_alpha = aero.calculateInterpStabDer(windParameters, initialControls, StabilityDerivatives.CL_ALPHA);
        double CL_0 = aero.calculateInterpStabDer(windParameters, initialControls, StabilityDerivatives.CL_0);
        lift = q * s * ((CL_alpha * alphaTrim) + CL_0);
        double CD_alpha = aero.calculateInterpStabDer(windParameters, initialControls, StabilityDerivatives.CD_ALPHA);
        double CD_0 = aero.calculateInterpStabDer(windParameters, initialControls, StabilityDerivatives.CD_0);
        drag = q * s * ((CD_alpha * alphaTrim) + CD_0);
        // Calculate zForce to find trim alpha to zero forces
        zForce = (-lift * Math.cos(alphaTrim)) - (drag * Math.sin(alphaTrim)) + (weight * Math.cos(thetaTrim));
        if (zForce > 0)
            alphaMin = alphaTrim;
        else
            alphaMax = alphaTrim;
        // Recalculate w velocity for new angle of attack
        wVelocityTrim = windParameters[0] * Math.sin(alphaTrim);
        // ==================================================== Elevator ========================================================
        // Calculate trim elevator, limiting if necessary
        double CM_alpha = aero.calculateInterpStabDer(windParameters, initialControls, StabilityDerivatives.CM_ALPHA);
        double CM_d_elev = aircraft.getStabilityDerivative(StabilityDerivatives.CM_D_ELEV).getValue();
        double CM_0 = aircraft.getStabilityDerivative(StabilityDerivatives.CM_0).getValue();
        elevTrim = (CM_0 + (CM_alpha * alphaTrim)) / CM_d_elev;
        elevTrim = elevTrim > FlightControl.ELEVATOR.getMaximum() ? FlightControl.ELEVATOR.getMaximum() : elevTrim < FlightControl.ELEVATOR.getMinimum() ? FlightControl.ELEVATOR.getMinimum() : elevTrim;
        counter++;
    } while (Math.abs(zForce) > 1);
    logger.debug("...done!");
    // ==================================================== Throttle ============================================================
    Set<Engine> engines = aircraft.getEngines();
    drag = (drag * Math.cos(alphaTrim)) - (lift * Math.sin(alphaTrim)) + (weight * Math.sin(thetaTrim));
    counter = 0;
    logger.debug("Finding trim throttle...");
    do {
        throttleTrim = (throttleMin + throttleMax) / 2;
        // Break out of loop if trim condition not satisfied after 100 attempts
        if (counter == 100) {
            logger.error("Unable to trim throttle for given conditions!");
            break;
        }
        initialControls.put(FlightControl.THROTTLE_1, throttleTrim);
        initialControls.put(FlightControl.THROTTLE_2, throttleTrim);
        initialControls.put(FlightControl.THROTTLE_3, throttleTrim);
        initialControls.put(FlightControl.THROTTLE_4, throttleTrim);
        // Get total thrust, equate it with drag of aircraft to find trim throttle
        totalThrust = 0.0;
        for (Engine engine : engines) {
            engine.updateEngineState(initialControls, environmentParams, new double[] { trueAirspeed, 0, 0 });
            totalThrust += engine.getEngineThrust()[0];
        }
        if (totalThrust < drag)
            throttleMin = throttleTrim;
        else
            throttleMax = throttleTrim;
        counter++;
    } while (Math.abs(totalThrust - drag) > 1);
    logger.debug("...done!");
    // Update initialControls and initialConditions
    initialConditions.put(InitialConditions.INITTHETA, thetaTrim);
    initialConditions.put(InitialConditions.INITW, wVelocityTrim);
    initialControls.put(FlightControl.ELEVATOR, -elevTrim);
    initialControls.put(FlightControl.AILERON, 0.0);
    initialControls.put(FlightControl.RUDDER, 0.0);
    logger.debug("Finished trimming aircraft!");
    logger.debug(String.format("Trim controls are: \nElevator: %.4f rad\nThrottle: %.4f", elevTrim, throttleTrim));
    logger.debug(String.format("Trim states are: \nW Velocity: %3.4f ft/sec\nTheta: %.4f rad\nAlpha: %.4f rad", wVelocityTrim, thetaTrim, alphaTrim));
    // In test mode do not write any config settings to files
    if (!testMode) {
        logger.debug("Updating initial conditions and initial flight controls...");
        configuration.setInitialConditions(initialConditions);
        configuration.setInitialControls(initialControls);
        configuration.save();
    } else {
        logger.debug(Trimming.outputTrimValues());
    }
}
Also used : Aerodynamics(com.chrisali.javaflightsim.simulation.aircraft.Aerodynamics) Aircraft(com.chrisali.javaflightsim.simulation.aircraft.Aircraft) Engine(com.chrisali.javaflightsim.simulation.propulsion.Engine)

Example 5 with Engine

use of com.chrisali.javaflightsim.simulation.propulsion.Engine in project j6dof-flight-sim by chris-ali.

the class AccelAndMoments method calculateTotalMoments.

/**
 * Calculates the total moment experienced by the aircraft (lb ft)
 *
 * @param windParameters
 * @param angularRates
 * @param environmentParameters
 * @param controls
 * @param alphaDot
 * @param engineList
 * @param aircraft
 * @param groundReaction
 * @param heightAGL
 * @return totalMoments
 */
public static double[] calculateTotalMoments(double[] windParameters, double[] angularRates, Map<EnvironmentParameters, Double> environmentParameters, Map<FlightControl, Double> controls, double alphaDot, Set<Engine> engineList, Aircraft aircraft, IntegrateGroundReaction groundReaction, double heightAGL) {
    Vector3D aeroForceVector = new Vector3D(aero.calculateBodyForces(windParameters, angularRates, environmentParameters, controls, alphaDot, heightAGL));
    // Apache Commons vector methods only accept primitive double[] arrays
    Vector3D acVector = new Vector3D(aircraft.getAerodynamicCenter());
    Vector3D cgVector = new Vector3D(aircraft.getCenterOfGravity());
    Vector3D aeroForceCrossProd = Vector3D.crossProduct(aeroForceVector, acVector.subtract(cgVector));
    Vector3D aeroMomentVector = new Vector3D(aero.calculateAeroMoments(windParameters, angularRates, environmentParameters, controls, alphaDot));
    Vector3D groundMomentVector = new Vector3D(groundReaction.getTotalGroundMoments());
    // Create a vector of engine moment, iterate through engineList and add the moment of each engine in list
    Vector3D engineMoment = Vector3D.ZERO;
    for (Engine engine : engineList) engineMoment = engineMoment.add(new Vector3D(engine.getEngineMoment()));
    totalMoments = aeroMomentVector.add(engineMoment).add(aeroForceCrossProd).add(groundMomentVector).toArray();
    return SaturationUtilities.limitTotalMoments(totalMoments);
}
Also used : Vector3D(org.apache.commons.math3.geometry.euclidean.threed.Vector3D) Engine(com.chrisali.javaflightsim.simulation.propulsion.Engine)

Aggregations

Engine (com.chrisali.javaflightsim.simulation.propulsion.Engine)8 Aircraft (com.chrisali.javaflightsim.simulation.aircraft.Aircraft)2 Vector3D (org.apache.commons.math3.geometry.euclidean.threed.Vector3D)2 Aerodynamics (com.chrisali.javaflightsim.simulation.aircraft.Aerodynamics)1 EnumMap (java.util.EnumMap)1 Test (org.junit.Test)1