このページは前リリースの情報です。該当の英語のページはこのリリースで削除されています。

LTE 用のデジタル ダウン コンバーターの HDL 実装

この例では、LTE などの無線通信用途のためにデジタル ダウン コンバーター (DDC) を設計して、HDL Coder™ で HDL コードを生成する方法を示します。

はじめに

DDC は、無線周波数 (RF) または中間周波数 (IF) 信号をベースバンドに変換するためにデジタル通信受信機で幅広く使用されています。DDC は、低い周波数に信号をシフトしてサンプリング レートを削減することにより、以後の処理段階を容易にします。ここで示す DDC は、4 段階のフィルター チェーンを使用して、複雑な周波数変換を実行してからサンプルレートを変換します。この例では、最初に浮動小数点で DSP System Toolbox™ の関数を使用して DDC を設計します。次に、各段階を固定小数点に変換してから、合成可能な HDL コードを生成する Simulink® モデルで使用します。2 つのテスト信号を使用して、DDC の動作の例示と検証を行います。

  1. 32 MHz の IF 搬送波に変調された正弦波。

  2. 32 MHz の IF 搬送波に変調された、帯域幅が 1.4 MHz の LTE ダウンリンク信号。

この例では、浮動小数点と固定小数点の DDC の出力における信号の品質を評価して、この 2 つを比較します。最後に、FPGA の実装結果を示します。

メモ: この例では、スティミュラスを生成する関数と DDC の出力を分析する関数が含まれているヘルパー クラスである DDCTestUtils を使用します。詳細については、DDCTestUtils.m ファイルを参照してください。

DDC の構成

DDC は、数値制御発振器 (NCO)、混合器および間引きフィルター チェーンから構成されます。フィルター チェーンは、CIC 間引き、CIC ゲイン修正、CIC 補正間引き (FIR)、ハーフバンド FIR 間引きおよび最終 FIR 間引きから構成されます。このフィルター チェーンの全体的な応答は、同じ仕様の信号間引きフィルターの応答と同等です。しかし、フィルターを複数の間引き段に分割すると、より効率的な設計になり、使用するハードウェア リソースが少なくなります。CIC 間引きは初期間引き係数が大きいので、以後のフィルターはより低いレートで動作できます。CIC 補正間引きは、サンプルの半分を間引きながら CIC の低下を補正することにより、スペクトル応答を向上させます。ハーフバンドは中間的な間引きであり、最終間引きは DDC の正確な Fpass および Fstop 特性を実装します。サンプリング レートが低くなるので、チェーンの終わりに近いフィルターほど、乗算器を共有することによりリソースの使用を最適化できます。DDC のブロック線図を以下に示します。

DDC への入力は 122.88 Msps でサンプリングされますが、出力のサンプルレートは 1.92 Msps です。したがって、全体的な間引き係数は 64 です。1.92 Msps は、セル探索と MIB (マスター情報ブロック) リカバリを実行するために LTE 受信機で使用される一般的なサンプリング レートです。このため、DDC フィルターはこの用途に合わせて設計されています。DDC は、122.88 MHz のクロック レートで動作するように最適化されています。

DDC 設計

この節では、MATLAB® の浮動小数点演算とフィルター設計関数を使用して DDC を設計する方法について説明します。

DDC のパラメーター

必要な DDC の応答は、入力サンプリング レート、搬送周波数およびフィルターの特性によって規定されます。この必要なフィルター応答を変更すると、Simulink モデルでフィルター ブロックの HDL ブロック プロパティを変更することが必要になる可能性があります。HDL ブロック プロパティについては、この例で後述します。

FsIn  = 122.88e6;   % Sampling rate at input to DDC
Fc    = 32e6;	    % Carrier frequency
Fpass = 540e3;      % Passband frequency, equivalent to 36x15kHz LTE subcarriers
Fstop = 700e3;      % Stopband frequency
Ap    = 0.1;        % Passband ripple
Ast   = 60;         % Stopband attenuation

この節の残りの部分では、各フィルターの設計方法を順番に示します。

