Main Content

Sample Rate Conversion for an LTE Receiver

This example shows how to design and implement sample rate conversion for an LTE receiver front end. The model is compatible with the Wireless HDL Toolbox™ receiver reference applications, and supports HDL code generation with HDL Coder™.

Introduction

The LTE HDL Cell Search, LTE HDL MIB Recovery, and LTE HDL SIB1 Recovery reference applications require an input sampling rate of 30.72 Msps. In practice, the sampling rate presented to hardware may differ from this, for example due to choice of components or system design decisions. Therefore, sample rate conversion may be required to integrate these reference applications into a larger system. The model shown in this example converts from 125 Msps to 30.72 Msps using two FIR Decimation filters and a Farrow rate converter. The rate change from 125 Msps to 30.72 Msps was deliberately chosen because it is not trivial to implement yet represents an example of the type of rate change often required in a radio receiver.

Sample Rate Converter Design Overview

The conversion from 125 Msps to 30.72 Msps corresponds to a rate change factor of 0.24576. This is implemented with the filter chain shown. First, the input signal is decimated by two (i.e. a rate change of 1/2) using a halfband filter. Next, a Farrow rate converter is used to make a fine adjustment to the sample rate by a factor of 1565/1592 = 0.983. Last, a decimating FIR filter implements the final decimate-by-two stage.

The reasons behind this choice of filters is as follows:

  1. The first filter stage can be done efficiently with a halfband filter. The subsequent filter then has two cycles available per input sample to implement resource sharing.

  2. A Farrow rate converter was chosen to implement the fine adjustment stage due to the high rate change resolution achievable with this approach. This leads to a flexible design which can be readily modified to implement other rate changes.

  3. Farrow rate converters are expensive in terms of multipliers. This block was placed second in the filter chain, as this option resulted in the least resource utilization while still meeting the specification. If the filter was first in the chain, the width of its transition band could have been relaxed, leading to a shorter filter, however no resource sharing would have been possible. If the filter was last in the chain, it would have required a narrower transition band leading to a longer filter, however more resource sharing would have been possible.

  4. It then follows that the last stage is a decimating FIR filter, which can use resource sharing by a factor of two.

In this example, the clock rate is 125 MHz and the input sampling rate is 125 Msps, therefore no resource sharing is implemented in the first filter stage. Stages two and three have a minimum of two cycles per sample available, therefore resource sharing by a factor of two is implemented in parts of the Farrow Rate Converter, and in the final FIR decimation stage. This approximately halves the number of multipliers required to implement these stages compared to a fully parallel implementation.

All of the filter stages have valid input and output signals. These signals are used to represent different sampling rates throughout the filter chain. It's essential for the Farrow rate converter to have a valid output signal because it implements a non-integer rate change. However providing a valid input signal at the first stage means that it is not necessary to pass new data into the sample rate converter on every cycle. This is relevant in scenarios where the hardware clock rate is greater than the input sampling rate.

Top Level Parameters

Configure the top level parameters of the sample rate converter. FsADC is the input rate, while FsLTERx is the output rate; that is, the input to the LTE receiver. Fpass is the passband cut-off frequency and is set to 10 MHz to accommodate the maximum possible LTE bandwidth of 20 MHz. Fstop is set to the Nyquist rate, however can be adjusted if more out-of-band signal rejection is required. Ast is the stopband attenuation in dBs, and Ap is the desired amount of passband ripple.

FsADC   = 125e6;
FsLTERx = 30.72e6;
Fpass   = 10e6;
Fstop   = FsLTERx/2;
Ast     = 60;
Ap      = 0.1;

Farrow Rate Converter

The Farrow rate converter consists of (i) a fractional delay filter implemented using a Farrow structure and (ii) control logic to determine when to generate output samples, and with which sampling phase. In this example, the Farrow fractional delay filter approximates the impulse response of a custom prototype filter using a set of 3rd order polynomials. The prototype filter is designed taking the signal bandwidth and output sampling rate into account, allowing the filter length to be minimized while avoiding aliasing within the signal of interest. The Farrow filter structure is the same as that used in the dsp.VariableIntegerDelay (DSP System Toolbox) and dsp.FarrowRateConverter (DSP System Toolbox) System objects. Note that the System objects were not used here as they don't support HDL code generation from Simulink.

