주요 콘텐츠

dsphdl.Channelizer

Polyphase filter bank and fast Fourier transform

Description

The dsphdl.Channelizer System object™ separates a broadband input signal into multiple narrowband output signals. It provides hardware speed and area optimization for streaming data applications. The object accepts scalar or vector input of real or complex data, provides hardware-friendly control signals, and has optional output frame control signals. You can achieve gigasamples-per-second (GSPS) throughput by using vector input. The object implements a polyphase filter, with one subfilter per input vector element. The hardware implementation interleaves the subfilters, which results in sharing each filter multiplier (FFT Length / Input Size) times. The object implements the same pipelined Radix 2^2 FFT algorithm as the dsphdl.FFT System object.

To channelize input data:

  1. Create the dsphdl.Channelizer 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?

Note

The output of this object has a phase shift compared to the dsp.Channelizer (DSP System Toolbox™) object unless you set the PreservePhase property to true. The channels detected by both blocks match when analyzed over multiple frames. Also, to match the dsp.Channelizer (DSP System Toolbox) object, apply FFT Length – 1 zeros at the start of the data stream. For an example of comparing the two algorithms, see Preserve Channelizer Phase.

Note

You can also generate HDL code for this hardware-optimized algorithm, without creating a MATLAB® script, by using the DSP HDL IP Designer app. The app provides the same interface and configuration options as the System object.

Creation

Description

channelizer = dsphdl.Channelizer returns a System object, channelizer, that implements a raised-cosine filter and an 8-point FFT.

channelizer = dsphdl.Channelizer(PropertyName=Value) sets properties using one or more name-value arguments.

example

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.

FFT length, specified as an integer power of two. For HDL code generation, the FFT length must be between 22 and 216, inclusive.

Polyphase filter coefficients, specified as a vector of numeric values. If the number of coefficients is not a multiple of NumFrequencyBands, the object pads this vector with zeros. The default filter specification is a raised-cosine FIR filter, rcosdesign(0.25,2,4,'sqrt'). You can specify a vector of coefficients or a call to a filter design function that returns the coefficient values. By default, the object casts the coefficients to the same word length as the input.

Specify the HDL filter architecture as one of these structures:

  • 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.

  • 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.

HDL implementation of complex multipliers, specified as either 'Use 4 multipliers and 2 adders' or 'Use 3 multipliers and 5 adders'. Depending on your synthesis tool and target device, one option may be faster or smaller.

Size of output data, specified as:

  • 'Same as number of frequency bands' — Output data is a 1-by-M vector, where M is the FFT length.

  • 'Same as input size' — Output data is an M-by-1 vector, where M is the input vector size.

The output order is bit natural for both output sizes.

FFT output scaling, specified as either:

  • true — The FFT implements an overall 1/N scale factor by scaling the result of each pipeline stage by 2. This adjustment keeps the output of the FFT in the same amplitude range as its input.

  • false — The FFT avoids overflow by increasing the word length by one bit at each stage.

Since R2026a

The hardware-optimized channelizer algorithm results in a phase rotation of 2Π/FFTLength for each channel compared to the dsp.Channelizer object. Set this property to true to shift the phase of the output signal to match the dsp.Channelizer output.

The phase correction uses one complex multiplier and adds five cycles of latency. If your output size and FFT length equal 4, then the shift values are +/- 1 and the channelizer implements the shift without a multiplier.

Rounding mode used for fixed-point operations. The object uses fixed-point arithmetic for internal calculations when the input is any integer or fixed-point data type. This option does not apply when the input is single or double. Each FFT stage rounds after the twiddle factor multiplication but before the butterflies. Rounding can also occur when casting the coefficients and the output of the polyphase filter to the data types you specify.

Overflow Handling used for fixed-point operations. The object uses fixed-point arithmetic for internal calculations when the input is any integer or fixed-point data type. This option does not apply when the input is single or double. This option applies to casting the coefficients and the output of the polyphase filter to the data types you specify.

The FFT algorithm avoids overflow by either scaling the output of each stage (Normalize enabled), or by increasing the word length by 1 bit at each stage (Normalize disabled).

The object casts the polyphase filter coefficients to this data type, using the rounding and overflow settings you specify. When you specify 'Same word length as input' (default), the object selects the binary point using fi() best-precision rules.

If you specify an unsigned data type for this parameter, the filter uses the unsigned values and converts them to a signed data type. The signed data type is required to map the design onto DSP slices on an FPGA.

