FOC Reference 04 The inverter

Space-vector PWM

The current loop finishes by asking for a voltage vector. It asks in volts, at an arbitrary angle and magnitude, as though the inverter were an ideal three-phase source.

It is not. It is six transistors, and each of the three legs can only be connected to the top rail or the bottom one. There are eight combinations, and that is the complete list of voltages the bridge can produce. Everything else — every angle, every magnitude in between — has to be manufactured by switching between them fast enough that the machine’s inductance averages the result.

This page is about how that averaging is arranged, and about the 15.5% of your DC link that the obvious method throws away.

A requested voltage vector reaching three duty cycles by two routes: the sector-and-dwell construction, and min-max injection. the construction what firmware actually runs same answer v α , v β what the PI asked for which sector? one of six dwell times T₁, T₂, T₀ switching sequence centre-aligned, T₀ split min–max injection subtract the mid-point three duties d a , d b , d c timer compares six gate edges
Two routes to the same three numbers. The construction along the top is how SVPWM is derived; the single line along the bottom is what firmware actually runs — and a test on this site asserts they agree across the whole plane.

Eight states, six of them useful

Label each state by which legs are tied high. 100 means phase to the top rail and , to the bottom.

Six of the eight put different voltages across different phases. Applying Clarke to each gives six vectors of equal length , spaced 60° apart — through . The remaining two, 000 and 111, tie all three phases to the same rail. The machine sees zero volts across its terminals in both cases. These are the null vectors, and , and they are not wasted states — they are the throttle.

Join the six active tips and you get a hexagon. Its interior is precisely the set of average voltages the bridge can synthesise.

Drag the vector, or use the arrow keys.
Left: the eight switch states and the requested vector. Right: the gate signals that produce it, over one PWM period. Drag the vector — or press Spin — and watch the sequence change as it crosses each sector boundary.

Making an arbitrary vector

Any request inside the hexagon falls between two adjacent active vectors. Spend part of the period on each, and the rest on a null vector, and the average is the request.

For a request at angle within its sector, the dwell fractions are

with on the trailing vector, on the leading one, and shared between the two null vectors.

Take the figure’s default: modulation index 0.75, sitting at 30°, so exactly mid-sector. That gives V, and . Symmetric, as it must be by symmetry of the geometry.

Why the limit is a circle, not the hexagon

A steady rotating request traces a circle. To produce it without distortion the whole circle has to fit inside the hexagon — so the binding constraint is the inscribed circle, not the vertices:

For a 48 V link that is 27.71 V peak per phase, against 32 V at the hexagon vertices. The corners are real voltage, and they are reachable — but only in six directions, so a rotating vector cannot use them without distorting.

The 15.5%

Plain sinusoidal PWM sets each phase’s duty from its own reference: . The duty hits 1 when reaches — 24 V on a 48 V link. Compare:

SPWM leaves 15.5% of the achievable voltage unused. On a motor that is 15.5% less speed before field weakening, from hardware you have already bought.

The trick to recover it is almost too simple. Add the same offset to all three duties:

which centres the three references between the rails, then compute duties as before.

A common-mode offset appears identically on all three phase terminals. The star point of an isolated-neutral machine simply floats to follow it, so the differences between phases — the only thing that drives current — are untouched. The machine cannot tell.

Modulator
One electrical cycle at modulation index 1.0. Switch between SVPWM and SPWM to see the difference, and drag the modulation index past 0.87 to watch plain SPWM clip while SVPWM keeps working.

Set the modulation index to 1.0 and switch between the two. SPWM clips badly. SVPWM’s duties reach exactly 0.0 and 1.0 and no further — the saddle-shaped waveform touches each rail without ever crossing it. The injected common mode peaks at 6.93 V, 14.4% of the link, and it is a triangular third harmonic: it completes three cycles for every one of the fundamental, which is why it never disturbs a three-phase balanced set.

On the bench Plain SPWM starts clipping above modulation index 0.866 — that is , the ratio of the two limits. If you have inherited a drive that loses the plot somewhere around 87% of full output, check the modulator before you suspect anything else.

