Implementing digital filters in DSP for power converter control

As more power converters are digitally controlled, implementing digital filters in DSP or FPGA become more common and important. Filters such as resonant type compensators, peak and notch filters are very useful in AC-DC, DC-AC applications. In this article I’ll show several methods I use to get the parameters for the digital filters in Matlab, and how to use them in Texas Instruments DSP in C in a power converter control application. I’m also providing exemplar Matlab and C-code (to use the code in C, it depends on how you set up the interrupt and sampling with regard to your PWM signal, more discussion is in the article) you can use for your applications. (Disclaimer: this article will be more useful if you know how to use ADCs and PWMs using a DSP for power converters. It is a quick and easy way to integrate filters into existing PWM control, yet if you want to optimize memory allocation and accelerate computation, you have to get deep into the use of CLA, whic won’t be covered in this article)

Digital filter basics

To implement digital filters in DSP, some basic knowledge of transfer function (TF) in s-domain and z-domain, or continuous v.s. discrete domains is required. In the final implementation in DSP, we have to use filters with transfer function represented in z-domain, and write the transfer function as difference equation in C. Since there’s plenty of materials on the z-transform on Wikipedia, I won’t write it in detail.

Design discrete filters in Matlab

While understanding the transformation between s and z domain is essential, you don’t have to derive by-hand every time you want to implement a filter in the DSP, because we have Matlab. In Matlab, there are two methods I use to get the parameters I need for a filter:

  1. Use Matlab functions such as iirpeak() or iirnotch() to directly get the numerators and denominators in z-domain transfer functions
  2. Define a filter in s-domain, and use c2d() to perform s-to-z, then get the numerators and denominators.

Using built-in second-order infinite-impulse-response (IIR) filter functions in Matlab

I’ll give one example of using iirpeak() to design a peak filter centered at 120 Hz,with a quality factor of 5 (bandwidth of 24 Hz), and ADC sample frequency of 150 kHz. More details of this function can be found on Matlab’s website

fs = 150e3; % sampling frequency
f_center = 120; % center frequency
Q = 5; % 

% setup for iirpeak
wo = f_center/(fs/2); 
bw = wo/Q; %bandwidth 

% get the numerator and denominator 
% and generate transfer function
[num1,den1] = iirpeak(wo, bw)
G_peak = tf(num1,den1,1/fs);

figure
bode(G_peak, {0 2*pi*1000}, bode_opts);   

We can write the transfer function in a general form:

    \[ G_\text{peak} (z) = \frac{b_2 z^2 + b_1 z + b_0}{z^2 + a_1 z + a_0} \]

The function [num1,den1] = iirpeak(wo, bw) will get us the coefficients of the transfer function, \text{num1} = [b_2, b_1, b_0] and \text{den1} = [1, a_1, a_0], which are the exact parameters we will use to implement filters in DSP.

Define a filter in s-domain and transform into z-domain

In case that you want to implement arbitrary filters, you can first write your filter transfer function in s-domain and convert to z-domain using the built-in c2d() function using Tustin method in Matlab (there’s other ways for s-to-z transformation). I’ll just present the code for a second-order high-pass filter since it’s quite readable.

% a second-order high-pass filter with 10 Hz corner frequency

s = tf ('s');
w = 2*pi*10; % the corner frequency is at 10 Hz

hpf = s^2/(s^2+10*s+w^2);

% use tustin method to discretize the tf and get the numerator and denominator
[num2,den2] = tfdata(c2d(hpf,1/fs,'tustin'));
 

Similarly, you can get the coefficients as numerator and denominator arrays in z-domain for the next step of implementing in DSP.

From z-domain transfer functions to difference equations

Once we got the coefficients of the z-domain TF, we will write the TF into the format of a difference equation. Again, there are a lot of materials on this topic (just google difference equation and z-transform), so I’ll skip derivations and just present the key things we need for the actual use.

