Main Content

HDL Butterworth Filter

This example illustrates how to generate HDL code for a 5th order Butterworth filter. The cutoff-frequency for this filter is very low relative to the sample rate, leading to a filter that is difficult to make practical. Also, because the filter has small input (8-bit) and output (9-bit) word sizes, the quantized filter requires scaling to be realizable.

Design the Filter

Use the CD sampling rate of 44.1 kHz and a cut-off frequency of 500 Hz. First, create the filter design object, then create a biquad filter System object™. Finally, use fvtool to examine the response in log frequency.

Fs = 44100;
F3db = 500;
filtdes = fdesign.lowpass('n,f3db', 5, F3db, Fs);
butterFilter = design(filtdes,'butter',...
    'SystemObject',true,'FilterStructure','df1sos','UseLegacyBiquadFilter',true);

fvtool(butterFilter,'Fs',Fs,'FrequencyScale','log');

Figure Figure 1: Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB), xlabel Frequency (kHz), ylabel Magnitude (dB) contains 2 objects of type line.

Create the Quantized Filter

Apply the fixed point settings to the filter object. This example uses 9-bit fixed-point output data with 12-bit coefficients, 20-bit states, full-precision products, and 32-bit adders. Check the response by using fvtool.

butterFilter.NumeratorCoefficientsDataType = 'Custom';
butterFilter.CustomNumeratorCoefficientsDataType = numerictype([],12);
butterFilter.CustomDenominatorCoefficientsDataType = numerictype([],12);
butterFilter.CustomScaleValuesDataType = numerictype([],12);
butterFilter.SectionInputDataType = 'Custom';
butterFilter.CustomSectionInputDataType = numerictype([],20,15);
butterFilter.SectionOutputDataType = 'Custom';
butterFilter.CustomSectionOutputDataType = numerictype([],20,15);
butterFilter.NumeratorProductDataType = 'Full precision';
butterFilter.DenominatorProductDataType = 'Full precision';
butterFilter.NumeratorAccumulatorDataType = 'Custom';
butterFilter.CustomNumeratorAccumulatorDataType = numerictype([],32,24);
butterFilter.DenominatorAccumulatorDataType = 'Custom';
butterFilter.CustomDenominatorAccumulatorDataType = numerictype([],32,25);
butterFilter.OutputDataType = 'Custom';
butterFilter.CustomOutputDataType = numerictype([],9,7);
butterFilter.RoundingMethod = 'nearest';
butterFilter.OverflowAction = 'wrap';
fvtool(butterFilter,'Fs',Fs,'FrequencyScale','log','Arithmetic','fixed');

Figure Figure 2: Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB), xlabel Frequency (kHz), ylabel Magnitude (dB) contains 3 objects of type line. These objects represent Filter #1: Quantized, Filter #1: Reference.

Requantize the Filter

In the plot above, fvtool shows that the quantized passband is approximately 2 dB lower than the desired response. Adjust the coefficient word length from 12 to 16 to get the quantized response closer to the reference double-precision response and zoom in on the passband response. The quantized filter is now just over 0.1 dB lower than the reference filter.

butterFilter.CustomNumeratorCoefficientsDataType = numerictype([],16);
butterFilter.CustomDenominatorCoefficientsDataType = numerictype([],16);
butterFilter.CustomScaleValuesDataType = numerictype([],16);

h = fvtool(butterFilter,'Fs',Fs,'FrequencyScale','log','Arithmetic','fixed');
h.zoom([0 1.0 -1 1]);

Figure Figure 3: Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB), xlabel Frequency (kHz), ylabel Magnitude (dB) contains 3 objects of type line. These objects represent Filter #1: Quantized, Filter #1: Reference.

Examine the Scale Values

A key step for hardware realization of the filter design is to check whether the scale values are reasonable and adjust the scale value if needed. First, examine the quantized scale values relative to the input specification. The input data are 8-bit values with fraction length of 7 bits. Since the first two scale values are smaller than can be represented with these input settings, most of the input values are quantized away. To correct this behavior, the filter must be scaled.

