dsp.HDLFIRFilter

Finite impulse response filter—optimized for HDL code generation

Description

The dsp.HDLFIRFilter System object™ models finite-impulse response filter architectures optimized for HDL code generation. The object accepts one input sample at a time, and provides an option for programmable coefficients. It provides a hardware-friendly interface with input and output control signals. To provide a cycle-accurate simulation of the generated HDL code, the object models architectural latency including pipeline registers and resource sharing.

The object provides three filter structures. The direct form systolic architecture provides a fully parallel implementation that makes efficient use of Intel® and Xilinx® DSP blocks. The direct form transposed architecture is a fully parallel implementation and is suitable for FPGA and ASIC applications. The partly-serial systolic architecture provides a configurable serial implementation that makes efficient use of FPGA DSP blocks. For a filter implementation that matches multipliers, pipeline registers, and pre-adders to the DSP configuration of your FPGA vendor, specify your target device when you generate HDL code.

All three structures optimize hardware resources by sharing multipliers for symmetric or antisymmetric filters. The parallel implementations also remove the multipliers for zero-valued coefficients such as in half-band filters and Hilbert transforms.

The latency between valid input data and the corresponding valid output data depends on the filter structure, serialization options, the number of coefficients and whether the coefficient values provide optimization opportunities.

For a FIR filter with multichannel or frame-based inputs, use the dsp.FIRFilter System object instead of this System object.

To filter input data with an HDL-optimized FIR filter:

  1. Create the dsp.HDLFIRFilter object and set its properties.

  2. Call the object with arguments, as if it were a function.

To learn more about how System objects work, see What Are System Objects? (MATLAB).

Creation

Description

firFilt = dsp.HDLFIRFilter creates an HDL-optimized discrete FIR filter System object, firFilt, with default properties.

firFilt = dsp.HDLFIRFilter(num) creates a filter with the Numerator property set to num.

firFilt = dsp.HDLFIRFilter(___,Name,Value)sets properties using one or more name-value pairs. Enclose each property name in single quotes.

For example:

Numerator = firpm(10,[0,0.1,0.5,1],[1,1,0,0]);
fir = dsp.HDLFIRFilter(Numerator,'FilterStructure','Direct form transposed');
...
[dataOut,validOut] = fir(dataIn,validIn);

Properties

expand all

Unless otherwise indicated, properties are nontunable, which means you cannot change their values after calling the object. Objects lock when you call them, and the release function unlocks them.

If a property is tunable, you can change its value at any time.

For more information on changing property values, see System Design in MATLAB Using System Objects (MATLAB).

Main

You can enter constant filter coefficients as a property or provide time-varying filter coefficients using an input argument.

Setting this property to 'Input port (Parallel interface)' enables the coeff argument, and the NumeratorPrototype property. Specify a prototype to enable the object to optimize the filter implementation according to the symmetry of your coefficients. To use 'Input port (Parallel interface)', set the FilterStructure property to 'Direct form systolic'.

Discrete FIR filter coefficients, specified as a vector of real or complex values. You can also specify the vector as a workspace variable, or as a call to a filter design function. When the input data type is a floating-point type, the object casts the coefficients to the same data type as the input. When the input data type is an integer type or a fixed-point type, you can modify the coefficient data type by using the CoefficientsDataType property.

Example: dsp.HDLFIRFIlter('Numerator',firpm(30,[0 0.1 0.2 0.5]*2,[1 1 0 0])) defines coefficients using a linear-phase filter design function.

Dependencies

To enable this property, set NumeratorSource to 'Property'.

Data Types: single | double | int8 | int16 | int32 | uint8 | uint16 | uint32

Prototype filter coefficients, specified as a vector of real or complex values. The prototype specifies a sample coefficient vector that is representative of the symmetry and zero-value locations of the expected input coefficients. If all of your input coefficient vectors have the same symmetry and zero-value coefficient locations, set NumeratorPrototype to one of those vectors. If your coefficients are unknown or not expected to share symmetry or zero-value locations, set NumeratorPrototype to []. The object uses the prototype to optimize the filter by sharing multipliers for symmetric or antisymmetric coefficients, and removing multipliers for zero-value coefficients.

Coefficient optimizations affect the expected size of the coeff input argument. Provide only the nonduplicate coefficients as the argument. For example, if you set the NumeratorPrototype property to a symmetric 14-tap filter, the object shares one multiplier between each pair of duplicate coefficients, so the object expects a vector of 7 values for the coeff argument. You must still provide zeros in the input coeff vector for the nonduplicate zero-value coefficients.

Dependencies

To enable this property, set NumeratorSource to 'Input port (Parallel interface)'.

