a11⋮am1⋯⋱⋯a1n⋮amn×b11⋮bn1⋯⋱⋯b1m⋮bnm=∑j=1na1jbj1⋮∑j=1namjbj1⋯⋱⋯∑j=1na1jbjm⋮∑j=1namjbjm=Cm×m也就是说,对于C的某一行i某一列j有:
C(i,j)=t=1∑naitbtj
这样一来,我们就可以将X[k]的表达式与之对应。
X就是此处的C,且为一维行向量,X[k]就是第一行第k列的值。
同理,x[n]也是一维行向量。为了计算,我们需要将WNkn作为方阵处理,由此得到:
X=x×WN
其中,有:
x=[x0,x1,...,xn]WN=WN0×0⋮WNN−1×0⋯⋱⋯WN0×N−1⋮WNN−1×N−1
(注:此处都是以起始为0计算的)
可见,W矩阵的指数部分其实就是由0~(N-1)的数组合而成,可以使用如下方式表示之:
n=[0,1,...,N−1]n′=012⋮N−1ans=n×n′
于是,我们就可以得到如下的计算方法了。
1 2 3 4 5 6 7 8
| function Xk = mydft(xn, N) n = [0:1:N-1]; k = n; WN= exp(-j*2*pi/N); nk = n' * k; Xk = xn(1:N) * WN.^nk; end
|
注:n'
表示n的转置;.^
表示每一项都进行指数运算
反变换(iDFT)
结合逆变换的表达式,我们可以很轻易得到逆变换的函数。
x[n]=N1k=0∑N−1X[k]ejN2πkn
1 2 3 4 5 6 7 8
| function xn = myidft(Xk, N) n = [0:1:N-1]; k = n; WN= exp(-j*2*pi/N); nk = n' * k; xn = (Xk(1:N) * WN.^(-nk))/N; end
|
事实上,前面的卷积表达式也可以利用矩阵的方式简化代码。此处不再赘述,其他类型的代码会放在后文
再谈离散卷积
起点不为0情况
其他的卷积算法
利用FFT的卷积计算(首推)
问:什么是FFT?
答:快速傅里叶变换(Fast Fourier Transform)的简称。是计算机领域内基于DFT设计并优化的更好的算法
关于FFT将在新文章中继续探讨~
之前我们已经介绍了可以利用公式:
f(t)∗g(t)=F(s)×G(s)
计算卷积。
因此我们可以直接调用matlab内自带的函数fft()
来进行计算。
对,FFT也自带得有 (笑)
1 2 3 4 5 6 7 8 9
| function y = myNewConv(x,h) xn = [x,zeros([1,length(h)-1])]; hn = [h,zeros([1,length(x)-1])]; y = ifft(fft(xn).*fft(hn)); end
|
注意:
- 运算符
.*
表示矩阵内各元素一一相乘,区别于矩阵相乘。因此,两个矩阵必须保证维度相同 - 由于最终的卷积结果长度为N+M−1(结论一),因此填零保证维度相同的时候,使用对方矩阵的长度-1
- 将两矩阵进行拼接时应当注意,[a,b]是水平拼接,[a;b]是垂直拼接
参考资料
1.编写离散序列卷积函数|知乎
2.matlab实现离散序列卷积|简书
3.DFT和IDFT的MATLAB实现 - 王俊|知乎