From f85c0320ec5284941018d6d22f2143e86263cc8b Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 16 Feb 2023 17:09:12 +0100 Subject: [PATCH] Airspeed **POSITIONABLE** - Added function `GetAirspeedIndicated` to return IAS - Added function `GetAirspeedTrue` to return TAS **UTILS** - Added function `UTILS.IasToTas` to convert IAS to TAS - Added function `TasToIas` to convert TAS to IAS. **POINT** - Added function `COORDINATE:GetWindVec3` --- Moose Development/Moose/Core/Point.lua | 57 ++++++++++++++----- Moose Development/Moose/Utilities/Utils.lua | 25 ++++++++ .../Moose/Wrapper/Positionable.lua | 52 +++++++++++++++++ 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0a9d28e25..23172a347 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1054,28 +1054,55 @@ do -- COORDINATE return heading end + --- Returns the 3D wind direction vector. Note that vector points into the direction the wind in blowing to. + -- @param #COORDINATE self + -- @param #number height (Optional) parameter specifying the height ASL in meters. The minimum height will be always be the land height since the wind is zero below the ground. + -- @param #boolean turbulence (Optional) If `true`, include turbulence. + -- @return DCS#Vec3 Wind 3D vector. Components in m/s. + function COORDINATE:GetWindVec3(height, turbulence) + + -- We at 0.1 meters to be sure to be above ground since wind is zero below ground level. + local landheight=self:GetLandHeight()+0.1 + + local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z} + + -- Get wind velocity vector. + local wind = nil --DCS#Vec3 + + if turbulence then + wind = atmosphere.getWindWithTurbulence(point) + else + wind = atmosphere.getWind(point) + end + + return wind + end + --- Returns the wind direction (from) and strength. -- @param #COORDINATE self - -- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. - -- @return Direction the wind is blowing from in degrees. - -- @return Wind strength in m/s. - function COORDINATE:GetWind(height) - local landheight=self:GetLandHeight()+0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level. - local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z} - -- get wind velocity vector - local wind = atmosphere.getWind(point) - local direction = math.deg(math.atan2(wind.z, wind.x)) - if direction < 0 then - direction = 360 + direction - end - -- Convert to direction to from direction + -- @param #number height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground. + -- @param #boolean turbulence If `true`, include turbulence. If `false` or `nil`, wind without turbulence. + -- @return #number Direction the wind is blowing from in degrees. + -- @return #number Wind strength in m/s. + function COORDINATE:GetWind(height, turbulence) + + -- Get wind velocity vector + local wind = self:GetWindVec3(height, turbulence) + + -- Calculate the direction of the vector. + local direction=UTILS.VecHdg(wind) + + -- Invert "to" direction to "from" direction. if direction > 180 then direction = direction-180 else direction = direction+180 end - local strength=math.sqrt((wind.x)^2+(wind.z)^2) - -- Return wind direction and strength km/h. + + -- Wind strength in m/s. + local strength=UTILS.VecNorm(wind) -- math.sqrt((wind.x)^2+(wind.z)^2) + + -- Return wind direction and strength. return direction, strength end diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index d81856f3b..7d3efe12f 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -489,6 +489,31 @@ UTILS.hPa2inHg = function( hPa ) return hPa * 0.0295299830714 end +--- Convert indicated airspeed (IAS) to true airspeed (TAS) for a given altitude above main sea level. +-- The conversion is based on the approximation that TAS is ~2% higher than IAS with every 1000 ft altitude above sea level. +-- @param #number ias Indicated air speed in any unit (m/s, km/h, knots, ...) +-- @param #number altitude Altitude above main sea level in meters. +-- @param #number oatcorr (Optional) Outside air temperature correction factor. Default 0.017. +-- @return #number True airspeed in the same unit the IAS has been given. +UTILS.IasToTas = function( ias, altitude, oatcorr ) + oatcorr=oatcorr or 0.017 + local tas=ias + (ias * oatcorr * UTILS.MetersToFeet(altitude) / 1000) + return tas +end + +--- Convert true airspeed (TAS) to indicated airspeed (IAS) for a given altitude above main sea level. +-- The conversion is based on the approximation that TAS is ~2% higher than IAS with every 1000 ft altitude above sea level. +-- @param #number tas True air speed in any unit (m/s, km/h, knots, ...) +-- @param #number altitude Altitude above main sea level in meters. +-- @param #number oatcorr (Optional) Outside air temperature correction factor. Default 0.017. +-- @return #number Indicated airspeed in the same unit the TAS has been given. +UTILS.TasToIas = function( tas, altitude, oatcorr ) + oatcorr=oatcorr or 0.017 + local ias=tas/(1+oatcorr*UTILS.MetersToFeet(altitude)/1000) + return ias +end + + --- Convert knots to altitude corrected KIAS, e.g. for tankers. -- @param #number knots Speed in knots. -- @param #number altitude Altitude in feet diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 72f9a9fce..f47d888d8 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -845,6 +845,58 @@ function POSITIONABLE:GetVelocityKNOTS() return UTILS.MpsToKnots( self:GetVelocityMPS() ) end +--- Returns the true airspeed (TAS). This is calculated from the current velocity minus wind in 3D. +-- @param #POSITIONABLE self +-- @return #number TAS in m/s. Returns 0 if the POSITIONABLE does not exist. +function POSITIONABLE:GetAirspeedTrue() + + -- TAS + local tas=0 + + -- Get current coordinate. + local coord=self:GetCoord() + + if coord then + + -- Altitude in meters. + local alt=coord.y + + -- Wind velocity vector. + local wvec3=coord:GetWindVec3(alt, false) + + -- Velocity vector. + local vvec3=self:GetVelocityVec3() + + --GS=TAS+WIND ==> TAS=GS-WIND + local tasvec3=UTILS.VecSubstract(vvec3, wvec3) + + -- True airspeed in m/s + tas=UTILS.VecNorm(tasvec3) + + end + + return tas +end + +--- Returns the indicated airspeed (IAS). +-- The IAS is calculated from the TAS under the approximation that TAS increases by ~2% with every 1000 feet altitude ASL. +-- @param #POSITIONABLE self +-- @param #number oatcorr (Optional) Outside air temperature (OAT) correction factor. Default 0.017 (=1.7%). +-- @return #number IAS in m/s. Returns 0 if the POSITIONABLE does not exist. +function POSITIONABLE:GetAirspeedIndicated(oatcorr) + + -- Get true airspeed. + local tas=self:GetAirspeedTrue() + + -- Get altitude. + local altitude=self:GetAltitude() + + -- Convert TAS to IAS. + local ias=UTILS.TasToIas(tas, altitude, oatcorr) + + return ias +end + --- Returns the Angle of Attack of a POSITIONABLE. -- @param #POSITIONABLE self -- @return #number Angle of attack in degrees.