mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-09-02 15:03:49 +00:00
Navigation
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -5645,3 +5645,85 @@ function UTILS.CalculateInterceptBearing(A1, V1, A2, V2_speed)
|
||||
|
||||
return UTILS.Round(bearing,0)
|
||||
end
|
||||
|
||||
|
||||
--- Returns the speed of sound in dry air from the static air temperature.
|
||||
-- @param #number Temperature Static air temperature in degrees Celsius.
|
||||
-- @return #number Speed of sound in m/s.
|
||||
-- @return #nil Invalid temperature.
|
||||
function UTILS.GetSpeedOfSound( Temperature )
|
||||
if type(Temperature) ~= "number" or Temperature ~= Temperature
|
||||
or Temperature <= -273.15 or Temperature == math.huge then
|
||||
return nil
|
||||
end
|
||||
|
||||
return math.sqrt(1.4 * 287.05287 * (Temperature + 273.15))
|
||||
end
|
||||
|
||||
|
||||
--- Returns the ideal pitot impact-pressure ratio qc/p from Mach number.
|
||||
-- qc is pitot pressure minus static pressure; p is upstream static pressure.
|
||||
-- Includes the normal shock ahead of a supersonic pitot probe.
|
||||
-- Assumes dry, calorically perfect air with gamma = 1.4.
|
||||
-- @param #number Mach Mach number, dimensionless and non-negative.
|
||||
-- @return #number Impact-pressure ratio qc/p, dimensionless.
|
||||
-- @return #nil Invalid input or non-finite result.
|
||||
function UTILS.MachToImpactPressureRatio( Mach )
|
||||
if type(Mach) ~= "number" or Mach ~= Mach
|
||||
or Mach < 0 or Mach == math.huge then
|
||||
return nil
|
||||
end
|
||||
|
||||
local M2 = Mach * Mach
|
||||
local Ratio
|
||||
|
||||
if Mach <= 1 then
|
||||
Ratio = (1 + 0.2 * M2) ^ 3.5 - 1
|
||||
else
|
||||
local PressureRatio = (7 * M2 - 1) / 6
|
||||
local DownstreamMachSquared = (M2 + 5) / (7 * M2 - 1)
|
||||
|
||||
Ratio = PressureRatio
|
||||
* (1 + 0.2 * DownstreamMachSquared) ^ 3.5 - 1
|
||||
end
|
||||
|
||||
if Ratio ~= Ratio or Ratio == math.huge then return nil end
|
||||
return Ratio
|
||||
end
|
||||
|
||||
|
||||
--- Returns Mach number from the ideal pitot impact-pressure ratio qc/p.
|
||||
-- Supports subsonic and supersonic flow; uses bisection above Mach 1.
|
||||
-- @param #number PressureRatio Impact-pressure ratio qc/p, dimensionless.
|
||||
-- @return #number Mach number, dimensionless.
|
||||
-- @return #nil Invalid input or failed numerical evaluation.
|
||||
function UTILS.ImpactPressureRatioToMach( PressureRatio )
|
||||
if type(PressureRatio) ~= "number" or PressureRatio ~= PressureRatio
|
||||
or PressureRatio < 0 or PressureRatio == math.huge then
|
||||
return nil
|
||||
end
|
||||
|
||||
if PressureRatio <= UTILS.MachToImpactPressureRatio(1) then
|
||||
return math.sqrt(
|
||||
math.max(0, 5 * ((1 + PressureRatio) ^ (2 / 7) - 1))
|
||||
)
|
||||
end
|
||||
|
||||
local Low, High = 1, math.sqrt(PressureRatio + 1)
|
||||
|
||||
for Iteration = 1, 60 do
|
||||
local Mid = (Low + High) / 2
|
||||
local Ratio = UTILS.MachToImpactPressureRatio(Mid)
|
||||
if Ratio == nil then return nil end
|
||||
|
||||
if Ratio < PressureRatio then
|
||||
Low = Mid
|
||||
else
|
||||
High = Mid
|
||||
end
|
||||
end
|
||||
|
||||
return (Low + High) / 2
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1132,6 +1132,95 @@ function POSITIONABLE:GetGroundSpeed()
|
||||
return gs
|
||||
end
|
||||
|
||||
|
||||
--- Returns horizontal ground speed.
|
||||
-- The vertical velocity component is excluded.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #number Ground speed in m/s. Returns 0 if velocity is unavailable.
|
||||
function POSITIONABLE:GetGroundSpeed()
|
||||
local Velocity = self:GetVelocityVec3()
|
||||
if not Velocity then return 0 end
|
||||
|
||||
return UTILS.Vec2Norm({x=Velocity.x, y=Velocity.z})
|
||||
end
|
||||
|
||||
|
||||
--- Returns true airspeed relative to the surrounding air.
|
||||
-- Uses all three velocity components and wind without turbulence.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #number TAS in m/s. Returns 0 if data is unavailable.
|
||||
function POSITIONABLE:GetAirspeedTrue()
|
||||
local Coordinate = self:GetCoord()
|
||||
local Velocity = self:GetVelocityVec3()
|
||||
if not Coordinate or not Velocity then return 0 end
|
||||
|
||||
local Wind = Coordinate:GetWindVec3(Coordinate.y, false)
|
||||
if not Wind then return 0 end
|
||||
|
||||
local AirVelocity = UTILS.VecSubstract(Velocity, Wind)
|
||||
return UTILS.VecNorm(AirVelocity)
|
||||
end
|
||||
|
||||
|
||||
--- Returns the Mach number using local static air temperature.
|
||||
-- Uses wind without turbulence.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #number Mach number, dimensionless.
|
||||
-- @return #nil Required data is unavailable or invalid.
|
||||
function POSITIONABLE:GetMachNumber()
|
||||
local Coordinate = self:GetCoord()
|
||||
local Velocity = self:GetVelocityVec3()
|
||||
if not Coordinate or not Velocity then return nil end
|
||||
|
||||
local Wind = Coordinate:GetWindVec3(Coordinate.y, false)
|
||||
local SpeedOfSound = UTILS.GetSpeedOfSound(Coordinate:GetTemperature())
|
||||
if not Wind or not SpeedOfSound then return nil end
|
||||
|
||||
-- Read TAS here to distinguish unavailable data from a valid TAS of zero.
|
||||
local AirVelocity = UTILS.VecSubstract(Velocity, Wind)
|
||||
local TAS = UTILS.VecNorm(AirVelocity)
|
||||
if TAS ~= TAS or TAS == math.huge then return nil end
|
||||
|
||||
return TAS / SpeedOfSound
|
||||
end
|
||||
|
||||
|
||||
--- Returns a CAS-based estimate of indicated airspeed.
|
||||
-- Computes ideal calibrated airspeed, including supersonic pitot correction.
|
||||
-- This is NOT a cockpit reading and does not model instrument or position errors.
|
||||
-- Uses local static pressure, static temperature and wind without turbulence.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #number Estimated IAS in m/s, numerically equal to calculated CAS.
|
||||
-- @return #nil Required data is unavailable or invalid.
|
||||
function POSITIONABLE:GetAirspeedIndicatedEstimated()
|
||||
local Mach = self:GetMachNumber()
|
||||
if Mach == nil then return nil end
|
||||
|
||||
local Coordinate = self:GetCoord()
|
||||
if not Coordinate then return nil end
|
||||
|
||||
-- MOOSE returns local static pressure in hPa, not Pa.
|
||||
local Pressure = Coordinate:GetPressure()
|
||||
if type(Pressure) ~= "number" or Pressure ~= Pressure
|
||||
or Pressure <= 0 or Pressure == math.huge then
|
||||
return nil
|
||||
end
|
||||
|
||||
local ImpactRatio = UTILS.MachToImpactPressureRatio(Mach)
|
||||
if ImpactRatio == nil then return nil end
|
||||
|
||||
-- Convert qc/p to qc/p0 using ISA sea-level pressure p0 = 1013.25 hPa.
|
||||
local ReferenceRatio = ImpactRatio * (Pressure / 1013.25)
|
||||
local ReferenceMach = UTILS.ImpactPressureRatioToMach(ReferenceRatio)
|
||||
if ReferenceMach == nil then return nil end
|
||||
|
||||
-- ISA sea-level static temperature is 15 degrees Celsius.
|
||||
return ReferenceMach * UTILS.GetSpeedOfSound(15)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Returns the Angle of Attack of a POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #number Angle of attack in degrees.
|
||||
|
||||
Reference in New Issue
Block a user