blob: fce3a56cf364de67030cec2e53bf412c8766482c [file] [log] [blame]
Brian Silverman8d3816a2017-07-03 18:52:15 -07001#ifndef MOTORS_MATH_H_
2#define MOTORS_MATH_H_
3
4#include <limits.h>
5
6#include <complex>
7#include <ratio>
8
9// This file has some specialized math functions useful for implementing our
10// controls in a minimal number of cycles.
11
12namespace frc971 {
13namespace salsa {
14
15inline constexpr unsigned int Log2RoundUp(unsigned int x) {
16 return (x < 2) ? x : (1 + Log2RoundUp(x / 2));
17}
18
19template <typename T>
20inline constexpr const T &ConstexprMax(const T &a, const T &b) {
21 return (a < b) ? b : a;
22}
23
24namespace math_internal {
25
Brian Silvermana6e53b42018-01-03 20:33:15 -080026constexpr uint32_t SinCosTableSize() { return 4096; }
Brian Silverman8d3816a2017-07-03 18:52:15 -070027
28constexpr float FloatMaxMagnitude() { return 1.0f; }
29
30constexpr bool IsPowerOf2(uint32_t value) {
31 return value == (1u << (Log2RoundUp(value) - 1));
32}
33
34static_assert(IsPowerOf2(SinCosTableSize()), "Tables need to be a power of 2");
35
36extern float sin_int_table[SinCosTableSize()];
37extern float cos_int_table[SinCosTableSize()];
38extern float sin_float_table[SinCosTableSize() + 1];
39extern float cos_float_table[SinCosTableSize() + 1];
40
41template <class Rotation>
42float FastTableLookupInt(uint32_t theta, const float *table) {
43 static_assert(IsPowerOf2(Rotation::den),
44 "Denominator needs to be a power of 2");
45
46 // Don't need to worry about the sizes of intermediates given this constraint.
47 static_assert(
48 ConstexprMax<uint32_t>(Rotation::den, SinCosTableSize()) * Rotation::num <
49 UINT32_MAX,
50 "Numerator and denominator are too big");
51
52 // Rounding/truncating here isn't supported.
53 static_assert(Rotation::den <= SinCosTableSize(),
54 "Tables need to be bigger");
55
56 // Don't feel like thinking through the consequences of this not being true.
57 static_assert(Rotation::num > 0 && Rotation::den > 0,
58 "Need a positive ratio");
59
60 constexpr uint32_t kDenominatorRatio = SinCosTableSize() / Rotation::den;
61
62 // These should always be true given the other constraints.
63 static_assert(kDenominatorRatio * Rotation::den == SinCosTableSize(),
64 "Math is broken");
65 static_assert(IsPowerOf2(kDenominatorRatio), "Math is broken");
66
67 return table[(theta * kDenominatorRatio * Rotation::num +
68 kDenominatorRatio * Rotation::num / 2) %
69 SinCosTableSize()];
70}
71
72inline float FastTableLookupFloat(float theta, const float *table) {
Brian Silvermana6e53b42018-01-03 20:33:15 -080073 static constexpr float kScalar =
74 (SinCosTableSize() / 2) / FloatMaxMagnitude();
75 const int index =
76 (SinCosTableSize() / 2) + static_cast<int32_t>(theta * kScalar);
Brian Silverman8d3816a2017-07-03 18:52:15 -070077 return table[index];
78}
79
80} // namespace math_internal
81
82// All theta arguments to the float-based functions must be in [-0.2, 0.2].
83
84inline float FastSinFloat(float theta) {
85 return math_internal::FastTableLookupFloat(theta,
86 math_internal::sin_float_table);
87}
88
89inline float FastCosFloat(float theta) {
90 return math_internal::FastTableLookupFloat(theta,
91 math_internal::cos_float_table);
92}
93
94inline ::std::complex<float> ImaginaryExpFloat(float theta) {
95 return ::std::complex<float>(FastCosFloat(theta), FastSinFloat(theta));
96}
97
98// The integer-based sin/cos functions all have a Rotation template argument,
99// which should be a ::std::ratio. The real argument to the trigonometric
100// function is this ratio multiplied by the theta argument.
101//
102// Specifically, they return the function evaluated at
103// (Rotation * (theta + 0.5)).
104//
105// All theta arguments must be in [0, Rotation::den).
106//
107// All denominators must be powers of 2.
108
109template<class Rotation>
110float FastSinInt(uint32_t theta) {
111 return math_internal::FastTableLookupInt<Rotation>(
112 theta, math_internal::sin_int_table);
113}
114
115template<class Rotation>
116float FastCosInt(uint32_t theta) {
117 return math_internal::FastTableLookupInt<Rotation>(
118 theta, math_internal::cos_int_table);
119}
120
121template<class Rotation>
122::std::complex<float> ImaginaryExpInt(uint32_t theta) {
123 return ::std::complex<float>(FastCosInt<Rotation>(theta),
124 FastSinInt<Rotation>(theta));
125}
126
127void MathInit();
128
129} // namespace salsa
130} // namespace frc971
131
132#endif // MOTORS_MATH_H_