feat: move stuff to numerics
This commit is contained in:
parent
465ad00f7b
commit
b7fd7046ff
5 changed files with 119 additions and 29 deletions
|
|
@ -1,7 +1,6 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"predictor-refactored/internal/numerics"
|
||||
|
|
@ -19,10 +18,7 @@ func Sum(models ...Model) Model {
|
|||
return func(t float64, s State) State {
|
||||
var sum State
|
||||
for _, m := range models {
|
||||
d := m(t, s)
|
||||
sum.Lat += d.Lat
|
||||
sum.Lng += d.Lng
|
||||
sum.Altitude += d.Altitude
|
||||
sum = numerics.AddGeo(sum, m(t, s))
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
|
@ -44,9 +40,8 @@ func ConstantRate(rate float64) Model {
|
|||
//
|
||||
// using the NASA atmosphere model for rho. Equivalent to Tawhiri's drag_descent.
|
||||
func ParachuteDescent(seaLevelRate float64) Model {
|
||||
k := seaLevelRate * 1.1045
|
||||
return func(_ float64, s State) State {
|
||||
return State{Altitude: -k / math.Sqrt(numerics.NasaDensity(s.Altitude))}
|
||||
return State{Altitude: numerics.DragTerminalVelocity(seaLevelRate, s.Altitude)}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,15 +74,13 @@ func Piecewise(segments []RateSegment) Model {
|
|||
}
|
||||
|
||||
// WindTransport returns a model that moves laterally at the wind velocity
|
||||
// sampled from field. Vertical component is zero. Wind components in m/s
|
||||
// are converted to deg/s on Earth's surface using R = 6371009 m.
|
||||
// sampled from field. The vertical component is zero. Sampling and the
|
||||
// non-fatal "above_model" event live here (orchestration); the m/s → deg/s
|
||||
// conversion is numerics.WindToGeoRate.
|
||||
//
|
||||
// If events is non-nil, an "above_model" event is emitted whenever the
|
||||
// wind field reports altitude above the highest pressure level.
|
||||
func WindTransport(field weather.WindField, events *EventSink) Model {
|
||||
const earthR = 6371009.0
|
||||
const piOver180 = math.Pi / 180.0
|
||||
const degPerRad = 180.0 / math.Pi
|
||||
return func(t float64, s State) State {
|
||||
sample, err := field.Wind(t, s.Lat, s.Lng, s.Altitude)
|
||||
if err != nil {
|
||||
|
|
@ -97,10 +90,7 @@ func WindTransport(field weather.WindField, events *EventSink) Model {
|
|||
events.Emit("above_model", t, s,
|
||||
"altitude exceeded the highest pressure level of the wind dataset; samples extrapolated")
|
||||
}
|
||||
r := earthR + s.Altitude
|
||||
return State{
|
||||
Lat: degPerRad * sample.V / r,
|
||||
Lng: degPerRad * sample.U / (r * math.Cos(s.Lat*piOver180)),
|
||||
}
|
||||
dLat, dLng := numerics.WindToGeoRate(sample.U, sample.V, s.Lat, s.Altitude)
|
||||
return State{Lat: dLat, Lng: dLng}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,25 +241,31 @@ func buildPiecewise(spec ModelSpec, deps BuildDeps) (BuiltModel, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// resolveSegments converts spec segments to engine.RateSegment using the
|
||||
// stage context to resolve relative references.
|
||||
// resolveSegments converts spec segments to engine.RateSegment, turning each
|
||||
// segment's reference-relative Until into an absolute UNIX time. References
|
||||
// are validated by buildPiecewise, so an unrecognised one here is treated as
|
||||
// absolute rather than re-erroring.
|
||||
func resolveSegments(in []PiecewiseSegmentSpec, ctx StageContext) []RateSegment {
|
||||
out := make([]RateSegment, 0, len(in))
|
||||
for _, s := range in {
|
||||
var until float64
|
||||
switch s.Reference {
|
||||
case "", "absolute":
|
||||
until = s.Until
|
||||
case "profile_start":
|
||||
until = ctx.ProfileStart + s.Until
|
||||
case "propagator_start":
|
||||
until = ctx.PropagatorStart + s.Until
|
||||
}
|
||||
out = append(out, RateSegment{Until: until, Rate: s.Rate})
|
||||
out = append(out, RateSegment{Until: segmentBase(s.Reference, ctx) + s.Until, Rate: s.Rate})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// segmentBase returns the absolute time a piecewise segment's Until is
|
||||
// measured from, per its reference.
|
||||
func segmentBase(reference string, ctx StageContext) float64 {
|
||||
switch reference {
|
||||
case "profile_start":
|
||||
return ctx.ProfileStart
|
||||
case "propagator_start":
|
||||
return ctx.PropagatorStart
|
||||
default: // "", "absolute"
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// maybeAddWind sums a WindTransport model into base when the spec asks for it.
|
||||
func maybeAddWind(base Model, includeWind bool, deps BuildDeps) Model {
|
||||
if !includeWind {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue