在2D矩阵中对多个1D信号进行卷积,在2D矩阵中使用多个1D内核

时间:2015-06-27 10:22:31

标签: matlab signal-processing fft convolution

我有一个大小为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。此外,我怀疑在计算卷积时索引HS。具体来说,对于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?我尝试使用conv2fftfilt,但我认为这不会给我Y,因为Y的大小也必须S

1 个答案:

答案 0 :(得分:3)

这很容易。这是2D信号上的卷积仅应用于1维。如果我们假设变量k用于访问行而t用于访问列,则可以将HS的每一行视为单独的信号其中S的每一行都是一维信号,H的每一行都是一个卷积核。

有两种方法可以解决这个问题。

时域

如果你想坚持使用时域,最简单的方法是循环输出的每一行,找到每对SH行的卷积并存储输出在相应的输出行中。从我所知道的情况来看,没有任何实用程序只能在给定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的行相同... ...这是更大的行。

频域

您也可以在频域中执行相同的计算。如果您对卷积和傅立叶变换的属性一无所知,您就会知道时域中的卷积是频域中的乘法。您对两个信号进行傅里叶变换,将它们按元素相乘,然后再进行逆傅立叶变换。

但是,您需要记住以下错综复杂的内容:

  1. 执行完整卷积意味着输出信号的最终长度为length(A)+length(B)-1,假设AB是1D信号。因此,您需要确保AB 零填充,以便它们都匹配相同的大小。 为什么确保信号大小相同的原因是允许乘法运算起作用。

  2. 一旦你将频域中的信号相乘,然后取反,您将看到Y的每一行都是卷积的完整长度。为确保您获得与输入大小相同的输出,您需要在开头和结尾处修剪某些点。具体来说,由于H的每个内核/列长度为10,因此您必须删除输出中每个信号的前5个和后5个点,以匹配for循环代码中的内容。

  3. 通常在逆傅立叶变换之后,由于FFT算法的性质,存在一些残余复系数。使用real删除结果的复杂值部分是一种很好的做法。

  4. 将所有这些理论结合在一起,这就是代码的样子:

    %// 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匹配。

    两者之间的比较

    如果你真的想比较它们,我们可以。我们首先需要做的是定义HS。为了重建我所做的,我使用已知种子生成随机值:

    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 。我说这很不错。