Data type of the output of the polyphase filter, specified as 'Same word length as input', 'Full precision', or a numerictype object. The object casts the output of the polyphase filter (the input to the FFT) to this data type, using the rounding and overflow settings you specify. When you specify 'Full precision', the object selects a best-precision binary point by considering the values of your filter coefficients and the range of your input data type.

By default, the FFT logic does not change the data type. When you disable Normalize, the FFT algorithm avoids overflow by increasing the word length by 1 bit at each stage.

Enable reset input argument to the object. When reset is 1 (true), the object stops the current calculation and clears internal states. When the reset is 0 (false) and the input valid is 1 (true), the object captures data for processing.

Enable startOut output argument of the object. When enabled, the object returns an additional output signal that is 1 (true) on the first cycle of each valid output frame.

Enable endOut output argument of the object. When enabled, the object returns an additional output signal that is 1 (true) on the first cycle of each valid output frame.

Usage

Description

[dataOut,validOut] = channelizer(dataIn,validIn) filters and computes a fast Fourier transform, and returns the frequency channels, dataOut, detected in the input signal, dataIn, when validIn is 1 (true). The validIn and validOut arguments are logical scalars that indicate the validity of the input and output signals, respectively.

example

[dataOut,validOut] = channelizer(dataIn,validIn,reset) returns the frequency channels, dataOut, detected in the input signal, dataIn, when validIn is 1 (true) and reset is 0 (false). When reset is 1 (true), the object stops the current calculation and clears all internal state.

To use this syntax, set the ResetInputPort property to true. For example:

channelizer = dsphdl.Channelizer(...,ResetInputPort=true);
...
[dataOut,validOut] = channelizer(dataIn,validIn,reset)

[dataOut,startOut,endOut,validOut] = channelizer(___) returns the frequency channels, dataOut, computed from the input arguments of any of the previous syntaxes. startOut is 1 (true) for the first sample of a frame of output data. endOut is 1 (true) for the last sample of a frame of output data.

To use this syntax, set the StartOutputPort and EndOutputPort properties to true. For example:

channelizer = dsphdl.Channelizer(...,StartOutputPort=true,EndOutputPort=true);
...
[dataOut,startOut,endOut,validOut] = channelizer(dataIn,validIn)

Input Arguments

expand all

Input data, specified as a scalar or column vector of real or complex values.

The vector size must be a power of 2 and in the range [2, 64], and is not greater than the number of channels (FFT length).

The software supports double and single data types for simulation, but not for HDL code generation.

The object does not accept uint64 data.

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

Control signal that indicates if the input data is valid. When validIn is 1 (true), the object captures the values from the dataIn argument. When validIn is 0 (false), the object ignores the values from the dataIn argument.

Data Types: logical

Control signal that clears internal states. When reset is 1 (true), the object stops the current calculation and clears internal states. When the reset is 0 (false) and the input valid is 1 (true), the block captures data for processing.

For more reset considerations, see the Reset Signal section on the Hardware Control Signals page.

Dependencies

To enable this argument, set ResetInputPort to true.

Data Types: logical

Output Arguments

expand all

Frequency channel output data, returned as a row vector.

  • If you set OutputSize to 'Same as number of frequency bands' (default), the output data is a 1-by-M vector, where M is the FFT length.

  • If you set OutputSize to 'Same as input size', the output data is an M-by-1 vector, where M is the input vector size.

The output order is bit natural for either output size. The data type is a result of the FilterOutputDataType and the FFT bit growth necessary to avoid overflow.

Control signal that indicates if the output data is valid. When validOut is 1 (true), the object returns valid data from the dataOut argument. When validOut is 0 (false), values from the dataOut argument are not valid.

Data Types: logical

First sample of output frame, returned as a logical scalar. The object sets startOut to 1 (true) during the first valid sample on dataOut.

Dependencies

To enable this argument, set StartOutputPort to true.

Data Types: logical

Last sample of output frame, returned as a logical scalar. The object sets endOut to 1 (true) during the last valid sample on dataOut.

Dependencies

To enable this argument, set EndOutputPort to true.

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 channelizer calculation
stepRun System object algorithm
releaseRelease resources and allow changes to System object property values and input characteristics
resetReset internal states of System object

Examples

collapse all

Create a function that contains a channelizer object and supports HDL code generation.

