bool FGPropulsion::Run(bool Holding) { unsigned int i; if (FGModel::Run(Holding)) return true; if (Holding) return false; RunPreFunctions(); vForces.InitMatrix(); vMoments.InitMatrix(); for (i=0; i<numEngines; i++) { Engines[i]->Calculate(); ConsumeFuel(Engines[i]); vForces += Engines[i]->GetBodyForces(); // sum body frame forces vMoments += Engines[i]->GetMoments(); // sum body frame moments } TotalFuelQuantity = 0.0; for (i=0; i<numTanks; i++) { Tanks[i]->Calculate( in.TotalDeltaT, in.TAT_c); if (Tanks[i]->GetType() == FGTank::ttFUEL) { TotalFuelQuantity += Tanks[i]->GetContents(); } } if (refuel) DoRefuel( in.TotalDeltaT ); if (dump) DumpFuel( in.TotalDeltaT ); RunPostFunctions(); return false; }
bool FGFCS::Run(bool Holding) { unsigned int i; if (FGModel::Run(Holding)) return true; // fast exit if nothing to do if (Holding) return false; RunPreFunctions(); for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i]; for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i]; for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i]; for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i]; // Execute system channels in order for (i=0; i<SystemChannels.size(); i++) { if (debug_lvl & 4) cout << " Executing System Channel: " << SystemChannels[i]->GetName() << endl; ChannelRate = SystemChannels[i]->GetRate(); SystemChannels[i]->Execute(); } ChannelRate = 1; RunPostFunctions(); return false; }
bool FGPropulsion::Run(void) { unsigned int i; if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; RunPreFunctions(); double dt = FDMExec->GetDeltaT(); vForces.InitMatrix(); vMoments.InitMatrix(); for (i=0; i<numEngines; i++) { Engines[i]->Calculate(); vForces += Engines[i]->GetBodyForces(); // sum body frame forces vMoments += Engines[i]->GetMoments(); // sum body frame moments } TotalFuelQuantity = 0.0; for (i=0; i<numTanks; i++) { Tanks[i]->Calculate( dt * rate ); if (Tanks[i]->GetType() == FGTank::ttFUEL) { TotalFuelQuantity += Tanks[i]->GetContents(); } } if (refuel) DoRefuel( dt * rate ); if (dump) DumpFuel( dt * rate ); RunPostFunctions(); return false; }
void FGRocket::Calculate(void) { if (FDMExec->IntegrationSuspended()) return; RunPreFunctions(); PropellantFlowRate = (FuelExpended + OxidizerExpended)/in.TotalDeltaT; TotalPropellantExpended += FuelExpended + OxidizerExpended; // If Isp has been specified as a function, override the value of Isp to that, otherwise // assume a constant value is given. if (isp_function) Isp = isp_function->GetValue(); // If there is a thrust table, it is a function of propellant burned. The // engine is started when the throttle is advanced to 1.0. After that, it // burns without regard to throttle setting. if (ThrustTable != 0L) { // Thrust table given -> Solid fuel used if ((in.ThrottlePos[EngineNumber] == 1 || BurnTime > 0.0 ) && !Starved) { VacThrust = ThrustTable->GetValue(TotalPropellantExpended) * (ThrustVariation + 1) * (TotalIspVariation + 1); if (BurnTime <= BuildupTime && BuildupTime > 0.0) { VacThrust *= sin((BurnTime/BuildupTime)*M_PI/2.0); // VacThrust *= (1-cos((BurnTime/BuildupTime)*M_PI))/2.0; // 1 - cos approach } BurnTime += in.TotalDeltaT; // Increment burn time } else { VacThrust = 0.0; } } else { // liquid fueled rocket assumed if (in.ThrottlePos[EngineNumber] < MinThrottle || Starved) { // Combustion not supported PctPower = 0.0; // desired thrust Flameout = true; VacThrust = 0.0; } else { // Calculate thrust // PctPower = Throttle / MaxThrottle; // Min and MaxThrottle range from 0.0 to 1.0, normally. PctPower = in.ThrottlePos[EngineNumber]; Flameout = false; VacThrust = Isp * PropellantFlowRate; } } // End thrust calculations LoadThrusterInputs(); It += Thruster->Calculate(VacThrust) * in.TotalDeltaT; ItVac += VacThrust * in.TotalDeltaT; RunPostFunctions(); }
bool FGOutput::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (enabled && !FDMExec->IntegrationSuspended() && !Holding) { RunPreFunctions(); Print(); RunPostFunctions(); } return false; }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void FGPiston::Calculate(void) { RunPreFunctions(); if (FuelFlow_gph > 0.0) ConsumeFuel(); Throttle = FCS->GetThrottlePos(EngineNumber); Mixture = FCS->GetMixturePos(EngineNumber); // Input values. p_amb = Atmosphere->GetPressure() * psftopa; double p = Auxiliary->GetTotalPressure() * psftopa; p_ram = (p - p_amb) * Ram_Air_Factor + p_amb; T_amb = RankineToKelvin(Atmosphere->GetTemperature()); RPM = Thruster->GetRPM() * Thruster->GetGearRatio(); MeanPistonSpeed_fps = ( RPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS IAS = Auxiliary->GetVcalibratedKTS(); doEngineStartup(); if (Boosted) doBoostControl(); doMAP(); doAirFlow(); doFuelFlow(); //Now that the fuel flow is done check if the mixture is too lean to run the engine //Assume lean limit at 22 AFR for now - thats a thi of 0.668 //This might be a bit generous, but since there's currently no audiable warning of impending //cutout in the form of misfiring and/or rough running its probably reasonable for now. // if (equivalence_ratio < 0.668) // Running = false; doEnginePower(); if (IndicatedHorsePower < 0.1250) Running = false; doEGT(); doCHT(); doOilTemperature(); doOilPressure(); if (Thruster->GetType() == FGThruster::ttPropeller) { ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber)); ((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber)); } PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired(); Thruster->Calculate(PowerAvailable); RunPostFunctions(); }
void FGPiston::Calculate(void) { // Input values. p_amb = in.Pressure * psftopa; double p = in.TotalPressure * psftopa; p_ram = (p - p_amb) * Ram_Air_Factor + p_amb; T_amb = RankineToKelvin(in.Temperature); RunPreFunctions(); TotalDeltaT = ( in.TotalDeltaT < 1e-9 ) ? 1.0 : in.TotalDeltaT; /* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */ RPM = Thruster->GetEngineRPM(); MeanPistonSpeed_fps = ( RPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS IAS = in.Vc; doEngineStartup(); if (Boosted) doBoostControl(); doMAP(); doAirFlow(); doFuelFlow(); //Now that the fuel flow is done check if the mixture is too lean to run the engine //Assume lean limit at 22 AFR for now - thats a thi of 0.668 //This might be a bit generous, but since there's currently no audiable warning of impending //cutout in the form of misfiring and/or rough running its probably reasonable for now. // if (equivalence_ratio < 0.668) // Running = false; doEnginePower(); if (IndicatedHorsePower < 0.1250) Running = false; doEGT(); doCHT(); doOilTemperature(); doOilPressure(); if (Thruster->GetType() == FGThruster::ttPropeller) { ((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]); ((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]); } LoadThrusterInputs(); Thruster->Calculate(HP * hptoftlbssec); RunPostFunctions(); }
bool FGInertial::Run(void) { // Fast return if we have nothing to do ... if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; RunPreFunctions(); // Gravitation accel double r = Propagate->GetRadius(); gAccel = GetGAccel(r); earthPosAngle += FDMExec->GetDeltaT()*RotationRate; RunPostFunctions(); return false; }
void FGElectric::Calculate(void) { RunPreFunctions(); if (Thruster->GetType() == FGThruster::ttPropeller) { ((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]); ((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]); } RPM = Thruster->GetRPM() * Thruster->GetGearRatio(); HP = PowerWatts * in.ThrottlePos[EngineNumber] / hptowatts; LoadThrusterInputs(); Thruster->Calculate(HP * hptoftlbssec); RunPostFunctions(); }
bool FGBuoyantForces::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; // if paused don't execute if (NoneDefined) return true; RunPreFunctions(); vTotalForces.InitMatrix(); vTotalMoments.InitMatrix(); for (unsigned int i=0; i<Cells.size(); i++) { Cells[i]->Calculate(FDMExec->GetDeltaT()); vTotalForces += Cells[i]->GetBodyForces(); vTotalMoments += Cells[i]->GetMoments(); } RunPostFunctions(); return false; }
bool FGAircraft::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; RunPreFunctions(); vForces = in.AeroForce; vForces += in.PropForce; vForces += in.GroundForce; vForces += in.ExternalForce; vForces += in.BuoyantForce; vMoments = in.AeroMoment; vMoments += in.PropMoment; vMoments += in.GroundMoment; vMoments += in.ExternalMoment; vMoments += in.BuoyantMoment; RunPostFunctions(); return false; }
bool FGInput::Run(void) { string line, token; size_t start=0, string_start=0, string_end=0; double value=0; FGPropertyManager* node=0; if (FGModel::Run()) return true; // fast exit if nothing to do if (port == 0) return false; // Do nothing here if port not defined // return false if no error // This model DOES execute if "Exec->Holding" RunPreFunctions(); data = socket->Receive(); // get socket transmission if present if (data.size() > 0) { // parse lines while (1) { string_start = data.find_first_not_of("\r\n", start); if (string_start == string::npos) break; string_end = data.find_first_of("\r\n", string_start); if (string_end == string::npos) break; line = data.substr(string_start, string_end-string_start); if (line.size() == 0) break; // now parse individual line vector <string> tokens = split(line,' '); string command="", argument="", str_value=""; if (tokens.size() > 0) { command = to_lower(tokens[0]); if (tokens.size() > 1) { argument = trim(tokens[1]); if (tokens.size() > 2) { str_value = trim(tokens[2]); } } } if (command == "set") { // SET PROPERTY node = PropertyManager->GetNode(argument); if (node == 0) socket->Reply("Unknown property\n"); else { value = atof(str_value.c_str()); node->setDoubleValue(value); } socket->Reply(""); } else if (command == "get") { // GET PROPERTY if (argument.size() == 0) { socket->Reply("No property argument supplied.\n"); break; } try { node = PropertyManager->GetNode(argument); } catch(...) { socket->Reply("Badly formed property query\n"); break; } if (node == 0) { if (FDMExec->Holding()) { // if holding can query property list string query = FDMExec->QueryPropertyCatalog(argument); socket->Reply(query); } else { socket->Reply("Must be in HOLD to search properties\n"); } } else if (node > 0) { ostringstream buf; buf << argument << " = " << setw(12) << setprecision(6) << node->getDoubleValue() << endl; socket->Reply(buf.str()); } } else if (command == "hold") { // PAUSE FDMExec->Hold(); socket->Reply(""); } else if (command == "resume") { // RESUME FDMExec->Resume(); socket->Reply(""); } else if (command == "quit") { // QUIT // close the socket connection socket->Reply(""); socket->Close(); } else if (command == "info") { // INFO // get info about the sim run and/or aircraft, etc. ostringstream info; info << "JSBSim version: " << JSBSim_version << endl; info << "Config File version: " << needed_cfg_version << endl; info << "Aircraft simulated: " << Aircraft->GetAircraftName() << endl; info << "Simulation time: " << setw(8) << setprecision(3) << FDMExec->GetSimTime() << endl; socket->Reply(info.str()); } else if (command == "help") { // HELP socket->Reply( " JSBSim Server commands:\n\n" " get {property name}\n" " set {property name} {value}\n" " hold\n" " resume\n" " help\n" " quit\n" " info\n\n"); } else { socket->Reply(string("Unknown command: ") + token + string("\n")); } start = string_end; } } RunPostFunctions(); return false; }
bool FGMassBalance::Run(bool Holding) { double denom, k1, k2, k3, k4, k5, k6; double Ixx, Iyy, Izz, Ixy, Ixz, Iyz; if (FGModel::Run(Holding)) return true; if (Holding) return false; RunPreFunctions(); double ChildFDMWeight = 0.0; for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) { if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight(); } Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight() + in.GasMass*slugtolb + ChildFDMWeight; Mass = lbtoslug*Weight; // Calculate new CG vXYZcg = (EmptyWeight*vbaseXYZcg + GetPointMassMoment() + in.TanksMoment + in.GasMoment) / Weight; // Track frame-by-frame delta CG, and move the EOM-tracked location // by this amount. if (vLastXYZcg.Magnitude() == 0.0) vLastXYZcg = vXYZcg; vDeltaXYZcg = vXYZcg - vLastXYZcg; vDeltaXYZcgBody = StructuralToBody(vLastXYZcg) - StructuralToBody(vXYZcg); vLastXYZcg = vXYZcg; FDMExec->GetPropagate()->NudgeBodyLocation(vDeltaXYZcgBody); // Calculate new total moments of inertia // At first it is the base configuration inertia matrix ... mJ = baseJ; // ... with the additional term originating from the parallel axis theorem. mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg ); // Then add the contributions from the additional pointmasses. mJ += CalculatePMInertias(); mJ += in.TankInertia; mJ += in.GasInertia; Ixx = mJ(1,1); Iyy = mJ(2,2); Izz = mJ(3,3); Ixy = -mJ(1,2); Ixz = -mJ(1,3); Iyz = -mJ(2,3); // Calculate inertia matrix inverse (ref. Stevens and Lewis, "Flight Control & Simulation") k1 = (Iyy*Izz - Iyz*Iyz); k2 = (Iyz*Ixz + Ixy*Izz); k3 = (Ixy*Iyz + Iyy*Ixz); denom = 1.0/(Ixx*k1 - Ixy*k2 - Ixz*k3 ); k1 = k1*denom; k2 = k2*denom; k3 = k3*denom; k4 = (Izz*Ixx - Ixz*Ixz)*denom; k5 = (Ixy*Ixz + Iyz*Ixx)*denom; k6 = (Ixx*Iyy - Ixy*Ixy)*denom; mJinv.InitMatrix( k1, k2, k3, k2, k4, k5, k3, k5, k6 ); RunPostFunctions(); Debug(0); return false; }
bool FGAerodynamics::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; // if paused don't execute unsigned int axis_ctr, ctr; const double twovel=2*in.Vt; RunPreFunctions(); // calculate some oft-used quantities for speed if (twovel != 0) { bi2vel = in.Wingspan / twovel; ci2vel = in.Wingchord / twovel; } alphaw = in.Alpha + in.Wingincidence; qbar_area = in.Wingarea * in.Qbar; if (alphaclmax != 0) { if (in.Alpha > 0.85*alphaclmax) { impending_stall = 10*(in.Alpha/alphaclmax - 0.85); } else { impending_stall = 0; } } if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (in.Alpha > alphahystmax) { stall_hyst = 1; } else if (in.Alpha < alphahystmin) { stall_hyst = 0; } } vFw.InitMatrix(); vFwAtCG.InitMatrix(); vFnative.InitMatrix(); vFnativeAtCG.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctions[axis_ctr].size(); ctr++) { vFnative(axis_ctr+1) += AeroFunctions[axis_ctr][ctr]->GetValue(); } } for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctionsAtCG[axis_ctr].size(); ctr++) { vFnativeAtCG(axis_ctr+1) += AeroFunctionsAtCG[axis_ctr][ctr]->GetValue(); } } // Note that we still need to convert to wind axes here, because it is // used in the L/D calculation, and we still may want to look at Lift // and Drag. // JSB 4/27/12 - After use, convert wind axes to produce normal lift // and drag values - not negative ones! // As a clarification, JSBSim assumes that drag and lift values are defined // in wind axes - BUT with a 180 rotation about the Y axis. That is, lift and // drag will be positive up and aft, respectively, so that they are reported // as positive numbers. However, the wind axes themselves assume that the X // and Z forces are positive forward and down. switch (axisType) { case atBodyXYZ: // Forces already in body axes; no manipulation needed vFw = in.Tb2w*vFnative; vForces = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vFwAtCG = in.Tb2w*vFnativeAtCG; vForcesAtCG = vFnativeAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; break; case atLiftDrag: // Copy forces into wind axes vFw = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vForces = in.Tw2b*vFw; vFw(eDrag)*=-1; vFw(eLift)*=-1; vFwAtCG = vFnativeAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; vForcesAtCG = in.Tw2b*vFwAtCG; vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1; break; case atAxialNormal: // Convert native forces into Axial|Normal|Side system vFw = in.Tb2w*vFnative; vFnative(eX)*=-1; vFnative(eZ)*=-1; vForces = vFnative; vFwAtCG = in.Tb2w*vFnativeAtCG; vFnativeAtCG(eX)*=-1; vFnativeAtCG(eZ)*=-1; vForcesAtCG = vFnativeAtCG; break; default: cerr << endl << " A proper axis type has NOT been selected. Check " << "your aerodynamics definition." << endl; exit(-1); } // Calculate lift coefficient squared if ( in.Qbar > 0) { clsq = (vFw(eLift) + vFwAtCG(eLift))/ (in.Wingarea*in.Qbar); clsq *= clsq; } // Calculate lift Lift over Drag if ( fabs(vFw(eDrag) + vFwAtCG(eDrag)) > 0.0) lod = fabs( (vFw(eLift) + vFwAtCG(eLift))/ (vFw(eDrag) + vFwAtCG(eDrag))); // Calculate aerodynamic reference point shift, if any. The shift // takes place in the structual axis. That is, if the shift is positive, // it is towards the back (tail) of the vehicle. The AeroRPShift // function should be non-dimensionalized by the wing chord. The // calculated vDeltaRP will be in feet. if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord; vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY); vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ); vMomentsMRC.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr = 0; ctr < AeroFunctions[axis_ctr+3].size(); ctr++) { vMomentsMRC(axis_ctr+1) += AeroFunctions[axis_ctr+3][ctr]->GetValue(); } } vMoments = vMomentsMRC + vDXYZcg*vForces; // M = r X F // Now add the "at CG" values to base forces - after the moments have been transferred vForces += vForcesAtCG; vFnative += vFnativeAtCG; vFw += vFwAtCG; RunPostFunctions(); return false; }
void FGTurbine::Calculate(void) { double thrust; RunPreFunctions(); ThrottlePos = in.ThrottlePos[EngineNumber]; if (ThrottlePos > 1.0) { AugmentCmd = ThrottlePos - 1.0; ThrottlePos -= AugmentCmd; } else { AugmentCmd = 0.0; } // When trimming is finished check if user wants engine OFF or RUNNING if ((phase == tpTrim) && (in.TotalDeltaT > 0)) { if (Running && !Starved) { phase = tpRun; N1_factor = MaxN1 - IdleN1; N2_factor = MaxN2 - IdleN2; N2 = IdleN2 + ThrottlePos * N2_factor; N1 = IdleN1 + ThrottlePos * N1_factor; OilTemp_degK = 366.0; Cutoff = false; } else { phase = tpOff; Cutoff = true; EGT_degC = in.TAT_c; } } if (!Running && Cutoff && Starter) { if (phase == tpOff) phase = tpSpinUp; } // start if ((Starter == true) || (in.qbar > 30.0)) { if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart; } if (Cutoff && (phase != tpSpinUp)) phase = tpOff; if (in.TotalDeltaT == 0) phase = tpTrim; if (Starved) phase = tpOff; if (Stalled) phase = tpStall; if (Seized) phase = tpSeize; switch (phase) { case tpOff: thrust = Off(); break; case tpRun: thrust = Run(); break; case tpSpinUp: thrust = SpinUp(); break; case tpStart: thrust = Start(); break; case tpStall: thrust = Stall(); break; case tpSeize: thrust = Seize(); break; case tpTrim: thrust = Trim(); break; default: thrust = Off(); } Thruster->Calculate(thrust); // allow thruster to modify thrust (i.e. reversing) RunPostFunctions(); }
bool FGAerodynamics::Run(bool Holding) { if (FGModel::Run(Holding)) return true; if (Holding) return false; // if paused don't execute unsigned int axis_ctr, ctr; const double twovel=2*in.Vt; RunPreFunctions(); // calculate some oft-used quantities for speed if (twovel != 0) { bi2vel = in.Wingspan / twovel; ci2vel = in.Wingchord / twovel; } alphaw = in.Alpha + in.Wingincidence; qbar_area = in.Wingarea * in.Qbar; if (alphaclmax != 0) { if (in.Alpha > 0.85*alphaclmax) { impending_stall = 10*(in.Alpha/alphaclmax - 0.85); } else { impending_stall = 0; } } if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (in.Alpha > alphahystmax) { stall_hyst = 1; } else if (in.Alpha < alphahystmin) { stall_hyst = 0; } } vFw.InitMatrix(); vFnative.InitMatrix(); for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < AeroFunctions[axis_ctr].size(); ctr++) { vFnative(axis_ctr+1) += AeroFunctions[axis_ctr][ctr]->GetValue(); } } // Note that we still need to convert to wind axes here, because it is // used in the L/D calculation, and we still may want to look at Lift // and Drag. switch (axisType) { case atBodyXYZ: // Forces already in body axes; no manipulation needed vFw = in.Tb2w*vFnative; vForces = vFnative; break; case atLiftDrag: // Copy forces into wind axes vFw = vFnative; vFw(eDrag)*=-1; vFw(eLift)*=-1; vForces = in.Tw2b*vFw; break; case atAxialNormal: // Convert native forces into Axial|Normal|Side system vFw = in.Tb2w*vFnative; vFnative(eX)*=-1; vFnative(eZ)*=-1; vForces = vFnative; break; default: cerr << endl << " A proper axis type has NOT been selected. Check " << "your aerodynamics definition." << endl; exit(-1); } // Calculate lift coefficient squared if ( in.Qbar > 0) { clsq = vFw(eLift) / (in.Wingarea*in.Qbar); clsq *= clsq; } // Calculate lift Lift over Drag if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) ); // Calculate aerodynamic reference point shift, if any. The shift // takes place in the structual axis. That is, if the shift is positive, // it is towards the back (tail) of the vehicle. The AeroRPShift // function should be non-dimensionalized by the wing chord. The // calculated vDeltaRP will be in feet. if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord; vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY); vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ); vMoments = vDXYZcg*vForces; // M = r X F for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr = 0; ctr < AeroFunctions[axis_ctr+3].size(); ctr++) { vMoments(axis_ctr+1) += AeroFunctions[axis_ctr+3][ctr]->GetValue(); } } RunPostFunctions(); return false; }
void FGTurboProp::Calculate(void) { RunPreFunctions(); TAT = in.TAT_c; ThrottlePos = in.ThrottlePos[EngineNumber]; /* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */ RPM = Thruster->GetEngineRPM(); if (thrusterType == FGThruster::ttPropeller) { ((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]); ((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]); ((FGPropeller*)Thruster)->SetReverse(Reversed); if (Reversed) { ((FGPropeller*)Thruster)->SetReverseCoef(ThrottlePos); } else { ((FGPropeller*)Thruster)->SetReverseCoef(0.0); } if (Reversed) { if (ThrottlePos < BetaRangeThrottleEnd) { ThrottlePos = 0.0; // idle when in Beta-range } else { // when reversed: ThrottlePos = (ThrottlePos-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower; } } } // When trimming is finished check if user wants engine OFF or RUNNING if ((phase == tpTrim) && (in.TotalDeltaT > 0)) { if (Running && !Starved) { phase = tpRun; N2 = IdleN2; N1 = IdleN1; OilTemp_degK = 366.0; Cutoff = false; } else { phase = tpOff; Cutoff = true; Eng_ITT_degC = TAT; Eng_Temperature = TAT; OilTemp_degK = TAT+273.15; } } if (!Running && Starter) { if (phase == tpOff) { phase = tpSpinUp; if (StartTime < 0) StartTime=0; } } if (!Running && !Cutoff && (N1 > 15.0)) { phase = tpStart; StartTime = -1; } if (Cutoff && (phase != tpSpinUp)) phase = tpOff; if (in.TotalDeltaT == 0) phase = tpTrim; if (Starved) phase = tpOff; if (Condition >= 10) { phase = tpOff; StartTime=-1; } // limiter intervention wanted? if (Ielu_max_torque > 0.0) { double torque = 0.0; if (thrusterType == FGThruster::ttPropeller) { torque = ((FGPropeller*)(Thruster))->GetTorque(); } else if (thrusterType == FGThruster::ttRotor) { torque = ((FGRotor*)(Thruster))->GetTorque(); } if (Condition < 1) { if ( abs(torque) > Ielu_max_torque && ThrottlePos >= OldThrottle ) { ThrottlePos = OldThrottle - 0.1 * in.TotalDeltaT; //IELU down Ielu_intervent = true; } else if ( Ielu_intervent && ThrottlePos >= OldThrottle) { ThrottlePos = OldThrottle + 0.05 * in.TotalDeltaT; //IELU up Ielu_intervent = true; } else { Ielu_intervent = false; } } else { Ielu_intervent = false; } OldThrottle = ThrottlePos; } switch (phase) { case tpOff: HP = Off(); break; case tpRun: HP = Run(); break; case tpSpinUp: HP = SpinUp(); break; case tpStart: HP = Start(); break; default: HP = 0; } LoadThrusterInputs(); Thruster->Calculate(HP * hptoftlbssec); RunPostFunctions(); }