Data Types: single | double | int8 | int16 | int32 | uint8 | uint16 | uint32

HDL filter architecture, specified as one of these structures:

  • 'Direct form systolic' — This architecture provides a fully parallel filter implementation that makes efficient use of Intel and Xilinx DSP blocks. For architecture and performance details, see Fully Parallel Systolic Architecture.

  • 'Direct form transposed' — This architecture is a fully parallel implementation that is suitable for FPGA and ASIC applications. For architecture and performance details, see Fully Parallel Transposed Architecture.

  • 'Partly serial systolic' — This architecture provides a serial filter implementation and options for tradeoffs between throughput and resource utilization. It makes efficient use of Intel and Xilinx DSP blocks. The object implements a serial L-coefficient filter with M multipliers and requires input samples that are at least N cycles apart, such that L = N×M. You can specify either M or N. For this implementation, the object provides an output signal, ready, that indicates when the object is ready for new input data. For architecture and performance details, see Partly Serial Systolic Architecture (1 < N < L) and Fully Serial Systolic Architecture (N ≥ L).

All implementations share multipliers for symmetric and antisymmetric coefficients. The 'Direct form systolic' and 'Direct form transposed' structures also remove multipliers for zero-valued coefficients.

Specify the rule that the object uses to serialize the filter as one of:

  • 'Minimum number of cycles between valid input samples' – Specify a requirement for input data timing by using the NumberOfCycles property.

  • 'Maximum number of multipliers' – Specify a requirement for resource usage by using the NumberOfMultipliers property.

For a filter with L coefficients, the object implements a serial filter with not more than M multipliers and requires input samples that are at least N cycles apart, such that L = N×M. The object applies coefficient optimizations after serialization, so the M or N values of the final filter implementation can be lower than the value that you specified.

Dependencies

To enable this property, set FilterStructure to 'Partly serial systolic'.

Serialization requirement for input timing, specified as a positive integer. This property represents N, the minimum number of cycles between valid input samples. In this case, the object calculates M = L/N. To implement a fully-serial architecture, set NumberOfCycles to a value greater than the filter length, L, or to Inf.

The object applies coefficient optimizations after serialization, so the M and N values of the final filter can be lower than the value you specified.

Dependencies

To enable this property, set FilterStructure to 'Partly serial systolic' and set SerializationOption to 'Minimum number of cycles between valid input samples'.

Serialization requirement for resource usage, specified as a positive integer. This property represents M, the maximum number of multipliers in the filter implementation. In this case, the object calculates N = L/M. If the input data is complex, the object allocates floor(M/2) multipliers for the real part of the filter and floor(M/2) multipliers for the imaginary part of the filter. To implement a fully-serial architecture, set NumberOfMultipliers to 1 for real input, or 2 for complex input.

The object applies coefficient optimizations after serialization, so the M and N values of the final filter can be lower than the value you specified.

Dependencies

To enable this property, set the FilterStructure to 'Partly serial systolic', and set SerializationOption to 'Maximum number of multipliers'.

Data Types

Rounding method for type-casting the output, specified as 'Floor', 'Ceiling', 'Convergent', 'Nearest', 'Round', or 'Zero'. The rounding method is used when casting the output to the data type specified by the OutputDataType property. When the input data type is floating point, the object ignores the RoundingMethod property. For more details, see Rounding Modes.

Overflow handling for type-casting the output, specified as 'Wrap' or 'Saturate'. Overflow handling is used when casting the output to the data type specified by the OutputDataType property. When the input data type is floating point, the object ignores the OverflowAction property. For more details, see Overflow Handling.

Data type of discrete FIR filter coefficients, specified as 'Same word length as input' or a numerictype object. To specify a numerictype object, call numerictype(s,w,f), where:

  • s is 1 for signed and 0 for unsigned.

  • w is the word length in bits.

  • f is the number of fractional bits.

The object type-casts the filter coefficients of the discrete FIR filter to the specified data type. The quantization rounds to the nearest representable value and saturates on overflow. When the input data type is floating point, the object ignores the Coefficients property.

Dependencies

To enable this property, set NumeratorSource to 'Property'.

Data type of discrete FIR filter output, specified as 'Same word length as input', 'Full precision', or a numerictype object. To specify a numerictype object, call numerictype(s,w,f), where:

  • s is 1 for signed and 0 for unsigned.

  • w is the word length in bits.

  • f is the number of fractional bits.

The object type-casts the output of the discrete FIR filter to the specified data type. The quantization uses the settings of the RoundingMethod and OverflowAction properties. When the input data type is floating point, the object ignores the OutputDataType property.

