1.问题
上一篇中介绍了利用循环卷积计算线性卷积,但是当两个卷积项长度相差很大时,短序列需要补的0非常多,这样无助于计算量的减小,并且这种方法需要等长序列全部输入完之后才开始计算,这会造成输出有很大的延时。
但是实际中这种现象很长见,比如对音频信号进行数字滤波,滤波器抽头系数点数较少,而MIC一直在录音,需要滤波的信号可以认为是无限长的,如果等录很久后才开始进行滤波,则会造成需要存储的数据量急剧增大,同时输出的信号也会有较长的延时,这个时候怎样保证延时小的同时输出的结果跟对长信号滤波的结果相同呢
滤波器系数
h
(
n
)
,
h(n),
h(n),长度为
N
N
N,输入信号
x
(
n
)
x(n)
x(n),长度为无限长,输出
y
(
n
)
y(n)
y(n)即为它们的卷积
y
(
n
)
=
∑
m
=
0
M
x
(
n
−
m
)
h
(
m
)
y(n)=\sum^{M}_{m=0}x(n-m)h(m)
y(n)=m=0∑Mx(n−m)h(m)
那怎么利用频域计算呢,两种方法,重叠相加(overlap-add)和重叠保留(overlap-save)
重叠相加法(OLA)
- 将 x ( n ) x(n) x(n)分段,每段长为 M M M,保证 M M M接近 N N N即可,然后将 x k ( n ) x_{k}(n) xk(n)补零延长到 L = M + N − 1 L = M+N-1 L=M+N−1,计算 L L L点 F F T FFT FFT得到 X K ( K ) X_{K}(K) XK(K)
- 将 h ( n ) h(n) h(n)补零延长至 L = M + N − 1 L = M+N-1 L=M+N−1,计算 L L L点 F F T FFT FFT得到 H ( K ) 。 H(K)。 H(K)。
- 计算 y k ( k ) = X K ( K ) ∗ H ( K ) y_{k}(k)=X_{K}(K)*H(K) yk(k)=XK(K)∗H(K),然后求 L L L点的 I F F T , IFFT, IFFT,得到 y k ( K ) y_{k}(K) yk(K)
观察可以发现,每段 x k ( n ) x_{k}(n) xk(n)长为 M M M,恢复得到的 y k ( K ) y_{k}(K) yk(K)长为 L , L > M L,L>M L,L>M,那怎么将每段 y k ( K ) y_{k}(K) yk(K)拼接起来呢,方法为在还原的时候将重叠部分相加就可以了,这也是重叠相加法名字的由来。
用matlab验证一下,很简单,因为matlab的 F F T FFT FFT指定长度后会自动补零,那么上述过程几行代码就可以验证了
close all
clear all
h = [1,7,8];
N = length(h);
x = [5,8,9,6,3,4,8,2,1,7,5,6];
M = 4;
L = M+N-1;
x1 = x(1:4);
x2 = x(5:8);
x3 = x(9:12);
H = fft(h,L);
Y1 = fft(x1,L).*H;
Y2 = fft(x2,L).*H;
Y3 = fft(x3,L).*H;
y1 = ifft(Y1,L);
y2 = ifft(Y2,L);
y3 = ifft(Y3,L);
y_conv = conv(h,x)
y_ola = [y1(1:4),y1(5:6)+...
y2(1:2),y2(3:4),y2(5:6)+...
y3(1:2),y3(3:6)]
上面代码为了看的更清楚,循环都不用了,可以对比看看结果直接计算的y_conv与y_ola是不是相等的
重叠保留法(OLS)
- 将 x ( n ) x(n) x(n)分段,每段长为 M M M,保证 M M M接近 N N N即可,然后 将每段 x k ( n ) x_{k}(n) xk(n)向前多取 N − 1 N-1 N−1个点,第一段前面补 N − 1 N-1 N−1个0,则每段 x k ( n ) x_{k}(n) xk(n)长为 L = M + N − 1 L = M+N-1 L=M+N−1,计算 L L L点 F F T FFT FFT得到 X K ( K ) X_{K}(K) XK(K)
- 将 h ( n ) h(n) h(n)补零延长至 L = M + N − 1 L = M+N-1 L=M+N−1,计算 L L L点 F F T FFT FFT得到 H ( K ) 。 H(K)。 H(K)。
- 计算 y k ( k ) = X K ( K ) ∗ H ( K ) y_{k}(k)=X_{K}(K)*H(K) yk(k)=XK(K)∗H(K),然后求 L L L点的 I F F T , IFFT, IFFT,得到 y k ( K ) y_{k}(K) yk(K)
分析下上面的步骤,对比下线性卷积与圆周卷积:
线性卷积:
x
k
(
n
)
x_{k}(n)
xk(n):
L
=
M
+
N
−
1
L = M+N-1
L=M+N−1
h
:
N
h: N
h:N
y
k
(
n
)
:
M
+
2
N
−
2
y_{k}(n):M+2N-2
yk(n):M+2N−2
圆周卷积:
X
K
(
K
)
X_{K}(K)
XK(K):
L
=
M
+
N
−
1
L = M+N-1
L=M+N−1
H
(
K
)
:
L
=
M
+
N
−
1
H(K):L = M+N-1
H(K):L=M+N−1
Y
k
(
K
)
:
L
=
M
+
N
−
1
Y_{k}(K):L = M+N-1
Yk(K):L=M+N−1
可以看到线性卷积的长度(
M
+
2
N
−
2
M+2N-2
M+2N−2)>圆周卷积长度(
M
+
N
−
1
M+N-1
M+N−1),由线性卷积与圆周卷积的关系可知当圆周卷积长度小于线性卷积长度时会发生混叠,那就在恢复的时候,丢掉前面混叠的部分(
M
+
2
N
−
2
M+2N-2
M+2N−2)-(
M
+
N
−
1
M+N-1
M+N−1)
=
N
−
1
=N-1
=N−1,每段仅保留后面
M
M
M 点就行,这也是重叠保留名字的由来。
代码如下:
close all
clear all
h = [1,7,8];
N = length(h);
x0 = [5,8,9,6,3,4,8,2,1,7,5,6];
M = 4;
x = [zeros(1,N-1),x0];
L = M+N-1;
x1 = x(1:6);
x2 = x(5:10);
x3 = x(9:14);
x4 = [x(13:14),zeros(1,4)];
H = fft(h,L);
Y1 = fft(x1,L).*H;
Y2 = fft(x2,L).*H;
Y3 = fft(x3,L).*H;
Y4 = fft(x4,L).*H;
y1 = ifft(Y1,L);
y2 = ifft(Y2,L);
y3 = ifft(Y3,L);
y4 = ifft(Y4,L);
y_conv = conv(h,x0)
y_ols = [y1(3:6),y2(3:6),y3(3:6),y4(3:6)]
可以对比看看y_conv与y_ols是否相同
参考链接: