, and noticed that at high speeds, some pretty significant harmonics showed up in the phase currents. Here's an example with an obvious 5th harmonic  I'm commanding 20A, peak, and the harmonics add a couple amps of ripple on top of that:
This ripple shows up because there's a 5th harmonic in the motor's flux linkage (and therefore backemf). From the perspective of the fieldoriented control, these harmonics at the phases show up as AC disturbances on the D/Q voltages. The two current loops will try to squash these disturbances, but it's ability to do so depends on the current loop bandwidth and the magnitude of the disturbances. Since both the magnitude and frequency go up with motor speed, even really highbandwidth current loops have trouble keeping up. For example, in the scope shot at the top, the current loop had around 2 kHz closedloop bandwidth. The motor's electrical frequency was 300 Hz, so the harmonic (in D/Q) was at 1.8 kHz, so the controller couldn't quite reject it.
So how exactly do harmonics in the flux linkage at each phase show up when transformed into D and Q? In the sinusoidal flux linkage case with no positionvarying inductance, the motor's dynamics in the D/Q frame is exactly the classic voltage equations:
$$V_{d} = Ri_{d} + L\frac{di_{d}}{dt}  \omega Li_{q}$$
$$V_{q} = Ri_{q} + L\frac{di_{q}}{dt} + \omega Li_{d} + \omega\lambda$$
Where \(L\) is the synchronous inductance, \(R\) is the synchronous resistance, \(\omega\) is the (electrical) angular velocity, and \(\lambda\) is the peak flux linkage of one phase.
In the equations above, the flux linkage of a single phase \(\lambda_{p}\) is assumed to be of the form \(\lambda_{p} = \lambda \cos(\theta)\), where \(\theta\) is the rotor angle. Other phases will have an offset of \(\pm \frac{2\pi}{3}\).
If the flux linkage has a fifthharmonic in it, for a single phase it looks like \(\lambda \cos(\theta) + \lambda_{2}\cos(5 \theta) \). With the fifth harmonic in flux linkage, the voltage equations in D and Q become:
$$V_{d} = Ri_{d} + L\frac{di_{d}}{dt}  \omega Li_{q} + 5\omega\lambda_{2}\sin(6\theta)$$
$$V_{q} = Ri_{q} + L\frac{di_{q}}{dt} + \omega Li_{d} + \omega\lambda  5\omega\lambda_{2}\cos(6\theta)$$
(I have no interest in doing tedious trig and algebra by hand, so I wrote a
Mathematica script to do the transforms analytically for me.)
That's interesting  a fifth harmonic at the phases shows up as a 6th harmonic through the transforms. It turns out, a 7th harmonic at the phases
also shows up as a 6th harmonic through the transforms  just with both positive sine and cosine components, rather than positive sine negative cosine. 11 and 13 show up as 12, and so on. Also (although this may be more intuitively obvious), odd multiples of 3 disappear through the transforms.
Just to confirm, here's the output when plugging a fifth harmonic into my
motor simulator, using the the other motor parameters from the U12 and same controller gains as the hardware.
Phase currents:
D and Q axis currents, as well as rotor angle. You can count the 6 periods in the AC component of the current per electrical cycle.
So what if you want to control out those harmonics? Or add in harmonics of your own, for some reason? If you know how the voltages of the harmonics appear on the D and Q axes, theoretically you could feedforward them out, but there's a more interesting way to closedloop deal with them, without knowing the specific amplitude of phasing of the harmonic, just it's frequency.
Introducing
Adaptive Feedforward Cancellation. This is a weird technique which was briefly introduced at the very end of
2.14, which has the seemingly magical property of giving your controller infinite gain at a specific frequency  i.e. it will perfectly track a signal at that frequency, or perfectly reject a disturbance at that frequency. AFC is probably most wellknown for its use in things like harddisk read heads, which have to follow very fine tracks of data on the hard drive platters. Since the platters have some runout as they spin, the readhead has to track in the presence of periodic disturbances. Interestingly, AFC is a lot like field oriented control: FOC gives your controller infinite gain at the fundamental electrical frequency of your motor, letting you track sinusoidal currents of much higher frequency than the bandwidth of your current controllers.
Here's a block diagram of how AFC works, taken from
this paper. \(r(t)\) is the reference (current, in my case), and \(d(t)\) is a disturbance (backemf harmonics, in my case), and \(y(t)\) is the control effort (D or Q voltage in my case).
And here's how the AFC(s) are integrated into the control loop. The red box is your normal feedback controller (in my case the PI current controllers for D and Q current).
The AFC works kind of like a pair of integrators on the sine and cosine components of the periodic part of the error. If there's zero error \(e(t)\), the AFC outputs the sum of \(\cos(\omega t)\cdot (\text{cos integral})\) and \(\sin(\omega t)\cdot (\text{sin integral})\), which is some sinusoidal thing. If there is some error, the portion of it at the same frequency as \(\omega\) doesn't average to zero when multiplied by the \(\cos(\omega t)\) or \(\sin(\omega t)\)'s before the integrators. The integrators then integrate up to whatever value drives the \(\omega\) frequency component of the error to zero.
The slight modification to get this to work for motor currents is changing the \(\omega t\) to be \(\theta\), the electrical angle of the motor. The periodic disturbances are not a fixed frequency in
time, they are a fixed frequency in
state.
This basically just works. Implementing a 6th harmonic AFC on both the D and Q current loops completely eliminates the 5th harmonic in phase currents. Here's the simulation result:
Phase currents:
D/Q currents:
And here's what the integrators in the AFC do:
There's one simple addition to the controller which makes it behave a little better. The magnitude of the harmonic voltage is proportional to how fast the motor is spinning  so if the motor is accelerating, the magnitude is increasing, and the AFC integrators are constantly playing catchup. This means that at a constant acceleration, there will be a constant error in the AFC:
The AFC still does a pretty good job even at high acceleration, but how well it does depends on how large the AFC gain is. Below you can see the integrators ramping up with speed:
The simple fix for this is to divide the error by angular velocity before integrating, and then multiply by angular velocity at the end of the AFC calculations. This way, the AFC integrators integrate up to the harmonic in the flux linkage, which is constant, rather than the backemf, which is proportional to speed. Honestly, this change doesn't make a huge difference, because the time constant of the integrator can be quite fast compared to how fast the motor can accelerate, but it's kind of cool none the less:
Now the integrators just converge to constants, even as the motor accelerates:
Pseudocode implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 h = 6.0f; // Harmonic number
k_afc = 100; // AFC Gain  larger gain converges faster
s = sin(h*theta);
c = cos(h*theta);
i_error = i_ref  i;
if(abs(thetadot) > 1) //avoid dividing by zero
{
afc_cos_int += dt*i_error*k_afc*c/thetadot;
afc_sin_int += dt*i_error*k_afc*s/thetadot;
}
afc_out = thetadot*(s*afc_sin_int + c*afc_cos_int);
i_error = i_ref  i + afc_out; //Now use this error in the PI current loop.

And here it is after implementing on the hardware:
The AFC behaves a little strangely when the voltage saturates (causing higher harmonics to show up), and I haven't put any effort into fixing that, but for most operating points it works quite well.
Here's an FFT of the phase current at the beginning of the post. There are significant components at 5, 7 and 11 times the electrical frequency:
And here's the FFT after adding an AFC at 6 times the electrical frequency:
In addition to canceling out harmonics, you can use this technique to add in harmonics of your own, or track periodic current references.
For example, a typical way to cancel out cogging torque is to add in an AC component to your Qaxis current reference which tries to cancel out the cogging torque. The controller's ability to track this reference depends on how fast the motor is spinning, and its bandwidth. But if you add in an AFC at the cogging frequencies, the AFC just takes care of tracking the cogging current.
Or if you want to add certain harmonics at the phases, you can do so by taking the dq0 transform of the harmonics you want, then adding those to your D/Q current references with an AFC to track them. Say, for example, you wanted your phase currents to be more trapezoidal, you could take the transform of the trapezoidal waveform, use that as your D/Q current references, and add AFCs at the first few Fourier coefficients in order to track the reference at high speed.