Copyright | (c) 2020 Cedric Liegeois |
---|---|
License | BSD3 |
Maintainer | Cedric Liegeois <ofmooseandmen@yahoo.fr> |
Stability | experimental |
Portability | portable |
Safe Haskell | Safe |
Language | Haskell2010 |
Types and functions for working with kinematics calculations assuming a spherical celestial body.
In order to use this module you should start with the following imports:
import qualified Data.Geo.Jord.Geodetic as Geodetic import qualified Data.Geo.Jord.Kinematics as Kinematics
All functions are implemented using the vector-based approached described in Gade, K. (2010). A Non-singular Horizontal Position Representation and in Shudde, Rex H. (1986). Some tactical algorithms for spherical geometry
Synopsis
- data Track a = Track {}
- data Course
- data Cpa a
- timeToCpa :: Cpa a -> Duration
- distanceAtCpa :: Cpa a -> Length
- cpaOwnshipPosition :: Cpa a -> HorizontalPosition a
- cpaIntruderPosition :: Cpa a -> HorizontalPosition a
- data Intercept a
- timeToIntercept :: Intercept a -> Duration
- distanceToIntercept :: Intercept a -> Length
- interceptPosition :: Intercept a -> HorizontalPosition a
- interceptorBearing :: Intercept a -> Angle
- interceptorSpeed :: Intercept a -> Speed
- course :: Spherical a => HorizontalPosition a -> Angle -> Course
- positionAfter :: Spherical a => HorizontalPosition a -> Angle -> Speed -> Duration -> HorizontalPosition a
- positionAfter' :: Spherical a => HorizontalPosition a -> Course -> Speed -> Duration -> HorizontalPosition a
- trackPositionAfter :: Spherical a => Track a -> Duration -> HorizontalPosition a
- cpa :: Spherical a => Track a -> Track a -> Maybe (Cpa a)
- intercept :: Spherical a => Track a -> HorizontalPosition a -> Maybe (Intercept a)
- interceptBySpeed :: Spherical a => Track a -> HorizontalPosition a -> Speed -> Maybe (Intercept a)
- interceptByTime :: Spherical a => Track a -> HorizontalPosition a -> Duration -> Maybe (Intercept a)
- data Duration
- data Speed
The Track
type.
Track
represents the state of a vehicle by its current horizontal position, bearing and speed.
Track | |
|
The Course
type.
Course
represents the cardinal direction in which the vehicle is to be steered.
The Cpa
type.
Time to, and distance at, closest point of approach (CPA) as well as position of both tracks at CPA.
distanceAtCpa :: Cpa a -> Length Source #
distance at CPA.
cpaOwnshipPosition :: Cpa a -> HorizontalPosition a Source #
horizontal position of ownship CPA.
cpaIntruderPosition :: Cpa a -> HorizontalPosition a Source #
horizontal position of intruder at CPA.
The Intercept
type.
Time, distance and position of intercept as well as speed and initial bearing of interceptor.
timeToIntercept :: Intercept a -> Duration Source #
time to intercept.
distanceToIntercept :: Intercept a -> Length Source #
distance travelled to intercept.
interceptPosition :: Intercept a -> HorizontalPosition a Source #
horizontal position of intercept.
interceptorBearing :: Intercept a -> Angle Source #
initial bearing of interceptor.
interceptorSpeed :: Intercept a -> Speed Source #
speed of interceptor.
Calculations
course :: Spherical a => HorizontalPosition a -> Angle -> Course Source #
course p b
computes the course of a vehicle currently at position p
and following bearing b
.
positionAfter :: Spherical a => HorizontalPosition a -> Angle -> Speed -> Duration -> HorizontalPosition a Source #
positionAfter p b s d
computes the horizontal position of a vehicle currently at position p
following
bearing b
and travelling at speed s
after duration d
has elapsed. For example:
>>>
let p = Geodetic.s84Pos 53.321 (-1.729)
>>>
let b = Angle.decimalDegrees 96.0217
>>>
let s = Speed.kilometresPerHour 124.8
>>>
Kinematics.positionAfter p b s (Duration.hours 1)
53°11'19.367"N,0°8'2.456"E (S84)
This is equivalent to:
Kinematics.positionAfter' p (Kinematics.course p b) s d
positionAfter' :: Spherical a => HorizontalPosition a -> Course -> Speed -> Duration -> HorizontalPosition a Source #
positionAfter' p c s d
computes the horizontal position of a vehicle currently at position p
on course c
and
travelling at speed s
after duration d
has elapsed.
Note: course must have been calculated from position p
.
trackPositionAfter :: Spherical a => Track a -> Duration -> HorizontalPosition a Source #
trackPositionAfter t d
computes the horizontal position of a track t
after duration d
has elapsed. For example:
>>>
let p = Geodetic.s84Pos 53.321 (-1.729)
>>>
let b = Angle.decimalDegrees 96.0217
>>>
let s = Speed.kilometresPerHour 124.8
>>>
Kinematics.trackPositionAfter (Kinematics.Track p b s) (Duration.hours 1)
53°11'19.367"N,0°8'2.456"E (S84)
cpa :: Spherical a => Track a -> Track a -> Maybe (Cpa a) Source #
cpa ownship intruder
computes the closest point of approach between tracks ownship
and intruder
.
The closest point of approach is calculated assuming both ships maintain a constant course and speed.
>>>
let ownship = Kinematics.Track (Geodetic.s84Pos 20 (-60)) (Angle.decimalDegrees 10) (Speed.knots 15)
>>>
let intruder = Kinematics.Track (Geodetic.s84Pos 34 (-50)) (Angle.decimalDegrees 220) (Speed.knots 300)
>>>
let cpa = Kinematics.cpa ownship intruder
Just (Cpa { timeToCpa = 3H9M56.155S , distanceAtCpa = 124.231730834km , cpaOwnshipPosition = 20°46'43.641"N,59°51'11.225"W (S84) , cpaIntruderPosition = 21°24'8.523"N,60°50'48.159"W (S84)})
intercept :: Spherical a => Track a -> HorizontalPosition a -> Maybe (Intercept a) Source #
intercept t p
computes the minimum speed of interceptor at position p
needed for an intercept with target
track t
to take place. Intercept time, position, distance and interceptor bearing are derived from this minimum
speed. For example:
>>>
let t = Kinematics.Track (Geodetic.s84Pos 34 (-50)) (Angle.decimalDegrees 220) (Speed.knots 600)
>>>
let ip = Geodetic.s84Pos 20 (-60)
>>>
Kinematics.intercept t ip
Just (Intercept { timeToIntercept = 1H39M53.831S , distanceToIntercept = 162.294627463km , interceptPosition = 20°43'42.305"N,61°20'56.848"W (S84) , interceptorBearing = 300°10'18.053" , interceptorSpeed = 97.476999km/h})
Returns Nothing
if intercept cannot be achieved e.g.:
- interceptor and target are at the same position
- interceptor is "behind" the target
interceptBySpeed :: Spherical a => Track a -> HorizontalPosition a -> Speed -> Maybe (Intercept a) Source #
interceptByTime :: Spherical a => Track a -> HorizontalPosition a -> Duration -> Maybe (Intercept a) Source #
interceptByTime t p d
computes the speed of interceptor at position p
needed for an intercept with target
track t
to take place after duration d
.For example:
>>>
let t = Kinematics.Track (Geodetic.s84Pos 34 (-50)) (Angle.decimalDegrees 220) (Speed.knots 600)
>>>
let ip = Geodetic.s84Pos 20 (-60)
>>>
let d = Duration.seconds 2700
>>>
interceptByTime t ip d
Just (Intercept { timeToIntercept = 0H45M0.000S , distanceToIntercept = 1015.302358852km , interceptPosition = 28°8'12.046"N,55°27'21.411"W (S84) , interceptorBearing = 26°7'11.649" , interceptorSpeed = 1353.736478km/h})
Returns Nothing
if given duration is <= 0 or interceptor and target are at the same position. Contrary to
intercept
and interceptBySpeed
this function handles cases where the interceptor has to catch up the target.
re-exported for convenience
A duration with a resolution of 1 millisecond.