pub struct RecursiveMovingAverage<const N: usize> { /* private fields */ }Expand description
Const-generic N-point moving average filter implemented recursively (Steven W. Smith,
Ch. 15, Eq. 15-3): each sample is updated with a single add and subtract, instead of an
O(N) convolution sum.
Implementations§
Source§impl<const N: usize> RecursiveMovingAverage<N>
impl<const N: usize> RecursiveMovingAverage<N>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Creates a new N-point recursive moving average filter with empty history.
Examples found in repository?
examples/motor_control_foc.rs (line 66)
15fn main() {
16 println!("===============================================================================");
17 println!(" embedded-dsp Field-Oriented Control (FOC) & Motor Control Loop ");
18 println!("===============================================================================");
19 println!();
20
21 const CONTROL_RATE_HZ: f32 = 20000.0; // 20 kHz FOC current loop (50 μs per step)
22 const NUM_CONTROL_CYCLES: usize = 20;
23
24 // -----------------------------------------------------------------------------------------
25 // 1. 3-Phase Current Feedback Simulation with Inverter Switching Ripple
26 // -----------------------------------------------------------------------------------------
27 println!("--- 1. 3-Phase Current Sensing with Inverter PWM Switching Noise ---");
28 let target_torque_current = 5.0f32; // 5 Amps commanded torque current (Iq)
29 let rotor_speed_rpm = 3000.0f32;
30 let pole_pairs = 4.0f32;
31 let electrical_freq_hz = (rotor_speed_rpm * pole_pairs) / 60.0; // 200 Hz electrical freq
32 let omega_e = 2.0 * core::f32::consts::PI * electrical_freq_hz;
33
34 let mut ia_raw = [0.0f32; NUM_CONTROL_CYCLES];
35 let mut ib_raw = [0.0f32; NUM_CONTROL_CYCLES];
36 let mut ic_raw = [0.0f32; NUM_CONTROL_CYCLES];
37 let mut theta_e = [0.0f32; NUM_CONTROL_CYCLES];
38
39 for i in 0..NUM_CONTROL_CYCLES {
40 let t = i as f32 / CONTROL_RATE_HZ;
41 let theta = (omega_e * t) % (2.0 * core::f32::consts::PI);
42 theta_e[i] = theta;
43
44 // Ideal stator currents (balanced 3-phase, 120° apart, Iq = 5A, Id = 0A)
45 // Ia = -Iq * sin(θ), Ib = -Iq * sin(θ - 2π/3), Ic = -Iq * sin(θ + 2π/3)
46 let ia_ideal = -target_torque_current * theta.sin();
47 let ib_ideal = -target_torque_current * (theta - 2.0 * core::f32::consts::PI / 3.0).sin();
48 let ic_ideal = -target_torque_current * (theta + 2.0 * core::f32::consts::PI / 3.0).sin();
49
50 // 20 kHz PWM inverter switching noise (±0.4A ripple)
51 let ripple = if i % 2 == 0 { 0.35f32 } else { -0.35f32 };
52 ia_raw[i] = ia_ideal + ripple;
53 ib_raw[i] = ib_ideal - ripple * 0.5;
54 ic_raw[i] = ic_ideal - ripple * 0.5;
55 }
56
57 println!(
58 " Initial Raw Stator Currents at t=0: Ia={:.2}A, Ib={:.2}A, Ic={:.2}A",
59 ia_raw[0], ib_raw[0], ic_raw[0]
60 );
61
62 // -----------------------------------------------------------------------------------------
63 // 2. Real-Time Current Filtering (O(1) Recursive Moving Average)
64 // -----------------------------------------------------------------------------------------
65 println!("\n--- 2. Stator Current Feedback Filtering (O(1) Recursive Moving Average) ---");
66 let mut ma_filter_ia = RecursiveMovingAverage::<8>::new();
67 let mut ma_filter_ib = RecursiveMovingAverage::<8>::new();
68 let mut ia_filtered = [0.0f32; NUM_CONTROL_CYCLES];
69 let mut ib_filtered = [0.0f32; NUM_CONTROL_CYCLES];
70
71 for i in 0..NUM_CONTROL_CYCLES {
72 ia_filtered[i] = ma_filter_ia.process(ia_raw[i]);
73 ib_filtered[i] = ma_filter_ib.process(ib_raw[i]);
74 }
75 println!(
76 " Raw Ia[4] = {:.3}A -> Filtered Ia[4] = {:.3}A",
77 ia_raw[4], ia_filtered[4]
78 );
79 println!(
80 " Raw Ib[4] = {:.3}A -> Filtered Ib[4] = {:.3}A",
81 ib_raw[4], ib_filtered[4]
82 );
83
84 // -----------------------------------------------------------------------------------------
85 // 3. Fast Trigonometric Evaluation & Angle Transformations
86 // -----------------------------------------------------------------------------------------
87 println!("\n--- 3. Fast Trigonometry vs Table Lookup for Rotor Angle θ ---");
88 let test_angle = core::f32::consts::FRAC_PI_3; // 60 degrees (π/3 rad)
89 let fast_s_i16 = fast_sin_i16(test_angle);
90 let fast_c_i16 = fast_cos_i16(test_angle);
91 let std_s = test_angle.sin();
92 let std_c = test_angle.cos();
93 println!(
94 " θ = 60°: LUT fast_sin_i16 = {} ({:.4}, Exact: {:.4})",
95 fast_s_i16,
96 fast_s_i16 as f32 / 32768.0,
97 std_s
98 );
99 println!(
100 " θ = 60°: LUT fast_cos_i16 = {} ({:.4}, Exact: {:.4})",
101 fast_c_i16,
102 fast_c_i16 as f32 / 32768.0,
103 std_c
104 );
105
106 // Q31 Fixed-Point CORDIC Sine/Cosine (angle in [-π, π) mapped to Q31)
107 let angle_q31 = ((test_angle / core::f32::consts::PI) * 2147483648.0) as i32;
108 let s_q31 = sin_q31(angle_q31);
109 let c_q31 = cos_q31(angle_q31);
110 println!(
111 " CORDIC Q31 Sine/Cosine: sin = {} ({:.4}, Exact: {:.4}), cos = {} ({:.4}, Exact: {:.4})",
112 s_q31,
113 s_q31 as f64 / 2147483648.0,
114 std_s,
115 c_q31,
116 c_q31 as f64 / 2147483648.0,
117 std_c
118 );
119
120 // -----------------------------------------------------------------------------------------
121 // 4. Forward Clarke & Park Transforms (f32 & Q15)
122 // -----------------------------------------------------------------------------------------
123 println!("\n--- 4. Forward Clarke & Park Transforms ---");
124 let mut i_alpha = 0.0f32;
125 let mut i_beta = 0.0f32;
126 let mut i_d = 0.0f32;
127 let mut i_q = 0.0f32;
128
129 // Evaluate step 10
130 let step_idx = 10;
131 clarke_f32(
132 ia_filtered[step_idx],
133 ib_filtered[step_idx],
134 &mut i_alpha,
135 &mut i_beta,
136 );
137 park_f32(i_alpha, i_beta, theta_e[step_idx], &mut i_d, &mut i_q);
138
139 println!(" f32 Forward Transforms at Step {}:", step_idx);
140 println!(
141 " • Stator Stationary Frame: I_alpha = {:>6.3} A, I_beta = {:>6.3} A",
142 i_alpha, i_beta
143 );
144 println!(
145 " • Rotor Synchronous Frame: I_d (Flux) = {:>6.3} A, I_q (Torque) = {:>6.3} A",
146 i_d, i_q
147 );
148
149 // Fixed-point Q15 Clarke and Park verification
150 let q15_scale = 1000.0f32; // 1 Amp = 1000 Q15 counts
151 let ia_q15 = (ia_filtered[step_idx] * q15_scale) as q15;
152 let ib_q15 = (ib_filtered[step_idx] * q15_scale) as q15;
153 let mut q15_alpha = 0i16;
154 let mut q15_beta = 0i16;
155 let mut q15_d = 0i16;
156 let mut q15_q = 0i16;
157
158 clarke_q15(ia_q15, ib_q15, &mut q15_alpha, &mut q15_beta);
159 let sin_q15 = fast_sin_i16(theta_e[step_idx]);
160 let cos_q15 = fast_cos_i16(theta_e[step_idx]);
161 park_q15(
162 q15_alpha, q15_beta, sin_q15, cos_q15, &mut q15_d, &mut q15_q,
163 );
164
165 println!(" Q15 Forward Transforms:");
166 println!(
167 " • Q15 Clarke: alpha = {} ({:.3} A), beta = {} ({:.3} A)",
168 q15_alpha,
169 q15_alpha as f32 / q15_scale,
170 q15_beta,
171 q15_beta as f32 / q15_scale
172 );
173 println!(
174 " • Q15 Park : d = {} ({:.3} A), q = {} ({:.3} A)",
175 q15_d,
176 q15_d as f32 / q15_scale,
177 q15_q,
178 q15_q as f32 / q15_scale
179 );
180
181 // -----------------------------------------------------------------------------------------
182 // 5. Dual Current Regulators (Id & Iq PID Loops) + Outer Speed Controller
183 // -----------------------------------------------------------------------------------------
184 println!("\n--- 5. Vector Current Regulators (Dual PID Loops for Id & Iq) ---");
185 // Outer Velocity Loop: Target 3000 RPM, Actual 2950 RPM -> Error = 50 RPM
186 let mut speed_pid = PidInstanceF32::new(0.08, 0.005, 0.001);
187 let speed_error_rpm = 50.0f32;
188 let demanded_iq = speed_pid.process(speed_error_rpm).clamp(-15.0, 15.0);
189 println!(
190 " Outer Speed PID: Error = {:.1} RPM -> Commanded I_q* = {:.3} A",
191 speed_error_rpm, demanded_iq
192 );
193
194 // Inner Current Regulators:
195 // Id controller: Setpoint = 0.0 A (Zero d-axis current for Maximum Torque Per Ampere)
196 // Iq controller: Setpoint = demanded_iq
197 let mut id_pid = PidInstanceF32::new(2.5, 0.15, 0.0);
198 let mut iq_pid = PidInstanceF32::new(2.5, 0.15, 0.0);
199
200 let id_setpoint = 0.0f32;
201 let iq_setpoint = demanded_iq;
202
203 let id_error = id_setpoint - i_d;
204 let iq_error = iq_setpoint - i_q;
205
206 let v_d_command = id_pid.process(id_error).clamp(-24.0, 24.0); // 24V DC bus voltage limit
207 let v_q_command = iq_pid.process(iq_error).clamp(-24.0, 24.0);
208
209 println!(" Inner Current PIDs:");
210 println!(
211 " • d-Axis (Flux) : Error = {:>6.3} A -> Commanded V_d = {:>6.3} V",
212 id_error, v_d_command
213 );
214 println!(
215 " • q-Axis (Torque): Error = {:>6.3} A -> Commanded V_q = {:>6.3} V",
216 iq_error, v_q_command
217 );
218
219 // -----------------------------------------------------------------------------------------
220 // 6. Inverse Park & Inverse Clarke Transforms (Modulation Voltages)
221 // -----------------------------------------------------------------------------------------
222 println!("\n--- 6. Inverse Park & Inverse Clarke Transforms (SVPWM Modulation) ---");
223 let mut v_alpha = 0.0f32;
224 let mut v_beta = 0.0f32;
225 let mut v_a = 0.0f32;
226 let mut v_b = 0.0f32;
227
228 inv_park_f32(
229 v_d_command,
230 v_q_command,
231 theta_e[step_idx],
232 &mut v_alpha,
233 &mut v_beta,
234 );
235 inv_clarke_f32(v_alpha, v_beta, &mut v_a, &mut v_b);
236 let v_c = -v_a - v_b; // 3-phase balanced neutral
237
238 println!(
239 " Inverse Park : V_alpha = {:>6.3} V, V_beta = {:>6.3} V",
240 v_alpha, v_beta
241 );
242 println!(
243 " Inverse Clarke : V_a = {:>6.3} V, V_b = {:>6.3} V, V_c = {:>6.3} V",
244 v_a, v_b, v_c
245 );
246
247 // Compute PWM Duty Cycles for Inverter Gate Drivers (normalized to 0.0 .. 1.0)
248 let v_dc = 24.0f32;
249 let duty_a = (v_a / v_dc + 0.5).clamp(0.0, 1.0);
250 let duty_b = (v_b / v_dc + 0.5).clamp(0.0, 1.0);
251 let duty_c = (v_c / v_dc + 0.5).clamp(0.0, 1.0);
252
253 println!(" Generated Inverter PWM Duty Cycles:");
254 println!(" • Phase A Duty : {:>5.1} %", duty_a * 100.0);
255 println!(" • Phase B Duty : {:>5.1} %", duty_b * 100.0);
256 println!(" • Phase C Duty : {:>5.1} %", duty_c * 100.0);
257
258 println!();
259 println!("===============================================================================");
260 println!(" Field-Oriented Control (FOC) Execution Complete! ");
261 println!("===============================================================================");
262}Sourcepub fn process(&mut self, x: f32) -> f32
pub fn process(&mut self, x: f32) -> f32
Pushes a new input sample and returns the updated moving average. While fewer than N
samples have been seen, the average is taken over the (growing) window received so far.
Examples found in repository?
examples/motor_control_foc.rs (line 72)
15fn main() {
16 println!("===============================================================================");
17 println!(" embedded-dsp Field-Oriented Control (FOC) & Motor Control Loop ");
18 println!("===============================================================================");
19 println!();
20
21 const CONTROL_RATE_HZ: f32 = 20000.0; // 20 kHz FOC current loop (50 μs per step)
22 const NUM_CONTROL_CYCLES: usize = 20;
23
24 // -----------------------------------------------------------------------------------------
25 // 1. 3-Phase Current Feedback Simulation with Inverter Switching Ripple
26 // -----------------------------------------------------------------------------------------
27 println!("--- 1. 3-Phase Current Sensing with Inverter PWM Switching Noise ---");
28 let target_torque_current = 5.0f32; // 5 Amps commanded torque current (Iq)
29 let rotor_speed_rpm = 3000.0f32;
30 let pole_pairs = 4.0f32;
31 let electrical_freq_hz = (rotor_speed_rpm * pole_pairs) / 60.0; // 200 Hz electrical freq
32 let omega_e = 2.0 * core::f32::consts::PI * electrical_freq_hz;
33
34 let mut ia_raw = [0.0f32; NUM_CONTROL_CYCLES];
35 let mut ib_raw = [0.0f32; NUM_CONTROL_CYCLES];
36 let mut ic_raw = [0.0f32; NUM_CONTROL_CYCLES];
37 let mut theta_e = [0.0f32; NUM_CONTROL_CYCLES];
38
39 for i in 0..NUM_CONTROL_CYCLES {
40 let t = i as f32 / CONTROL_RATE_HZ;
41 let theta = (omega_e * t) % (2.0 * core::f32::consts::PI);
42 theta_e[i] = theta;
43
44 // Ideal stator currents (balanced 3-phase, 120° apart, Iq = 5A, Id = 0A)
45 // Ia = -Iq * sin(θ), Ib = -Iq * sin(θ - 2π/3), Ic = -Iq * sin(θ + 2π/3)
46 let ia_ideal = -target_torque_current * theta.sin();
47 let ib_ideal = -target_torque_current * (theta - 2.0 * core::f32::consts::PI / 3.0).sin();
48 let ic_ideal = -target_torque_current * (theta + 2.0 * core::f32::consts::PI / 3.0).sin();
49
50 // 20 kHz PWM inverter switching noise (±0.4A ripple)
51 let ripple = if i % 2 == 0 { 0.35f32 } else { -0.35f32 };
52 ia_raw[i] = ia_ideal + ripple;
53 ib_raw[i] = ib_ideal - ripple * 0.5;
54 ic_raw[i] = ic_ideal - ripple * 0.5;
55 }
56
57 println!(
58 " Initial Raw Stator Currents at t=0: Ia={:.2}A, Ib={:.2}A, Ic={:.2}A",
59 ia_raw[0], ib_raw[0], ic_raw[0]
60 );
61
62 // -----------------------------------------------------------------------------------------
63 // 2. Real-Time Current Filtering (O(1) Recursive Moving Average)
64 // -----------------------------------------------------------------------------------------
65 println!("\n--- 2. Stator Current Feedback Filtering (O(1) Recursive Moving Average) ---");
66 let mut ma_filter_ia = RecursiveMovingAverage::<8>::new();
67 let mut ma_filter_ib = RecursiveMovingAverage::<8>::new();
68 let mut ia_filtered = [0.0f32; NUM_CONTROL_CYCLES];
69 let mut ib_filtered = [0.0f32; NUM_CONTROL_CYCLES];
70
71 for i in 0..NUM_CONTROL_CYCLES {
72 ia_filtered[i] = ma_filter_ia.process(ia_raw[i]);
73 ib_filtered[i] = ma_filter_ib.process(ib_raw[i]);
74 }
75 println!(
76 " Raw Ia[4] = {:.3}A -> Filtered Ia[4] = {:.3}A",
77 ia_raw[4], ia_filtered[4]
78 );
79 println!(
80 " Raw Ib[4] = {:.3}A -> Filtered Ib[4] = {:.3}A",
81 ib_raw[4], ib_filtered[4]
82 );
83
84 // -----------------------------------------------------------------------------------------
85 // 3. Fast Trigonometric Evaluation & Angle Transformations
86 // -----------------------------------------------------------------------------------------
87 println!("\n--- 3. Fast Trigonometry vs Table Lookup for Rotor Angle θ ---");
88 let test_angle = core::f32::consts::FRAC_PI_3; // 60 degrees (π/3 rad)
89 let fast_s_i16 = fast_sin_i16(test_angle);
90 let fast_c_i16 = fast_cos_i16(test_angle);
91 let std_s = test_angle.sin();
92 let std_c = test_angle.cos();
93 println!(
94 " θ = 60°: LUT fast_sin_i16 = {} ({:.4}, Exact: {:.4})",
95 fast_s_i16,
96 fast_s_i16 as f32 / 32768.0,
97 std_s
98 );
99 println!(
100 " θ = 60°: LUT fast_cos_i16 = {} ({:.4}, Exact: {:.4})",
101 fast_c_i16,
102 fast_c_i16 as f32 / 32768.0,
103 std_c
104 );
105
106 // Q31 Fixed-Point CORDIC Sine/Cosine (angle in [-π, π) mapped to Q31)
107 let angle_q31 = ((test_angle / core::f32::consts::PI) * 2147483648.0) as i32;
108 let s_q31 = sin_q31(angle_q31);
109 let c_q31 = cos_q31(angle_q31);
110 println!(
111 " CORDIC Q31 Sine/Cosine: sin = {} ({:.4}, Exact: {:.4}), cos = {} ({:.4}, Exact: {:.4})",
112 s_q31,
113 s_q31 as f64 / 2147483648.0,
114 std_s,
115 c_q31,
116 c_q31 as f64 / 2147483648.0,
117 std_c
118 );
119
120 // -----------------------------------------------------------------------------------------
121 // 4. Forward Clarke & Park Transforms (f32 & Q15)
122 // -----------------------------------------------------------------------------------------
123 println!("\n--- 4. Forward Clarke & Park Transforms ---");
124 let mut i_alpha = 0.0f32;
125 let mut i_beta = 0.0f32;
126 let mut i_d = 0.0f32;
127 let mut i_q = 0.0f32;
128
129 // Evaluate step 10
130 let step_idx = 10;
131 clarke_f32(
132 ia_filtered[step_idx],
133 ib_filtered[step_idx],
134 &mut i_alpha,
135 &mut i_beta,
136 );
137 park_f32(i_alpha, i_beta, theta_e[step_idx], &mut i_d, &mut i_q);
138
139 println!(" f32 Forward Transforms at Step {}:", step_idx);
140 println!(
141 " • Stator Stationary Frame: I_alpha = {:>6.3} A, I_beta = {:>6.3} A",
142 i_alpha, i_beta
143 );
144 println!(
145 " • Rotor Synchronous Frame: I_d (Flux) = {:>6.3} A, I_q (Torque) = {:>6.3} A",
146 i_d, i_q
147 );
148
149 // Fixed-point Q15 Clarke and Park verification
150 let q15_scale = 1000.0f32; // 1 Amp = 1000 Q15 counts
151 let ia_q15 = (ia_filtered[step_idx] * q15_scale) as q15;
152 let ib_q15 = (ib_filtered[step_idx] * q15_scale) as q15;
153 let mut q15_alpha = 0i16;
154 let mut q15_beta = 0i16;
155 let mut q15_d = 0i16;
156 let mut q15_q = 0i16;
157
158 clarke_q15(ia_q15, ib_q15, &mut q15_alpha, &mut q15_beta);
159 let sin_q15 = fast_sin_i16(theta_e[step_idx]);
160 let cos_q15 = fast_cos_i16(theta_e[step_idx]);
161 park_q15(
162 q15_alpha, q15_beta, sin_q15, cos_q15, &mut q15_d, &mut q15_q,
163 );
164
165 println!(" Q15 Forward Transforms:");
166 println!(
167 " • Q15 Clarke: alpha = {} ({:.3} A), beta = {} ({:.3} A)",
168 q15_alpha,
169 q15_alpha as f32 / q15_scale,
170 q15_beta,
171 q15_beta as f32 / q15_scale
172 );
173 println!(
174 " • Q15 Park : d = {} ({:.3} A), q = {} ({:.3} A)",
175 q15_d,
176 q15_d as f32 / q15_scale,
177 q15_q,
178 q15_q as f32 / q15_scale
179 );
180
181 // -----------------------------------------------------------------------------------------
182 // 5. Dual Current Regulators (Id & Iq PID Loops) + Outer Speed Controller
183 // -----------------------------------------------------------------------------------------
184 println!("\n--- 5. Vector Current Regulators (Dual PID Loops for Id & Iq) ---");
185 // Outer Velocity Loop: Target 3000 RPM, Actual 2950 RPM -> Error = 50 RPM
186 let mut speed_pid = PidInstanceF32::new(0.08, 0.005, 0.001);
187 let speed_error_rpm = 50.0f32;
188 let demanded_iq = speed_pid.process(speed_error_rpm).clamp(-15.0, 15.0);
189 println!(
190 " Outer Speed PID: Error = {:.1} RPM -> Commanded I_q* = {:.3} A",
191 speed_error_rpm, demanded_iq
192 );
193
194 // Inner Current Regulators:
195 // Id controller: Setpoint = 0.0 A (Zero d-axis current for Maximum Torque Per Ampere)
196 // Iq controller: Setpoint = demanded_iq
197 let mut id_pid = PidInstanceF32::new(2.5, 0.15, 0.0);
198 let mut iq_pid = PidInstanceF32::new(2.5, 0.15, 0.0);
199
200 let id_setpoint = 0.0f32;
201 let iq_setpoint = demanded_iq;
202
203 let id_error = id_setpoint - i_d;
204 let iq_error = iq_setpoint - i_q;
205
206 let v_d_command = id_pid.process(id_error).clamp(-24.0, 24.0); // 24V DC bus voltage limit
207 let v_q_command = iq_pid.process(iq_error).clamp(-24.0, 24.0);
208
209 println!(" Inner Current PIDs:");
210 println!(
211 " • d-Axis (Flux) : Error = {:>6.3} A -> Commanded V_d = {:>6.3} V",
212 id_error, v_d_command
213 );
214 println!(
215 " • q-Axis (Torque): Error = {:>6.3} A -> Commanded V_q = {:>6.3} V",
216 iq_error, v_q_command
217 );
218
219 // -----------------------------------------------------------------------------------------
220 // 6. Inverse Park & Inverse Clarke Transforms (Modulation Voltages)
221 // -----------------------------------------------------------------------------------------
222 println!("\n--- 6. Inverse Park & Inverse Clarke Transforms (SVPWM Modulation) ---");
223 let mut v_alpha = 0.0f32;
224 let mut v_beta = 0.0f32;
225 let mut v_a = 0.0f32;
226 let mut v_b = 0.0f32;
227
228 inv_park_f32(
229 v_d_command,
230 v_q_command,
231 theta_e[step_idx],
232 &mut v_alpha,
233 &mut v_beta,
234 );
235 inv_clarke_f32(v_alpha, v_beta, &mut v_a, &mut v_b);
236 let v_c = -v_a - v_b; // 3-phase balanced neutral
237
238 println!(
239 " Inverse Park : V_alpha = {:>6.3} V, V_beta = {:>6.3} V",
240 v_alpha, v_beta
241 );
242 println!(
243 " Inverse Clarke : V_a = {:>6.3} V, V_b = {:>6.3} V, V_c = {:>6.3} V",
244 v_a, v_b, v_c
245 );
246
247 // Compute PWM Duty Cycles for Inverter Gate Drivers (normalized to 0.0 .. 1.0)
248 let v_dc = 24.0f32;
249 let duty_a = (v_a / v_dc + 0.5).clamp(0.0, 1.0);
250 let duty_b = (v_b / v_dc + 0.5).clamp(0.0, 1.0);
251 let duty_c = (v_c / v_dc + 0.5).clamp(0.0, 1.0);
252
253 println!(" Generated Inverter PWM Duty Cycles:");
254 println!(" • Phase A Duty : {:>5.1} %", duty_a * 100.0);
255 println!(" • Phase B Duty : {:>5.1} %", duty_b * 100.0);
256 println!(" • Phase C Duty : {:>5.1} %", duty_c * 100.0);
257
258 println!();
259 println!("===============================================================================");
260 println!(" Field-Oriented Control (FOC) Execution Complete! ");
261 println!("===============================================================================");
262}Trait Implementations§
Source§impl<const N: usize> Clone for RecursiveMovingAverage<N>
impl<const N: usize> Clone for RecursiveMovingAverage<N>
Source§fn clone(&self) -> RecursiveMovingAverage<N>
fn clone(&self) -> RecursiveMovingAverage<N>
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl<const N: usize> Debug for RecursiveMovingAverage<N>
impl<const N: usize> Debug for RecursiveMovingAverage<N>
Source§impl<const N: usize> Default for RecursiveMovingAverage<N>
impl<const N: usize> Default for RecursiveMovingAverage<N>
Auto Trait Implementations§
impl<const N: usize> Freeze for RecursiveMovingAverage<N>
impl<const N: usize> RefUnwindSafe for RecursiveMovingAverage<N>
impl<const N: usize> Send for RecursiveMovingAverage<N>
impl<const N: usize> Sync for RecursiveMovingAverage<N>
impl<const N: usize> Unpin for RecursiveMovingAverage<N>
impl<const N: usize> UnsafeUnpin for RecursiveMovingAverage<N>
impl<const N: usize> UnwindSafe for RecursiveMovingAverage<N>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more