ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

IIR フィルターの浮動小数点から固定小数点への変換

この例では、固定小数点コンバーター アプリを使用して IIR フィルターを浮動小数点から固定小数点の実装に変換する方法を説明します。二次型 (または "双二次") の構造は、伝達関数を直接実装する構造よりも、固定小数点演算を使用する場合にうまく機能します。ここでは、"浮動から固定" の変換を成功させるための最も確実な方法を説明します。この方法は、以下の手順で構成されています。

  • 2 次セクション型 (SOS) 構造、つまり dsp.BiquadFilter を選択

  • フィルターの各ノードのダイナミック レンジ解析を実行。つまり、シミュレーションの最小値とシミュレーションの最大値の計測によるテスト ベンチ アプローチを使用

  • 代替方法である双二次スケーリング実装と比較し、'fvtool' および dsp.SpectrumAnalyzer を使用して解析および検証して、異なる選択に起因する量子化の影響を表示

はじめに

IIR フィルターを効率的に実装する方法として、2 次セクション型 (SOS) 双二次フィルター構造を使用する方法があります。たとえば、システムから高周波数のトーン信号である干渉源を除去する必要があると仮定します。これを実行する方法の 1 つは、ローパス フィルター設計を使用することです。

ローパス楕円フィルターの設計

この例では、最小次数のローパス楕円直接型 I 設計を使用します。フィルターの設計仕様は、以下のとおりです。

  • 通過帯域周波数エッジ: 0.4*pi

  • 阻止帯域周波数エッジ: 0.45*pi

  • 通過帯域リップル: 0.5 dB

  • 阻止帯域の減衰: 80 dB

フィルターの可視化ツールを使用して、すべての 2 次セクション型の累積フィルター応答を可視化します。

BQ = design(fdesign.lowpass('Fp,Fst,Ap,Ast',0.4,0.45,0.5,80), 'ellip', ...
    'FilterStructure', 'df1sos', 'SystemObject', true);
hfvt = fvtool(BQ,'Legend','on');
hfvt.SosviewSettings.View = 'Cumulative';

浮動小数点と固定小数点の比較に用いるフィルター係数 (SOS、B、A) の取得

SOS フィルター係数値は (double または 16 ビット固定小数点値のどちらの場合にも) ほぼ同じフィルター応答を導くことに注意してください。

sosMatrix = BQ.SOSMatrix;
sclValues = BQ.ScaleValues;
hfvt_comp = fvtool(sosMatrix, fi(sosMatrix, 1, 16));
legend(hfvt_comp, ...
    'Floating-point (double) SOS', 'Fixed-point (16-bit) SOS');
b = repmat(sclValues(1:(end-1)),1,3) .* sosMatrix(:,(1:3));
a = sosMatrix(:,(5:6));
num = b'; % matrix of scaled numerator sections
den = a'; % matrix of denominator sections

close(hfvt);      % clean up
close(hfvt_comp); % clean up

既定の浮動小数点演算

フィルターを通して何らかのデータをストリーミングし、入出力応答を表示してフィルターの動作を検証します。まず、付加的な高周波数トーンの干渉源をともなう (浮動小数点の) 疑似ランダム ノイズ信号 (たとえば 300 Hz でサンプリングされた信号) のフィルター処理を試行し、トーンが除去されるかを確認します。これは後でテスト ベンチの基準信号として使用します。