Define the key parameters of the Farrow rate converter. numTaps is the number of taps in each fixed-coefficient FIR of the farrow structure. It is also the number of polynomials used in the approximation. FsIn and FsOut are the input and output rates respectively. Fsig is the bandwidth of the signal of interest. The filter is designed to avoid aliasing within this region. sps is the number of samples per section (also known as the oversampling factor) used while designing the prototype filter.

farrow.numTaps = 6;
farrow.FsIn    = FsADC/2;
farrow.FsOut   = 2*FsLTERx;
farrow.Fsig    = Fpass;
farrow.sps     = 16;

Design the prototype filter, and approximate it with a set of polynomials. A helper class called FarrowDesignUtils contains a set of methods which are used to design and analyze the fractional delay filter. These methods will not be discussed in detail. Refer to the source code for more information.

farrow.prototype   = FarrowDesignUtils.designFilterPrototype(farrow);
farrow.polynomials = FarrowDesignUtils.generatePolynomialCoefficients(farrow);

Evaluate the impulse response of the approximation, and compare it to the prototype filter. For visualization purposes, the reconstruction is performed with 100 samples per section in contrast to the prototype filter, which only contains 16 samples per section.

[protoInterp,ta] = FarrowDesignUtils.evaluateApproximation(farrow.polynomials,100);

srcPlots.FarrowIR = figure;
tp = ((0:length(farrow.prototype)-1) - floor(length(farrow.prototype)/2))/farrow.sps;
stem(tp,farrow.prototype,'.'); hold on;
plot(ta,protoInterp);

SRCTestUtils.setPlotNameAndTitle('Farrow Impulse Response');
ylabel('p[k]');
xlabel('Discrete time index, k');
legend('Prototype filter','Piece-wise polynomial approximation');

Compare the approximation to the prototype filter in the frequency domain. The reconstruction is performed with 16 samples per section to match the sampling rate of the prototype filter and facilitate the comparison. The plot also highlights the spectral components which will alias on top of the signal of interest once it has been converted to the output rate. This shows that no significant aliasing will occur.

protoApprox = FarrowDesignUtils.evaluateApproximation(farrow.polynomials,farrow.sps);

srcPlots.FarrowFreq = figure; clf;

Fsover = farrow.sps  * farrow.FsIn;
Nfft   = 2048;
f      = Fsover*(-Nfft/2:Nfft/2-1)/Nfft;
plot(f/1e6,20*log10(abs(fftshift(fft(farrow.prototype/farrow.sps,Nfft)))),'g'); hold on;
plot(f/1e6,20*log10(abs(fftshift(fft(protoApprox/farrow.sps,Nfft)))),'b');
ax = axis;
axis([ax(1) ax(2) -80 30]);
FarrowDesignUtils.plotSignalImages(farrow.FsOut);

SRCTestUtils.setPlotNameAndTitle('Farrow Frequency Response');
xlabel('Frequency [MHz]');
ylabel('Magnitude [dB]');
legend('Prototype filter','Approximation','Spectral images at FsOut');

Decimating FIR Filters

Design the first and last FIR filter stages. Both filters use 16-bit coefficients. For convenience, the coefficients data type is defined.

FIRCoeffsDT = numerictype(1,16,15);

Halfband Decimator

Design a halfband filter to efficiently decimate the input by 2.

hbParams.FsIn                = FsADC;
hbParams.FsOut               = FsADC/2;
hbParams.TransitionWidth     = hbParams.FsOut - 2*Fpass;
hbParams.StopbandAttenuation = Ast + 10;

hbSpec = fdesign.decimator(2,'halfband',...
    'Tw,Ast',...
    hbParams.TransitionWidth, ...
    hbParams.StopbandAttenuation,...
    hbParams.FsIn);

halfband = design(hbSpec,'SystemObject',true);

halfband.FullPrecisionOverride = false;
halfband.CoefficientsDataType  = 'Custom';
halfband.CustomCoefficientsDataType = numerictype([],...
    FIRCoeffsDT.WordLength,FIRCoeffsDT.FractionLength);

Plot the frequency response of the filter, including the quantized response.

srcPlots.halfband = fvtool(halfband,'arithmetic','fixed');
SRCTestUtils.setPlotNameAndTitle('Halfband FIR');
legend('Quantized filter','Reference filter','Design constraints');

Final FIR Decimator

Design the final decimate-by-2 FIR filtering stage.

finalSpec = fdesign.decimator(2,'lowpass',...
    'Fp,Fst,Ap,Ast',Fpass,Fstop,Ap,Ast,farrow.FsOut);

finalFilt = design(finalSpec,'equiripple','SystemObject',true);

