问题限定: 仅对离散信号做分析
首先要回答什么是卷积的问题.
In mathematics and, in particular, functional analysis, convolution is a mathematical operation on two functions f and g, producing a third function that is typically viewed as a modified version of one of the original functions, giving the area overlap between the two functions as a function of the amount that one of the original functions is translated.
—— wikipedia
对于卷积这个东东,一般看到这两个字的人就头大,往往望而生畏.
上述定义严谨,而《The sciencetist and engineer's guide to DSP》有更为简单直接的描述
Convolution is a mathematical way of combining two signals to form a third signal.
Convolution is a formal mathematical operation, just as multiplication, addition, and integration. Addition takes two numbers and produces a third number, while convolution takes two signals and produces a third signal.
不要有太大的心理压力,它不过就是一种数学计算操作而已,用两个输入信号合成第三个信号输出.至于具体的怎么操作,后面一步步讲清楚.
先抛出个问题,然后借助解答这个问题去回答“what is convolution ?".
这里有两组很简单信号x[n], h[n],这两组信号做卷积处理之后得到y[n]
问题来了,x[n] 和 h[n]怎么操作就可以得到y[n]呢?
一步步分解
第一步,图1,x[0]h[n-0] ,这里表达的就是把x[0]依次 和h[0]~h[3]做乘法,把结果输出到此时对应的output[n](图中的方块)
第二步,图2,x[1]h[n-1] ,这里表达的就是把x[1]依次 和h[0]~h[3]做乘法,把结果输出到此时对应的output[n](图中的方块)
第三步,图3,x[2]h[n-2] ,这里表达的就是把x[2]依次 和h[0]~h[3]做乘法,把结果输出到此时对应的output[n](图中的方块)
... ...
第九步,图9,x[8]h[n-8] ,这里表达的就是把x[8]依次 和h[0]~h[3]做乘法,把结果输出到此时对应的output[n](图中的方块)
So ? 看出规律了?
之前我故意没有给出卷积的公式定义
现在再看卷积的公式定义一点清楚得多!
用Octave(或者 matlab)实现一个demo
利用了这幅图的数据
%code writer : EOF %code date : 2014.09.11 %e-mail : [email protected] %code file : convolution_input_side.m %code purpose: % A demo for convolution. clear all close all x = [0 -1 -1.2 2 1.4 1.4 0.8 0 -0.8]; h = [1 -0.6 -0.4 -0.1]; length_x = size(x,2); length_h = size(h,2); output = zeros(1,length_h+length_x); figure(1); subplot(121); scatter(1:length_x,x,'r','filled'); title('x[n]'); subplot(122); scatter(1:length_h,h,'g','filled'); title('h[n]'); for tmp_1 = 1:length_x for tmp_2 = 1:length_h output(tmp_1+tmp_2-1) = output(tmp_1+tmp_2-1) + x(tmp_1)*h(tmp_2); end end figure(2); scatter(1:size(output,2),output,'filled'); title('output[n]');
到此,回答了什么是卷积.或者说更深刻体会了什么是卷积
为什么我们要用卷积这种东东?
Why should we use convolution? God said I just want to make filter more simple. : )
时域中的卷积就对应于频域中的乘积,那么频域中的卷积对应于时域中的乘积
卷积为滤波而生.
这里是两个利用卷积做滤波器的例子
图a是低通滤波,图b是高通滤波,一开始我也纳闷Input signal确实复合了多个频率的信号,怎么耶和中间的信号做卷积之后就有滤波的效果了呢?
低通滤波做卷积的这个信号有什么特点吗??
filter = [0 0.1 0.16 0.25 0.25 0.16 0.1 0]*0.125;
scatter(1:8,real(fft(filter)),'filled');
假设图中的数据是filter(我自己模拟的数据)
可以用频谱分析发现
这货的频谱是低频部分高的!抑制高频部分
把两个输入信号都变换到频率领域里面去,然后想乘,再把结果逆变换到时间领域不久得到低通滤波的结果了么!
这里再给出一种低通滤波的demo
首先,利用一下两个信号合成一个输入信号,模拟带高频噪声的输入
利用上面两个信号,我模拟合成了下面第一幅图的信号,作为带高频噪声的输入信号,而下面的第二幅图就是我们的做卷积的另外一个信号(低通滤波就靠它了!)
将以上两个信号做卷积得到输出信号
漂亮!几乎完美的滤去的高频噪声.
实现:
%code writer : EOF %code date : 2014.09.11 %e-mail : [email protected] %code file : convolution_input_side.m %code purpose: % Just a demo for low-pass filter by convolution. clear all close all % 'y' is a simulation for original pure signal y = sin(0.5*pi*[0:0.05:8]); % 'u' is a simulation for noise. u = 0.2*sin(8*pi*[0:0.05:8]); figure(1); subplot(211); plot(1:size(y,2),y); title('original pure signal'); %BUG, I don't know why I can't write title on this figure. subplot(212); plot(1:size(u,2),u); title('noise'); input_signal = y + u; x = input_signal; h = [1 1 1 1 1 1 1 1 1 1]*0.1; length_x = size(x,2); length_h = size(h,2); output_signal = zeros(1,length_h+length_x); figure(2); subplot(211); plot(1:length_x,x); subplot(212); scatter(1:length_h,h,'filled'); for tmp_1 = 1:length_x for tmp_2 = 1:length_h output_signal(tmp_1+tmp_2-1) = output_signal(tmp_1+tmp_2-1) + x(tmp_1)*h(tmp_2); end end figure(3); plot(1:size(output_signal,2),output_signal); title('Output signal');
哈哈是不是想看看这个家伙的频谱图呢?
怎么它就可以低通滤波捏?下面给出了上面那个家伙的频谱图,看!低通滤波!只有在低频地带有赋值为1,其他的都是0!
当我们想要什么类型的滤波器,我们可以先构想频谱表达,然后通过逆向傅立叶变换(实际上是逆向FFT),然后得到和输入信号做卷积的因子,然后做卷积,即可实现滤波!
Why should we use convolution? God said I just want to make filter more simple. : )
update: 2014.11.13
给出卷积的C语言实现demo
/********************************************************* code writer : EOF code file : conv_demo.c code date : 2014.11.13 e-mail : [email protected] code description: A implementation of convolution in C lanuage **********************************************************/ #include <stdio.h> #include <stdlib.h> #define DEBUG int* init_input(int number) { if(number <= 0) { printf("number < 0! in function %s\n",__FUNCTION__); return NULL; } int* p_input = (int*)malloc(sizeof(int)*number); if(!p_input) { printf("malloc error!\n"); return NULL; } int temp = 0; for(temp = 0;temp < number;temp++) { if(scanf("%d",(p_input+temp)) < 0) { return NULL; } } return p_input; } int* init_unit_responce(int number) { if(number <= 0) { printf("number < 0! in function %s\n",__FUNCTION__); return NULL; } int* p_unit_responce = (int*)malloc(sizeof(int)*number); if(!p_unit_responce) { printf("malloc error!\n"); return NULL; } int temp = 0; for(temp = 0;temp < number;temp++) { if(scanf("%d",(p_unit_responce +temp)) < 0) { return NULL; } } return p_unit_responce; } void release(int* p_input,int* p_unit_responce) { free(p_input); free(p_unit_responce); } int* conv(int* p_input,int ip_num,int* p_unit_responce,int ur_num) { if(!p_input || !p_unit_responce || ip_num <= 0 || ur_num <= 0) { printf("Data losted!\n"); return NULL; } int* p_output = (int*)malloc(sizeof(int)*(ip_num + ur_num - 1)); if(!p_output) { printf("malloc error! in function %s\n",__FUNCTION__); return NULL; } int tmp = 0; int idx = 0; int sum = 0; for(tmp = 0;tmp < ip_num + ur_num -1;tmp++) { sum = 0; for(idx = 0; (tmp - idx) >= 0 && idx < ur_num;idx++) { if((tmp -idx) < ip_num) { sum += p_unit_responce[idx]*p_input[tmp-idx]; } } *(p_output + tmp) = sum; #ifdef DEBUG printf("\t%d",sum); #endif } #ifdef DEBUG printf("\n"); #endif return p_output; } int main() { int ip_num = 0; printf("Hey guys! Just input the size of input-data!\n"); while(!scanf("%d",&ip_num)) { printf("input data type error! Input again!\n"); getchar();// clear the '\n' after we inputed. } int* p_input = NULL; p_input = init_input(ip_num); if(!p_input) { goto out; } printf("What about the size of unit-responce!\n"); int ur_num = 0; while(!scanf("%d",&ur_num)) { printf("input data type error! Input again!\n"); getchar();// clear the '\n' after we inputed. } int* p_unit_responce = NULL; p_unit_responce = init_unit_responce(ur_num); if(!p_unit_responce) { goto out; } conv(p_input,ip_num,p_unit_responce,ur_num); out: release(p_input,p_unit_responce); return 0; }
用matlab的conv函数来检验我们程序的正确性,对比可知,我们程序实现是正确的。