Main Content

HDL Fractional Delay (Farrow) Filter

This example illustrates how to generate HDL code for a fractional delay (Farrow) filter for timing recovery in a digital modem. A Farrow filter structure provides variable fractional delay for the received data stream prior to downstream symbol sampling. This special FIR filter structure permits simple handling of filter coefficients by an efficient polynomial interpolation formula implementation to provide variable fractional resampling.

In a typical digital modem application, the fractionally resampled data output from a Farrow filter is passed along to a symbol sampler with optional carrier recovery. For more details of this complete application please refer to "Timing Recovery Using Fixed-Rate Resampling" for Simulink® and Communications Toolbox™.

Design the Filter

To design a fractional delay filter using the Cubic Lagrange interpolation method, first create a specification object with filter order 3 and an arbitrary fractional delay of 0.3. Next, create a farrow filter object Hd, using the design method of the specification object with argument lagrange. This method is also called with property FilterStructure and its value fd. You can look into the details of the filter object Hd by using the info command.

fDelay = 0.3;
filtdes = fdesign.fracdelay(fDelay, 'N', 3);
Hd = design(filtdes,'lagrange', 'FilterStructure', 'farrowfd');
info(Hd)
Discrete-Time FIR Farrow Filter (real)     
--------------------------------------     
Filter Structure  : Farrow Fractional Delay
Filter Length     : 4                      
Stable            : Yes                    
Linear Phase      : No                     
                                           
Arithmetic        : double                 

The fractional delay for the Farrow filter is tunable and can be altered to lead a different magnitude response. You can see this by creating a set of filters that are copies of the pre-designed filter Hd with each differing in their fracdelay values.

h = repmat(Hd,1,10); % preallocating size
for d=0:9
    h(d+1) = copy(Hd); % create unique filter objects
    h(d+1).fracdelay = d/10;
end
fvtool(h)

fvtool(h,'Analysis','PhaseDelay')

Quantize the Filter

Set the filter object to fixed-point mode to quantize it. Assume eight-bit input data with eight-bit coefficients and six-bit fractional delay. Modify the fixed-point data word lengths and fraction lengths accordingly. The CoeffFracLength property is set automatically because coefficient autoscaling is set to on by default by the property CoeffAutoscale. Switch off FDAutoScale and set FDFracLength to six, allowing a fractional delay in the range 0 to 1 to be represented.

Hd.arithmetic            = 'fixed';
Hd.InputWordLength       = 8;
Hd.InputFracLength       = 7;
Hd.CoeffWordLength       = 8;
Hd.FDWordLength          = 6;
Hd.FDAutoScale           = false;
Hd.FDFracLength          = 6;

Generate HDL Code from the Quantized Filter

Starting with the correctly quantized filter, you can generate VHDL or Verilog code using the generatehdl command. You create a temporary work directory and then use the generatehdl command using the appropriate property-value pairs. After generating the HDL code using VHDL for the TargetLanguage property in this case, you can open the generated VHDL file in the editor by clicking on the hyperlink displayed in the command line display messages.

workingdir = tempname;
generatehdl(Hd, 'Name', 'hdlfarrow', ...  
                'TargetLanguage', 'VHDL',...
                'TargetDirectory', workingdir);
### Starting VHDL code generation process for filter: hdlfarrow
### Generating: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow.vhd
### Starting generation of hdlfarrow VHDL entity
### Starting generation of hdlfarrow VHDL architecture
### Successful completion of VHDL code generation process for filter: hdlfarrow
### HDL latency is 2 samples

Generate HDL Test Bench

To verify the HDL code, you can generate an HDL test bench to simulate the HDL code using an HDL simulator. The test bench will verify the results of the HDL code with the results of the MATLAB® filter command. The stimuli for the filter input filter_in port and fractional delay filter_fd port can be specified using properties TestbenchStimulus, TestbenchUserStimulus and TestbenchFracDelayStimulus.

Predefined stimulus for the filter input filter_in port can be specified for input data stimulus using the property TestbenchStimulus as with the other filter structures. You can specify your own stimulus for the input data by using the property TestbenchUserStimulus and passing a MATLAB vector as the value.

You can specify the fractional delay stimulus using the property TestbenchFracdelayStimulus. A vector of double between 0 and 1 is generated automatically by specifying either RandSweep or RampSweep. The default behavior is to provide a fractional delay stimulus of a constant set to the fracdelay value of the filter object.