Say the output signal is y(z) and input signal is u(z), the transfer function G(z) = \frac{y(z)}{u(z)} can be written as

    \[ y(z)(z^2 + a_1 z + a_0) = u(z)(b_2 z^2 + b_1 z + b_0) \]

Here I’m just gonna write the rule we need to use: defining the number of samples to be k, that is, your newest data in your current sample period should be y(k) and u(k), the data from your previous one sample period is y(k-1) and u(k-1), and previous two periods is y(k-2) and u(k-2), so on so forth.

In the difference equation, the highest order term y(z)z^2 equals y(k), second highest order term y(z)z is thus y(k-1) and so on. The difference equation by using just sample datas can be written as

    \[ y(k) + a_1 y(k-1) + a_0 y(k-2) = b_2 u(k) + b_1 u(k-1) + b_0 u(k-2) \]

And moving y(k) to one side to get the equation for computing the latest output:

    \[ y(k) = b_2 u(k) + b_1 u(k-1) + b_0 u(k-2) -  a_1 y(k-1) - a_0 y(k-2) \]

At this point, we have got all the parameters we need to implement filters in DSP, as well as how we can use sampled datas to realize transfer function using difference equation.

Implementing difference equations in DSP in C for power converter control

Implementing the filters for power electronics control applications is straightforward, as long as you know how you operate your ADCs and main control functions. There are many ways to set up PWMs, control and ADCs in the DSP for power converter control, here I use the following method to generate PWM, perform control computation functions and get values from ADCs:

In the TI C2000 series, you can use the PWM counter to trigger ADC, and when ADCs finish converting, they will send end-of-conversion signals, which can be used to trigger the main control functions. In a more vivid description, PWM tells ADC, “hey, a new switching cycle is starting, please begin getting the values we need for computing duty ratio for next cycle”, and the ADC acknowledged and starts to get values. After the ADC finished converting analog signals to digital values, they tell the control function that I’m done with getting values, here are the values you can use. Then the main control function use these values to compute duty ratio for the next switching cycle. As a result, PWMs, ADC sampling, and control functions are running at the same frequency. (if you are not familiar with this setup, Texas Instruments have many great resources. )

In previous example with the peak filter, we define a sampling frequency of 150 kHz, which means the switching frequency of the PWM, the control frequency for computing are both 150 kHz. To speak in terms of the difference equation, y(k) and y(k-1) are 1/(150kHz) apart.

There are three main steps you need to setup the difference equations in C:

  1. Declare all variables, including the TF coefficients, and all signal variables y(k), y(k-1)... u(k), u(k-1)...
  2. In the main control function, update the values for previous sampled data y(k-1), y(k-2)... u(k-1), u(k-2)...
  3. Use the final expression to get y(k)

Still using the results from the peak filter example, here are the variables that should be defined as global variables in the global_variables.h file for your project:

// declare all tf coefficients
float32 b2 = 5.024023319309956e-04;
float32 b1 = 0;
float32 b0 = -5.024023319309956e-04;
float32 a1 = -1.998969941895834;
float32 a0 = 0.998995195336138;

//declare sampled datas
float32 u = 0;
float32 u1 = 0;//u[n-1]
float32 u2 = 0;//u[n-2]

float32 y = 0;
float32 y1 = 0;//y[n-1]
float32 y2 = 0;//y[n-2]

In the main control function, adc_reading is the input signal from ADC that you want to filter, For instance, we want to extract the 120 Hz harmonic in the inverter output voltage, the ADC is reading the inverter output voltage. To perform step 2 and 3:

//update previous values
y2 = y1;
y1 = y;
u2 = u1;
u1 = u;

//latest input from adc....
//adc_reading is the 
//signal you want to filter
u = adc_reading;

//final tf output
y = b2*u + b1*u1 + b0*u2 - a1*y1 - a0*y2;

While it seems that I’ve written out most of the Matlab file…you can download the .m file here.