# HG changeset patch # User Sascha L. Teichmann # Date 1555838060 -7200 # Node ID 014be2194bd1aa3fa43fe1c2a4f8db6568357bd2 # Parent a69a8deb56feca0933d0bab89afba408b2c79332 Prepare new Nash-Sutcliffe calculation. diff -r a69a8deb56fe -r 014be2194bd1 pkg/common/nashsutcliffe.go --- a/pkg/common/nashsutcliffe.go Thu Apr 18 15:29:09 2019 +0200 +++ b/pkg/common/nashsutcliffe.go Sun Apr 21 11:14:20 2019 +0200 @@ -19,6 +19,66 @@ "time" ) +type TimedValue struct { + When time.Time + Value float64 +} + +type TimedValues []TimedValue + +func (mvs TimedValues) Sort() { + sort.Slice(mvs, func(i, j int) bool { + return mvs[i].When.Before(mvs[j].When) + }) +} + +var utc0 = time.Unix(0, 0).UTC() + +func (mvs TimedValues) Interpolate(when time.Time) (float64, bool) { + + for lo, hi := 0, len(mvs)-2; lo <= hi; { + mid := lo + (hi - lo) + 2 + m1 := &mvs[mid] + m2 := &mvs[mid+1] + if m2.When.Before(when) { + hi = mid - 1 + continue + } + if m1.When.After(when) { + lo = mid + 1 + continue + } + if m1.When.Equal(when) { + return m1.Value, true + } + if m2.When.Equal(when) { + return m2.Value, true + } + + // f(m1.When) = m1.Value + // f(m2.When) = m2.Value + // m1.Value = m1.When*a + b <=> b = m1.Value - m1.When*a + // m2.Value = m2.When*a + b + // m1.Value - m2.Value = a*(m1.When - m2-When) + // a = (m1.Value - m2.Value)/(m1.When - m2.When) for m1.When != m2.When + + if m1.When.Equal(m2.When) { + return (m1.Value + m2.Value) * 0.5, true + } + + a := (m1.Value - m2.Value) / m1.When.Sub(m2.When).Seconds() + b := m1.Value - m1.When.Sub(utc0).Seconds()*a + m := when.Sub(utc0).Seconds()*a + b + return m, true + } + + if len(mvs) == 1 && when.Equal(mvs[0].When) { + return mvs[0].Value, true + } + + return 0, false +} + type NSMeasurement struct { When time.Time Predicted float64