1. 程式人生 > >卷積的數學意義及信號學應用

卷積的數學意義及信號學應用

getc p s set out iostream n) tar 兩個 turn

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語言實現

卷積的數學意義及信號學應用