mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-09-02 05:51:14 +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)
|
return UTILS.Round(bearing,0)
|
||||||
end
|
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
|
return gs
|
||||||
end
|
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.
|
--- Returns the Angle of Attack of a POSITIONABLE.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
-- @return #number Angle of attack in degrees.
|
-- @return #number Angle of attack in degrees.
|
||||||
|
|||||||
Reference in New Issue
Block a user