Create the specifications and input signal. The signal has 8 frequency channels.

N = 8;
loopCount = 1024;
offsets = [-40 -30 -20 10 15 25 35 -15];
sinewave = dsp.SineWave(ComplexOutput=true, ...
    Frequency=offsets+(-375:125:500), ...
    SamplesPerFrame=loopCount);
sa = spectrumAnalyzer(ShowLegend=true, ...
     SampleRate=sinewave.SampleRate/N);

Write a function that creates and calls the channelizer System object™. You can generate HDL from this function.

function [yOut,validOut] = HDLChannelizer8(yIn,validIn)
%HDLChannelizer8 
% Process one sample of data using the dsphdl.Channelizer System object
% yIn is a fixed-point scalar or column vector. 
% validIn is a logical scalar value.
% You can generate HDL code from this function.

  persistent channelize8;
  coder.extrinsic('tf');
  coder.extrinsic('dsp.Channelizer');
  
  if isempty(channelize8)
    % Use filter coeffs from non-HDL channelizer, or supply your own.  
    channelizer = coder.const(dsp.Channelizer(NumFrequencyBands=8));
    coeff = coder.const(tf(channelizer));
    channelize8 = dsphdl.Channelizer(NumFrequencyBands=8,FilterCoefficients=coeff);
  end    
  [yOut,validOut] = channelize8(yIn,validIn);
end

% Copyright 2016-2023 The MathWorks, Inc.

Channelize the input data by calling the object for each data sample.

y = zeros(loopCount/N,N);
validOut = false(loopCount/N,1);
yValid = zeros(loopCount/(N*N),N);
for reps=1:10
   x = fi(sum(sinewave(),2),1,18);
   for loop=1:length(x)
      [y(loop,:),validOut(loop)]= HDLChannelizer8(x(loop),true);
   end
   yValid = y(validOut == 1,:);
   sa(yValid);
end

This example shows how to separate channels of a sine wave signal with multiple frequencies, and compare the results using dsp.Channelizer and dsphdl.Channelizer objects.

You can also implement this algorithm in Simulink® by using the DSP HDL Toolbox™ Channelizer block.

Generate a sine wave with multiple frequencies as the input signal. Configure both channelizers to split the signal into 8 frequency bands.

Fs = 2000;
nBand = 8;

nTone = 3; % # of tones at randomized freq
tones = randi([-Fs/2 Fs/2],1,nTone)
tones = 1×3

   630   812  -746

sinewave = dsp.SineWave(ComplexOutput=true,Frequency=tones,SampleRate=Fs,...
    SamplesPerFrame=100*nBand);

DSP System Toolbox™ Channelizer

Split the input signal into frequency channels by using the dsp.Channelizer System object™. Calculate and display the magnitude of the frequency response.

channelizer = dsp.Channelizer(NumFrequencyBands=nBand,StopbandAttenuation=140);

x = sum(sinewave(),2);
y = channelizer(x);
yf = abs(fftshift(fft(y),1));

% Frequency axis
Finc = Fs/numel(yf);
Faxis = -Fs/2:Finc:Fs/2-Finc;

% Shift the freq axis so bin 1 is Fs/nBand centered at 0 Hz
Faxis = circshift(Faxis,-numel(yf)/2 + size(yf,1)/2); 
Fgrid = reshape(Faxis,size(yf));

% Bin (nBand/2)+1 wraps from Fs/2 to -Fs/2. Nulling the data point at -Fs/2
% prevents a connecting line across the plot
yf(Fgrid==-Fs/2) = NaN;

figure; colororder("glow12")
title("dsp.Channelizer")
hold on;
for n = 1:size(yf,2)
    xline(Fgrid(1,n),'--',['Bin ' num2str(n)]);
    plot(Fgrid(:,n),yf(:,n));
    
end
hold off

Figure contains an axes object. The axes object with title dsp.Channelizer contains 16 objects of type constantline, line.

DSP HDL Toolbox™ Channelizer

The dsphdl.Channelizer System object™ uses a different architecture compared to the DSP System Toolbox version. The hardware-optimized implementation results in a phase shift in the output. However the magnitude responses are the same.

hdlchannelizer = dsphdl.Channelizer(NumFrequencyBands=nBand,...
    FilterCoefficients=channelizer.coeffs.Numerator,Normalize=false);