カスケード接続積分器櫛形 (CIC) 間引き

最初のフィルター段は、CIC 間引きとして実装されています。これは、大きい間引き係数を効率的に実装できるからです。CIC フィルターの応答は移動平均フィルターのカスケードに似ていますが、乗算も除算も使用しません。この結果、CIC フィルターの DC ゲインは大きくなります。

cicParams.DecimationFactor  = 8;
cicParams.DifferentialDelay = 1;
cicParams.NumSections       = 3;
cicParams.FsOut             = FsIn/cicParams.DecimationFactor;

cicFilt = dsp.CICDecimator(cicParams.DecimationFactor,...
    cicParams.DifferentialDelay,cicParams.NumSections) %#ok<*NOPTS>

cicGain = gain(cicFilt)
cicFilt = 

  dsp.CICDecimator with properties:

      DecimationFactor: 8
     DifferentialDelay: 1
           NumSections: 3
    FixedPointDataType: 'Full precision'


cicGain =

   512

CIC のゲインは 2 のべき乗なので、シフト演算によりハードウェアで容易に修正できます。解析用に、ゲイン修正は MATLAB では 1 タップの dsp.FIRFilter System object によって表されます。

cicGainCorr = dsp.FIRFilter('Numerator',1/cicGain)
cicGainCorr = 

  dsp.FIRFilter with properties:

            Structure: 'Direct form'
      NumeratorSource: 'Property'
            Numerator: 0.0020
    InitialConditions: 0

  Use get to show all properties

fvtool を使用して、ゲイン修正がある場合とない場合の CIC フィルターの振幅応答を表示します。解析用に、CIC フィルターとゲイン修正フィルターを dsp.FilterCascade System object に結合します。CIC フィルターは内部的に常に固定小数点演算を使用するので、fvtool は量子化された応答と量子化されていない応答の両方をプロットします。

ddcPlots.cicDecim = fvtool(...
    cicFilt,...
    dsp.FilterCascade(cicFilt,cicGainCorr), ...
    'Fs',[FsIn,FsIn]);

DDCTestUtils.setPlotNameAndTitle('CIC Decimator');

legend(...
    'CIC No Correction: Quantized', ...
    'CIC No Correction: Reference', ...
    'CIC With Gain Correction: Quantized', ...
    'CIC With gain correction: Reference');

CIC 低下補正フィルター

CIC フィルターの振幅応答は通過帯域領域で大幅に "低下" するので、FIR ベースの低下補正フィルターを使用して通過帯域応答をフラット化します。低下補償器は、CIC 間引きと同じパラメーターを使用して設定されています。このフィルターはサンプル数を半分にする間引きも実装するので、帯域制限特性を指定します。フィルターの必要条件を指定してから、関数 design を使用して、これらの特性があるフィルターの System object を取得します。

compParams.R     = 2;                            % CIC compensation decimation factor
compParams.Fpass = Fstop;                        % CIC comp passband frequency
compParams.FsOut = cicParams.FsOut/compParams.R; % New sampling rate
compParams.Fstop = compParams.FsOut - Fstop;     % CIC comp stopband frequency
compParams.Ap    = Ap;                           % Same Ap as overall filter
compParams.Ast   = Ast;                          % Same Ast as overall filter

compSpec = fdesign.decimator(compParams.R,'ciccomp',...
    cicParams.DifferentialDelay,...
    cicParams.NumSections,...
    cicParams.DecimationFactor,...
    'Fp,Fst,Ap,Ast',...
    compParams.Fpass,compParams.Fstop,compParams.Ap,compParams.Ast,...
    cicParams.FsOut);


compFilt = design(compSpec,'SystemObject',true)
compFilt = 

  dsp.FIRDecimator with properties:

     NumeratorSource: 'Property'
           Numerator: [-0.0398 -0.0126 0.2901 0.5258 0.2901 -0.0126 -0.0398]
    DecimationFactor: 2
           Structure: 'Direct form'

  Use get to show all properties

