|
|
ru.algorithms- RU.ALGORITHMS ---------------------------------------------------------------- From : Alexander Rebrov 2:5000/115.17 11 Nov 2001 23:43:36 To : Aleksey V Vaneev Subject : Re: FFT -------------------------------------------------------------------------------- 09 ноября 2001 21:37, you wrote to me: AV>>> она веpхи (imho, выше 10кГц) pубает почем зpя. AR>> 4-х точечная кубическая? Если да, то она, имхо, ничего AR>> не обpезает. AV> Если бы это было так, то зачем было бы использовать формулы более AV> высокого порядка? :) А вообще, она, imho, дает т.н. "muddy sound". AV> Чистый, но нечеткий. Hаверное, по фазам перекос дает. Ты кубическую так? делаешь? Я попробовал результат работы в виде графика посмотреть. По-моему Hикаких перекосов. А то что звук Hе совсем четкий - так это точек все же маловато. ===> fPosition := fPosition + fRatio; nPosition := Trunc (fPosition); p := fPosition - nPosition; q := (1.0 - p); if nOldPos <> nPosition Then Begin pBPos := pBPos + (nPosition - nOldPos); If pBPos > nInSize - 2 Then Begin Result:=samp; Exit; End; ABCD := pIn^[pBPos] - pIn^[pBPos-1] + pIn^[pBPos+1] - pIn^[pBPos+2]; CB := pIn^[pBPos+1] - pIn^[pBPos]; B := pIn^[pBPos]; nOldPos := nPosition; End; tmp := B + p*(0.25*q*ABCD+CB); if tmp > 32767 Then pOut^[samp] := 32767 Else if tmp < -32767 Then pOut^[samp] := -32767 Else pOut^[samp] := Round (tmp); Inc (Samp); ===> AR>> А вообще есть windowed-sinc с окном Кайзеpа. Качество идеальное. AR>> Там этих точек хоть миллион задавай. Пpобовал пpимеpно со 170 до AR>> 44100 интеpполиpовать - абсолютно чистый звук (эс-ноодни низы). AV> А у тебя есть исходники, может, зашлешь мылом? А вот sinc иHтерполяция. Тут кто-то тоже Hасчет этого базарит, поэтому сюда закиHу: ===> Const MaxInterpFilterSize = 16384; var // Массив значений фильтра (т.н. impulse response) InterpFilterImp: Array [0..MaxInterpFilterSize-1] Of Single; // Массив разниц: FilterImpDeltas[i]:=FilterImp[i+1]-FilterImp[i] // Служит для быстрой линейной интерполяции фильтра(!), т.е. // к интерполирующему фильтру применяется линейная интерполяция. InterpFilterImpDeltas: Array [0..MaxInterpFilterSize-1] Of Single; // Количество точек интерполяции в одну сторону InterpNumPoints: Integer; // Количество значений функции в одном периоде InterpFilterPeriodSize: Integer; // Количество значений фильтра InterpFilterSize: Integer; { NumPoints - количество точек интерполяции в одну сторону. Так как при интерполяции половина значений берется по левую сторону от текущего сэмпла, а половина - по правую, то общее количество точек интерполяции равно NumPoints*2. В связи с этим и количество периодов функции фильтра равно NumPoints. PeriodSize - количество значений функции фильтра в одном периоде. Чем больше значений - тем выше точность интерполяции. Общее кол-во значений массива равно NumPoints*PeriodSize. FrqRoll - коэффициент ФЧ, должен быть от 0 до 1; определает частоту среза. ачинает обрезать частоты свыше FrqRoll*оваяЧастотаДикретизации/2. Beta - сам не понял, но это параметр окна Кайзера. Вроде как влияет на соотношение сигнал/шум. Вот описание на англ. Beta trades the rejection of the lowpass filter against the" transition width from passband to stopband. Larger Beta means" a slower transition and greater stopband rejection. See Rabiner" and Gold (Th. and App. of DSP) under Kaiser windows for more about" Beta. The following table from Rabiner and Gold (p. 101) gives some" feel for the effect of Beta:" BETA D PB RIP SB RIP" 2.120 1.50 +-0.27 -30" 3.384 2.23 0.0864 -40" 4.538 2.93 0.0274 -50" 5.658 3.62 0.00868 -60" 6.764 4.32 0.00275 -70" 7.865 5.0 0.000868 -80" 8.960 5.7 0.000275 -90" 10.056 6.4 0.000087 -100" Above, ripples are in dB, and the transition band width is " approximately D*Fs/N, where Fs = sampling rate, " and N = window length. PB = 'pass band' and SB = 'stop band'." Alternatively, D is the transition widths in bins given a" length N DFT (i.e. a window transform with no zero padding." } Function CreateFilter (NumPoints, PeriodSize: Integer; FrqRoll, Beta: Single): Boolean; Function Izero (X: Double): Double; Const IzeroEPSILON = 1E-21; // Max error acceptable in Izero Var Sum, U, HalfX, Temp: Double; N: Integer; Begin Sum := 1; U := 1; N := 1; HalfX := X * 0.5; Repeat Temp := HalfX / N; Inc (N); Temp := Temp * Temp; U := U * Temp; Sum := Sum + U; Until U < IzeroEPSILON * Sum; Result := Sum; End; Var IBeta, Temp1, Temp2, Inm1, alpha, alpha1, alpha2: Double; I: Integer; Begin InterpNumPoints := NumPoints; InterpFilterPeriodSize := PeriodSize; InterpFilterSize := NumPoints * PeriodSize; // Проверяем размер массива If InterpFilterSize > MaxInterpFilterSize Then Begin Result := False; Exit; End; // Calculate ideal lowpass filter impulse response coefficients: alpha := sin (pi / (InterpFilterSize - 1)) / sin (2 * pi / (InterpFilterSize - 1)); alpha := alpha * alpha; alpha1 := (alpha + 1) / 2; alpha2 := alpha / 2; InterpFilterImp[0] := FrqRoll; IBeta := 1.0 / Izero (Beta); Inm1 := 1.0 / (InterpFilterSize-1); For I:=1 To InterpFilterSize-1 Do Begin // по идее сначала нужно посчитать все значения InterpFilterImp, // затем найти максимальное, вычислить коэффициент, при умножении на // который это максимальное будет равно еденице, а затем перемножить // все значения фильтра на этот коэффициент и затем уж посчитать // InterpFilterImpDeltas. о на практике оказалось, что оно вроде как // изначально все правильно. Temp1 := PI * I / PeriodSize; Temp2 := I * Inm1; // Analog sinc-функции, частота среза = FrqRoll // В принципе, функция sinc(x)=sin(pi*x)/(pi*x) - это та же самая // интерполяционная функция Лагранжа, только проще. InterpFilterImp[i] := sin (Temp1 * FrqRoll) / Temp1 * // Calculate and Apply Kaiser window to ideal lowpass filter. // Note: last window value is IBeta which is NOT zero. // You're supposed to really truncate the window here, not ramp // it to zero. This helps reduce the first sidelobe. Izero (Beta * sqrt (1.0 - temp2 * temp2)) * IBeta; InterpFilterImpDeltas[i-1]:=InterpFilterImp[i]-InterpFilterImp[i-1]; End; // Последний коэффициент не интерполируется InterpFilterImpDeltas[InterpFilterSize-1] := -InterpFilterImp[InterpFilterSize-1]; Result := True; End; { ****************************************************** SincInterpolation *** } Function SincInterpolation (fRatio: Single; pIn, pOut: PSmallIntArray; nInSize: Integer; nOutSize: Integer; FLF: Boolean): Integer; Var samp, x, tmp, Hoi: Integer; v, t, Ho, dh: double; nPosition: Integer; // index of first sample fPosition, p: Single; // floating point position accumulator sum1: integer; sum2: double; points: integer; PC: integer; Begin points:=8; // В принципе, создать фильтр нужно только один раз. CreateFilter (points, 512, 1, 9.5); // Initial input array element pointer nPosition:= 0; // index of first sample fPosition:= 0.0; // floating point position accumulator // Filter sampling period dh := InterpFilterPeriodSize; // for all output samples pOut^[0]:=pIn^[0]; samp := 0; // =1 p:=0; If FLF Then While samp < nOutSize Do // с фильтром Ч Begin // THE EQUATION v:=0; x:=nPosition; Ho := p * dh; PC:=0; While Ho < InterpFilterSize Do Begin if x<0 Then Break; Hoi:=Trunc(Ho); v:=v+pIn^[x]*(InterpFilterImp[Hoi]+(Ho-Hoi)*InterpFilterImpDeltas[H oi]); Ho:=Ho+dh; x:=x-1; Inc (PC); End; If PC<Points then PC:=3; PC:=0; x:=nPosition+1; Ho := (1-p) * dh; // If (1-p)=0 Then Ho:=Ho+dh; While Ho < InterpFilterSize Do Begin if x>=nInSize Then Break; Hoi:=Trunc(Ho); v:=v+pIn^[x]*(InterpFilterImp[Hoi]+(Ho-Hoi)*InterpFilterImpDeltas[H oi]); Ho:=Ho+dh; x:=x+1; Inc (PC); End; If PC<Points then PC:=3; tmp:=Round(v); // SATURATE AND WRITE RESULTS if tmp > 32767 Then pOut^[samp] := 32767 Else if tmp < -32767 Then pOut^[samp] := -32767 Else pOut^[samp] := Round (tmp); Inc (Samp); // increment position by the ratio of # of in samples to # of out samples fPosition := fPosition + fRatio; nPosition := Trunc (fPosition); p := fPosition - nPosition; If nPosition > nInSize Then Break; End Else While samp < nOutSize Do Begin // THE EQUATION v:=0; x:=nPosition; Ho := p * dh; While Ho < InterpFilterSize Do Begin if x<0 Then Break; Hoi:=Trunc(Ho); v:=v+pIn^[x]*InterpFilterImp[Hoi]; Ho:=Ho+dh; x:=x-1; End; x:=nPosition+1; Ho := (1-p) * dh; If (1-p)=0 Then Ho:=Ho+dh; While Ho < InterpFilterSize-1 Do Begin if x>=nInSize Then Break; Hoi:=Trunc(Ho); v:=v+pIn^[x]*InterpFilterImp[Hoi]; Ho:=Ho+dh; x:=x+1; End; tmp:=Round(v); // SATURATE AND WRITE RESULTS if tmp > 32767 Then pOut^[samp] := 32767 Else if tmp < -32767 Then pOut^[samp] := -32767 Else pOut^[samp] := Round (tmp); Inc (Samp); // increment position by the ratio of # of in samples to # of out samples fPosition := fPosition + fRatio; nPosition := Trunc (fPosition); p := fPosition - nPosition; If nPosition > nInSize Then Break; End; Result:=Samp; End; ===> Alexander --- * Origin: (2:5000/115.17) Вернуться к списку тем, сортированных по: возрастание даты уменьшение даты тема автор
Архивное /ru.algorithms/174343beeff33.html, оценка из 5, голосов 10
|