Note that it clips near the phase peaks first, not everywhere at once. In the hexagon figure, set the modulation index to 0.9 and spin: the SPWM readout reports “in range” at 30° and “clipped” as the vector swings towards 0°. That is why the symptom is distortion rather than a hard ceiling.

Min-max is space-vector PWM

The two derivations look nothing alike. One decomposes onto basis vectors with trigonometry and a sector lookup; the other takes a max, a min and an average.

They produce identical duty cycles. The min-max form is what production firmware uses — a handful of comparisons instead of a sector branch and two sine evaluations — and the sector construction is how you understand what it is doing.

That equivalence is worth more than an assertion, so the site’s test suite derives the switching sequence independently, by sorting the six gate edges, and checks that the time spent on each vector matches the sector decomposition’s , and across the whole plane. They agree to 1e-9.

The order of the sequence matters

Knowing how long to spend on each vector does not say in what order. Centre each phase’s on-time in the period and the order falls out on its own. For the worked example above:

with the null time split evenly, 12.5% on each of and .

Two properties make this the right sequence, and both are visible in the timing diagram:

Only one leg switches at each transition. Walk the sequence: 000100110111 and back. Every step changes exactly one bit. A sequence that changed two legs at once would double the switching losses for no benefit, and inject a much larger common-mode step into the machine.

It is symmetric about the middle of the period. The pattern read backwards is the pattern read forwards, which puts the current ripple’s centroid exactly at the period midpoint. That is what makes it safe to sample phase current at the PWM centre and get the true average without filtering — which is the sampling strategy every drive relies on.

On the bench Splitting the null time evenly between 000 and 111 is what makes the pattern symmetric. Uneven splits are a real technique — discontinuous modulation parks on one null vector to cut switching losses by a third — but they give up the symmetry, and with it the clean centre-sampling.

Overmodulation

Push the request past the inscribed circle and : the two active vectors alone need more than the whole period, leaving negative null time. Drag the vector past the circle in the figure and the readout goes red.

There is no honest answer here — the bridge cannot do it. What it can do is get as close as possible, which means clamping and accepting distortion. The implementation in svpwmDuties clamps each duty to , which is the simplest and most common choice.

The useful region is between the inscribed circle and the hexagon: modulation index 1.0 to 1.155. Drives that need every last volt at high speed work here deliberately and accept the low-order harmonics that come with it.

In code

/* SVPWM by min-max injection. This is the whole modulator. */
void svpwm(float v_alpha, float v_beta, float vdc, float *duty)
{
    /* Inverse Clarke: the three phase references. */
    const float va = v_alpha;
    const float vb = -0.5f * v_alpha + SQRT3_2 * v_beta;
    const float vc = -0.5f * v_alpha - SQRT3_2 * v_beta;

    /* Centre them between the rails. */
    float vmax = fmaxf(va, fmaxf(vb, vc));
    float vmin = fminf(va, fminf(vb, vc));
    const float offset = 0.5f * (vmax + vmin);

    duty[0] = clamp01(0.5f + (va - offset) / vdc);
    duty[1] = clamp01(0.5f + (vb - offset) / vdc);
    duty[2] = clamp01(0.5f + (vc - offset) / vdc);
}

No sector lookup, no trigonometry, no dwell times. Load the three results into the timer’s compare registers in centre-aligned mode and the hardware produces the symmetric sequence for you.

What to take away

  • The bridge has eight states. Everything between them is made by averaging, and the null vectors are what set the magnitude.
  • The linear limit is the inscribed circle, , because a rotating request has to fit in every direction at once.
  • Plain SPWM reaches only and wastes 15.5% of the link. Common-mode injection recovers it for three lines of code, and the machine cannot detect the injection.
  • Min-max injection and the sector-and-dwell construction are the same modulator. Use the first, understand the second.
  • Centre-aligned duties give one switch transition per step and a symmetric pattern, which is what makes centre-of-period current sampling correct.

Next: what deadtime does to all of this, and why the compensation matters most at the speeds where you have the least voltage to spare.