The following command specifies the input stimulus to chirp, and the fractional delay vector is set to a constant 0.3 for all the simulation time. This is the default behavior when the TestbenchFracDelayStimulus property is not set otherwise.

generatehdl(Hd, 'Name', 'hdlfarrow', ...
    'GenerateHDLTestbench', 'on', ...
    'TestBenchName', 'hdlfarrow_default_tb',...
    'TargetLanguage', 'VHDL',...
    'TargetDirectory', workingdir);
### Starting VHDL code generation process for filter: hdlfarrow
### Generating: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow.vhd
### Starting generation of hdlfarrow VHDL entity
### Starting generation of hdlfarrow VHDL architecture
### Successful completion of VHDL code generation process for filter: hdlfarrow
### HDL latency is 2 samples
### Starting generation of VHDL Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 3100 samples.
### Generating Test bench: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow_default_tb.vhd
### Creating stimulus vectors ...
### Done generating VHDL Test Bench.

To automatically generate the test vector for a fractional delay port, specify RampSweep for TestBenchFracDelayStimulus. It generates a vector of values between 0 and 1 sweeping in a linear fashion. The length of this vector is equal to the input stimulus vector.

generatehdl(Hd, 'Name', 'hdlfarrow', ...
    'GenerateHDLTestbench', 'on', ...
    'TestBenchName', 'hdlfarrow_rampsweep_tb',...
    'TargetLanguage', 'VHDL',...
    'TestBenchStimulus', 'chirp',...
    'TestbenchFracDelaystimulus', 'Rampsweep', ...
    'TargetDirectory', workingdir);
### Starting VHDL code generation process for filter: hdlfarrow
### Generating: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow.vhd
### Starting generation of hdlfarrow VHDL entity
### Starting generation of hdlfarrow VHDL architecture
### Successful completion of VHDL code generation process for filter: hdlfarrow
### HDL latency is 2 samples
### Starting generation of VHDL Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1028 samples.
### Generating Test bench: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow_rampsweep_tb.vhd
### Creating stimulus vectors ...
### Done generating VHDL Test Bench.

You can generate a customized input stimulus vector using MATLAB commands and pass it to the test bench stimulus properties for the user defined input and fracdelay stimuli. An input test vector userinputstim is generated using the chirp command and the fractional delay test vector userfdstim is generated of length equal to the input test vector.

t=-2:0.01:2;                           % +/-2 secs @ 100 Hz sample rate
userinputstim = chirp(t,100,1,200,'q'); % Start @100Hz, cross 200Hz at t=1sec 
leninput = length(userinputstim);
samplefdvalues = [0.1, 0.34, 0.78, 0.56, 0.93, 0.25, 0.68, 0.45];
samplesheld = ceil(leninput/length(samplefdvalues));
ix = 1;
for n = 1:length(samplefdvalues)-1
    userfdstim(ix: ix + samplesheld-1) =  repmat(samplefdvalues(n),1, samplesheld);
    ix = ix + samplesheld;
end
userfdstim(ix:leninput)= repmat(samplefdvalues(end),1 , leninput-length(userfdstim));

generatehdl(Hd, 'Name', 'hdlfarrow', ...
    'GenerateHDLTestbench', 'on', ...
    'TestBenchName', 'hdlfarrow_userdefined_tb',...
    'TargetLanguage', 'VHDL',...
    'TestBenchUserStimulus', userinputstim,...
    'TestbenchFracDelaystimulus', userfdstim, ...
    'TargetDirectory', workingdir);
### Starting VHDL code generation process for filter: hdlfarrow
### Generating: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow.vhd
### Starting generation of hdlfarrow VHDL entity
### Starting generation of hdlfarrow VHDL architecture
### Successful completion of VHDL code generation process for filter: hdlfarrow
### HDL latency is 2 samples
### Starting generation of VHDL Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 401 samples.
### Generating Test bench: /tmp/Bdoc24a_2528353_248711/tp0cb7b687_8a14_4053_a4c3_bdb7a37f6686/hdlfarrow_userdefined_tb.vhd
### Creating stimulus vectors ...
### Done generating VHDL Test Bench.

ModelSim® Simulation Results

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

Conclusion

In this example, we showed how you can design a double-precision fractional delay filter to meet the given specifications. We also showed how you can quantize the filter and generate VHDL code. Then we showed how you can generate VHDL test benches using several options to specify the input and fracdelay stimulus vector.

You can use any HDL simulator to verify these results. You can also experiment with Verilog for both filters and test benches.