Skip to main content

RecursiveMovingAverage

Struct RecursiveMovingAverage 

Source
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>

Source

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}
Source

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}
Source

pub fn reset(&mut self)

Resets the filter to its initial, empty state.

Trait Implementations§

Source§

impl<const N: usize> Clone for RecursiveMovingAverage<N>

Source§

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)

Performs copy-assignment from source. Read more
Source§

impl<const N: usize> Debug for RecursiveMovingAverage<N>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<const N: usize> Default for RecursiveMovingAverage<N>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<const N: usize> Format for RecursiveMovingAverage<N>

Source§

fn format(&self, f: Formatter<'_>)

Writes the defmt representation of self to fmt.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.