関数のモジュラー HDL コードの生成
この例では、関数を含む MATLAB® コードからモジュラー HDL コードを生成する方法を説明します。
既定では、HDL Coder™ は、最上位の設計関数の本体内で呼び出されるすべての MATLAB 関数をインライン化します。このインライン化の結果として、関数に対する HDL コードを含む単一のファイルが生成されます。モジュラー HDL コードを生成するには、[関数に対してインスタンス化可能なコードを生成] 設定を使用します。この設定を有効にすると、HDL Coder はそれぞれの関数について単一の VHDL® エンティティまたは Verilog® モジュールまたは SystemVerilog モジュールを生成します。
LMS フィルター MATLAB 設計
この例で使用する MATLAB 設計は、LMS (最小平均二乗) フィルターの実装です。LMS フィルターは、ノイズに組み込まれている FIR フィルター信号を特定する適応フィルターのクラスです。MATLAB での LMS フィルター設計実装は、出力信号と目的の信号との差異を低減するよう最適なフィルター係数を計算する最上位の関数 mlhdlc_lms_fcn
で構成されます。
design_name = 'mlhdlc_lms_fcn'; testbench_name = 'mlhdlc_lms_fir_id_tb';
MATLAB 設計を確認します。
open(design_name);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MATLAB Design: Adaptive Noise Canceler algorithm using Least Mean Square % (LMS) filter implemented in MATLAB % % Key Design pattern covered in this example: % (1) Use of function calls % (2) Function inlining vs instantiation knobs available in the coder % (3) Use of system objects in the testbench to stream test vectors into the design %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %#codegen function [filtered_signal, y, fc] = mlhdlc_lms_fcn(input, ... desired, step_size, reset_weights) % 'input' : The signal from Exterior Mic which records the ambient noise. % 'desired': The signal from Pilot's Mic which includes % original music signal and the noise signal % 'err_sig': The difference between the 'desired' and the filtered 'input' % It represents the estimated music signal (output of this block) % % The LMS filter is trying to retrieve the original music signal('err_sig') % from Pilot's Mic by filtering the Exterior Mic's signal and using it to % cancel the noise in Pilot's Mic. The coefficients/weights of the filter % are updated(adapted) in real-time based on 'input' and 'err_sig'. % register filter coefficients persistent filter_coeff; if isempty(filter_coeff) filter_coeff = zeros(1, 40); end % Variable Filter: Call 'mtapped_delay_fcn' function on path to create % 40-step tapped delay delayed_signal = mtapped_delay_fcn(input); % Apply filter coefficients weight_applied = delayed_signal .* filter_coeff; % Call treesum function on matlab path to sum up the results filtered_signal = mtreesum_fcn(weight_applied); % Output estimated Original Signal td = desired; tf = filtered_signal; esig = td - tf; y = esig; % Update Weights: Call 'update_weight_fcn' function on MATLAB path to % calculate the new weights updated_weight = update_weight_fcn(step_size, esig, delayed_signal, ... filter_coeff, reset_weights); % update filter coefficients register filter_coeff = updated_weight; fc = filter_coeff; function y = mtreesum_fcn(u) %Implement the 'sum' function without a for-loop % y = sum(u); % The loop based implementation of 'sum' function is not ideal for % HDL generation and results in a longer critical path. % A tree is more efficient as it results in % delay of log2(N) instead of a delay of N delay % This implementation shows how to explicitly implement the vector sum in % a tree shape to enable hardware optimizations. % The ideal way to code this generically for any length of 'u' is to use % recursion but it is not currently supported by MATLAB Coder % NOTE: To instruct MATLAB Coder to compile an external function, % add the following compilation directive or pragma to the function code %#codegen % This implementation is hardwired for a 40tap filter. level1 = vsum(u); level2 = vsum(level1); level3 = vsum(level2); level4 = vsum(level3); level5 = vsum(level4); level6 = vsum(level5); y = level6; function output = vsum(input) coder.inline('always'); vt = input(1:2:end); for i = int32(1:numel(input)/2) k = int32(i*2); vt(i) = vt(i) + input(k); end output = vt; function tap_delay = mtapped_delay_fcn(input) % The Tapped Delay function delays its input by the specified number % of sample periods, and outputs all the delayed versions in a vector % form. The output includes current input % NOTE: To instruct MATLAB Coder to compile an external function, % add the following compilation directive or pragma to the function code %#codegen persistent u_d; if isempty(u_d) u_d = zeros(1,40); end u_d = [u_d(2:40), input]; tap_delay = u_d; function weights = update_weight_fcn(step_size, err_sig, ... delayed_signal, filter_coeff, reset_weights) % This function updates the adaptive filter weights based on LMS algorithm % Copyright 2007-2022 The MathWorks, Inc. % NOTE: To instruct MATLAB Coder to compile an external function, % add the following compilation directive or pragma to the function code %#codegen step_sig = step_size .* err_sig; correction_factor = delayed_signal .* step_sig; updated_weight = correction_factor + filter_coeff; if reset_weights weights = zeros(1,40); else weights = updated_weight; end
MATLAB 関数はモジュール化されていて、次の関数を使用します。
mtapped_delay_fcn
でベクトル形式の入力信号の遅延バージョンを計算。mtreesum_fcn
でツリー構造で適用された重みの合計を計算。個別の合計は関数vsum
を使用して計算されます。update_weight_fcn
で最小平均二乗アルゴリズムに基づいて更新されたフィルターの重みを計算。
LMS フィルター MATLAB テスト ベンチ
MATLAB テスト ベンチを確認します。
open(testbench_name);
clear ('mlhdlc_lms_fcn'); % returns an adaptive FIR filter System object, HLMS, that computes the % filtered output, filter error, and the filter weights for a given input % and desired signal using the Least MeanSquares (LMS) algorithm. % Copyright 2011-2022 The MathWorks, Inc. stepSize = 0.01; reset_weights =false; hfilt = dsp.FIRFilter; % System to be identified hfilt.Numerator = fir1(10, .25); rng('default'); % always default to known state x = randn(1000,1); % input signal d = step(hfilt, x) + 0.01*randn(1000,1); % desired signal hSrc = dsp.SignalSource(x); hDesiredSrc = dsp.SignalSource(d); hOut = dsp.SignalSink; hErr = dsp.SignalSink; %%%%%%%%%%%%%%%%%%%%%%%%%%%% %Call to the design %%%%%%%%%%%%%%%%%%%%%%%%%%%% while (~isDone(hSrc)) [y, e, w] = mlhdlc_lms_fcn(step(hSrc), step(hDesiredSrc), ... stepSize, reset_weights); step(hOut, y); step(hErr, e); end figure('Name', [mfilename, '_plot']); subplot(2,1,1), plot(1:1000, [d,hOut.Buffer,hErr.Buffer]); title('System Identification of an FIR filter'); legend('Desired', 'Output', 'Error'); xlabel('time index'); ylabel('signal value'); subplot(2,1,2); stem([hfilt.Numerator.', w(end-10:end).']); legend('Actual','Estimated'); xlabel('coefficient #'); ylabel('coefficient value');
MATLAB アルゴリズムのテスト
実行時エラーを避けるために、テスト ベンチを使用して設計をシミュレートします。
mlhdlc_lms_fir_id_tb
HDL Coder プロジェクトの作成
MATLAB 設計から HDL コードを生成するには、次のようにします。
1. HDL Coder プロジェクトを作成します。
coder -hdlcoder -new mlhdlc_fcn_partition
2.mlhdlc_lms_fcn.m
ファイルを [MATLAB 関数] としてプロジェクトに追加し、mlhdlc_lms_fir_id_tb.m
を [MATLAB テスト ベンチ] として追加します。
3.[型の自動定義] をクリックして MATLAB 関数 mlhdlc_lms_fcn
の入力と出力の推奨される型を使用します。
MATLAB HDL Coder プロジェクトの作成と入力に関する詳細なチュートリアルについては、MATLAB から HDL へのワークフロー入門を参照してください。
固定小数点変換と HDL コード生成の実行
[ワークフロー アドバイザー] ボタンをクリックして、ワークフロー アドバイザーを開始します。
[HDL コード生成] タスクを右クリックして [選択したタスクまで実行] を選択します。
単一の HDL ファイル mlhdlc_lms_fcn_FixPt.vhd
が MATLAB 設計に対して生成されます。MATLAB 設計内のすべての関数に対する VHDL コードはこのファイルでインライン化されます。
インスタンス化可能な HDL コードの生成
[詳細設定] タブで [関数に対してインスタンス化可能なコードを生成] チェック ボックスをオンにします。
[実行] ボタンをクリックして [HDL コード生成] タスクを再実行します。
最上位関数と、最上位関数内で呼び出される関数に対して生成されたコードを含む複数の HDL ファイルがあることがわかります。関数のインスタンス化可能なコードの生成も参照してください。
各関数に対するインライン化の制御
場合によっては、補助関数とユーティリティに対する HDL コードをインライン化してインスタンス化することが考えられます。そのような関数のインライン化をローカルに制御するには、MATLAB コードで coder.inline
プラグマを使用します。
生成されたコードで関数をインライン化するには、次のディレクティブをその関数内に配置します。
coder.inline('always')
生成されたコードで関数のインライン化を抑止するには、次のディレクティブをその関数内に配置します。
coder.inline('never')
生成されたコードで関数をインライン化するかどうかをコード ジェネレーターで判別するには、次のディレクティブをその関数内に配置します。
coder.inline('default')
coder.inline
プラグマの使用方法について確認するには、次のように入力します。
help coder.inline
関数からの HDL コードのインスタンス化に関する制限
条件式内の関数呼び出しと for ループは、インライン化され、インスタンス化はされない。
ステートをもつ関数はインライン化される。