def AR_psd(ak, sigma_v, n_freqs=1024, sides="onesided"): r""" Compute the PSD of an AR process, based on the process coefficients and covariance n_freqs : int The number of spacings on the frequency grid from [-PI,PI). If sides=='onesided', n_freqs/2+1 frequencies are computed from [0,PI] sides : str (optional) Indicates whether to return a one-sided or two-sided PSD Returns ------- (w, ar_psd) w : Array of normalized frequences from [-.5, .5) or [0,.5] ar_psd : A PSD estimate computed by sigma_v / |1-a(f)|**2 , where a(f) = DTFT(ak) """ # compute the psd as |H(f)|**2, where H(f) is the transfer function # for this model s[n] = a1*s[n-1] + a2*s[n-2] + ... aP*s[n-P] + v[n] # Taken as a IIR system with unit-variance white noise input e[n] # and output s[n], # b0*e[n] = w0*s[n] + w1*s[n-1] + w2*s[n-2] + ... + wP*s[n-P], # where b0 = sqrt(VAR{v[n]}), w0 = 1, and wk = -ak for k>0 # the transfer function here is H(f) = DTFT(w) # leading to Sxx(f)/Exx(f) = |H(f)|**2 = VAR{v[n]} / |W(f)|**2 w, hw = freq_response(sigma_v ** 0.5, a=np.r_[1, -ak], n_freqs=n_freqs, sides=sides) ar_psd = (hw * hw.conj()).real return (w, 2 * ar_psd) if sides == "onesided" else (w, ar_psd)
def AR_psd(ak, sigma_v, n_freqs=1024, sides='onesided'): r""" Compute the PSD of an AR process, based on the process coefficients and covariance n_freqs : int The number of spacings on the frequency grid from [-PI,PI). If sides=='onesided', n_freqs/2+1 frequencies are computed from [0,PI] sides : str (optional) Indicates whether to return a one-sided or two-sided PSD Returns ------- (w, ar_psd) w : Array of normalized frequences from [-.5, .5) or [0,.5] ar_psd : A PSD estimate computed by sigma_v / |1-a(f)|**2 , where a(f) = DTFT(ak) """ # compute the psd as |H(f)|**2, where H(f) is the transfer function # for this model s[n] = a1*s[n-1] + a2*s[n-2] + ... aP*s[n-P] + v[n] # Taken as a IIR system with unit-variance white noise input e[n] # and output s[n], # b0*e[n] = w0*s[n] + w1*s[n-1] + w2*s[n-2] + ... + wP*s[n-P], # where b0 = sqrt(VAR{v[n]}), w0 = 1, and wk = -ak for k>0 # the transfer function here is H(f) = DTFT(w) # leading to Sxx(f)/Exx(f) = |H(f)|**2 = VAR{v[n]} / |W(f)|**2 w, hw = freq_response(sigma_v**0.5, a=np.r_[1, -ak], n_freqs=n_freqs, sides=sides) ar_psd = (hw * hw.conj()).real return (w, 2 * ar_psd) if sides == 'onesided' else (w, ar_psd)
def transfer_function_xy(a, n_freqs=1024): r"""Helper routine to compute the transfer function H(w) based on sequence of coefficient matrices A(i). The z transforms follow from this definition: X[t] + sum_{k=1}^P a[k]X[t-k] = Err[t] Parameters ---------- a : ndarray, shape (P, 2, 2) sequence of coef matrices describing an mAR process n_freqs : int, optional number of frequencies to compute in range [0,PI] Returns ------- Hw : ndarray The transfer function from innovations process vector to mAR process X """ # these concatenations follow from the observation that A(0) is # implicitly the identity matrix ai = np.r_[1, a[:, 0, 0]] bi = np.r_[0, a[:, 0, 1]] ci = np.r_[0, a[:, 1, 0]] di = np.r_[1, a[:, 1, 1]] # compute A(w) such that A(w)X(w) = Err(w) w, aw = freq_response(ai, n_freqs=n_freqs) _, bw = freq_response(bi, n_freqs=n_freqs) _, cw = freq_response(ci, n_freqs=n_freqs) _, dw = freq_response(di, n_freqs=n_freqs) # A = np.array([ [1-aw, -bw], [-cw, 1-dw] ]) A = np.array([[aw, bw], [cw, dw]]) # compute the transfer function from Err to X. Since Err(w) is 1(w), # the transfer function H(w) = A^(-1)(w) # (use 2x2 matrix shortcut) detA = A[0, 0] * A[1, 1] - A[0, 1] * A[1, 0] Hw = np.array([[dw, -bw], [-cw, aw]]) Hw /= detA return w, Hw
def transfer_function_xy(a, n_freqs=1024): r"""Helper routine to compute the transfer function H(w) based on sequence of coefficient matrices A(i). The z transforms follow from this definition: X[t] + sum_{k=1}^P a[k]X[t-k] = Err[t] Parameters ---------- a : ndarray, shape (P, 2, 2) sequence of coef matrices describing an mAR process n_freqs : int, optional number of frequencies to compute in range [0,PI] Returns ------- Hw : ndarray The transfer function from innovations process vector to mAR process X """ # these concatenations follow from the observation that A(0) is # implicitly the identity matrix ai = np.r_[1, a[:, 0, 0]] bi = np.r_[0, a[:, 0, 1]] ci = np.r_[0, a[:, 1, 0]] di = np.r_[1, a[:, 1, 1]] # compute A(w) such that A(w)X(w) = Err(w) w, aw = freq_response(ai, n_freqs=n_freqs) _, bw = freq_response(bi, n_freqs=n_freqs) _, cw = freq_response(ci, n_freqs=n_freqs) _, dw = freq_response(di, n_freqs=n_freqs) #A = np.array([ [1-aw, -bw], [-cw, 1-dw] ]) A = np.array([[aw, bw], [cw, dw]]) # compute the transfer function from Err to X. Since Err(w) is 1(w), # the transfer function H(w) = A^(-1)(w) # (use 2x2 matrix shortcut) detA = (A[0, 0] * A[1, 1] - A[0, 1] * A[1, 0]) Hw = np.array([[dw, -bw], [-cw, aw]]) Hw /= detA return w, Hw