From f85c0320ec5284941018d6d22f2143e86263cc8b Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 16 Feb 2023 17:09:12 +0100 Subject: [PATCH 1/2] 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. From 3b1b57a33e128975a9cf6946a6bf9dbd33d148cf Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 16 Feb 2023 17:20:53 +0100 Subject: [PATCH 2/2] Update Positionable.lua - Added GetGroundSpeed --- .../Moose/Wrapper/Positionable.lua | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index f47d888d8..082977785 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -897,6 +897,26 @@ function POSITIONABLE:GetAirspeedIndicated(oatcorr) return ias end +--- Returns the horizonal speed relative to eath's surface. The vertical component of the velocity vector is projected out (set to zero). +-- @param #POSITIONABLE self +-- @return #number Ground speed in m/s. Returns 0 if the POSITIONABLE does not exist. +function POSITIONABLE:GetGroundSpeed() + + local gs=0 + + local vel=self:GetVelocityVec3() + + if vel then + + local vec2={x=vel.x, y=vel.z} + + gs=UTILS.Vec2Norm(vel) + + end + + return gs +end + --- Returns the Angle of Attack of a POSITIONABLE. -- @param #POSITIONABLE self -- @return #number Angle of attack in degrees.