自己相関・相互相関の理論とPython実装

自己相関関数(ACF)と相互相関関数(CCF)の数学的定義・性質から、周期性検出・遅延推定・音声ピッチ推定・時系列分析への応用まで、Pythonで体系的に解説します。

はじめに

「この信号にはどんな周期性が隠れているか?」「2つのセンサーの信号はどれだけ遅延しているか?」—こうした問いに答える基本的なツールが相関関数です。

**自己相関関数(ACF: Autocorrelation Function)**は信号とそれ自身の遅延コピーの類似度を測り、信号の周期性・繰り返し構造を明らかにします。一方、**相互相関関数(CCF: Cross-Correlation Function)**は2つの異なる信号間の類似度と遅延を定量化します。これらは信号処理・統計・機械学習の多くの分野で基礎的な役割を果たしています。

本記事では自己相関・相互相関の数学的定義から、FFTを用いた高速計算法、音声ピッチ推定・遅延推定・時系列分析への実践的な応用まで、Pythonで体系的に解説します。

自己相関関数(ACF)の定義と性質

連続時間の自己相関

連続時間信号 \(x(t)\) のエネルギー有限信号(決定論的信号)の自己相関関数は以下のように定義されます。

\[R_{xx}(\tau) = \int_{-\infty}^{\infty} x(t) \cdot x(t + \tau) \, dt \tag{1}\]

確率過程(確率的信号)の場合は期待値で定義されます。

\[R_{xx}(\tau) = E[x(t) \cdot x(t + \tau)] \tag{2}\]

ここで \(\tau\) は**ラグ(遅延)**と呼ばれるパラメータです。

離散時間の自己相関

長さ \(N\) の離散時間信号 \(x[n]\) の自己相関は次のように定義されます。

\[R_{xx}[l] = \sum_{n=-\infty}^{\infty} x[n] \cdot x[n + l] \tag{3}\]

実用的には正規化自己相関(最大値を1に正規化)を使うことが多く、これにより信号のスケールに依存しない類似度指標が得られます。

\[\rho_{xx}[l] = \frac{R_{xx}[l]}{R_{xx}[0]} \tag{4}\]

\(R_{xx}[0] = \sum_n x[n]^2\) は信号のエネルギー(または分散に比例)であり、常に正です。

ACFの重要な性質

偶関数性(対称性)

\[R_{xx}[-l] = R_{xx}[l] \tag{5}\]

これはラグの符号を反転しても値が変わらないことを意味します。

最大値性

\[|R_{xx}[l]| \leq R_{xx}[0] \quad \text{for all } l \tag{6}\]

正規化すると \(|\rho_{xx}[l]| \leq 1\) となります。

周期信号との関係:信号 \(x[n]\) が周期 \(T\) を持つ場合、ACFも同じ周期 \(T\) を持ちます。

\[x[n + T] = x[n] \Rightarrow R_{xx}[l + T] = R_{xx}[l] \tag{7}\]

ウィーナー・ヒンチン定理:自己相関関数のフーリエ変換は**パワースペクトル密度(PSD)**に等しいです。

\[S_{xx}(f) = \mathcal{F}\{R_{xx}[\tau]\}(f) \tag{8}\]

これは自己相関とパワースペクトルが同等の情報を異なる表現で持つことを示す重要な定理です。

相互相関関数(CCF)の定義

2つの信号 \(x[n]\) と \(y[n]\) の相互相関関数は以下のように定義されます。

\[R_{xy}[l] = \sum_{n=-\infty}^{\infty} x[n] \cdot y[n + l] \tag{9}\]

\(R_{xy}[l]\) が最大となるラグ \(l^*\) が、\(y\) が \(x\) より進んでいる(または遅れている)サンプル数を示します。

\[l^* = \arg\max_l R_{xy}[l] \tag{10}\]

相互相関は一般に対称でないことに注意が必要です。

\[R_{xy}[l] \neq R_{xy}[-l] \quad \text{(一般に)} \tag{11}\]

ただし以下の共役対称性があります。

\[R_{xy}[-l] = R_{yx}[l] \tag{12}\]

正規化相互相関係数は以下のように定義されます。

\[\rho_{xy}[l] = \frac{R_{xy}[l]}{\sqrt{R_{xx}[0] \cdot R_{yy}[0]}} \tag{13}\]

