Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

HDL 用に最適化した正規化逆数の使用方法

この例では、関数 normalizedReciprocal および Normalized Reciprocal HDL Optimized ブロックを使用して入力の正規化逆数を計算する方法と、使用のタイミングを示します。

値の逆数は範囲が広くなることがあり、固定小数点型は浮動小数点型に比べて範囲が制限されます。入力値 u が小さければ 1/u は大きくなり、u が大きければ 1/u は小さくなります。したがって、1/u の固定小数点型には高い精度と広い範囲が求められ、長い語長が必要となります。

逆数と別の変数の積の範囲がわかっているアプリケーションでは、正規化逆数を計算し、それに他の変数を乗算してから、最終的な出力にシフトを適用すると効率的です。これには、たとえば、後退代入でピボット要素による除算が必要な最小二乗のアプリケーションなどが該当します。

正規化逆数の計算

入力を u とすると、正規化逆数 y および指数 e は、次のように計算されます。

       (2.^e).*y = 1./u,

および

       0.5 < |y| <= 1.

u = 0u が固定小数点またはスケーリングされた double の場合、y = 2 - eps(y) になります。

u = 0u が浮動小数点型の場合、y = inf になります。

u~=0 の場合、この関数が返すのは以下と等価になります。

      [y,e] = log2(1./abs(double(u)))
      y(u<0) = -y(u<0)

異なる点はシフトと加算のみを使用して計算されることです。

MATLAB 関数または Simulink ブロックの選択

C コードの生成およびシステムの設計には、MATLAB 関数 normalizedReciprocal を使用します。この関数ではレイテンシでの計算は行われません。シミュレーションでは、fiaccelbuildInstrumentedMex、または codegen を使用する速度について、関数を MEX ファイルにコンパイルします。

最適化された HDL コードを生成するには、Normalized Reciprocal HDL Optimized ブロックを使用します。このブロックは HDL において高いスループットを小さい面積で実現できるように最適化されており、生成された HDL コードと同じレイテンシでシミュレーションを行います。

結果の数値出力はブロックと関数で同じです。

MATLAB を使用した正規化逆数の計算

固定小数点入力 u の正規化逆数を計算し、その値を実際の逆数の値と比較します。

u = fi([-pi,0.01,pi])
u = 

   -3.1416    0.0100    3.1416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 13
[y,e] = normalizedReciprocal(u)
y = 

   -0.6367    0.7806    0.6367

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 16
        FractionLength: 14

e =

  1x3 int32 row vector

   -1    7   -1

computed_reciprocal = 2.^double(e).* double(y)
computed_reciprocal =

   -0.3183   99.9141    0.3183

actual_reciprocal = 1./double(u)
actual_reciprocal =

   -0.3183   99.9024    0.3183

正規化逆数と実際の逆数の値が近いことがわかります。

Simulink モデルの入力の定義

Normalized Reciprocal HDL Optimized ブロックを使用して、正規化逆数を取得する固定小数点入力 u を定義します。

x = linspace(0.001,100,100);
x = [fliplr(-x),x];
u = fi(x,1,18);

Normalized Reciprocal HDL Optimized ブロックのレイテンシ

Normalized Reciprocal HDL Optimized ブロックは、二分探索を使用する入力を正規化することで機能します。二分探索のレイテンシは入力の語長の約 log2、それに続く CORDIC 逆数カーネルのレイテンシは入力の語長とほぼ同じです。

Normalized Reciprocal HDL Optimized ブロックは、常にデータを受け入れる準備ができています。最初のレイテンシの後、サンプルごとに有効なサンプルが出力されます。固定小数点入力 u のサンプルのレイテンシは次のとおりです。

       D = ceil(log2(u.WordLength)) + u.WordLength + 5

この例に含まれている関数 normalizedReciprocalLatency を使用して、固定小数点、double、または single の数値型の入力のレイテンシを計算できます。

入力サンプルを Normalized Reciprocal HDL Optimized ブロックの出力と合わせるには、レイテンシ D を遅延で使用します。

D = normalizedReciprocalLatency(u)
D =

    28

正規化逆数 Simulink モデルの実行

逆数と別の変数の積の範囲がわかっている簡単な例として、値の正規化逆数を計算し、それにその値自体を乗算します。この最終的な積は 1 と等しくなるはずです。入力値と逆数の範囲が広い場合でも、値とその逆数の積は既知の範囲になります。

0.5 < abs(y) <= 1 であり、積の大きさがこれよりも大きくなることはないため、積 u*yu と同じ型で計算できることに注意してください。

model = 'NormalizedReciprocalModel';
open_system(model)
out = sim(model);

正規化逆数 Simulink モデルの結果の解析

次のプロットから、入力 u と逆数 1/u の範囲が広いのに対し、正規化逆数 y の範囲は -1 ~ 1 であることがわかります。

入力 u は -100 ~ 100 の範囲の fi 値のベクトルです。

normalizedReciprocalPlot(1,u,out.y,out.e,out.z);

逆数 1/u の実際の値は正規化逆数 (2.^e).*y とほぼ同じです。逆数 1/u は範囲が広いため、直線的な逆数を固定小数点で計算するにはハイ ダイナミック レンジのデータ型 (つまり語長と小数部が長いデータ型) が必要になります。

normalizedReciprocalPlot(2,u,out.y,out.e,out.z);

正規化逆数 y の範囲は次のとおりです。

       0.5 < |y| <= 1

u と同じ語長のデータ型に効率的かつ正確に格納できます。y の数値型の小数部の長さは u の語長よりも 2 短くなります。この追加の整数ビットにより、y の正または負の区別に加え、値 -1 および +1 を正確に表現できます。

normalizedReciprocalPlot(3,u,out.y,out.e,out.z);

正規化指数 e と入力 u の大きさは逆相関関係にあります。u の大きさが大きいと、e は大きい負の値になります。u がゼロに近いと、e は大きい正の値になります。この関係を次に示します。

       (2.^e).*y = 1./u,
normalizedReciprocalPlot(4,u,out.y,out.e,out.z);

このモデルでは、正規化逆数 y に入力 u を乗算し、e でシフトして結果をスケーリングしています。y の大きさは 1 より小さいため、u の固定小数点型で積を計算できます。出力 z = 2^e (y * u) は 1 とほぼ等しくなります。

normalizedReciprocalPlot(5,u,out.y,out.e,out.z);

正規化逆数を固定小数点データ型で計算した結果として、出力 z には僅かな丸め誤差があります。

normalizedReciprocalPlot(6,u,out.y,out.e,out.z);