1
0
Fork 0
flightgear/src/FDM/ps-10520c.cxx
2001-03-26 18:22:31 +00:00

535 lines
15 KiB
C++

// 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 (philip@zedley.com)
//
// 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
// 19/8/2000 PLS Updated E-mail address - This version compiles
// 19/8/2000 PLS Set Max Prop blade angle to prevent prop exeeding 90
// ------------------------------------------------------------------------
// INCLUDES
// ------------------------------------------------------------------------
#include <simgear/compiler.h>
#include <math.h>
#include STL_IOSTREAM
#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
SG_USING_STD(cout);
SG_USING_STD(endl);
#endif
// ------------------------------------------------------------------------
// CODE
// ------------------------------------------------------------------------
// prototype definitions
// These should be in a header file 10520c.h
float Density (float x);
void ShowRho (float x);
float IAS_to_FPS (float x);
void ShowFPS(float x);
float Get_Throttle (float x);
void Show_Throttle (float x);
float Manifold_Pressure (float x, float z);
void Show_Manifold_Pressure (float x);
float CHT (float Fuel_Flow, float Mixture, float IAS);
void Show_CHT (float x);
float Oil_Temp (float x, float y);
void Show_Oil_Temp (float x);
float Oil_Press (float Oil_Temp, float Engine_RPM);
void Show_Oil_Press (float x);
int main()
{
// Declare local variables
int num = 0; // Not used. Counting variables
int num2 = 100; // Not used.
float ManXRPM = 0;
float Vo = 0;
float V1 = 0;
// Set up the new variables
float Blade_Station = 30;
float Rho = 0.002378;
float FGProp_Area = 1.405/3;
float PI = 3.1428571;
// Input Variables
float IAS = 0;
cout << "Enter IAS ";
// cin >> IAS;
IAS = 85;
cout << endl;
// 0 = Closed, 100 = Fully Open
float FGEng1_Throttle_Lever_Pos = 75;
// 0 = Full Course 100 = Full Fine
float FGEng1_Propeller_Lever_Pos = 75;
// 0 = Idle Cut Off 100 = Full Rich
float FGEng1_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 FGEng1_Fuel_Available = 1;
// Off = 0. Reduces power by 3 % for same throttle setting
int FGEng1_Alternate_Air_Pos =0;
// 1 = On. Reduces power by 5 % for same power lever settings
int FGEng1_Magneto_Left = 1;
// 1 = On. Ditto, Both of the above though do not alter fuel flow
int FGEng1_Magneto_Right = 1;
// There needs to be a section in here to trap silly values, like
// 0, otherwise they will crash the calculations
// 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 FGEng_Max_Manifold_Pressure = 29.50;
float FGEng_Max_RPM = 2700;
float FGEng_Min_RPM = 1000;
float FGEng_Max_Fuel_Flow = 130;
float FGEng_Mag_Derate_Percent = 5;
float FGEng_MaxHP = 285;
float FGEng_Gear_Ratio = 1;
// Initialise Engine Variables used by this instance
float FGEng1_Percentage_Power = 0;
float FGEng1_Manifold_Pressure = 29.00; // Inches
float FGEng1_RPM = 500;
float FGEng1_Fuel_Flow = 0; // lbs/hour
float FGEng1_Torque = 0;
float FGEng1_CHT = 370;
float FGEng1_Mixture = 14;
float FGEng1_Oil_Pressure = 0; // PSI
float FGEng1_Oil_Temp = 85; // Deg C
float FGEng1_HP = 0;
float FGEng1_RPS = 0;
float Torque_Imbalance = 0;
float FGEng1_Desired_RPM = 0;
// Initialise Propellor Variables used by this instance
float FGProp1_Angular_V = 0;
float FGProp1_Coef_Drag = 0.6;
float FGProp1_Torque = 0;
float FGProp1_Thrust = 0;
float FGProp1_RPS = 0;
float FGProp1_Coef_Lift = 0.1;
float Alpha1 = 13.5;
float FGProp1_Blade_Angle = 13.5;
float FGProp_Fine_Pitch_Stop = 13.5;
float FGProp_Course_Pitch_Stop = 55;
// cout << "Enter Blade Angle ";
// cin >> FGProp1_Blade_Angle;
// cout << endl;
cout << " Number of Iterations ";
// cin >> num2;
num2 = 100;
cout << endl;
cout << " Throttle % ";
// cin >> FGEng1_Throttle_Lever_Pos;
FGEng1_Throttle_Lever_Pos = 50;
cout << endl;
cout << " Prop % ";
// cin >> FGEng1_Propeller_Lever_Pos;
FGEng1_Propeller_Lever_Pos = 100;
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"
ShowRho(Rho);
// Calculate Manifold Pressure (Engine 1) as set by throttle opening
FGEng1_Manifold_Pressure = Manifold_Pressure(FGEng1_Throttle_Lever_Pos,
FGEng1_Manifold_Pressure );
Show_Manifold_Pressure(FGEng1_Manifold_Pressure);
// Calculate Desired RPM as set by Prop Lever Position.
// Actual engine RPM may be different
// The governed max RPM at 100% Prop Lever Position = FGEng_MaxRPM
// The governed minimum RPM at 0% Prop Lever Position = FGEng_Min_RPM
// The actual minimum RPM of the engine can be < FGEng_Min_RPM if there is insufficient
// engine torque to counter act the propeller torque at FGProp_Fine_Pitch_Stop
FGEng1_RPM = (FGEng1_Propeller_Lever_Pos * (FGEng_Max_RPM - FGEng_Min_RPM) /100)
+ FGEng_Min_RPM ;
// * ((FGEng_Max_RPM + FGEng_Min_RPM) / 100);
if (FGEng1_RPM >= 2700) {
FGEng1_RPM = 2700;
}
FGEng1_Desired_RPM = FGEng1_RPM;
cout << "Desired RPM = " << FGEng1_Desired_RPM << endl;
//==================================================================
// Engine Power & Torque Calculations
// Loop until stable - required for testing only
for (num = 1; num < num2; num++) {
cout << endl << "====================" << endl;
cout << "MP Inches = " << FGEng1_Manifold_Pressure << "\t";
cout << FGEng1_RPM << " RPM" << "\t";
// For a givem Manifold Pressure and RPM calculate the % Power
// Multiply Manifold Pressure by RPM
ManXRPM = FGEng1_Manifold_Pressure * FGEng1_RPM;
cout << ManXRPM << endl;
// Calculate % Power
FGEng1_Percentage_Power = (+ 7E-09 * ManXRPM * ManXRPM)
+ ( + 7E-04 * ManXRPM) - 0.1218;
cout << "percent power = " << FGEng1_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
FGEng1_Percentage_Power = FGEng1_Percentage_Power - (FG_ISA_VAR * 7 /120);
cout << " adjusted T = " << FGEng1_Percentage_Power << "%" << "\t";
// Adjust for Altitude. In this version a linear variation is
// used. Decrease 1% for each 1000' increase in Altitde
FGEng1_Percentage_Power = FGEng1_Percentage_Power
+ (FG_Pressure_Ht * 12/10000);
cout << " adjusted A = " << FGEng1_Percentage_Power << "%" << "\t";
// Now Calculate Fuel Flow based on % Power Best Power Mixture
FGEng1_Fuel_Flow = FGEng1_Percentage_Power
* FGEng_Max_Fuel_Flow / 100;
// cout << FGEng1_Fuel_Flow << " lbs/hr"<< endl;
// Now Derate engine for the effects of Bad/Switched off magnetos
if (FGEng1_Magneto_Left == 0 && FGEng1_Magneto_Right == 0) {
// cout << "Both OFF\n";
FGEng1_Percentage_Power = 0;
} else if (FGEng1_Magneto_Left && FGEng1_Magneto_Right) {
// cout << "Both On ";
} else if (FGEng1_Magneto_Left == 0 || FGEng1_Magneto_Right== 0) {
// cout << "1 Magneto Failed ";
FGEng1_Percentage_Power = FGEng1_Percentage_Power *
((100 - FGEng_Mag_Derate_Percent)/100);
// cout << FGEng1_Percentage_Power << "%" << "\t";
}
// Calculate Engine Horsepower
FGEng1_HP = FGEng1_Percentage_Power * FGEng_MaxHP/100;
// Calculate Engine Torque
FGEng1_Torque = FGEng1_HP * 5252 / FGEng1_RPM;
cout << FGEng1_Torque << "Ft/lbs" << "\t";
// Calculate Cylinder Head Temperature
FGEng1_CHT = CHT (FGEng1_Fuel_Flow, FGEng1_Mixture, IAS);
// Show_CHT (FGEng1_CHT);
// Calculate Oil Pressure
FGEng1_Oil_Pressure = Oil_Press (FGEng1_Oil_Temp, FGEng1_RPM);
// Show_Oil_Press(FGEng1_Oil_Pressure);
//==============================================================
// Now do the Propellor Calculations
// Revs per second
FGProp1_RPS = FGEng1_RPM * FGEng_Gear_Ratio/60;
// 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 << "Angular Velocity " << FGProp1_Angular_V << 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);
// ShowFPS ( Vo );
// cout << Vo << "Axial Velocity" << endl;
// Relative Velocity (V1)
V1 = sqrt((FGProp1_Angular_V * FGProp1_Angular_V) +
(Vo * Vo));
cout << "Relative Velocity " << V1 << endl;
if ( FGProp1_Blade_Angle >= FGProp_Course_Pitch_Stop ) {
FGProp1_Blade_Angle = FGProp_Course_Pitch_Stop;
}
cout << FGProp1_Blade_Angle << " Prop Blade Angle" << endl;
// Blade Angle of Attack (Alpha1)
Alpha1 = FGProp1_Blade_Angle -(atan(Vo / FGProp1_Angular_V) * (180/PI));
// cout << Alpha1 << " Alpha1" << endl;
cout << " Alpha1 = " << Alpha1
<< " Blade angle = " << FGProp1_Blade_Angle
<< " Vo = " << Vo
<< " FGProp1_Angular_V = " << FGProp1_Angular_V << 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 << "Prop Torque = " << FGProp1_Torque << endl;
// Calculate Prop Thrust
FGProp1_Thrust = 0.5 * Rho * (V1 * V1) * FGProp_Area
* ((FGProp1_Coef_Lift * cos(Alpha1 * PI / 180))
- (FGProp1_Coef_Drag * sin(Alpha1 * PI / 180)));
cout << " Prop Thrust = " << FGProp1_Thrust << endl;
// End of Propeller Calculations
//==============================================================
Torque_Imbalance = FGProp1_Torque - FGEng1_Torque;
// cout << Torque_Imbalance << endl;
if (Torque_Imbalance > 20) {
FGEng1_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) {
FGEng1_RPM += 14.5;
// FGProp1_RPM += 25;
FGProp1_Blade_Angle += 0.75;
}
if (FGEng1_RPM >= 2700) {
FGEng1_RPM = 2700;
}
// cout << FGEng1_RPM << " Blade_Angle " << FGProp1_Blade_Angle << endl << endl;
}
return (0);
}
// Functions
// Calculate Air Density - Rho
float Density ( float x )
{
float y ;
y = ((9E-08 * x * x) - (7E-08 * x) + 0.0024);
return(y);
}
// Show Air Density Calculations
void ShowRho (float x)
{
cout << "Rho = ";
cout << x << endl;
}
// Calculate Speed in FPS given Knots CAS
float IAS_to_FPS (float x)
{
float y;
y = x * 1.68888888;
return (y);
}
// Show Feet per Second
void ShowFPS (float x)
{
cout << "Feet/sec = ";
cout << x << endl;
}
// Calculate Manifold Pressure based on Throttle lever Position
float Manifold_Pressure ( float x, float z)
{
float y;
// if ( x < = 0 )
// {
// x = 0.00001;
// }
y = x * z / 100;
return (y);
}
// Show Manifold Pressure
void Show_Manifold_Pressure (float x)
{
cout << "Manifold Pressure = ";
cout << x << endl;
}
// Calculate Oil Temperature
float Oil_Temp (float Fuel_Flow, float Mixture, float IAS)
{
float Oil_Temp = 85;
return (Oil_Temp);
}
// Show Oil Temperature
void Show_Oil_Temp (float x)
{
cout << "Oil Temperature (F) = ";
cout << x << endl;
}
// Calculate Oil Pressure
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);
}
// Show Oil Pressure
void Show_Oil_Press (float x)
{
cout << "Oil Pressure (PSI) = ";
cout << x << endl;
}
// Calculate Cylinder Head Temperature
float CHT (float Fuel_Flow, float Mixture, float IAS)
{
float CHT = 350;
return (CHT);
}
// Show Cyl Head Temperature
void Show_CHT (float x)
{
cout << "CHT (F) = ";
cout << x << endl;
}