Wo      = 75/(300/2); % 75 Hz tone; system running at 300 Hz
inp_len = 4000;       % Number of input samples (signal length)
inp_itf = 0.5 .* sin((pi*Wo) .* (0:(inp_len-1))'); % tone interferer
plot1   = dsp.SpectrumAnalyzer('SampleRate',300,...
    'PlotAsTwoSidedSpectrum',false,'ShowLegend',true,'YLimits',[-85 25],...
    'Title','Floating-Point Input Signal and Filter Output Signal', ...
    'ChannelNames', {'Floating-Point Input', 'Filter Output'});
rng(12345); % seed the rng for repeatable results
bqLPFiltFloat = dsp.BiquadFilter('SOSMatrixSource', 'Input port', ...
    'ScaleValuesInputPort', false);
for k = 1:10
    inp_sig = rand(inp_len,1) - 0.5; % random values in range (-0.5, 0.5)
    input = inp_sig + inp_itf; % combined input signal, range (-1.0, 1.0)
    out_1 = step(bqLPFiltFloat, input, num, den); % filter
    step(plot1,[input,out_1]) % visualize input and filtered output
end

clear plot1 bqLPFiltFloat; % clean up

既定の固定小数点演算

今度はオブジェクトの既定の設定を使用して、フィルターに何らかの固定小数点データを通します。固定小数点の既定の動作は無効な結果の原因となることに注意してください。

plot2 = dsp.SpectrumAnalyzer('SampleRate',300,...
    'PlotAsTwoSidedSpectrum',false,'ShowLegend',true,'YLimits',[-85 25],...
    'Title','Fixed-Point Input Signal and Filter Output Signal', ...
    'ChannelNames', ...
    {'Fixed-Point Input', 'Default (Incorrect) Fixed-Point Output'});
rng(12345); % seed the rng for repeatable results
bqLPFiltFixpt = dsp.BiquadFilter('SOSMatrixSource', 'Input port', ...
    'ScaleValuesInputPort', false);
for k = 1:10
    inp_sig = rand(inp_len,1) - 0.5;  % random values in range (-0.5, 0.5)
    inputFi = fi(inp_sig + inp_itf, 1, 16, 15); % signal range (-1.0, 1.0)
    out_2 = step(bqLPFiltFixpt, inputFi, fi(num,1,16), fi(den,1,16));
    step(plot2,[inputFi,out_2]) % visualize
end

clear plot2 bqLPFiltFixpt; % clean up

浮動小数点双二次 IIR フィルター関数の固定小数点への変換

オブジェクトの既定の固定小数点設定の代わりに、固定小数点コンバーター アプリを使用して固定小数点に変換します。この方法によって、フィルターの実装内における個々の固定小数点型の可視性および制御性が向上し、固定小数点演算がより正確になります。

まず、固定小数点コンバーター アプリを使用する準備として、すべてのフィルターのデータ型の選択を "Custom" に設定し、変換する関数を作成します。

type myIIRLowpassBiquad;
function output = myIIRLowpassBiquad(input,num,den)
%myIIRNotchBiquad Biquad lowpass filter implementation
%   Used as part of a MATLAB Fixed Point Converter App example.
persistent bqLPFilter;
if isempty(bqLPFilter)
    bqLPFilter = dsp.BiquadFilter(        ...
        'SOSMatrixSource', 'Input port',  ...
        'ScaleValuesInputPort', false,    ...
        'SectionInputDataType',           'Custom', ...
        'SectionOutputDataType',          'Custom', ...
        'NumeratorProductDataType',       'Custom', ...
        'DenominatorProductDataType',     'Custom', ...
        'NumeratorAccumulatorDataType',   'Custom', ...
        'DenominatorAccumulatorDataType', 'Custom', ...
        'StateDataType',                  'Custom', ...
        'OutputDataType',                 'Custom');
end
output = step(bqLPFilter, input, num, den);
end

テスト ベンチ スクリプトの作成

データ型で制御されるすべての信号パスについて、シミュレーションの最小値とシミュレーションの最大値をシミュレートし、計測したこれらの値を収集するテスト ベンチを作成します。これにより、その後ツールでオートスケールされた固定小数点設定を推奨できるようになります。上記のコードの一部をテスト ベンチ スクリプトとして使用し、浮動小数点の入力から始めてテスト ベンチを検証した後、最小および最大データをシミュレートして収集します。その後、固定小数点コンバーター アプリを使用し、浮動小数関数の実装を固定小数点関数の実装に変換します。

type myIIRLowpassBiquad_tb.m;
%% Test Bench for myIIRLowpassBiquad.m

%% Pre-designed filter (coefficients stored in MAT file):
% f = design(fdesign.lowpass('Fp,Fst,Ap,Ast',0.4,0.45,0.5,80), ...
%            'ellip', 'FilterStructure', 'df1sos','SystemObject',true);
% sosMatrix = f.SOSMatrix;
% sclValues = f.ScaleValues;
% b = repmat(sclValues(1:(end-1)),1,3) .* sosMatrix(:,(1:3));
% a = sosMatrix(:,(5:6));
% num = b';
% den = a';
% save('myIIRLowpassBiquadDesign.mat', 'b', 'a', 'num', 'den');
load('myIIRLowpassBiquadDesign.mat');

%% Interference signal, using values in range (-0.5, 0.5)
Wo      = 75/(300/2); % 75 Hz tone; system running at 300 Hz
inp_len = 4000; sinTvec = (0:(inp_len-1))';
inp_itf = 0.5 .* sin((pi*Wo) .* sinTvec);

%% Filtering and visualization
% Filter an input signal, including an interference
% tone, to see if the tone is successfully removed.
rng(12345); % seed the rng for repeatable results
sa_plot = dsp.SpectrumAnalyzer('SampleRate',300,...
    'PlotAsTwoSidedSpectrum',false,'ShowLegend',true,'YLimits',[-125 25],...
    'Title','Input Signal and Filter Output Signal', ...
    'ChannelNames', {'Input', 'Filter Output'});

for k = 1:10
    inp_sig = rand(inp_len,1) - 0.5; % random values in range (-0.5, 0.5)
    input = inp_sig + inp_itf;
    out_1 = myIIRLowpassBiquad(input,num,den); % filter
    step(sa_plot,[input,out_1]); % visualize
end

固定小数点コンバーター アプリケーションを使用した固定小数点への変換

  • 固定小数点コンバーター アプリを起動します。このツールを起動するには、MATLAB の [アプリ] メニューと 'fixedPointConverter' コマンドとの 2 つの方法があります。

  • 変換する関数を [エントリポイント関数] ボックスに入力します。

  • テスト ベンチのスクリプト名を入力して入力を定義します。

  • 生成されたコードをチェックして実行時の問題がないか確認します。

  • シミュレーションして [シミュレーションの最小値] および [シミュレーションの最大値] の値を収集し、観察します。

  • 必要に応じて [推奨された型] フィールドを調整します。

  • 型推奨レポートを生成して固定小数点に変換します。

結果として得られる固定小数点の MATLAB 実装

生成された固定小数点関数の実装は次のようになります。

type myIIRLowpassBiquad_fixpt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                          %
%           Generated by MATLAB 8.5 and Fixed-Point Designer 5.0           %
%                                                                          %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%#codegen
function output = myIIRLowpassBiquad_fixpt(input,num,den)
%myIIRNotchBiquad Biquad lowpass filter implementation
%   Used as part of a MATLAB Fixed Point Converter App example.
fm = fimath('RoundingMethod', 'Floor', 'OverflowAction', 'Wrap', ...
    'ProductMode', 'FullPrecision', 'MaxProductWordLength', 128, ...
    'SumMode', 'FullPrecision', 'MaxSumWordLength', 128);

persistent bqLPFilter;
if isempty(bqLPFilter)
    bqLPFilter = dsp.BiquadFilter(        ...
        'SOSMatrixSource', 'Input port',  ...
        'ScaleValuesInputPort', false,    ...
        'SectionInputDataType',           'Custom', ...
        'SectionOutputDataType',          'Custom', ...
        'NumeratorProductDataType',       'Custom', ...
        'DenominatorProductDataType',     'Custom', ...
        'NumeratorAccumulatorDataType',   'Custom', ...
        'DenominatorAccumulatorDataType', 'Custom', ...
        'StateDataType',                  'Custom', ...
        'OutputDataType',                 'Custom' , ...
        'CustomSectionInputDataType', numerictype([], 16, 8), ...
        'CustomSectionOutputDataType', numerictype([], 16, 8), ...
        'CustomNumeratorProductDataType', numerictype([], 32, 26),...
        'CustomDenominatorProductDataType', numerictype([], 32, 23),...
        'CustomNumeratorAccumulatorDataType', numerictype([], 32, 24),...
        'CustomDenominatorAccumulatorDataType', numerictype([], 32, 23),...
        'CustomStateDataType', numerictype([], 16, 8), ...
        'CustomOutputDataType', numerictype([], 16, 15));
end
output = fi(step(bqLPFilter, input, num, den), 1, 16, 15, fm);
end

コマンド ライン API を使用した固定小数点変換の自動化

別の方法として、コマンド ライン API を使用して固定小数点変換を自動化することもできます。

type myIIRLowpassF2F_prj_script;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Script generated from project 'myIIRLowpassBiquad.prj' on 16-Oct-2014.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create configuration object of class 'coder.FixPtConfig'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cfg = coder.config('fixpt');

cfg.TestBenchName = { sprintf('S:\\Work\\15aFeatureExamples\\biquad_notch_f2f\\myIIRLowpassBiquad_tb.m') };
cfg.DefaultWordLength = 16;
cfg.LogIOForComparisonPlotting = true;
cfg.TestNumerics = true;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Define argument types for entry-point 'myIIRLowpassBiquad'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ARGS = cell(1,1);
ARGS{1} = cell(3,1);
ARGS{1}{1} = coder.typeof(0,[4000   1]);
ARGS{1}{2} = coder.typeof(0,[3 5]);
ARGS{1}{3} = coder.typeof(0,[2 5]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Invoke MATLAB Coder.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
codegen -float2fixed cfg myIIRLowpassBiquad -args ARGS{1}

変換済み MATLAB 固定小数点実装のテスト

変換済みの固定小数点関数を実行し、入出力結果を表示します。

plot3 = dsp.SpectrumAnalyzer('SampleRate',300,...
    'PlotAsTwoSidedSpectrum',false,'ShowLegend',true,'YLimits',[-85 25],...
    'Title','Fixed-Point Input Signal and Filter Output Signal', ...
    'ChannelNames', {'Fixed-Point Input', 'Fixed-Point Filter Output'});
rng(12345); % seed the rng for repeatable results
for k = 1:10
    inp_sig = rand(inp_len,1) - 0.5;  % random values in range (-0.5, 0.5)
    inputFi = fi(inp_sig + inp_itf, 1, 16, 15); % signal range (-1.0, 1.0)
    out_3 = myIIRLowpassBiquad_fixpt(inputFi, fi(num,1,16), fi(den,1,16));
    step(plot3,[inputFi,out_3]) % visualize
end

clear plot3; % clean up

浮動小数点と固定小数点の出力間の誤差が次のプロットに表示されます。誤差がかなり大きいことがわかります。出力値のこのような差は、多くの場合、スケーリングの選択と 2 次セクション型の順序が原因となります。次の節で、実装の早い段階にこの誤差を減らす方法を説明します。

fig = figure;
subplot(3,1,1);
plot(out_1);
title('Floating-point filter output');
subplot(3,1,2);
plot(out_3);
title('Fixed-point filter output');
subplot(3,1,3);
plot(out_1 - double(out_3));
axis([0 4000 -4e-2 7e-2]);
title('Error');

close(fig); % clean up

無限大ノルム スケーリングを使用した楕円フィルターの再設計

楕円フィルター設計には、'Linf' 2 次セクション型スケーリング (無限大ノルム) が使用された場合、比較的良好なスケーリングが行われるという特長があります。この方法を使用すると、多くの場合、量子化誤差の低減につながります。

BQ_Linf = design(fdesign.lowpass('Fp,Fst,Ap,Ast',0.4,0.45,0.5,80), ...
    'ellip', 'FilterStructure', 'df1sos', ...
    'SOSScaleNorm', 'Linf', 'SystemObject', true);
hfvt_Linf = fvtool(BQ_Linf,'Legend','on');
hfvt_Linf.SosviewSettings.View = 'Cumulative';

各セクションのフィルターへの入力からさまざまな状態までの間で測定された累積内部周波数応答で、0 dB を超えるものがないことに注意してください。したがって、この設計は、固定小数点実装のための適切な候補であることがわかります。

浮動小数点と固定小数点の比較に用いる Linf ノルム フィルター係数の取得

SOS フィルター係数値は (double または 16 ビット固定小数点値のどちらの場合にも) ほぼ同じフィルター応答を導くことに注意してください。

sosMtrLinf = BQ_Linf.SOSMatrix;
sclValLinf = BQ_Linf.ScaleValues;
hfvt_comp_Linf = fvtool(sosMtrLinf, fi(sosMtrLinf, 1, 16));
legend(hfvt_comp_Linf, 'Floating-point (double) SOS, Linf Scaling', ...
    'Fixed-point (16-bit) SOS, Linf Scaling');
bLinf = repmat(sclValLinf(1:(end-1)),1,3) .* sosMtrLinf(:,(1:3));
aLinf = sosMtrLinf(:,(5:6));
numLinf = bLinf'; % matrix of scaled numerator sections
denLinf = aLinf'; % matrix of denominator sections

close(hfvt_Linf);      % clean up
close(hfvt_comp_Linf); % clean up

変換済み MATLAB 固定小数点 Linf ノルム双二次フィルターのテスト

上記の固定小数点コンバーターの手順 (ただし、Linf ノルム スケーリングしたフィルター係数値を使用) に再度従った後、変換した新しい固定小数点関数を実行し、入出力結果を表示します。

plot4 = dsp.SpectrumAnalyzer('SampleRate',300,...
    'PlotAsTwoSidedSpectrum',false,'ShowLegend',true,'YLimits',[-85 25],...
    'Title',...
    'Fixed-Point Input Signal and Linf-Norm Filter Output Signal', ...
    'ChannelNames', ...
    {'Fixed-Point Input', 'Fixed-Point Linf-Norm Filter Output'});
rng(12345); % seed the rng for repeatable results
for k = 1:10
    inp_sig = rand(inp_len,1) - 0.5;  % random values in range (-0.5, 0.5)
    inputFi = fi(inp_sig + inp_itf, 1, 16, 15); % signal range (-1.0, 1.0)
    out_4 = ...
        myIIRLinfBiquad_fixpt(inputFi, fi(numLinf,1,16), fi(denLinf,1,16));
    step(plot4,[inputFi,out_4]) % visualize
end

clear plot4; % clean up

Linf ノルム SOS スケーリングを使用した固定小数点実装誤差の低減

多くの場合、無限大ノルム SOS スケーリングで出力を生成することで誤差が少なくなります。

fig1 = figure;
subplot(3,1,1);
plot(out_1);
title('Floating-point filter output');
subplot(3,1,2);
plot(out_4);
title('Fixed-point (Linf-norm SOS) filter output');
subplot(3,1,3);
plot(out_1 - double(out_4));
axis([0 4000 0 1e-3]);
title('Error');

fig2 = figure;
subplot(2,1,1);
plot(out_1 - double(out_3));
axis([0 4000 -4e-2 7e-2]);
title('Fixed-point error (default SOS filter scaling)');
subplot(2,1,2);
plot(out_1 - double(out_4));
axis([0 4000 0 1e-3]);
title('Fixed-point error (''Linf'' SOS filter scaling)');

close(fig1); % clean up
close(fig2); % clean up

まとめ

ここでは、浮動小数点 IIR フィルターを固定小数点実装に変換する手順を説明しました。DSP System Toolbox™ の dsp.BiquadFilter オブジェクトには、シミュレーションの最小値と最大値の計測機能が備えられており、固定小数点コンバーター アプリで自動的かつ動的に内部フィルター信号をスケーリングするのに役立ちます。また、'fvtool' および dsp.SpectrumAnalyzer は、さまざまな解析においてプロセスの各ステップで検証を行うためのツールとして使用できます。

この情報は役に立ちましたか?