dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
misc_math.c
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  */
29 
30 #include <stdbool.h>
31 #include <math.h>
32 #include "misc_math.h" /* API declarations */
33 #include "physical_constants.h"
34 
38 float bound_min_max(float val, float min, float max)
39 {
40  if (val < min)
41  return min;
42  if (val > max)
43  return max;
44  return val;
45 }
46 
50 float bound_sym(float val, float range)
51 {
52  return (bound_min_max(val, -range, range));
53 }
54 
62 float circular_modulus_deg(float err)
63 {
64  float val = fmodf(err + 180.0f, 360.0f);
65 
66  // fmodf converts negative values into the negative remainder
67  // so we must add 360 to make sure this ends up correct and
68  // behaves like positive output modulus
69  if (val < 0)
70  val += 180;
71  else
72  val -= 180;
73 
74  return val;
75 
76 }
77 
78 
86 float circular_modulus_rad(float err)
87 {
88  float val = fmodf(err + PI, 2*PI);
89 
90  // fmodf converts negative values into the negative remainder
91  // so we must add 360 to make sure this ends up correct and
92  // behaves like positive output modulus
93  if (val < 0)
94  val += PI;
95  else
96  val -= PI;
97 
98  return val;
99 
100 }
101 
111 float expo3(float x, int32_t g)
112 {
113  return (x * ((100 - g) / 100.0f) + powf(x, 3) * (g / 100.0f));
114 }
115 
116 float expoM(float x, int32_t g, float exponent) {
117  float out = x * (100 - g) * .01f;
118 
119  if (x > 0) {
120  out += powapprox(x, exponent) * g * 0.01f;
121  } else {
122  out -= powapprox(-x, exponent) * g * 0.01f;
123  }
124 
125  if (out < -1) {
126  return -1;
127  }
128 
129  if (out > 1) {
130  return 1;
131  }
132 
133  return out;
134 }
135 
145 float interpolate_value(const float fraction, const float beginVal,
146  const float endVal) {
147  return beginVal + (endVal - beginVal) * bound_min_max(fraction, 0, 1);
148 }
149 
159 float vectorn_magnitude(const float *v, int n)
160 {
161  float sum=0;
162 
163  for (int i=0; i<n; i++) {
164  sum += powf(v[i], 2);
165  }
166 
167  return sqrtf(sum);
168 }
169 
178 float vector3_distances(const float *actual,
179  const float *desired, float *out, bool normalize)
180 {
181  out[0] = desired[0] - actual[0];
182  out[1] = desired[1] - actual[1];
183  out[2] = desired[2] - actual[2];
184 
185  if (normalize) {
186  float mag=vectorn_magnitude(out, 3);
187 
188  if (mag < 0.00001f) {
189  /* Just pick a direction. */
190  out[0] = 1.0; out[1] = 0.0; out[2] = 0.0;
191  } else {
192  out[0] /= mag; out[1] /= mag; out[2] /= mag;
193  }
194 
195  return mag;
196  }
197 
198  return 0.0;
199 }
200 
208 void vector2_clip(float *vels, float limit)
209 {
210  float mag = vectorn_magnitude(vels, 2); // only horiz component
211 
212  if (mag > limit && mag != 0) {
213  float scale = limit / mag;
214  vels[0] *= scale;
215  vels[1] *= scale;
216  }
217 }
218 
225 void vector2_rotate(const float *original, float *out, float angle) {
226  angle *= DEG2RAD;
227 
228  out[0] = original[0] * cosf(angle) - original[1] * sinf(angle);
229  out[1] = original[0] * sinf(angle) + original[1] * cosf(angle);
230 }
231 
246 float cubic_deadband(float in, float w, float b, float m, float r)
247 {
248  // First get the nice linear bits -- outside the deadband-- out of
249  // the way.
250  if (in <= -w) {
251  return in+w-r;
252  } else if (in >= w) {
253  return in-w+r;
254  }
255 
256  return powf(m*in, 3)+b*in;
257 }
258 
266 void cubic_deadband_setup(float w, float b, float *m, float *r)
267 {
268  /* So basically.. we want the function to be tangent to the
269  ** linear sections-- have a slope of 1-- at -w and w. In the
270  ** middle we want a slope of b. So the cube here does all the
271  ** work b isn't doing. */
272  *m = cbrtf((1-b)/(3*powf(w,2)));
273 
274  *r = powf(*m*w, 3)+b*w;
275 }
276 
290 float linear_interpolate(float const input, float const * curve, uint8_t num_points, const float input_min, const float input_max)
291 {
292  // shift our input [min,max] into the typical range [0,1]
293  float scale = fmaxf( (input - input_min) / (input_max - input_min), 0.0f) * (float) (num_points - 1);
294  // select a starting bin via truncation
295  int idx1 = scale;
296  // save the offset from the starting bin for linear interpolation
297  scale -= (float)idx1;
298  // select an ending bin (linear interpolation occurs between starting and ending bins)
299  int idx2 = idx1 + 1;
300  // if the ending bin bin is above the last bin
301  if (idx2 >= num_points) {
302  //clamp to highest entry in table
303  idx2 = num_points -1;
304  // if the starting bin is above the last bin
305  if (idx1 >= num_points) {
306  // we no longer do interpolation; instead, we just select the max point on the curve
307  return curve[num_points-1];
308  }
309  }
310  return curve[idx1] * (1.0f - scale) + curve[idx2] * scale;
311 }
312 
313 static uint32_t random_state[4] = { 0xdeadbeef, 0xfeedfeed, 0xcafebabe, 1234 };
314 
315 void randomize_addseed(uint32_t seed)
316 {
317  randomize_int(0);
318  random_state[0] ^= seed;
319 }
320 
321 static uint32_t randomize_int32()
322 {
323  /* TODO: Not re-entrant. Need to think how best to handle this
324  * once there's more users of this API.
325  */
326 
327  /* Xorshift 128 bit variant RNG */
328  uint32_t t = random_state[3] ^ (random_state[3] << 11);
329  t ^= t >> 8;
330  t ^= random_state[0] ^ (random_state[0] >> 19);
331 
332  random_state[3] = random_state[2];
333  random_state[2] = random_state[1];
334  random_state[1] = random_state[0];
335  random_state[0] = t;
336 
337  return t;
338 }
339 
340 uint32_t randomize_int(uint32_t interval)
341 {
342  /* TODO: This could improve a lot from constant static
343  * value evaluation in the optimizer, so it may belong in
344  * the header as inline...
345  */
346  uint32_t thresh = UINT32_MAX;
347  uint32_t rand_val;
348 
349  if (interval) {
350  uint32_t remainder = UINT32_MAX % interval;
351 
352  if (remainder != (interval - 1)) {
353  thresh -= remainder + 1;
354  }
355  }
356 
357  /* All of this junk is here so we can avoid biases by retrying
358  * in the case of really large drawn numbers */
359  do {
360  rand_val = randomize_int32();
361  } while (rand_val > thresh);
362 
363  if (interval == 0) {
364  return rand_val;
365  }
366 
367  return rand_val % interval;
368 }
369 
373 void apply_channel_deadband(float *value, float deadband)
374 {
375  if (deadband < 0.0001f) return; /* ignore tiny deadband value */
376  if (deadband >= 0.85f) return; /* reject nonsensical db values */
377 
378  if (fabsf(*value) < deadband) {
379  *value = 0.0f;
380  } else {
381  if (*value > 0.0f) {
382  *value -= deadband;
383  } else {
384  *value += deadband;
385  }
386 
387  *value /= (1 - deadband);
388  }
389 }
390 
float cubic_deadband(float in, float w, float b, float m, float r)
Definition: misc_math.c:246
struct _msp_pid_item mag
Definition: msp_messages.h:104
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 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
static uint32_t randomize_int32()
Definition: misc_math.c:321
float interpolate_value(const float fraction, const float beginVal, const float endVal)
Definition: misc_math.c:145
float circular_modulus_deg(float err)
Circular modulus.
Definition: misc_math.c:62
#define powapprox
Definition: misc_math.h:578
#define PI
Definition: mgrs.c:136
void apply_channel_deadband(float *value, float deadband)
Apply deadband to Roll/Pitch/Yaw channels.
Definition: misc_math.c:373
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
uint16_t value
Definition: storm32bgc.c:155
void cubic_deadband_setup(float w, float b, float *m, float *r)
Definition: misc_math.c:266
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
float vectorn_magnitude(const float *v, int n)
Definition: misc_math.c:159
static uint32_t random_state[4]
Definition: misc_math.c:313
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