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

ローパス FIR フィルターの設計

この例では、ローパス FIR フィルターの設計法を説明します。ここで説明する多くの概念は、ハイパス、バンドパスなどの他の応答にも拡張できます。

FIR フィルターは、高性能な設計アルゴリズム、非再帰的な形で実装された際の安定性、線形位相の得やすさ、マルチレート ケースへの簡単な拡張性、充実したハードウェア サポートなどにより、広く使用されています。この例では、さまざまな特性のローパス FIR フィルターの設計に使用できる DSP System Toolbox™ の機能を紹介します。

ローパス FIR フィルター係数の取得

Lowpass Filter Design では、DSP System Toolbox を使用したローパス フィルターの設計の概要が提供されます。要約すると、FIR フィルター係数のベクトルを返す 2 つの関数 firceqrip および firgr が提示されています。firceqrip は、フィルター次数 (フィルター長と同様) が既知で固定の場合に使用されます。

N   = 100;        % FIR filter order
Fp  = 20e3;       % 20 kHz passband-edge frequency
Fs  = 96e3;       % 96 kHz sampling frequency
Rp  = 0.00057565; % Corresponds to 0.01 dB peak-to-peak ripple
Rst = 1e-4;       % Corresponds to 80 dB stopband attenuation

eqnum = firceqrip(N,Fp/(Fs/2),[Rp Rst],'passedge'); % eqnum = vec of coeffs
fvtool(eqnum,'Fs',Fs,'Color','White') % Visualize filter

フィルター次数 100 は無作為の選択です。一般に、大きい次数の方が理想の近似値になりますが、実装がコスト高になります。次数をおよそ 2 倍にすると、フィルターの遷移幅は半分になります (他のすべてのパラメーターは変わらないと仮定)。

N2 = 200; % Change filter order from 100 to 200
eqNum200 = firceqrip(N2,Fp/(Fs/2),[Rp Rst],'passedge');
fvt = fvtool(eqnum,1,eqNum200,1,'Fs',Fs,'Color','White');
legend(fvt,'FIR filter; Order = 100','FIR filter. Order = 200')

最小次数ローパス フィルターの設計

フィルター次数を指定する代わりに、firgr を使用して設計仕様を満たすために最小限必要な次数を判断できます。そのためには、遷移領域の幅を指定する必要があります。これは阻止帯域エッジ周波数を設定することで実行できます。

Fst = 23e3;  % Transition Width = Fst - Fp
numMinOrder = firgr('minorder',[0,Fp/(Fs/2),Fst/(Fs/2),1],[1 1 0 0],...
    [Rp Rst]);
fvt = fvtool(eqnum,1,eqNum200,1,numMinOrder,1,'Fs',Fs,'Color','White');
legend(fvt,'FIR filter; Order = 100','FIR filter. Order = 200',...
    'FIR filter. Order = 133')

関数 firgr では、偶数の最小次数 ('mineven') または奇数の最小次数 ('minodd') のフィルターを設計することもできます。

ローパス FIR フィルターの実装

フィルター係数を取得した後、dsp.FIRFilter でフィルターを実装できます。これは、倍精度/単精度浮動小数点データだけでなく固定小数点データもサポートします。また、C コードおよび HDL コード生成に加え、ARM® Cortex® M および ARM Cortex A に最適化されたコード生成もサポートします。

lowpassFIR = dsp.FIRFilter('Numerator',eqnum); %or eqNum200 or numMinOrder
fvtool(lowpassFIR,'Fs',Fs,'Color','White')

実際のフィルター処理を行うために、FIR を関数と同様に直接呼び出します。以下のコードは、ガウス性ホワイト ノイズをフィルター処理し、結果のフィルター処理された信号を 10 秒間スペクトル アナライザーに表示します。

scope  = dsp.SpectrumAnalyzer('SampleRate',Fs,'SpectralAverages',5);
tic
while toc < 10
    x = randn(256,1);
    y = lowpassFIR(x);
    scope(y);
end

フィルターの設計と実装を一度に実行

便宜上、フィルターの設計と実装は、dsp.LowpassFilter を使用して 1 つのステップで実行できます。これは、浮動小数点、固定小数点、C コード生成および ARM Cortex M と ARM Cortex A の最適化コード生成もサポートしています。

