相互相関の計算

相互相関 (cross-correlation) を計算するCommon Lispプログラムを作りました。とは言っても、畳み込み演算ができれば簡単に実装できます。Matlabのxcorr関数とそれなりの互換性があるものが欲しかったので、相互相関値だけでなくラグも返すようにしました。

(defun xcorr (x1 x2)
  "Calculate cross-correlation of two vectors <x1> and <x2>."
  (let* ((r (fftconv-linear x1 (reverse x2)))
         (lags (linspace (- 1 (length x1))
                         (- (length x2) 1)
                         (+ (length x1) (length x2) -1))))
    (list r lags)))

ここに登場するfftconv-linearは「Common Lispで畳み込み演算 - 丸井綜研」で紹介しています。

うまく動くか確認してみましょう。まずはMatlabのサンプルコードをそのまま実行した結果です。

>> n = 0:15;
>> x = 0.84.^n;
>> y = circshift(x,5);
>> x
x =
  1 列から 111.0000    0.8400    0.7056    0.5927    0.4979    0.4182    0.3513    0.2951    0.2479    0.2082    0.1749
  12 列から 160.1469    0.1234    0.1037    0.0871    0.0731
>> y
y =
  1 列から 110.1469    0.1234    0.1037    0.0871    0.0731    1.0000    0.8400    0.7056    0.5927    0.4979    0.4182
  12 列から 160.3513    0.2951    0.2479    0.2082    0.1749
>> [r,lags] = xcorr(x, y)
r =
  1 列から 110.1749    0.3551    0.5462    0.7539    0.9846    1.2452    1.5439    1.8896    2.2928    2.7660    3.3234
  12 列から 222.8648    2.4935    2.1982    1.9699    1.8017    1.5026    1.2494    1.0343    0.8507    0.6930    0.5564
  23 列から 310.4368    0.3305    0.2343    0.1452    0.0605    0.0463    0.0336    0.0218    0.0107
lags =
  1 列から 18-15   -14   -13   -12   -11   -10    -9    -8    -7    -6    -5    -4    -3    -2    -1     0     1     2
  19 列から 313     4     5     6     7     8     9    10    11    12    13    14    15

これと同じものを自作コードでも実行してみます。circshiftのあたりが面倒な気がしたので、xとyはMatlabの計算結果をそのままコピーしてきました。

CL-USER> (setq x #(1.0000 0.8400 0.7056 0.5927 0.4979 0.4182 0.3513 0.2951
                   0.2479 0.2082 0.1749 0.1469 0.1234 0.1037 0.0871 0.0731))
CL-USER> (setq y #(0.1469 0.1234 0.1037 0.0871 0.0731 1.0000 0.8400 0.7056
                   0.5927 0.4979 0.4182 0.3513 0.2951 0.2479 0.2082 0.1749))
CL-USER> (xcorr x y)
#(0.17489999532699563d0 0.35511598426365865d0 0.546197423498211d0
  0.7539051399312973d0 0.984585083989236d0 1.2452508289644957d0
  1.543912061084979d0 1.8895891470502966d0 2.29286128923301d0
  2.766004757651965d0 3.3234476471624053d0 2.8647975672684733d0
  2.4935325254862217d0 2.198278020674617d0 1.9699693688096958d0
  1.8016461558485104d0 1.502649998495152d0 1.2494363412632585d0
  1.0342891628549766d0 0.8506471855956199d0 0.6929649098329114d0
  0.5563953268840145d0 0.43679569768332227d0 0.33050440362259415d0
  0.23423337562113478d0 0.14511612936740637d0 0.06049087947964149d0
  0.04632331975089787d0 0.033562139367923294d0 0.021815529998273853d0
  0.010738389958605543d0)
(-15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11
 12 13 14 15)

同じ結果になっていますね。よし。(このコードはゆくゆく両耳間相互相関係数 (interaural cross-correlation coefficient, IACC) の計算に使う予定です)