\(|\rho_{xy}[l]| \leq 1\) が保証され、1に近いほど2つの信号の類似度が高いことを示します。

FFTを用いた高速相関計算

直接計算による自己相関の計算量は \(O(N^2)\) ですが、FFTの畳み込み定理を利用することで \(O(N \log N)\) に削減できます。

時間領域の相関は周波数領域では複素共役の積に対応します。

\[R_{xy}[l] = \mathcal{F}^{-1}\{X^*(f) \cdot Y(f)\} \tag{14}\]

ここで \(X^*(f)\) は \(X(f)\) の複素共役です。自己相関の場合は \(Y = X\) なので:

\[R_{xx}[l] = \mathcal{F}^{-1}\{|X(f)|^2\} \tag{15}\]

\(|X(f)|^2\) はまさにパワースペクトルであり、ウィーナー・ヒンチン定理と一致します。

Python実装

基本的な自己相関・相互相関の計算

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import correlate, correlation_lags

# --- テスト信号の生成 ---
np.random.seed(42)
fs = 1000      # サンプリング周波数 [Hz]
T = 2.0        # 信号長 [s]
t = np.arange(0, T, 1/fs)

# 信号1: 50Hzの正弦波 + ノイズ
x = np.sin(2 * np.pi * 50 * t) + 0.3 * np.random.randn(len(t))

# 信号2: xを100サンプル遅延させたもの + 異なるノイズ
delay_samples = 100
y = np.zeros_like(x)
y[delay_samples:] = x[:-delay_samples] + 0.3 * np.random.randn(len(t) - delay_samples)

# --- 自己相関 ---
def autocorr_fft(x):
    """FFTを用いた高速自己相関計算(正規化あり)"""
    N = len(x)
    # ゼロパディングして循環誤差を防ぐ
    X = np.fft.fft(x, n=2*N)
    # パワースペクトル → 逆FFT
    acf = np.fft.ifft(X * np.conj(X)).real
    # 正の遅延部分のみ取得し、正規化
    acf = acf[:N]
    acf /= acf[0]  # 正規化
    return acf

# --- 相互相関 ---
# scipy.signal.correlate は完全な相関を計算
corr_xy = correlate(x, y, mode='full')
lags = correlation_lags(len(x), len(y), mode='full')

# 正規化
norm = np.sqrt(np.sum(x**2) * np.sum(y**2))
corr_xy_normalized = corr_xy / norm

# --- プロット ---
fig, axes = plt.subplots(3, 1, figsize=(12, 10))

# 元の信号
axes[0].plot(t[:500], x[:500], label='x(t)', alpha=0.8)
axes[0].plot(t[:500], y[:500], label=f'y(t) = x(t - {delay_samples/fs*1000:.0f}ms)',
             alpha=0.8)
axes[0].set_xlabel('Time [s]')
axes[0].set_ylabel('Amplitude')
axes[0].set_title('Input Signals')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 自己相関
acf = autocorr_fft(x)
lag_times = np.arange(len(acf)) / fs * 1000  # ms単位
axes[1].plot(lag_times, acf)
axes[1].axhline(y=0, color='k', linestyle='--', linewidth=0.8)
axes[1].set_xlabel('Lag [ms]')
axes[1].set_ylabel('Normalized ACF')
axes[1].set_title('Autocorrelation of x(t): Peak at 20 ms → 50 Hz')
axes[1].set_xlim(0, 100)
axes[1].grid(True, alpha=0.3)
# 最初のピーク検出(ラグ0を除く)
first_peak_idx = np.argmax(acf[10:]) + 10
print(f"ACF最初のピーク: lag={first_peak_idx/fs*1000:.1f} ms → "
      f"周波数 = {fs/first_peak_idx:.1f} Hz")

# 相互相関
axes[2].plot(lags / fs * 1000, corr_xy_normalized)
axes[2].axhline(y=0, color='k', linestyle='--', linewidth=0.8)
axes[2].set_xlabel('Lag [ms]')
axes[2].set_ylabel('Normalized CCF')
axes[2].set_title(f'Cross-Correlation: Peak at lag = {delay_samples/fs*1000:.0f} ms')
axes[2].set_xlim(-300, 300)
axes[2].grid(True, alpha=0.3)

