Main Content

HDL Sample Rate Conversion Using Farrow Filters

This example shows how you can design and implement hardware efficient sample rate converters for an arbitrary factor using polynomial-based (Farrow) structures. Sample rate conversion (SRC) between arbitrary factors is useful for many applications including symbol synchronizations in digital receivers, speech coding, audio sampling, etc. This example shows how you can convert the sampling rate of an audio signal from 8kHz to 44.1 kHz.

Overview

To resample the incoming signal from 8 kHz to 44.1 kHz, you must interpolate by 441 and decimate by 80. This SRC can be implemented using polyphase structures. However using the polyphase structures for any arbitrary factor usually results in large number of coefficients leading to a lot of memory requirement and area. This example shows how to efficiently implement SRC with a mix of polyphase and Farrow filter structures.

Design of Interpolating Stages

First, interpolate the original 8 kHz signal by a factor of 4 using a cascade of FIR halfband filters. This interpolation results in an intermediate signal of 32 kHz. Polyphase filters are particularly well adapted for interpolation or decimation by an integer factor and for fractional rate conversions when the interpolation and the decimation factors are low. Design the interpolating stages for the specifications given.

TW  = .125; % Transition Width
Astop = 50; % Minimum stopband attenuation 
cascadeSpec  = fdesign.interpolator(4, 'Nyquist', 4, 'TW,Ast', TW, Astop);
FIRCascade   = design(cascadeSpec, 'multistage', ...
    'HalfbandDesignMethod', 'equiripple', 'SystemObject', true);

Design of Farrow Filter

The signal output from the above interpolating stages needs to be further interpolated from 32 kHz to 44.1 kHz. This operation is done by a Farrow rate converter filter designed with a cubic Lagrange polynomial.

FsInp = 32e3;   % Input sample rate
FsOut = 44.1e3; % Output sample rate
TOL   = 0;      % Output rate tolerance
NP    = 3;      % Polynomial order

farrowFilter = dsp.FarrowRateConverter(FsInp, FsOut, TOL, NP);

To prevent the datapath from growing to very large word lengths, quantize the filter stages such that the inputs to each stage are 12 bits and the outputs are 12 bits.

cascadeOutNT = numerictype([],12,11);
FIRCascade.Stage1.FullPrecisionOverride = false;
FIRCascade.Stage1.OutputDataType        = 'Custom';
FIRCascade.Stage1.CustomOutputDataType  = cascadeOutNT;
FIRCascade.Stage2.FullPrecisionOverride = false;
FIRCascade.Stage2.OutputDataType        = 'Custom';
FIRCascade.Stage2.CustomOutputDataType  = cascadeOutNT;

farrowOutNT = numerictype(1,12,11);
farrowFilter.OutputDataType = farrowOutNT;

Cascade of Complete SRC and Magnitude Response

The overall filter is obtained by creating a cascade of the interpolating stages and the Farrow filter.

sampleRateConverter = cascade(FIRCascade.Stage1, FIRCascade.Stage2, farrowFilter);

The magnitude response of the cascaded SRC filter shows that it meets the 50 dB minimum stopband attenuation specification.

Fs = 32e3*441;                % The highest clock rate is 14.112 MHz
W = linspace(0,44.1e3,2048);  % Define the frequency range analysis

fvt = fvtool(sampleRateConverter,'FrequencyRange','Specify freq. vector', ...
    'FrequencyVector',W,'Fs',Fs, ...
    'NormalizeMagnitudeto1','on', 'Color', 'white');

legend(fvt,'Cascade of FIR and Farrow Rate Converter Response',...
    'Location','NorthEast')

Figure Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB) contains an object of type line. This object represents Cascade of FIR and Farrow Rate Converter Response.

Generate HDL & Test Bench

You can now generate VHDL code for the cascaded SRC using the generatehdl command. You can also generate the VHDL test bench by passing the 'TestBenchUserStimulus' and 'GenerateHDLTestbench' properties into the generatehdl command. The VHDL code can be simulated in any HDL simulator to verify the results.

workingdir = tempname;
inpFrameSz = 640;
tVector    = linspace(0.005, 7.5, inpFrameSz);
srcTBStim  = (chirp(tVector, 0, 1, 150))';

generatehdl(sampleRateConverter, ...
    'TargetDirectory',       workingdir, ...
    'InputDataType',         numerictype(1,12,11), ...
    'OptimizeForHDL',        'on', ...
    'GenerateHDLTestbench',  'on', ...
    'TestBenchUserStimulus', srcTBStim, ...
    'ErrorMargin',           2);
### Starting VHDL code generation process for filter: casfilt
### Cascade stage # 1
### Starting VHDL code generation process for filter: casfilt_stage1
### Generating: /tmp/Bdoc22a_1891349_36474/tp454db37e_1b70_4995_898a_d2fc0dc11fc5/casfilt_stage1.vhd
### Starting generation of casfilt_stage1 VHDL entity
### Starting generation of casfilt_stage1 VHDL architecture
### Successful completion of VHDL code generation process for filter: casfilt_stage1
### Cascade stage # 2
### Starting VHDL code generation process for filter: casfilt_stage2
### Generating: /tmp/Bdoc22a_1891349_36474/tp454db37e_1b70_4995_898a_d2fc0dc11fc5/casfilt_stage2.vhd
### Starting generation of casfilt_stage2 VHDL entity
### Starting generation of casfilt_stage2 VHDL architecture
### Successful completion of VHDL code generation process for filter: casfilt_stage2
### Cascade stage # 3
### Starting VHDL code generation process for filter: casfilt_stage3
### Generating: /tmp/Bdoc22a_1891349_36474/tp454db37e_1b70_4995_898a_d2fc0dc11fc5/casfilt_stage3.vhd
### Starting generation of casfilt_stage3 VHDL entity
### Starting generation of casfilt_stage3 VHDL architecture
### Successful completion of VHDL code generation process for filter: casfilt_stage3
### Generating: /tmp/Bdoc22a_1891349_36474/tp454db37e_1b70_4995_898a_d2fc0dc11fc5/casfilt.vhd
### Starting generation of casfilt VHDL entity
### Starting generation of casfilt VHDL architecture
### Successful completion of VHDL code generation process for filter: casfilt
### HDL latency is 1325 samples
### Starting generation of VHDL Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 640 samples.
Warning: HDL optimization may cause small numeric differences that will be flagged as errors when running this testbench.
### Generating Test bench: /tmp/Bdoc22a_1891349_36474/tp454db37e_1b70_4995_898a_d2fc0dc11fc5/casfilt_tb.vhd
### Creating stimulus vectors ...
### Done generating VHDL Test Bench.

ModelSim® Simulation Results

The following display shows the ModelSim® HDL simulator results after running the VHDL test bench.

Conclusion

This example showed how you can design a sample rate converter using a Farrow structure, and how to analyze the response, quantize it, and generate bit-accurate VHDL code and test bench.