From fa000a3447a7c9e123642018028b0ac75061f2b5 Mon Sep 17 00:00:00 2001 From: curt Date: Mon, 28 Aug 2000 20:39:55 +0000 Subject: [PATCH] Starting to play around with an engine model. --- src/FDM/10520d.cxx | 460 ++++++++++++++++++++++++++++++++++++++++++++ src/FDM/10520d.hxx | 141 ++++++++++++++ src/FDM/Makefile.am | 7 + src/FDM/engine.cxx | 24 +++ 4 files changed, 632 insertions(+) create mode 100644 src/FDM/10520d.cxx create mode 100644 src/FDM/10520d.hxx create mode 100644 src/FDM/engine.cxx diff --git a/src/FDM/10520d.cxx b/src/FDM/10520d.cxx new file mode 100644 index 000000000..4ffaa9cd4 --- /dev/null +++ b/src/FDM/10520d.cxx @@ -0,0 +1,460 @@ +// Module: 10520c.c +// Author: Phil Schubert +// Date started: 12/03/99 +// Purpose: Models a Continental IO-520-M Engine +// Called by: FGSimExec +// +// Copyright (C) 1999 Philip L. Schubert (philings@ozemail.com.au) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// Further information about the GNU General Public License can also +// be found on the world wide web at http://www.gnu.org. +// +// FUNCTIONAL DESCRIPTION +// ------------------------------------------------------------------------ +// Models a Continental IO-520-M engine. This engine is used in Cessna +// 210, 310, Beechcraft Bonaza and Baron C55. The equations used below +// were determined by a first and second order curve fits using Excel. +// The data is from the Cessna Aircraft Corporations Engine and Flight +// Computer for C310. Part Number D3500-13 +// +// ARGUMENTS +// ------------------------------------------------------------------------ +// +// +// HISTORY +// ------------------------------------------------------------------------ +// 12/03/99 PLS Created +// 07/03/99 PLS Added Calculation of Density, and Prop_Torque +// 07/03/99 PLS Restructered Variables to allow easier implementation +// of Classes +// 15/03/99 PLS Added Oil Pressure, Oil Temperature and CH Temp +// ------------------------------------------------------------------------ +// INCLUDES +// ------------------------------------------------------------------------ + +#include +#include + +#include "10520d.hxx" + + +// ------------------------------------------------------------------------ +// CODE +// ------------------------------------------------------------------------ + + +// Calculate Engine RPM based on Propellor Lever Position +float FGEngine::Calc_Engine_RPM (float LeverPosition) +{ + // Calculate RPM as set by Prop Lever Position. Assumes engine + // will run at 1000 RPM at full course + + float RPM; + RPM = LeverPosition * Max_RPM / 100.0; + // * ((FGEng_Max_RPM + FGEng_Min_RPM) / 100); + + if ( RPM >= Max_RPM ) { + RPM = Max_RPM; + } + + return RPM; +} + + +// Calculate Manifold Pressure based on Throttle lever Position +static float Calc_Manifold_Pressure ( float LeverPosn, float MaxMan) +{ + float Inches; + // if ( x < = 0 ) { + // x = 0.00001; + // } + Inches = LeverPosn * MaxMan / 100; + return Inches; +} + + +// set initial default values +void FGEngine::init() { + // Control and environment inputs + IAS = 0; + Throttle_Lever_Pos = 75; + Propeller_Lever_Pos = 75; + Mixture_Lever_Pos = 100; + + // Engine Specific Variables used by this program that have limits. + // Will be set in a parameter file to be read in to create + // and instance for each engine. + Max_Manifold_Pressure = 29.50; + Max_RPM = 2700; + Min_RPM = 1000; + Max_Fuel_Flow = 130; + Mag_Derate_Percent = 5; + MaxHP = 285; + Gear_Ratio = 1; + + // Initialise Engine Variables used by this instance + Percentage_Power = 0; + Manifold_Pressure = 29.00; // Inches + RPM = 2700; + Fuel_Flow = 0; // lbs/hour + Torque = 0; + CHT = 370; + Mixture = 14; + Oil_Pressure = 0; // PSI + Oil_Temp = 85; // Deg C + HP = 0; + RPS = 0; + Torque_Imbalance = 0; + Desired_RPM = 0; + + // Initialise Propellor Variables used by this instance + FGProp1_Angular_V = 0; + FGProp1_Coef_Drag = 0.6; + FGProp1_Torque = 0; + FGProp1_Thrust = 0; + FGProp1_RPS = 0; + FGProp1_Coef_Lift = 0.1; + Alpha1 = 13.5; + FGProp1_Blade_Angle = 13.5; + FGProp_Fine_Pitch_Stop = 13.5; + + // Other internal values + Rho = 0.002378; +} + + +// Calculate Oil Pressure +static float Oil_Press (float Oil_Temp, float Engine_RPM) +{ + float Oil_Pressure = 0; //PSI + float Oil_Press_Relief_Valve = 60; //PSI + float Oil_Press_RPM_Max = 1800; + float Design_Oil_Temp = 85; //Celsius + float Oil_Viscosity_Index = 0.25; // PSI/Deg C + float Temp_Deviation = 0; // Deg C + + Oil_Pressure = (Oil_Press_Relief_Valve / Oil_Press_RPM_Max) * Engine_RPM; + + // Pressure relief valve opens at Oil_Press_Relief_Valve PSI setting + if (Oil_Pressure >= Oil_Press_Relief_Valve) + { + Oil_Pressure = Oil_Press_Relief_Valve; + } + + // Now adjust pressure according to Temp which affects the viscosity + + Oil_Pressure += (Design_Oil_Temp - Oil_Temp) * Oil_Viscosity_Index; + + return Oil_Pressure; +} + + +// Calculate Cylinder Head Temperature +static float Calc_CHT (float Fuel_Flow, float Mixture, float IAS) +{ + float CHT = 350; + + return CHT; +} + + +// Calculate Density Ratio +static float Density_Ratio ( float x ) +{ + float y ; + y = ((3E-10 * x * x) - (3E-05 * x) + 0.9998); + return(y); +} + + +// Calculate Air Density - Rho +static float Density ( float x ) +{ + float y ; + y = ((9E-08 * x * x) - (7E-08 * x) + 0.0024); + return(y); +} + + +// Calculate Speed in FPS given Knots CAS +static float IAS_to_FPS (float x) +{ + float y; + y = x * 1.68888888; + return y; +} + + +// update the engine model based on current control positions +void FGEngine::update() { + // Declare local variables + int num = 0; + const int num2 = 1; // default is 100, number if iterations to run + float ManXRPM = 0; + float Vo = 0; + float V1 = 0; + + + // Set up the new variables + float Blade_Station = 30; + float FGProp_Area = 1.405/3; + float PI = 3.1428571; + + // Input Variables + + // 0 = Closed, 100 = Fully Open + // float Throttle_Lever_Pos = 75; + // 0 = Full Course 100 = Full Fine + // float Propeller_Lever_Pos = 75; + // 0 = Idle Cut Off 100 = Full Rich + // float Mixture_Lever_Pos = 100; + + // Environmental Variables + + // Temp Variation from ISA (Deg F) + float FG_ISA_VAR = 0; + // Pressure Altitude 1000's of Feet + float FG_Pressure_Ht = 0; + + // Parameters that alter the operation of the engine. + // Yes = 1. Is there Fuel Available. Calculated elsewhere + int Fuel_Available = 1; + // Off = 0. Reduces power by 3 % for same throttle setting + int Alternate_Air_Pos =0; + // 1 = On. Reduces power by 5 % for same power lever settings + int Magneto_Left = 1; + // 1 = On. Ditto, Both of the above though do not alter fuel flow + int Magneto_Right = 1; + + // There needs to be a section in here to trap silly values, like + // 0, otherwise they will crash the calculations + + // cout << " Number of Iterations "; + // cin >> num2; + // cout << endl; + + // cout << " Throttle % "; + // cin >> Throttle_Lever_Pos; + // cout << endl; + + // cout << " Prop % "; + // cin >> Propeller_Lever_Pos; + // cout << endl; + + //================================================================== + // Engine & Environmental Inputs from elsewhere + + // Calculate Air Density (Rho) - In FG this is calculated in + // FG_Atomoshere.cxx + + Rho = Density(FG_Pressure_Ht); // In FG FG_Pressure_Ht is "h" + // cout << "Rho = " << Rho << endl; + + // Calculate Manifold Pressure (Engine 1) as set by throttle opening + + Manifold_Pressure = + Calc_Manifold_Pressure( Throttle_Lever_Pos, Max_Manifold_Pressure ); + // cout << "manifold pressure = " << Manifold_Pressure << endl; + + + // Calculate Manifold Pressure (Engine 2) as set by throttle opening + + // FGEng2_Manifold_Pressure = Manifold_Pressure(FGEng2_Throttle_Lever_Pos, FGEng2_Manifold_Pressure); + // Show_Manifold_Pressure(FGEng2_Manifold_Pressure); + + RPM = Calc_Engine_RPM(Propeller_Lever_Pos); + // cout << "Engine RPM = " << RPM << endl; + + Desired_RPM = RPM; + + //================================================================== + // Engine Power & Torque Calculations + + // Loop until stable - required for testing only + for (num = 0; num < num2; num++) { + // cout << Manifold_Pressure << " Inches" << "\t"; + // cout << RPM << " RPM" << "\t"; + + // For a given Manifold Pressure and RPM calculate the % Power + // Multiply Manifold Pressure by RPM + ManXRPM = Manifold_Pressure * RPM; + // cout << ManXRPM; + // cout << endl; + + // Calculate % Power + Percentage_Power = (+ 7E-09 * ManXRPM * ManXRPM) + + ( + 7E-04 * ManXRPM) - 0.1218; + // cout << Percentage_Power << "%" << "\t"; + + // Adjust for Temperature - Temperature above Standard decrease + // power % by 7/120 per degree F increase, and incease power for + // temps below at the same ratio + Percentage_Power = Percentage_Power - (FG_ISA_VAR * 7 /120); + // cout << Percentage_Power << "%" << "\t"; + + // Adjust for Altitude. In this version a linear variation is + // used. Decrease 1% for each 1000' increase in Altitde + Percentage_Power = Percentage_Power + (FG_Pressure_Ht * 12/10000); + // cout << Percentage_Power << "%" << "\t"; + + // Now Calculate Fuel Flow based on % Power Best Power Mixture + Fuel_Flow = Percentage_Power * Max_Fuel_Flow / 100.0; + // cout << Fuel_Flow << " lbs/hr"<< endl; + + // Now Derate engine for the effects of Bad/Switched off magnetos + if (Magneto_Left == 0 && Magneto_Right == 0) { + // cout << "Both OFF\n"; + Percentage_Power = 0; + } else if (Magneto_Left && Magneto_Right) { + // cout << "Both On "; + } else if (Magneto_Left == 0 || Magneto_Right== 0) { + // cout << "1 Magneto Failed "; + + Percentage_Power = Percentage_Power * + ((100.0 - Mag_Derate_Percent)/100.0); + // cout << FGEng1_Percentage_Power << "%" << "\t"; + } + + // Calculate Engine Horsepower + + HP = Percentage_Power * MaxHP / 100.0; + + // Calculate Engine Torque + + Torque = HP * 5252 / RPM; + // cout << Torque << "Ft/lbs" << "\t"; + + // Calculate Cylinder Head Temperature + CHT = Calc_CHT( Fuel_Flow, Mixture, IAS); + // cout << "Cylinder Head Temp (F) = " << CHT << endl; + + // Calculate Oil Pressure + Oil_Pressure = Oil_Press( Oil_Temp, RPM ); + // cout << "Oil Pressure (PSI) = " << Oil_Pressure << endl; + + //============================================================== + + // Now do the Propellor Calculations + + // Revs per second + FGProp1_RPS = RPM * Gear_Ratio / 60.0; + // cout << FGProp1_RPS << " RPS" << endl; + + //Radial Flow Vector (V2) Ft/sec at Ref Blade Station (usually 30") + FGProp1_Angular_V = FGProp1_RPS * 2 * PI * (Blade_Station / 12); + // cout << FGProp1_Angular_V << "Angular Velocity " << endl; + + // Axial Flow Vector (Vo) Ft/sec + // Some further work required here to allow for inflow at low speeds + // Vo = (IAS + 20) * 1.688888; + Vo = IAS_to_FPS(IAS + 20); + // cout << "Feet/sec = " << Vo << endl; + + // cout << Vo << "Axial Velocity" << endl; + + // Relative Velocity (V1) + V1 = sqrt((FGProp1_Angular_V * FGProp1_Angular_V) + + (Vo * Vo)); + // cout << V1 << "Relative Velocity " << endl; + + // cout << FGProp1_Blade_Angle << " Prop Blade Angle" << endl; + + // Blade Angle of Attack (Alpha1) + + cout << " Alpha1 = " << Alpha1 + << " Blade angle = " << FGProp1_Blade_Angle + << " Vo = " << Vo + << " FGProp1_Angular_V = " << FGProp1_Angular_V << endl; + Alpha1 = FGProp1_Blade_Angle -(atan(Vo / FGProp1_Angular_V) * (180/PI)); + // cout << Alpha1 << " Alpha1" << endl; + + // Calculate Coefficient of Drag at Alpha1 + FGProp1_Coef_Drag = (0.0005 * (Alpha1 * Alpha1)) + (0.0003 * Alpha1) + + 0.0094; + // cout << FGProp1_Coef_Drag << " Coef Drag" << endl; + + // Calculate Coefficient of Lift at Alpha1 + FGProp1_Coef_Lift = -(0.0026 * (Alpha1 * Alpha1)) + (0.1027 * Alpha1) + + 0.2295; + // cout << FGProp1_Coef_Lift << " Coef Lift " << endl; + + // Covert Alplha1 to Radians + // Alpha1 = Alpha1 * PI / 180; + + // Calculate Prop Torque + FGProp1_Torque = (0.5 * Rho * (V1 * V1) * FGProp_Area + * ((FGProp1_Coef_Lift * sin(Alpha1 * PI / 180)) + + (FGProp1_Coef_Drag * cos(Alpha1 * PI / 180)))) + * (Blade_Station/12); + // cout << FGProp1_Torque << " Prop Torque" << endl; + + // Calculate Prop Thrust + // cout << " V1 = " << V1 << " Alpha1 = " << Alpha1 << endl; + FGProp1_Thrust = 0.5 * Rho * (V1 * V1) * FGProp_Area + * ((FGProp1_Coef_Lift * cos(Alpha1 * PI / 180)) + - (FGProp1_Coef_Drag * sin(Alpha1 * PI / 180))); + // cout << FGProp1_Thrust << " Prop Thrust " << endl; + + // End of Propeller Calculations + //============================================================== + + + +#if 0 + Torque_Imbalance = FGProp1_Torque - Torque; + // cout << Torque_Imbalance << endl; + + if (Torque_Imbalance > 20) { + RPM -= 14.5; + // FGProp1_RPM -= 25; + FGProp1_Blade_Angle -= 0.75; + } + + if (FGProp1_Blade_Angle < FGProp_Fine_Pitch_Stop) { + FGProp1_Blade_Angle = FGProp_Fine_Pitch_Stop; + } + if (Torque_Imbalance < -20) { + RPM += 14.5; + // FGProp1_RPM += 25; + FGProp1_Blade_Angle += 0.75; + } + + if (RPM >= 2700) { + RPM = 2700; + } +#endif + + + // cout << FGEng1_RPM << " Blade_Angle " << FGProp1_Blade_Angle << endl << endl; + + } +} + + + + +// Functions + +// Calculate Oil Temperature + +static float Oil_Temp (float Fuel_Flow, float Mixture, float IAS) +{ + float Oil_Temp = 85; + + return (Oil_Temp); +} diff --git a/src/FDM/10520d.hxx b/src/FDM/10520d.hxx new file mode 100644 index 000000000..e4e41fc2c --- /dev/null +++ b/src/FDM/10520d.hxx @@ -0,0 +1,141 @@ +// Module: 10520c.c +// Author: Phil Schubert +// Date started: 12/03/99 +// Purpose: Models a Continental IO-520-M Engine +// Called by: FGSimExec +// +// Copyright (C) 1999 Philip L. Schubert (philings@ozemail.com.au) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// Further information about the GNU General Public License can also +// be found on the world wide web at http://www.gnu.org. +// +// FUNCTIONAL DESCRIPTION +// ------------------------------------------------------------------------ +// Models a Continental IO-520-M engine. This engine is used in Cessna +// 210, 310, Beechcraft Bonaza and Baron C55. The equations used below +// were determined by a first and second order curve fits using Excel. +// The data is from the Cessna Aircraft Corporations Engine and Flight +// Computer for C310. Part Number D3500-13 +// +// ARGUMENTS +// ------------------------------------------------------------------------ +// +// +// HISTORY +// ------------------------------------------------------------------------ +// 12/03/99 PLS Created +// 07/03/99 PLS Added Calculation of Density, and Prop_Torque +// 07/03/99 PLS Restructered Variables to allow easier implementation +// of Classes +// 15/03/99 PLS Added Oil Pressure, Oil Temperature and CH Temp +// ------------------------------------------------------------------------ +// INCLUDES +// ------------------------------------------------------------------------ + +#ifndef _10520D_HXX_ +#define _10520D_HXX_ + + +#include +#include + + +class FGEngine { + +private: + + // Control and environment inputs + float IAS; + // 0 = Closed, 100 = Fully Open + float Throttle_Lever_Pos; + // 0 = Full Course 100 = Full Fine + float Propeller_Lever_Pos; + // 0 = Idle Cut Off 100 = Full Rich + float Mixture_Lever_Pos; + + // Engine Specific Variables used by this program that have limits. + // Will be set in a parameter file to be read in to create + // and instance for each engine. + float Max_Manifold_Pressure; + float Max_RPM; + float Min_RPM; + float Max_Fuel_Flow; + float Mag_Derate_Percent; + float MaxHP; + float Gear_Ratio; + + // Initialise Engine Variables used by this instance + float Percentage_Power; + float Manifold_Pressure; // Inches + float RPM; + float Fuel_Flow; // lbs/hour + float Torque; + float CHT; + float Mixture; + float Oil_Pressure; // PSI + float Oil_Temp; // Deg C + float HP; + float RPS; + float Torque_Imbalance; + float Desired_RPM; + + // Initialise Propellor Variables used by this instance + float FGProp1_Angular_V; + float FGProp1_Coef_Drag; + float FGProp1_Torque; + float FGProp1_Thrust; + float FGProp1_RPS; + float FGProp1_Coef_Lift; + float Alpha1; + float FGProp1_Blade_Angle; + float FGProp_Fine_Pitch_Stop; + + // Other internal values + float Rho; + + // Calculate Engine RPM based on Propellor Lever Position + float Calc_Engine_RPM (float Position); + +public: + + // set initial default values + void init(); + + // update the engine model based on current control positions + void update(); + + inline void set_IAS( float value ) { IAS = value; } + inline void set_Throttle_Lever_Pos( float value ) { + Throttle_Lever_Pos = value; + } + inline void set_Propeller_Lever_Pos( float value ) { + Propeller_Lever_Pos = value; + } + inline void set_Mixture_Lever_Pos( float value ) { + Mixture_Lever_Pos = value; + } + + // accessors + inline float get_RPM() const { return RPM; } + inline float get_FGProp1_Thrust() const { return FGProp1_Thrust; } + + inline float get_Rho() const { return Rho; } +}; + + +#endif _10520D_HXX_ diff --git a/src/FDM/Makefile.am b/src/FDM/Makefile.am index 146b5017c..13fe4db22 100644 --- a/src/FDM/Makefile.am +++ b/src/FDM/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = Balloon JSBSim LaRCsim UIUCModel noinst_LIBRARIES = libFlight.a libFlight_a_SOURCES = \ + 10520d.cxx 10520d.hxx \ Balloon.cxx Balloon.h \ External.cxx External.hxx \ flight.cxx flight.hxx \ @@ -10,4 +11,10 @@ libFlight_a_SOURCES = \ LaRCsim.cxx LaRCsim.hxx \ MagicCarpet.cxx MagicCarpet.hxx +bin_PROGRAMS = engine + +engine_SOURCES = engine.cxx + +engine_LDADD = libFlight.a + INCLUDES += -I$(top_builddir) -I$(top_builddir)/src diff --git a/src/FDM/engine.cxx b/src/FDM/engine.cxx new file mode 100644 index 000000000..cb5c0eedf --- /dev/null +++ b/src/FDM/engine.cxx @@ -0,0 +1,24 @@ +// 10520d test program + +#include "10520d.hxx" + +int main() { + FGEngine e; + + e.init(); + + for ( int i = 0; i < 10000; ++i ) { + e.set_IAS( 45 ); + e.set_Throttle_Lever_Pos( (double)i / 100.0 ); + e.set_Propeller_Lever_Pos( 100 ); + e.set_Mixture_Lever_Pos( 75 ); + + e.update(); + // cout << "Rho = " << e.get_Rho(); + cout << "Throttle = " << i / 100.0; + cout << " RPM = " << e.get_RPM(); + cout << " Thrust = " << e.get_FGProp1_Thrust() << endl; + } + + return 0; +} -- 2.39.5