scaless = butterFilter.ScaleValues .* 2^7 %#ok<*NASGU> 
scaless = 4×1

    0.1588
    0.1535
    4.4042
  128.0000

Now scale the filter using the frequency domain infinity norm. In this case, after scaling, the scale values are all equal to one.

scale(butterFilter,'Linf');
scaless = butterFilter.ScaleValues
scaless = 4×1

    1.0000
    1.0000
    1.0000
    1.0000

Generate HDL Code and Test Bench from the Quantized Filter

Starting with the correctly quantized filter, generate VHDL® or Verilog® code. You have the option of generating a VHDL or Verilog test bench to verify that the HDL design matches the MATLAB® filter.

To generate Verilog instead, change the value of the TargetLanguage property, from 'VHDL' to 'Verilog'.

Since the passband of this filter is low relative to the sampling rate, a custom input stimulus is a better way to test the filter implementation. Build the test input with one cycle of each of 50 to 300 Hz, in 50 Hz steps.

Generate 8-bit signed fixed-point input with 7 bits of fractional length.

Generate VHDL code for the filter and a VHDL test bench to verify that the results match the MATLAB results exactly.

userstim = [];
for n = [50, 100, 150, 200, 250, 300]
  userstim = [userstim,sin(2*pi*n/Fs*(0:Fs/n))]; %#ok
end

generatehdl(butterFilter,'Name','hdlbutter', ...
    'TargetLanguage','VHDL', ...
    'GenerateHDLTestbench','on', ...
    'TestBenchUserStimulus',userstim, ...
    'InputDataType',numerictype(1,8,7));
### Starting VHDL code generation process for filter: hdlbutter
### Generating: /tmp/Bdoc23b_2361005_716704/tp23c51c9c/hdlfilter-ex42204542/hdlsrc/hdlbutter.vhd
### Starting generation of hdlbutter VHDL entity
### Starting generation of hdlbutter VHDL architecture
### First-order section, # 1
### Second-order section, # 2
### Second-order section, # 3
### Successful completion of VHDL code generation process for filter: hdlbutter
### HDL latency is 2 samples
### Starting generation of VHDL Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 2166 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_716704/tp23c51c9c/hdlfilter-ex42204542/hdlsrc/hdlbutter_tb.vhd
### Creating stimulus vectors ...
### Done generating VHDL Test Bench.

Generate HDL Code and Test Bench Using FDHDLTool

Alternatively, you can generate HDL code and test bench by using the fdhdhltool command. This command opens a dialog that allows you to customize and generate Verilog or VHDL code and test benches for the quantized filter.

When you specify a type of filter, the tool is customized to show only the relevant options for that filter type.

fdhdltool(butterFilter,numerictype(1,8,7));

You can modify the default settings and click Generate to generate HDL code and/or a test bench.

ModelSim® Simulation Results

The image shows the ModelSim HDL simulator after running the VHDL test bench. Compare the ModelSim result with the MATLAB result.

xrange = (0:length(userstim) - 1);
y = butterFilter(fi(userstim.',1,8,7));
subplot(2,1,1); plot(xrange,userstim); 
axis([0 length(userstim) -1.1 1.1]);
title('HDL Butterworth Filter Input Stimulus');
xlabel('Sample #');
subplot(2,1,2); plot(xrange, y); 
axis([0 length(userstim) -1.1 1.1]);
title('HDL Butterworth Filter Output Response');
xlabel('Sample #');

Figure contains 2 axes objects. Axes object 1 with title HDL Butterworth Filter Input Stimulus, xlabel Sample # contains an object of type line. Axes object 2 with title HDL Butterworth Filter Output Response, xlabel Sample # contains an object of type line.

Conclusion

You designed a Butterworth filter to meet the given specification. You then quantized the filter and discovered that the passband requirement was not met. Requantizing the coefficients and scaling the filter fixed this issue. You then generated VHDL code for the filter and a VHDL test bench.

You can use the ModelSim HDL Simulator, to verify these results. You can also experiment with VHDL and Verilog for both filters and test benches.