-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphysics.hpp
209 lines (177 loc) · 5.26 KB
/
physics.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#ifndef NXC_PHYSICS_INCLUDED
#define NXC_PHYSICS_INCLUDED
#include "cpp_utils/common.hpp"
#include <cmath>
#include <concepts>
#include <chrono>
#include <functional>
#include <numbers>
namespace nxc::physics
{
template <typename Angle>
constexpr auto pi = std::numbers::pi_v<Angle>;
template <typename Angle>
constexpr Angle full_angle = 2 * pi<Angle>;
template <typename Angle>
requires (std::signed_integral<Angle> || std::floating_point<Angle>)
struct radians
{
private:
Angle m_value; // always [0;2*pi)
public:
radians() = default;
radians(const Angle angle)
: m_value{ fmod(angle, full_angle<Angle>) }
{}
radians& operator+=(const radians right)
{
return *this = (m_value + right.m_value);
}
radians& operator-=(const radians right)
{
return *this = (m_value - right.m_value + full_angle<Angle>);
}
radians operator+(const radians right) const
{
return radians{ *this } += right;
}
radians operator-(const radians right) const
{
return radians{ *this } -= right;
}
constexpr Angle value() const { return m_value; }
};
template <typename Angle>
inline auto sin(const radians<Angle> angle)
{
return ::sin(angle.value());
}
template <typename Angle>
inline auto cos(const radians<Angle> angle)
{
return ::cos(angle.value());
}
template <typename T>
concept chrono_duration =
std::same_as<const volatile T, const volatile std::chrono::duration<typename T::rep, typename T::period>>;
template <typename T>
concept chrono_time_point =
std::same_as<const volatile T, const volatile std::chrono::time_point<typename T::clock, typename T::duration>>;
template <chrono_duration Duration>
constexpr auto freq_to_period(const auto hz)
{
using reduced_period = typename Duration::period::type;
return Duration
{
static_cast<typename Duration::rep>( reduced_period::den / (reduced_period::num * hz))
};
}
constexpr auto millis_count(const chrono_duration auto duration)
{
using namespace std::chrono;
return duration_cast<milliseconds>(duration).count();
}
template <typename Clock>
auto millis_from_epoch()
{
using namespace std::chrono;
return millis_count(Clock::now().time_since_epoch());
}
template <typename Angle>
constexpr radians<Angle> phase(const chrono_duration auto time,
const chrono_duration auto period)
{
// phi = 2*pi*t/T
return (full_angle<Angle> * time) / period;
}
template <typename Angle>
auto sine_wave(
const chrono_duration auto timeStamp,
const chrono_duration auto period,
const radians<Angle> phaseOffset = {})
{
return sin(phase<Angle>(timeStamp, period) - phaseOffset);
}
template <typename Angle>
auto sine_wave(
const chrono_duration auto timeStamp,
const chrono_duration auto period,
const chrono_duration auto offset)
{
return sine_wave<Angle>(timeStamp - offset, period);
}
template <typename Angle>
auto cosine_wave(
const chrono_duration auto timeStamp,
const chrono_duration auto period,
const radians<Angle> phaseOffset = {})
{
return cos(phase<Angle>(timeStamp, period) - phaseOffset);
}
template <typename Angle>
auto cosine_wave(
const chrono_duration auto t, const chrono_duration auto period,
const chrono_duration auto offset)
{
return cosine_wave<Angle>(t - offset, period);
}
// pwm generator
//
// |<offset><---------period--------><duty>
// true: | _____ _____
// false: |________| |___________________| |___________________
// 0 --> t
//
constexpr bool pwm(const chrono_duration auto period,
const chrono_duration auto dutyDuration,
const chrono_duration auto offset,
const chrono_time_point auto t)
{
using namespace std::chrono_literals;
const auto currentTimePoint = (t - offset).time_since_epoch();
return abs(currentTimePoint % period) < dutyDuration;
}
template <std::totally_ordered T>
class hysteresis
{
enum class status_t { alpha, beta, k };
T alpha_limit;
T beta_limit;
bool last_status;
template <typename Val>
status_t compare(const Val& x)
{
if (std::less_equal{}(x, alpha_limit))
return status_t::alpha;
if (std::less{}(x, beta_limit))
return status_t::k;
return status_t::beta;
}
public:
constexpr hysteresis(const T& alphaLimit, const T& betaLimit,
const bool previousStatus = false)
: alpha_limit{ alphaLimit }, beta_limit{ betaLimit },
last_status{ previousStatus }
{}
template <typename Val>
constexpr bool update(const Val& x)
{
switch (compare(x))
{
case status_t::alpha:
return (last_status = false);
case status_t::k:
return last_status;
case status_t::beta:
return (last_status = true);
default:
assert(false);
}
}
constexpr bool status() const
{
return last_status;
}
};
}
#endif