Power spectrum estimation of autoregressive (AR) models (implementation)

The previous part introduced the theoretical knowledge of the AR model, and this part will introduce various estimation methods of the AR model. Click here for a quick review of theoretical knowledge. In these experiments, it is assumed that N=1024 and P=512.

Yule-Walker method

flow chart

Insert image description here

python code

import scipy
import numpy as np
from matplotlib import pyplot as plt


# 自相关函数
def x_corr(x):
    x_inv = x[::-1]
    # r_x = np.correlate(x, x)
    r_x = np.convolve(x, x_inv)
    r_x /= len(x)
    return r_x


if __name__ == "__main__":
    N = int(input("采样点数N:"))
    P = int(input("模型阶数P:"))
    # a_N [0, 1, ..., N-1]
    a_N = np.arange(0, N, 1)

    # 信号频率
    f1 = 0.1
    f2 = 0.13
    a_X = 2 * np.sin(2 * np.pi * f1 * a_N + np.pi / 3) + 10 * np.sin(2 * np.pi * f2 * a_N + np.pi / 4)

    # 自相关函数Rxx
    # Rxx(0), Rxx(1), ..., Rxx(N-1)
    Rxx = x_corr(a_X)[N-1:]
    # 取前P+1个
    # Rxx(0), Rxx(1), Rxx(P-1), Rxx(P)
    Rxx = Rxx[: P+1]

    # 自相关矩阵a_Rxx
    # [Rxx(0)   Rxx(1)   ... Rxx(p-1)]
    # [Rxx(-1)  Rxx(0)   ... Rxx(p-2)]
    # ...
    # [Rxx(1-p) Rxx(2-p) ... Rxx(0)  ]
    a_Rxx = np.zeros([P, P])
    for i in range(P):
        for j in range(P):
            a_Rxx[i, j] = Rxx[abs(i-j)]

    # 结果矩阵a_rx
    # [-Rxx(1)]
    # [-Rxx(2)]
    # ...
    # [-Rxx(p)]
    a_rx = np.zeros([P, 1])
    for i in range(P):
        a_rx[i, 0] = -Rxx[i + 1]

    # 系数矩阵a_apk
    # [a_p1]
    # [a_p2]
    # ...
    # [a_pp]
    a_Rxx_inv = np.linalg.inv(a_Rxx)
    a_apk = np.matmul(a_Rxx_inv, a_rx)

    # 标准差sigma
    sigma = Rxx[0]
    for i in range(P):
        sigma += a_apk[i, 0] * Rxx[i + 1]
    sigma = np.sqrt(sigma)

    # [ap1, ..., app]->[1, ap1, ..., app]
    a_ap = np.insert(a_apk, 0, [1])
    w, h = scipy.signal.freqz(sigma, a_ap, worN=N)

    Hf = abs(h)
    psd = Hf**2
    f = w / (2 * np.pi)

    plt.figure(1)
    plt.subplot(211)
    plt.plot(f, Hf)
    plt.xlabel("f/hz")
    plt.ylabel("Hf")

    plt.subplot(212)
    plt.plot(f, psd)
    plt.xlabel("f/hz")
    plt.ylabel("psd")
    plt.show()

Experimental results

Insert image description here

Levinson-Durbin method

flow chart

Insert image description here

python code

import numpy as np
import scipy
from matplotlib import pyplot as plt


def x_corr(a_x):
    a_x_inv = a_x[::-1]
    a_rx = np.convolve(a_x, a_x_inv)
    a_rx /= len(a_x)
    return a_rx