The object increases the word length for full precision inside each filter tap and casts the final output to the specified type. The maximum final internal data type (WF) depends on the input data type (WI), the coefficient data type (WC), and the number of coefficients (L) and is given by

WF = WI + WC + ceil(log2(L)).

When you specify a fixed set of coefficients, usually the actual full-precision internal word length is smaller than WF because the values of the coefficients limit the potential growth. When you use programmable coefficients, the object cannot calculate the dynamic range, and the internal data type is always WF.

Control Arguments

When you set this property to true, the object expects a value for the reset input argument. The reset signal implements a local synchronous reset of the data path registers.

For more reset considerations, see Tips.

Set this property to true to connect the generated HDL global reset signal to the data path registers. This property does not change the arguments of the object or modify simulation behavior in MATLAB®. When this property is set to false, the generated HDL global reset clears only control path registers. The generated HDL global reset can be synchronous or asynchronous depending on your HDL code generation settings.

For more reset considerations, see Tips.

Usage

Description

[dataOut,validOut] = firFilt(dataIn,validIn) filters the input data only when validIn is true.

example

[dataOut,validOut,ready] = firFilt(dataIn,validIn) returns ready set to true when the object is ready to accept new input data on the next call.

The object returns the ready argument only when you set the FilterStructure property to 'Partly serial systolic'. For example:

firFilt = dsp.HDLFIRFilter(Numerator,...
            'FilterStructure','Partly serial systolic',...
            'SerializationOption','Minimum number of cycles between valid input samples',...
            'NumberOfCycles',8)
...
for k=1:length(dataIn)
    [dataOut,validOut,ready] = firFilt(dataIn(k),validIn(k));

[dataOut,validOut] = firFilt(dataIn,validIn,coeff) filters data using the coefficients, coeff. The object expects the coeff argument only when you set the NumeratorSource property to 'Input port (Parallel interface)'. For example:

firFilt = dsp.HDLFIRFilter(NumeratorSource,'Input Port (Parallel interface)')
...
for k=1:length(dataIn)
    Numerator = myGetNumerator();  %calculate coefficients
    [dataOut,validOut] = firFilt(dataIn(k),validIn(k),Numerator);

[dataOut,validOut] = firFilt(dataIn,validIn,reset) filters data when reset is false. When reset is true, the object resets the filter registers. The object expects the reset argument only when you set the ResetInputPort property to true. For example:

firFilt = dsp.HDLFIRFilter(Numerator,'ResetInputPort',true)
...
% reset the filter
firFilt(0,false,true);
for k=1:length(dataIn)
    [dataOut,validOut] = firFilt(dataIn(k),validIn(k),false);
For more reset considerations, see Tips.

Input Arguments

expand all

Input data, specified as a real or complex scalar. When the input data type is an integer type or fixed-point type, the object uses fixed-point arithmetic for internal calculations. double and single data types are accepted for simulation but not for HDL code generation.

Data Types: fi | single | double | int8 | int16 | int32 | uint8 | uint16 | uint32
Complex Number Support: Yes

Validity of the input data, specified as a logical scalar. The dataIn argument is valid only when validIn is 1 (true).

Data Types: logical

Filter coefficients, specified as a vector of real or complex values. You can change the input coefficients at any time. The size of the vector depends on the size and symmetry of the sample coefficients specified in the NumeratorPrototype property. The prototype specifies a sample coefficient vector that is representative of the symmetry and zero-value locations of the expected input coefficients. The object uses the prototype to optimize the filter by sharing multipliers for symmetric or antisymmetric coefficients, and removing multipliers for zero-value coefficients. Therefore, provide only the nonduplicate coefficients in the argument. For example, if you set the NumeratorPrototype property to a symmetric 14-tap filter, the object expects a vector of 7 values for the coeff argument. You must still provide zeros in the input coeff vector for the nonduplicate zero-value coefficients.

double and single data types are accepted for simulation but not for HDL code generation.

Dependencies

To enable this argument, set the NumeratorSource property to 'Input port (Parallel interface)'.

Data Types: fi | single | double | int8 | int16 | int32 | uint8 | uint16 | uint32

When the reset argument is true, the object stops the current calculation and clears the internal state of the filter. The reset signal is synchronous and clears the data path and control path states. For more reset considerations, see Tips.

Dependencies

To enable this argument, set the ResetInputPort property to true.

Data Types: logical

Output Arguments

expand all

Filtered output data, returned as a real or complex scalar. When the input data is floating point, the output data inherits the data type of the input data. When the input data is an integer type or fixed-point type, the OutputDataType property determines the output data type.

