dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
misc_math.h
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 #ifndef MISC_MATH_H
32 #define MISC_MATH_H
33 
34 #include <math.h>
35 
36 #include "stdint.h"
37 #include "stdbool.h"
38 
39 // Max/Min macros. Taken from http://stackoverflow.com/questions/3437404/min-and-max-in-c
40 #define MAX(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
41 #define MIN(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
42 
44 #define sign(x) ((x) < 0 ? -1 : 1)
45 
47 float bound_sym(float val, float range);
48 
50 float bound_min_max(float val, float min, float max);
51 
53 float circular_modulus_deg(float err);
54 float circular_modulus_rad(float err);
55 
57 float expo3(float x, int32_t g);
58 float expoM(float x, int32_t g, float exponent);
59 
60 float interpolate_value(const float fraction, const float beginVal,
61  const float endVal);
62 float vectorn_magnitude(const float *v, int n);
63 float vector3_distances(const float *actual,
64  const float *desired, float *out, bool normalize);
65 void vector2_clip(float *vels, float limit);
66 void vector2_rotate(const float *original, float *out, float angle);
67 float cubic_deadband(float in, float w, float b, float m, float r);
68 void cubic_deadband_setup(float w, float b, float *m, float *r);
69 float linear_interpolate(float const input, float const * curve, uint8_t num_points, const float input_min, const float input_max);
70 void randomize_addseed(uint32_t seed);
71 uint32_t randomize_int(uint32_t interval);
72 void apply_channel_deadband(float *value, float deadband);
73 
74 /* Note--- current compiler chain has been verified to produce proper call
75  * to fpclassify even when compiling with -ffast-math / -ffinite-math.
76  * Previous attempts were made here to limit scope of disabling those
77  * optimizations to this function, but were infectious and increased
78  * stack usage across unrelated code because of compiler limitations.
79  * See TL issue #1879.
80  */
81 static inline bool IS_NOT_FINITE(float x) {
82  return (!isfinite(x));
83 }
84 
90 static inline int16_t sin_approx(int32_t x)
91 {
92 #define s_qN 13
93 #define s_qP 15
94 #define s_qA 12
95  static const int
96  qR= 2*s_qN - s_qP,
97  qS= s_qN + s_qP + 1 - s_qA;
98 
99  x= x<<(30-s_qN); // shift to full s32 range (Q13->Q30)
100 
101  if( (x^(x<<1)) < 0) // test for quadrant 1 or 2
102  x= (1<<31) - x;
103 
104  x= x>>(30-s_qN);
105 
106  return x * ( (3<<s_qP) - (x*x>>qR) ) >> qS;
107 }
108 
121 static inline void matrix_mul(const float *a, const float *b,
122  float *out, int arows, int acolsbrows, int bcols)
123 {
124  const float *restrict apos = a;
125  float *restrict opos = out;
126 
127  for (int ar = 0; ar < arows; ar++) {
128  for (int bc = 0 ; bc < bcols; bc++) {
129  float sum = 0;
130 
131  const float *restrict bpos = b + bc;
132 
133  int acbr;
134 
135  /* This is manually unrolled. -Os doesn't really want to
136  * unroll things, but this is a case where we want to
137  * encourage it to.
138  *
139  * This structure was chosen / experimented with across
140  * many compilers to always do the right things-- namely
141  *
142  * A) vectorize when appropriate on the architecture
143  * B) eliminate the loop when there's a static, small number
144  * of cols (10 or less)
145  * C) generate pretty good code when the dimensions aren't
146  * known.
147  */
148  for (acbr = 0; acbr < (acolsbrows & (~3)); acbr += 4) {
149  /*
150  sum += a[ar * acolsbrows + acbr] *
151  b[acbr * bcols + bc];
152  */
153 
154  sum += (apos[acbr]) * (*bpos);
155  bpos += bcols;
156  sum += (apos[acbr+1]) * (*bpos);
157  bpos += bcols;
158  sum += (apos[acbr+2]) * (*bpos);
159  bpos += bcols;
160  sum += (apos[acbr+3]) * (*bpos);
161  bpos += bcols;
162  }
163 
164  for (; acbr < acolsbrows; acbr++) {
165  /*
166  sum += a[ar * acolsbrows + acbr] *
167  b[acbr * bcols + bc];
168  */
169 
170  sum += (apos[acbr]) * (*bpos);
171  bpos += bcols;
172  }
173  /* out[ar * bcols + bc] = sum; */
174 
175  *opos = sum;
176 
177  opos++;
178  }
179 
180  apos += acolsbrows;
181  }
182 }
183 
193 static inline void matrix_mul_scalar(const float *a, float scalar, float *out,
194  int rows, int cols)
195 {
196  int size = rows * cols;
197 
198  const float * apos = a;
199 
200  for (int i = 0; i < size; i++) {
201  *out = (*apos) * scalar;
202  apos++; out++;
203  }
204 }
205 
216 static inline void matrix_add(const float *a, const float *b,
217  float *out, int rows, int cols)
218 {
219  int size = rows * cols;
220 
221  const float * apos = a;
222  const float * bpos = b;
223  float * opos = out;
224 
225  for (int i = 0; i < size; i++) {
226  *opos = (*apos) + (*bpos);
227  apos++; bpos++; opos++;
228  }
229 }
230 
241 static inline void matrix_sub(const float *a, const float *b,
242  float *out, int rows, int cols)
243 {
244  int size = rows * cols;
245 
246  const float * apos = a;
247  const float * bpos = b;
248  float * opos = out;
249 
250  for (int i = 0; i < size; i++) {
251  *opos = (*apos) - (*bpos);
252  apos++; bpos++; opos++;
253  }
254 }
255 
265 static inline void matrix_transpose(const float *a, float *out, int arows,
266  int acols)
267 {
268  for (int i = 0; i < arows; i++) {
269  for (int j = 0; j < acols; j++) {
270  out[j * arows + i] = a[i * acols + j];
271  }
272  }
273 }
274 
275 #define TOL_EPS 0.0001f
276 
277 /* Not intended for outside use (at least just yet). Sees whether
278  * a and b look like good inverses.
279  */
280 static inline bool matrix_pseudoinv_convergecheck(const float *a,
281  const float *b, const float *prod, int rows, int cols)
282 {
283  const float *pos = prod;
284  bool ret = true;
285 
286  /* Product (desired pseudo identity matrix) is cols*cols */
287  for (int i = 0; i < cols; i++) {
288  float sum = 0.0f;
289 
290  for (int j = 0; j < cols; j++) {
291  sum += *pos;
292 
293  pos++;
294  }
295 
296  /* It needs to be near 1 or 0 for us to be converged.
297  * First, return false if outside 0..1
298  */
299  if (sum > (1 + TOL_EPS)) {
300  ret = false;
301  break;
302  }
303 
304  if (sum < (0 - TOL_EPS)) {
305  ret = false;
306  break;
307  }
308 
309  /* Next, continue if very close to 1 or 0 */
310  if (sum > (1 - TOL_EPS)) {
311  continue;
312  }
313 
314  if (sum < (0 + TOL_EPS)) {
315  continue;
316  }
317 
318  /* We're between 0 and 1, outside of the tolerance */
319  ret = false;
320  break;
321  }
322 
323  if (ret) {
324  return true;
325  }
326 
327  /* Sometimes the pseudoidentity matrix doesn't meet this constraint; fall
328  * back to verifying elements.
329  * (Which in itself is numerically problematic)
330  */
331 
332  int elems = rows * cols;
333 
334  for (int i = 0; i < elems; i++) {
335  float diff = (a[i] - b[i]);
336 
337  /* This strange structure chosen because NaNs will return false
338  * to both of these...
339  */
340  if (diff < TOL_EPS) {
341  if (diff > -TOL_EPS) {
342  continue;
343  }
344  }
345 
346  return false;
347  }
348 
349  return true;
350 }
351 
352 /* Not intended for outside use. Performs one step of the pseudoinverse
353  * approximation by calculating 2 * ainv - ainv * a * ainv */
354 static inline bool matrix_pseudoinv_step(const float *a, float *ainv,
355  int arows, int acols)
356 {
357  float prod[acols * acols];
358  float invcheck[acols * arows];
359 
360  /* Calculate 2 * ainv - ainv * a * ainv */
361 
362  /* prod = ainv * a */
363  matrix_mul(ainv, a, prod, acols, arows, acols);
364 
365  /* invcheck = prod * ainv */
366  matrix_mul(prod, ainv, invcheck, acols, acols, arows);
367 
368  if (matrix_pseudoinv_convergecheck(ainv, invcheck, prod, arows, acols)) {
369  return true;
370  }
371 
372  /* ainv_ = 2 * ainv */
373  matrix_mul_scalar(ainv, 2, ainv, acols, arows);
374 
375  /* ainv__ = ainv_ - invcheck */
376  /* AKA expanded ainv__ = 2 * ainv - ainv * a * ainv */
377  matrix_sub(ainv, invcheck, ainv, acols, arows);
378 
379  return false;
380 }
381 
388 static inline float matrix_getmaxabs(const float *a, int arows, int acols)
389 {
390  float mx = 0.0f;
391 
392  const int size = arows * acols;
393 
394  for (int i = 0; i < size; i ++) {
395  float val = fabsf(a[i]);
396 
397  if (val > mx) {
398  mx = val;
399  }
400  }
401 
402  return mx;
403 }
404 
405 #ifndef PSEUDOINV_CONVERGE_LIMIT
406 #define PSEUDOINV_CONVERGE_LIMIT 75
407 #endif
408 
423 static inline bool matrix_pseudoinv(const float *a, float *out,
424  int arows, int acols)
425 {
426  matrix_transpose(a, out, arows, acols);
427 
428  float scale = matrix_getmaxabs(a, arows, acols);
429 
430  matrix_mul_scalar(out, 0.01f / scale, out, acols, arows);
431 
432  for (int i = 0; i < PSEUDOINV_CONVERGE_LIMIT; i++) {
433  if (matrix_pseudoinv_step(a, out, arows, acols)) {
434  /* Do one more step when we look pretty good! */
435  matrix_pseudoinv_step(a, out, arows, acols);
436 
437  return true;
438  }
439  }
440 
441  return false;
442 }
443 
444 /* The following are wrappers which attempt to do compile-time checking of
445  * array dimensions.
446  */
447 #define matrix_mul_check(a, b, out, arows, acolsbrows, bcols) \
448  do { \
449  /* Note the dimensions each get used multiple times */ \
450  const float (*my_a)[arows*acolsbrows] = &(a); \
451  const float (*my_b)[acolsbrows*bcols] = &(b); \
452  float (*my_out)[arows*bcols] = &(out); \
453  matrix_mul(*my_a, *my_b, *my_out, arows, acolsbrows, bcols); \
454  } while (0);
455 
456 #define matrix_mul_scalar_check(a, scalar, out, rows, cols) \
457  do { \
458  /* Note the dimensions each get used multiple times */ \
459  const float (*my_a)[rows*cols] = &(a); \
460  float (*my_out)[rows*cols] = &(out); \
461  matrix_mul_scalar(*my_a, scalar, my_out, rows, cols); \
462  } while (0);
463 
464 #define matrix_add_check(a, b, out, rows, cols) \
465  do { \
466  /* Note the dimensions each get used multiple times */ \
467  const float (*my_a)[rows*cols] = &(a); \
468  const float (*my_b)[rows*cols] = &(b); \
469  float (*my_out)[rows*cols] = &(out); \
470  matrix_add(*my_a, *my_b, *my_out, rows, cols) \
471  } while (0);
472 
473 #define matrix_sub_check(a, b, out, rows, cols) \
474  do { \
475  /* Note the dimensions each get used multiple times */ \
476  const float (*my_a)[rows*cols] = &(a); \
477  const float (*my_b)[rows*cols] = &(b); \
478  float (*my_out)[rows*cols] = &(out); \
479  matrix_sub(*my_a, *my_b, *my_out, rows, cols) \
480  } while (0);
481 
482 #define matrix_transpose_check(a, b, out, rows, cols) \
483  do { \
484  /* Note the dimensions each get used multiple times */ \
485  const float (*my_a)[rows*cols] = &(a); \
486  const float (*my_b)[rows*cols] = &(b); \
487  float (*my_out)[rows*cols] = &(out); \
488  matrix_transpose(*my_a, *my_b, *my_out, rows, cols) \
489  } while (0);
490 
491 /* Following functions from fastapprox https://code.google.com/p/fastapprox/
492  * are governed by this license agreement: */
493 
494 /*=====================================================================*
495  * Copyright (C) 2011 Paul Mineiro *
496  * All rights reserved. *
497  * *
498  * Redistribution and use in source and binary forms, with *
499  * or without modification, are permitted provided that the *
500  * following conditions are met: *
501  * *
502  * * Redistributions of source code must retain the *
503  * above copyright notice, this list of conditions and *
504  * the following disclaimer. *
505  * *
506  * * Redistributions in binary form must reproduce the *
507  * above copyright notice, this list of conditions and *
508  * the following disclaimer in the documentation and/or *
509  * other materials provided with the distribution. *
510  * *
511  * * Neither the name of Paul Mineiro nor the names *
512  * of other contributors may be used to endorse or promote *
513  * products derived from this software without specific *
514  * prior written permission. *
515  * *
516  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
517  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
518  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
519  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
520  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER *
521  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
522  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
523  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE *
524  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
525  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
526  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
527  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
528  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
529  * POSSIBILITY OF SUCH DAMAGE. *
530  * *
531  * Contact: Paul Mineiro <paul@mineiro.com> *
532  *=====================================================================*/
533 
534 #ifdef __cplusplus
535 #define cast_uint32_t static_cast<uint32_t>
536 #else
537 #define cast_uint32_t (uint32_t)
538 #endif
539 
540 static inline float
541 fastlog2 (float x)
542 {
543  union { float f; uint32_t i; } vx = { x };
544  union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | (0x7e << 23) };
545  float y = vx.i;
546  y *= 1.0f / (1 << 23);
547 
548  return y - 124.22551499f
549  - 1.498030302f * mx.f
550  - 1.72587999f / (0.3520887068f + mx.f);
551 }
552 
553 static inline float
554 fastpow2 (float p)
555 {
556  float offset = (p < 0) ? 1.0f : 0.0f;
557  int w = p;
558  float z = p - w + offset;
559  union { uint32_t i; float f; } v = { cast_uint32_t ((1 << 23) * (p + 121.2740838f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z)) };
560 
561  return v.f;
562 }
563 
564 
565 static inline float
566 fastpow (float x, float p)
567 {
568  return fastpow2 (p * fastlog2 (x));
569 }
570 
571 static inline float
572 fastexp (float p)
573 {
574  return fastpow2 (1.442695040f * p);
575 }
576 
577 /* Use full versions for now on all targets */
578 #define powapprox powf
579 #define expapprox expf
580 
581 #endif /* MISC_MATH_H */
582 
float cubic_deadband(float in, float w, float b, float m, float r)
Definition: misc_math.c:246
float expoM(float x, int32_t g, float exponent)
Definition: misc_math.c:116
float circular_modulus_rad(float err)
Definition: misc_math.c:86
static void matrix_sub(const float *a, const float *b, float *out, int rows, int cols)
Subtracts two matrices Can safely be done in-place. (e.g. is slow and not vectorized/unrolled) ...
Definition: misc_math.h:241
static float scale(float val, float inMin, float inMax, float outMin, float outMax)
Definition: txpid.c:444
float vector3_distances(const float *actual, const float *desired, float *out, bool normalize)
Definition: misc_math.c:178
#define cast_uint32_t
Definition: misc_math.h:537
volatile int j
Definition: loadabletest.c:12
static bool matrix_pseudoinv_step(const float *a, float *ainv, int arows, int acols)
Definition: misc_math.h:354
#define s_qA
static bool matrix_pseudoinv(const float *a, float *out, int arows, int acols)
Finds a pseudo-inverse of a matrix.
Definition: misc_math.h:423
static float fastpow(float x, float p)
Definition: misc_math.h:566
#define s_qP
float interpolate_value(const float fraction, const float beginVal, const float endVal)
Definition: misc_math.c:145
#define PSEUDOINV_CONVERGE_LIMIT
Definition: misc_math.h:406
static float fastlog2(float x)
Definition: misc_math.h:541
static bool matrix_pseudoinv_convergecheck(const float *a, const float *b, const float *prod, int rows, int cols)
Definition: misc_math.h:280
#define restrict
Definition: unittest.cpp:41
float circular_modulus_deg(float err)
Circular modulus.
Definition: misc_math.c:62
static void matrix_add(const float *a, const float *b, float *out, int rows, int cols)
Adds two matrices Can safely be done in-place. (e.g. is slow and not vectorized/unrolled) ...
Definition: misc_math.h:216
static int16_t sin_approx(int32_t x)
Fast approximation of sine; 3rd order taylor expansion. Based on http://www.coranac.com/2009/07/sines/.
Definition: misc_math.h:90
struct _msp_pid_item pos
Definition: msp_messages.h:100
void apply_channel_deadband(float *value, float deadband)
Apply deadband to Roll/Pitch/Yaw channels.
Definition: misc_math.c:373
static void matrix_mul_scalar(const float *a, float scalar, float *out, int rows, int cols)
Multiplies a matrix by a scalar Can safely be done in-place. (e.g. is slow and not vectorized/unrolle...
Definition: misc_math.h:193
void vector2_clip(float *vels, float limit)
Definition: misc_math.c:208
uint32_t randomize_int(uint32_t interval)
Definition: misc_math.c:340
uint8_t i
Definition: msp_messages.h:97
float bound_min_max(float val, float min, float max)
Bound input value between min and max.
Definition: misc_math.c:38
float bound_sym(float val, float range)
Bound input value within range (plus or minus)
Definition: misc_math.c:50
static void matrix_mul(const float *a, const float *b, float *out, int arows, int acolsbrows, int bcols)
Multiplies out = a b.
Definition: misc_math.h:121
uint16_t value
Definition: storm32bgc.c:155
void cubic_deadband_setup(float w, float b, float *m, float *r)
Definition: misc_math.c:266
uint32_t offset
Definition: uavtalk_priv.h:51
static float matrix_getmaxabs(const float *a, int arows, int acols)
Finds the largest value in a matrix.
Definition: misc_math.h:388
static float fastexp(float p)
Definition: misc_math.h:572
tuple f
Definition: px_mkfw.py:81
void randomize_addseed(uint32_t seed)
Definition: misc_math.c:315
float linear_interpolate(float const input, float const *curve, uint8_t num_points, const float input_min, const float input_max)
Definition: misc_math.c:290
#define s_qN
#define TOL_EPS
Definition: misc_math.h:275
float vectorn_magnitude(const float *v, int n)
Definition: misc_math.c:159
static void matrix_transpose(const float *a, float *out, int arows, int acols)
Transposes a matrix.
Definition: misc_math.h:265
uint8_t p
Definition: msp_messages.h:96
static float fastpow2(float p)
Definition: misc_math.h:554
uint16_t max
Definition: msp_messages.h:97
float expo3(float x, int32_t g)
Approximation an exponential scale curve.
Definition: misc_math.c:111
void vector2_rotate(const float *original, float *out, float angle)
Definition: misc_math.c:225
uint16_t min
Definition: msp_messages.h:96
static bool IS_NOT_FINITE(float x)
Definition: misc_math.h:81