1use embedded_dsp::*;
14
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; const NUM_CONTROL_CYCLES: usize = 20;
23
24 println!("--- 1. 3-Phase Current Sensing with Inverter PWM Switching Noise ---");
28 let target_torque_current = 5.0f32; let rotor_speed_rpm = 3000.0f32;
30 let pole_pairs = 4.0f32;
31 let electrical_freq_hz = (rotor_speed_rpm * pole_pairs) / 60.0; 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 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 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 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 println!("\n--- 3. Fast Trigonometry vs Table Lookup for Rotor Angle θ ---");
88 let test_angle = core::f32::consts::FRAC_PI_3; 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 let angle_q31 = q31::from_bits(((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.to_bits() as f64 / 2147483648.0,
114 std_s,
115 c_q31,
116 c_q31.to_bits() as f64 / 2147483648.0,
117 std_c
118 );
119
120 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 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 let q15_scale = 1000.0f32; let ia_q15 = q15::from_bits((ia_filtered[step_idx] * q15_scale) as i16);
152 let ib_q15 = q15::from_bits((ib_filtered[step_idx] * q15_scale) as i16);
153 let mut q15_alpha = q15::ZERO;
154 let mut q15_beta = q15::ZERO;
155 let mut q15_d = q15::ZERO;
156 let mut q15_q = q15::ZERO;
157
158 clarke_q15(ia_q15, ib_q15, &mut q15_alpha, &mut q15_beta);
159 let sin_q15 = q15::from_bits(fast_sin_i16(theta_e[step_idx]));
160 let cos_q15 = q15::from_bits(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.to_bits() as f32 / q15_scale,
170 q15_beta,
171 q15_beta.to_bits() as f32 / q15_scale
172 );
173 println!(
174 " • Q15 Park : d = {} ({:.3} A), q = {} ({:.3} A)",
175 q15_d,
176 q15_d.to_bits() as f32 / q15_scale,
177 q15_q,
178 q15_q.to_bits() as f32 / q15_scale
179 );
180
181 println!("\n--- 5. Vector Current Regulators (Dual PID Loops for Id & Iq) ---");
185 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 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); 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 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; 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 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}