finalFilt.FullPrecisionOverride = false;
finalFilt.CoefficientsDataType  = 'Custom';
finalFilt.CustomCoefficientsDataType = numerictype([],...
    FIRCoeffsDT.WordLength,FIRCoeffsDT.FractionLength);

Plot the frequency response of the filter, including the quantized response.

srcPlots.finalFilt = fvtool(finalFilt,'arithmetic','fixed');
SRCTestUtils.setPlotNameAndTitle('Final Decimating FIR');
legend('Quantized filter','Reference filter','Design constraints');

Simulink HDL Implementation

Open the model and update the diagram. The top level of the model is shown. HDL code can be generated for the Sample Rate Converter subsystem.

stopTime  = 0;
dataIn    = 0;
validIn   = false;
modelName = 'SampleRateConversionHDL';
open_system(modelName);
set_param(modelName,'SimulationCommand','Update');
set_param(modelName, 'Open','on');

As discussed, the sample rate converter contains a halfband filter, a Farrow rate converter and a final FIR decimation stage.

set_param([modelName '/Sample Rate Converter'],'Open','on');

The halfband FIR is implemented using the Discrete FIR Filter HDL Optimized block, and a MATLAB function block to implement decimation by 2. The FIR block uses a transposed filter structure, which optimizes for symmetry and zero coefficients.

set_param([modelName '/Sample Rate Converter/Halfband Filter'],'Open','on');

The Farrow rate converter comprises a Filter Bank of fixed-coefficient FIRs, a Sample Controller for generating the output timing, and a Sum Product Chain to compute the final output samples. The Sample Controller uses a validOut signal to tell the Sum Product Chain when to generate a new output sample. It also passes the new sampling phase as a fraction, rho, where 0 <= rho < 1.

set_param([modelName '/Sample Rate Converter/Farrow Rate Converter'],'Open','on');

The Filter Bank subsystem is implemented with four Discrete FIR Filter HDL Optimized blocks. Each block is configured to share resources according to the Min cycles between valid input samples parameter of the Farrow Fate Converter subsystem, which is set to 2 in this case. The latency of the FIRs may differ from one another due to symmetry and zero coefficient optimization, therefore each filter also has an associated latency matcher (delay) block to compensate for any differences. The additional delay needed to compensate for the latency of each filter is calculated by the getSubFilterMatchingLatencies function. getSubFilterMatchingLatencies is called during model initialization and assigned to a variable called matchLatencies. To see this, edit the Farrow Rate Converter subsystem mask and go to the Initialization tab. In this example, all of the filters have equal latency, therefore all of the latency matcher have a delay of zero. If the Farrow coefficients are changed via the block mask, the FIR latencies may change and the latency matcher blocks will automatically compensate for any differences. Finally all four filter outputs are passed out in a vector.

set_param([modelName '/Sample Rate Converter/Farrow Rate Converter/Filter Bank'],'Open','on');

The Sum Product Chain combines the four FIR outputs with rho to generate output samples according to the Farrow structure.

set_param([modelName '/Sample Rate Converter/Farrow Rate Converter/Sum Product Chain'],'Open','on');

Validation and Verification

An LTE test signal is generated at 125 Msps and passed through the rate converter. An Error Vector Magnitude (EVM) measurement is then performed, confirming that the resampler is suitable for use in an LTE receiver. For reference, three different methods are used to resample the signal to 30.72 Msps and their EVM results compared. The three methods are:

  1. The MATLAB resample function.

  2. A MATLAB model of the rate converter.

  3. The Simulink HDL model of the rate converter.

In addition, to confirm correct operation of the HDL implementation, the root-mean-square error between the outputs of the MATLAB and Simulink rate converter models is computed.

Generate a 20 MHz LTE test signal sampled at 125 Msps.

rng(0);
enb              = lteRMCDL('R.9');
enb.TotSubframes = 2;
[tx, ~, sigInfo] = lteRMCDLTool(enb,randi([0 1],1000,1));
dataIn = resample(tx,FsADC,sigInfo.SamplingRate);
dataIn  = 0.95 * dataIn / max(abs(dataIn));
validIn = true(size(dataIn));

Use the resample function to resample the received signal from the ADC rate to 30.72 Msps. This provides a good quality reference to compare to the rate converter.

resampleOut = resample(dataIn,FsLTERx,FsADC);

Pass the signal through a MATLAB model of the rate converter.

