Tutorial 03 — Isolated flyback (transformer + commutation)¶
Goal. Drive a 1:1 isolated flyback converter and verify that the secondary-side capacitor settles to the expected output voltage given the duty cycle.
Concepts introduced:
- add_transformer (Layer 2 V2) — two-winding coupled inductors with mutual coupling k.
- Multi-rail topologies (primary-side and secondary-side share only the transformer).
- Why SwitchedDiode event detection is critical for hard commutation.
Reference YAML: examples/flyback.yaml.
Topology¶
┌─────┬───────┐ ┌────D_out───┬──── vout
│ │ │ │ │
Vin ────┤ L_p L_s (k = 0.95) │ C_out
│ │ │ │ │
│ ▼ │ secondary ground ───┴────────────┴─── gnd_sec
│ Q1 R_L
│ (LS switch)
│ │
⏚ ⏚ (primary gnd)
Two galvanically isolated subnets, connected only by the magnetic coupling between L_p and L_s. The transformer turns-ratio is set implicitly by L_p / L_s (here 1:1).
Python build¶
import pulsim as p
V_IN = 24.0
F_PWM = 100e3
DUTY = 0.40
b = p.CircuitBuilder()
b.add_voltage_source("Vin", "vin", "gnd", V_IN)
b.add_transformer(
"T1",
primary_pos="vin", primary_neg="sw_pri",
secondary_pos="sec_pos", secondary_neg="sec_gnd",
L_p=200e-6, L_s=200e-6, k=0.95,
)
b.add_mosfet ("Q1", "sw_pri", "gnd") # low-side switch on primary
b.add_diode ("Dout", "sec_pos", "vout", 1e3, 1e-9, V_th=0.7)
b.add_capacitor("Cout", "vout", "sec_gnd", 47e-6)
b.add_resistor ("R_L", "vout", "sec_gnd", 10.0)
# Secondary needs a path to primary ground (otherwise the
# secondary node-set is dangling). Use a tiny resistor.
b.add_resistor ("R_iso", "sec_gnd", "gnd", 1e-6)
Note on isolation. A real flyback's primary and secondary grounds are physically separate. Pulsim's MNA solver requires a connected matrix, so we tie them through a 1 µΩ "isolation resistor". This is a numerical artifact; it does not affect the physics.
Switch driver¶
pwm = p.make_pwm_switch_fn(
switch_index=0, frequency=F_PWM, duty=DUTY, phase=0.0,
)
Switch index 0 is Q1. The diode Dout has its own switch index (1), but the user does NOT drive it — event detection flips it automatically when current tries to flow backward.
Run¶
res = p.simulate(b, t_end=10e-3, dt=1e-7, switch_fn=pwm)
vout_idx = b.node_id_of("vout")
v = [s[vout_idx] for s in res.states]
k_skip = int(5e-3 / 1e-7)
print(f"V_out (mean over last half) = "
f"{sum(v[k_skip:]) / (len(v) - k_skip):.2f} V")
For ideal 1:1 ratio + 40 % duty: V_out ≈ V_in · D / (1 − D) ≈ 16 V (continuous conduction; less in DCM, more with leakage spike).
Two switch states, four commutations¶
The flyback alternates between two large-signal states:
- Q1 ON, Dout OFF. Primary inductor energizes from
V_in. Secondary has no path (D_out blocks the reverse polarity). - Q1 OFF, Dout ON. Magnetizing energy transfers to the secondary;
D_outconducts;C_outis charged.
Every PWM edge triggers two commutations: Q1 flips, then a few hundred nanoseconds later D_out flips when the secondary voltage polarity inverts. the kernel's substep event detection (Layer 5 V2.1) finds both crossings exactly so the integration doesn't accumulate "diode briefly conducting in reverse" garbage.
Try this next¶
- Add a clamp. Real flybacks have RCD snubbers or active clamps to handle leakage-inductance spikes. Add a series-R + parallel-C across
Q1and watch the spike soften. - Multi-winding (Layer 2 V16). Use
add_multi_winding_transformerto build a 3-output flyback (main + aux bias + monitor) and verify each output settles independently. - Saturating core (Layer 2 V17). Replace
add_transformerwith twoadd_saturable_inductorcalls + aTransformerCoupling(advanced) — the boost-saturable showcase has the pattern.
Going to Tutorial 04¶
Next we leave SMPS-land and look at a 3-phase inverter for motor drive applications.