CIC フィルター (ゲイン修正あり) の応答と低下補正の応答を結合してプロットします。

ddcPlots.cicComp = fvtool(...
    dsp.FilterCascade(cicFilt,cicGainCorr,compFilt), ...
    'Fs',FsIn,'Legend','off');

DDCTestUtils.setPlotNameAndTitle('CIC Decim + Droop Comp');

ハーフバンド間引き

ハーフバンド フィルターは、サンプルの半分を効率的に間引きます。ハーフバンド フィルターは、係数のほぼ半分がゼロに等しいので効率的です。

hbParams.FsOut               = compParams.FsOut/2;
hbParams.TransitionWidth     = hbParams.FsOut - 2*Fstop;
hbParams.StopbandAttenuation = Ast;

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

hbFilt = design(hbSpec,'SystemObject',true)
hbFilt = 

  dsp.FIRDecimator with properties:

     NumeratorSource: 'Property'
           Numerator: [1x11 double]
    DecimationFactor: 2
           Structure: 'Direct form'

  Use get to show all properties

ハーフバンド フィルターの出力までの DDC の応答をプロットします。

ddcPlots.halfbandFIR = fvtool(...
    dsp.FilterCascade(cicFilt,cicGainCorr,compFilt,hbFilt), ...
    'Fs',FsIn,'Legend','off');

DDCTestUtils.setPlotNameAndTitle('CIC Decim + Droop Comp + HB FIR');

最終 FIR 間引き

最終 FIR は、DDC の通過帯域と阻止帯域の詳細な特性を実装します。このフィルターには先行する FIR フィルターより多くの係数がありますが、低いサンプリング レートで動作するので、共有できるハードウェアのリソースが多くなります。

% Add 3dB of headroom to the stopband attenuation so that the DDC still meets the
% spec after fixed-point quantization. This value was determined by trial and error
% with |fvtool|.
finalSpec = fdesign.decimator(2,'lowpass',...
    'Fp,Fst,Ap,Ast',Fpass,Fstop,Ap,Ast+3,hbParams.FsOut);

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

  dsp.FIRDecimator with properties:

     NumeratorSource: 'Property'
           Numerator: [1x70 double]
    DecimationFactor: 2
           Structure: 'Direct form'

  Use get to show all properties

DDC の全体的な振幅応答を可視化します。

ddcFilterChain           = dsp.FilterCascade(cicFilt,cicGainCorr,compFilt,hbFilt,finalFilt);
ddcPlots.overallResponse = fvtool(ddcFilterChain,'Fs',FsIn,'Legend','off');
DDCTestUtils.setPlotNameAndTitle('Overall DDC Filter Chain');

固定小数点への変換

浮動小数点 DDC フィルター チェーンの周波数応答が、仕様を満たすようになりました。次に、各フィルター段を量子化して固定小数点型を使用し、これらを解析してフィルター チェーンが引き続き仕様を満たすことを確認します。

フィルターの量子化

この例では、仕様を十分に満たす 16 ビットの係数を使用します。18 ビット未満の係数を使用すると、FPGA の実装に必要な DSP ブロックの数が最小限になります。DDC フィルター チェーンへの入力は 16 ビット データであり、15 ビットが小数ビットです。フィルターの出力は 18 ビット値です。これにより、中間信号のヘッドルームと精度が向上します。

CIC 間引きについて固定小数点データ型オプションとして Minimum section word lengths を選択すると、出力の語長および他の CIC パラメーターに基づいて内部的な語長が自動的に最適化されます。

cicFilt.FixedPointDataType = 'Minimum section word lengths';
cicFilt.OutputWordLength   = 18;

FIR ベースの System object とゲイン修正の固定小数点パラメーターを設定します。明示的には示されていませんが、この System object は RoundingMethodOverflowAction の既定設定 (それぞれ FloorWrap) を使用します。

% CIC Gain Correction
cicGainCorr.FullPrecisionOverride      = false;
cicGainCorr.CoefficientsDataType       = 'Custom';
cicGainCorr.CustomCoefficientsDataType = numerictype(fi(cicGainCorr.Numerator,1,16));
cicGainCorr.OutputDataType             = 'Custom';
cicGainCorr.CustomOutputDataType       = numerictype(1,18,16);

