...
1package main
2
3import (
4 "fmt"
5 "sort"
6 "sync"
7)
8
9/*
10 given some reference points will interpolate a value,
11
12examples:
13 1. reference points 5(50) and 10(100), interpolation: 7=70, 8=80,3=30 (0 is assumed), 11=100 (highest=max)
14*/
15type Interpolator struct {
16 sync.Mutex
17 referencepoints []*interpolator_referencepoint
18}
19
20type interpolator_referencepoint struct {
21 number float64
22 value float64
23}
24
25func (ip *Interpolator) AddReferencePoints(points map[float64]float64) {
26 for k, v := range points {
27 ip.AddReferencePoint(k, v)
28 }
29}
30func (ip *Interpolator) AddReferencePoint(number, value float64) {
31 ip.Lock()
32 defer ip.Unlock()
33 if len(ip.referencepoints) == 0 {
34 ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: 0, value: 0})
35 }
36 ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: number, value: value})
37 sort.Slice(ip.referencepoints, func(i, j int) bool {
38 return ip.referencepoints[i].number < ip.referencepoints[j].number
39 })
40 var last *interpolator_referencepoint
41 for _, ir := range ip.referencepoints {
42 if last == nil {
43 last = ir
44 continue
45 }
46 if ir.value < last.value {
47 fmt.Printf("WARNING: interpolator values out of order: %s\n", ip.String())
48 }
49 last = ir
50 }
51}
52func (ip *Interpolator) Interpolate(number float64) float64 {
53 ir1, ir2 := ip.findReferences(number)
54 if ir2 == nil {
55 // max out
56 // fmt.Printf("Value %0.1f is maxed out, because highest is %s\n", number, ir1.String())
57 return ir1.value
58 }
59 xa := ir1.number
60 ya := ir1.value
61 xb := ir2.number
62 yb := ir2.value
63 x := number
64 diff := (x - xa) / (xb - xa)
65 y := ya + (yb-ya)*diff
66 //fmt.Printf("Value %0.1f is between %s and %s, diff=%0.1f, res=%0.1f\n", number, ir1.String(), ir2.String(), diff, y)
67 return y
68}
69func (ip *Interpolator) findReferences(number float64) (*interpolator_referencepoint, *interpolator_referencepoint) {
70 var ir1 *interpolator_referencepoint
71 var ir2 *interpolator_referencepoint
72 for i, ir := range ip.referencepoints {
73 if number < ir.number {
74 continue
75 }
76 ir1 = ir
77 if i < len(ip.referencepoints)-1 {
78 ir2 = ip.referencepoints[i+1]
79 } else {
80 ir2 = nil
81 }
82 }
83 return ir1, ir2
84}
85func (ip *Interpolator) String() string {
86 deli := ""
87 s := ""
88 for _, ir := range ip.referencepoints {
89 s = s + deli + fmt.Sprintf("%f->%f", ir.number, ir.value)
90 deli = ", "
91 }
92 return s
93}
94
95func (ir *interpolator_referencepoint) String() string {
96 return fmt.Sprintf("%f->%f", ir.number, ir.value)
97}
View as plain text