Data Types: fi | single | double
Complex Number Support: Yes

Validity of the output data, returned as a logical scalar. The object sets validOut to 1 (true) with each valid output data in the dataOut argument.

Data Types: logical

Indication of whether the object is ready for new input data, returned as a logical scalar. The object sets this value to true to indicate that it is ready to accept new input data on the next call.

When using the partly-serial architecture, the object processes one sample at a time. If your design waits for the object to return ready set to false before de-asserting validIn, then one extra data input value arrives at the object. The object stores this extra data while processing the current data, and then does not set ready to true until the extra input is processed.

Dependencies

The object returns this value only when the FilterStructure property is set to 'Partly serial systolic'.

Data Types: logical

Object Functions

To use an object function, specify the System object as the first input argument. For example, to release system resources of a System object named obj, use this syntax:

release(obj)

expand all

getLatencyLatency of FIR filter
stepRun System object algorithm
releaseRelease resources and allow changes to System object property values and input characteristics
resetReset internal states of System object

Examples

expand all

Create an HDL FIR filter System object with default settings.

firFilt = dsp.HDLFIRFilter;

Create an input signal of random noise, and allocate memory for outputs.

L = 100;
dataIn = randn(L,1);
dataOut = zeros(L,1);
validOut = false(L,1);

Call the object on the input signal, asserting that the input data is always valid. The object processes one data sample at a time.

for k=1:L
    [dataOut(k),validOut(k)] = firFilt(dataIn(k),true);
end

This example shows how to configure the dsp.HDLFIRFilter System object™ as a partly-serial 31-tap lowpass filter.

Design the filter coefficients. Then create an HDL FIR filter System object. Set the FilterStructure to 'Partly serial systolic'. By default, the SerializationOption property is 'Minimum number of cycles between valid input samples', and so you must specify the serialization rule using the NumberOfCycles property. To share each multiplier between 10 coefficients, set the NumberOfCycles to 10.

numerator = firpm(30,[0 0.1 0.2 0.5]*2,[1 1 0 0]);
numCycles = 10;
firFilt = dsp.HDLFIRFilter('Numerator',numerator, ...
    'FilterStructure','Partly serial systolic','NumberOfCycles',numCycles);

This serial filter implementation requires 10 time steps to calculate each output. Create input signals dataIn and validIn such that new data is applied only every NumberOfCycles time steps.

L = 16;
x = fi(randn(L,1),1,16);
dataIn = zeros(L*numCycles,1,'like',x);
dataIn(1:numCycles:end) = x;
validIn = false(L*numCycles,1);
validIn(1:numCycles:end) = true;

Create a LogicAnalyzer object to view the inputs and output signals.

la = dsp.LogicAnalyzer('NumInputPorts',5, ...
    'SampleTime',1,'TimeSpan',length(dataIn));
tags = getDisplayChannelTags(la);
modifyDisplayChannel(la,tags{1},'Name','dataIn');
modifyDisplayChannel(la,tags{2},'Name','validIn');
modifyDisplayChannel(la,tags{3},'Name','dataOut');
modifyDisplayChannel(la,tags{4},'Name','validOut');
modifyDisplayChannel(la,tags{5},'Name','ready');

Call the filter System object on the input signals, and view the results in the Logic Analyzer. The object models HDL pipeline registers and resource sharing, so the waveform shows an initial delay before the object returns valid output samples.

for k=1:length(dataIn)
    [dataOut,validOut,ready] = firFilt(dataIn(k),validIn(k));
    la(dataIn(k),validIn(k),dataOut,validOut,ready)
end

To generate HDL code from a System object™, create a function that contains and calls the object.

Create Function

Write a function that creates and calls an 11-tap HDL FIR filter System object. You can generate HDL code from this function.

function [dataOut,validOut] = HDLFIR11Tap(dataIn, validIn)
%HDLFIR11Tap
% Process one sample of data by using the dsp.HDLFIRFilter System
% object. 
% dataIn is a fixed-point scalar value. 
% You can generate HDL code from this function.
    persistent fir
    if isempty(fir)
        Numerator = firpm(10,[0 0.1 0.5 1],[1 1 0 0]);
        fir = dsp.HDLFIRFilter('Numerator',Numerator);
    end
    [dataOut,validOut] = fir(dataIn,validIn);    
end


Create Test Bench for Function

Clear the workspace, create an input signal of random noise, and allocate memory for outputs.

clear variables
clear HDLFIR11Tap
L = 200;
dataIn = fi(randn(L,1),1,16);
validIn = ones(L,'logical');
dataOut = zeros(L,1);
validOut = false(L,1);

Call the function on the input signal.

