Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

最小/最大計測機能を使用したデータ型の設定

この例では、最小/最大ログ作成の MATLAB® コードをインストルメント化し、データ型を推奨するツールを使用することによって、固定小数点データ型を設定する方法を説明します。

使用する関数は以下のとおりです。

テスト対象のユニット

この例で固定小数点に変換する関数は、2 次直接型 2 転置フィルターです。実際の作業では、このサンプル関数を独自の関数で置き換えて以下の手順を実行できます。

function [y,z] = fi_2nd_order_df2t_filter(b,a,x,y,z)
    for i=1:length(x)
        y(i) = b(1)*x(i) + z(1);
        z(1) = b(2)*x(i) + z(2) - a(2) * y(i);
        z(2) = b(3)*x(i)        - a(3) * y(i);
    end
end

MATLAB® 関数をインストルメント化するには、関数がコード生成に適していなければなりません。コード生成の詳細については、buildInstrumentedMex のリファレンス ページを参照してください。buildInstrumentedMex の使用には MATLAB® Coder™ ライセンスは必要ありません。

この関数では、変数 y および z は入力と出力の両方として使用されます。これは以下の理由から重要なパターンです。

  • 関数の外で y および z のデータ型を設定できるので、固定小数点と浮動小数点型の両方で関数を再利用できます。

  • 生成された C コードは、関数の引数リスト内の参照として y および z を作成します。このパターンの詳細については、ドキュメンテーションの「MATLAB® からのコード生成」、「ユーザー ガイド」、「Generating Efficient and Reusable Code」、「Generating Efficient Code」、「Eliminating Redundant Copies of Function Inputs」を参照してください。

この例により実際の作業が妨げられないようにするため、以下のコードを実行してテスト関数を一時ディレクトリにコピーしてください。

tempdirObj = fidemo.fiTempdir('fi_instrumentation_fixed_point_filter_demo');
copyfile(fullfile(matlabroot,'toolbox','fixedpoint','fidemos','+fidemo',...
                  'fi_2nd_order_df2t_filter.m'),'.','f');

以下のコードを実行して現在の状態を取得し、グローバル状態をリセットします。

FIPREF_STATE = get(fipref);
reset(fipref)

設計の要件によって決定されるデータ型

この例では、設計の要件によって入力 x のデータ型が決まります。これらの要件は符号付き 16 ビットの非整数です。

N = 256;
x = fi(zeros(N,1),1,16,15);

また、設計の要件によって、40 ビットのアキュムレータをもつ DSP ターゲットの固定小数点演算も決まります。この例では、負方向の丸めとオーバーフローのラップを使用して、効率的なコードを生成します。

F = fimath('RoundingMethod','Floor',...
           'OverflowAction','Wrap',...
           'ProductMode','KeepLSB',...
           'ProductWordLength',40,...
           'SumMode','KeepLSB',...
           'SumWordLength',40);

以下の係数は、次によって作成された 2 次ローパス フィルターに対応します。

[num,den] = butter(2,0.125)

係数の値は、フィルターの出力および状態に割り当てられる値の範囲に影響します。

num = [0.0299545822080925  0.0599091644161849  0.0299545822080925];
den = [1                  -1.4542435862515900  0.5740619150839550];

設計の要件によって決まる係数のデータ型は、16 ビットの語長として指定され、最高精度にスケーリングされます。定数係数から fi オブジェクトを作成するためのパターンは以下のとおりです。

1. 既定の最も近い正の整数方向への丸めと飽和オーバーフロー設定を使用して、係数を fi オブジェクトにキャストします。これにより、係数の精度が高くなります。

2. fimath に負方向の丸めとオーバーフローのラップ設定を付加して演算を制御します。これにより、より効率的な C コードが生成されます。

b = fi(num,1,16); b.fimath = F;
a = fi(den,1,16); a.fimath = F;

フィルター係数を buildInstrumentedMex コマンドに定数として渡すことで、フィルター係数をこのフィルターの実装にハード コードします。

B = coder.Constant(b);
A = coder.Constant(a);

係数および入力の値によって決定されるデータ型

係数の値および入力の値によって、出力 y および状態ベクトル z のデータ型が決まります。値の最大範囲を保持して潜在的なオーバーフローを特定しデータ型を推奨できるように、スケーリングされた double データ型の値を作成します。

yisd = fi(zeros(N,1),1,16,15,'DataType','ScaledDouble','fimath',F);
zisd = fi(zeros(2,1),1,16,15,'DataType','ScaledDouble','fimath',F);

スケーリングされた double の MEX 関数として MATLAB® 関数をインストルメント化