halfbandOut       = halfband(dataIn);
farrowOut         = FarrowDesignUtils.convertSampleRate(farrow,halfbandOut);
farrowOut         = farrowOut(1:length(farrowOut)-mod(length(farrowOut),2));
floatResamplerOut = finalFilt(farrowOut);

Pass the signal through the fixed-point Simulink HDL implementation model.

stopTime       = (length(dataIn)+1000)/FsADC;
simOut         = sim(modelName);
fiResamplerOut = simOut.dataOut(simOut.validOut);
fiResamplerOut = fiResamplerOut(1:length(floatResamplerOut));

Plot validIn and validOut to show the overall rate change of the sample rate converter. validIn is always HIGH, whereas validOut is HIGH about a quarter (0.24576%) of the time.

srcPlots.validSignals = figure;
Ns = 300;
validInSlice = validIn(1:Ns);
validOutSlice = simOut.validOut(1:Ns);
subplot(2,1,1);
plot((0:Ns-1)/FsADC,validInSlice);
axis([0 (Ns-1)/FsADC -0.1 1.2]);
ylabel('validIn');
xlabel('time');
subplot(2,1,2);
plot((0:Ns-1)/FsADC,validOutSlice);
axis([0 (Ns-1)/FsADC -0.1 1.2]);
ylabel('validOut');
xlabel('time');

Compute the root mean square error between the outputs of the MATLAB and Simulink models of the rate converter

e = floatResamplerOut-fiResamplerOut;
rootMeanSquareError = sqrt((e' * e)/length(e));
disp(['Root-mean-square error: ' num2str(rootMeanSquareError)]);
Root-mean-square error: 9.4529e-05

Measure the EVM of all three resampling methods.

results.resampleEVM                    = SRCTestUtils.MeasureEVM(sigInfo,resampleOut,FsLTERx);
results.floatPointSRCEVM               = SRCTestUtils.MeasureEVM(sigInfo,floatResamplerOut,FsLTERx);
[results.fixedPointSRCEVM,fiEqSymbols] = SRCTestUtils.MeasureEVM(sigInfo,fiResamplerOut,FsLTERx);

disp('LTE Error Vector Magnitude (EVM) Measurements');
disp(['     resample function RMS EVM: '  num2str(results.resampleEVM.RMS*100,3) ' %']);
disp(['    resample function Peak EVM: ' num2str(results.resampleEVM.Peak*100,3) ' %']);
disp(['    floating point SRC RMS EVM: '  num2str(results.floatPointSRCEVM.RMS*100,3) ' %']);
disp(['   floating point SRC Peak EVM: ' num2str(results.floatPointSRCEVM.Peak*100,3) ' %']);
disp(['   fixed point HDL SRC RMS EVM: '  num2str(results.fixedPointSRCEVM.RMS*100,3) ' %']);
disp(['  fixed point HDL SRC Peak EVM: ' num2str(results.fixedPointSRCEVM.Peak*100,3) ' %']);
LTE Error Vector Magnitude (EVM) Measurements
     resample function RMS EVM: 0.0138 %
    resample function Peak EVM: 0.0248 %
    floating point SRC RMS EVM: 0.0403 %
   floating point SRC Peak EVM: 0.11 %
   fixed point HDL SRC RMS EVM: 0.0486 %
  fixed point HDL SRC Peak EVM: 0.144 %

Confirm that the signal quality is high by plotting the equalized pilot symbols from the EVM measurement of the HDL implementation. Note that almost no blurring of the constellation points is visible.

srcPlots.scatterPlot = scatterplot(fiEqSymbols);
SRCTestUtils.setPlotNameAndTitle('Equalized Cell RS');

HDL Code Generation and FPGA Implementation

To generate the HDL code for this example you must have an HDL Coder™ license. Use the makehdl and makehdltb commands to generate HDL code and an HDL testbench for the Sample Rate Converter subsystem. The resulting HDL code was synthesized on a Xilinx® Zynq®-7000 ZC706 evaluation board. The post place and route resource utilization results are shown in the table. The design met timing with a clock frequency of 200 MHz.

disp(table(...
    categorical({'LUT'; 'LUTRAM'; 'FF'; 'BRAM'; 'DSP'}),...
    categorical({'1553'; '46'; '5629'; '0'; '60'}),...
    'VariableNames',{'Resource','Usage'}));
    Resource    Usage
    ________    _____

     LUT        1553 
     LUTRAM     46   
     FF         5629 
     BRAM       0    
     DSP        60