-
Notifications
You must be signed in to change notification settings - Fork 0
/
harmonics.go
122 lines (99 loc) · 3.29 KB
/
harmonics.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package tides
import (
"time"
"github.com/ryan-lang/tides/astronomy"
)
const (
DEFAULT_PREDICTION_INTERVAL = time.Minute
)
type (
Harmonics struct {
Constituents []*HarmonicConstituent
Datums []*Datum
TidePredOffsets *TidePredOffsets
}
HarmonicConstituent struct {
Name string `json:"name"`
Model harmonicConstituentModel `json:"-"`
PhaseUTC float64 `json:"phase_UTC"`
PhaseLocal float64 `json:"phase_local"` // TODO how/hwere is this used
Amplitude float64 `json:"amplitude"`
Speed float64 `json:"speed"` // TODO how/hwere is this used
}
harmonicConstituentModel interface {
GetName() string
Speed(*astronomy.Astro) float64
Value(*astronomy.Astro) float64
NodeFactor(*astronomy.Astro) float64
FormFactor(*astronomy.Astro) float64
}
harmonicResults map[string]harmonicResult
harmonicFactors map[string]harmonicFactor
harmonicResult struct {
speed float64
value float64
}
harmonicFactor struct {
node float64
form float64
}
)
// Creates a new Prediction struct for a date range with the given start and end times. Optionally accepts PredictionOpts
func (h *Harmonics) NewRangePrediction(start, end time.Time, opts ...PredictionOpt) *Prediction {
p := &Prediction{
Start: start,
End: end,
Interval: DEFAULT_PREDICTION_INTERVAL,
Harmonics: h,
extendedResults: make([]*PredictionValue, 0),
}
for _, opt := range opts {
opt(p)
}
return p
}
// Creates a new Prediction struct for a single point in time. Optionally accepts PredictionOpts
func (h *Harmonics) NewTimePrediction(t time.Time, opts ...PredictionOpt) *Prediction {
p := &Prediction{
Start: t,
End: t,
Interval: DEFAULT_PREDICTION_INTERVAL,
Harmonics: h,
extendedResults: make([]*PredictionValue, 0),
}
for _, opt := range opts {
opt(p)
}
return p
}
func harmonicResultsAtTime(constituents []*HarmonicConstituent, t time.Time) harmonicResults {
// Create maps to store base values and speeds for each constituent.
result := harmonicResults{}
// Initialize the starting astronomical conditions based on the prediction start time.
astro := &astronomy.Astro{Time: t}
// Iterate over each constituent to calculate and store their base value and speed at the start time.
for _, constituent := range constituents {
value := constituent.Model.Value(astro)
speed := constituent.Model.Speed(astro)
result[constituent.Name] = harmonicResult{
value: astronomy.DEG_TO_RAD * value,
speed: astronomy.DEG_TO_RAD * speed,
}
}
return result
}
func harmonicFactorsAtTime(constituents []*HarmonicConstituent, t time.Time) harmonicFactors {
factors := harmonicFactors{}
stepAstro := &astronomy.Astro{Time: t}
// Calculate node and form factors for each constituent at this time step.
// Values are adjusted to ensure they fall within the [0, 360) range and converted to radians as needed.
for _, constituent := range constituents {
nodeFactor := modulus(constituent.Model.NodeFactor(stepAstro), 360)
formFactor := modulus(constituent.Model.FormFactor(stepAstro), 360)
factors[constituent.Name] = harmonicFactor{
node: astronomy.DEG_TO_RAD * nodeFactor,
form: formFactor,
}
}
return factors
}