-
Notifications
You must be signed in to change notification settings - Fork 1
/
magcal_test.go
156 lines (135 loc) · 3.72 KB
/
magcal_test.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package magcal
import (
"fmt"
"math/rand"
"testing"
"time"
)
func TestDefault(t *testing.T) {
mc := NewDefault()
v := vector{1, 2, 3}
x, y, z := mc.Apply(v[0], v[1], v[2])
w := vector{x, y, z}
if !v.close(w, 3) {
t.Fatalf(`want %v got %v`, v, w)
}
}
func TestCustom(t *testing.T) {
cal := []float32{
0.5, 0.0, 0.0, // offset
1.0, 0.0, 0.0, // covariance matrix
0.0, 1.2, 0.0,
0.0, 0.0, 1.0,
}
mc := New(NewState(cal), DefaultConfiguration())
v := vector{1, 2, 3}
expect := vector{0.5, 2.4, 3}
ax, ay, az := mc.Apply(v[0], v[1], v[2])
actual := vector{ax, ay, az}
if !actual.close(expect, 3) {
t.Fatalf(`want %v got %v`, expect, actual)
}
}
var calOptimal = []float32{
// fake
0.5, -0.2, 0.1, // offset
1.0, -0.15, 0.0, // covariance matrix
0.0, 1.2, 0.1,
0.0, 0.19, 1.1,
// real from board
// -0.13, 0.24, 0.05,
// 0.99, -0.15, -0.05,
// 0.19, 1.04, -0.11,
// 0.09, 0.14, 1.10,
}
// 5 of 8 quadrants are enough to have a good result (sometimes)
// does not matter which, 5 is enough for them be on different sides of (0,0)
func TestSearch(t *testing.T) {
rand.Seed(time.Now().UnixNano())
// activeQuadrants := []byte{0, 1, 2, 3, 4}
activeQuadrants := []byte{0, 1, 2, 3, 4, 5, 6, 7}
mc := NewDefault()
// load buffer with random uncalibrated vectors
for !mc.buf.full() {
v := unCalibrate(randomCalibrated(), calOptimal)
w := mc.State.apply(v) // it be same as v here actually, since no calibration happened yet
q := v.quadrant()
for _, a := range activeQuadrants {
if q == a {
mc.buf.push(v, w)
}
}
}
// search for solution
iter := mc.search()
fmt.Printf("%d %+0.3f %+0.3f\r\n", iter, mc.errorTotal(), mc.errorTotal()/float32(mc.config.BufferSize))
mc.State.dump() // found solution
diff := mc.State.diff(NewState(calOptimal)) // difference from optimal
diff.dump()
// buffer
// for _, v := range mc.buf.raw {
// w := mc.State.apply(v)
// e := mc.error(w)
// fmt.Printf("%v, %+0.3f, %+0.3f\r\n", w.string(), w.len(), e)
// }
// println()
// for _, w := range mc.buf.cal {
// e := mc.error(w)
// fmt.Printf("%v, %+0.3f, %+0.3f\r\n", w.string(), w.len(), e)
// }
// check
for i, s := range diff.data {
if (i < 3) && abs(s) > mc.config.Target*0.1 {
t.Fatal("Result calibration matrix offset item differs more than 10%: ", i, s, calOptimal[i])
} else if (i == 3 || i == 7 || i == 11) && abs(s) > 0.1 { // trace shall be quite good
t.Fatal("Result calibration matrix trace item differs more than 0.1: ", i, s, calOptimal[i])
} else if abs(s) > 0.5 {
t.Fatal("Result calibration matrix non-trace item differs more than 0.5: ", i, s, calOptimal[i])
}
}
// check error for each vector in buffer
for _, v := range mc.buf.raw {
w := mc.State.apply(v)
e := mc.error(w)
if e > mc.config.Tolerance*10 {
fmt.Printf("%v, %+0.3f, %+0.3f\r\n", w.string(), w.len(), e)
t.Fatalf(`error larger than expected: %0.4f`, e)
}
}
}
func BenchmarkSearch(b *testing.B) {
rand.Seed(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
mc := NewDefault()
for i := 0; i < mc.config.BufferSize*10; i++ {
v := unCalibrate(randomCalibrated(), calOptimal)
w := mc.State.apply(v) // at first v and w be same, and after buffer fills they diverge
mc.buf.push(v, w)
if mc.buf.full() {
mc.search()
}
}
}
}
func randomCalibrated() (v vector) {
x := 3*rand.Float32() - 1.5
y := 3*rand.Float32() - 1.5
z := 3*rand.Float32() - 1.5
random := vector{x, y, z}
v = random.norm()
return v
}
func unCalibrate(v vector, cal []float32) (w vector) {
m := matrix(make([]float32, 9))
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
m[i*3+j] = cal[(i+1)*3+j]
}
}
mi := m.inv()
w = mi.mul(v)
for i := range w {
w[i] += cal[i]
}
return w
}