autd3_core/firmware/
phase.rs1use core::f32::consts::PI;
2
3use crate::{
4 common::{Angle, rad},
5 geometry::Complex,
6};
7
8#[derive(Clone, Copy, PartialEq, Eq, Default)]
10#[repr(C)]
11pub struct Phase(pub u8);
12
13impl core::fmt::Debug for Phase {
14 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15 write!(f, "0x{:02X}", self.0)
16 }
17}
18
19impl Phase {
20 pub const ZERO: Self = Self(0);
22 pub const PI: Self = Self(0x80);
24
25 #[must_use]
27 pub const fn radian(&self) -> f32 {
28 self.0 as f32 / 256.0 * 2.0 * PI
29 }
30}
31
32impl From<Angle> for Phase {
33 fn from(v: Angle) -> Self {
34 let p = v.radian() / (2.0 * PI) * 256.0;
35 let p = p.round();
36 Self(((p as i32) & 0xFF) as _)
37 }
38}
39
40impl From<Complex> for Phase {
41 fn from(v: Complex) -> Self {
42 Self::from(v.arg() * rad)
43 }
44}
45
46impl core::ops::Add<Phase> for Phase {
47 type Output = Phase;
48
49 fn add(self, rhs: Phase) -> Self::Output {
50 Phase(self.0.wrapping_add(rhs.0))
51 }
52}
53
54impl core::ops::Sub<Phase> for Phase {
55 type Output = Phase;
56
57 fn sub(self, rhs: Phase) -> Self::Output {
58 Phase(self.0.wrapping_sub(rhs.0))
59 }
60}
61
62impl core::ops::Mul<u8> for Phase {
63 type Output = Phase;
64
65 fn mul(self, rhs: u8) -> Self::Output {
66 Phase(self.0.wrapping_mul(rhs))
67 }
68}
69
70impl core::ops::Div<u8> for Phase {
71 type Output = Phase;
72
73 fn div(self, rhs: u8) -> Self::Output {
74 Phase(self.0.wrapping_div(rhs))
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[rstest::rstest]
83 #[case(Phase(0x02), Phase(0x01), Phase(0x01))]
84 #[case(Phase(0xFE), Phase(0x7F), Phase(0x7F))]
85 #[case(Phase(0x7E), Phase(0x7F), Phase(0xFF))]
86 fn add(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: Phase) {
87 assert_eq!(expected, lhs + rhs);
88 }
89
90 #[rstest::rstest]
91 #[case(Phase::ZERO, Phase(0x01), Phase(0x01))]
92 #[case(Phase(0x01), Phase(0x02), Phase(0x01))]
93 #[case(Phase(0x80), Phase(0x7F), Phase(0xFF))]
94 fn sub(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: Phase) {
95 assert_eq!(expected, lhs - rhs);
96 }
97
98 #[rstest::rstest]
99 #[case(Phase(0x02), Phase(0x01), 2)]
100 #[case(Phase(0xFE), Phase(0x7F), 2)]
101 #[case(Phase::ZERO, Phase(0x80), 2)]
102 fn mul(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: u8) {
103 assert_eq!(expected, lhs * rhs);
104 }
105
106 #[rstest::rstest]
107 #[case(Phase(0x01), Phase(0x02), 2)]
108 #[case(Phase(0x7F), Phase(0xFE), 2)]
109 #[case(Phase::ZERO, Phase(0x01), 2)]
110 fn div(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: u8) {
111 assert_eq!(expected, lhs / rhs);
112 }
113
114 #[rstest::rstest]
115 #[case(0.0, 0)]
116 #[case(2.0 * PI / 256.0 * 128.0, 128)]
117 #[case(2.0 * PI / 256.0 * 255.0, 255)]
118 fn radian(#[case] expect: f32, #[case] value: u8) {
119 approx::assert_abs_diff_eq!(expect, Phase(value).radian());
120 }
121
122 #[rstest::rstest]
123 #[case(Phase(0x00), Complex::new(1.0, 0.0))]
124 #[case(Phase(0x40), Complex::new(0.0, 1.0))]
125 #[case(Phase(0x80), Complex::new(-1.0, 0.0))]
126 #[case(Phase(0xC0), Complex::new(0.0, -1.0))]
127 fn from_complex(#[case] expect: Phase, #[case] value: Complex) {
128 assert_eq!(expect, Phase::from(value));
129 }
130
131 #[test]
132 fn dbg() {
133 assert_eq!(format!("{:?}", Phase::ZERO), "0x00");
134 assert_eq!(format!("{:?}", Phase(0x01)), "0x01");
135 assert_eq!(format!("{:?}", Phase(0xFF)), "0xFF");
136 }
137}