我有一个大小为H
的随机定义的600 x 10
矩阵。此矩阵H
中的每个元素都可以表示为H(k,t)
。我获得了S
语音谱图600 x 597
。我使用Mel功能获得它,所以它应该是40 x 611
但是我使用了帧堆叠概念,其中我将15帧堆叠在一起。因此它给了我(40x15) x (611-15+1)
,600 x 597
。
现在我想获得一个输出矩阵Y
,它由基于卷积Y(k,t) = ∑ H(k,τ)S(k,t-τ)
的等式给出。总和从τ=0
到τ=Lh-1
。在这种情况下,Lh
将是597。
我不知道如何获得Y
。此外,我怀疑在计算卷积时索引H
和S
。具体来说,对于Y(1,1)
,我们有:
Y(1,1) = H(1,0)S(1,1) + H(1,1)S(1,0) + H(1,2)S(1,-1) + H(1,3)S(1,-2) + ...
现在,MATLAB中没有负面索引 - 例如S(1,-1) S(1,-2)
等等。那么,我应该使用什么类型的卷积来获得Y
?我尝试使用conv2
或fftfilt
,但我认为这不会给我Y
,因为Y
的大小也必须S
。
答案 0 :(得分:3)
这很容易。这是2D信号上的卷积仅应用于1维。如果我们假设变量k
用于访问行而t
用于访问列,则可以将H
和S
的每一行视为单独的信号其中S
的每一行都是一维信号,H
的每一行都是一个卷积核。
有两种方法可以解决这个问题。
如果你想坚持使用时域,最简单的方法是循环输出的每一行,找到每对S
和H
行的卷积并存储输出在相应的输出行中。从我所知道的情况来看,没有任何实用程序只能在给定N-D信号的情况下在一个维度上进行卷积....除非你进入频域的东西,但让我们留待以后。
类似的东西:
Y = zeros(size(S));
for idx = 1 : size(Y,1)
Y(idx,:) = conv(S(idx,:), H(idx,:), 'same');
end
对于输出的每一行,我们使用一行S
和一行H
执行逐行卷积。我使用'same'
标志,因为输出应该与S
的行相同... ...这是更大的行。
您也可以在频域中执行相同的计算。如果您对卷积和傅立叶变换的属性一无所知,您就会知道时域中的卷积是频域中的乘法。您对两个信号进行傅里叶变换,将它们按元素相乘,然后再进行逆傅立叶变换。
但是,您需要记住以下错综复杂的内容:
执行完整卷积意味着输出信号的最终长度为length(A)+length(B)-1
,假设A
和B
是1D信号。因此,您需要确保A
和B
零填充,以便它们都匹配相同的大小。 为什么确保信号大小相同的原因是允许乘法运算起作用。
一旦你将频域中的信号相乘,然后取反,您将看到Y
的每一行都是卷积的完整长度。为确保您获得与输入大小相同的输出,您需要在开头和结尾处修剪某些点。具体来说,由于H
的每个内核/列长度为10,因此您必须删除输出中每个信号的前5个和后5个点,以匹配for
循环代码中的内容。
通常在逆傅立叶变换之后,由于FFT算法的性质,存在一些残余复系数。使用real
删除结果的复杂值部分是一种很好的做法。
将所有这些理论结合在一起,这就是代码的样子:
%// Define zero-padded H and S matrices
%// Rows are the same, but columns must be padded to match point #1
H2 = zeros(size(H,1), size(H,2)+size(S,2)-1);
S2 = zeros(size(S,1), size(H,2)+size(S,2)-1);
%// Place H and S at the beginning and leave the rest of the columns zero
H2(:,1:size(H,2)) = H;
S2(:,1:size(S,2)) = S;
%// Perform Fourier Transform on each row separately of padded matrices
Hfft = fft(H2, [], 2);
Sfft = fft(S2, [], 2);
%// Perform convolution
Yfft = Hfft .* Sfft;
%// Take inverse Fourier Transform and convert to real
Y2 = real(ifft(Yfft, [], 2));
%// Trim off unnecessary values
Y2 = Y2(:,size(H,2)/2 + 1 : end - size(H,2)/2 + 1);
Y2
应该是已解决的结果,并且应与之前的Y
循环代码中的for
匹配。
如果你真的想比较它们,我们可以。我们首先需要做的是定义H
和S
。为了重建我所做的,我使用已知种子生成随机值:
rng(123);
H = rand(600,10);
S = rand(600,597);
一旦我们为时域版本和频域版本运行上述代码,让我们看看它们在命令提示符中是如何匹配的。让我们显示前5行和5列:
>> format long g;
>> Y(1:5,1:5)
ans =
1.63740867892464 1.94924208172753 2.38365646354643 2.05455605619097 2.21772526557861
2.04478411247085 2.15915645246324 2.13672842742653 2.07661341840867 2.61567534623066
0.987777477630861 1.3969752201781 2.46239452105228 3.07699790208937 3.04588738611503
1.36555260994797 1.48506871890027 1.69896157726456 1.82433906982894 1.62526864072424
1.52085236885395 2.53506897420001 2.36780282057747 2.22335617436888 3.04025523335182
>> Y2(1:5,1:5)
ans =
1.63740867892464 1.94924208172753 2.38365646354643 2.05455605619097 2.21772526557861
2.04478411247085 2.15915645246324 2.13672842742653 2.07661341840867 2.61567534623066
0.987777477630861 1.3969752201781 2.46239452105228 3.07699790208937 3.04588738611503
1.36555260994797 1.48506871890027 1.69896157726456 1.82433906982894 1.62526864072424
1.52085236885395 2.53506897420001 2.36780282057747 2.22335617436888 3.04025523335182
对我好看!作为另一项衡量标准,让我们弄清楚Y
中的一个值与Y2
中的相应值之间的最大差异:
>> max(abs(Y(:) - Y2(:)))
ans =
5.32907051820075e-15
这说明两个输出之间的最大误差大约为10 -15 。我说这很不错。