latency = getLatency(hdlchannelizer) 
latency = 
53
xin = [x; zeros(latency,1)]; % account for HDL latency
vin = [true(numel(x),1); false(latency,1)];

z = zeros(numel(xin),nBand);
vout = false(numel(xin),1);
for k = 1:numel(vout)
    [z(k,:),vout(k)] = hdlchannelizer(xin(k),vin(k));
end

zvalid = z(vout,:);
zf = abs(fftshift(fft(zvalid),1));

% Null data point at -F2/2 for plotting
zf(Fgrid==-Fs/2) = NaN;

figure; colororder("glow12")
title("dsphdl.Channelizer")
hold on;
for n = 1:size(zf,2)
    xline(Fgrid(1,n),'--',['Bin ' num2str(n)]);
    plot(Fgrid(:,n),zf(:,n));
end
hold off

Figure contains an axes object. The axes object with title dsphdl.Channelizer contains 16 objects of type constantline, line.

Compare the outputs of the dsp.Channelizer and the dsphdl.Channelizer objects sample-by-sample.

reference=reshape(y,[],1);
dsphdl=reshape(zvalid,[],1);
label = 'dsp.Channelizer vs dsphdl.Channelizer';

ref_vec = double([real(reference) imag(reference)]);
dsphdl_vec = double([real(dsphdl) imag(dsphdl)]);
err_vec = ref_vec - dsphdl_vec;
max_err = max(abs(err_vec));
max_ref = max(abs(ref_vec));

figure;
c = get(groot,'defaultAxesColorOrder');
% Plot real and imaginary parts separately
tag = {'(Real)','(Imag)'};
msg = sprintf('\nMaximum error for %s out of %d values\n',label,length(dsphdl));
for n = 1:size(ref_vec,2)
    msg = [msg sprintf('%s %d (absolute), %d (percentage)\n',tag{n},max_err(n),max_err(n)/max_ref(n)*100)];
    row_num = size(ref_vec,2);
    col_num = 1;
    plot_num = n;
    subplot(row_num,col_num,plot_num);
    plot(ref_vec(:,n),'Color',c(3,:));
    hold on
    plot(dsphdl_vec(:,n),'Color',c(1,:));
    plot(err_vec(:,n),'Color',c(2,:));
    legend('Reference','HDL Algorithm','Error')
    title(sprintf('%s %s\n max error = %.3d',label,tag{n},max_err(n)));
    hold off
end

Figure contains 2 axes objects. Axes object 1 with title dsp.Channelizer vs dsphdl.Channelizer (Real) max error = 2.361e+00 contains 3 objects of type line. These objects represent Reference, HDL Algorithm, Error. Axes object 2 with title dsp.Channelizer vs dsphdl.Channelizer (Imag) max error = 2.349e+00 contains 3 objects of type line. These objects represent Reference, HDL Algorithm, Error.

fprintf(msg);
Maximum error for dsp.Channelizer vs dsphdl.Channelizer out of 800 values
(Real) 2.360518e+00 (absolute), 1.556526e+02 (percentage)
(Imag) 2.348774e+00 (absolute), 1.511404e+02 (percentage)

To produce identical outputs, zero-pad the input with nBand-1 zeros, and configure the dsphdl.Channelizer object to adjust the output phase. The phase correction adds five cycles of latency to the object compared to the default settings. If your output size is the same as the FFT length, the channelizer implements the phase correction with canonical signed digit (CSD) multiplies. Otherwise, the phase correction uses one complex multiplier.

reset(hdlchannelizer);
release(hdlchannelizer);
hdlchannelizer.PreservePhase=true;
latency = getLatency(hdlchannelizer) 
latency = 
58
xin2 = [zeros(nBand-1,1); xin];
vin2 = [true(nBand-1,1); vin];

z2 = zeros(numel(xin2),nBand);
vout2 = false(numel(xin2),1);
for k = 1:numel(vout2)
    [z2(k,:),vout2(k)] = hdlchannelizer(xin2(k),vin2(k));
end
z2valid = z2(vout2,:);

Again, compare the outputs of the dsp.Channelizer and the dsphdl.Channelizer objects sample-by-sample.

reference=reshape(y,[],1);
dsphdl=reshape(z2valid,[],1);
label = 'dsp.Channelizer vs dsphdl.Channelizer with Phase Preservation';

