Skip to content

Commit 309c294

Browse files
committed
Avoid reevaluating arguments.
_round, _constrain and _sign currently reevaluate their arguments, which wastes CPU cycles. In torque/foc_current mode, this fix saves about 300ns/foc loop (about 2% of total CPU usage). In other modes, especially estimated_current, it saves more.
1 parent 7f9c45f commit 309c294

1 file changed

Lines changed: 47 additions & 5 deletions

File tree

src/common/foc_utils.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,54 @@
33

44
#include "Arduino.h"
55

6-
// sign function
7-
#define _sign(a) ( ( (a) < 0 ) ? -1 : ( (a) > 0 ) )
6+
template<typename T>
7+
constexpr inline int _sign(T val) {
8+
return __builtin_signbit(val);
9+
}
10+
11+
#ifndef __AVR__
12+
#include <type_traits>
13+
814
#ifndef _round
9-
#define _round(x) ((x)>=0?(long)((x)+0.5f):(long)((x)-0.5f))
15+
// Use enable_if to select the roundf function for single precision floats.
16+
// This improves performance when -ffast-math is not set.
17+
template<typename T>
18+
constexpr inline typename std::enable_if<std::is_same<T, float>::value, long>::type _round(T x) {
19+
return __builtin_roundf(x);
20+
}
21+
template<typename T>
22+
constexpr inline typename std::enable_if<std::is_same<T, double>::value, long>::type _round(T x) {
23+
return __builtin_round(x);
24+
}
25+
#endif
26+
27+
// Use enable_if to select the fastest implementation according to the amt type.
28+
// Using __builtin_fXf is measurably faster than using the ternary approach.
29+
template<typename T, typename L, typename H>
30+
constexpr inline typename std::enable_if<std::is_integral<T>::value, T>::type _constrain(T amt, L low, H high) {
31+
return (amt < low) ? low : (amt > high) ? high : amt;
32+
}
33+
template<typename T, typename L, typename H>
34+
constexpr inline typename std::enable_if<std::is_same<T, float>::value, T>::type _constrain(T amt, L low, H high) {
35+
return __builtin_fmaxf(low, __builtin_fminf(high, amt));
36+
}
37+
template<typename T, typename L, typename H>
38+
constexpr inline typename std::enable_if<std::is_same<T, double>::value, T>::type _constrain(T amt, L low, H high) {
39+
return __builtin_fmax(low, __builtin_fmin(high, amt));
40+
}
41+
#else // __AVR__
42+
// AVR compiler lacks type_traits, so we are forced to use the slower non-type inferenced
43+
// version. That's okay, right? If you wanted to go fast you would not be on AVR.
44+
template<typename T>
45+
constexpr long _round(T x) {
46+
return __builtin_round(x);
47+
}
48+
template<typename T, typename L, typename H>
49+
constexpr T _constrain(T amt, L low, H high) {
50+
return (amt < low) ? low : (amt > high) ? high : amt;
51+
}
1052
#endif
11-
#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
53+
1254
#define _sqrt(a) (_sqrtApprox(a))
1355
#define _isset(a) ( (a) != (NOT_SET) )
1456
#define _UNUSED(v) (void) (v)
@@ -121,4 +163,4 @@ float _electricalAngle(float shaft_angle, int pole_pairs);
121163
*/
122164
float _sqrtApprox(float value);
123165

124-
#endif
166+
#endif

0 commit comments

Comments
 (0)