Contents

卷積(convolution)

卷積(convolution),又稱疊積、褶積或旋積,可以將函數 $f$ 與 $g$ 進行運算產生新函數。

Mathematical Definition

對於連續(continuous)函數: $$ (f \star g)(t) = \int_{-\infty}^{\infty} f(\tau) g(t - \tau) d\tau $$ 對於離散(discrete)函數: $$ (f \star g)[n] = \sum_{m=-\infty}^{\infty} f[m] g[n - m] $$ 其中 $t, n$ 稱為移位(displacement)或滯後(lag),若 $t, n=0$ 則 $(f * g)(0)$ 等於$f$與X軸反轉的 $g$ 的相乘積分或相乘加總,可以用一個簡單的 python 展示 $n=0$ 時的離散函數卷積:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# function f, g
f = [1, 2, 3]
g = [4, 5, 6]
result = 0

# g(-m)
g.reverse()

# [1, 2, 3]
#  |  |  |
# [4, 5, 6]
for i, j in zip(f, g):
    result += i * j

print(result)
>>> 28
Info
展示卷積運算的酷酷網站,phiresky.github.io/convolution-demo

做單次運算會得到一個值(value),但卷積並不只運算一次,還必須考量 $n\neq0$ 的其他情況。假設 $n=1$,則 $g(1-m)=g(-m+1)$,代表 $g$ 不僅對X軸反轉,還要向右移動一格:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
f = [1, 2, 3]
g = [4, 5, 6]
result = 0

# g(1-m)
g.append(0)
g.reverse()

# [1, 2, 3]
#  |  |  |
# [0, 6, 5, 4]
for i, j in zip(f, g):
    result += i * j

print(result)
>>> 27

但在上述例子中,一旦 $\left|n\right|>3$ 便沒有意義,因為$g$被平移超過三格後所對應到的$f$都會是0:

1
2
3
[1, 2, 3]
 |  |  |
[0, 0, 0, 6, 5, 4]

因此我們可以計算出 $\left|n\right|>3$ 情況下的新卷積函數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
f = [1, 2, 3]
g = [4, 5, 6]
result = []

g.extend([0 for _ in range(len(f) - 1)])
g.reverse()

while g:
    s = 0
    for i, j in zip(f, g):
        s += i * j
    result.append(s)
    g = g[1:]

result.reverse()
print(result)
>>> [4, 13, 28, 27, 18]

Numpy

事實上 Python 的 Numpy 本身自帶convolve函式,可以計算$\left|n\right|\leq3$時的離散函數卷積:

1
2
3
4
5
6
7
8
import numpy as np

f = [1, 2, 3]
g = [4, 5, 6]
result = np.convolve(f, g)
print(result)
>>>  [ 4 13 28 27 18]
# n = -2 -1  0  1  2

Scipy

若希望提升計算速度,可以改用 Scipy,其fftconvolve函式利用快速傅立葉轉換將卷積運算複雜度由 $O(n^2)$ 降低至 $O(nlog(n))$,在資料量龐大時尤其明顯:

1
2
3
4
5
6
7
from scipy import signal

f = [1, 2, 3]
g = [4, 5, 6]
result = signal.fftconvolve(f, g)
print(result)
>>> [ 4. 13. 28. 27. 18.]

References