% CIC Droop Compensation
compFilt.FullPrecisionOverride      = false;
compFilt.CoefficientsDataType       = 'Custom';
compFilt.CustomCoefficientsDataType = numerictype([],16,15);
compFilt.ProductDataType            = 'Full precision';
compFilt.AccumulatorDataType        = 'Full precision';
compFilt.OutputDataType             = 'Custom';
compFilt.CustomOutputDataType       = numerictype([],18,16);

% Halfband
hbFilt.FullPrecisionOverride      = false;
hbFilt.CoefficientsDataType       = 'Custom';
hbFilt.CustomCoefficientsDataType = numerictype([],16,15);
hbFilt.ProductDataType            = 'Full precision';
hbFilt.AccumulatorDataType        = 'Full precision';
hbFilt.OutputDataType             = 'Custom';
hbFilt.CustomOutputDataType       = numerictype([],18,16);

% FIR
finalFilt.FullPrecisionOverride      = false;
finalFilt.CoefficientsDataType       = 'Custom';
finalFilt.CustomCoefficientsDataType = numerictype([],16,15);
finalFilt.ProductDataType            = 'Full precision';
finalFilt.AccumulatorDataType        = 'Full precision';
finalFilt.OutputDataType             = 'Custom';
finalFilt.CustomOutputDataType       = numerictype([],18,16);

固定小数点の解析

fvtool で量子化の効果を調べます。フィルターは、個別でもカスケード接続した状態でも解析できます。fvtool は、量子化された応答と量子化されていない応答 (リファレンス) を重ねて表示します。たとえば、最終 FIR フィルター段を量子化した効果は次のようになります。

ddcPlots.quantizedFIR = fvtool(finalFilt,'Fs',hbParams.FsOut,'arithmetic','fixed');
DDCTestUtils.setPlotNameAndTitle('Quantized Final Filter');

ddcFilterChain カスケード オブジェクトを再定義して、各フィルターの固定小数点プロパティを含めます。次に、fvtool を使用してフィルター チェーン全体を解析し、量子化された DDC が引き続き仕様を満たすことを確認します。

ddcFilterChain = dsp.FilterCascade(cicFilt,cicGainCorr,compFilt,hbFilt,finalFilt);
ddcPlots.quantizedDDCResponse = fvtool(ddcFilterChain,'Fs',FsIn,'Arithmetic','fixed');
DDCTestUtils.setPlotNameAndTitle('Quantized DDC Filter Chain');
legend(...
    'DDC filter chain: Quantized', ...
    'DDC filter chain: Reference');

HDL 用に最適化された Simulink モデル

設計フローの次のステップでは、HDL Coder 互換ブロックを使用して Simulink で DDC を実装します。

モデル コンフィギュレーション

このモデルでは、MATLAB ワークスペースの変数を使用してブロックを設定します。既に定義されているフィルター チェーンの変数を使用します。次に、数値制御発振器 (NCO) のパラメーターと入力信号を定義します。これらのパラメーターを使用して NCO ブロックを設定します。

目的の周波数分解能を指定します。目的の分解能を達成するために必要なアキュムレータのビット数を計算し、量子化されたアキュムレータのビット数を定義します。量子化されたアキュムレータの出力を使用して、NCO 内の正弦ルックアップ テーブルのアドレスを指定します。さらに、指定された搬送周波数を生成するために必要な位相増分を計算します。これらのアキュムレータのビットに位相ディザーを適用します。これらのビットは量子化時に除去されます。

nco.Fd = 1;
nco.AccWL          = nextpow2(FsIn/nco.Fd) + 1;
nco.QuantAccWL     = 12;
nco.PhaseInc       = round((-Fc * 2^nco.AccWL)/FsIn);
nco.NumDitherBits  = nco.AccWL - nco.QuantAccWL;