MATLAB® コードをインストルメント化するには、buildInstrumentedMex コマンドを使用して MATLAB® 関数から MEX 関数を作成します。buildInstrumentedMex への入力は fiaccel への入力と同じですが、buildInstrumentedMex には fi オブジェクトの制限がありません。buildInstrumentedMex の出力は、計測機能を挿入された MEX 関数です。この MEX 関数を実行すると、すべての名前付き変数および中間値について、シミュレーションされた最小値と最大値が記録されます。

'-o' オプションを使用して、生成される MEX 関数に名前を付けます。'-o' オプションを使用しない場合は、元の MATLAB® 関数の名前の最後に '_mex' を付けた名前が MEX 関数に付けられます。MEX 関数に MATLAB® 関数と同じ名前を付けることもできますが、MEX 関数の方が MATLAB® 関数より優先されるため、同じ名前の MEX 関数が再生成されるか削除されてクリアされるまでは MATLAB® 関数に対する変更が実行されない点に注意する必要があります。

buildInstrumentedMex fi_2nd_order_df2t_filter ...
    -o filter_scaled_double ...
    -args {B,A,x,yisd,zisd}

チャープ入力を使用したテスト ベンチ

このシステムのテスト ベンチは、チャープ信号およびステップ信号を実行するように設定されています。一般に、システムのテスト ベンチは、広範囲な入力信号をカバーします。

最初のテスト ベンチではチャープ入力を使用します。チャープ信号は広範囲な周波数をカバーするため、優れた代表的な入力となっています。

t = linspace(0,1,N);       % Time vector from 0 to 1 second
f1 = N/2;                  % Target frequency of chirp set to Nyquist
xchirp = sin(pi*f1*t.^2);  % Linear chirp from 0 to Fs/2 Hz in 1 second
x(:) = xchirp;             % Cast the chirp to fixed-point

インストルメント化した MEX 関数の実行による最小値/最大値の記録

シミュレーション実行の最小値と最大値を記録するには、インストルメント化した MEX 関数を実行しなければなりません。その後の実行で計測結果が集積されていき、その集積は clearInstrumentationResults によって計測結果がクリアされるまで続きます。

分子と分母の係数が定数としてコンパイルされているため、生成された MEX 関数への入力として指定されないという点に注意してください。

ychirp = filter_scaled_double(x,yisd,zisd);

フィルター処理されたチャープ信号のプロットは、フィルターのローパス動作をこれらの特定の係数と共に表示します。低周波数は通過し、高周波数は減衰されます。

clf
plot(t,x,'c',t,ychirp,'bo-')
title('Chirp')
legend('Input','Scaled-double output')
figure(gcf); drawnow;

計測結果と推奨されたチャープの小数部の長さの表示

showInstrumentationResults コマンドは、計測された値を示すコード生成レポートを表示します。showInstrumentationResults への入力は、結果表示の対象にするインストルメント化された MEX 関数の名前です。

以下に、showInstrumentationResults コマンドのオプションのリストを示します。

  • -defaultDT T: double に推奨される既定のデータ型。ここで、Tnumerictype オブジェクトまたは string {remainFloat, double, single, int8, int16, int32, int64, uint8, uint16, uint32, uint64} のいずれかとなります。既定の設定は remainFloat です。

  • -nocode 印刷可能なレポートに MATLAB コードを表示しません。変数テーブルのログのみを表示します。このオプションは、-printable オプションと組み合わせた場合にのみ有効になります。

  • -optimizeWholeNumbers シミュレーションの最小/最大値のログに常に 0 または正の整数であることが示されている変数の語長を最適化します。

  • -percentSafetyMargin N シミュレーションの最小/最大値に対する安全余裕。ここで、N は割合を示します。

  • -printable 印刷可能なレポートを作成し、システム ブラウザーで開きます。

  • -proposeFL 指定された語長について小数部の長さを推奨します。

  • -proposeWL 指定された小数部の長さについて語長を推奨します。

オーバーフローの可能性は、スケーリングされた double データ型をもつ fi オブジェクトにのみ表示されます。

この特定の設計は語長が固定の DSP 用なので、proposeFL フラグを使用して、小数部の長さを推奨します。

showInstrumentationResults filter_scaled_double -proposeFL

インストルメント化されたコード生成レポート内の式または変数にカーソルを合わせると、シミュレーションの最小値と最大値が表示されます。この設計では、入力の範囲は -1 ~ +1 であり、すべての変数の値や中間結果の範囲も -1 ~ +1 になります。つまり、データ型がすべて非整数 (小数部の長さは語長より 1 ビット短い) になる可能性を示します。ただし、この関数に対して他の種類の入力を使用した場合は、常にそうなるとは限りません。最終的な固定小数点データ型を設定する前に、多くの種類の入力をテストすることが重要です。

ステップ入力を使用したテスト ベンチ

