从幅度导出最小相位

信息处理 转换功能 希尔伯特变换
2022-02-18 21:53:22

如下所述,在 C++ 频域中具有所需的传递函数幅度,正确的相应最小相位是多少?一般来说,如果已知所需的幅度,特别是它的复数 IFFT 将返回一个完全实数的部分,那么如何在频域中导出正确的最小相位。

// PnCutoff.cpp : Pink noise above a cutoff.
#include <tchar.h>
#include <math.h>
#include <conio.h>

class PnAtFilter
{
    double _fcHz;
    public:
    PnAtFilter(double fcHz) { _fcHz = fcHz; }
    double Mag(double fHz)
    {
        if(fHz < _fcHz) return 1.0;
        else return  1.0 / sqrt(fHz/_fcHz);
    }
    double Phase(double fHz)
    {
        return 0.0; // what is the the correct minimum phase in r?
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    PnAtFilter* pnf = new PnAtFilter(1000);
    for(int fHz = 10; fHz <= 100000; fHz *= 10)
    {
        double mag = pnf->Mag(fHz); 
        double phase = pnf->Phase(fHz);
        _cprintf_s("%d Mag=%f, Phase=%f\r\n", fHz, mag, phase);
    }
    _getch();
    return 0;
}

/* output:
10 Mag=1.000000, Phase=0.000000
100 Mag=1.000000, Phase=0.000000
1000 Mag=1.000000, Phase=0.000000
10000 Mag=0.316228, Phase=0.000000
100000 Mag=0.100000, Phase=0.000000
*/
2个回答

查看 Julius O. Smith III 的文章

幅度响应之间存在希尔伯特变换关系,G(ω),以及相位响应,θ(ω),相关的最小相位滤波器。

如果

H(ω)=G(ω)exp(ȷθ(ω))
然后
ln(H(ω))=ln(G(ω))+jθ(ω)
θ(ω)=H[ln(G(ω))]
在哪里H是希尔伯特变换。

还可以查看维基百科的文章。

从仅幅度频率响应中近似最小相位传递函数的一种方法是首先在零极点 Z 平面域中找到传递函数的合适近似值。然后将所有零点反射到单位圆内以获得最小相位响应。第一部分有时被称为“系统识别问题”,通常没有封闭形式的解决方案。差分进化算法可能有用的是找到一个“足够接近”的零极点近似(似乎有关于这种方法的 IEEE 论文。参见 2005 年 1 月的 IEEE 信号处理杂志)。

当然,如果您可以对频率响应进行精确分解,那么解决方案就很简单了。(反射零等)

对于“平滑幅度响应”,另一个近似值是使用复杂倒谱的属性,如CCRMA的 JOS 所述。以下用于将任意 FIR 滤波器转换为最小相位近似值的脚本要求频率响应没有任何零点,以允许对给定幅度响应的倒谱实部进行近似反转。为了获得有用的结果,可能需要使用比给定幅度响应或初始 FIR 滤波器近似长得多的 FFT。

wn = [ones(1,m); 2*ones((n+odd)/2-1,m) ; ones(1-rem(n,2),m); zeros((n+od d)/2-1,m)];
y = real(ifft(exp(fft(wn .*  real(ifft(log(abs(fft(x)))))  ))));