DDC への入力は ddcIn に由来します。ここでは、モデルでデータ型を計算できるようにするため、ddcIn にダミー値を割り当てます。テスト時に、ddcIn は入力データをモデルに提供します。

ddcIn = 0; %#ok<NASGU>

モデルの構造

DDC の Simulink モデルの最上位レベルを示します。このモデルでは、Signal From Workspace ブロックを使用して ddcIn を MATLAB ワークスペースからインポートし、16 ビットに変換してから DDC に適用します。HDL コードは、HDL_DDC サブシステムから生成できます。

modelName = 'DDCHDLImplementation';
open_system(modelName);
set_param(modelName,'SimulationCommand','Update');
set_param(modelName, 'Open','on');

DDC の実装は、HDL_DDC サブシステムの内部にあります。NCO HDL Optimized ブロックは、搬送周波数で複素フェーザを生成します。この信号は混合器に送られ、入力信号と乗算されます。混合器の出力はフィルター チェーンに供給され、1.92 Msps に間引かれます。

set_param([modelName '/HDL_DDC'],'Open','on');

NCO ブロックのパラメーター

NCO ブロックは、構造体 nco で定義されているパラメーターを使用して設定されます。このブロックのパラメーター ダイアログのタブを両方とも示します。

CIC ゲイン修正

CIC ゲイン修正では、CIC の出力を 512 で除算します。これは、右に 9 ビットだけシフトすることと同じです。ゲイン修正の入力と出力のビット数はどちらも 18 ビットなので、このシフトはデータ型を次のように再解釈するだけで実装できます。

set_param([modelName '/HDL_DDC/CIC Gain Correction'],'Open','on');

フィルター ブロックのパラメーター

すべてのフィルターは、対応する System object のプロパティを継承するように設定されます。各ブロックには、生成される HDL コードの最適化に使用される一連の HDL プロパティもあります。特に、CIC 補正、ハーフバンドおよび最終 FIR フィルターの各ブロックは、それぞれクロック レート (Fclk) の 1/8、1/16 および 1/32 のサンプリング レートで動作します。これらのブロックでは、シリアル化手法 (リソースの共有) を使用してハードウェア リソースの使用率を最小化します。たとえば、Final Decimation ブロックへの入力は Fclk/32 でサンプリングされるので、32 クロック サイクルを各入力サンプルの処理に使用できます。DDC 用の HDL コードを生成すると、HDL Coder はフィルター ブロックに使用できる SerialPartition のすべてのオプションを係数に基づいてリストします。ベクトル SerialPartition の最大値は、フィルターの共有係数を表します。Final Decimation ブロックでは、SerialPartition[32 1] に設定されているので、32 クロック サイクルすべてを利用できます。詳細については、SerialPartition (HDL Coder)およびHDL フィルター アーキテクチャ (HDL Coder)を参照してください。

搬送波への正弦波の変調によるテストと検証

DDC をテストするため、40 kHz の正弦波を搬送周波数に変調して DDC を通過させます。そして、生成されたトーンのスプリアス フリー ダイナミック レンジ (SFDR) と NCO の出力の SFDR を測定します。

% Initialize random seed before executing any simulations.
rng(0);

% Generate a 40kHz test tone, modulated onto the carrier.
ddcIn = DDCTestUtils.GenerateTestTone(40e3,Fc);

% Demodulate the test signal with the floating point DDC.
ddcOut = DDCTestUtils.DownConvert(ddcIn,FsIn,Fc,ddcFilterChain);
release(ddcFilterChain);

% Demodulate the test signal by executing the fixed-point Simulink model with the sim function.
simOut = sim(modelName);

% Measure the SFDR of the NCO, floating point DDC and the fixed-point DDC outputs.
results.sfdrNCO      = sfdr(real(simOut.ncoOut),FsIn/64);
results.sfdrFloatDDC = sfdr(real(ddcOut),FsIn/64);
results.sfdrFixedDDC = sfdr(real(simOut.ddcOut),FsIn/64);

