dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
insgps14state.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  */
31 
32 #include "insgps.h"
33 #include "physical_constants.h"
34 #include <math.h>
35 #include <stdint.h>
36 
37 // constants/macros/typdefs
38 #define NUMX 14 // number of states, X is the state vector
39 #define NUMW 10 // number of plant noise inputs, w is disturbance noise vector
40 #define NUMV 10 // number of measurements, v is the measurement noise vector
41 #define NUMU 6 // number of deterministic inputs, U is the input vector
42 
43 #if defined(GENERAL_COV)
44 // This might trick people so I have a note here. There is a slower but bigger version of the
45 // code here but won't fit when debugging disabled (requires -Os)
46 #define COVARIANCE_PREDICTION_GENERAL
47 #endif
48 
49 // Private functions
50 void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW],
51  float Q[NUMW], float dT, float P[NUMX][NUMX]);
52 void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV],
53  float Y[NUMV], float P[NUMX][NUMX], float X[NUMX],
54  uint16_t SensorsUsed);
55 void RungeKutta(float X[NUMX], float U[NUMU], float dT);
56 void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]);
57 void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX],
58  float G[NUMX][NUMW]);
59 void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]);
60 void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]);
61 
62 // Private variables
63 float F[NUMX][NUMX], G[NUMX][NUMW], H[NUMV][NUMX]; // linearized system matrices
64  // global to init to zero and maintain zero elements
65 float Be[3]; // local magnetic unit vector in NED frame
66 float P[NUMX][NUMX], X[NUMX]; // covariance matrix and state vector
67 float Q[NUMW], R[NUMV]; // input noise and measurement noise variances
68 float K[NUMX][NUMV]; // feedback gain matrix
69 
70 // ************* Exposed Functions ****************
71 // *************************************************
72 
73 uint16_t ins_get_num_states()
74 {
75  return NUMX;
76 }
77 
78 void INSGPSInit() //pretty much just a place holder for now
79 {
80  Be[0] = 1.0f;
81  Be[1] = 0;
82  Be[2] = 0; // local magnetic unit vector
83 
84  for (int i = 0; i < NUMX; i++) {
85  for (int j = 0; j < NUMX; j++) {
86  P[i][j] = 0.0f; // zero all terms
87  F[i][j] = 0.0f;
88  }
89  for (int j = 0; j < NUMW; j++)
90  G[i][j] = 0.0f;
91 
92  for (int j = 0; j < NUMV; j++) {
93  H[j][i] = 0.0f;
94  K[i][j] = 0.0f;
95  }
96 
97  X[i] = 0.0f;
98  }
99  for (int i = 0; i < NUMW; i++)
100  Q[i] = 0.0f;
101  for (int i = 0; i < NUMV; i++)
102  R[i] = 0.0f;
103 
104  P[0][0] = P[1][1] = P[2][2] = 25.0f; // initial position variance (m^2)
105  P[3][3] = P[4][4] = P[5][5] = 5.0f; // initial velocity variance (m/s)^2
106  P[6][6] = P[7][7] = P[8][8] = P[9][9] = 1e-5f; // initial quaternion variance
107  P[10][10] = P[11][11] = P[12][12] = 1e-6f; // initial gyro bias variance (rad/s)^2
108  P[13][13] = 1e-5f; // initial accel bias variance (deg/s)^2
109 
110  X[0] = X[1] = X[2] = X[3] = X[4] = X[5] = 0.0f; // initial pos and vel (m)
111  X[6] = 1.0f;
112  X[7] = X[8] = X[9] = 0.0f; // initial quaternion (level and North) (m/s)
113  X[10] = X[11] = X[12] = 0.0f; // initial gyro bias (rad/s)
114  X[13] = 0.0f; // initial accel bias
115 
116  Q[0] = Q[1] = Q[2] = 1e-5f; // gyro noise variance (rad/s)^2
117  Q[3] = Q[4] = Q[5] = 1e-5f; // accelerometer noise variance (m/s^2)^2
118  Q[6] = Q[7] = 1e-6f; // gyro x and y bias random walk variance (rad/s^2)^2
119  Q[8] = 1e-6f; // gyro z bias random walk variance (rad/s^2)^2
120  Q[9] = 5e-4f; // accel bias random walk variance (m/s^3)^2
121 
122  R[0] = R[1] = 0.004f; // High freq GPS horizontal position noise variance (m^2)
123  R[2] = 0.036f; // High freq GPS vertical position noise variance (m^2)
124  R[3] = R[4] = 0.004f; // High freq GPS horizontal velocity noise variance (m/s)^2
125  R[5] = 0.004f; // High freq GPS vertical velocity noise variance (m/s)^2
126  R[6] = R[7] = R[8] = 0.005f; // magnetometer unit vector noise variance
127  R[9] = .05f; // High freq altimeter noise variance (m^2)
128 }
129 
131 void INSSetArmed(bool armed)
132 {
133  return;
134  // Speed up convergence of accel and gyro bias when not armed
135  if (armed) {
136  Q[9] = 1e-4f;
137  Q[8] = 2e-9f;
138  } else {
139  Q[9] = 1e-2f;
140  Q[8] = 2e-8f;
141  }
142 }
143 
152 void INSGetState(float *pos, float *vel, float *attitude, float *gyro_bias, float *accel_bias)
153 {
154  if (pos) {
155  pos[0] = X[0];
156  pos[1] = X[1];
157  pos[2] = X[2];
158  }
159 
160  if (vel) {
161  vel[0] = X[3];
162  vel[1] = X[4];
163  vel[2] = X[5];
164  }
165 
166  if (attitude) {
167  attitude[0] = X[6];
168  attitude[1] = X[7];
169  attitude[2] = X[8];
170  attitude[3] = X[9];
171  }
172 
173  if (gyro_bias) {
174  gyro_bias[0] = X[10];
175  gyro_bias[1] = X[11];
176  gyro_bias[2] = X[12];
177  }
178 
179  if (accel_bias) {
180  accel_bias[0] = 0.0f;
181  accel_bias[1] = 0.0f;
182  accel_bias[2] = X[13];
183  }
184 }
185 
190 void INSGetVariance(float *var_out)
191  {
192  for (uint32_t i = 0; i < NUMX; i++)
193  var_out[i] = P[i][i];
194  }
195 
196 void INSResetP(const float *PDiag)
197 {
198  uint8_t i,j;
199 
200  // if PDiag[i] nonzero then clear row and column and set diagonal element
201  for (i=0;i<NUMX;i++){
202  if (PDiag != 0){
203  for (j=0;j<NUMX;j++)
204  P[i][j]=P[j][i]=0.0f;
205  P[i][i]=PDiag[i];
206  }
207  }
208 }
209 
210 void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], const float accel_bias[3])
211 {
212  X[0] = pos[0];
213  X[1] = pos[1];
214  X[2] = pos[2];
215  X[3] = vel[0];
216  X[4] = vel[1];
217  X[5] = vel[2];
218  X[6] = q[0];
219  X[7] = q[1];
220  X[8] = q[2];
221  X[9] = q[3];
222  X[10] = gyro_bias[0];
223  X[11] = gyro_bias[1];
224  X[12] = gyro_bias[2];
225  X[13] = accel_bias[2];
226 }
227 
228 void INSPosVelReset(const float pos[3], const float vel[3])
229 {
230  for (int i = 0; i < 6; i++) {
231  for(int j = i; j < NUMX; j++) {
232  P[i][j] = 0.0f; // zero the first 6 rows and columns
233  P[j][i] = 0.0f;
234  }
235  }
236 
237  P[0][0] = P[1][1] = P[2][2] = 25.0f; // initial position variance (m^2)
238  P[3][3] = P[4][4] = P[5][5] = 5.0f; // initial velocity variance (m/s)^2
239 
240  X[0] = pos[0];
241  X[1] = pos[1];
242  X[2] = pos[2];
243  X[3] = vel[0];
244  X[4] = vel[1];
245  X[5] = vel[2];
246 }
247 
248 void INSSetPosVelVar(float PosVar, float VelVar, float VertPosVar)
249 {
250  R[0] = PosVar;
251  R[1] = PosVar;
252  R[2] = VertPosVar;
253  R[3] = VelVar;
254  R[4] = VelVar;
255  R[5] = VelVar; // Don't change vertical velocity, not measured
256 }
257 
258 void INSSetGyroBias(const float gyro_bias[3])
259 {
260  X[10] = gyro_bias[0];
261  X[11] = gyro_bias[1];
262  X[12] = gyro_bias[2];
263 }
264 
265 void INSSetAccelBias(const float accel_bias[3])
266 {
267  X[13] = accel_bias[2];
268 }
269 
270 void INSSetAccelVar(const float accel_var[3])
271 {
272  Q[3] = accel_var[0];
273  Q[4] = accel_var[1];
274  Q[5] = accel_var[2];
275 }
276 
277 void INSSetGyroVar(const float gyro_var[3])
278 {
279  Q[0] = gyro_var[0];
280  Q[1] = gyro_var[1];
281  Q[2] = gyro_var[2];
282 }
283 
284 void INSSetMagVar(const float scaled_mag_var[3])
285 {
286  R[6] = scaled_mag_var[0];
287  R[7] = scaled_mag_var[1];
288  R[8] = scaled_mag_var[2];
289 }
290 
291 void INSSetBaroVar(const float baro_var)
292 {
293  R[9] = baro_var;
294 }
295 
296 void INSSetMagNorth(const float B[3])
297 {
298  Be[0] = B[0];
299  Be[1] = B[1];
300  Be[2] = B[2];
301 }
302 
304 {
305  // The Z accel bias should never wander too much. This helps ensure the filter
306  // remains stable.
307  if (X[13] > 0.1f) {
308  X[13] = 0.1f;
309  } else if (X[13] < -0.1f) {
310  X[13] = -0.1f;
311  }
312 
313  // Make sure no gyro bias gets to more than 10 deg / s. This should be more than
314  // enough for well behaving sensors.
315  const float GYRO_BIAS_LIMIT = 10 * DEG2RAD;
316  for (int i = 10; i < 13; i++) {
317  if (X[i] < -GYRO_BIAS_LIMIT)
318  X[i] = -GYRO_BIAS_LIMIT;
319  else if (X[i] > GYRO_BIAS_LIMIT)
320  X[i] = GYRO_BIAS_LIMIT;
321  }
322 }
323 
324 void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT)
325 {
326  float U[6];
327  float qmag;
328 
329  // rate gyro inputs in units of rad/s
330  U[0] = gyro_data[0];
331  U[1] = gyro_data[1];
332  U[2] = gyro_data[2];
333 
334  // accelerometer inputs in units of m/s
335  U[3] = accel_data[0];
336  U[4] = accel_data[1];
337  U[5] = accel_data[2];
338 
339  // EKF prediction step
340  LinearizeFG(X, U, F, G);
341  RungeKutta(X, U, dT);
342  qmag = sqrtf(X[6] * X[6] + X[7] * X[7] + X[8] * X[8] + X[9] * X[9]);
343  X[6] /= qmag;
344  X[7] /= qmag;
345  X[8] /= qmag;
346  X[9] /= qmag;
347 }
348 
350 {
351  CovariancePrediction(F, G, Q, dT, P);
352 }
353 
354 void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3],
355  float BaroAlt, uint16_t SensorsUsed)
356 {
357  float Z[10], Y[10];
358  float qmag;
359 
360  // GPS Position in meters and in local NED frame
361  Z[0] = Pos[0];
362  Z[1] = Pos[1];
363  Z[2] = Pos[2];
364 
365  // GPS Velocity in meters and in local NED frame
366  Z[3] = Vel[0];
367  Z[4] = Vel[1];
368  Z[5] = Vel[2];
369 
370  if (SensorsUsed & MAG_SENSORS) {
371  // magnetometer data in any units (use unit vector) and in body frame
372  float Rbe_a[3][3];
373  float q0 = X[6];
374  float q1 = X[7];
375  float q2 = X[8];
376  float q3 = X[9];
377  float k1 = 1.0f/sqrtf(powf(q0*q1*2.0f+q2*q3*2.0f,2.0f)+powf(q0*q0-q1*q1-q2*q2+q3*q3,2.0f));
378  float k2 = sqrtf(-powf(q0*q2*2.0f-q1*q3*2.0f,2.0f)+1.0f);
379 
380  Rbe_a[0][0] = k2;
381  Rbe_a[0][1] = 0.0f;
382  Rbe_a[0][2] = q0*q2*-2.0f+q1*q3*2.0f;
383  Rbe_a[1][0] = k1*(q0*q1*2.0f+q2*q3*2.0f)*(q0*q2*2.0f-q1*q3*2.0f);
384  Rbe_a[1][1] = k1*(q0*q0-q1*q1-q2*q2+q3*q3);
385  Rbe_a[1][2] = k1*sqrtf(-powf(q0*q2*2.0f-q1*q3*2.0f,2.0f)+1.0f)*(q0*q1*2.0f+q2*q3*2.0f);
386  Rbe_a[2][0] = k1*(q0*q2*2.0f-q1*q3*2.0f)*(q0*q0-q1*q1-q2*q2+q3*q3);
387  Rbe_a[2][1] = -k1*(q0*q1*2.0f+q2*q3*2.0f);
388  Rbe_a[2][2] = k1*k2*(q0*q0-q1*q1-q2*q2+q3*q3);
389 
390  Z[6] = Rbe_a[0][0]*mag_data[0] + Rbe_a[1][0]*mag_data[1] + Rbe_a[2][0]*mag_data[2] ;
391  Z[7] = Rbe_a[0][1]*mag_data[0] + Rbe_a[1][1]*mag_data[1] + Rbe_a[2][1]*mag_data[2] ;
392  Z[8] = Rbe_a[0][2]*mag_data[0] + Rbe_a[1][2]*mag_data[1] + Rbe_a[2][2]*mag_data[2] ;
393  }
394 
395  // barometric altimeter in meters and in local NED frame
396  Z[9] = BaroAlt;
397 
398  // EKF correction step
399  LinearizeH(X, Be, H);
400  MeasurementEq(X, Be, Y);
401  SerialUpdate(H, R, Z, Y, P, X, SensorsUsed);
402  qmag = sqrtf(X[6] * X[6] + X[7] * X[7] + X[8] * X[8] + X[9] * X[9]);
403  X[6] /= qmag;
404  X[7] /= qmag;
405  X[8] /= qmag;
406  X[9] /= qmag;
407 
408  INSLimitBias();
409 }
410 
411 // ************* CovariancePrediction *************
412 // Does the prediction step of the Kalman filter for the covariance matrix
413 // Output, Pnew, overwrites P, the input covariance
414 // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G'
415 // Q is the discrete time covariance of process noise
416 // Q is vector of the diagonal for a square matrix with
417 // dimensions equal to the number of disturbance noise variables
418 // The General Method is very inefficient,not taking advantage of the sparse F and G
419 // The first Method is very specific to this implementation
420 // ************************************************
421 
422 #ifdef COVARIANCE_PREDICTION_GENERAL
423 
424 void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW],
425  float Q[NUMW], float dT, float P[NUMX][NUMX])
426 {
427  float Dummy[NUMX][NUMX], dTsq;
428  uint8_t i, j, k;
429 
430  // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = T^2[(P/T + F*P)*(I/T + F') + G*Q*G')]
431 
432  dTsq = dT * dT;
433 
434  for (i = 0; i < NUMX; i++) // Calculate Dummy = (P/T +F*P)
435  for (j = 0; j < NUMX; j++) {
436  Dummy[i][j] = P[i][j] / dT;
437  for (k = 0; k < NUMX; k++)
438  Dummy[i][j] += F[i][k] * P[k][j];
439  }
440  for (i = 0; i < NUMX; i++) // Calculate Pnew = Dummy/T + Dummy*F' + G*Qw*G'
441  for (j = i; j < NUMX; j++) { // Use symmetry, ie only find upper triangular
442  P[i][j] = Dummy[i][j] / dT;
443  for (k = 0; k < NUMX; k++)
444  P[i][j] += Dummy[i][k] * F[j][k]; // P = Dummy/T + Dummy*F'
445  for (k = 0; k < NUMW; k++)
446  P[i][j] += Q[k] * G[i][k] * G[j][k]; // P = Dummy/T + Dummy*F' + G*Q*G'
447  P[j][i] = P[i][j] = P[i][j] * dTsq; // Pnew = T^2*P and fill in lower triangular;
448  }
449 }
450 
451 #else
452 
453 void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW],
454  float Q[NUMW], float dT, float P[NUMX][NUMX])
455 {
456  float D[NUMX][NUMX], T, Tsq;
457  uint8_t i, j;
458 
459  // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = scalar expansion from symbolic manipulator
460 
461  T = dT;
462  Tsq = dT * dT;
463 
464  for (i = 0; i < NUMX; i++) // Create a copy of the upper triangular of P
465  for (j = i; j < NUMX; j++)
466  D[i][j] = P[i][j];
467 
468  // Brute force calculation of the elements of P
469  P[0][0] = D[3][3]*Tsq + (2*D[0][3])*T + D[0][0];
470  P[0][1] = P[1][0] = D[3][4]*Tsq + (D[0][4] + D[1][3])*T + D[0][1];
471  P[0][2] = P[2][0] = D[3][5]*Tsq + (D[0][5] + D[2][3])*T + D[0][2];
472  P[0][3] = P[3][0] = (F[3][6]*D[3][6] + F[3][7]*D[3][7] + F[3][8]*D[3][8] + F[3][9]*D[3][9] + F[3][13]*D[3][13])*Tsq + (D[3][3] + F[3][6]*D[0][6] + F[3][7]*D[0][7] + F[3][8]*D[0][8] + F[3][9]*D[0][9] + F[3][13]*D[0][13])*T + D[0][3];
473  P[0][4] = P[4][0] = (F[4][6]*D[3][6] + F[4][7]*D[3][7] + F[4][8]*D[3][8] + F[4][9]*D[3][9] + F[4][13]*D[3][13])*Tsq + (D[3][4] + F[4][6]*D[0][6] + F[4][7]*D[0][7] + F[4][8]*D[0][8] + F[4][9]*D[0][9] + F[4][13]*D[0][13])*T + D[0][4];
474  P[0][5] = P[5][0] = (F[5][6]*D[3][6] + F[5][7]*D[3][7] + F[5][8]*D[3][8] + F[5][9]*D[3][9] + F[5][13]*D[3][13])*Tsq + (D[3][5] + F[5][6]*D[0][6] + F[5][7]*D[0][7] + F[5][8]*D[0][8] + F[5][9]*D[0][9] + F[5][13]*D[0][13])*T + D[0][5];
475  P[0][6] = P[6][0] = (F[6][7]*D[3][7] + F[6][8]*D[3][8] + F[6][9]*D[3][9] + F[6][10]*D[3][10] + F[6][11]*D[3][11] + F[6][12]*D[3][12])*Tsq + (D[3][6] + F[6][7]*D[0][7] + F[6][8]*D[0][8] + F[6][9]*D[0][9] + F[6][10]*D[0][10] + F[6][11]*D[0][11] + F[6][12]*D[0][12])*T + D[0][6];
476  P[0][7] = P[7][0] = (F[7][6]*D[3][6] + F[7][8]*D[3][8] + F[7][9]*D[3][9] + F[7][10]*D[3][10] + F[7][11]*D[3][11] + F[7][12]*D[3][12])*Tsq + (D[3][7] + F[7][6]*D[0][6] + F[7][8]*D[0][8] + F[7][9]*D[0][9] + F[7][10]*D[0][10] + F[7][11]*D[0][11] + F[7][12]*D[0][12])*T + D[0][7];
477  P[0][8] = P[8][0] = (F[8][6]*D[3][6] + F[8][7]*D[3][7] + F[8][9]*D[3][9] + F[8][10]*D[3][10] + F[8][11]*D[3][11] + F[8][12]*D[3][12])*Tsq + (D[3][8] + F[8][6]*D[0][6] + F[8][7]*D[0][7] + F[8][9]*D[0][9] + F[8][10]*D[0][10] + F[8][11]*D[0][11] + F[8][12]*D[0][12])*T + D[0][8];
478  P[0][9] = P[9][0] = (F[9][6]*D[3][6] + F[9][7]*D[3][7] + F[9][8]*D[3][8] + F[9][10]*D[3][10] + F[9][11]*D[3][11] + F[9][12]*D[3][12])*Tsq + (D[3][9] + F[9][6]*D[0][6] + F[9][7]*D[0][7] + F[9][8]*D[0][8] + F[9][10]*D[0][10] + F[9][11]*D[0][11] + F[9][12]*D[0][12])*T + D[0][9];
479  P[0][10] = P[10][0] = D[3][10]*T + D[0][10];
480  P[0][11] = P[11][0] = D[3][11]*T + D[0][11];
481  P[0][12] = P[12][0] = D[3][12]*T + D[0][12];
482  P[0][13] = P[13][0] = D[3][13]*T + D[0][13];
483  P[1][1] = D[4][4]*Tsq + (2*D[1][4])*T + D[1][1];
484  P[1][2] = P[2][1] = D[4][5]*Tsq + (D[1][5] + D[2][4])*T + D[1][2];
485  P[1][3] = P[3][1] = (F[3][6]*D[4][6] + F[3][7]*D[4][7] + F[3][8]*D[4][8] + F[3][9]*D[4][9] + F[3][13]*D[4][13])*Tsq + (D[3][4] + F[3][6]*D[1][6] + F[3][7]*D[1][7] + F[3][8]*D[1][8] + F[3][9]*D[1][9] + F[3][13]*D[1][13])*T + D[1][3];
486  P[1][4] = P[4][1] = (F[4][6]*D[4][6] + F[4][7]*D[4][7] + F[4][8]*D[4][8] + F[4][9]*D[4][9] + F[4][13]*D[4][13])*Tsq + (D[4][4] + F[4][6]*D[1][6] + F[4][7]*D[1][7] + F[4][8]*D[1][8] + F[4][9]*D[1][9] + F[4][13]*D[1][13])*T + D[1][4];
487  P[1][5] = P[5][1] = (F[5][6]*D[4][6] + F[5][7]*D[4][7] + F[5][8]*D[4][8] + F[5][9]*D[4][9] + F[5][13]*D[4][13])*Tsq + (D[4][5] + F[5][6]*D[1][6] + F[5][7]*D[1][7] + F[5][8]*D[1][8] + F[5][9]*D[1][9] + F[5][13]*D[1][13])*T + D[1][5];
488  P[1][6] = P[6][1] = (F[6][7]*D[4][7] + F[6][8]*D[4][8] + F[6][9]*D[4][9] + F[6][10]*D[4][10] + F[6][11]*D[4][11] + F[6][12]*D[4][12])*Tsq + (D[4][6] + F[6][7]*D[1][7] + F[6][8]*D[1][8] + F[6][9]*D[1][9] + F[6][10]*D[1][10] + F[6][11]*D[1][11] + F[6][12]*D[1][12])*T + D[1][6];
489  P[1][7] = P[7][1] = (F[7][6]*D[4][6] + F[7][8]*D[4][8] + F[7][9]*D[4][9] + F[7][10]*D[4][10] + F[7][11]*D[4][11] + F[7][12]*D[4][12])*Tsq + (D[4][7] + F[7][6]*D[1][6] + F[7][8]*D[1][8] + F[7][9]*D[1][9] + F[7][10]*D[1][10] + F[7][11]*D[1][11] + F[7][12]*D[1][12])*T + D[1][7];
490  P[1][8] = P[8][1] = (F[8][6]*D[4][6] + F[8][7]*D[4][7] + F[8][9]*D[4][9] + F[8][10]*D[4][10] + F[8][11]*D[4][11] + F[8][12]*D[4][12])*Tsq + (D[4][8] + F[8][6]*D[1][6] + F[8][7]*D[1][7] + F[8][9]*D[1][9] + F[8][10]*D[1][10] + F[8][11]*D[1][11] + F[8][12]*D[1][12])*T + D[1][8];
491  P[1][9] = P[9][1] = (F[9][6]*D[4][6] + F[9][7]*D[4][7] + F[9][8]*D[4][8] + F[9][10]*D[4][10] + F[9][11]*D[4][11] + F[9][12]*D[4][12])*Tsq + (D[4][9] + F[9][6]*D[1][6] + F[9][7]*D[1][7] + F[9][8]*D[1][8] + F[9][10]*D[1][10] + F[9][11]*D[1][11] + F[9][12]*D[1][12])*T + D[1][9];
492  P[1][10] = P[10][1] = D[4][10]*T + D[1][10];
493  P[1][11] = P[11][1] = D[4][11]*T + D[1][11];
494  P[1][12] = P[12][1] = D[4][12]*T + D[1][12];
495  P[1][13] = P[13][1] = D[4][13]*T + D[1][13];
496  P[2][2] = D[5][5]*Tsq + (2*D[2][5])*T + D[2][2];
497  P[2][3] = P[3][2] = (F[3][6]*D[5][6] + F[3][7]*D[5][7] + F[3][8]*D[5][8] + F[3][9]*D[5][9] + F[3][13]*D[5][13])*Tsq + (D[3][5] + F[3][6]*D[2][6] + F[3][7]*D[2][7] + F[3][8]*D[2][8] + F[3][9]*D[2][9] + F[3][13]*D[2][13])*T + D[2][3];
498  P[2][4] = P[4][2] = (F[4][6]*D[5][6] + F[4][7]*D[5][7] + F[4][8]*D[5][8] + F[4][9]*D[5][9] + F[4][13]*D[5][13])*Tsq + (D[4][5] + F[4][6]*D[2][6] + F[4][7]*D[2][7] + F[4][8]*D[2][8] + F[4][9]*D[2][9] + F[4][13]*D[2][13])*T + D[2][4];
499  P[2][5] = P[5][2] = (F[5][6]*D[5][6] + F[5][7]*D[5][7] + F[5][8]*D[5][8] + F[5][9]*D[5][9] + F[5][13]*D[5][13])*Tsq + (D[5][5] + F[5][6]*D[2][6] + F[5][7]*D[2][7] + F[5][8]*D[2][8] + F[5][9]*D[2][9] + F[5][13]*D[2][13])*T + D[2][5];
500  P[2][6] = P[6][2] = (F[6][7]*D[5][7] + F[6][8]*D[5][8] + F[6][9]*D[5][9] + F[6][10]*D[5][10] + F[6][11]*D[5][11] + F[6][12]*D[5][12])*Tsq + (D[5][6] + F[6][7]*D[2][7] + F[6][8]*D[2][8] + F[6][9]*D[2][9] + F[6][10]*D[2][10] + F[6][11]*D[2][11] + F[6][12]*D[2][12])*T + D[2][6];
501  P[2][7] = P[7][2] = (F[7][6]*D[5][6] + F[7][8]*D[5][8] + F[7][9]*D[5][9] + F[7][10]*D[5][10] + F[7][11]*D[5][11] + F[7][12]*D[5][12])*Tsq + (D[5][7] + F[7][6]*D[2][6] + F[7][8]*D[2][8] + F[7][9]*D[2][9] + F[7][10]*D[2][10] + F[7][11]*D[2][11] + F[7][12]*D[2][12])*T + D[2][7];
502  P[2][8] = P[8][2] = (F[8][6]*D[5][6] + F[8][7]*D[5][7] + F[8][9]*D[5][9] + F[8][10]*D[5][10] + F[8][11]*D[5][11] + F[8][12]*D[5][12])*Tsq + (D[5][8] + F[8][6]*D[2][6] + F[8][7]*D[2][7] + F[8][9]*D[2][9] + F[8][10]*D[2][10] + F[8][11]*D[2][11] + F[8][12]*D[2][12])*T + D[2][8];
503  P[2][9] = P[9][2] = (F[9][6]*D[5][6] + F[9][7]*D[5][7] + F[9][8]*D[5][8] + F[9][10]*D[5][10] + F[9][11]*D[5][11] + F[9][12]*D[5][12])*Tsq + (D[5][9] + F[9][6]*D[2][6] + F[9][7]*D[2][7] + F[9][8]*D[2][8] + F[9][10]*D[2][10] + F[9][11]*D[2][11] + F[9][12]*D[2][12])*T + D[2][9];
504  P[2][10] = P[10][2] = D[5][10]*T + D[2][10];
505  P[2][11] = P[11][2] = D[5][11]*T + D[2][11];
506  P[2][12] = P[12][2] = D[5][12]*T + D[2][12];
507  P[2][13] = P[13][2] = D[5][13]*T + D[2][13];
508  P[3][3] = (Q[3]*G[3][3]*G[3][3] + Q[4]*G[3][4]*G[3][4] + Q[5]*G[3][5]*G[3][5] + F[3][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[3][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[3][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[3][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[3][13]*(F[3][6]*D[6][13] + F[3][7]*D[7][13] + F[3][8]*D[8][13] + F[3][9]*D[9][13] + F[3][13]*D[13][13]))*Tsq + (2*F[3][6]*D[3][6] + 2*F[3][7]*D[3][7] + 2*F[3][8]*D[3][8] + 2*F[3][9]*D[3][9] + 2*F[3][13]*D[3][13])*T + D[3][3];
509  P[3][4] = P[4][3] = (F[4][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[4][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[4][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[4][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[4][13]*(F[3][6]*D[6][13] + F[3][7]*D[7][13] + F[3][8]*D[8][13] + F[3][9]*D[9][13] + F[3][13]*D[13][13]) + G[3][3]*G[4][3]*Q[3] + G[3][4]*G[4][4]*Q[4] + G[3][5]*G[4][5]*Q[5])*Tsq + (F[3][6]*D[4][6] + F[4][6]*D[3][6] + F[3][7]*D[4][7] + F[4][7]*D[3][7] + F[3][8]*D[4][8] + F[4][8]*D[3][8] + F[3][9]*D[4][9] + F[4][9]*D[3][9] + F[3][13]*D[4][13] + F[4][13]*D[3][13])*T + D[3][4];
510  P[3][5] = P[5][3] = (F[5][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[5][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[5][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[5][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[5][13]*(F[3][6]*D[6][13] + F[3][7]*D[7][13] + F[3][8]*D[8][13] + F[3][9]*D[9][13] + F[3][13]*D[13][13]) + G[3][3]*G[5][3]*Q[3] + G[3][4]*G[5][4]*Q[4] + G[3][5]*G[5][5]*Q[5])*Tsq + (F[3][6]*D[5][6] + F[5][6]*D[3][6] + F[3][7]*D[5][7] + F[5][7]*D[3][7] + F[3][8]*D[5][8] + F[5][8]*D[3][8] + F[3][9]*D[5][9] + F[5][9]*D[3][9] + F[3][13]*D[5][13] + F[5][13]*D[3][13])*T + D[3][5];
511  P[3][6] = P[6][3] = (F[6][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[6][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[6][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[6][10]*(F[3][6]*D[6][10] + F[3][7]*D[7][10] + F[3][8]*D[8][10] + F[3][9]*D[9][10] + F[3][13]*D[10][13]) + F[6][11]*(F[3][6]*D[6][11] + F[3][7]*D[7][11] + F[3][8]*D[8][11] + F[3][9]*D[9][11] + F[3][13]*D[11][13]) + F[6][12]*(F[3][6]*D[6][12] + F[3][7]*D[7][12] + F[3][8]*D[8][12] + F[3][9]*D[9][12] + F[3][13]*D[12][13]))*Tsq + (F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[6][7]*D[3][7] + F[3][8]*D[6][8] + F[6][8]*D[3][8] + F[3][9]*D[6][9] + F[6][9]*D[3][9] + F[6][10]*D[3][10] + F[6][11]*D[3][11] + F[6][12]*D[3][12] + F[3][13]*D[6][13])*T + D[3][6];
512  P[3][7] = P[7][3] = (F[7][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[7][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[7][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[7][10]*(F[3][6]*D[6][10] + F[3][7]*D[7][10] + F[3][8]*D[8][10] + F[3][9]*D[9][10] + F[3][13]*D[10][13]) + F[7][11]*(F[3][6]*D[6][11] + F[3][7]*D[7][11] + F[3][8]*D[8][11] + F[3][9]*D[9][11] + F[3][13]*D[11][13]) + F[7][12]*(F[3][6]*D[6][12] + F[3][7]*D[7][12] + F[3][8]*D[8][12] + F[3][9]*D[9][12] + F[3][13]*D[12][13]))*Tsq + (F[3][6]*D[6][7] + F[7][6]*D[3][6] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[7][8]*D[3][8] + F[3][9]*D[7][9] + F[7][9]*D[3][9] + F[7][10]*D[3][10] + F[7][11]*D[3][11] + F[7][12]*D[3][12] + F[3][13]*D[7][13])*T + D[3][7];
513  P[3][8] = P[8][3] = (F[8][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[8][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[8][9]*(F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[3][13]*D[9][13]) + F[8][10]*(F[3][6]*D[6][10] + F[3][7]*D[7][10] + F[3][8]*D[8][10] + F[3][9]*D[9][10] + F[3][13]*D[10][13]) + F[8][11]*(F[3][6]*D[6][11] + F[3][7]*D[7][11] + F[3][8]*D[8][11] + F[3][9]*D[9][11] + F[3][13]*D[11][13]) + F[8][12]*(F[3][6]*D[6][12] + F[3][7]*D[7][12] + F[3][8]*D[8][12] + F[3][9]*D[9][12] + F[3][13]*D[12][13]))*Tsq + (F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[8][6]*D[3][6] + F[8][7]*D[3][7] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[8][9]*D[3][9] + F[8][10]*D[3][10] + F[8][11]*D[3][11] + F[8][12]*D[3][12] + F[3][13]*D[8][13])*T + D[3][8];
514  P[3][9] = P[9][3] = (F[9][6]*(F[3][6]*D[6][6] + F[3][7]*D[6][7] + F[3][8]*D[6][8] + F[3][9]*D[6][9] + F[3][13]*D[6][13]) + F[9][7]*(F[3][6]*D[6][7] + F[3][7]*D[7][7] + F[3][8]*D[7][8] + F[3][9]*D[7][9] + F[3][13]*D[7][13]) + F[9][8]*(F[3][6]*D[6][8] + F[3][7]*D[7][8] + F[3][8]*D[8][8] + F[3][9]*D[8][9] + F[3][13]*D[8][13]) + F[9][10]*(F[3][6]*D[6][10] + F[3][7]*D[7][10] + F[3][8]*D[8][10] + F[3][9]*D[9][10] + F[3][13]*D[10][13]) + F[9][11]*(F[3][6]*D[6][11] + F[3][7]*D[7][11] + F[3][8]*D[8][11] + F[3][9]*D[9][11] + F[3][13]*D[11][13]) + F[9][12]*(F[3][6]*D[6][12] + F[3][7]*D[7][12] + F[3][8]*D[8][12] + F[3][9]*D[9][12] + F[3][13]*D[12][13]))*Tsq + (F[9][6]*D[3][6] + F[9][7]*D[3][7] + F[9][8]*D[3][8] + F[3][6]*D[6][9] + F[3][7]*D[7][9] + F[3][8]*D[8][9] + F[3][9]*D[9][9] + F[9][10]*D[3][10] + F[9][11]*D[3][11] + F[9][12]*D[3][12] + F[3][13]*D[9][13])*T + D[3][9];
515  P[3][10] = P[10][3] = (F[3][6]*D[6][10] + F[3][7]*D[7][10] + F[3][8]*D[8][10] + F[3][9]*D[9][10] + F[3][13]*D[10][13])*T + D[3][10];
516  P[3][11] = P[11][3] = (F[3][6]*D[6][11] + F[3][7]*D[7][11] + F[3][8]*D[8][11] + F[3][9]*D[9][11] + F[3][13]*D[11][13])*T + D[3][11];
517  P[3][12] = P[12][3] = (F[3][6]*D[6][12] + F[3][7]*D[7][12] + F[3][8]*D[8][12] + F[3][9]*D[9][12] + F[3][13]*D[12][13])*T + D[3][12];
518  P[3][13] = P[13][3] = (F[3][6]*D[6][13] + F[3][7]*D[7][13] + F[3][8]*D[8][13] + F[3][9]*D[9][13] + F[3][13]*D[13][13])*T + D[3][13];
519  P[4][4] = (Q[3]*G[4][3]*G[4][3] + Q[4]*G[4][4]*G[4][4] + Q[5]*G[4][5]*G[4][5] + F[4][6]*(F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[4][8]*D[6][8] + F[4][9]*D[6][9] + F[4][13]*D[6][13]) + F[4][7]*(F[4][6]*D[6][7] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[4][9]*D[7][9] + F[4][13]*D[7][13]) + F[4][8]*(F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[4][13]*D[8][13]) + F[4][9]*(F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[4][13]*D[9][13]) + F[4][13]*(F[4][6]*D[6][13] + F[4][7]*D[7][13] + F[4][8]*D[8][13] + F[4][9]*D[9][13] + F[4][13]*D[13][13]))*Tsq + (2*F[4][6]*D[4][6] + 2*F[4][7]*D[4][7] + 2*F[4][8]*D[4][8] + 2*F[4][9]*D[4][9] + 2*F[4][13]*D[4][13])*T + D[4][4];
520  P[4][5] = P[5][4] = (F[5][6]*(F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[4][8]*D[6][8] + F[4][9]*D[6][9] + F[4][13]*D[6][13]) + F[5][7]*(F[4][6]*D[6][7] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[4][9]*D[7][9] + F[4][13]*D[7][13]) + F[5][8]*(F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[4][13]*D[8][13]) + F[5][9]*(F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[4][13]*D[9][13]) + F[5][13]*(F[4][6]*D[6][13] + F[4][7]*D[7][13] + F[4][8]*D[8][13] + F[4][9]*D[9][13] + F[4][13]*D[13][13]) + G[4][3]*G[5][3]*Q[3] + G[4][4]*G[5][4]*Q[4] + G[4][5]*G[5][5]*Q[5])*Tsq + (F[4][6]*D[5][6] + F[5][6]*D[4][6] + F[4][7]*D[5][7] + F[5][7]*D[4][7] + F[4][8]*D[5][8] + F[5][8]*D[4][8] + F[4][9]*D[5][9] + F[5][9]*D[4][9] + F[4][13]*D[5][13] + F[5][13]*D[4][13])*T + D[4][5];
521  P[4][6] = P[6][4] = (F[6][7]*(F[4][6]*D[6][7] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[4][9]*D[7][9] + F[4][13]*D[7][13]) + F[6][8]*(F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[4][13]*D[8][13]) + F[6][9]*(F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[4][13]*D[9][13]) + F[6][10]*(F[4][6]*D[6][10] + F[4][7]*D[7][10] + F[4][8]*D[8][10] + F[4][9]*D[9][10] + F[4][13]*D[10][13]) + F[6][11]*(F[4][6]*D[6][11] + F[4][7]*D[7][11] + F[4][8]*D[8][11] + F[4][9]*D[9][11] + F[4][13]*D[11][13]) + F[6][12]*(F[4][6]*D[6][12] + F[4][7]*D[7][12] + F[4][8]*D[8][12] + F[4][9]*D[9][12] + F[4][13]*D[12][13]))*Tsq + (F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[6][7]*D[4][7] + F[4][8]*D[6][8] + F[6][8]*D[4][8] + F[4][9]*D[6][9] + F[6][9]*D[4][9] + F[6][10]*D[4][10] + F[6][11]*D[4][11] + F[6][12]*D[4][12] + F[4][13]*D[6][13])*T + D[4][6];
522  P[4][7] = P[7][4] = (F[7][6]*(F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[4][8]*D[6][8] + F[4][9]*D[6][9] + F[4][13]*D[6][13]) + F[7][8]*(F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[4][13]*D[8][13]) + F[7][9]*(F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[4][13]*D[9][13]) + F[7][10]*(F[4][6]*D[6][10] + F[4][7]*D[7][10] + F[4][8]*D[8][10] + F[4][9]*D[9][10] + F[4][13]*D[10][13]) + F[7][11]*(F[4][6]*D[6][11] + F[4][7]*D[7][11] + F[4][8]*D[8][11] + F[4][9]*D[9][11] + F[4][13]*D[11][13]) + F[7][12]*(F[4][6]*D[6][12] + F[4][7]*D[7][12] + F[4][8]*D[8][12] + F[4][9]*D[9][12] + F[4][13]*D[12][13]))*Tsq + (F[4][6]*D[6][7] + F[7][6]*D[4][6] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[7][8]*D[4][8] + F[4][9]*D[7][9] + F[7][9]*D[4][9] + F[7][10]*D[4][10] + F[7][11]*D[4][11] + F[7][12]*D[4][12] + F[4][13]*D[7][13])*T + D[4][7];
523  P[4][8] = P[8][4] = (F[8][6]*(F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[4][8]*D[6][8] + F[4][9]*D[6][9] + F[4][13]*D[6][13]) + F[8][7]*(F[4][6]*D[6][7] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[4][9]*D[7][9] + F[4][13]*D[7][13]) + F[8][9]*(F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[4][13]*D[9][13]) + F[8][10]*(F[4][6]*D[6][10] + F[4][7]*D[7][10] + F[4][8]*D[8][10] + F[4][9]*D[9][10] + F[4][13]*D[10][13]) + F[8][11]*(F[4][6]*D[6][11] + F[4][7]*D[7][11] + F[4][8]*D[8][11] + F[4][9]*D[9][11] + F[4][13]*D[11][13]) + F[8][12]*(F[4][6]*D[6][12] + F[4][7]*D[7][12] + F[4][8]*D[8][12] + F[4][9]*D[9][12] + F[4][13]*D[12][13]))*Tsq + (F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[8][6]*D[4][6] + F[8][7]*D[4][7] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[8][9]*D[4][9] + F[8][10]*D[4][10] + F[8][11]*D[4][11] + F[8][12]*D[4][12] + F[4][13]*D[8][13])*T + D[4][8];
524  P[4][9] = P[9][4] = (F[9][6]*(F[4][6]*D[6][6] + F[4][7]*D[6][7] + F[4][8]*D[6][8] + F[4][9]*D[6][9] + F[4][13]*D[6][13]) + F[9][7]*(F[4][6]*D[6][7] + F[4][7]*D[7][7] + F[4][8]*D[7][8] + F[4][9]*D[7][9] + F[4][13]*D[7][13]) + F[9][8]*(F[4][6]*D[6][8] + F[4][7]*D[7][8] + F[4][8]*D[8][8] + F[4][9]*D[8][9] + F[4][13]*D[8][13]) + F[9][10]*(F[4][6]*D[6][10] + F[4][7]*D[7][10] + F[4][8]*D[8][10] + F[4][9]*D[9][10] + F[4][13]*D[10][13]) + F[9][11]*(F[4][6]*D[6][11] + F[4][7]*D[7][11] + F[4][8]*D[8][11] + F[4][9]*D[9][11] + F[4][13]*D[11][13]) + F[9][12]*(F[4][6]*D[6][12] + F[4][7]*D[7][12] + F[4][8]*D[8][12] + F[4][9]*D[9][12] + F[4][13]*D[12][13]))*Tsq + (F[9][6]*D[4][6] + F[9][7]*D[4][7] + F[9][8]*D[4][8] + F[4][6]*D[6][9] + F[4][7]*D[7][9] + F[4][8]*D[8][9] + F[4][9]*D[9][9] + F[9][10]*D[4][10] + F[9][11]*D[4][11] + F[9][12]*D[4][12] + F[4][13]*D[9][13])*T + D[4][9];
525  P[4][10] = P[10][4] = (F[4][6]*D[6][10] + F[4][7]*D[7][10] + F[4][8]*D[8][10] + F[4][9]*D[9][10] + F[4][13]*D[10][13])*T + D[4][10];
526  P[4][11] = P[11][4] = (F[4][6]*D[6][11] + F[4][7]*D[7][11] + F[4][8]*D[8][11] + F[4][9]*D[9][11] + F[4][13]*D[11][13])*T + D[4][11];
527  P[4][12] = P[12][4] = (F[4][6]*D[6][12] + F[4][7]*D[7][12] + F[4][8]*D[8][12] + F[4][9]*D[9][12] + F[4][13]*D[12][13])*T + D[4][12];
528  P[4][13] = P[13][4] = (F[4][6]*D[6][13] + F[4][7]*D[7][13] + F[4][8]*D[8][13] + F[4][9]*D[9][13] + F[4][13]*D[13][13])*T + D[4][13];
529  P[5][5] = (Q[3]*G[5][3]*G[5][3] + Q[4]*G[5][4]*G[5][4] + Q[5]*G[5][5]*G[5][5] + F[5][6]*(F[5][6]*D[6][6] + F[5][7]*D[6][7] + F[5][8]*D[6][8] + F[5][9]*D[6][9] + F[5][13]*D[6][13]) + F[5][7]*(F[5][6]*D[6][7] + F[5][7]*D[7][7] + F[5][8]*D[7][8] + F[5][9]*D[7][9] + F[5][13]*D[7][13]) + F[5][8]*(F[5][6]*D[6][8] + F[5][7]*D[7][8] + F[5][8]*D[8][8] + F[5][9]*D[8][9] + F[5][13]*D[8][13]) + F[5][9]*(F[5][6]*D[6][9] + F[5][7]*D[7][9] + F[5][8]*D[8][9] + F[5][9]*D[9][9] + F[5][13]*D[9][13]) + F[5][13]*(F[5][6]*D[6][13] + F[5][7]*D[7][13] + F[5][8]*D[8][13] + F[5][9]*D[9][13] + F[5][13]*D[13][13]))*Tsq + (2*F[5][6]*D[5][6] + 2*F[5][7]*D[5][7] + 2*F[5][8]*D[5][8] + 2*F[5][9]*D[5][9] + 2*F[5][13]*D[5][13])*T + D[5][5];
530  P[5][6] = P[6][5] = (F[6][7]*(F[5][6]*D[6][7] + F[5][7]*D[7][7] + F[5][8]*D[7][8] + F[5][9]*D[7][9] + F[5][13]*D[7][13]) + F[6][8]*(F[5][6]*D[6][8] + F[5][7]*D[7][8] + F[5][8]*D[8][8] + F[5][9]*D[8][9] + F[5][13]*D[8][13]) + F[6][9]*(F[5][6]*D[6][9] + F[5][7]*D[7][9] + F[5][8]*D[8][9] + F[5][9]*D[9][9] + F[5][13]*D[9][13]) + F[6][10]*(F[5][6]*D[6][10] + F[5][7]*D[7][10] + F[5][8]*D[8][10] + F[5][9]*D[9][10] + F[5][13]*D[10][13]) + F[6][11]*(F[5][6]*D[6][11] + F[5][7]*D[7][11] + F[5][8]*D[8][11] + F[5][9]*D[9][11] + F[5][13]*D[11][13]) + F[6][12]*(F[5][6]*D[6][12] + F[5][7]*D[7][12] + F[5][8]*D[8][12] + F[5][9]*D[9][12] + F[5][13]*D[12][13]))*Tsq + (F[5][6]*D[6][6] + F[5][7]*D[6][7] + F[6][7]*D[5][7] + F[5][8]*D[6][8] + F[6][8]*D[5][8] + F[5][9]*D[6][9] + F[6][9]*D[5][9] + F[6][10]*D[5][10] + F[6][11]*D[5][11] + F[6][12]*D[5][12] + F[5][13]*D[6][13])*T + D[5][6];
531  P[5][7] = P[7][5] = (F[7][6]*(F[5][6]*D[6][6] + F[5][7]*D[6][7] + F[5][8]*D[6][8] + F[5][9]*D[6][9] + F[5][13]*D[6][13]) + F[7][8]*(F[5][6]*D[6][8] + F[5][7]*D[7][8] + F[5][8]*D[8][8] + F[5][9]*D[8][9] + F[5][13]*D[8][13]) + F[7][9]*(F[5][6]*D[6][9] + F[5][7]*D[7][9] + F[5][8]*D[8][9] + F[5][9]*D[9][9] + F[5][13]*D[9][13]) + F[7][10]*(F[5][6]*D[6][10] + F[5][7]*D[7][10] + F[5][8]*D[8][10] + F[5][9]*D[9][10] + F[5][13]*D[10][13]) + F[7][11]*(F[5][6]*D[6][11] + F[5][7]*D[7][11] + F[5][8]*D[8][11] + F[5][9]*D[9][11] + F[5][13]*D[11][13]) + F[7][12]*(F[5][6]*D[6][12] + F[5][7]*D[7][12] + F[5][8]*D[8][12] + F[5][9]*D[9][12] + F[5][13]*D[12][13]))*Tsq + (F[5][6]*D[6][7] + F[7][6]*D[5][6] + F[5][7]*D[7][7] + F[5][8]*D[7][8] + F[7][8]*D[5][8] + F[5][9]*D[7][9] + F[7][9]*D[5][9] + F[7][10]*D[5][10] + F[7][11]*D[5][11] + F[7][12]*D[5][12] + F[5][13]*D[7][13])*T + D[5][7];
532  P[5][8] = P[8][5] = (F[8][6]*(F[5][6]*D[6][6] + F[5][7]*D[6][7] + F[5][8]*D[6][8] + F[5][9]*D[6][9] + F[5][13]*D[6][13]) + F[8][7]*(F[5][6]*D[6][7] + F[5][7]*D[7][7] + F[5][8]*D[7][8] + F[5][9]*D[7][9] + F[5][13]*D[7][13]) + F[8][9]*(F[5][6]*D[6][9] + F[5][7]*D[7][9] + F[5][8]*D[8][9] + F[5][9]*D[9][9] + F[5][13]*D[9][13]) + F[8][10]*(F[5][6]*D[6][10] + F[5][7]*D[7][10] + F[5][8]*D[8][10] + F[5][9]*D[9][10] + F[5][13]*D[10][13]) + F[8][11]*(F[5][6]*D[6][11] + F[5][7]*D[7][11] + F[5][8]*D[8][11] + F[5][9]*D[9][11] + F[5][13]*D[11][13]) + F[8][12]*(F[5][6]*D[6][12] + F[5][7]*D[7][12] + F[5][8]*D[8][12] + F[5][9]*D[9][12] + F[5][13]*D[12][13]))*Tsq + (F[5][6]*D[6][8] + F[5][7]*D[7][8] + F[8][6]*D[5][6] + F[8][7]*D[5][7] + F[5][8]*D[8][8] + F[5][9]*D[8][9] + F[8][9]*D[5][9] + F[8][10]*D[5][10] + F[8][11]*D[5][11] + F[8][12]*D[5][12] + F[5][13]*D[8][13])*T + D[5][8];
533  P[5][9] = P[9][5] = (F[9][6]*(F[5][6]*D[6][6] + F[5][7]*D[6][7] + F[5][8]*D[6][8] + F[5][9]*D[6][9] + F[5][13]*D[6][13]) + F[9][7]*(F[5][6]*D[6][7] + F[5][7]*D[7][7] + F[5][8]*D[7][8] + F[5][9]*D[7][9] + F[5][13]*D[7][13]) + F[9][8]*(F[5][6]*D[6][8] + F[5][7]*D[7][8] + F[5][8]*D[8][8] + F[5][9]*D[8][9] + F[5][13]*D[8][13]) + F[9][10]*(F[5][6]*D[6][10] + F[5][7]*D[7][10] + F[5][8]*D[8][10] + F[5][9]*D[9][10] + F[5][13]*D[10][13]) + F[9][11]*(F[5][6]*D[6][11] + F[5][7]*D[7][11] + F[5][8]*D[8][11] + F[5][9]*D[9][11] + F[5][13]*D[11][13]) + F[9][12]*(F[5][6]*D[6][12] + F[5][7]*D[7][12] + F[5][8]*D[8][12] + F[5][9]*D[9][12] + F[5][13]*D[12][13]))*Tsq + (F[9][6]*D[5][6] + F[9][7]*D[5][7] + F[9][8]*D[5][8] + F[5][6]*D[6][9] + F[5][7]*D[7][9] + F[5][8]*D[8][9] + F[5][9]*D[9][9] + F[9][10]*D[5][10] + F[9][11]*D[5][11] + F[9][12]*D[5][12] + F[5][13]*D[9][13])*T + D[5][9];
534  P[5][10] = P[10][5] = (F[5][6]*D[6][10] + F[5][7]*D[7][10] + F[5][8]*D[8][10] + F[5][9]*D[9][10] + F[5][13]*D[10][13])*T + D[5][10];
535  P[5][11] = P[11][5] = (F[5][6]*D[6][11] + F[5][7]*D[7][11] + F[5][8]*D[8][11] + F[5][9]*D[9][11] + F[5][13]*D[11][13])*T + D[5][11];
536  P[5][12] = P[12][5] = (F[5][6]*D[6][12] + F[5][7]*D[7][12] + F[5][8]*D[8][12] + F[5][9]*D[9][12] + F[5][13]*D[12][13])*T + D[5][12];
537  P[5][13] = P[13][5] = (F[5][6]*D[6][13] + F[5][7]*D[7][13] + F[5][8]*D[8][13] + F[5][9]*D[9][13] + F[5][13]*D[13][13])*T + D[5][13];
538  P[6][6] = (Q[0]*G[6][0]*G[6][0] + Q[1]*G[6][1]*G[6][1] + Q[2]*G[6][2]*G[6][2] + F[6][7]*(F[6][7]*D[7][7] + F[6][8]*D[7][8] + F[6][9]*D[7][9] + F[6][10]*D[7][10] + F[6][11]*D[7][11] + F[6][12]*D[7][12]) + F[6][8]*(F[6][7]*D[7][8] + F[6][8]*D[8][8] + F[6][9]*D[8][9] + F[6][10]*D[8][10] + F[6][11]*D[8][11] + F[6][12]*D[8][12]) + F[6][9]*(F[6][7]*D[7][9] + F[6][8]*D[8][9] + F[6][9]*D[9][9] + F[6][10]*D[9][10] + F[6][11]*D[9][11] + F[6][12]*D[9][12]) + F[6][10]*(F[6][7]*D[7][10] + F[6][8]*D[8][10] + F[6][9]*D[9][10] + F[6][10]*D[10][10] + F[6][11]*D[10][11] + F[6][12]*D[10][12]) + F[6][11]*(F[6][7]*D[7][11] + F[6][8]*D[8][11] + F[6][9]*D[9][11] + F[6][10]*D[10][11] + F[6][11]*D[11][11] + F[6][12]*D[11][12]) + F[6][12]*(F[6][7]*D[7][12] + F[6][8]*D[8][12] + F[6][9]*D[9][12] + F[6][10]*D[10][12] + F[6][11]*D[11][12] + F[6][12]*D[12][12]))*Tsq + (2*F[6][7]*D[6][7] + 2*F[6][8]*D[6][8] + 2*F[6][9]*D[6][9] + 2*F[6][10]*D[6][10] + 2*F[6][11]*D[6][11] + 2*F[6][12]*D[6][12])*T + D[6][6];
539  P[6][7] = P[7][6] = (F[7][6]*(F[6][7]*D[6][7] + F[6][8]*D[6][8] + F[6][9]*D[6][9] + F[6][10]*D[6][10] + F[6][11]*D[6][11] + F[6][12]*D[6][12]) + F[7][8]*(F[6][7]*D[7][8] + F[6][8]*D[8][8] + F[6][9]*D[8][9] + F[6][10]*D[8][10] + F[6][11]*D[8][11] + F[6][12]*D[8][12]) + F[7][9]*(F[6][7]*D[7][9] + F[6][8]*D[8][9] + F[6][9]*D[9][9] + F[6][10]*D[9][10] + F[6][11]*D[9][11] + F[6][12]*D[9][12]) + F[7][10]*(F[6][7]*D[7][10] + F[6][8]*D[8][10] + F[6][9]*D[9][10] + F[6][10]*D[10][10] + F[6][11]*D[10][11] + F[6][12]*D[10][12]) + F[7][11]*(F[6][7]*D[7][11] + F[6][8]*D[8][11] + F[6][9]*D[9][11] + F[6][10]*D[10][11] + F[6][11]*D[11][11] + F[6][12]*D[11][12]) + F[7][12]*(F[6][7]*D[7][12] + F[6][8]*D[8][12] + F[6][9]*D[9][12] + F[6][10]*D[10][12] + F[6][11]*D[11][12] + F[6][12]*D[12][12]) + G[6][0]*G[7][0]*Q[0] + G[6][1]*G[7][1]*Q[1] + G[6][2]*G[7][2]*Q[2])*Tsq + (F[7][6]*D[6][6] + F[6][7]*D[7][7] + F[6][8]*D[7][8] + F[7][8]*D[6][8] + F[6][9]*D[7][9] + F[7][9]*D[6][9] + F[6][10]*D[7][10] + F[7][10]*D[6][10] + F[6][11]*D[7][11] + F[7][11]*D[6][11] + F[6][12]*D[7][12] + F[7][12]*D[6][12])*T + D[6][7];
540  P[6][8] = P[8][6] = (F[8][6]*(F[6][7]*D[6][7] + F[6][8]*D[6][8] + F[6][9]*D[6][9] + F[6][10]*D[6][10] + F[6][11]*D[6][11] + F[6][12]*D[6][12]) + F[8][7]*(F[6][7]*D[7][7] + F[6][8]*D[7][8] + F[6][9]*D[7][9] + F[6][10]*D[7][10] + F[6][11]*D[7][11] + F[6][12]*D[7][12]) + F[8][9]*(F[6][7]*D[7][9] + F[6][8]*D[8][9] + F[6][9]*D[9][9] + F[6][10]*D[9][10] + F[6][11]*D[9][11] + F[6][12]*D[9][12]) + F[8][10]*(F[6][7]*D[7][10] + F[6][8]*D[8][10] + F[6][9]*D[9][10] + F[6][10]*D[10][10] + F[6][11]*D[10][11] + F[6][12]*D[10][12]) + F[8][11]*(F[6][7]*D[7][11] + F[6][8]*D[8][11] + F[6][9]*D[9][11] + F[6][10]*D[10][11] + F[6][11]*D[11][11] + F[6][12]*D[11][12]) + F[8][12]*(F[6][7]*D[7][12] + F[6][8]*D[8][12] + F[6][9]*D[9][12] + F[6][10]*D[10][12] + F[6][11]*D[11][12] + F[6][12]*D[12][12]) + G[6][0]*G[8][0]*Q[0] + G[6][1]*G[8][1]*Q[1] + G[6][2]*G[8][2]*Q[2])*Tsq + (F[6][7]*D[7][8] + F[8][6]*D[6][6] + F[8][7]*D[6][7] + F[6][8]*D[8][8] + F[6][9]*D[8][9] + F[8][9]*D[6][9] + F[6][10]*D[8][10] + F[8][10]*D[6][10] + F[6][11]*D[8][11] + F[8][11]*D[6][11] + F[6][12]*D[8][12] + F[8][12]*D[6][12])*T + D[6][8];
541  P[6][9] = P[9][6] = (F[9][6]*(F[6][7]*D[6][7] + F[6][8]*D[6][8] + F[6][9]*D[6][9] + F[6][10]*D[6][10] + F[6][11]*D[6][11] + F[6][12]*D[6][12]) + F[9][7]*(F[6][7]*D[7][7] + F[6][8]*D[7][8] + F[6][9]*D[7][9] + F[6][10]*D[7][10] + F[6][11]*D[7][11] + F[6][12]*D[7][12]) + F[9][8]*(F[6][7]*D[7][8] + F[6][8]*D[8][8] + F[6][9]*D[8][9] + F[6][10]*D[8][10] + F[6][11]*D[8][11] + F[6][12]*D[8][12]) + F[9][10]*(F[6][7]*D[7][10] + F[6][8]*D[8][10] + F[6][9]*D[9][10] + F[6][10]*D[10][10] + F[6][11]*D[10][11] + F[6][12]*D[10][12]) + F[9][11]*(F[6][7]*D[7][11] + F[6][8]*D[8][11] + F[6][9]*D[9][11] + F[6][10]*D[10][11] + F[6][11]*D[11][11] + F[6][12]*D[11][12]) + F[9][12]*(F[6][7]*D[7][12] + F[6][8]*D[8][12] + F[6][9]*D[9][12] + F[6][10]*D[10][12] + F[6][11]*D[11][12] + F[6][12]*D[12][12]) + G[6][0]*G[9][0]*Q[0] + G[6][1]*G[9][1]*Q[1] + G[6][2]*G[9][2]*Q[2])*Tsq + (F[9][6]*D[6][6] + F[9][7]*D[6][7] + F[9][8]*D[6][8] + F[6][7]*D[7][9] + F[6][8]*D[8][9] + F[6][9]*D[9][9] + F[6][10]*D[9][10] + F[9][10]*D[6][10] + F[6][11]*D[9][11] + F[9][11]*D[6][11] + F[6][12]*D[9][12] + F[9][12]*D[6][12])*T + D[6][9];
542  P[6][10] = P[10][6] = (F[6][7]*D[7][10] + F[6][8]*D[8][10] + F[6][9]*D[9][10] + F[6][10]*D[10][10] + F[6][11]*D[10][11] + F[6][12]*D[10][12])*T + D[6][10];
543  P[6][11] = P[11][6] = (F[6][7]*D[7][11] + F[6][8]*D[8][11] + F[6][9]*D[9][11] + F[6][10]*D[10][11] + F[6][11]*D[11][11] + F[6][12]*D[11][12])*T + D[6][11];
544  P[6][12] = P[12][6] = (F[6][7]*D[7][12] + F[6][8]*D[8][12] + F[6][9]*D[9][12] + F[6][10]*D[10][12] + F[6][11]*D[11][12] + F[6][12]*D[12][12])*T + D[6][12];
545  P[6][13] = P[13][6] = (F[6][7]*D[7][13] + F[6][8]*D[8][13] + F[6][9]*D[9][13] + F[6][10]*D[10][13] + F[6][11]*D[11][13] + F[6][12]*D[12][13])*T + D[6][13];
546  P[7][7] = (Q[0]*G[7][0]*G[7][0] + Q[1]*G[7][1]*G[7][1] + Q[2]*G[7][2]*G[7][2] + F[7][6]*(F[7][6]*D[6][6] + F[7][8]*D[6][8] + F[7][9]*D[6][9] + F[7][10]*D[6][10] + F[7][11]*D[6][11] + F[7][12]*D[6][12]) + F[7][8]*(F[7][6]*D[6][8] + F[7][8]*D[8][8] + F[7][9]*D[8][9] + F[7][10]*D[8][10] + F[7][11]*D[8][11] + F[7][12]*D[8][12]) + F[7][9]*(F[7][6]*D[6][9] + F[7][8]*D[8][9] + F[7][9]*D[9][9] + F[7][10]*D[9][10] + F[7][11]*D[9][11] + F[7][12]*D[9][12]) + F[7][10]*(F[7][6]*D[6][10] + F[7][8]*D[8][10] + F[7][9]*D[9][10] + F[7][10]*D[10][10] + F[7][11]*D[10][11] + F[7][12]*D[10][12]) + F[7][11]*(F[7][6]*D[6][11] + F[7][8]*D[8][11] + F[7][9]*D[9][11] + F[7][10]*D[10][11] + F[7][11]*D[11][11] + F[7][12]*D[11][12]) + F[7][12]*(F[7][6]*D[6][12] + F[7][8]*D[8][12] + F[7][9]*D[9][12] + F[7][10]*D[10][12] + F[7][11]*D[11][12] + F[7][12]*D[12][12]))*Tsq + (2*F[7][6]*D[6][7] + 2*F[7][8]*D[7][8] + 2*F[7][9]*D[7][9] + 2*F[7][10]*D[7][10] + 2*F[7][11]*D[7][11] + 2*F[7][12]*D[7][12])*T + D[7][7];
547  P[7][8] = P[8][7] = (F[8][6]*(F[7][6]*D[6][6] + F[7][8]*D[6][8] + F[7][9]*D[6][9] + F[7][10]*D[6][10] + F[7][11]*D[6][11] + F[7][12]*D[6][12]) + F[8][7]*(F[7][6]*D[6][7] + F[7][8]*D[7][8] + F[7][9]*D[7][9] + F[7][10]*D[7][10] + F[7][11]*D[7][11] + F[7][12]*D[7][12]) + F[8][9]*(F[7][6]*D[6][9] + F[7][8]*D[8][9] + F[7][9]*D[9][9] + F[7][10]*D[9][10] + F[7][11]*D[9][11] + F[7][12]*D[9][12]) + F[8][10]*(F[7][6]*D[6][10] + F[7][8]*D[8][10] + F[7][9]*D[9][10] + F[7][10]*D[10][10] + F[7][11]*D[10][11] + F[7][12]*D[10][12]) + F[8][11]*(F[7][6]*D[6][11] + F[7][8]*D[8][11] + F[7][9]*D[9][11] + F[7][10]*D[10][11] + F[7][11]*D[11][11] + F[7][12]*D[11][12]) + F[8][12]*(F[7][6]*D[6][12] + F[7][8]*D[8][12] + F[7][9]*D[9][12] + F[7][10]*D[10][12] + F[7][11]*D[11][12] + F[7][12]*D[12][12]) + G[7][0]*G[8][0]*Q[0] + G[7][1]*G[8][1]*Q[1] + G[7][2]*G[8][2]*Q[2])*Tsq + (F[7][6]*D[6][8] + F[8][6]*D[6][7] + F[8][7]*D[7][7] + F[7][8]*D[8][8] + F[7][9]*D[8][9] + F[8][9]*D[7][9] + F[7][10]*D[8][10] + F[8][10]*D[7][10] + F[7][11]*D[8][11] + F[8][11]*D[7][11] + F[7][12]*D[8][12] + F[8][12]*D[7][12])*T + D[7][8];
548  P[7][9] = P[9][7] = (F[9][6]*(F[7][6]*D[6][6] + F[7][8]*D[6][8] + F[7][9]*D[6][9] + F[7][10]*D[6][10] + F[7][11]*D[6][11] + F[7][12]*D[6][12]) + F[9][7]*(F[7][6]*D[6][7] + F[7][8]*D[7][8] + F[7][9]*D[7][9] + F[7][10]*D[7][10] + F[7][11]*D[7][11] + F[7][12]*D[7][12]) + F[9][8]*(F[7][6]*D[6][8] + F[7][8]*D[8][8] + F[7][9]*D[8][9] + F[7][10]*D[8][10] + F[7][11]*D[8][11] + F[7][12]*D[8][12]) + F[9][10]*(F[7][6]*D[6][10] + F[7][8]*D[8][10] + F[7][9]*D[9][10] + F[7][10]*D[10][10] + F[7][11]*D[10][11] + F[7][12]*D[10][12]) + F[9][11]*(F[7][6]*D[6][11] + F[7][8]*D[8][11] + F[7][9]*D[9][11] + F[7][10]*D[10][11] + F[7][11]*D[11][11] + F[7][12]*D[11][12]) + F[9][12]*(F[7][6]*D[6][12] + F[7][8]*D[8][12] + F[7][9]*D[9][12] + F[7][10]*D[10][12] + F[7][11]*D[11][12] + F[7][12]*D[12][12]) + G[7][0]*G[9][0]*Q[0] + G[7][1]*G[9][1]*Q[1] + G[7][2]*G[9][2]*Q[2])*Tsq + (F[9][6]*D[6][7] + F[9][7]*D[7][7] + F[9][8]*D[7][8] + F[7][6]*D[6][9] + F[7][8]*D[8][9] + F[7][9]*D[9][9] + F[7][10]*D[9][10] + F[9][10]*D[7][10] + F[7][11]*D[9][11] + F[9][11]*D[7][11] + F[7][12]*D[9][12] + F[9][12]*D[7][12])*T + D[7][9];
549  P[7][10] = P[10][7] = (F[7][6]*D[6][10] + F[7][8]*D[8][10] + F[7][9]*D[9][10] + F[7][10]*D[10][10] + F[7][11]*D[10][11] + F[7][12]*D[10][12])*T + D[7][10];
550  P[7][11] = P[11][7] = (F[7][6]*D[6][11] + F[7][8]*D[8][11] + F[7][9]*D[9][11] + F[7][10]*D[10][11] + F[7][11]*D[11][11] + F[7][12]*D[11][12])*T + D[7][11];
551  P[7][12] = P[12][7] = (F[7][6]*D[6][12] + F[7][8]*D[8][12] + F[7][9]*D[9][12] + F[7][10]*D[10][12] + F[7][11]*D[11][12] + F[7][12]*D[12][12])*T + D[7][12];
552  P[7][13] = P[13][7] = (F[7][6]*D[6][13] + F[7][8]*D[8][13] + F[7][9]*D[9][13] + F[7][10]*D[10][13] + F[7][11]*D[11][13] + F[7][12]*D[12][13])*T + D[7][13];
553  P[8][8] = (Q[0]*G[8][0]*G[8][0] + Q[1]*G[8][1]*G[8][1] + Q[2]*G[8][2]*G[8][2] + F[8][6]*(F[8][6]*D[6][6] + F[8][7]*D[6][7] + F[8][9]*D[6][9] + F[8][10]*D[6][10] + F[8][11]*D[6][11] + F[8][12]*D[6][12]) + F[8][7]*(F[8][6]*D[6][7] + F[8][7]*D[7][7] + F[8][9]*D[7][9] + F[8][10]*D[7][10] + F[8][11]*D[7][11] + F[8][12]*D[7][12]) + F[8][9]*(F[8][6]*D[6][9] + F[8][7]*D[7][9] + F[8][9]*D[9][9] + F[8][10]*D[9][10] + F[8][11]*D[9][11] + F[8][12]*D[9][12]) + F[8][10]*(F[8][6]*D[6][10] + F[8][7]*D[7][10] + F[8][9]*D[9][10] + F[8][10]*D[10][10] + F[8][11]*D[10][11] + F[8][12]*D[10][12]) + F[8][11]*(F[8][6]*D[6][11] + F[8][7]*D[7][11] + F[8][9]*D[9][11] + F[8][10]*D[10][11] + F[8][11]*D[11][11] + F[8][12]*D[11][12]) + F[8][12]*(F[8][6]*D[6][12] + F[8][7]*D[7][12] + F[8][9]*D[9][12] + F[8][10]*D[10][12] + F[8][11]*D[11][12] + F[8][12]*D[12][12]))*Tsq + (2*F[8][6]*D[6][8] + 2*F[8][7]*D[7][8] + 2*F[8][9]*D[8][9] + 2*F[8][10]*D[8][10] + 2*F[8][11]*D[8][11] + 2*F[8][12]*D[8][12])*T + D[8][8];
554  P[8][9] = P[9][8] = (F[9][6]*(F[8][6]*D[6][6] + F[8][7]*D[6][7] + F[8][9]*D[6][9] + F[8][10]*D[6][10] + F[8][11]*D[6][11] + F[8][12]*D[6][12]) + F[9][7]*(F[8][6]*D[6][7] + F[8][7]*D[7][7] + F[8][9]*D[7][9] + F[8][10]*D[7][10] + F[8][11]*D[7][11] + F[8][12]*D[7][12]) + F[9][8]*(F[8][6]*D[6][8] + F[8][7]*D[7][8] + F[8][9]*D[8][9] + F[8][10]*D[8][10] + F[8][11]*D[8][11] + F[8][12]*D[8][12]) + F[9][10]*(F[8][6]*D[6][10] + F[8][7]*D[7][10] + F[8][9]*D[9][10] + F[8][10]*D[10][10] + F[8][11]*D[10][11] + F[8][12]*D[10][12]) + F[9][11]*(F[8][6]*D[6][11] + F[8][7]*D[7][11] + F[8][9]*D[9][11] + F[8][10]*D[10][11] + F[8][11]*D[11][11] + F[8][12]*D[11][12]) + F[9][12]*(F[8][6]*D[6][12] + F[8][7]*D[7][12] + F[8][9]*D[9][12] + F[8][10]*D[10][12] + F[8][11]*D[11][12] + F[8][12]*D[12][12]) + G[8][0]*G[9][0]*Q[0] + G[8][1]*G[9][1]*Q[1] + G[8][2]*G[9][2]*Q[2])*Tsq + (F[9][6]*D[6][8] + F[9][7]*D[7][8] + F[9][8]*D[8][8] + F[8][6]*D[6][9] + F[8][7]*D[7][9] + F[8][9]*D[9][9] + F[8][10]*D[9][10] + F[9][10]*D[8][10] + F[8][11]*D[9][11] + F[9][11]*D[8][11] + F[8][12]*D[9][12] + F[9][12]*D[8][12])*T + D[8][9];
555  P[8][10] = P[10][8] = (F[8][6]*D[6][10] + F[8][7]*D[7][10] + F[8][9]*D[9][10] + F[8][10]*D[10][10] + F[8][11]*D[10][11] + F[8][12]*D[10][12])*T + D[8][10];
556  P[8][11] = P[11][8] = (F[8][6]*D[6][11] + F[8][7]*D[7][11] + F[8][9]*D[9][11] + F[8][10]*D[10][11] + F[8][11]*D[11][11] + F[8][12]*D[11][12])*T + D[8][11];
557  P[8][12] = P[12][8] = (F[8][6]*D[6][12] + F[8][7]*D[7][12] + F[8][9]*D[9][12] + F[8][10]*D[10][12] + F[8][11]*D[11][12] + F[8][12]*D[12][12])*T + D[8][12];
558  P[8][13] = P[13][8] = (F[8][6]*D[6][13] + F[8][7]*D[7][13] + F[8][9]*D[9][13] + F[8][10]*D[10][13] + F[8][11]*D[11][13] + F[8][12]*D[12][13])*T + D[8][13];
559  P[9][9] = (Q[0]*G[9][0]*G[9][0] + Q[1]*G[9][1]*G[9][1] + Q[2]*G[9][2]*G[9][2] + F[9][6]*(F[9][6]*D[6][6] + F[9][7]*D[6][7] + F[9][8]*D[6][8] + F[9][10]*D[6][10] + F[9][11]*D[6][11] + F[9][12]*D[6][12]) + F[9][7]*(F[9][6]*D[6][7] + F[9][7]*D[7][7] + F[9][8]*D[7][8] + F[9][10]*D[7][10] + F[9][11]*D[7][11] + F[9][12]*D[7][12]) + F[9][8]*(F[9][6]*D[6][8] + F[9][7]*D[7][8] + F[9][8]*D[8][8] + F[9][10]*D[8][10] + F[9][11]*D[8][11] + F[9][12]*D[8][12]) + F[9][10]*(F[9][6]*D[6][10] + F[9][7]*D[7][10] + F[9][8]*D[8][10] + F[9][10]*D[10][10] + F[9][11]*D[10][11] + F[9][12]*D[10][12]) + F[9][11]*(F[9][6]*D[6][11] + F[9][7]*D[7][11] + F[9][8]*D[8][11] + F[9][10]*D[10][11] + F[9][11]*D[11][11] + F[9][12]*D[11][12]) + F[9][12]*(F[9][6]*D[6][12] + F[9][7]*D[7][12] + F[9][8]*D[8][12] + F[9][10]*D[10][12] + F[9][11]*D[11][12] + F[9][12]*D[12][12]))*Tsq + (2*F[9][6]*D[6][9] + 2*F[9][7]*D[7][9] + 2*F[9][8]*D[8][9] + 2*F[9][10]*D[9][10] + 2*F[9][11]*D[9][11] + 2*F[9][12]*D[9][12])*T + D[9][9];
560  P[9][10] = P[10][9] = (F[9][6]*D[6][10] + F[9][7]*D[7][10] + F[9][8]*D[8][10] + F[9][10]*D[10][10] + F[9][11]*D[10][11] + F[9][12]*D[10][12])*T + D[9][10];
561  P[9][11] = P[11][9] = (F[9][6]*D[6][11] + F[9][7]*D[7][11] + F[9][8]*D[8][11] + F[9][10]*D[10][11] + F[9][11]*D[11][11] + F[9][12]*D[11][12])*T + D[9][11];
562  P[9][12] = P[12][9] = (F[9][6]*D[6][12] + F[9][7]*D[7][12] + F[9][8]*D[8][12] + F[9][10]*D[10][12] + F[9][11]*D[11][12] + F[9][12]*D[12][12])*T + D[9][12];
563  P[9][13] = P[13][9] = (F[9][6]*D[6][13] + F[9][7]*D[7][13] + F[9][8]*D[8][13] + F[9][10]*D[10][13] + F[9][11]*D[11][13] + F[9][12]*D[12][13])*T + D[9][13];
564  P[10][10] = Q[6]*Tsq + D[10][10];
565  P[10][11] = P[11][10] = D[10][11];
566  P[10][12] = P[12][10] = D[10][12];
567  P[10][13] = P[13][10] = D[10][13];
568  P[11][11] = Q[7]*Tsq + D[11][11];
569  P[11][12] = P[12][11] = D[11][12];
570  P[11][13] = P[13][11] = D[11][13];
571  P[12][12] = Q[8]*Tsq + D[12][12];
572  P[12][13] = P[13][12] = D[12][13];
573  P[13][13] = Q[9]*Tsq + D[13][13];
574 
575 }
576 #endif
577 
578 // ************* SerialUpdate *******************
579 // Does the update step of the Kalman filter for the covariance and estimate
580 // Outputs are Xnew & Pnew, and are written over P and X
581 // Z is actual measurement, Y is predicted measurement
582 // Xnew = X + K*(Z-Y), Pnew=(I-K*H)*P,
583 // where K=P*H'*inv[H*P*H'+R]
584 // NOTE the algorithm assumes R (measurement covariance matrix) is diagonal
585 // i.e. the measurment noises are uncorrelated.
586 // It therefore uses a serial update that requires no matrix inversion by
587 // processing the measurements one at a time.
588 // Algorithm - see Grewal and Andrews, "Kalman Filtering,2nd Ed" p.121 & p.253
589 // - or see Simon, "Optimal State Estimation," 1st Ed, p.150
590 // The SensorsUsed variable is a bitwise mask indicating which sensors
591 // should be used in the update.
592 // ************************************************
593 
594 void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV],
595  float Y[NUMV], float P[NUMX][NUMX], float X[NUMX],
596  uint16_t SensorsUsed)
597 {
598  float HP[NUMX], HPHR, Error;
599  uint8_t i, j, k, m;
600 
601  // Iterate through all the possible measurements and apply the
602  // appropriate corrections
603  for (m = 0; m < NUMV; m++) {
604 
605  if (SensorsUsed & (0x01 << m)) { // use this sensor for update
606 
607  for (j = 0; j < NUMX; j++) { // Find Hp = H*P
608  HP[j] = 0.0f;
609  for (k = 0; k < NUMX; k++)
610  HP[j] += H[m][k] * P[k][j];
611  }
612  HPHR = R[m]; // Find HPHR = H*P*H' + R
613  for (k = 0; k < NUMX; k++)
614  HPHR += HP[k] * H[m][k];
615 
616  for (k = 0; k < NUMX; k++)
617  K[k][m] = HP[k] / HPHR; // find K = HP/HPHR
618 
619  for (i = 0; i < NUMX; i++) { // Find P(m)= P(m-1) + K*HP
620  for (j = i; j < NUMX; j++)
621  P[i][j] = P[j][i] =
622  P[i][j] - K[i][m] * HP[j];
623  }
624 
625  Error = Z[m] - Y[m];
626  for (i = 0; i < NUMX; i++) // Find X(m)= X(m-1) + K*Error
627  X[i] = X[i] + K[i][m] * Error;
628 
629  }
630  }
631 
632  INSLimitBias();
633 }
634 
635 // ************* RungeKutta **********************
636 // Does a 4th order Runge Kutta numerical integration step
637 // Output, Xnew, is written over X
638 // NOTE the algorithm assumes time invariant state equations and
639 // constant inputs over integration step
640 // ************************************************
641 
642 void RungeKutta(float X[NUMX], float U[NUMU], float dT)
643 {
644 
645  float dT2 =
646  dT / 2.0f, K1[NUMX], K2[NUMX], K3[NUMX], K4[NUMX], Xlast[NUMX];
647  uint8_t i;
648 
649  for (i = 0; i < NUMX; i++)
650  Xlast[i] = X[i]; // make a working copy
651 
652  StateEq(X, U, K1); // k1 = f(x,u)
653  for (i = 0; i < NUMX; i++)
654  X[i] = Xlast[i] + dT2 * K1[i];
655  StateEq(X, U, K2); // k2 = f(x+0.5*dT*k1,u)
656  for (i = 0; i < NUMX; i++)
657  X[i] = Xlast[i] + dT2 * K2[i];
658  StateEq(X, U, K3); // k3 = f(x+0.5*dT*k2,u)
659  for (i = 0; i < NUMX; i++)
660  X[i] = Xlast[i] + dT * K3[i];
661  StateEq(X, U, K4); // k4 = f(x+dT*k3,u)
662 
663  // Xnew = X + dT*(k1+2*k2+2*k3+k4)/6
664  for (i = 0; i < NUMX; i++)
665  X[i] =
666  Xlast[i] + dT * (K1[i] + 2.0f * K2[i] + 2.0f * K3[i] +
667  K4[i]) / 6.0f;
668 }
669 
670 // ************* Model Specific Stuff ***************************
671 // *** StateEq, MeasurementEq, LinerizeFG, and LinearizeH ********
672 //
673 // State Variables = [Pos Vel Quaternion GyroBias AccelBias]
674 // Deterministic Inputs = [AngularVel Accel]
675 // Disturbance Noise = [GyroNoise AccelNoise GyroRandomWalkNoise AccelRandomWalkNoise]
676 //
677 // Measurement Variables = [Pos Vel BodyFrameMagField Altimeter]
678 // Inputs to Measurement = [EarthFrameMagField]
679 //
680 // Notes: Pos and Vel in earth frame
681 // AngularVel and Accel in body frame
682 // MagFields are unit vectors
683 // Xdot is output of StateEq()
684 // F and G are outputs of LinearizeFG(), all elements not set should be zero
685 // y is output of OutputEq()
686 // H is output of LinearizeH(), all elements not set should be zero
687 // ************************************************
688 
689 void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX])
690 {
691  const float wx = U[0] - X[10];
692  const float wy = U[1] - X[11];
693  const float wz = U[2] - X[12]; // subtract the biases on gyros
694  const float ax = U[3];
695  const float ay = U[4];
696  const float az = U[5] - X[13]; // subtract the biases on accels
697  const float q0 = X[6];
698  const float q1 = X[7];
699  const float q2 = X[8];
700  const float q3 = X[9];
701 
702  // Pdot = V
703  Xdot[0] = X[3];
704  Xdot[1] = X[4];
705  Xdot[2] = X[5];
706 
707  // Vdot = Reb*a
708  Xdot[3] =
709  (q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3) * ax + 2.0f * (q1 * q2 -
710  q0 * q3) *
711  ay + 2.0f * (q1 * q3 + q0 * q2) * az;
712  Xdot[4] =
713  2.0f * (q1 * q2 + q0 * q3) * ax + (q0 * q0 - q1 * q1 + q2 * q2 -
714  q3 * q3) * ay + 2.0f * (q2 * q3 -
715  q0 * q1) *
716  az;
717  Xdot[5] =
718  2.0f * (q1 * q3 - q0 * q2) * ax + 2.0f * (q2 * q3 + q0 * q1) * ay +
719  (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3) * az + GRAVITY;
720 
721  // qdot = Q*w
722  Xdot[6] = (-q1 * wx - q2 * wy - q3 * wz) / 2.0f;
723  Xdot[7] = (q0 * wx - q3 * wy + q2 * wz) / 2.0f;
724  Xdot[8] = (q3 * wx + q0 * wy - q1 * wz) / 2.0f;
725  Xdot[9] = (-q2 * wx + q1 * wy + q0 * wz) / 2.0f;
726 
727  // best guess is that bias stays constant
728  Xdot[10] = Xdot[11] = Xdot[12] = 0;
729 
730  // For accels to make sure things stay stable, assume bias always walks weakly
731  // towards zero for the horizontal axis. This prevents drifting around an
732  // unobservable manifold of possible attitudes and gyro biases. The z-axis
733  // we assume no drift becaues this is teh one we want to estimate most accurately.
734  Xdot[13] = 0.0f;
735 }
736 
751 void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX],
752  float G[NUMX][NUMW])
753 {
754  const float wx = U[0] - X[10];
755  const float wy = U[1] - X[11];
756  const float wz = U[2] - X[12]; // subtract the biases on gyros
757  const float ax = U[3];
758  const float ay = U[4];
759  const float az = U[5] - X[13]; // subtract the biases on accels
760  const float q0 = X[6];
761  const float q1 = X[7];
762  const float q2 = X[8];
763  const float q3 = X[9];
764 
765  // Pdot = V
766  F[0][3] = F[1][4] = F[2][5] = 1.0f;
767 
768  // dVdot/dq
769  F[3][6] = 2.0f * (q0 * ax - q3 * ay + q2 * az);
770  F[3][7] = 2.0f * (q1 * ax + q2 * ay + q3 * az);
771  F[3][8] = 2.0f * (-q2 * ax + q1 * ay + q0 * az);
772  F[3][9] = 2.0f * (-q3 * ax - q0 * ay + q1 * az);
773  F[4][6] = 2.0f * (q3 * ax + q0 * ay - q1 * az);
774  F[4][7] = 2.0f * (q2 * ax - q1 * ay - q0 * az);
775  F[4][8] = 2.0f * (q1 * ax + q2 * ay + q3 * az);
776  F[4][9] = 2.0f * (q0 * ax - q3 * ay + q2 * az);
777  F[5][6] = 2.0f * (-q2 * ax + q1 * ay + q0 * az);
778  F[5][7] = 2.0f * (q3 * ax + q0 * ay - q1 * az);
779  F[5][8] = 2.0f * (-q0 * ax + q3 * ay - q2 * az);
780  F[5][9] = 2.0f * (q1 * ax + q2 * ay + q3 * az);
781 
782  // dVdot/dabias & dVdot/dna - the equations for how the accel input and accel bias influence velocity are the same
783  F[3][13]=G[3][5]=-2.0f*(q1*q3+q0*q2);
784  F[4][13]=G[4][5]=2.0f*(-q2*q3+q0*q1);
785  F[5][13]=G[5][5]=-q0*q0+q1*q1+q2*q2-q3*q3;
786 
787  // dqdot/dq
788  F[6][6] = 0;
789  F[6][7] = -wx / 2.0f;
790  F[6][8] = -wy / 2.0f;
791  F[6][9] = -wz / 2.0f;
792  F[7][6] = wx / 2.0f;
793  F[7][7] = 0;
794  F[7][8] = wz / 2.0f;
795  F[7][9] = -wy / 2.0f;
796  F[8][6] = wy / 2.0f;
797  F[8][7] = -wz / 2.0f;
798  F[8][8] = 0;
799  F[8][9] = wx / 2.0f;
800  F[9][6] = wz / 2.0f;
801  F[9][7] = wy / 2.0f;
802  F[9][8] = -wx / 2.0f;
803  F[9][9] = 0;
804 
805  // dqdot/dwbias
806  F[6][10] = q1 / 2.0f;
807  F[6][11] = q2 / 2.0f;
808  F[6][12] = q3 / 2.0f;
809  F[7][10] = -q0 / 2.0f;
810  F[7][11] = q3 / 2.0f;
811  F[7][12] = -q2 / 2.0f;
812  F[8][10] = -q3 / 2.0f;
813  F[8][11] = -q0 / 2.0f;
814  F[8][12] = q1 / 2.0f;
815  F[9][10] = q2 / 2.0f;
816  F[9][11] = -q1 / 2.0f;
817  F[9][12] = -q0 / 2.0f;
818 
819  // dVdot/dna
820  G[3][3]=-q0*q0-q1*q1+q2*q2+q3*q3; G[3][4]=2*(-q1*q2+q0*q3); G[3][5]=-2*(q1*q3+q0*q2);
821  G[4][3]=-2*(q1*q2+q0*q3); G[4][4]=-q0*q0+q1*q1-q2*q2+q3*q3; G[4][5]=2*(-q2*q3+q0*q1);
822  G[5][3]=2*(-q1*q3+q0*q2); G[5][4]=-2*(q2*q3+q0*q1); G[5][5]=-q0*q0+q1*q1+q2*q2-q3*q3;
823 
824  // dqdot/dnw
825  G[6][0] = q1 / 2.0f;
826  G[6][1] = q2 / 2.0f;
827  G[6][2] = q3 / 2.0f;
828  G[7][0] = -q0 / 2.0f;
829  G[7][1] = q3 / 2.0f;
830  G[7][2] = -q2 / 2.0f;
831  G[8][0] = -q3 / 2.0f;
832  G[8][1] = -q0 / 2.0f;
833  G[8][2] = q1 / 2.0f;
834  G[9][0] = q2 / 2.0f;
835  G[9][1] = -q1 / 2.0f;
836  G[9][2] = -q0 / 2.0f;
837 }
838 
845 void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV])
846 {
847  const float q0 = X[6];
848  const float q1 = X[7];
849  const float q2 = X[8];
850  const float q3 = X[9];
851 
852  // first six outputs are P and V
853  Y[0] = X[0];
854  Y[1] = X[1];
855  Y[2] = X[2];
856  Y[3] = X[3];
857  Y[4] = X[4];
858  Y[5] = X[5];
859 
860  // Rotate Be by only the yaw heading
861  const float a1 = 2*q0*q3 + 2*q1*q2;
862  const float a2 = q0*q0 + q1*q1 - q2*q2 - q3*q3;
863  const float r = sqrtf( a1*a1 + a2*a2 );
864  const float cP = a2 / r;
865  const float sP = a1 / r;
866  Y[6] = Be[0] * cP + Be[1] * sP;
867  Y[7] = -Be[0] * sP + Be[1] * cP;
868  Y[8] = 0; // don't care
869 
870  // Alt = -Pz
871  Y[9] = X[2] * -1.0f;
872 }
873 
879 void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX])
880 {
881  const float q0 = X[6];
882  const float q1 = X[7];
883  const float q2 = X[8];
884  const float q3 = X[9];
885 
886  // dP/dP=I; (expect position to measure the position)
887  H[0][0] = H[1][1] = H[2][2] = 1.0f;
888  // dV/dV=I; (expect velocity to measure the velocity)
889  H[3][3] = H[4][4] = H[5][5] = 1.0f;
890 
891  // dBb/dq (expected magnetometer readings in the horizontal plane)
892  // these equations were generated by Rhb(q)*Be which is the matrix that
893  // rotates the earth magnetic field into the horizontal plane, and then
894  // taking the partial derivative wrt each term in q. Maniuplated in
895  // matlab symbolic toolbox
896  const float Be_0 = Be[0];
897  const float Be_1 = Be[1];
898  const float a1 = q0*q3*2.0f+q1*q2*2.0f;
899  const float a1s = a1*a1;
900  const float a2 = q0*q0+q1*q1-q2*q2-q3*q3;
901  const float a2s = a2*a2;
902  const float a3 = 1.0f/powf(a1s+a2s,3.0f/2.0f)*(1.0f/2.0f);
903 
904  const float k1 = 1.0f/sqrtf(a1s + a2s);
905  const float k3 = a3*a2;
906  const float k4 = a2*4.0f;
907  const float k5 = a1*4.0f;
908  const float k6 = a3*a1;
909 
910  H[6][6] = Be_0*q0*k1*2.0f + Be_1*q3*k1*2.0f - Be_0*(q0*k4+q3*k5)*k3 - Be_1*(q0*k4+q3*k5)*k6;
911  H[6][7] = Be_0*q1*k1*2.0f + Be_1*q2*k1*2.0f - Be_0*(q1*k4+q2*k5)*k3 - Be_1*(q1*k4+q2*k5)*k6;
912  H[6][8] = Be_0*q2*k1*-2.0f + Be_1*q1*k1*2.0f + Be_0*(q2*k4-q1*k5)*k3 + Be_1*(q2*k4-q1*k5)*k6;
913  H[6][9] = Be_1*q0*k1*2.0f - Be_0*q3*k1*2.0f + Be_0*(q3*k4-q0*k5)*k3 + Be_1*(q3*k4-q0*k5)*k6;
914  H[7][6] = Be_1*q0*k1*2.0f - Be_0*q3*k1*2.0f - Be_1*(q0*k4+q3*k5)*k3 + Be_0*(q0*k4+q3*k5)*k6;
915  H[7][7] = Be_0*q2*k1*-2.0f + Be_1*q1*k1*2.0f - Be_1*(q1*k4+q2*k5)*k3 + Be_0*(q1*k4+q2*k5)*k6;
916  H[7][8] = Be_0*q1*k1*-2.0f - Be_1*q2*k1*2.0f + Be_1*(q2*k4-q1*k5)*k3 - Be_0*(q2*k4-q1*k5)*k6;
917  H[7][9] = Be_0*q0*k1*-2.0f - Be_1*q3*k1*2.0f + Be_1*(q3*k4-q0*k5)*k3 - Be_0*(q3*k4-q0*k5)*k6;
918  H[8][6] = 0.0f;
919  H[8][7] = 0.0f;
920  H[8][9] = 0.0f;
921 
922  // dAlt/dPz = -1 (expected baro readings)
923  H[9][2] = -1.0f;
924 }
925 
void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX])
float F[NUMX][NUMX]
Definition: insgps14state.c:63
void INSSetArmed(bool armed)
Set the current flight state.
void INSSetAccelBias(const float accel_bias[3])
float H[NUMV][NUMX]
Definition: insgps14state.c:63
void INSGetVariance(float *var_out)
float Q[NUMW]
Definition: insgps14state.c:67
void INSPosVelReset(const float pos[3], const float vel[3])
Include file of the INSGPS exposed functionality.
void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], float BaroAlt, uint16_t SensorsUsed)
float R[NUMV]
Definition: insgps14state.c:67
void INSSetAccelVar(const float accel_var[3])
void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX])
void INSGPSInit()
Definition: insgps14state.c:78
volatile int j
Definition: loadabletest.c:12
float P[NUMX][NUMX]
Definition: insgps14state.c:66
#define K2
Definition: lqg.c:117
void INSGetState(float *pos, float *vel, float *attitude, float *gyro_bias, float *accel_bias)
#define NUMX
Definition: insgps14state.c:38
void INSSetGyroVar(const float gyro_var[3])
#define NUMW
Definition: insgps14state.c:39
void INSSetMagNorth(const float B[3])
static float T[3]
Scales used in NED transform (local tangent plane approx).
Definition: attitude.c:210
static float accel_bias[3]
Definition: sensors.c:114
void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], float Q[NUMW], float dT, float P[NUMX][NUMX])
void INSSetGyroBias(const float gyro_bias[3])
uint16_t ins_get_num_states()
Definition: insgps14state.c:73
struct _msp_pid_item pos
Definition: msp_messages.h:100
#define NUMU
Definition: insgps14state.c:41
uint8_t i
Definition: msp_messages.h:97
void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT)
void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], uint16_t SensorsUsed)
void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], float G[NUMX][NUMW])
#define NUMV
Definition: insgps14state.c:40
#define MAG_SENSORS
Definition: insgps.h:44
float Be[3]
Definition: insgps14state.c:65
void INSSetMagVar(const float scaled_mag_var[3])
void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV])
#define K1
Definition: lqg.c:116
void INSSetPosVelVar(float PosVar, float VelVar, float VertPosVar)
void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], const float accel_bias[3])
tuple f
Definition: px_mkfw.py:81
void INSResetP(const float *PDiag)
void INSSetBaroVar(const float baro_var)
float X[NUMX]
Definition: insgps14state.c:66
void INSLimitBias()
void INSCovariancePrediction(float dT)
float K[NUMX][NUMV]
Definition: insgps14state.c:68
float G[NUMX][NUMW]
Definition: insgps14state.c:63
void RungeKutta(float X[NUMX], float U[NUMU], float dT)
struct _msp_pid_item vel
Definition: msp_messages.h:105