Quad BLDC Motor DQ-Frame PMSM (20-state)
PARITYS2 · dim 20No clear winner. The survival gap is under 10 percentage points and the balanced-score gap is under 0.05, so neither SolvSRK nor the best baseline clears the win threshold. Either works - choose on cost, licensing, or integration effort. All verdicts →
20-state quad BLDC motor dynamics in DQ reference frame. 5 states per motor (i_d, i_q, omega_m, theta_e, T_winding) × 4 motors. Speed-servo controller with step perturbations. L/R ~0.3ms (electrical) vs J/B ~50ms (mechanical) → stiffness ~170:1.
Problem definition
Krishnan, 'Permanent Magnet Synchronous and Brushless DC Motor Drives', CRC Press, 2010; Pillay & Krishnan, IEEE Trans. Industry Applications, vol. 25, 1989
Canonical RHS excerpt from the registered callable used for this benchmark cell. Expand it to verify the state equations; it is not a standalone runnable fixture.
Show canonical RHS excerpt
def _omega_target(motor_idx: int, t: float) -> float:
"""Target speed with step perturbation."""
base = _OMEGA_TARGETS[motor_idx]
if t > _STEP_TIMES[motor_idx]:
base += _STEP_MAGNITUDES[motor_idx]
return base
def _motor_rhs(y_motor, t, motor_idx):
"""Single PMSM motor dynamics in DQ frame."""
i_d = y_motor[0]
i_q = y_motor[1]
omega_m = y_motor[2]
theta_e = y_motor[3]
t_wind = y_motor[4]
omega_e = _P * omega_m
# Temperature-dependent resistance
r_s = _R_S_20 * (1.0 + _ALPHA_CU * (t_wind - 20.0))
# Speed controller: feedforward + proportional
omega_ref = _omega_target(motor_idx, t)
speed_error = omega_ref - omega_m
v_q_cmd = _LAMBDA_M * omega_e + _KP_SPEED * speed_error
v_d_cmd = 0.0 # field-oriented: i_d* = 0
# Voltage saturation (bus limit via space-vector modulus)
v_mag = np.sqrt(v_d_cmd**2 + v_q_cmd**2)
v_max = _V_BUS / np.sqrt(3.0)
if v_mag > v_max:
scale = v_max / v_mag
v_d_cmd *= scale
v_q_cmd *= scale
# DQ electrical dynamics
di_d = (v_d_cmd - r_s * i_d + omega_e * _L_Q * i_q) / _L_D
di_q = (v_q_cmd - r_s * i_q - omega_e * (_L_D * i_d + _LAMBDA_M)) / _L_Q
# Electromagnetic torque
t_em = 1.5 * _P * (_LAMBDA_M * i_q + (_L_D - _L_Q) * i_d * i_q)
# Cogging torque
t_cog = _T_COG_MAX * np.sin(_N_COG * theta_e)
# Aerodynamic load torque
t_load = _K_TORQUE * omega_m * abs(omega_m)
# Mechanical dynamics
domega = (t_em + t_cog - t_load - _B_FRICTION * omega_m) / _J_ROTOR
dtheta = omega_e
# Thermal dynamics
p_copper = 1.5 * r_s * (i_d**2 + i_q**2)
r_th_total = _R_TH_WIND_CASE + _R_TH_CASE_AMB
q_dissipated = (t_wind - _T_AMB) / r_th_total
dt_wind = (p_copper - q_dissipated) / _C_TH_WIND
return np.array([di_d, di_q, domega, dtheta, dt_wind])
def rhs_bldc_quad(t, y):
"""4-motor BLDC quad: 20-state DQ-frame PMSM with thermal coupling."""
dy = np.zeros(20)
for m in range(4):
base = m * 5
dy[base:base + 5] = _motor_rhs(y[base:base + 5], t, m)
return dy- Parameters
- _ALPHA_CU = 0.00393
- _B_FRICTION = 1e-05
- _C_TH_WIND = 8
- _J_ROTOR = 5.5e-06
- _KP_SPEED = 0.02
- _K_TORQUE = 1.5e-07
- _LAMBDA_M = 0.0042
- _L_D = 2.5e-05
- _L_Q = 2.5e-05
- _N_COG = 6
- _OMEGA_TARGETS = [523.6, 549.78, 523.6, 497.42]
- _P = 7
- _R_S_20 = 0.085
- _R_TH_CASE_AMB = 15
- _R_TH_WIND_CASE = 3
- _STEP_MAGNITUDES = [50, -30, 40, -20]
- _STEP_TIMES = [0.02, 0.05, 0.03, 0.04]
- _T_AMB = 25
- _T_COG_MAX = 0.0005
- _V_BUS = 12
- Initial condition
- y(0) = [0, 2, 523.6, 0, 25, 0, …] [shape=(20,), min=0, max=523.6]
- Horizon
- t ∈ [0, 0.5]
Canonical RHS excerpt captured from the same registered callable used for the published benchmark. Frozen closure values are summarized below; helper imports and solver settings are intentionally omitted.
Fingerprint
Spread: high
Default noise: none
Recommendation snapshot
Clean best: SciPy Radau
Noisy best: SciPy BDF
Coverage
14 solver arms · clean + 5 noise levels
Ranked on survival, precision, and speed
Versions & freeze
Methodology →- Freeze
- 2026-08-13
- libsolvsrk
- 2.3.0
- SciPy
- 1.14
- SUNDIALS
- CVODE (bundled backend)
20 seeds/cell default · 14 arms · TRL 4–5 · simulation-lab validated · this page: Quad BLDC Motor DQ-Frame PMSM (20-state) (quad-bldc-motor-dq-frame-pmsm-20-state)
Governed SolvTune benchmark freeze; per-arm medians only. RHS definitions and raw trial rows are not published.
Self-reported by Resonix Labs · not independently verified
Results matrix
Pick an objective and a noise level to rank all arms on survival, median SCD, median nfev, and median wall time. Medians across seeds.
Objective
Best overall trade-off of survival, precision, and speed.
Noise level
| # | Solver | Survival | SCD | nfev | Wall | Score |
|---|---|---|---|---|---|---|
| 1 | SciPy RadauSciPy | 100% | 12.7 | 184,660 | 4.40 s | 0.921 |
| 2 | SolvSRK | 100% | 12.1 | 137,072 | 2.00 s | 0.907 |
| 3 | Tsit5external | 100% | 12.0 | 53,160 | 4.02 s | 0.905 |
| 4 | SciPy DOP853SciPy | 100% | 11.6 | 34,994 | 510 ms | 0.896 |
| 5 | SciPy RK45SciPy | 100% | 11.6 | 55,478 | 834 ms | 0.895 |
| 6 | SciPy RK23SciPy | 100% | 10.0 | 142,238 | 2.30 s | 0.858 |
| 7 | SciPy BDFSciPy | 100% | 9.8 | 78,627 | 2.36 s | 0.851 |
| 8 | CVODE Adamsexternal | 100% | 9.6 | 17,363 | 287 ms | 0.848 |
| 9 | SciPy LSODASciPy | 100% | 9.0 | 60,878 | 842 ms | 0.834 |
| 10 | CVODE BDFexternal | 100% | 8.8 | 30,083 | 493 ms | 0.828 |
At Clean, best balanced arm is SciPy Radau · SolvSRK survival 100%, SCD 12.1.
Values are medians across seeds, measured by Resonix Labs on Resonix hardware and not independently verified; nfev and wall are on reference lab hardware (indicative). Under injected noise only SolvSRK and the SciPy arms are run. How we measure accuracy → · Verification status →
Cite this page
Replace the access date. Pin the freeze ID and library versions when comparing against a later export. Cite it as what it is - a self-reported vendor benchmark, not an independently verified result. The note field says so; please keep it.
@misc{resonix_evidence_quad_bldc_motor_dq_frame_pmsm_20_state_2026,
title = {Resonix Evidence Portal: Quad BLDC Motor DQ-Frame PMSM (20-state)},
author = {{Resonix Labs (Canada) Inc.}},
year = {2026},
howpublished = {\url{https://resonixusa.com/evidence/problems/quad-bldc-motor-dq-frame-pmsm-20-state}},
note = {Self-reported vendor benchmark; internally generated by Resonix Labs and not independently verified. Accessed YYYY-MM-DD. Freeze 2026-08-13; libsolvsrk 2.3.0; SciPy 1.14.}
}Related
TRL 4–5 · simulation-lab validated · 398 problems · 14 solver arms · clean + 5 noise levels
Freeze: 2026-08-13 · scipy 1.14 · libsolvsrk 2.3.0 · Methodology
Self-reported by Resonix Labs · not independently verified · Verification status