1use 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::AddAssign for Phase {
55 fn add_assign(&mut self, rhs: Phase) {
56 self.0 = self.0.wrapping_add(rhs.0);
57 }
58}
59
60impl core::ops::Sub<Phase> for Phase {
61 type Output = Phase;
62
63 fn sub(self, rhs: Phase) -> Self::Output {
64 Phase(self.0.wrapping_sub(rhs.0))
65 }
66}
67
68impl core::ops::SubAssign for Phase {
69 fn sub_assign(&mut self, rhs: Phase) {
70 self.0 = self.0.wrapping_sub(rhs.0);
71 }
72}
73
74impl core::ops::Mul<u8> for Phase {
75 type Output = Phase;
76
77 fn mul(self, rhs: u8) -> Self::Output {
78 Phase(self.0.wrapping_mul(rhs))
79 }
80}
81
82impl core::ops::Mul<Phase> for u8 {
83 type Output = Phase;
84
85 fn mul(self, rhs: Phase) -> Self::Output {
86 Phase(self.wrapping_mul(rhs.0))
87 }
88}
89
90impl core::ops::Div<u8> for Phase {
91 type Output = Phase;
92
93 fn div(self, rhs: u8) -> Self::Output {
94 Phase(self.0.wrapping_div(rhs))
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[rstest::rstest]
103 #[case(Phase(0x02), Phase(0x01), Phase(0x01))]
104 #[case(Phase(0xFE), Phase(0x7F), Phase(0x7F))]
105 #[case(Phase(0x7E), Phase(0x7F), Phase(0xFF))]
106 fn add(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: Phase) {
107 assert_eq!(expected, lhs + rhs);
108 }
109
110 #[rstest::rstest]
111 #[case(Phase(0x02), Phase(0x01), Phase(0x01))]
112 #[case(Phase(0xFE), Phase(0x7F), Phase(0x7F))]
113 #[case(Phase(0x7E), Phase(0x7F), Phase(0xFF))]
114 fn add_assign(#[case] expected: Phase, #[case] mut lhs: Phase, #[case] rhs: Phase) {
115 lhs += rhs;
116 assert_eq!(expected, lhs);
117 }
118
119 #[rstest::rstest]
120 #[case(Phase::ZERO, Phase(0x01), Phase(0x01))]
121 #[case(Phase(0x01), Phase(0x02), Phase(0x01))]
122 #[case(Phase(0x80), Phase(0x7F), Phase(0xFF))]
123 fn sub(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: Phase) {
124 assert_eq!(expected, lhs - rhs);
125 }
126
127 #[rstest::rstest]
128 #[case(Phase::ZERO, Phase(0x01), Phase(0x01))]
129 #[case(Phase(0x01), Phase(0x02), Phase(0x01))]
130 #[case(Phase(0x80), Phase(0x7F), Phase(0xFF))]
131 fn sub_assign(#[case] expected: Phase, #[case] mut lhs: Phase, #[case] rhs: Phase) {
132 lhs -= rhs;
133 assert_eq!(expected, lhs);
134 }
135
136 #[rstest::rstest]
137 #[case(Phase(0x02), Phase(0x01), 2)]
138 #[case(Phase(0xFE), Phase(0x7F), 2)]
139 #[case(Phase::ZERO, Phase(0x80), 2)]
140 fn mul(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: u8) {
141 assert_eq!(expected, lhs * rhs);
142 assert_eq!(expected, rhs * lhs);
143 }
144
145 #[rstest::rstest]
146 #[case(Phase(0x01), Phase(0x02), 2)]
147 #[case(Phase(0x7F), Phase(0xFE), 2)]
148 #[case(Phase::ZERO, Phase(0x01), 2)]
149 fn div(#[case] expected: Phase, #[case] lhs: Phase, #[case] rhs: u8) {
150 assert_eq!(expected, lhs / rhs);
151 }
152
153 #[rstest::rstest]
154 #[case(0.0, 0)]
155 #[case(2.0 * PI / 256.0 * 128.0, 128)]
156 #[case(2.0 * PI / 256.0 * 255.0, 255)]
157 fn radian(#[case] expect: f32, #[case] value: u8) {
158 approx::assert_abs_diff_eq!(expect, Phase(value).radian());
159 }
160
161 #[rstest::rstest]
162 #[case(Phase(0x00), Complex::new(1.0, 0.0))]
163 #[case(Phase(0x40), Complex::new(0.0, 1.0))]
164 #[case(Phase(0x80), Complex::new(-1.0, 0.0))]
165 #[case(Phase(0xC0), Complex::new(0.0, -1.0))]
166 fn from_complex(#[case] expect: Phase, #[case] value: Complex) {
167 assert_eq!(expect, Phase::from(value));
168 }
169
170 #[test]
171 fn dbg() {
172 assert_eq!(format!("{:?}", Phase::ZERO), "0x00");
173 assert_eq!(format!("{:?}", Phase(0x01)), "0x01");
174 assert_eq!(format!("{:?}", Phase(0xFF)), "0xFF");
175 }
176}