卷積的數學意義及信號學應用
1、卷積的數學意義
從數學上講,卷積與加減乘除一樣是一種運算,其運算的根本操作是將兩個函數的其中一個先平移,然後再與另一個函數相稱後的累加和。這個運算過程中,因為涉及到積分、級數的操作,所以看起來很復雜。在卷積(轉自wiki百科)中已經講過了卷積的定義如下所示:
對於定義在連續域的函數,卷積定義為
對於定義在離散域的函數,卷積定義為
這裏令U(x,y) = f(x)g(y) ,考慮到函數 f 和 g 應該地位平等,即變量 x 和 y 應該地位平等,一種可取的辦法就是沿直線 x+y = t將U(x,y)卷起來。下面為t取實際值的時候的坐標圖,可以看到不同取值的t可以遍歷整個平面。
將x+y=t中t取一次定值(這個定值可能是我們想要知道的某時刻的結果或著某種特征,由我們賦值),代入到U(x,y)中,就相當於U(x,y)所在平面沿著x+y=t直線做一次旋轉如下列動圖所示:
這裏便是完成了整個卷積的降維過程,完成降維過程後,U(x,y)也就從一個二元函數 U(x,y) = f(x)g(y) 被卷成一元函數 V(x)=f(x)g(t-x),最後再對x求積分(即遍歷降維後的軸上的特征點之和)。
2、卷積的C語言編寫
編寫卷積的程序,需要根據其離散方程組來進行了解。前面已經知道了卷積的離散函數的定義公式為:
在用C語言等其他語言進行實現是可以采用定義,利用兩個for循環完成代碼。
根據離散公式,可以編寫如下C++代碼:
#include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; float min(float a, float b) { return a < b ? a : b; } void convolution(float *input1, float *input2, float *output, int mm, int nn) { float *xx = new float[mm + nn - 1]; float *tempinput2 = new float[mm + nn - 1]; for (int i = 0; i < nn; i++) { tempinput2[i] = input2[i]; } for (int i = nn; i < mm + nn - 1; i++) { tempinput2[i] = 0.0; } // do convolution for (int i = 0; i < mm + nn - 1; i++) { xx[i] = 0.0; int tem = (min(i, mm)) == mm ? mm - 1 : min(i, mm); for (int j = 0; j <= tem; j++) { xx[i] += (input1[j] * tempinput2[i - j]); } } // set value to the output array for (int i = 0; i < mm + nn - 1; i++) output[i] = xx[i]; delete[] xx; } int main() { float a[3] = {2,6,4 }; float b[5] = {1,2,5,4,8}; float *c = new float[9]; convolution(a, b, c, 3, 5); for (int i = 0; i < 7; i++) { cout << c[i] << " "; } getchar(); return 0; }
運行結果如上圖所示,打開matlab進行驗證有:
卷積的列表法計算 :
如圖所示:斜線上數據相加,便是卷積結果;該方法適合用於並行計算求卷積。
3、卷積的信號學應用
打個比方,往平靜的水面裏面扔石頭。我們把水面的反應看作是一種沖擊響應。水面在t=0時刻石頭丟進去的時候會激起高度為h(0)的波紋,但水面不會立馬歸於平靜,隨著時間的流逝,波紋幅度會越來越小,在t=1時刻,幅度衰減為h(1), 在t=2時刻,幅度衰減為h(2)……直到一段時間後,水面重復歸於平靜。
從時間軸上來看,我們只在t=0時刻丟了一塊石頭,其它時刻並沒有做任何事,但在t=1,2….時刻,水面是不平靜的,這是因為過去(t=0時刻)的作用一直持續到了現在。
那麽,問題來了:
如果我們在t=1時刻也丟入一塊石子呢?此時t=0時刻的影響還沒有消失(水面還沒有恢復平靜)新的石子又丟進來了,那麽現在激起的波浪有多高呢?答案是當前激起的波浪與t=0時刻殘余的影響的疊加。那麽t=0時刻對t=1時刻的殘余影響有多大呢?
為了便於說明,接下來我們作一下兩個假設:
1. 水面對於“單位石塊”的響應是固定的
2. 丟一個兩倍於的“單位石塊”的石塊激起的波紋高度是丟一個石塊的兩倍(即系統滿足線性疊加原理)
現在我們來計算每一時刻的波浪有多高:
- t=0時刻:
y(0)=x(0)*h(0);
- t=1時刻:
當前石塊引起的影響x(1)*h(0);
t=0時刻石塊x(0)引起的殘余影響x(0)*h(1);
y(1)=x(1)*h(0)+ x(0)*h(1);
- t=2時刻:
當前石塊引起的影響x(2)*h(0);
t=0時刻石塊x(0)引起的殘余影響x(0)*h(2);
t=1時刻石塊x(1)引起的殘余影響x(1)*h(1);
y(2)=x(2)*h(0)+ x(1)*h(1)+x(0)*h(2);
……
- t=N時刻:
當前石塊引起的影響x(N)*h(0);
t=0時刻石塊x(0)引起的殘余影響x(0)*h(N);
t=1時刻石塊x(1)引起的殘余影響x(1)*h(N-1);
y(N)=x(N)*h(0)+ x(N-1)*h(1)+x(N-2)*h(2)+…+x(0)*h(N);
這就是離散卷積的公式了
理解了上面的問題,下面我們來看看“翻轉”是怎麽回事:
當我們每次要丟石子時,站在當前的時間點,系統的對我們的回應都是h(0),時間軸之後的(h(1),h(2).....)都是對未來的影響。而整體的回應要加上過去對於現在的殘余影響。
現在我們來觀察t=4這個時刻。
站在t=0時刻看他對於未來(t=4)時刻(從現在往後4秒)的影響,可見是x(0)*h(4)
站在t=1時刻看他對於未來(t=4)時刻的影響(從現在往後3秒),可見是x(1)*h(3)
站在t=2時刻看他對於未來(t=4)時刻的影響(從現在往後2秒),可見是x(2)*h(2)
站在t=3時刻看他對於未來(t=4)時刻的影響(從現在往後1秒),可見是x(3)*h(1)
所以所謂的翻轉只是因為你站立的現在是過去的未來,而因為h(t)始終不變,故h(1)其實是前一秒的h(1),而前一秒的h(1)就是現在,所以從當前x(4)的角度往左看,你看到的是過去的作用。h(t)未翻轉前,當從h(0)往右看,你看到的是現在對於未來的影響,當翻轉h(t)之後,從h(0)往左看,你依次看到的越來越遠的過去對現在的影響,而這個影響,與從x=4向左看的作用影響相對應(都是越來越遠的過去),作用與作用的響應就對應起來了,這一切的本質,是因為你站立的時間觀察點和方向在變。
參考資料
卷積為什麽叫「卷」積?
如何通俗易懂地解釋卷積?
在定義卷積時為什麽要對其中一個函數進行翻轉?
Matlab中fileter和conv的區別及卷積的計算方法
卷積C語言實現
卷積的數學意義及信號學應用