Main Content

Implementing the Filter Chain of a Digital Down-Converter in HDL

This example shows how to use the DSP System Toolbox™ and Fixed-Point Designer™ to design a three-stage, multirate, fixed-point filter that implements the filter chain of a Digital Down-Converter (DDC) designed to meet the Global System for Mobile (GSM) specification.

Using the Filter Design HDL Coder™ we will generate synthesizable HDL code for the same three-stage, multirate, fixed-point filter. Finally, using Simulink® and HDL Verifier™ MS, we will co-simulate the fixed-point filters to verify that the generated HDL code produces the same results as the equivalent Simulink behavioral model.

Digital Down-Converter

Digital Down-Converters (DDC) are a key component of digital radios. The DDC performs the frequency translation necessary to convert the high input sample rates found in a digital radio, down to lower sample rates for further and easier processing. In this example, the DDC operates at approximately 70 MHz and must reduce the rate down to 270 KHz.

To further constrain our problem we will model one of the DDCs in Graychip's GC4016 Multi-Standard Quad DDC Chip. The GC4016, among other features, provides the following filters: a five-stage CIC filter with programmable decimation factor (8-4096); a 21-tap FIR filter which decimates by 2 and has programmable 16-bit coefficients; and a 63-tap FIR filter which also decimates by 2 and has programmable 16-bit coefficients.

The DDC consists of a Numeric Controlled Oscillator (NCO) and a mixer to quadrature down convert the input signal to baseband. The baseband signal is then low pass filtered by a Cascaded Integrator-Comb (CIC) filter followed by two FIR decimating filters to achieve a low sample-rate of about 270 KHz ready for further processing. The final stage often includes a resampler which interpolates or decimates the signal to achieve the desired sample rate depending on the application. Further filtering can also be achieved with the resampler. A block diagram of a typical DDC is shown below.

This example focuses on the three-stage, multirate, decimation filter, which consists of the CIC and the two decimating FIR filters.

GSM Specifications

The GSM bandwidth of interest is 160 KHz. Therefore, the DDC's three-stage, multirate filter response must be flat over this bandwidth to within the passband ripple, which must be less than 0.1 dB peak to peak. Looking at the GSM out of band rejection mask shown below, we see that the filter must also achieve 18 dB of attenuation at 100 KHz.

In addition, GSM requires a symbol rate of 270.833 Ksps. Since the Graychip's input sample rate is the same as its clock rate of 69.333 MHz, we must downsample the input down to 270.833 KHz. This requires that the three-stage, multirate filter decimate by 256.

Cascaded Integrator-Comb (CIC) Filter

CIC filters are multirate filters that are very useful because they can achieve high decimation (or interpolation) rates and are implemented without multipliers. CICs are simply boxcar filters implemented recursively cascaded with an upsampler or downsampler. These characteristic make CICs very useful for digital systems operating at high rates, especially when these systems are to be implemented in ASICs or FPGAs.

Although CICs have desirable characteristics they also have some drawbacks, most notably the fact that they incur attenuation in the passband region due to their sinc-like response. For that reason CICs often have to be followed by a compensating filter. The compensating filter must have an inverse-sinc response in the passband region to lift the droop caused by the CIC.

The design and cascade of the three filters can be performed via the graphical user interface Filter Designer,

but we'll use the command line functionality.

We define the CIC as follows:

R    = 64; % Decimation factor
D    = 1;  % Differential delay
Nsecs = 5;  % Number of sections

OWL = 20; % Output word length