if __name__ == "__main__":
    N = int(input("采样点数N:"))
    P = int(input("模型阶数P:"))

    a_N = np.arange(N)
    # 信号频率
    f1 = 0.1
    f2 = 0.3
    # 信号
    a_X = 2 * np.sin(2 * np.pi * f1 * a_N + np.pi / 3) + 10 * np.sin(2 * np.pi * f2 * a_N + np.pi / 4)

    # 自相关函数Rx
    Rxx = x_corr(a_X)[N - 1:]
    Rxx = Rxx[: P + 1]

    # 初始化参数apk, sigma
    # p=1
    a_apk = np.zeros([P + 1, P + 1])
    a_apk[1, 1] = -Rxx[1] / Rxx[0]
    a_sigma = np.zeros(P + 1)
    a_sigma[1] = (1 - np.square(a_apk[1, 1])) * Rxx[0]

    # p>1
    for p in range(2, P + 1):
        kp_sum = 0
        for i in range(1, p):
            kp_sum += a_apk[p - 1, i] * Rxx[p - i]
        a_apk[p, p] = - (Rxx[p] + kp_sum) / a_sigma[p - 1]
        for k in range(1, p):
            a_apk[p, k] = a_apk[p - 1, k] + a_apk[p, p] * a_apk[p - 1, p - k]
        a_sigma[p] = (1 - np.square(a_apk[p, p])) * a_sigma[p - 1]
    
    a_ap = a_apk[- 1][1:]

    # a_apk = np.zeros([P, P])
    # a_apk[0, 0] = -Rxx[1] / Rxx[0]
    # a_sigma = np.zeros(P)
    # a_sigma[0] = (1 - np.square(a_apk[0, 0])) * Rxx[0]
    #
    # for p in range(1, P):
    #     kp_sum = 0
    #     for i in range(0, p):
    #         kp_sum += a_apk[p - 1, i] * Rxx[p - i]
    #     a_apk[p, p] = - (Rxx[p + 1] + kp_sum) / a_sigma[p - 1]
    #     for k in range(p):
    #         a_apk[p, k] = a_apk[p - 1, k] + a_apk[p, p] * a_apk[p - 1, p - k - 1]
    #     a_sigma[p] = a_sigma[p - 1] * (1 - np.square(a_apk[p, p]))

    # a_ap = a_apk[- 1]
    
    sigma = a_sigma[- 1]
    sigma = np.sqrt(sigma)
    a_ap = np.insert(a_ap, 0, [1])
    w, h = scipy.signal.freqz(sigma, a_ap, worN=N)

    Hf = abs(h)
    psd = Hf**2
    f = w / (2 * np.pi)

    plt.figure(1)
    plt.subplot(211)
    plt.plot(f, Hf)
    plt.xlabel("f/hz")
    plt.ylabel("Hf")

    plt.subplot(212)
    plt.plot(f, psd)
    plt.xlabel("f/hz")
    plt.ylabel("psd")
    plt.show()

Experimental results

Insert image description here

Burg method

flow chart

Insert image description here

python code

import numpy as np
import scipy
from matplotlib import pyplot as plt


def x_corr(a_x):
    a_x_inv = a_x[::-1]
    a_rx = np.convolve(a_x, a_x_inv)
    a_rx /= len(a_x)
    return a_rx


if __name__ == "__main__":
    N = int(input("采样点数N:"))  # 1024
    P = int(input("模型阶数P:"))  # 512
    a_N = np.arange(N)
    # 信号频率
    f1 = 0.1
    f2 = 0.13
    a_X = 2 * np.sin(2 * np.pi * f1 * a_N + np.pi / 3) + 10 * np.sin(2 * np.pi * f2 * a_N + np.pi / 4)

    a_epn = np.zeros([P+1, N])
    a_bpn = np.zeros([P+1, N])

    # 初始化e0n, b0n
    a_epn[0] = a_X
    a_bpn[0] = a_X
    # for i in range(N):
    #     a_epn[0, i] = a_X[i]
    #     a_bpn[0, i] = a_X[i]

    a_Kp = np.zeros(P+1)
    a_apk = np.zeros([P+1, P+1])
    a_sigma = np.zeros(P+1)

    # 初始化sigma1
    # a_sigma[0] = x_corr(a_X)[N-1:][0]
    sum1 = 0
    for n in range(N):
        sum1 += np.square(a_X[n])
    a_sigma[0] = sum1 / N

    for p in range(1, P+1):
        Kp_sum1 = 0
        Kp_sum2 = 0
        for n in range(p, N):
            Kp_sum1 += a_epn[p-1, n] * a_bpn[p-1, n-1]
            Kp_sum2 += np.square(a_epn[p-1, n]) + np.square(a_bpn[p-1, n-1])
        a_Kp[p] = -(2 * Kp_sum1) / Kp_sum2

        for n in range(p, N):
            a_epn[p, n] = a_epn[p-1, n] + a_Kp[p] * a_bpn[p-1, n-1]
            a_bpn[p, n] = a_bpn[p-1, n-1] + a_Kp[p] * a_epn[p-1, n]

    a_apk[1, 1] = a_Kp[1]
    a_sigma[1] = (1 - np.square(a_Kp[1])) * a_sigma[0]
    for p in range(2, P+1):
        a_apk[p, p] = a_Kp[p]
        for i in range(1, p):
            a_apk[p, i] = a_apk[p-1, i] + a_apk[p, p] * a_apk[p-1, p-i]
        a_sigma[p] = (1 - np.square(a_Kp[p])) * a_sigma[p - 1]

    a_ap = a_apk[-1][1:]
    sigma = np.sqrt(a_sigma[-1])
    a_ap = np.insert(a_ap, 0, [1])
    w, h = scipy.signal.freqz(sigma, a_ap, worN=N)
    Hf = abs(h)
    psd = Hf ** 2
    f = w / (2 * np.pi)

    plt.figure(1)
    plt.subplot(211)
    plt.plot(f, Hf)
    plt.xlabel("f/hz")
    plt.ylabel("Hf")

    plt.subplot(212)
    plt.plot(f, psd)
    plt.xlabel("f/hz")
    plt.ylabel("psd")
    plt.show()