次のテスト ベンチはステップ入力で実行されます。ステップ入力はシステムの動作を特徴付けるために使用されることがあるので、優れた代表的な入力となっています。

xstep = [ones(N/2,1);-ones(N/2,1)];
x(:) = xstep;

ステップ入力によるインストルメント化した MEX 関数の実行

計測結果は集積され、その集積は clearInstrumentationResults によって計測結果がクリアされるまで続きます。

ystep = filter_scaled_double(x,yisd,zisd);

clf
plot(t,x,'c',t,ystep,'bo-')
title('Step')
legend('Input','Scaled-double output')
figure(gcf); drawnow;

累積計測結果の表示

インストルメント化されたコード生成レポートで現在の範囲の 100% の位置にある x が示すように、ステップの入力とチャープ入力が両方とも最大範囲である場合、ステップ入力ではオーバーフローが発生しますが、チャープ入力では発生しません。これは、テスト ベンチには多数のさまざまな入力をもつ必要があることを意味します。この例の目的上、入力は 2 つだけ使用しましたが、実際のテスト ベンチではさらに多くの入力を使用します。

showInstrumentationResults filter_scaled_double -proposeFL

推奨された固定小数点プロパティの適用

オーバーフローを避けるには、インストルメント化されたコード生成レポートに示されている y および z の推奨された小数部の長さである 14 ビットに基づいて、推奨された固定小数点プロパティを設定します。

ワークフローのこの時点では、実際の固定小数点型 (前述のデータ型を決定する手順で使用したスケーリングされた double 型とは異なる) を使用します。

yi = fi(zeros(N,1),1,16,14,'fimath',F);
zi = fi(zeros(2,1),1,16,14,'fimath',F);

固定小数点 MEX 関数として MATLAB® 関数をインストルメント化

固定小数点入力と buildInstrumentedMex コマンドを使って、インストルメント化した固定小数点 MEX 関数を作成します。

buildInstrumentedMex fi_2nd_order_df2t_filter ...
    -o filter_fixed_point ...
    -args {B,A,x,yi,zi}

固定小数点のアルゴリズムの検証

固定小数点に変換したら、固定小数点の入力を使用してテスト ベンチを再実行し、設計を検証します。

チャープ入力を使用した検証

チャープ入力を使用して固定小数点アルゴリズムを実行し、設計を検証します。

x(:) = xchirp;
[y,z] = filter_fixed_point(x,yi,zi);
[ysd,zsd] = filter_scaled_double(x,yisd,zisd);
err = double(y) - double(ysd);

固定小数点の出力とスケーリングされた double の出力を比較して、設計基準を満たしていることを確認します。

clf
subplot(211);plot(t,x,'c',t,ysd,'bo-',t,y,'mx')
xlabel('Time (s)');
ylabel('Amplitude')
legend('Input','Scaled-double output','Fixed-point output');
title('Fixed-Point Chirp')
subplot(212);plot(t,err,'r');title('Error');xlabel('t'); ylabel('err');
figure(gcf); drawnow;

変数と中間結果を調べて、最小値/最大値が範囲内であることを確認します。

showInstrumentationResults filter_fixed_point

ステップ入力を使用した検証

ステップ入力を使用して固定小数点アルゴリズムを実行し、設計を検証します。

ステップ入力の実行の効果のみを確認できるように、以下のコードを実行して前の計測結果をクリアします。

clearInstrumentationResults filter_fixed_point

固定小数点フィルターを通過するステップ入力を実行し、スケーリングされた double フィルターの出力と比較します。

x(:) = xstep;
[y,z] = filter_fixed_point(x,yi,zi);
[ysd,zsd] = filter_scaled_double(x,yisd,zisd);
err = double(y) - double(ysd);

スケーリングされた double の出力に対して固定小数点の出力をプロットし、設計基準を満たしていることを確認します。

clf
subplot(211);plot(t,x,'c',t,ysd,'bo-',t,y,'mx')
title('Fixed-Point Step');
legend('Input','Scaled-double output','Fixed-point output')
subplot(212);plot(t,err,'r');title('Error');xlabel('t'); ylabel('err');
figure(gcf); drawnow;

変数と中間結果を調べて、最小値/最大値が範囲内であることを確認します。

showInstrumentationResults filter_fixed_point

以下のコードを実行してグローバル状態を復元します。

fipref(FIPREF_STATE);
clearInstrumentationResults filter_fixed_point
clearInstrumentationResults filter_scaled_double
clear fi_2nd_order_df2t_filter_fixed_instrumented
clear fi_2nd_order_df2t_filter_float_instrumented

以下のコードを実行して一時ディレクトリを削除します。

tempdirObj.cleanUp;
%#ok<*ASGLU>