cic = dsp.CICDecimator('DecimationFactor',R,'NumSections',Nsecs,...
    'FixedPointDataType','Minimum section word lengths',...

We can view the CIC's details by invoking the info method.

ans =

  9x56 char array

    'Discrete-Time FIR Multirate Filter (real)               '
    '-----------------------------------------               '
    'Filter Structure    : Cascaded Integrator-Comb Decimator'
    'Decimation Factor   : 64                                '
    'Differential Delay  : 1                                 '
    'Number of Sections  : 5                                 '
    'Stable              : Yes                               '
    'Linear Phase        : Yes (Type 2)                      '
    '                                                        '

Let's plot and analyze the theoretical magnitude response of the CIC filter which will operate at the input rate of 69.333 MHz.

Fs_in = 69.333e6;
fvt = fvtool(cic,'Fs',Fs_in);
fvt.Color = 'White';

The first thing to note is that the CIC filter has a huge passband gain, which is due to the additions and feedback within the structure. We can normalize the CIC's magnitude response by using the corresponding setting in FVTool. Normalizing the CIC filter response to have 0 dB gain at DC will make it easier to analyze the overlaid filter response of the next stage filter.

fvt.NormalizeMagnitudeto1 = 'on';

The other thing to note is that zooming in the passband region we see that the CIC has about -0.4 dB of attenuation (droop) at 80 KHz, which is within the bandwidth of interest. A CIC filter is essentially a cascade of boxcar filters and therefore has a sinc-like response which causes the droop. This droop needs to be compensated by the FIR filter in the next stage.

axis([0 .1 -0.8 0]);

Compensation FIR Decimator

The second stage of our DDC filter chain needs to compensate for the passband droop caused by the CIC and decimate by 2. Since the CIC has a sinc-like response, we can compensate for the droop with a lowpass filter that has an inverse-sinc response in the passband. This filter will operate at 1/64th the input sample rate which is 69.333 MHz, therefore its rate is 1.0833MHz. Instead of designing a lowpass filter with an inverse-sinc passband response from scratch, we'll use a canned function which lets us design a decimator with a CIC Compensation (inverse-sinc) response directly.

% Filter specifications
Fs     = 1.0833e6; % Sampling frequency 69.333MHz/64
Apass  = 0.01;     % dB
Astop  = 70;       % dB
Fpass  = 80e3;     % Hz passband-edge frequency
Fstop  = 293e3;    % Hz stopband-edge frequency

% Design decimation filter. D and Nsecs have been defined above as the
% differential delay and number of sections, respectively.
compensator = dsp.CICCompensationDecimator('SampleRate',Fs,...

% Now we have to define the fixed-point attributes of our multirate filter.
% By default, the fixed-point attributes of the accumulator and multipliers
% are set to ensure that full precision arithmetic is used, i.e. no
% quantization takes place. By default, 16 bits are used to represent the
% filter coefficients. Since that is what we want in this case, no changes
% from default values are required.

Using the info command we can get a comprehensive report of the FIR compensation filter, including the word lengths of the accumulator and product, which are automatically determined.

ans =

  10x56 char array

    'Discrete-Time FIR Multirate Filter (real)               '
    '-----------------------------------------               '
    'Filter Structure   : Direct-Form FIR Polyphase Decimator'
    'Decimation Factor  : 2                                  '
    'Polyphase Length   : 11                                 '
    'Filter Length      : 21                                 '
    'Stable             : Yes                                '
    'Linear Phase       : Yes (Type 1)                       '
    '                                                        '
    'Arithmetic         : double                             '

Cascading the CIC with the inverse sinc filter we can see if we eliminated the passband droop caused by the CIC.

cicCompCascade = cascade(cic,compensator);
fvt = fvtool(cic,compensator,cicCompCascade,'Fs',[Fs_in,Fs_in/64,Fs_in]);
fvt.Color = 'White';
fvt.NormalizeMagnitudeto1 = 'on';
axis([0 .1 -0.8 0.8]);

As we can see in the filter response of the cascade of the two filters, which is between the CIC response and the compensating FIR response, the passband droop has been eliminated.

Third Stage FIR Decimator

As indicated earlier the GSM spectral mask requires an attenuation of 18 dB at 100 KHz. So, for our third and final stage we can try a simple equiripple lowpass filter. Once again we need to quantize the coefficients to 16 bits (default). This filter also needs to decimate by 2.

N = 62;       % 63 taps
Fs = 541666;  % 541.666 kHz
Fpass = 80e3;
Fstop = 100e3;

spec = fdesign.decimator(2,'lowpass','N,Fp,Fst',N,Fpass,Fstop,Fs);
% Give more weight to passband
decimator = design(spec,'equiripple','Wpass',2,'SystemObject',true);

When defining a multirate filter by default the accumulator word size is determined automatically to maintain full precision. However, because we only have 20 bits for the output let's set the output format to a word length of 20 bits and a fraction length of -12. First, we must change the FullPrecisionOverride property's default value from true to false.

decimator.FullPrecisionOverride = false;
decimator.OutputDataType = 'custom';
decimator.RoundingMethod = 'nearest';
decimator.OverflowAction = 'Saturate';
decimator.CustomOutputDataType = numerictype([],20,-12);

We can use the info method to view the filter details.

ans =

  10x56 char array

    'Discrete-Time FIR Multirate Filter (real)               '
    '-----------------------------------------               '
    'Filter Structure   : Direct-Form FIR Polyphase Decimator'
    'Decimation Factor  : 2                                  '
    'Polyphase Length   : 32                                 '
    'Filter Length      : 63                                 '
    'Stable             : Yes                                '
    'Linear Phase       : Yes (Type 1)                       '
    '                                                        '
    'Arithmetic         : double                             '

Multistage Multirate DDC Filter Chain

Now that we have designed and quantized the three filters, we can get the overall filter response by cascading the normalized CIC and the two FIR filters. Again, we're using normalized magnitude to ensure that the cascaded filter response is normalized to 0 dB.

ddc = cascade(cic,compensator,decimator);
fvt = fvtool(ddc,'Fs',Fs_in);
fvt.Color = 'White';
fvt.NormalizeMagnitudeto1 = 'on';
fvt.NumberofPoints = 8192*3;
axis([0 1 -200 10]);  % Zoom-in

To see if the overall filter response meets the GSM specifications, we can overlay the GSM spectral mask on the filter response.


We can see that our overall filter response is within the constraints of the GSM spectral mask. We also need to ensure that the passband ripple meets the requirement that it is less than 0.1 dB peak-to-peak. We can verify this by zooming in using the axis command.

axis([0 .09 -0.08 0.08]);

Indeed the passband ripple is well below the 0.1 dB peak-to-peak GSM requirement.

Generate VHDL Code

Filter Designer also supports the generation of HDL code from the dialog shown below.

From Filter Designer as well as the command line you can generate VHDL or Verilog code as well as test benches in VHDL or Verilog files. Also, you have the ability to customize your generated HDL code by specifying many options to meet your coding standards and guidelines.

However, here we will use the command line functionality to generate the HDL code.

Now that we have our fixed-point, three-stage, multirate filter meeting the specs we are ready to generate HDL code.

Cascade of CIC and two FIR filters and generate VHDL.

To avoid quantizing the fixed-point data coming from the mixer, which has a word length of 20 bits and a fraction length of 18 bits, (S20,18), we'll set the input word length and fraction length of the CIC to the same values, S20,18.

%hcas = cascade(hcic,hcfir,hpfir);
workingdir = tempname;
inT = numerictype(1,20,18);
generatehdl(ddc,'InputDataType', inT,...
### Starting VHDL code generation process for filter: filter
### Cascade stage # 1
### Starting VHDL code generation process for filter: filter_stage1
### Generating: <a href="matlab:edit('/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage1.vhd')">/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage1.vhd</a>
### Starting generation of filter_stage1 VHDL entity
### Starting generation of filter_stage1 VHDL architecture
### Section # 1 : Integrator
### Section # 2 : Integrator
### Section # 3 : Integrator
### Section # 4 : Integrator
### Section # 5 : Integrator
### Section # 6 : Comb
### Section # 7 : Comb
### Section # 8 : Comb
### Section # 9 : Comb
### Section # 10 : Comb
### Successful completion of VHDL code generation process for filter: filter_stage1
### Cascade stage # 2
### Starting VHDL code generation process for filter: filter_stage2
### Generating: <a href="matlab:edit('/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage2.vhd')">/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage2.vhd</a>
### Starting generation of filter_stage2 VHDL entity
### Starting generation of filter_stage2 VHDL architecture
### Successful completion of VHDL code generation process for filter: filter_stage2
### Cascade stage # 3
### Starting VHDL code generation process for filter: filter_stage3
### Generating: <a href="matlab:edit('/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage3.vhd')">/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter_stage3.vhd</a>
### Starting generation of filter_stage3 VHDL entity
### Starting generation of filter_stage3 VHDL architecture
### Successful completion of VHDL code generation process for filter: filter_stage3
### Generating: <a href="matlab:edit('/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter.vhd')">/tmp/Bdoc21b_1757077_58267/tp92e56bd5_0d38_4cf1_9288_99fd51978240/hdlsrc/filter.vhd</a>
### Starting generation of filter VHDL entity
### Starting generation of filter VHDL architecture
### Successful completion of VHDL code generation process for filter: filter
### HDL latency is 2 samples

HDL Co-simulation with ModelSim in Simulink

To verify that the generated HDL code is producing the same results as our Simulink model, we'll use HDL Verifier MS to co-simulate our HDL code in Simulink. We have a pre-built Simulink model that includes two signal paths. One signal path produces Simulink's behavioral model results of the three-stage, multirate filter. The other path produces the results of simulating, with ModelSim®, the VHDL code we generated.


Start ModelSim by double clicking on the button in the Simulink model. Note that ModelSim must be installed and on the system path. ModelSim will automatically compile the HDL code, initialize the simulation and open the Wave viewer.

When ModelSim is ready run the Simulink model. This will execute co-simulation with ModelSim and automatically open a Time Scope to view the results.

Use the Logic Analyzer to view the results.

Verifying Results

The trace on the top is the excitation chirp signal. The next signal labeled "ref" is the reference signal produced by the Simulink behavioral model of the three-stage multirate filter. The bottom trace labeled "cosim" on the scope is of the ModelSim simulation results of the generated HDL code of the three-stage multirate filter. The last trace shows the error between Simulink's behavioral model results and ModelSim's simulation of the HDL code.


We used several MathWorks™ products to design and analyze a three-stage, multirate, fixed-point filter chain of a DDC for a GSM application. Then we generated HDL code to implement the filter and verified the generated code by comparing Simulink's behavioral model with HDL code simulated in ModelSim via HDL Verifier MS.