# 最大相関のラグを表示
peak_lag = lags[np.argmax(corr_xy_normalized)]
print(f"相互相関ピーク: lag={peak_lag/fs*1000:.1f} ms → "
      f"遅延 = {peak_lag} サンプル")

plt.tight_layout()
plt.show()

ACFによる周期性検出

import numpy as np
import matplotlib.pyplot as plt

def detect_periodicity(signal, fs, max_lag_sec=None):
    """
    ACFを用いた周期性検出。

    Parameters
    ----------
    signal : np.ndarray
        入力信号
    fs : float
        サンプリング周波数 [Hz]
    max_lag_sec : float, optional
        解析する最大ラグ [s]。省略時は信号長の半分。

    Returns
    -------
    period_sec : float or None
        検出された周期 [s](検出されない場合は None)
    acf : np.ndarray
        正規化ACF
    lags_sec : np.ndarray
        ラグ [s]
    """
    N = len(signal)
    max_lag = int(max_lag_sec * fs) if max_lag_sec else N // 2

    # FFTベースのACF
    X = np.fft.fft(signal, n=2*N)
    acf = np.fft.ifft(X * np.conj(X)).real[:N]
    acf = acf[:max_lag]
    acf_norm = acf / acf[0]
    lags_sec = np.arange(max_lag) / fs

    # 最初のピーク(ゼロクロス後の最大値)を検出
    # まずゼロクロスを探す
    zero_cross = np.where(np.diff(np.sign(acf_norm)))[0]
    if len(zero_cross) < 2:
        return None, acf_norm, lags_sec

    search_start = zero_cross[0] + 1
    search_end = zero_cross[1] if len(zero_cross) > 1 else max_lag
    peak_idx = search_start + np.argmax(acf_norm[search_start:search_end])
    period_sec = lags_sec[peak_idx]

    return period_sec, acf_norm, lags_sec


# --- 複数の信号で周期性を比較 ---
fs = 1000
t = np.arange(0, 1.0, 1/fs)
np.random.seed(0)

signals = {
    '50 Hz 正弦波': np.sin(2 * np.pi * 50 * t) + 0.2 * np.random.randn(len(t)),
    '複合正弦波\n(50 + 130 Hz)': (np.sin(2 * np.pi * 50 * t)
                                   + 0.5 * np.sin(2 * np.pi * 130 * t)
                                   + 0.1 * np.random.randn(len(t))),
    'ホワイトノイズ': np.random.randn(len(t)),
}

fig, axes = plt.subplots(len(signals), 2, figsize=(14, 10))