disp('Spurious Free Dynamic Range (SFDR) Measurements');
disp(['   Floating point DDC SFDR: ',num2str(results.sfdrFloatDDC) ' dB']);
disp(['   Fixed-point NCO SFDR: ',num2str(results.sfdrNCO) ' dB']);
disp(['   Fixed-point DDC SFDR: ',num2str(results.sfdrFixedDDC) ' dB']);
fprintf(newline);

% Plot the SFDR of the NCO and fixed-point DDC outputs.
ddcPlots.ncoOutSDFR = figure;
sfdr(real(simOut.ncoOut),FsIn/64);
DDCTestUtils.setPlotNameAndTitle(['NCO Out ' get(gca,'Title').String]);

ddcPlots.ddcOutSDFR = figure;
sfdr(real(simOut.ddcOut),FsIn/64);
DDCTestUtils.setPlotNameAndTitle(['Fixed-Point DDC Out ' get(gca,'Title').String]);
Spurious Free Dynamic Range (SFDR) Measurements
   Floating point DDC SFDR: 291.3483 dB
   Fixed-point NCO SFDR: 83.0249 dB
   Fixed-point DDC SFDR: 89.9658 dB

LTE のテストと検証

LTE のテスト信号を使用して、より厳密に DDC をテストします。LTE Toolbox™ を使用して、標準準拠の LTE 波形を生成します。この波形を搬送波に変調してから、DDC でダウン コンバートします。LTE Toolbox を使用して、生成された信号のエラー ベクトル振幅 (EVM) を測定します。

% Only execute this test if an LTE Toolbox license is present.
if license('test','LTE_Toolbox')

    % Generate a modulated LTE test signal with LTE Toolbox
    [ddcIn, sigInfo] = DDCTestUtils.GenerateLTETestSignal(Fc);

    % Downconvert with a MATLAB Floating Point Model
    ddcOut = DDCTestUtils.DownConvert(ddcIn,FsIn,Fc,ddcFilterChain);
    release(ddcFilterChain);

    % Downconvert using Simulink model
    simOut = sim(modelName);

    results.evmFloat = DDCTestUtils.MeasureEVM(sigInfo,ddcOut);
    results.evmFixed = DDCTestUtils.MeasureEVM(sigInfo,simOut.ddcOut);

    disp('LTE Error Vector Magnitude (EVM) Measurements');
    disp(['   Floating point DDC RMS EVM: '  num2str(results.evmFloat.RMS*100,3) '%']);
    disp(['   Floating point DDC Peak EVM: ' num2str(results.evmFloat.Peak*100,3) '%']);
    disp(['   Fixed-point DDC RMS EVM: '     num2str(results.evmFixed.RMS*100,3) '%']);
    disp(['   Fixed-point DDC Peak EVM: '    num2str(results.evmFixed.Peak*100,3) '%']);
    fprintf(newline);

end
LTE Error Vector Magnitude (EVM) Measurements
   Floating point DDC RMS EVM: 0.633%
   Floating point DDC Peak EVM: 2.44%
   Fixed-point DDC RMS EVM: 0.694%
   Fixed-point DDC Peak EVM: 2.5%

HDL コードの生成と FPGA の実装

この例の HDL コードを生成するには、HDL Coder™ のライセンスが必要です。makehdl コマンドと makehdltb コマンドを使用して、HDL_DDC サブシステムの HDL コードと HDL テストベンチを生成します。この DDC は、Xilinx® Zynq®-7000 ZC706 評価ボードで合成されています。配置配線後のリソース使用状況の結果を表に示します。この設計は、180 MHz のクロック周波数でタイミングを満たしました。

T = table(...
    categorical({'LUT'; 'LUTRAM'; 'FF'; 'BRAM'; 'DSP'}),...
    categorical({'2178'; '38'; '4794'; '0.5'; '16'}),...
    'VariableNames',{'Resource','Usage'})
T =

  5x2 table

    Resource    Usage
    ________    _____

     LUT        2178 
     LUTRAM     38   
     FF         4794 
     BRAM       0.5  
     DSP        16