double FGPropeller::Calculate(double EnginePower) { FGColumnVector3 localAeroVel = Transform().Transposed() * in.AeroUVW; double omega, PowerAvailable; double Vel = localAeroVel(eU); double rho = in.Density; double RPS = RPM/60.0; // Calculate helical tip Mach double Area = 0.25*Diameter*Diameter*M_PI; double Vtip = RPS * Diameter * M_PI; HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed; PowerAvailable = EnginePower - GetPowerRequired(); if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally else J = Vel / Diameter; if (MaxPitch == MinPitch) { // Fixed pitch prop ThrustCoeff = cThrust->GetValue(J); } else { // Variable pitch prop ThrustCoeff = cThrust->GetValue(J, Pitch); } // Apply optional scaling factor to Ct (default value = 1) ThrustCoeff *= CtFactor; // Apply optional Mach effects from CT_MACH table if (CtMach) ThrustCoeff *= CtMach->GetValue(HelicalTipMach); Thrust = ThrustCoeff*RPS*RPS*D4*rho; // Induced velocity in the propeller disk area. This formula is obtained // from momentum theory - see B. W. McCormick, "Aerodynamics, Aeronautics, // and Flight Mechanics" 1st edition, eqn. 6.15 (propeller analysis chapter). // Since Thrust and Vel can both be negative we need to adjust this formula // To handle sign (direction) separately from magnitude. double Vel2sum = Vel*abs(Vel) + 2.0*Thrust/(rho*Area); if( Vel2sum > 0.0) Vinduced = 0.5 * (-Vel + sqrt(Vel2sum)); else Vinduced = 0.5 * (-Vel - sqrt(-Vel2sum)); // We need to drop the case where the downstream velocity is opposite in // direction to the aircraft velocity. For example, in such a case, the // direction of the airflow on the tail would be opposite to the airflow on // the wing tips. When such complicated airflows occur, the momentum theory // breaks down and the formulas above are no longer applicable // (see H. Glauert, "The Elements of Airfoil and Airscrew Theory", // 2nd edition, ยง16.3, pp. 219-221) if ((Vel+2.0*Vinduced)*Vel < 0.0) { // The momentum theory is no longer applicable so let's assume the induced // saturates to -0.5*Vel so that the total velocity Vel+2*Vinduced equals 0. Vinduced = -0.5*Vel; } // P-factor is simulated by a shift of the acting location of the thrust. // The shift is a multiple of the angle between the propeller shaft axis // and the relative wind that goes through the propeller disk. if (P_Factor > 0.0001) { double tangentialVel = localAeroVel.Magnitude(eV, eW); if (tangentialVel > 0.0001) { double angle = atan2(tangentialVel, localAeroVel(eU)); double factor = Sense * P_Factor * angle / tangentialVel; SetActingLocationY( GetLocationY() + factor * localAeroVel(eW)); SetActingLocationZ( GetLocationZ() + factor * localAeroVel(eV)); } } omega = RPS*2.0*M_PI; vFn(eX) = Thrust; // The Ixx value and rotation speed given below are for rotation about the // natural axis of the engine. The transform takes place in the base class // FGForce::GetBodyForces() function. vH(eX) = Ixx*omega*Sense; vH(eY) = 0.0; vH(eZ) = 0.0; if (omega > 0.0) ExcessTorque = PowerAvailable / omega; else ExcessTorque = PowerAvailable / 1.0; RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0; if (RPM < 0.0) RPM = 0.0; // Engine won't turn backwards // Transform Torque and momentum first, as PQR is used in this // equation and cannot be transformed itself. vMn = in.PQR*(Transform()*vH) + Transform()*vTorque; return Thrust; // return thrust in pounds }
double FGPropeller::Calculate(double EnginePower) { FGColumnVector3 localAeroVel = Transform().Transposed() * in.AeroUVW; double omega, PowerAvailable; double Vel = localAeroVel(eU); double rho = in.Density; double RPS = RPM/60.0; // Calculate helical tip Mach double Area = 0.25*Diameter*Diameter*M_PI; double Vtip = RPS * Diameter * M_PI; HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed; if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally else J = Vel / Diameter; PowerAvailable = EnginePower - GetPowerRequired(); if (MaxPitch == MinPitch) { // Fixed pitch prop ThrustCoeff = cThrust->GetValue(J); } else { // Variable pitch prop ThrustCoeff = cThrust->GetValue(J, Pitch); } // Apply optional scaling factor to Ct (default value = 1) ThrustCoeff *= CtFactor; // Apply optional Mach effects from CT_MACH table if (CtMach) ThrustCoeff *= CtMach->GetValue(HelicalTipMach); Thrust = ThrustCoeff*RPS*RPS*D4*rho; // Induced velocity in the propeller disk area. This formula is obtained // from momentum theory - see B. W. McCormick, "Aerodynamics, Aeronautics, // and Flight Mechanics" 1st edition, eqn. 6.15 (propeller analysis chapter). // Since Thrust and Vel can both be negative we need to adjust this formula // To handle sign (direction) separately from magnitude. double Vel2sum = Vel*abs(Vel) + 2.0*Thrust/(rho*Area); if( Vel2sum > 0.0) Vinduced = 0.5 * (-Vel + sqrt(Vel2sum)); else Vinduced = 0.5 * (-Vel - sqrt(-Vel2sum)); // P-factor is simulated by a shift of the acting location of the thrust. // The shift is a multiple of the angle between the propeller shaft axis // and the relative wind that goes through the propeller disk. if (P_Factor > 0.0001) { double tangentialVel = localAeroVel.Magnitude(eV, eW); if (tangentialVel > 0.0001) { // The angle made locally by the air flow with respect to the propeller // axis is influenced by the induced velocity. This attenuates the // influence of a string cross wind and gives a more realistic behavior. double angle = atan2(tangentialVel, Vel+Vinduced); double factor = Sense * P_Factor * angle / tangentialVel; SetActingLocationY( GetLocationY() + factor * localAeroVel(eW)); SetActingLocationZ( GetLocationZ() + factor * localAeroVel(eV)); } } omega = RPS*2.0*M_PI; vFn(eX) = Thrust; // The Ixx value and rotation speed given below are for rotation about the // natural axis of the engine. The transform takes place in the base class // FGForce::GetBodyForces() function. FGColumnVector3 vH(Ixx*omega*Sense*Sense_multiplier, 0.0, 0.0); if (omega > 0.0) ExcessTorque = PowerAvailable / omega; else ExcessTorque = PowerAvailable / 1.0; RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * in.TotalDeltaT) * 60.0; if (RPM < 0.0) RPM = 0.0; // Engine won't turn backwards // Transform Torque and momentum first, as PQR is used in this // equation and cannot be transformed itself. vMn = in.PQRi*(Transform()*vH) + Transform()*vTorque; return Thrust; // return thrust in pounds }