annotate src/compass_calib.c @ 96:a4bff632e97b

auto-reset compass filtering data before calibration
author heinrichsweikamp
date Mon, 28 Apr 2014 11:33:00 +0200
parents 11d4fc797f74
children 7d9edd3b8c86
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
heinrichsweikamp
parents:
diff changeset
1 #include "compass.h"
heinrichsweikamp
parents:
diff changeset
2
heinrichsweikamp
parents:
diff changeset
3 static unsigned short int compass_N;
heinrichsweikamp
parents:
diff changeset
4
heinrichsweikamp
parents:
diff changeset
5 static float Su, Sv, Sw;
heinrichsweikamp
parents:
diff changeset
6 static float Suu, Svv, Sww, Suv, Suw, Svw;
heinrichsweikamp
parents:
diff changeset
7 static float Suuu, Svvv, Swww;
heinrichsweikamp
parents:
diff changeset
8 static float Suuv, Suuw, Svvu, Svvw, Swwu, Swwv;
heinrichsweikamp
parents:
diff changeset
9
heinrichsweikamp
parents:
diff changeset
10 //////////////////////////////////////////////////////////////////////////////
heinrichsweikamp
parents:
diff changeset
11 // mH: Crude work-around, needs to be made right
heinrichsweikamp
parents:
diff changeset
12 #ifndef UNIX
heinrichsweikamp
parents:
diff changeset
13 # pragma udata overlay bank8=0x800
heinrichsweikamp
parents:
diff changeset
14 static char C_STACK[256]; // Overlay C-code data stack here.
heinrichsweikamp
parents:
diff changeset
15 # define RESET_C_STACK \
heinrichsweikamp
parents:
diff changeset
16 _asm \
heinrichsweikamp
parents:
diff changeset
17 LFSR 1, 0x800 \
heinrichsweikamp
parents:
diff changeset
18 LFSR 2, 0x800 \
heinrichsweikamp
parents:
diff changeset
19 _endasm
heinrichsweikamp
parents:
diff changeset
20 # pragma udata overlay bank9_compass
heinrichsweikamp
parents:
diff changeset
21 #else
heinrichsweikamp
parents:
diff changeset
22 # define RESET_C_STACK
heinrichsweikamp
parents:
diff changeset
23 #endif
heinrichsweikamp
parents:
diff changeset
24
heinrichsweikamp
parents:
diff changeset
25 //////////////////////////////////////////////////////////////////////////////
heinrichsweikamp
parents:
diff changeset
26
heinrichsweikamp
parents:
diff changeset
27 void compass_reset_calibration()
heinrichsweikamp
parents:
diff changeset
28 {
heinrichsweikamp
parents:
diff changeset
29 RESET_C_STACK;
heinrichsweikamp
parents:
diff changeset
30
heinrichsweikamp
parents:
diff changeset
31 compass_N = 0;
heinrichsweikamp
parents:
diff changeset
32 Su = Sv = Sw = 0.0;
heinrichsweikamp
parents:
diff changeset
33 Suu = Svv = Sww = Suv = Suw = Svw = 0.0;
heinrichsweikamp
parents:
diff changeset
34 Suuu = Svvv = Swww = 0.0;
heinrichsweikamp
parents:
diff changeset
35 Suuv = Suuw = Svvu = Svvw = Swwu = Swwv = 0.0;
96
a4bff632e97b auto-reset compass filtering data before calibration
heinrichsweikamp
parents: 0
diff changeset
36 compass_CX_f = compass_CY_f = compass_CZ_f = 0.0;
0
heinrichsweikamp
parents:
diff changeset
37 }
heinrichsweikamp
parents:
diff changeset
38
heinrichsweikamp
parents:
diff changeset
39 void compass_add_calibration()
heinrichsweikamp
parents:
diff changeset
40 {
heinrichsweikamp
parents:
diff changeset
41 OVERLAY float u, v, w;
heinrichsweikamp
parents:
diff changeset
42 RESET_C_STACK;
heinrichsweikamp
parents:
diff changeset
43
heinrichsweikamp
parents:
diff changeset
44 u = (compass_DX_f - compass_CX_f) / 32768.0f;
heinrichsweikamp
parents:
diff changeset
45 v = (compass_DY_f - compass_CY_f) / 32768.0f;
heinrichsweikamp
parents:
diff changeset
46 w = (compass_DZ_f - compass_CZ_f) / 32768.0f;
heinrichsweikamp
parents:
diff changeset
47
heinrichsweikamp
parents:
diff changeset
48 compass_N++;
heinrichsweikamp
parents:
diff changeset
49 Su += u;
heinrichsweikamp
parents:
diff changeset
50 Sv += v;
heinrichsweikamp
parents:
diff changeset
51 Sw += w;
heinrichsweikamp
parents:
diff changeset
52 Suv += u*v;
heinrichsweikamp
parents:
diff changeset
53 Suw += u*w;
heinrichsweikamp
parents:
diff changeset
54 Svw += v*w;
heinrichsweikamp
parents:
diff changeset
55 Suu += u*u;
heinrichsweikamp
parents:
diff changeset
56 Suuu += u*u*u;
heinrichsweikamp
parents:
diff changeset
57 Suuv += v*u*u;
heinrichsweikamp
parents:
diff changeset
58 Suuw += w*u*u;
heinrichsweikamp
parents:
diff changeset
59 Svv += v*v;
heinrichsweikamp
parents:
diff changeset
60 Svvv += v*v*v;
heinrichsweikamp
parents:
diff changeset
61 Svvu += u*v*v;
heinrichsweikamp
parents:
diff changeset
62 Svvw += w*v*v;
heinrichsweikamp
parents:
diff changeset
63 Sww += w*w;
heinrichsweikamp
parents:
diff changeset
64 Swww += w*w*w;
heinrichsweikamp
parents:
diff changeset
65 Swwu += u*w*w;
heinrichsweikamp
parents:
diff changeset
66 Swwv += v*w*w;
heinrichsweikamp
parents:
diff changeset
67 }
heinrichsweikamp
parents:
diff changeset
68
heinrichsweikamp
parents:
diff changeset
69 //////////////////////////////////////////////////////////////////////////////
heinrichsweikamp
parents:
diff changeset
70
heinrichsweikamp
parents:
diff changeset
71 void compass_solve_calibration()
heinrichsweikamp
parents:
diff changeset
72 {
heinrichsweikamp
parents:
diff changeset
73 OVERLAY float yu, yv, yw;
heinrichsweikamp
parents:
diff changeset
74 OVERLAY float delta;
heinrichsweikamp
parents:
diff changeset
75 OVERLAY float uc, vc, wc;
heinrichsweikamp
parents:
diff changeset
76 RESET_C_STACK;
heinrichsweikamp
parents:
diff changeset
77
heinrichsweikamp
parents:
diff changeset
78 //---- Normalize partial sums --------------------------------------------
heinrichsweikamp
parents:
diff changeset
79 //
heinrichsweikamp
parents:
diff changeset
80 // u, v, w should be centered on the mean value um, vm, wm:
heinrichsweikamp
parents:
diff changeset
81 // x = u + um, with um = Sx/N
heinrichsweikamp
parents:
diff changeset
82 //
heinrichsweikamp
parents:
diff changeset
83 // So:
heinrichsweikamp
parents:
diff changeset
84 // (u + um)**2 = u**2 + 2u*um + um**2
heinrichsweikamp
parents:
diff changeset
85 // Su = 0, um = Sx/N
heinrichsweikamp
parents:
diff changeset
86 // Sxx = Suu + 2 um Su + N*(Sx/N)**2 = Suu + Sx**2/N
heinrichsweikamp
parents:
diff changeset
87 // Suu = Sxx - Sx**2/N
heinrichsweikamp
parents:
diff changeset
88 yu = Su/compass_N;
heinrichsweikamp
parents:
diff changeset
89 yv = Sv/compass_N;
heinrichsweikamp
parents:
diff changeset
90 yw = Sw/compass_N;
heinrichsweikamp
parents:
diff changeset
91
heinrichsweikamp
parents:
diff changeset
92 Suu -= Su*yu;
heinrichsweikamp
parents:
diff changeset
93 Svv -= Sv*yv;
heinrichsweikamp
parents:
diff changeset
94 Sww -= Sw*yw;
heinrichsweikamp
parents:
diff changeset
95
heinrichsweikamp
parents:
diff changeset
96 // (u + um)(v + vm) = uv + u vm + v um + um vm
heinrichsweikamp
parents:
diff changeset
97 // Sxy = Suv + N * um vm
heinrichsweikamp
parents:
diff changeset
98 // Suv = Sxy - N * (Sx/N)(Sy/N);
heinrichsweikamp
parents:
diff changeset
99 Suv -= Su*yv;
heinrichsweikamp
parents:
diff changeset
100 Suw -= Su*yw;
heinrichsweikamp
parents:
diff changeset
101 Svw -= Sv*yw;
heinrichsweikamp
parents:
diff changeset
102
heinrichsweikamp
parents:
diff changeset
103 // (u + um)**3 = u**3 + 3 u**2 um + 3 u um**2 + um**3
heinrichsweikamp
parents:
diff changeset
104 // Sxxx = Suuu + 3 um Suu + 3 um**2 Su + N.um**3
heinrichsweikamp
parents:
diff changeset
105 // Su = 0, um = Sx/N:
heinrichsweikamp
parents:
diff changeset
106 // Suuu = Sxxx - 3 Sx*Suu/N - N.(Sx/N)**3
heinrichsweikamp
parents:
diff changeset
107 // = Sxxx - 3 Sx*Suu/N - Sx**3/N**2
heinrichsweikamp
parents:
diff changeset
108
heinrichsweikamp
parents:
diff changeset
109 // (u + um)**2 (v + vm) = (u**2 + 2 u um + um**2)(v + vm)
heinrichsweikamp
parents:
diff changeset
110 // Sxxy = Suuv + vm Suu + 2 um (Suv + vm Su) + um**2 (Sv + N.vm)
heinrichsweikamp
parents:
diff changeset
111 //
heinrichsweikamp
parents:
diff changeset
112 // Su = 0, Sv = 0, vm = Sy/N:
heinrichsweikamp
parents:
diff changeset
113 // Sxxy = Suuv + vm Suu + 2 um Suv + N um**2 vm
heinrichsweikamp
parents:
diff changeset
114 //
heinrichsweikamp
parents:
diff changeset
115 // Suuv = Sxxy - (Sy/N) Suu - 2 (Sx/N) Suv - (Sx/N)**2 Sy
heinrichsweikamp
parents:
diff changeset
116 // = Sxxy - Suu*Sy/N - 2 Suv*Sx/N - Sx*Sx*Sy/N/N
heinrichsweikamp
parents:
diff changeset
117 // = Sxxy - (Suu + Sx*Sx/N)*Sy/N - 2 Suv*Sx/N
heinrichsweikamp
parents:
diff changeset
118 Suuu -= (3*Suu + Su*yu)*yu;
heinrichsweikamp
parents:
diff changeset
119 Suuv -= (Suu + Su*yu)*yv + 2*Suv*yu;
heinrichsweikamp
parents:
diff changeset
120 Suuw -= (Suu + Su*yu)*yw + 2*Suw*yu;
heinrichsweikamp
parents:
diff changeset
121
heinrichsweikamp
parents:
diff changeset
122 Svvu -= (Svv + Sv*yv)*yu + 2*Suv*yv;
heinrichsweikamp
parents:
diff changeset
123 Svvv -= (3*Svv + Sv*yv)*yv;
heinrichsweikamp
parents:
diff changeset
124 Svvw -= (Svv + Sv*yv)*yw + 2*Svw*yv;
heinrichsweikamp
parents:
diff changeset
125
heinrichsweikamp
parents:
diff changeset
126 Swwu -= (Sww + Sw*yw)*yu + 2*Suw*yw;
heinrichsweikamp
parents:
diff changeset
127 Swwv -= (Sww + Sw*yw)*yv + 2*Svw*yw;
heinrichsweikamp
parents:
diff changeset
128 Swww -= (3*Sww + Sw*yw)*yw;
heinrichsweikamp
parents:
diff changeset
129
heinrichsweikamp
parents:
diff changeset
130 //---- Solve the system --------------------------------------------------
heinrichsweikamp
parents:
diff changeset
131 // uc Suu + vc Suv + wc Suw = (Suuu + Svvu + Swwu) / 2
heinrichsweikamp
parents:
diff changeset
132 // uc Suv + vc Svv + wc Svw = (Suuv + Svvv + Swwv) / 2
heinrichsweikamp
parents:
diff changeset
133 // uc Suw + vc Svw + wc Sww = (Suuw + Svvw + Swww) / 2
heinrichsweikamp
parents:
diff changeset
134 // Note this is symetric, with a positiv diagonal, hence
heinrichsweikamp
parents:
diff changeset
135 // it always have a uniq solution.
heinrichsweikamp
parents:
diff changeset
136 yu = 0.5f * (Suuu + Svvu + Swwu);
heinrichsweikamp
parents:
diff changeset
137 yv = 0.5f * (Suuv + Svvv + Swwv);
heinrichsweikamp
parents:
diff changeset
138 yw = 0.5f * (Suuw + Svvw + Swww);
heinrichsweikamp
parents:
diff changeset
139 delta = Suu * (Svv * Sww - Svw * Svw)
heinrichsweikamp
parents:
diff changeset
140 - Suv * (Suv * Sww - Svw * Suw)
heinrichsweikamp
parents:
diff changeset
141 + Suw * (Suv * Svw - Svv * Suw);
heinrichsweikamp
parents:
diff changeset
142
heinrichsweikamp
parents:
diff changeset
143 uc = (yu * (Svv * Sww - Svw * Svw)
heinrichsweikamp
parents:
diff changeset
144 - yv * (Suv * Sww - Svw * Suw)
heinrichsweikamp
parents:
diff changeset
145 + yw * (Suv * Svw - Svv * Suw) )/delta;
heinrichsweikamp
parents:
diff changeset
146 vc = (Suu * ( yv * Sww - yw * Svw)
heinrichsweikamp
parents:
diff changeset
147 - Suv * ( yu * Sww - yw * Suw)
heinrichsweikamp
parents:
diff changeset
148 + Suw * ( yu * Svw - yv * Suw) )/delta;
heinrichsweikamp
parents:
diff changeset
149 wc = (Suu * (Svv * yw - Svw * yv )
heinrichsweikamp
parents:
diff changeset
150 - Suv * (Suv * yw - Svw * yu )
heinrichsweikamp
parents:
diff changeset
151 + Suw * (Suv * yv - Svv * yu ) )/delta;
heinrichsweikamp
parents:
diff changeset
152
heinrichsweikamp
parents:
diff changeset
153 // Back to uncentered coordinates:
heinrichsweikamp
parents:
diff changeset
154 // xc = um + uc
heinrichsweikamp
parents:
diff changeset
155 uc = Su/compass_N + compass_CX_f/32768.0f + uc;
heinrichsweikamp
parents:
diff changeset
156 vc = Sv/compass_N + compass_CY_f/32768.0f + vc;
heinrichsweikamp
parents:
diff changeset
157 wc = Sw/compass_N + compass_CZ_f/32768.0f + wc;
heinrichsweikamp
parents:
diff changeset
158
heinrichsweikamp
parents:
diff changeset
159 // Then save the new calibrated center:
heinrichsweikamp
parents:
diff changeset
160 compass_CX_f = (short)(32768 * uc);
heinrichsweikamp
parents:
diff changeset
161 compass_CY_f = (short)(32768 * vc);
heinrichsweikamp
parents:
diff changeset
162 compass_CZ_f = (short)(32768 * wc);
heinrichsweikamp
parents:
diff changeset
163 }
heinrichsweikamp
parents:
diff changeset
164
heinrichsweikamp
parents:
diff changeset
165 ////////////////////////////// TEST CODE /////////////////////////////////////
heinrichsweikamp
parents:
diff changeset
166
heinrichsweikamp
parents:
diff changeset
167 #ifdef TEST_COMPASS_CALIBRATION
heinrichsweikamp
parents:
diff changeset
168
heinrichsweikamp
parents:
diff changeset
169 #include <QtDebug>
heinrichsweikamp
parents:
diff changeset
170 #include <stdio.h>
heinrichsweikamp
parents:
diff changeset
171
heinrichsweikamp
parents:
diff changeset
172 #include <math.h>
heinrichsweikamp
parents:
diff changeset
173 #include <stdlib.h>
heinrichsweikamp
parents:
diff changeset
174
heinrichsweikamp
parents:
diff changeset
175 short compass_DX_f, compass_DY_f, compass_DZ_f;
heinrichsweikamp
parents:
diff changeset
176 short compass_CX_f, compass_CY_f, compass_CZ_f;
heinrichsweikamp
parents:
diff changeset
177
heinrichsweikamp
parents:
diff changeset
178 inline float uniform() {
heinrichsweikamp
parents:
diff changeset
179 return (rand() & 0xFFFF) / 65536.0f;
heinrichsweikamp
parents:
diff changeset
180 }
heinrichsweikamp
parents:
diff changeset
181 inline float sqr(float x) {
heinrichsweikamp
parents:
diff changeset
182 return x*x;
heinrichsweikamp
parents:
diff changeset
183 }
heinrichsweikamp
parents:
diff changeset
184
heinrichsweikamp
parents:
diff changeset
185 static const float radius = 0.21f;
heinrichsweikamp
parents:
diff changeset
186 static const float cx = 0.79f, cy = -0.46f, cz = 0.24f;
heinrichsweikamp
parents:
diff changeset
187 // const float cx = 0, cy = 0, cz = 0;
heinrichsweikamp
parents:
diff changeset
188
heinrichsweikamp
parents:
diff changeset
189 void check_compass_calib()
heinrichsweikamp
parents:
diff changeset
190 {
heinrichsweikamp
parents:
diff changeset
191
heinrichsweikamp
parents:
diff changeset
192 // Starts with no calibration at all:
heinrichsweikamp
parents:
diff changeset
193 compass_CX_f = compass_CY_f = compass_CZ_f = 0;
heinrichsweikamp
parents:
diff changeset
194
heinrichsweikamp
parents:
diff changeset
195 // Try 10 recalibration passes:
heinrichsweikamp
parents:
diff changeset
196 for(int p=0; p<10; ++p)
heinrichsweikamp
parents:
diff changeset
197 {
heinrichsweikamp
parents:
diff changeset
198 compass_reset_calibration();
heinrichsweikamp
parents:
diff changeset
199
heinrichsweikamp
parents:
diff changeset
200 //---- Generates random points on a sphere -------------------------------
heinrichsweikamp
parents:
diff changeset
201 // of radius,center (cx, cy, cz):
heinrichsweikamp
parents:
diff changeset
202 for(int i=0; i<100; ++i)
heinrichsweikamp
parents:
diff changeset
203 {
heinrichsweikamp
parents:
diff changeset
204 float theta = uniform()*360.0f;
heinrichsweikamp
parents:
diff changeset
205 float phi = uniform()*180.0f - 90.0f;
heinrichsweikamp
parents:
diff changeset
206
heinrichsweikamp
parents:
diff changeset
207 float x = cx + radius * cosf(phi)*cosf(theta);
heinrichsweikamp
parents:
diff changeset
208 float y = cy + radius * cosf(phi)*sinf(theta);
heinrichsweikamp
parents:
diff changeset
209 float z = cz + radius * sinf(phi);
heinrichsweikamp
parents:
diff changeset
210
heinrichsweikamp
parents:
diff changeset
211 compass_DX_f = short(32768 * x);
heinrichsweikamp
parents:
diff changeset
212 compass_DY_f = short(32768 * y);
heinrichsweikamp
parents:
diff changeset
213 compass_DZ_f = short(32768 * z);
heinrichsweikamp
parents:
diff changeset
214 compass_add_calibration();
heinrichsweikamp
parents:
diff changeset
215 }
heinrichsweikamp
parents:
diff changeset
216
heinrichsweikamp
parents:
diff changeset
217 compass_solve_calibration();
heinrichsweikamp
parents:
diff changeset
218 qDebug() << "Center ="
heinrichsweikamp
parents:
diff changeset
219 << compass_CX_f/32768.0f
heinrichsweikamp
parents:
diff changeset
220 << compass_CY_f/32768.0f
heinrichsweikamp
parents:
diff changeset
221 << compass_CZ_f/32768.0f;
heinrichsweikamp
parents:
diff changeset
222
heinrichsweikamp
parents:
diff changeset
223 float r2 = sqr(compass_CX_f/32768.0f - cx)
heinrichsweikamp
parents:
diff changeset
224 + sqr(compass_CY_f/32768.0f - cy)
heinrichsweikamp
parents:
diff changeset
225 + sqr(compass_CZ_f/32768.0f - cz);
heinrichsweikamp
parents:
diff changeset
226 if( r2 > 0.01f*0.01f )
heinrichsweikamp
parents:
diff changeset
227 qWarning() << " calibration error: " << sqrtf(r2);
heinrichsweikamp
parents:
diff changeset
228 }
heinrichsweikamp
parents:
diff changeset
229 }
heinrichsweikamp
parents:
diff changeset
230 #endif // TEST_COMPASS_CALIBRATION