pub struct PidInstanceF32 {
pub a0: f32,
pub a1: f32,
pub a2: f32,
pub state: [f32; 3],
pub kp: f32,
pub ki: f32,
pub kd: f32,
}Expand description
Instance structure for the floating-point PID Control.
Fields§
§a0: f32§a1: f32§a2: f32§state: [f32; 3]§kp: f32§ki: f32§kd: f32Implementations§
Source§impl PidInstanceF32
impl PidInstanceF32
Sourcepub fn new(kp: f32, ki: f32, kd: f32) -> Self
pub fn new(kp: f32, ki: f32, kd: f32) -> Self
Examples found in repository?
examples/basic_usage.rs (line 36)
5fn main() {
6 println!("=== embedded-dsp Basic Usage Example ===");
7
8 // 1. Vector Operations
9 let a = [1.0f32, 2.0, 3.0, 4.0];
10 let b = [10.0f32, 20.0, 30.0, 40.0];
11 let mut vec_out = [0.0f32; 4];
12 add_f32(&a, &b, &mut vec_out);
13 println!("Vector Add: {:?}", vec_out);
14
15 let dot = dot_prod_f32(&a, &b);
16 println!("Vector Dot Product: {}", dot);
17
18 // 2. Q15 Fixed-Point Saturating Math
19 let q15_a = [20000i16, 25000];
20 let q15_b = [15000i16, 10000];
21 let mut q15_out = [0i16; 2];
22 add_q15(&q15_a, &q15_b, &mut q15_out);
23 println!("Q15 Saturating Add (clamped at 32767): {:?}", q15_out);
24
25 // 3. FIR Filtering
26 let coeffs = [0.25f32, 0.5, 0.25]; // 3-tap moving average filter
27 let mut state = [0.0f32; 3 + 4 - 1];
28 let mut fir = FirInstanceF32::init(3, &coeffs, &mut state);
29
30 let input_signal = [1.0f32, 2.0, 3.0, 4.0];
31 let mut filtered_signal = [0.0f32; 4];
32 fir_f32(&mut fir, &input_signal, &mut filtered_signal);
33 println!("FIR Filter Output: {:?}", filtered_signal);
34
35 // 4. PID Motor Controller
36 let mut pid = PidInstanceF32::new(2.0, 0.1, 0.05);
37 let control_output = pid.process(10.0);
38 println!("PID Control Signal: {}", control_output);
39
40 // 5. 64-Point Complex FFT
41 let mut fft_data = [0.0f32; 128]; // 64 complex pairs [re, im, ...]
42 for i in 0..64 {
43 fft_data[2 * i] = (i as f32 * 0.1).sin();
44 }
45 cfft_f32(&mut fft_data, 64, 0, 1);
46 println!("64-Point Complex FFT processed successfully!");
47
48 // 6. 1D Conditional Median Filtering (Impulse / Spike Rejection)
49 let spiky_signal = [1.0f32, 1.1, 1.0, 100.0, 1.2, 1.1, 1.0];
50 let mut clean_signal = [0.0f32; 7];
51 median_filter_1d_f32(&spiky_signal, &mut clean_signal, 3, 5.0);
52 println!("Conditional Median Filter Out: {:?}", clean_signal);
53
54 // 7. Welch's Method Power Spectral Density (PSD)
55 let mut psd_out = [0.0f32; 32];
56 let mut sine_wave = [0.0f32; 128];
57 for (i, val) in sine_wave.iter_mut().enumerate() {
58 *val = (2.0 * core::f32::consts::PI * 100.0 * (i as f32) / 1000.0).sin();
59 }
60 welch_psd_f32(
61 &sine_wave,
62 &mut psd_out,
63 64,
64 32,
65 1000.0,
66 WelchWindow::Hamming,
67 true,
68 );
69 println!("Welch PSD (dB) at bin 6: {:.2} dB", psd_out[6]);
70
71 // 8. 2D Spatial Processing (2D DCT & Sobel Edge Detection)
72 let img_4x4 = [
73 0.0f32, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0,
74 ];
75 let mut edges = [0.0f32; 16];
76 sobel_edge_detection_f32(&img_4x4, &mut edges, 4, 4, 15.0);
77 println!("2D Sobel Edge Output (4x4): {:?}", edges);
78
79 // 9. Weighted Polynomial Least-Squares Sensor Calibration
80 let x_cal = [0.0f32, 1.0, 2.0, 3.0, 4.0];
81 let y_cal = [2.0f32, 5.0, 8.0, 11.0, 14.0]; // y = 2 + 3x
82 let mut cal_coeffs = [0.0f32; 2];
83 polynomial_least_squares_fit(&x_cal, &y_cal, None, 1, &mut cal_coeffs);
84 println!(
85 "Fitted Sensor Calibration: y = {:.2} + {:.2}*x",
86 cal_coeffs[0], cal_coeffs[1]
87 );
88}More examples
examples/motor_control_foc.rs (line 186)
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}pub fn init(&mut self, reset_state_flag: i32)
pub fn reset(&mut self)
Sourcepub fn process(&mut self, in_val: f32) -> f32
pub fn process(&mut self, in_val: f32) -> f32
Examples found in repository?
examples/basic_usage.rs (line 37)
5fn main() {
6 println!("=== embedded-dsp Basic Usage Example ===");
7
8 // 1. Vector Operations
9 let a = [1.0f32, 2.0, 3.0, 4.0];
10 let b = [10.0f32, 20.0, 30.0, 40.0];
11 let mut vec_out = [0.0f32; 4];
12 add_f32(&a, &b, &mut vec_out);
13 println!("Vector Add: {:?}", vec_out);
14
15 let dot = dot_prod_f32(&a, &b);
16 println!("Vector Dot Product: {}", dot);
17
18 // 2. Q15 Fixed-Point Saturating Math
19 let q15_a = [20000i16, 25000];
20 let q15_b = [15000i16, 10000];
21 let mut q15_out = [0i16; 2];
22 add_q15(&q15_a, &q15_b, &mut q15_out);
23 println!("Q15 Saturating Add (clamped at 32767): {:?}", q15_out);
24
25 // 3. FIR Filtering
26 let coeffs = [0.25f32, 0.5, 0.25]; // 3-tap moving average filter
27 let mut state = [0.0f32; 3 + 4 - 1];
28 let mut fir = FirInstanceF32::init(3, &coeffs, &mut state);
29
30 let input_signal = [1.0f32, 2.0, 3.0, 4.0];
31 let mut filtered_signal = [0.0f32; 4];
32 fir_f32(&mut fir, &input_signal, &mut filtered_signal);
33 println!("FIR Filter Output: {:?}", filtered_signal);
34
35 // 4. PID Motor Controller
36 let mut pid = PidInstanceF32::new(2.0, 0.1, 0.05);
37 let control_output = pid.process(10.0);
38 println!("PID Control Signal: {}", control_output);
39
40 // 5. 64-Point Complex FFT
41 let mut fft_data = [0.0f32; 128]; // 64 complex pairs [re, im, ...]
42 for i in 0..64 {
43 fft_data[2 * i] = (i as f32 * 0.1).sin();
44 }
45 cfft_f32(&mut fft_data, 64, 0, 1);
46 println!("64-Point Complex FFT processed successfully!");
47
48 // 6. 1D Conditional Median Filtering (Impulse / Spike Rejection)
49 let spiky_signal = [1.0f32, 1.1, 1.0, 100.0, 1.2, 1.1, 1.0];
50 let mut clean_signal = [0.0f32; 7];
51 median_filter_1d_f32(&spiky_signal, &mut clean_signal, 3, 5.0);
52 println!("Conditional Median Filter Out: {:?}", clean_signal);
53
54 // 7. Welch's Method Power Spectral Density (PSD)
55 let mut psd_out = [0.0f32; 32];
56 let mut sine_wave = [0.0f32; 128];
57 for (i, val) in sine_wave.iter_mut().enumerate() {
58 *val = (2.0 * core::f32::consts::PI * 100.0 * (i as f32) / 1000.0).sin();
59 }
60 welch_psd_f32(
61 &sine_wave,
62 &mut psd_out,
63 64,
64 32,
65 1000.0,
66 WelchWindow::Hamming,
67 true,
68 );
69 println!("Welch PSD (dB) at bin 6: {:.2} dB", psd_out[6]);
70
71 // 8. 2D Spatial Processing (2D DCT & Sobel Edge Detection)
72 let img_4x4 = [
73 0.0f32, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0, 0.0, 0.0, 10.0, 10.0,
74 ];
75 let mut edges = [0.0f32; 16];
76 sobel_edge_detection_f32(&img_4x4, &mut edges, 4, 4, 15.0);
77 println!("2D Sobel Edge Output (4x4): {:?}", edges);
78
79 // 9. Weighted Polynomial Least-Squares Sensor Calibration
80 let x_cal = [0.0f32, 1.0, 2.0, 3.0, 4.0];
81 let y_cal = [2.0f32, 5.0, 8.0, 11.0, 14.0]; // y = 2 + 3x
82 let mut cal_coeffs = [0.0f32; 2];
83 polynomial_least_squares_fit(&x_cal, &y_cal, None, 1, &mut cal_coeffs);
84 println!(
85 "Fitted Sensor Calibration: y = {:.2} + {:.2}*x",
86 cal_coeffs[0], cal_coeffs[1]
87 );
88}More examples
examples/motor_control_foc.rs (line 188)
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 Clone for PidInstanceF32
impl Clone for PidInstanceF32
Source§fn clone(&self) -> PidInstanceF32
fn clone(&self) -> PidInstanceF32
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 Debug for PidInstanceF32
impl Debug for PidInstanceF32
Source§impl Default for PidInstanceF32
impl Default for PidInstanceF32
Source§fn default() -> PidInstanceF32
fn default() -> PidInstanceF32
Returns the “default value” for a type. Read more
Source§impl DspNode<f32> for PidInstanceF32
Available on crate feature controller only.
impl DspNode<f32> for PidInstanceF32
Available on crate feature
controller only.Source§fn process_sample(&mut self, input: f32) -> f32
fn process_sample(&mut self, input: f32) -> f32
Process a single input sample and produce one output sample.
Source§fn process_block(&mut self, in_buf: &[T], out_buf: &mut [T])
fn process_block(&mut self, in_buf: &[T], out_buf: &mut [T])
Process a block of samples from
in_buf into out_buf.Source§fn process_in_place(&mut self, buf: &mut [T])
fn process_in_place(&mut self, buf: &mut [T])
Process a block of samples in place.
Source§impl PartialEq for PidInstanceF32
impl PartialEq for PidInstanceF32
impl StructuralPartialEq for PidInstanceF32
Auto Trait Implementations§
impl Freeze for PidInstanceF32
impl RefUnwindSafe for PidInstanceF32
impl Send for PidInstanceF32
impl Sync for PidInstanceF32
impl Unpin for PidInstanceF32
impl UnsafeUnpin for PidInstanceF32
impl UnwindSafe for PidInstanceF32
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