ref_vec = double([real(reference) imag(reference)]);
dsphdl_vec = double([real(dsphdl) imag(dsphdl)]);
err_vec = ref_vec - dsphdl_vec;
max_err = max(abs(err_vec));
max_ref = max(abs(ref_vec));

figure;
c = get(groot,'defaultAxesColorOrder');
% Plot real and imaginary parts separately
tag = {'(Real)','(Imag)'};
msg = sprintf('\nMaximum error for %s out of %d values\n',label,length(dsphdl));
for n = 1:size(ref_vec,2)
    msg = [msg sprintf('%s %d (absolute), %d (percentage)\n',tag{n},max_err(n),max_err(n)/max_ref(n)*100)];
    row_num = size(ref_vec,2);
    col_num = 1;
    plot_num = n;
    subplot(row_num,col_num,plot_num);
    plot(ref_vec(:,n),'Color',c(3,:));
    hold on
    plot(dsphdl_vec(:,n),'Color',c(1,:));
    plot(err_vec(:,n),'Color',c(2,:));
    legend('Reference','HDL Algorithm','Error')
    title(sprintf('%s %s\n max error = %.3d',label,tag{n},max_err(n)));
    hold off
end

Figure contains 2 axes objects. Axes object 1 with title dsp.Channelizer vs dsphdl.Channelizer with Phase Preservation (Real) max error = 4.441e-16 contains 3 objects of type line. These objects represent Reference, HDL Algorithm, Error. Axes object 2 with title dsp.Channelizer vs dsphdl.Channelizer with Phase Preservation (Imag) max error = 4.441e-16 contains 3 objects of type line. These objects represent Reference, HDL Algorithm, Error.

fprintf(msg);
Maximum error for dsp.Channelizer vs dsphdl.Channelizer with Phase Preservation out of 800 values
(Real) 4.440892e-16 (absolute), 2.928324e-14 (percentage)
(Imag) 4.440892e-16 (absolute), 2.857653e-14 (percentage)

The latency of the dsphdl.Channelizer object varies with the FFT length, filter structure, vector size, and input type. Use the getLatency function to find the latency of a particular configuration. The latency is measured as the number of cycles between the first valid input and the first valid output, assuming that the input is contiguous. The number of filter coefficients does not affect the latency. Setting the output size equal to the input size reduces the latency because the samples are not saved and reordered.

Create a dsphdl.Channelizer object with filter structure set to direct form transposed and request the latency.

channelize = dsphdl.Channelizer(NumFrequencyBands=512, ...
    FilterStructure='Direct form transposed');
L512 = getLatency(channelize)
L512 = 
1118

Request hypothetical latency information about a similar object with a different number of frequency bands (FFT length). The properties of the original object do not change.

L256 = getLatency(channelize,256)
L256 = 
592
N = channelize.NumFrequencyBands
N = 
512

Request hypothetical latency information of a similar object that accepts eight-sample vector input.

L256v8 = getLatency(channelize,256,8)
L256v8 = 
132

Enable scaling at each stage of the FFT. The latency does not change.

channelize.Normalize = true;
L512n = getLatency(channelize)
L512n = 
1118

Request the same output size and order as the input data. The latency decreases because the object does not need to store and reorder the data before output. The default input size is scalar.

channelize.OutputSize = 'Same as input size';
L512r = getLatency(channelize)
L512r = 
1084

Check the latency of a vector input implementation where the input and output are the same size. Specify the current value of the FFT length and a vector size of 8 samples. The latency decreases because the object computes results in parallel when the input is a vector.

L512rv8 = getLatency(channelize,channelize.NumFrequencyBands,8)
L512rv8 = 
218

Check the latency of a vector input implementation where the input type is complex. Specify the current value of the FFT length and a vector size of 16 samples.

L512rv16i = getLatency(channelize,channelize.NumFrequencyBands,16,true)
L512rv16i = 
152

Algorithms

expand all

This object implements the algorithm described on the Channelizer block reference page.

Note

The output of the dsphdl.Channelizer object does not match the output from the dsp.Channelizer object sample-for-sample. This mismatch is because the objects apply the input samples to the subfilters in different orders. The dsphdl.Channelizer object applies input X(0) to subfilter EM-1(z), X(1) to subfilter EM-2(z), ..., X(M-1) to subfilter E0(z). The channels detected by both objects match, when analyzed over multiple frames.

Extended Capabilities

expand all

Version History

Introduced in R2017a

expand all