comparison src/compass_calib.c @ 623:c40025d8e750

3.03 beta released
author heinrichsweikamp
date Mon, 03 Jun 2019 14:01:48 +0200
parents ca4556fb60b9
children cd58f7fc86db
comparison
equal deleted inserted replaced
622:02d1386429a6 623:c40025d8e750
1 ////////////////////////////////////////////////////////////////////////////// 1 /////////////////////////////////////////////////////////////////////////////
2 /// compass_calib.c 2 //
3 /// Calibrate hard-iron for magnetic compass measurements. 3 // compass_calib.c next generation V3.03.4
4 /// Copyright (c) 2012-2015, JD Gascuel, HeinrichsWeikamp, all right reserved. 4 //
5 ////////////////////////////////////////////////////////////////////////////// 5 // Calibrate hard-iron for magnetic compass measurements.
6 // Copyright (c) 2012-2019, JD Gascuel, HeinrichsWeikamp, all rights reserved.
7 //
8 //////////////////////////////////////////////////////////////////////////////
9
6 // 2015-05-22 [jDG] Make a smaller calibration code (15.6 --> 6.7 KB). 10 // 2015-05-22 [jDG] Make a smaller calibration code (15.6 --> 6.7 KB).
7 11 // 2019-05-14 [rl] make it even smaller again by another 2.000 byte
12
13 #include "configuration.inc"
8 #include "compass.h" 14 #include "compass.h"
9 15
10 ////////////////////////////////////////////////////////////////////////////// 16
17 #ifdef _compass
18
19
20 //////////////////////////////////////////////////////////////////////////////
21 //
11 // mH: Put compass data into bank 8 (stack) and bank 9 (variables) 22 // mH: Put compass data into bank 8 (stack) and bank 9 (variables)
23 // rl: could also be overlaid with p2_deco.c stack...
24 //
12 #ifndef UNIX 25 #ifndef UNIX
13 # pragma udata overlay bank8=0x800 26 # pragma udata overlay bank8=0x800
14 static char C_STACK[256]; // overlay C-code data stack here 27 static char C_STACK[256]; // overlay C-code data stack here
15 # define RESET_C_STACK \ 28 # define RESET_C_STACK \
16 _asm \ 29 _asm \
17 LFSR 1, 0x800 \ 30 LFSR 1, 0x800 \
18 LFSR 2, 0x800 \ 31 LFSR 2, 0x800 \
19 _endasm 32 _endasm
20 # pragma udata overlay bank9_compass 33 # pragma udata overlay bank9_compass
21 #else 34 #else
22 # define RESET_C_STACK 35 # define RESET_C_STACK
23 #endif 36 #endif
24 37
25 ////////////////////////////////////////////////////////////////////////////// 38 //////////////////////////////////////////////////////////////////////////////
26 39
27 static unsigned short int compass_N; 40 static unsigned short int compass_N;
28 41
29 static float Su, Sv, Sw; // first order moments 42 static float Su, Sv, Sw; // first order moments
30 static float Suu, Svv, Sww, Suv, Suw, Svw; // second order moments 43 static float Suu, Svv, Sww, Suv, Suw, Svw; // second order moments
31 static float Saa; // Suu + Svv + Sww 44 static float Saa; // Suu + Svv + Sww
32 static float Saau; // Suuu + Svvu + Swwu // third order moment 45 static float Saau; // Suuu + Svvu + Swwu third order moment
33 static float Saav; // Suuv + Svvv + Swwv 46 static float Saav; // Suuv + Svvv + Swwv third order moment
34 static float Saaw; // Suuw + Svvw + Swww 47 static float Saaw; // Suuw + Svvw + Swww third order moment
35 static float yu, yv, yw; // temp solution vector 48
36 static float uc, vc, wc; // temp sphere's center 49 static float yu, yv, yw; // temp solution vector
37 50 static float uc, vc, wc; // temp sphere's center
38 ////////////////////////////////////////////////////////////////////////////// 51
39 52 static float yh, uh, S0, S1, S2, S3; // transfer vars for compass_solve_helper()
40 void compass_reset_calibration() 53 static float discriminant, delta; // transfer vars for calc_discriminant()
54
55
56 //////////////////////////////////////////////////////////////////////////////
57
58 #ifndef UNIX
59 # pragma code compass_calib
60 #endif
61
62 //////////////////////////////////////////////////////////////////////////////
63
64 void compass_reset_calibration() // 202 byte
41 { 65 {
42 RESET_C_STACK; 66 RESET_C_STACK;
43 67
44 compass_N = 0; 68 compass_N = 0;
45 Su = Sv = Sw = 0.0; 69 Su = Sv = Sw = 0.0;
46 Suu = Svv = Sww = 0.0; 70 Suu = Svv = Sww = 0.0;
47 Suv = Suw = Svw = 0.0; 71 Suv = Suw = Svw = 0.0;
48 Saau = Saav = Saaw = 0.0; 72 Saau = Saav = Saaw = 0.0;
49 compass_CX_f = compass_CY_f = compass_CZ_f = 0; 73 compass_CX_f = compass_CY_f = compass_CZ_f = 0; // int16
50 } 74 }
51 75
52 ////////////////////////////////////////////////////////////////////////////// 76 //////////////////////////////////////////////////////////////////////////////
53 77
54 void compass_add_calibration() 78 void compass_add_calibration() // 1488 byte
55 { 79 {
80 overlay float SQR_yu, SQR_yv, SQR_yw; // squared values;
81
56 RESET_C_STACK; 82 RESET_C_STACK;
57 83
58 // get filtered/calibrated magnetic direction 84 // get filtered/calibrated magnetic direction // 276 byte
59 yu = (compass_DX_f - compass_CX_f) / 32768.0f; 85 yu = (compass_DX_f - compass_CX_f) / 32768.0f;
60 yv = (compass_DY_f - compass_CY_f) / 32768.0f; 86 yv = (compass_DY_f - compass_CY_f) / 32768.0f;
61 yw = (compass_DZ_f - compass_CZ_f) / 32768.0f; 87 yw = (compass_DZ_f - compass_CZ_f) / 32768.0f;
62 88
63 // add to all moments 89 // compute squared values // 156 byte
90 SQR_yu = yu*yu;
91 SQR_yv = yv*yv;
92 SQR_yw = yw*yw;
93
94 // increment count
64 compass_N++; 95 compass_N++;
65 96
66 Su += yu; 97 // add to all moments // 156 byte
67 Sv += yv; 98 Su += yu;
68 Sw += yw; 99 Sv += yv;
69 100 Sw += yw;
70 Suu += yu*yu; 101
71 Suv += yu*yv; 102 // // 156 byte
72 Suw += yu*yw; 103 Suu += SQR_yu;
73 Svv += yv*yv; 104 Svv += SQR_yv;
74 Svw += yv*yw; 105 Sww += SQR_yw;
75 Sww += yw*yw; 106
76 107 // // 312 byte
77 Saa = yu*yu + yv*yv + yw*yw; 108 Suv += yu*yv;
109 Suw += yu*yw;
110 Svw += yv*yw;
111
112 // // 104 byte
113 Saa = SQR_yu + SQR_yv + SQR_yw;
114
115
116 // // 312 byte
78 Saau += yu * Saa; 117 Saau += yu * Saa;
79 Saav += yv * Saa; 118 Saav += yv * Saa;
80 Saaw += yw * Saa; 119 Saaw += yw * Saa;
81 } 120 }
82 121
83 ////////////////////////////////////////////////////////////////////////////// 122 //////////////////////////////////////////////////////////////////////////////
84 123
85 static float compass_discriminent(PARAMETER char column) 124 static void calc_discriminant(PARAMETER char column)
86 { 125 {
87 // basic symmetric matrix 126 // basic symmetric matrix
88 OVERLAY float a = Suu, d = Suv, g = Suw; 127 overlay float a = Suu, d = Suv, g = Suw;
89 OVERLAY float b = Suv, e = Svv, h = Svw; 128 overlay float b = Suv, e = Svv, h = Svw;
90 OVERLAY float c = Suw, f = Svw, i = Sww; 129 overlay float c = Suw, f = Svw, i = Sww;
91 130
92 // substitute a column, if asked to 131 // substitute a column, if asked to
93 if( column==1 ) { a = yu; b = yv; c = yw; } 132 if( column==1 ) { a = yu; b = yv; c = yw; }
94 if( column==2 ) { d = yu; e = yv; f = yw; } 133 if( column==2 ) { d = yu; e = yv; f = yw; }
95 if( column==3 ) { g = yu; h = yv; i = yw; } 134 if( column==3 ) { g = yu; h = yv; i = yw; }
96 135
97 // do the math 136 // do the math in a couple of single terms to reduce
98 return a * (e * i - f * h) 137 // the amount of required ".tmpdata" memory
99 - b * (d * i - f * g) 138 discriminant = a * (e * i - f * h);
100 + c * (d * h - e * g); 139 discriminant -= b * (d * i - f * g);
101 } 140 discriminant += c * (d * h - e * g);
102 141
103 ////////////////////////////////////////////////////////////////////////////// 142 // apply delta if column = 1/2/3
104 143 if( column ) discriminant *= delta;
105 static float compass_dotc(PARAMETER float u, float v, float w) 144 }
106 { 145
107 return u*uc + v*vc + w*wc; 146 //////////////////////////////////////////////////////////////////////////////
108 } 147
109 148 static void compass_solve_helper(void) // 338 byte
110 ////////////////////////////////////////////////////////////////////////////// 149 {
111 150 // computes:
112 void compass_solve_calibration() 151 //
113 { 152 // yh = S0 - Saa*uh - compass_dotc(Su*uh + 2*S1, Sv*uh + 2*S2, Sw*uh + 2*S3);
114 OVERLAY float delta; 153 //
154 // with compass_dotc(u,v,w) = u*uc + v*vc + w*wc the equation becomes:
155 //
156 // yh = S0 - Saa*uh - ( (Su*uh + 2*S1)*uc + (Sv*uh + 2*S2)*vc + (Sw*uh + 2*S3)*wc )
157 //
158 // this equation is now split into several single terms
159 // to reduce the amount of required ".tmpdata" memory:
160
161 yh = S0;
162 yh -= Saa*uh;
163 yh -= (Su*uh + 2*S1) * uc;
164 yh -= (Sv*uh + 2*S2) * vc;
165 yh -= (Sw*uh + 2*S3) * wc;
166 }
167
168 //////////////////////////////////////////////////////////////////////////////
169
170 void compass_solve_calibration() // 1738 byte
171 {
172 overlay float inv_compass_N;
173
115 RESET_C_STACK; 174 RESET_C_STACK;
116 175
117 //---- Compute center of measured magnetic directions -------------------- 176 // compute center of measured magnetic directions // 200 byte
118 uc = Su/compass_N; 177 inv_compass_N = 1 / compass_N;
119 vc = Sv/compass_N; 178 uc = Su * inv_compass_N;
120 wc = Sw/compass_N; 179 vc = Sv * inv_compass_N;
121 180 wc = Sw * inv_compass_N;
122 //---- Normalize partial sums -------------------------------------------- 181
182 // normalize partial sums
123 // 183 //
124 // We measured the (u, v, w) values, and need the centered (x, y, z) ones 184 // We measured the (u, v, w) values, and need the centered (x, y, z) ones
125 // around the sphere center's (uc, vc, wc) as: 185 // around the sphere center's (uc, vc, wc) as:
126 // uc = Su / N; The mean value 186 // uc = Su / N; The mean value
127 // x = u - uc; The differnce to the mean. 187 // x = u - uc; The difference to the mean.
128 // 188 //
129 // So: 189 // So:
130 // x**2 = (u - uc)**2 = u**2 - 2u*uc + uc**2 190 // x**2 = (u - uc)**2 = u**2 - 2u*uc + uc**2
131 // 191 //
132 // We need the Sxx sum of 2nd orders: 192 // We need the Sxx sum of 2nd orders:
156 // Sxxy = Suuv + vm Suu + 2 um Suv + N um**2 vm 216 // Sxxy = Suuv + vm Suu + 2 um Suv + N um**2 vm
157 // 217 //
158 // Suuv = Sxxy - (Sy/N) Suu - 2 (Sx/N) Suv - (Sx/N)**2 Sy 218 // Suuv = Sxxy - (Sy/N) Suu - 2 (Sx/N) Suv - (Sx/N)**2 Sy
159 // = Sxxy - Suu*Sy/N - 2 Suv*Sx/N - Sx*Sx*Sy/N/N 219 // = Sxxy - Suu*Sy/N - 2 Suv*Sx/N - Sx*Sx*Sy/N/N
160 // = Sxxy - (Suu + Sx*Sx/N)*Sy/N - 2 Suv*Sx/N 220 // = Sxxy - (Suu + Sx*Sx/N)*Sy/N - 2 Suv*Sx/N
221
161 Saa = Suu + Svv + Sww; 222 Saa = Suu + Svv + Sww;
162 yu = Saau - Saa*uc - compass_dotc(Su*uc + 2*Suu, Sv*uc + 2*Suv, Sw*uc + 2*Suw); 223
163 yv = Saav - Saa*vc - compass_dotc(Su*vc + 2*Suv, Sv*vc + 2*Svv, Sw*vc + 2*Svw); 224 // compute yu = Saau - Saa*uc - compass_dotc(Su*uc + 2*Suu, Sv*uc + 2*Suv, Sw*uc + 2*Suw);
164 yw = Saaw - Saa*wc - compass_dotc(Su*wc + 2*Suw, Sv*wc + 2*Svw, Sw*wc + 2*Sww); 225 //
226 uh = uc; S0 = Saau; S1 = Suu; S2 = Suv; S3 = Suw; compass_solve_helper(); yu = yh;
227
228 // compute yv = Saav - Saa*vc - compass_dotc(Su*vc + 2*Suv, Sv*vc + 2*Svv, Sw*vc + 2*Svw);
229 //
230 uh = vc; S0 = Saav; S1 = Suv; S2 = Svv; S3 = Svw; compass_solve_helper(); yv = yh;
231
232 // compute yw = Saaw - Saa*wc - compass_dotc(Su*wc + 2*Suw, Sv*wc + 2*Svw, Sw*wc + 2*Sww);
233 //
234 uh = wc; S0 = Saaw; S1 = Suw; S2 = Svw; S3 = Sww; compass_solve_helper(); yw = yh;
235
165 236
166 //---- Solve the system -------------------------------------------------- 237 //---- Solve the system --------------------------------------------------
167 // uc Suu + vc Suv + wc Suw = (Suuu + Svvu + Swwu) / 2 238 // uc Suu + vc Suv + wc Suw = (Suuu + Svvu + Swwu) / 2
168 // uc Suv + vc Svv + wc Svw = (Suuv + Svvv + Swwv) / 2 239 // uc Suv + vc Svv + wc Svw = (Suuv + Svvv + Swwv) / 2
169 // uc Suw + vc Svw + wc Sww = (Suuw + Svvw + Swww) / 2 240 // uc Suw + vc Svw + wc Sww = (Suuw + Svvw + Swww) / 2
170 // Note this is symmetric, with a positive diagonal, hence 241 //
171 // discriminant is always not null. 242 // Note this is symmetric, with a positive diagonal, hence discriminant is always not null
172 delta = 0.5f / compass_discriminent(0); 243
173 244 //compute delta value
174 // so computed new center, with offset values: 245 calc_discriminant(0); delta = 0.5f / discriminant;
175 uc += compass_discriminent(1) * delta; 246
176 vc += compass_discriminent(2) * delta; 247 // compute new center, with offset values
177 wc += compass_discriminent(3) * delta; 248 calc_discriminant(1); uc += discriminant;
178 249 calc_discriminant(2); vc += discriminant;
179 // add correction due to already applied calibration: 250 calc_discriminant(3); wc += discriminant;
251
252 // add correction due to already applied calibration
180 compass_CX_f += (short)(32768 * uc); 253 compass_CX_f += (short)(32768 * uc);
181 compass_CY_f += (short)(32768 * vc); 254 compass_CY_f += (short)(32768 * vc);
182 compass_CZ_f += (short)(32768 * wc); 255 compass_CZ_f += (short)(32768 * wc);
183 } 256 }
257
258 #endif // _compass