for k = 1:L
    [dataOut(k),validOut(k)] = HDLFIR11Tap(dataIn(k), validIn(k));
end

Plot the signals with the Logic Analyzer.

la = dsp.LogicAnalyzer('NumInputPorts',3,'SampleTime',1,'TimeSpan',L);
tags = getDisplayChannelTags(la);
modifyDisplayChannel(la,tags{1},'Name','dataIn','Format','Analog','Height',50);
modifyDisplayChannel(la,tags{2},'Name','dataOut','Format','Analog','Height',50);
modifyDisplayChannel(la,tags{3},'Name','validOut');
la(dataIn,dataOut,validOut)

The latency of the dsp.HDLFIRFilter System object™ varies with filter structure, serialization options, and whether the coefficient values provide optimization opportunities. Use the getLatency function to find the latency of a particular configuration. The latency is the number of cycles between the first valid input and the first valid output.

Create a dsp.HDLFIRFilter System object™ and request the latency. The default architecture is fully parallel systolic. The default data type for the coefficients is 'Same word length as input'. Therefore, when you call the getLatency object function, you must specify an input data type. The object casts the coefficient values to the input data type, and then checks for symmetric coefficients. This Numerator has 31 symmetric coefficients, so the object optimizes for the shared coefficients, and implements 16 multipliers.

Numerator = firpm(30,[0 0.1 0.2 0.5]*2,[1 1 0 0]);
Input_type = numerictype(1,16,15); % object uses only the word length for coefficient type cast
hdlfir = dsp.HDLFIRFilter('Numerator',Numerator);
L_sysp = getLatency(hdlfir,Input_type)
L_sysp = 23

Check the latency for a partly serial systolic implementation of the same filter. By default, the SerializationOption property is 'Minimum number of cycles between valid input samples', and so you must specify the serialization rule using the NumberOfCycles property. To share each multiplier between 8 coefficients, set the NumberOfCycles to 8. The object then optimizes based on the coefficient symmetry, so there are 16 unique coefficients shared 8 times each over 2 multipliers. This serial filter implementation requires input samples that are valid every 8 cycles.

hdlfir = dsp.HDLFIRFilter('Numerator',Numerator,'FilterStructure','Partly serial systolic','NumberOfCycles',8);
L_syss = getLatency(hdlfir,Input_type)
L_syss = 19

Check the latency of a nonsymmetric fully parallel systolic filter. The Numerator has 31 coefficients.

Numerator = sinc(0.4*[-30:0]);
hdlfir = dsp.HDLFIRFilter('Numerator',Numerator);
L_sysp = getLatency(hdlfir,Input_type)
L_sysp = 37

Check the latency of the same nonsymmetric filter implemented as a partly serial systolic filter. In this case, specify the SerializationOption by the number of multipliers. The object implements a filter that has 2 multipliers and requires 8 cycles between input samples.

hdlfir = dsp.HDLFIRFilter('Numerator',Numerator,'FilterStructure','Partly serial systolic',...
                          'SerializationOption','Maximum number of multipliers','NumberOfMultipliers',2);
L_syss = getLatency(hdlfir,Input_type)
L_syss = 25

Check the latency of a fully parallel transposed architecture. The latency for this filter structure is always 6 cycles.

hdlfir = dsp.HDLFIRFilter('Numerator',Numerator,'FilterStructure','Direct form transposed');
L_trans = getLatency(hdlfir,Input_type)
L_trans = 6

Tips

Reset Behavior

  • By default, the dsp.HDLFIRFilter object connects the generated HDL global reset to only control path registers. The two reset properties, ResetInputPort and HDLGlobalReset, connect a reset signal to the data path registers. Resetting data path registers can reduce synthesis performance because of the additional routing and loading on the reset signal.

  • The ResetInputPort property enables a reset argument when you call the object. The reset signal implements a local synchronous reset of the data path registers. For optimal use of FPGA resources, this option does not connect the reset signal to registers targeted to the DSP blocks of the FPGA.

  • The HDLGlobalReset property connects the generated HDL global reset signal to the data path registers. This property does not change the arguments of the object or modify simulation behavior in MATLAB. The generated HDL global reset can be synchronous or asynchronous depending on your HDL code generation settings. Depending on your device, using the global reset may move registers out of the DSP blocks and increase resource use.

  • When you set both the ResetInputPort and HDLGlobalReset properties to true, both the global and local reset signals clear the control and data path registers.

Algorithms

This System object implements the algorithms described on the Discrete FIR Filter HDL Optimized block reference page.

Compatibility Considerations

expand all

Behavior changed in R2019a

Introduced in R2017a