lowpassFilt = dsp.LowpassFilter('DesignForMinimumOrder',false, ...
    'FilterOrder',N,'PassbandFrequency',Fp,'SampleRate',Fs,...
    'PassbandRipple',0.01, 'StopbandAttenuation',80);
tic
while toc < 10
    x = randn(256,1);
    y = lowpassFilt(x);
    scope(y);
end

便宜上、直接入力される仕様では dB 値が使われることに注意してください。通過帯域リップルは、FVTool の [表示] メニューを選択後、[通過帯域] を選択して確認できます。dsp.LowpassFilter は IIR (双二次) 設計にも使用できます。

fvtool(lowpassFilt,'Fs',Fs,'Color','White')

フィルター係数の取得

関数 tf を使用して、dsp.LowpassFilter からフィルター係数を抽出できます。

eqnum = tf(lowpassFilt);

調整可能なローパス FIR フィルター

実行時にカットオフ周波数が調整可能なローパス FIR フィルターは、'dsp.VariableBandwidthFIRFilter' を使用して実装できます。このフィルターは、フィルターの応答特性全体の制御を同じ精度で行うことはありませんが、動的周波数応答は可能です。

vbwFilter = dsp.VariableBandwidthFIRFilter('CutoffFrequency',1e3);
tic
told = 0;
while toc < 10
    t = toc;
    if floor(t) > told
        % Add 1 kHz every second
        vbwFilter.CutoffFrequency = vbwFilter.CutoffFrequency + 1e3;
    end
    x = randn(256,1);
    y = vbwFilter(x);
    scope(y);
    told = floor(t);
end

詳細設計オプション: 最適な非等リップル ローパス フィルター

これまでに使用した設計は、すべて最適な等リップル設計でした。等リップル設計は、理想的な応答からの標準偏差を均等に分散して最適化を達成します。これは最大偏差 (リップル) を最小限にするという利点がありますが、そのエネルギー面から測定した全体的な偏差が大きくなる傾向があります。これは常に望ましいとは限りません。信号をローパス フィルター処理する場合、これは阻止帯域の信号の残留エネルギーが比較的大きい可能性を示唆しています。これが問題になる場合に、阻止帯域のエネルギーを最小限にする最適な設計を提供するのが最小二乗法です。最小二乗およびその他の種類のローパス フィルターの設計には fdesign.lowpass を使用できます。以下のコードは、最小二乗 FIR 設計を、次数と遷移幅が同じである FIR 等リップル設計と比較します。

lowpassSpec = fdesign.lowpass('N,Fp,Fst',133,Fp,Fst,Fs);
lsFIR = design(lowpassSpec,'firls','SystemObject',true);
LP_MIN = dsp.FIRFilter('Numerator',numMinOrder);
fvt = fvtool(LP_MIN,lsFIR,'Fs',Fs,'Color','White');
legend(fvt,'Equiripple design','Least-squares design')

最小二乗法設計では阻止帯域の減衰が周波数に比例して増えますが、等リップル設計では一定です。最小二乗法の場合、増大した減衰は、フィルターされる信号のその帯域のエネルギーを最小化します。

阻止帯域の減衰が増大する等リップル設計

最小二乗法設計の望ましくない結果として、エッジ近くの通過帯域のリップルが大きくなる傾向があることです。ローパス フィルター全般では、フィルター処理する信号の通過帯域周波数への影響ができるだけ少ない方が望ましいとされています。この点で、通常は等リップル通過帯域が推奨されます。阻止帯域で減衰を増やす必要がある場合は、等リップル設計オプションを使用してこれを達成できます。

FIR_eqrip_slope = design(lowpassSpec,'equiripple','StopbandShape','1/f',...
    'StopbandDecay',4,'SystemObject',true);
fvt = fvtool(lsFIR,FIR_eqrip_slope,'Fs',Fs,'Color','White');
legend(fvt,'Least-squares design',...
    'Equiripple design with stopband decaying as (1/f)^4')

阻止帯域はよく似ていますが、等リップル設計では、通過帯域エッジ周波数 20 kHz の近傍では、通過帯域リップルが大幅に小さくなっています。

mls = measure(lsFIR);
meq = measure(FIR_eqrip_slope);
mls.Apass
meq.Apass
ans =

    0.0121


ans =

    0.0046

