このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
任意の係数による効率的なサンプル レート変換
この例では、任意の係数間で効率的にサンプル レートを変換する方法を示します。
任意の係数によるサンプル レート変換は、数多くのアプリケーション (デジタル受信器のシンボルの同期、音声処理符号化および合成、連続時間システムのコンピューター シミュレーションなど) で必要になります。この例では、信号のサンプリング レートを 8 kHz から 44.1 kHz に変換する場合に、多項式ベースのフィルターおよびポリフェーズ フィルターのカスケードによって効率的なソリューションを形成できる例を見ていきます。
単一ポリフェーズ アプローチ
ポリフェーズ構造は、一般的にマルチレート フィルターの効率的な実装であると見なされます。ただし、分数のサンプル レート変換の場合には、位相数、したがってフィルターの次数が急激に過剰に高くなることがあります。信号を 8 kHz から 44.1 kHz にリサンプリングするために、441 で内挿し、80 で間引きます (8*441/80=44.1)。
sampRateConv = dsp.SampleRateConverter('Bandwidth',6e3, ... 'InputSampleRate',8e3,'OutputSampleRate',44.1e3, ... 'StopbandAttenuation',50);
これは、2 つの段により、比較的高い効率で実行できます。
info(sampRateConv)
ans = 'Overall Interpolation Factor : 441 Overall Decimation Factor : 80 Number of Filters : 2 Multiplications per Input Sample: 95.175000 Number of Coefficients : 1774 Filters: Filter 1: dsp.FIRRateConverter - Interpolation Factor: 147 - Decimation Factor : 80 Filter 2: dsp.FIRInterpolator - Interpolation Factor: 3 '
cost(sampRateConv)
ans = struct with fields:
NumCoefficients: 1774
NumStates: 30
MultiplicationsPerInputSample: 95.1750
AdditionsPerInputSample: 89.6750
入力サンプルあたりの演算数 (1 段目の終了後に周波数が 14.7 kHz に増加することを考慮して、約 95 の乗算と加算) は妥当な数ですが、この場合には 1774 の係数をメモリに格納しなければなりません。
出力レートの許容誤差の設定
多数の係数を軽減する方法の 1 つは、出力サンプルの正確なレートが重要でない場合にはレートの許容誤差を設けることです。たとえば、許容誤差 1% を設定すると、出力レートは 44.1 kHz ではなく 44 kHz になります。これは、11 で内挿して 2 で間引きする必要があります。これは単一の段で効率的に実行できます。
sampRateConvWithTol = dsp.SampleRateConverter('Bandwidth',6e3, ... 'InputSampleRate',8e3,'OutputSampleRate',44.1e3, ... 'StopbandAttenuation',50,'OutputRateTolerance',0.01); cost(sampRateConvWithTol)
ans = struct with fields:
NumCoefficients: 120
NumStates: 12
MultiplicationsPerInputSample: 60
AdditionsPerInputSample: 55
この場合、120 係数が必要で、入力サンプルあたりの乗算の数は 60 です。
単一 Farrow アプローチ
多数の係数を保存しなければならないという問題を克服するもう 1 つの方法は、多項式ベースのフィルターです。Farrow 構造は、このようなフィルターの効率的な実装です。
farrowSampRateConv_3rd = dsp.FarrowRateConverter('InputSampleRate',8e3, ... 'OutputSampleRate',44.1e3,'PolynomialOrder',3); farrowSampRateConv_4th = dsp.FarrowRateConverter('InputSampleRate',8e3, ... 'OutputSampleRate',44.1e3,'PolynomialOrder',4); cost(farrowSampRateConv_3rd)
ans = struct with fields:
NumCoefficients: 16
NumStates: 3
MultiplicationsPerInputSample: 66.1500
AdditionsPerInputSample: 60.6375
cost(farrowSampRateConv_4th)
ans = struct with fields:
NumCoefficients: 25
NumStates: 4
MultiplicationsPerInputSample: 121.2750
AdditionsPerInputSample: 99.2250
3 次多項式では、16 の係数と入力サンプルあたり約 66 の乗算が必要です。4 次多項式は、より高コストでわずかに優れたローパス応答を提供します。係数は 25、入力サンプルあたりの乗算は 121 です。
filts = getFilters(sampRateConv); W = linspace(0,44.1e3,2048); % Define the frequency range analysis Fs1 = 8e3*147; % The equivalent single stage filter is clocked at 3.53 MHz hfvt = fvtool(filts.Stage1,farrowSampRateConv_3rd, ... farrowSampRateConv_4th,'FrequencyRange','Specify freq. vector', ... 'FrequencyVector',W,'Fs',[Fs1 3*Fs1 3*Fs1], ... 'NormalizeMagnitudeto1','on','Color','white'); legend(hfvt,'Polyphase Sample-Rate Converter', ... '3rd-Order Farrow Interpolator','4th-Order Farrow Interpolator', ... 'Location','NorthEast')
出力レートの許容誤差を設定しても、Farrow フィルターの実装コストには大きな影響はありません。しかし、dsp.SampleRateConverter と同様に、内挿係数と間引き係数は変わります。
farrowSampRateConv_4th = dsp.FarrowRateConverter('InputSampleRate',8e3, ... 'OutputSampleRate',44.1e3,'PolynomialOrder',4, ... 'OutputRateTolerance',0.01); info(farrowSampRateConv_4th)
ans = 12x52 char array
'Discrete-Time FIR Multirate Filter (real) '
'----------------------------------------- '
'Filter Structure : Farrow Sample-Rate Converter'
'Interpolation Factor : 11 '
'Decimation Factor : 2 '
'Filter Length : 5 '
'Stable : Yes '
'Linear Phase : No '
' '
'Arithmetic : double '
'Output Rate Tolerance : 1.000000 % '
'Adjusted Output Rate : 44000.000000 '
cost(farrowSampRateConv_4th)
ans = struct with fields:
NumCoefficients: 25
NumStates: 4
MultiplicationsPerInputSample: 121
AdditionsPerInputSample: 99
Farrow および FIR ポリフェーズ構造のカスケード
次に、これまでに見てきた 2 種類のフィルターを利用した複合ソリューションを設計してみましょう。ポリフェーズ フィルターは、整数ファクターによる内挿または間引きと、内挿係数および間引き係数が低い非整数レート変換に特に適しています。Farrow フィルターは任意の (無理数を含む) レート変換ファクターを効果的に実装できます。まず、FIR ハーフバンド フィルターのカスケードを使用して、元の 8 kHz 信号を 4 で内挿します。
intSampRateConv = dsp.SampleRateConverter('Bandwidth',6e3, ... 'InputSampleRate',8e3,'OutputSampleRate',32e3, ... 'StopbandAttenuation',50); info(intSampRateConv)
ans = 'Overall Interpolation Factor : 4 Overall Decimation Factor : 1 Number of Filters : 1 Multiplications per Input Sample: 34.000000 Number of Coefficients : 34 Filters: Filter 1: dsp.FIRInterpolator - Interpolation Factor: 4 '
次に、44.1/32 = 1.378125 によって中間の 32 kHz 信号を内挿し、目的の最終的な 44.1 kHz のサンプリング周波数を取得します。この目的には 3 次ラグランジュ多項式ベース フィルターを使用します。
farrowSampRateConv = dsp.FarrowRateConverter('InputSampleRate',32e3, ... 'OutputSampleRate',44.1e3,'PolynomialOrder',3);
全体的なフィルターは、単に 2 つのフィルターをカスケードすることで求めます。
cost(intSampRateConv)
ans = struct with fields:
NumCoefficients: 34
NumStates: 11
MultiplicationsPerInputSample: 34
AdditionsPerInputSample: 31
cost(farrowSampRateConv)
ans = struct with fields:
NumCoefficients: 16
NumStates: 3
MultiplicationsPerInputSample: 16.5375
AdditionsPerInputSample: 15.1594
このハイブリッド設計の係数の数は比較的低く (36)、入力サンプルあたりの乗算の数も比較的低くなります 28 + 16*4 = 92.これら 2 つの設計の周波数応答の結合は、farrowSampRateConv_3rd
または farrowSampRateConv_4th
より優れています。
[Hsrc,f] = freqz(intSampRateConv); Fsfar = 32e3*441; Hfsrc = freqz(farrowSampRateConv,f,Fsfar); Hhybrid = Hsrc.*Hfsrc; Hhybrid_norm = Hhybrid/norm(Hhybrid,inf); % Normalize magnitude to 0 dB plot(f,20*log10(abs(Hhybrid_norm))); xlabel('Frequency (Hz)') ylabel('Magnitude (dB)') legend('Combined polyphase and Farrow sample rate converters', ... 'Location','NorthEast')
次に、単一設計と多段設計の周波数応答を重ねます。応答は、明らかに非常に近いものとなっています。
scope = spectrumAnalyzer('SampleRate',44.1e3,'PlotAsTwoSidedSpectrum',false, ... 'YLimits',[-80 20],'ShowLegend',true, ... 'ChannelNames',{'Single-stage design','Multi-stage design'}); tic, while toc < 20 % Run for 20 seconds x = randn(8000,1); % Convert rate using multistage FIR filters y1 = sampRateConv(x); % Convert rate using cascade of multistage FIR and Farrow filter ytemp = intSampRateConv(x); y2 = farrowSampRateConv(ytemp); % Compare the output from both approaches scope([y1,y2]) end