for i, (name, sig) in enumerate(signals.items()):
    period, acf, lags = detect_periodicity(sig, fs, max_lag_sec=0.15)

    axes[i, 0].plot(t[:300], sig[:300])
    axes[i, 0].set_xlabel('Time [s]')
    axes[i, 0].set_ylabel('Amplitude')
    axes[i, 0].set_title(f'Signal: {name}')
    axes[i, 0].grid(True, alpha=0.3)

    axes[i, 1].plot(lags * 1000, acf)
    axes[i, 1].axhline(y=0, color='k', linestyle='--', linewidth=0.8)
    if period:
        axes[i, 1].axvline(x=period * 1000, color='r', linestyle='--',
                           label=f'Period={period*1000:.1f} ms\n{1/period:.1f} Hz')
        axes[i, 1].legend(fontsize=9)
    axes[i, 1].set_xlabel('Lag [ms]')
    axes[i, 1].set_ylabel('Normalized ACF')
    axes[i, 1].set_title('Autocorrelation')
    axes[i, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

相互相関による遅延推定(GCC-PHAT)

マイクロフォンアレイ等での音源定位では、2つのマイクに到達する音の**到達時間差(TDOA: Time Difference of Arrival)を推定します。単純な相互相関よりGCC-PHAT(Generalized Cross-Correlation with Phase Transform)**が位置推定精度が高いとして広く使われます。

\[\hat{R}^{\text{PHAT}}_{xy}[l] = \mathcal{F}^{-1}\left\{\frac{X(f) Y^*(f)}{|X(f) Y^*(f)|}\right\} \tag{16}\]

分母で振幅スペクトルを正規化することで、特定周波数成分への依存が減り、ノイズ耐性が向上します。

import numpy as np
import matplotlib.pyplot as plt

def gcc_phat(x, y, fs, max_delay=None):
    """
    GCC-PHAT による遅延推定。

    Parameters
    ----------
    x, y : np.ndarray
        2つの入力信号
    fs : float
        サンプリング周波数 [Hz]
    max_delay : float, optional
        探索する最大遅延 [s]

    Returns
    -------
    delay_sec : float
        推定遅延 [s](y は x より delay_sec 遅れている)
    cc : np.ndarray
        GCC-PHAT の相関値
    lags_sec : np.ndarray
        ラグ [s]
    """
    N = len(x) + len(y) - 1
    N_fft = 2 ** int(np.ceil(np.log2(N)))

    X = np.fft.fft(x, n=N_fft)
    Y = np.fft.fft(y, n=N_fft)

    # GCC-PHAT: 位相のみ利用
    G = X * np.conj(Y)
    G_phat = G / (np.abs(G) + 1e-10)  # 数値安定化
    cc = np.fft.ifft(G_phat).real

    # lags の計算
    lags = np.fft.fftfreq(N_fft, d=1) * N_fft
    lags = lags.astype(int)

    # fftshift して中心をゼロラグに
    cc_shifted = np.fft.fftshift(cc)
    lags_shifted = np.fft.fftshift(lags)
    lags_sec = lags_shifted / fs

    if max_delay:
        mask = np.abs(lags_sec) <= max_delay
        cc_shifted = cc_shifted[mask]
        lags_sec = lags_sec[mask]

    peak_idx = np.argmax(cc_shifted)
    delay_sec = lags_sec[peak_idx]

    return delay_sec, cc_shifted, lags_sec


# --- テスト ---
fs = 16000
t = np.arange(0, 0.5, 1/fs)
np.random.seed(7)

# 音源信号
source = np.random.randn(len(t))
# マイク1: 直接波
mic1 = source.copy() + 0.1 * np.random.randn(len(t))
# マイク2: 実際の遅延(5 ms = 80 サンプル)
true_delay_samples = int(0.005 * fs)   # 80 サンプル
mic2 = np.zeros_like(mic1)
mic2[true_delay_samples:] = source[:-true_delay_samples] + 0.1 * np.random.randn(len(t) - true_delay_samples)

delay_est, cc, lags = gcc_phat(mic1, mic2, fs, max_delay=0.02)
print(f"真の遅延:     {true_delay_samples / fs * 1000:.2f} ms ({true_delay_samples} samples)")
print(f"GCC-PHAT推定: {delay_est * 1000:.2f} ms ({int(delay_est * fs)} samples)")

plt.figure(figsize=(10, 4))
plt.plot(lags * 1000, cc)
plt.axvline(x=delay_est * 1000, color='r', linestyle='--',
            label=f'Estimated delay = {delay_est*1000:.2f} ms')
plt.axvline(x=true_delay_samples / fs * 1000, color='g', linestyle=':',
            label=f'True delay = {true_delay_samples/fs*1000:.2f} ms')
plt.xlabel('Lag [ms]')
plt.ylabel('GCC-PHAT')
plt.title('GCC-PHAT Cross-Correlation for TDOA Estimation')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

応用:音声ピッチ推定(YIN 法の基礎)

ACFに基づくピッチ推定は音声処理で広く使われます。YIN アルゴリズム(de Cheveigné & Kawahara, 2002)は差分関数とACFを組み合わせてピッチを高精度に推定します。

差分関数 \(d[l]\) は以下のように定義されます。

\[d[l] = \sum_{n=0}^{N-1} (x[n] - x[n+l])^2 \tag{17}\]

展開すると自己相関との関係が明確になります。

\[d[l] = 2R_{xx}[0] - 2R_{xx}[l] \tag{18}\]

差分関数を用いた累積平均正規化差分(CMND)によりゼロクロス付近でのピーク検出精度が向上します。

import numpy as np
import matplotlib.pyplot as plt

def yin_pitch(signal, fs, fmin=75, fmax=500, threshold=0.1):
    """
    YIN アルゴリズムによるピッチ推定(簡易版)。

    Returns
    -------
    f0 : float or None
        推定F0 [Hz]
    d_norm : np.ndarray
        正規化差分関数
    """
    N = len(signal)
    W = N // 2  # 探索ウィンドウ

    # 差分関数(FFTで高速計算)
    X = np.fft.fft(signal, n=2*N)
    acf = np.fft.ifft(X * np.conj(X)).real[:N]

    d = np.zeros(W)
    d[0] = 0
    for l in range(1, W):
        d[l] = 2 * acf[0] - 2 * acf[l]

    # 累積平均正規化差分(CMND)
    d_norm = np.zeros(W)
    d_norm[0] = 1.0
    cumsum = 0.0
    for l in range(1, W):
        cumsum += d[l]
        d_norm[l] = d[l] / (cumsum / l)

    # ピッチ範囲の制限
    lag_min = int(fs / fmax)
    lag_max = int(fs / fmin)

    # 閾値を下回る最初のディップを検出
    f0 = None
    for l in range(lag_min, min(lag_max, W)):
        if d_norm[l] < threshold:
            # サブサンプル精度のためのパラボリック補間
            if 0 < l < W - 1:
                alpha = d_norm[l-1]
                beta = d_norm[l]
                gamma = d_norm[l+1]
                delta = (alpha - gamma) / (2 * (alpha - 2*beta + gamma))
                l_refined = l + delta
            else:
                l_refined = l
            f0 = fs / l_refined
            break

    return f0, d_norm


# --- テスト:異なるピッチの合成音声 ---
fs = 16000
t = np.arange(0, 0.1, 1/fs)  # 100 ms のフレーム

test_cases = {
    '男性声 (120 Hz)': 120,
    '女性声 (220 Hz)': 220,
    '子供声 (350 Hz)': 350,
}

fig, axes = plt.subplots(len(test_cases), 2, figsize=(14, 10))

for i, (label, f0_true) in enumerate(test_cases.items()):
    # ハーモニクスを含む合成音声
    np.random.seed(i)
    voice = (np.sin(2 * np.pi * f0_true * t)
             + 0.5 * np.sin(2 * np.pi * 2 * f0_true * t)
             + 0.3 * np.sin(2 * np.pi * 3 * f0_true * t)
             + 0.05 * np.random.randn(len(t)))

    f0_est, d_norm = yin_pitch(voice, fs)

    axes[i, 0].plot(t * 1000, voice)
    axes[i, 0].set_xlabel('Time [ms]')
    axes[i, 0].set_ylabel('Amplitude')
    axes[i, 0].set_title(f'{label}: True F0 = {f0_true} Hz')
    axes[i, 0].grid(True, alpha=0.3)

    lag_ms = np.arange(len(d_norm)) / fs * 1000
    axes[i, 1].plot(lag_ms, d_norm)
    axes[i, 1].axhline(y=0.1, color='r', linestyle='--', label='threshold=0.1')
    if f0_est:
        axes[i, 1].axvline(x=1000/f0_est, color='g', linestyle='--',
                           label=f'Est. F0 = {f0_est:.1f} Hz')
    axes[i, 1].set_xlabel('Lag [ms]')
    axes[i, 1].set_ylabel('Normalized d[l]')
    axes[i, 1].set_title('YIN: Cumulative Mean Normalized Difference')
    axes[i, 1].set_xlim(0, 30)
    axes[i, 1].legend(fontsize=9)
    axes[i, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

応用:時系列分析(ARIMAモデルの次数決定)

時系列分析において、ACFと**偏自己相関関数(PACF: Partial Autocorrelation Function)**はARIMAモデルの次数を決定するための基本的なツールです。

\[\text{PACF}(k) = \text{Corr}(x_t, x_{t-k} \mid x_{t-1}, \ldots, x_{t-k+1}) \tag{19}\]

PACFはラグ \(k\) 以外のラグの影響を除いた純粋な相関を表します。

import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import acf, pacf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# --- AR(2) プロセスのシミュレーション ---
# x[t] = 0.7 * x[t-1] - 0.3 * x[t-2] + noise
np.random.seed(42)
N = 300
phi = [0.7, -0.3]   # AR係数
noise_std = 1.0

x = np.zeros(N)
for t in range(2, N):
    x[t] = phi[0] * x[t-1] + phi[1] * x[t-2] + np.random.randn() * noise_std

# ACF と PACF の計算
nlags = 20
acf_vals = acf(x, nlags=nlags, fft=True)
pacf_vals = pacf(x, nlags=nlags)

# 信頼区間(近似: ±1.96/√N)
ci = 1.96 / np.sqrt(N)

fig, axes = plt.subplots(3, 1, figsize=(12, 10))

# 時系列プロット
axes[0].plot(x)
axes[0].set_xlabel('Time step')
axes[0].set_ylabel('x[t]')
axes[0].set_title('AR(2) Process: x[t] = 0.7·x[t-1] − 0.3·x[t-2] + noise')
axes[0].grid(True, alpha=0.3)

# ACF プロット
lags = np.arange(nlags + 1)
axes[1].bar(lags, acf_vals, color='steelblue', alpha=0.7)
axes[1].axhline(y=ci, color='r', linestyle='--', linewidth=0.8, label='±95% CI')
axes[1].axhline(y=-ci, color='r', linestyle='--', linewidth=0.8)
axes[1].axhline(y=0, color='k', linewidth=0.5)
axes[1].set_xlabel('Lag')
axes[1].set_ylabel('ACF')
axes[1].set_title('Autocorrelation Function (ACF): Gradual decay → AR process')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

# PACF プロット
axes[2].bar(lags, pacf_vals, color='coral', alpha=0.7)
axes[2].axhline(y=ci, color='r', linestyle='--', linewidth=0.8, label='±95% CI')
axes[2].axhline(y=-ci, color='r', linestyle='--', linewidth=0.8)
axes[2].axhline(y=0, color='k', linewidth=0.5)
axes[2].set_xlabel('Lag')
axes[2].set_ylabel('PACF')
axes[2].set_title('Partial ACF (PACF): Cuts off after lag 2 → confirms AR(2)')
axes[2].legend()
axes[2].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"PACF(1) = {pacf_vals[1]:.3f} (真値: φ₁ = {phi[0]})")
print(f"PACF(2) = {pacf_vals[2]:.3f} (真値: φ₂ = {phi[1]})")
print(f"PACF(3) = {pacf_vals[3]:.3f} (カットオフ: 0 に近い)")

ACFが指数的に減衰(カットオフなし)し、PACFがラグ2以降でカットオフすることから、このプロセスがAR(2)であると判断できます。

自己相関・相互相関の主な応用一覧

用途使用する相関特徴
周期性検出ACFピーク位置から基本周期を推定
ピッチ推定(音声)ACF (YIN等)声の基本周波数(F0)を抽出
TDOA推定(マイクアレイ)CCF (GCC-PHAT)到達時間差から音源位置を推定
テンプレートマッチングCCF画像・信号の類似位置探索
ARIMAモデル次数決定ACF + PACFp・qの次数選択
ホワイトノイズ検定ACF残差のランダム性検証
レーダー・ソナーCCF反射波の遅延から距離推定

まとめ

  • **自己相関関数(ACF)**は信号とその遅延コピーの類似度を測り、周期性・繰り返し構造の検出に有効である
  • ウィーナー・ヒンチン定理により、ACFのフーリエ変換はパワースペクトル密度(PSD)に等しく、時間領域と周波数領域の解析が等価であることが示される
  • **相互相関関数(CCF)**は2信号間の遅延推定・類似度定量化に使われ、GCC-PHATはノイズ耐性の高い遅延推定として音源定位に広く使われる
  • FFTを用いた高速計算(\(O(N \log N)\) )により、直接計算(\(O(N^2)\) )と比べて大幅に計算コストを削減できる
  • ACFとPACFの組み合わせによるARIMAモデルの次数決定は時系列分析の基本的な手順である
  • YINアルゴリズムは差分関数とACFの関係を利用した高精度なピッチ推定手法である

関連記事

参考文献

  • de Cheveigné, A., & Kawahara, H. (2002). “YIN, a fundamental frequency estimator for speech and music.” Journal of the Acoustical Society of America, 111(4), 1917-1930.
  • Knapp, C. H., & Carter, G. C. (1976). “The generalized correlation method for estimation of time delay.” IEEE Transactions on Acoustics, Speech, and Signal Processing, 24(4), 320-327.
  • Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time Series Analysis: Forecasting and Control (5th ed.). Wiley.
  • Oppenheim, A. V., & Schafer, R. W. (2009). Discrete-Time Signal Processing (3rd ed.). Prentice Hall.
  • SciPy signal.correlate documentation
  • Statsmodels ACF/PACF documentation