さらに別の可能性として、任意の振幅仕様を使用して 2 つの帯域を選択する (1 つは通過帯域用、もう一つは阻止帯域用) 方法があります。次に、2 番目の帯域の重みを使用すると、帯域全体の減衰を増大できます。この設計やその他の任意振幅設計の詳細は、任意振幅フィルター設計を参照してください。

B   = 2; % Number of bands
F   = [0 Fp linspace(Fst,Fs/2,40)];
A   = [1 1 zeros(1,length(F)-2)];
W   = linspace(1,100,length(F)-2);
lowpassArbSpec = fdesign.arbmag('N,B,F,A',N,B,F(1:2),A(1:2),F(3:end), ...
    A(3:end),Fs);
lpfilter = design(lowpassArbSpec,'equiripple','B2Weights',W, ...
    'SystemObject',true);
fvtool(lpfilter,'Fs',Fs,'Color','White');

最小位相ローパス フィルターの設計

ここまでは、線形位相設計のみを考慮しました。線形位相は多くの用途に適しています。言うまでもなく、線形位相が必要条件でない場合は、最小位相設計の方が線形位相設計よりも大幅な改善を期待できます。しかし、最小位相設計は常に数値的信頼性が高いわけではありません。必ず設計を FVTool でチェックしてください。

最小位相設計の利点の例として、同じ設計仕様を満たす線形位相設計と最小位相設計との比較を考えます。

Fp  = 20e3;
Fst = 22e3;
Fs  = 96e3;
Ap  = 0.06;
Ast = 80;
lowpassSpec = fdesign.lowpass('Fp,Fst,Ap,Ast',Fp,Fst,Ap,Ast,Fs);
linphaseSpec =  design(lowpassSpec,'equiripple','SystemObject',true);
eqripSpec =  design(lowpassSpec,'equiripple','minphase',true,...
    'SystemObject',true);
fvt = fvtool(linphaseSpec,eqripSpec,'Fs',Fs,...
    'Color','White');
legend(fvt,...
    'Linear-phase equiripple design',...
    'Minimum-phase equiripple design')

係数の数が 173 から 141 に減っています。群遅延プロットからも、最小位相設計の利点がわかります。群遅延が (特に通過帯域領域で) かなり小さいことに注意してください。

fvt = fvtool(linphaseSpec,eqripSpec,'Fs',Fs,...
    'Analysis','grpdelay','Color','White');
legend(fvt,...
    'Linear-phase equiripple design',...
    'Minimum-phase equiripple design')

多段手法を使用した最小次数ローパス フィルターの設計

最小位相設計に関連しない係数の数を最小化する別の方法に、多段手法の使用があります。ここでは内挿 FIR (IFIR) 法を紹介します。このアプローチでは、設計の問題をカスケード状の 2 つのフィルター設計に分割します。この例では、設計には 173 ではなく 151 の係数が必要です。詳細については、遷移帯域が狭い FIR フィルターの効率的な設計を参照してください。

Fp  = 20e3;
Fst = 22e3;
Fs  = 96e3;
Ap  = 0.06;
Ast = 80;
lowpassSpec = fdesign.lowpass('Fp,Fst,Ap,Ast',Fp,Fst,Ap,Ast,Fs);
interpFilter = design(lowpassSpec,'ifir','SystemObject',true);
cost(interpFilter)
fvt = fvtool(linphaseSpec,interpFilter,'Fs',Fs,'Color','White');
legend(fvt,...
    'Linear-phase equiripple design',...
    'Interpolated FIR equiripple design (two stages)')
ans = 

  struct with fields:

                  NumCoefficients: 151
                        NumStates: 238
    MultiplicationsPerInputSample: 151
          AdditionsPerInputSample: 149

この例では、群遅延プロットから IFIR 設計の欠点がわかります。IFIR 設計では線形位相が提供されますが、一般的に群遅延は同等の単一ステージ設計よりも大きくなります。

fvt = fvtool(linphaseSpec,interpFilter,'Fs',Fs,'Analysis','grpdelay',...
    'Color','White');
legend(fvt,...
    'Linear-phase equiripple design',...
    'Interpolated FIR equiripple design (two stages)')

マルチレートの用途向けローパス フィルターの設計

ローパス フィルターは間引きや内挿の設計に広く用いられています。この設計および効率的な実装となる多段手法の間引き/内挿の多段設計の詳細は、間引き/内挿の多段設計を参照してください。