Controllers
The discrete FOC control blocks. Each follows the same convention: a *State / *Params / *Output struct trio plus a mutating *_step! function, called once per fixed-step iteration of the hybrid loop.
Inner current controller
Runs closest to the machine, turning dq current references into a dq voltage command.
InductionMachineDrives.CurrentControllerDiscreteOutput — Type
CurrentControllerDiscreteOutput(; kwargs...)Result of one current_controller_step! call. A fresh instance is returned each sample; nothing here is carried over, the loop's memory lives in CurrentControllerDiscreteState.
Only vsd/vsq drive the plant. Everything else is diagnostic and is what the simulators log per sample.
Fields
vsd,vsq: the dq stator voltage command in V, after feedforward and saturation. This is the block's actual output, rotated to alpha-beta by the caller.isd_ref_lim,isq_ref_lim: current references in A after limiting to theIs_maxcircle with d-axis priority.isd_filt,isq_filt: the filtered measurements in A actually used this sample.err_d,err_q: the regulated current errors in A.vsd_PI,vsq_PI: PI contribution in V, proportional plus integrator.vsd_ff,vsq_ff: decoupling feedforward in V.vsq_ffincludes the back-EMF termomega_e*k*lambda_rd. Both are zero whenuse_feedforwardisfalse.vsd_unsat,vsq_unsat: the command in V before saturation, i.e. PI plus feedforward.vs_mod_unsat: magnitude of that unsaturated command in V. Compare againstVs_maxto see how much voltage headroom is left.saturado:truewhen the voltage limit was hit this sample (saturado is Spanish for saturated, kept from the MATLAB original).is_mod: magnitude of the filtered current vector in A.
See also CurrentControllerDiscreteParams.
InductionMachineDrives.CurrentControllerDiscreteParams — Type
CurrentControllerDiscreteParams(; kwargs...)Immutable tuning and machine constants of the discrete FOC inner current loop, consumed by current_controller_step!. Defaults describe the small bench machine; the 160 kW case passes its own values.
The PI gains are not stored — they are derived from these parameters on every step as tau_cl = ts_spec/3, Kp = sigma_Lss/tau_cl, Ki = Rs/tau_cl and Kaw = 1/Kp, so changing ts_spec between steps retunes the loop immediately.
Fields
Rs: stator resistance in Ω, sets the integral gain.sigma_Lss: transient inductanceLss - Lm^2/Lrrin H, sets the proportional gain and the cross-coupling feedforward.k: rotor coupling coefficientLm/Lrr, dimensionless, scales the back-EMF feedforward.Ts: controller sample time in s.ts_spec: specified closed-loop settling time of the current loop in s.tau_f: time constant in s of the optional current measurement filter.Vs_max: stator voltage magnitude limit in V. The command is scaled, not clipped per axis, so its direction survives saturation.Is_max: stator current magnitude limit in A, applied to the references with d-axis priority.use_filter,use_feedforward,use_saturation,use_antiwindup: development flags for switching the corresponding stage off. All default totrue, which is what every simulator in this package uses.
See also CurrentControllerDiscreteState, CurrentControllerDiscreteOutput.
InductionMachineDrives.CurrentControllerDiscreteState — Type
CurrentControllerDiscreteState(; kwargs...)Mutable state carried by the discrete FOC inner current loop between samples, advanced in place by current_controller_step!. All fields default to zero, which is the correct start for a machine at standstill; a non-zero start is better handled by passing reset = true on the first step, which seeds the filters from the present measurements.
Fields
ui_d,ui_q: d- and q-axis PI integrator states in V. Updated byKi * err * Tseach sample, minus the anti-windup back-calculation term when the voltage command saturates.isd_filt,isq_filt: one-pole low-pass filtered dq current measurements in A. Bypassed (set equal to the raw measurement) whenuse_filterisfalse.
See also CurrentControllerDiscreteParams, CurrentControllerDiscreteOutput.
InductionMachineDrives.current_controller_step! — Method
current_controller_step!(state, p; isd_ref, isq_ref, isd_med, isq_med,
omega_e, lambda_rd, reset = false)Advance the discrete FOC inner current loop by one sample period p.Ts.
This is the innermost block of the hybrid loop: it turns dq current references into the dq stator voltage command that is then rotated to alpha-beta and applied to the plant. It is called once per fixed-step iteration, after the outer torque or speed loop has produced isd_ref/isq_ref.
state is mutated in place — the two integrator states ui_d/ui_q and the two filtered measurements isd_filt/isq_filt. The result is returned as a fresh CurrentControllerDiscreteOutput.
Arguments
state::CurrentControllerDiscreteState: integrator and filter state, mutated.p::CurrentControllerDiscreteParams: machine constants, tuning, limits and the four feature flags.isd_ref,isq_ref: dq current references in A, before limiting.isd_med,isq_med: measured dq currents in A (medfor medido).omega_e: electrical angular frequency in rad/s, used by the decoupling feedforward only.lambda_rd: d-axis rotor flux linkage in Wb, normally from the rotor-flux observer.reset: whentrue, zero both integrators and seed the filter states with the present measurements, giving a bumpless start. Applied before anything else in the step.
Steps
- PI gains. Recomputed every call from
p:tau_cl = ts_spec/3,Kp = sigma_Lss/tau_cl,Ki = Rs/tau_cl, and the back-calculation gainKaw = 1/Kp. The integrator accumulatesKi * err * Ts, soKicarries units of V/(A·s). - Measurement filter. With
use_filter, a one-pole low pass withalpha = Ts/(tau_f + Ts); otherwise the raw measurements pass through. - Reference limiting, d-axis priority. The flux-producing axis wins: if
|isd_ref| > Is_maxit is clamped andisq_ref_limis forced to zero. Otherwiseisq_refis limited tosqrt(Is_max^2 - isd_ref_lim^2), so the commanded current vector stays inside theIs_maxcircle. - PI on the errors, proportional part plus stored integrator.
- Feedforward decoupling, with
use_feedforward:vsd_ff = -omega_e*sigma_Lss*isq_filtandvsq_ff = omega_e*sigma_Lss*isd_filt + omega_e*k*lambda_rd, the second term being the back-EMF. - Voltage saturation, with
use_saturation: if the unsaturated command exceedsVs_maxin magnitude, both components are scaled by the same factor, preserving direction rather than clipping per axis, andsaturadois set. - Anti-windup, with
use_antiwindup: when saturated, the integrator is corrected byKawtimes the difference between the unsaturated and saturated PI parts, feedforward excluded.
The four flags exist for development and bring-up; all default to true, which is the configuration the simulators use.
See also CurrentControllerDiscreteState, CurrentControllerDiscreteParams and CurrentControllerDiscreteOutput.
Outer torque loop, F1 constant flux
InductionMachineDrives.OuterTorqueFluxF1Output — Type
OuterTorqueFluxF1Output(; kwargs...)Result of one outer_torque_flux_f1_step! call, returned fresh each sample. isd_ref/isq_ref are what the inner current controller consumes; the rest is diagnostic.
Fields
isd_ref,isq_ref: dq current references in A forcurrent_controller_step!.Te_ref_out: torque reference in N·m after slew-rate limiting and clamping toTe_max.lambda_ref_out: rotor flux reference in Wb. Constant atLm*isd_nomin F1 mode.e_wm,e_Te,e_lambda: always zero here. They exist so torque and speed outer loops share an output layout; only the speed loops fill ine_wm.sat_isd,sat_isq,sat_Te: saturation flags,+1at the upper limit,-1at the lower limit,0when unlimited.T_load_est: theTLargument passed through unchanged, logged for comparison. This block does not use it.Kt_nom: nominal torque constant1.5*p*k*Lm*isd_nomin N·m/A used for the torque-to-isqmap.isq_max_disp: q-axis current in A still available inside theIs_maxcircle after the d-axis has taken its share (disponible, available).
See also OuterTorqueFluxF1Params.
InductionMachineDrives.OuterTorqueFluxF1Params — Type
OuterTorqueFluxF1Params(; kwargs...)Machine constants and limits of the F1 constant-flux torque outer loop, consumed by outer_torque_flux_f1_step!.
Fields
Ts: sample time in s. Both slew-rate limits are converted to a per-sample step with it.p: pole pairs.Lm,Lrr: magnetizing and rotor inductance in H. They fix the coupling coefficientk = Lm/Lrrand hence the nominal torque constantKt_nom = 1.5*p*k*Lm*isd_nom.isd_nom: the constant d-axis current reference in A that defines F1 mode. Flux is held atLm*isd_nomat all speeds — there is no field weakening in this block.Is_max: stator current magnitude limit in A, bounding the dq reference vector with d-axis priority.isd_min: lower bound in A on the d-axis reference, so the machine is never left without flux.Te_max: torque reference magnitude limit in N·m.Te_dot_max: torque reference slew rate in N·m/s.id_dot_max: d-axis current reference slew rate in A/s. Rotor flux cannot change instantly, so the flux command is ramped rather than stepped.
See also OuterTorqueFluxF1State, OuterTorqueFluxF1Output.
InductionMachineDrives.OuterTorqueFluxF1State — Type
OuterTorqueFluxF1State(; kwargs...)Mutable state of the F1 constant-flux torque outer loop, advanced in place by outer_torque_flux_f1_step!. This loop has no integrator: its only memory is the two slew-rate limiters (ant for anterior, the previous value).
Fields
Te_ref_ant: previous ramped torque reference in N·m, the starting point for this sample'sTe_dot_maxstep.id_ref_ant: previous ramped d-axis current reference in A. The default equals the defaultisd_nom, so a fresh state starts at nominal flux instead of ramping up from zero.
See also OuterTorqueFluxF1Params, OuterTorqueFluxF1Output.
InductionMachineDrives.outer_torque_flux_f1_step! — Method
outer_torque_flux_f1_step!(state, p; Te_ref_ext, TL = 0.0, reset = false)Advance the F1 constant-flux torque outer loop by one sample period p.Ts and return the dq current references the inner current controller should track.
This is the mode_control = 1 (TORQUE) + mode_torque = 1 (T1) + mode_flux = 1 (F1) path of the MATLAB original: an externally commanded torque is slew- and magnitude-limited, then converted to isq through the nominal torque constant, while isd is held at nominal flux. There is no feedback here — the block is a feedforward reference shaper, so it has no integrator and cannot wind up.
state is mutated in place; the result is a fresh OuterTorqueFluxF1Output.
Arguments
state::OuterTorqueFluxF1State: the two slew-rate limiter memories, mutated.p::OuterTorqueFluxF1Params: machine constants and limits.Te_ref_ext: externally commanded electromagnetic torque in N·m. Positive accelerates toward positive speed, perJ*dω/dt = Te + TL - B*ω.TL: load torque in N·m, passed through toT_load_estfor logging only. Same sign convention: positiveTLalso accelerates toward positive speed.reset: whentrue, reinitialise the ramp states and seed the torque ramp atTe_ref_ext, so the first step does not ramp up from zero.
Steps
- Torque reference shaping.
Te_ref_extis ramped atTe_dot_maxand then clamped to±Te_max, settingsat_Te. - F1 flux reference.
isdtargets the constantisd_nom, ramped atid_dot_maxand clamped to[isd_min, Is_max]. - Torque-to-current map.
isq_ref = Te_ref_out / Kt_nomwith the nominal torque constant. Because flux is constant in F1, this map is exact as long as the actual flux equalsLm*isd_nom. - Current-circle limiting, d-axis priority.
isq_refis clamped tosqrt(Is_max^2 - isd_ref^2), so flux is preserved and torque gives way.
See also outer_speed_flux_f1_step! for the speed-controlled counterpart, and outer_speed_flux_mtpa_step! for the variable-flux alternative.
Outer speed loop, F1 constant flux
InductionMachineDrives.OuterSpeedFluxF1Output — Type
OuterSpeedFluxF1Output(; kwargs...)Result of one outer_speed_flux_f1_step! call, returned fresh each sample. isd_ref/isq_ref drive the inner current controller; everything else is diagnostic and is logged per sample by the speed simulators.
Fields
isd_ref,isq_ref: dq current references in A forcurrent_controller_step!.Te_ref_out: torque reference in N·m after clamping to±Te_max, i.e.Te_PI + Te_fflimited.lambda_ref_out: rotor flux reference in Wb,Lm*isd_ref. EqualsLm*isd_nombelow base speed and drops in field weakening.wm_ref_ramp: speed reference in rad/s afterwm_dot_maxslew limiting — the reference the PI actually regulates against.wm_filt: filtered speed measurement in rad/s.e_wm: speed errorwm_ref_ramp - wm_filtin rad/s.e_Te,e_lambda: always zero, kept for layout compatibility with the other outer loops.sat_isd,sat_isq,sat_Te: saturation flags,+1upper,-1lower,0unlimited.T_load_est: theTL_estargument passed through, whether or not feedforward used it.Kt_nom: torque constant in N·m/A at nominal flux.isq_max_disp: q-axis current in A still available inside theIs_maxcircle after the d-axis share.Kt_ref: torque constant in N·m/A at the actual flux reference. Differs fromKt_nomonly under field weakening, and it is the one used for the torque-to-isqmap.isd_ref_no_fw: the d-axis reference in A that would have been commanded without field weakening, i.e.isd_nom.fw_speed:max(|wm_filt|, |wm_ref_ramp|)in rad/s, the speed the field-weakening decision is based on. Using the larger of the two avoids weakening too late during fast reel-in/reel-out transients.field_weakening_active:1while the flux is being reduced,0otherwise.Te_PI: PI contribution to the torque reference in N·m.Te_ff: feedforward contribution in N·m,load_ff_sign*TL_est + B*wm_ref_ramp + J*dωref/dt.
See also OuterSpeedFluxF1Params.
InductionMachineDrives.OuterSpeedFluxF1Params — Type
OuterSpeedFluxF1Params(; kwargs...)Machine constants, tuning and limits of the F1 constant-flux speed outer loop, consumed by outer_speed_flux_f1_step!.
As in the inner loop, the PI gains are derived on every step rather than stored: Kp_wm = J/(ts_wm/3), Ki_wm = Kp_wm/min(J/B, ts_dist_wm) and Kaw_wm = 1/Kp_wm.
Fields
Ts: sample time in s.p: pole pairs.Lm,Lss,Lrr: magnetizing, stator and rotor inductance in H.Lssis used only by the field-weakening voltage ellipse.J: total inertia in kg·m², motor plus load. SetsKp_wmand the acceleration feedforward.B: viscous friction coefficient in N·m·s/rad, opposing motion inJ*dω/dt = Te + TL - B*ω. Enters both the integral time constant and the friction feedforward.isd_nom: nominal d-axis current in A — the flux level F1 holds below base speed.Is_max: stator current magnitude limit in A.isd_min: lower bound in A on the d-axis reference, also the floor of field weakening.Te_max: torque reference magnitude limit in N·m.wm_dot_max: speed reference slew rate in rad/s². Set it very high (e.g.1e6) when a recorded profile should be played back unaltered.id_dot_max: d-axis current reference slew rate in A/s.use_field_weakening: whentrue, reduce flux abovewm_base_fwinstead of holdingisd_nomat all speeds.wm_base_fw: mechanical base speed in rad/s above which field weakening starts. Compared internally in electrical terms, asp*wm_base_fw.Vs_max: stator voltage limit in V used by the field-weakening voltage ellipse. Keep it consistent with the inner controller'sVs_max.tau_f_wm: speed measurement filter time constant in s.ts_wm: specified closed-loop settling time of the speed loop in s.ts_dist_wm: disturbance-rejection time constant in s, capping the integral time constant when the mechanical time constantJ/Bis long.use_load_feedforward: whentrue, addload_ff_sign * TL_estto the feedforward torque. Requires a meaningfulTL_est, e.g. fromload_torque_kalman_step!.load_ff_sign: sign of that term,-1.0by design. WithJ*dω/dt = Te + TL - B*ωa positiveTLalready accelerates the machine, so cancelling it requiresTe_ff = J*dωref/dt + B*ωref - TL_est. Flipping this to+1doubles the disturbance instead of rejecting it.
See also OuterSpeedFluxF1State, OuterSpeedFluxF1Output.
InductionMachineDrives.OuterSpeedFluxF1State — Type
OuterSpeedFluxF1State(; kwargs...)Mutable state of the F1 constant-flux speed outer loop, advanced in place by outer_speed_flux_f1_step! (ant is anterior, the previous value).
Fields
ui_wm: speed PI integrator state in N·m, corrected by back-calculation when the torque reference saturates.wm_filt: low-pass filtered mechanical speed measurement in rad/s.wm_ref_ant: previous ramped speed reference in rad/s. Its per-sample change also supplies theJ*dω/dtfeedforward term.id_ref_ant: previous ramped d-axis current reference in A, defaulting to the defaultisd_nomso a fresh state starts at nominal flux.
See also OuterSpeedFluxF1Params, OuterSpeedFluxF1Output.
InductionMachineDrives.outer_speed_flux_f1_step! — Method
outer_speed_flux_f1_step!(state, p; wm_ref, wm_med, omega_e = nothing,
TL_est = 0.0, reset = false)Advance the F1 constant-flux speed outer loop by one sample period p.Ts and return the dq current references for the inner current controller.
This is the mode_control = 2 (SPEED) + mode_torque = 1 (T1) + mode_flux = 1 (F1) path of the MATLAB original, extended with optional field weakening and optional load-torque feedforward. A PI on speed error plus a model-based feedforward produces a torque reference, which is then mapped to isq at the commanded flux level.
state is mutated in place; the result is a fresh OuterSpeedFluxF1Output.
Arguments
state::OuterSpeedFluxF1State: PI integrator, speed filter and the two ramp memories, mutated.p::OuterSpeedFluxF1Params: machine constants, tuning and limits.wm_ref: commanded mechanical speed in rad/s, before slew limiting. Signed — the loop tracks both directions.wm_med: measured mechanical speed in rad/s (medfor medido).omega_e: synchronous electrical speed in rad/s, normallyRotorFluxObserverDiscreteOutput.omega_e. Used only by field weakening. Passnothing(the default) and the block falls back to the pole-pair-scaled mechanical speedp*fw_speed; a non-finite value takes the same fallback.TL_est: estimated load torque in N·m, positive when it accelerates toward positive speed. Only used whenp.use_load_feedforwardistrue.reset: whentrue, zero the integrator, seed the speed filter withwm_medand the reference ramp withwm_ref, and restore nominal flux. Applied before anything else in the step.
Steps
- Speed filtering and reference ramp. One-pole filter with
alpha = Ts/(tau_f_wm + Ts); the reference is slew-limited atwm_dot_max. - PI plus feedforward.
Te_ref = Kp_wm*e_wm + ui_wm + (load_ff_sign*TL_est + B*wm_ref_ramp + J*dωref/dt), clamped to±Te_max. The integrator is then updated withKi_wm*e_wm*TsminusKaw_wmtimes the clamped-away excess, so the loop does not wind up against the torque limit. - Flux reference. Constant
isd_nom, unlessuse_field_weakeningistrueand the electrical speed exceedsp*wm_base_fw. Thenisd_refis the smallest ofisd_nom, the inverse-speed limitisd_nom*ω_base/ω, and the steady-state voltage-ellipse limit built fromVs_max, floored atisd_min. The result is ramped atid_dot_max, since rotor flux cannot step. - Torque-to-current map.
isq_ref = Te_ref_out / Kt_refwhereKt_refuses the achieved fluxLm*isd_ref, not the nominal one — this is what keeps the torque correct while the field is weakened. - Current-circle limiting, d-axis priority, as in the torque loop.
Note that the mechanical convention J*dω/dt = Te + TL - B*ω is what fixes load_ff_sign = -1.0. Changing that sign turns load feedforward from compensation into amplification.
See also outer_speed_flux_mtpa_step! for the variable-flux alternative, load_torque_kalman_step! for producing TL_est, and simulate_foc_speed_f1_hybrid for a complete loop using this block.
Outer speed loop, constrained MTPA with field weakening
See MTPA integration for the include-order constraint that this controller imposes on src/InductionMachineDrives.jl.
InductionMachineDrives.OuterSpeedFluxMTPAOutput — Type
OuterSpeedFluxMTPAOutput(; kwargs...)Result of one outer_speed_flux_mtpa_step! call, returned fresh each sample. isd_ref/isq_ref drive the inner current controller; the diagnostics below make it possible to see which constraint set the flux at any instant.
Fields
isd_ref,isq_ref: dq current references in A forcurrent_controller_step!.Te_ref_out: torque reference in N·m after clamping to±Te_max.lambda_ref_out: rotor flux reference in Wb,Lm*isd_ref. Unlike F1 this moves continuously with the torque demand.wm_ref_ramp: slew-limited speed reference in rad/s.wm_filt: filtered speed measurement in rad/s.e_wm: speed error in rad/s.e_Te,e_lambda: always zero, kept for layout compatibility.sat_isd,sat_isq,sat_Te: saturation flags,+1upper,-1lower,0unlimited.T_load_est: theTL_estargument passed through.Kt_isd: the bilinear torque coefficient1.5*p*Lm^2/Lrrin N·m/A².isd_mtpa: the unconstrained MTPA solutionsqrt(|Te_ref|/Kt_isd)in A.isd_floor: flux-floor constraintlambda_rd_floor/Lmin A, or0when disabled.isd_reserve: torque-reserve constraint in A, or0when disabled.isd_desired: the applied target,maxof the three above andisd_min, capped atIs_max/sqrt(2). Comparing it against the three tells you which constraint is binding.isq_max_disp: q-axis current in A available inside the current circle.Te_current_limited: torque in N·m actually achievable with the commandedisd_ref/isq_ref, i.e.Kt_isd*isd_ref*isq_ref. BelowTe_ref_outwhenever the current circle bites.torque_current_limited:1whenisqhit the circle limit,0otherwise.Te_PI: PI contribution in N·m.Te_ff: feedforward contribution in N·m.
See also OuterSpeedFluxMTPAParams.
InductionMachineDrives.OuterSpeedFluxMTPAParams — Type
OuterSpeedFluxMTPAParams(; kwargs...)Machine constants, tuning and limits of the constrained-MTPA speed outer loop, consumed by outer_speed_flux_mtpa_step!. The speed PI is designed exactly as in OuterSpeedFluxF1Params; the extra fields are the three constraints that make plain MTPA usable on a winch.
Fields
Ts: sample time in s.p: pole pairs.Lm,Lrr: magnetizing and rotor inductance in H. They fixKt_isd = 1.5*p*Lm^2/Lrr, the constant of the bilinear torque modelTe = Kt_isd * isd * isq.J: total inertia in kg·m².B: viscous friction coefficient in N·m·s/rad.isd_nom: d-axis current in A used to initialise the ramp state on reset. In MTPA it is a starting point, not a setpoint.Is_max: stator current magnitude limit in A. Also caps the MTPA solution atIs_max/sqrt(2), the point whereisd = isqfills the current circle.isd_min: lower bound in A on the d-axis reference.Te_max: torque reference magnitude limit in N·m.wm_dot_max: speed reference slew rate in rad/s².id_dot_max: d-axis current reference slew rate in A/s.lambda_rd_floor: minimum rotor flux in Wb to hold regardless of torque demand. Pure MTPA collapses the flux near zero torque, which would leave the machine unable to respond; this is the floor that prevents it. Set to0to disable.Te_reserve: torque in N·m that must remain achievable withinIs_maxat any moment. Translated into a flux floorTe_reserve/(1.5*p*k*Lm*Is_max), it buys fast response to a sudden load change at the cost of some efficiency. Set to0to disable.tau_f_wm: speed measurement filter time constant in s.ts_wm: specified closed-loop settling time of the speed loop in s.ts_dist_wm: disturbance-rejection time constant in s.use_load_feedforward: whentrue, addload_ff_sign * TL_estto the feedforward torque.load_ff_sign:-1.0by design, as required byJ*dω/dt = Te + TL - B*ω.
See also OuterSpeedFluxMTPAState, OuterSpeedFluxMTPAOutput.
InductionMachineDrives.OuterSpeedFluxMTPAState — Type
OuterSpeedFluxMTPAState(; kwargs...)Mutable state of the constrained-MTPA speed outer loop, advanced in place by outer_speed_flux_mtpa_step!. Layout is identical to OuterSpeedFluxF1State — the two controllers differ in how they choose the flux level, not in what they remember.
Fields
ui_wm: speed PI integrator state in N·m.wm_filt: filtered mechanical speed in rad/s.wm_ref_ant: previous ramped speed reference in rad/s.id_ref_ant: previous ramped d-axis current reference in A. Unlike F1, this one keeps moving during normal operation, since MTPA retargets the flux whenever the torque demand changes.
See also OuterSpeedFluxMTPAParams, OuterSpeedFluxMTPAOutput.
InductionMachineDrives.outer_speed_flux_mtpa_step! — Method
outer_speed_flux_mtpa_step!(state, p; wm_ref, wm_med, TL_est = 0.0,
reset = false)Advance the constrained-MTPA speed outer loop by one sample period p.Ts and return the dq current references for the inner current controller.
Counterpart of outer_speed_flux_f1_step! with the same speed PI and the same feedforward, but a different flux policy. F1 holds isd at isd_nom whatever the torque; this block chooses isd per sample to minimise stator current for the torque demanded — Maximum Torque Per Ampere — using the bilinear model
Te = Kt_isd * isd * isq, Kt_isd = 1.5 * p * Lm^2 / Lrrwhose optimum is isd = |isq|, i.e. isd_mtpa = sqrt(|Te_ref|/Kt_isd). Pure MTPA is not usable on its own — it starves the flux at low torque, so the machine cannot respond to a sudden load — hence the three floors described below. This is the mode_flux = F3 path of the MATLAB original.
state is mutated in place; the result is a fresh OuterSpeedFluxMTPAOutput.
Arguments
state::OuterSpeedFluxMTPAState: PI integrator, speed filter and the two ramp memories, mutated.p::OuterSpeedFluxMTPAParams: machine constants, tuning, limits and the two constraint settings.wm_ref: commanded mechanical speed in rad/s, signed, before slew limiting.wm_med: measured mechanical speed in rad/s.TL_est: estimated load torque in N·m, positive when it accelerates toward positive speed. Used only whenp.use_load_feedforwardistrue.reset: whentrue, zero the integrator, seed the speed filter withwm_medand the reference ramp withwm_ref, and set the flux ramp toisd_nom.
Steps
- Speed filtering, reference ramp, PI plus feedforward — identical to
outer_speed_flux_f1_step!, including the back-calculation anti-windup against±Te_max. - Constrained flux choice.
isd_desiredis the largest of the MTPA optimumisd_mtpa, the flux floorlambda_rd_floor/Lm, the torque reserveTe_reserve/(1.5*p*k*Lm*Is_max)andisd_min, then capped atIs_max/sqrt(2)— beyond that point a largerisdcould not be matched by an equalisqinside the current circle. The result is ramped atid_dot_maxbecause rotor flux cannot change instantaneously. - Torque-to-current map.
isq_ref = Te_ref_out / (Kt_isd * isd_ref), using the flux actually commanded this sample. - Current-circle limiting, d-axis priority.
isq_refis clamped tosqrt(Is_max^2 - isd_ref^2);Te_current_limitedthen reports the torque that remains achievable.
There is deliberately no field weakening here: the flux is already speed- independent and demand-driven. If you need voltage-limit-aware flux reduction, use outer_speed_flux_f1_step! with use_field_weakening = true.
See also simulate_foc_speed_mtpa_hybrid for a complete loop using this block.