Experimental results

Insert image description here

covariance method

Insert image description here

python code

I personally feel that there is something wrong with the code, but I don't know where the problem is. Could anyone please enlighten me.

import numpy as np
import scipy
from matplotlib import pyplot as plt


if __name__ == "__main__":
    N = int(input("采样点数N:"))
    P = int(input("模型阶数P:"))
    a_N = np.arange(N)
    # 信号频率
    f1 = 0.1
    f2 = 0.13
    a_X = 2 * np.sin(2 * np.pi * f1 * a_N + np.pi / 3) + 10 * np.sin(2 * np.pi * f2 * a_N + np.pi / 4)

    Cxx = np.zeros([P+1, P+1])
    for i in range(P+1):
        for k in range(P+1):
            sum_c = 0
            for n in range(P, N):
                sum_c += a_X[n-k] * a_X[n-i]
            Cxx[i, k] = sum_c / (N - P)

    a_Cxx = Cxx[1:, 1:]
    a_Cxx_inv = np.linalg.inv(a_Cxx)

    a_cx = Cxx[:, 0][1:]
    a_apk = np.matmul(a_Cxx_inv, -a_cx[:, None])

    sigma = Cxx[0, 0]
    for k in range(P):
        sigma += a_apk[k, 0] * Cxx[0, k + 1]
    sigma = np.sqrt(sigma)

    # [ap1, ..., app]->[1, ap1, ..., app]
    a_ap = np.insert(a_apk, 0, [1])
    w, h = scipy.signal.freqz(1, a_ap, worN=N)

    Hf = abs(h)
    psd = Hf**2
    f = w / (2 * np.pi)

    plt.figure(1)
    plt.subplot(211)
    plt.plot(f, Hf)
    plt.xlabel("f/hz")
    plt.ylabel("Hf")

    plt.subplot(212)
    plt.plot(f, psd)
    plt.xlabel("f/hz")
    plt.ylabel("psd")
    plt.show()

Experimental results

Insert image description here

modified covariance method

flow chart

Insert image description here

python code

There is also something wrong with this code. When setting p=512 and N=1024, the program keeps reporting errors. There is no way but to change it to p=512 to run normally. If you have any brothers and sisters, please send me a private message, thank you!

import numpy as np
import scipy
from matplotlib import pyplot as plt


if __name__ == "__main__":
    N = int(input("采样点数N:"))
    P = int(input("模型阶数P:"))
    a_N = np.arange(N)
    # 信号频率
    f1 = 0.1
    f2 = 0.13
    a_X = 2 * np.sin(2 * np.pi * f1 * a_N + np.pi / 3) + 10 * np.sin(2 * np.pi * f2 * a_N + np.pi / 4)

    Cxx = np.zeros([P+1, P+1])
    for i in range(P+1):
        for k in range(P+1):
            sum1 = 0
            sum2 = 0
            for n in range(P, N):
                sum1 += a_X[n-k] * a_X[n-i]
            for m in range(0, N-P):
                sum2 += a_X[m+k] * a_X[m+i]
            Cxx[i, k] = (sum1 + sum2) / (2 * (N - P))

    a_Cxx = Cxx[1:, 1:]
    a_Cxx_inv = np.linalg.inv(a_Cxx)

    a_cx = Cxx[:, 0][1:]
    a_apk = np.matmul(a_Cxx_inv, -a_cx[:, None])

    sigma = Cxx[0, 0]
    for k in range(P):
        sigma += a_apk[k, 0] * Cxx[0, k + 1]
    sigma = np.sqrt(sigma)

    # [ap1, ..., app]->[1, ap1, ..., app]
    a_ap = np.insert(a_apk, 0, [1])
    w, h = scipy.signal.freqz(sigma, a_ap, worN=N)

    Hf = abs(h)
    psd = Hf**2
    f = w / (2 * np.pi)

    plt.figure(1)
    plt.subplot(211)
    plt.plot(f, Hf)
    plt.xlabel("f/hz")
    plt.ylabel("Hf")

    plt.subplot(212)
    plt.plot(f, psd)
    plt.xlabel("f/hz")
    plt.ylabel("psd")
    plt.show()

Experimental results

Insert image description here

Guess you like

Origin blog.csdn.net/weixin_49346755/article/details/128093130