From 04a7c912ea0984794c31d0fc3b89073ad5880454 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 27 Sep 2023 22:21:17 +0200 Subject: [PATCH] Update Airboss.lua - Improved into wind --- Moose Development/Moose/Ops/Airboss.lua | 138 ++++++++++++++++++++---- 1 file changed, 119 insertions(+), 19 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index ef510bcd2..a1616b965 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -4075,7 +4075,7 @@ function AIRBOSS:_CheckRecoveryTimes() -- Check that wind is blowing from a direction > 5° different from the current heading. local hdg = self:GetHeading() - local wind = self:GetHeadingIntoWind() + local wind = self:GetHeadingIntoWind(nextwindow.SPEED) local delta = self:_GetDeltaHeading( hdg, wind ) local uturn = delta > 5 @@ -6728,7 +6728,7 @@ function AIRBOSS:_AddMarshalGroup( flight, stack ) -- If the carrier is supposed to turn into the wind, we take the wind coordinate. if self.recoverywindow and self.recoverywindow.WIND then - brc = self:GetBRCintoWind() + brc = self:GetBRCintoWind(self.recoverywindow.SPEED) end -- Get charlie time estimate. @@ -11553,7 +11553,7 @@ end -- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned. -- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position. -- @return #number Carrier heading in degrees. -function AIRBOSS:GetHeadingIntoWind( magnetic, coord ) +function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord ) local function adjustDegreesForWindSpeed(windSpeed) local degreesAdjustment = 0 @@ -11613,13 +11613,108 @@ function AIRBOSS:GetHeadingIntoWind( magnetic, coord ) return intowind end +--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway. +-- Implementation based on [Mags & Bambi](https://magwo.github.io/carrier-cruise/). +-- @param #AIRBOSS self +-- @param #number vdeck Desired wind velocity over deck in knots. +-- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned. +-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position. +-- @return #number Carrier heading in degrees. +-- @return #number Carrier speed in knots to reach desired wind speed on deck. +function AIRBOSS:GetHeadingIntoWind( vdeck, magnetic, coord ) + + -- Default offset angle. + local Offset=self.carrierparam.rwyangle or 0 + + -- Get direction the wind is blowing from. + local windfrom, vwind=self:GetWind(18, nil ,coord) + + -- Ships min/max speed. + local Vmin=4 + local Vmax=UTILS.KmphToKnots(self.carrier:GetSpeedMax()) + + -- No wind. will stay on current heading. + if vwind<0.1 then + local h=self:GetHeading(magnetic) + return h, math.min(vdeck, Vmax) + end + + -- Convert wind speed to knots. + vwind=UTILS.MpsToKnots(vwind) + + -- Wind to in knots. + local windto=(windfrom+180)%360 + + -- Offset angle in rad. We also define the rotation to be clock-wise, which requires a minus sign. + local alpha=math.rad(-Offset) + + -- Constant. + local C = math.sqrt(math.cos(alpha)^2 / math.sin(alpha)^2 + 1) + + + -- Upper limit of desired speed due to max boat speed. + local vdeckMax=vwind + math.cos(alpha) * Vmax + + -- Lower limit of desired speed due to min boat speed. + local vdeckMin=vwind + math.cos(alpha) * Vmin + + + -- Speed of ship so it matches the desired speed. + local v=0 + + -- Angle wrt. to wind TO-direction + local theta=0 + + if vdeck>vdeckMax then + -- Boat cannot go fast enough + + -- Set max speed. + v=Vmax + + -- Calculate theta. + theta = math.asin(v/(vwind*C)) - math.asin(-1/C) + + elseif vdeckvwind then + -- Too little wind + + -- Set theta to 90° + theta=math.pi/2 + + -- Set speed. + v = math.sqrt(vdeck^2 - vwind^2) + + else + -- Normal case + theta = math.asin(vdeck * math.sin(alpha) / vwind) + v = vdeck * math.cos(alpha) - vwind * math.cos(theta) + end + + -- Magnetic heading. + local magvar= magnetic and self.magvar or 0 + + -- Ship heading so cross wind is min for the given wind. + local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 + + return intowind, v +end + --- Get base recovery course (BRC) when the carrier would head into the wind. -- This includes the current wind direction and accounts for the angled runway. -- @param #AIRBOSS self +-- @param #number vdeck Desired wind velocity over deck in knots. -- @return #number BRC into the wind in degrees. -function AIRBOSS:GetBRCintoWind() +function AIRBOSS:GetBRCintoWind(vdeck) -- BRC is the magnetic heading. - return self:GetHeadingIntoWind( true ) + return self:GetHeadingIntoWind(vdeck, true ) end --- Get final bearing (FB) of carrier. @@ -13525,28 +13620,32 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) -- Wind speed. local _, vwind = self:GetWind() + -- Desired wind on deck in knots. + local vdeck=UTILS.MpsToKnots(vdeck) + + -- Get heading into the wind accounting for angled runway. + local hiw, speedknots = self:GetHeadingIntoWind(vdeck) + -- Speed of carrier in m/s but at least 4 knots. - local vtot = math.max( vdeck - vwind, UTILS.KnotsToMps( 4 ) ) + local vtot = UTILS.KnotsToMps(speedknots) -- Distance to travel local dist = vtot * time - -- Speed in knots - local speedknots = UTILS.MpsToKnots( vtot ) + -- Distance in NM. local distNM = UTILS.MetersToNM( dist ) - -- Debug output - self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Distance=%.1f NM, Speed=%.1f knots, Time=%d sec.", UTILS.MpsToKnots( vwind ), distNM, speedknots, time ) ) - - -- Get heading into the wind accounting for angled runway. - local hiw = self:GetHeadingIntoWind() - -- Current heading. local hdg = self:GetHeading() -- Heading difference. local deltaH = self:_GetDeltaHeading( hdg, hiw ) + -- Debug output + self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Heading=%03d-->%03d (Delta=%.1f), Speed=%.1f knots, Distance=%.1f NM, Time=%d sec", + UTILS.MpsToKnots( vwind ), hdg, hiw, deltaH, speedknots, distNM, speedknots, time ) ) + + -- Current coordinate. local Cv = self:GetCoordinate() local Ctiw = nil -- Core.Point#COORDINATE @@ -13560,7 +13659,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) Csoo = Cv:Translate( 750, hdg ):Translate( 750, hiw ) -- Heading into wind from Csoo. - local hsw = self:GetHeadingIntoWind( false, Csoo ) + local hsw = self:GetHeadingIntoWind(vdeck, false, Csoo ) -- Into the wind coord. Ctiw = Csoo:Translate( dist, hsw ) @@ -13572,7 +13671,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) Csoo = Cv:Translate( 900, hdg ):Translate( 900, hiw ) -- Heading into wind from Csoo. - local hsw = self:GetHeadingIntoWind( false, Csoo ) + local hsw = self:GetHeadingIntoWind(vdeck, false, Csoo ) -- Into the wind coord. Ctiw = Csoo:Translate( dist, hsw ) @@ -13584,7 +13683,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) Csoo = Cv:Translate( 1100, hdg - 90 ):Translate( 1000, hiw ) -- Heading into wind from Csoo. - local hsw = self:GetHeadingIntoWind( false, Csoo ) + local hsw = self:GetHeadingIntoWind(vdeck, false, Csoo ) -- Into the wind coord. Ctiw = Csoo:Translate( dist, hsw ) @@ -13596,7 +13695,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) Csoo = Cv:Translate( 1200, hdg - 90 ):Translate( 1000, hiw ) -- Heading into wind from Csoo. - local hsw = self:GetHeadingIntoWind( false, Csoo ) + local hsw = self:GetHeadingIntoWind(vdeck, false, Csoo ) -- Into the wind coord. Ctiw = Csoo:Translate( dist, hsw ) @@ -13809,7 +13908,8 @@ function AIRBOSS:_CheckCarrierTurning() local hdg if self.turnintowind then -- We are now steaming into the wind. - hdg = self:GetHeadingIntoWind( false ) + local vdeck=self.recoverywindow and self.recoverywindow.SPEED or 20 + hdg = self:GetHeadingIntoWind(vdeck, false) else -- We turn towards the next waypoint. hdg = self:GetCoordinate():HeadingTo( self:_GetNextWaypoint() )