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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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/Bdoc24b_2745562_153532/tp5e31ff0b_7cd6_46f4_b2b9_175308c549d1/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.