贡献者: addis
1. 直接数值积分
作为下文 FFT 方法的参照,我们先实现直接用数值积分计算傅里叶变换(式 1 )。调用时需要提供一元函数(句柄)f
,而不是一系列离散函数值。xspan
是对 f
积分的区间,而 kspan
是输出中 k
的区间,Nk
是 k
的长度。这么做虽然直观且精确,但计算量较大,所以一般还是用下一节中的 FFT 方法。
尤其是如果 f
并不是通过函数给出,而只是一系列等间距的散点,那么与其先插值再做数值积分,FFT 方法是最适合的,因为 FFT 已经相当于对散点进行了 sinc 插值(子节 4 )。
代码 1:CFT.m
同理,可以用数值积分计算反傅里叶变换
代码 2:iCFT.m
2. 用 FFT 近似傅里叶变换
这里使用的算法见子节 7 。给出任意等间距的 坐标格点 [x0, x0+dx, x0+2*dx, ...]
,以及对应的函数值 f = [f(1), f(2), ...]
,那么该代码可以通过 Matlab 提供的快速傅里叶变换(FFT)计算傅里叶变换(式 1 )。输入中 Nk
是可选的,默认等于 x
的个数。若 Nk
大于 f
的个数,输出中 k
的步长将会相应变小使 k
的长度为 Nk
,但区间不会变。k
的区间是由 dx
决定的。在实现上,当 Nk > numel(f)
时会预先在 f
两边添加 0 使其先具有 Nk
个元。
代码 3:FFT.m
对应的反傅里叶变换如下
代码 4:iFFT.m
下面是一些依赖程序
代码 5:fftresize.m
function y = fftresize(x, newN)
if size(x, 1) == 1
N = numel(x);
Ndiff = abs(newN - N);
if newN > N
if mod(Ndiff,2) == 0
Ndiff = 0.5*Ndiff;
y = [zeros(1, Ndiff), x, zeros(1, Ndiff)];
else
Ndiff = 0.5*(Ndiff-1);
if mod(N, 2) == 0
y = [zeros(1, Ndiff), x, zeros(1, Ndiff+1)];
else
y = [zeros(1, Ndiff+1), x, zeros(1, Ndiff)];
end
end
elseif newN < N
y = shrink(x, N, Ndiff);
else
y = x;
end
elseif size(x, 2) == 1
N = numel(x);
Ndiff = abs(newN - N);
if newN > N
if mod(Ndiff,2) == 0
Ndiff = 0.5*Ndiff;
y = [zeros(Ndiff, 1); x; zeros(Ndiff, 1)];
else
Ndiff = 0.5*(Ndiff-1);
if mod(N, 2) == 0
y = [zeros(Ndiff, 1); x; zeros(Ndiff+1, 1)];
else
y = [zeros(Ndiff+1, 1); x; zeros(Ndiff, 1)];
end
end
elseif newN < N
y = shrink(x, N, Ndiff);
else
y = x;
end
else
[N, Ncol] = size(x);
Ndiff = abs(newN - N);
if newN > N
if mod(Ndiff,2) == 0
Ndiff = 0.5*Ndiff;
y = [zeros(Ndiff, Ncol); x; zeros(Ndiff, Ncol)];
else
Ndiff = 0.5*(Ndiff-1);
if mod(N, 2) == 0
y = [zeros(Ndiff, Ncol); x; zeros(Ndiff+1, Ncol)];
else
y = [zeros(Ndiff+1, Ncol); x; zeros(Ndiff, Ncol)];
end
end
elseif newN < N
if mod(Ndiff,2) == 0
Ndiff = 0.5*Ndiff;
y = x(Ndiff+1:end-Ndiff, :);
else
Ndiff = 0.5*(Ndiff-1);
if mod(N, 2) == 0
y = x(Ndiff+2:end-Ndiff, :);
else
y = x(Ndiff+1:end-Ndiff-1, :);
end
end
else
y = x;
end
end
end
function y = shrink(x, N, Ndiff)
if mod(Ndiff,2) == 0
Ndiff = 0.5*Ndiff;
y = x(Ndiff+1:end-Ndiff);
else
Ndiff = 0.5*(Ndiff-1);
if mod(N, 2) == 0
y = x(Ndiff+2:end-Ndiff);
else
y = x(Ndiff+1:end-Ndiff-1);
end
end
end
代码 6:sffts.m
代码 7:fftlinspace.m
示例
图 1:输出
图 2:输出
傅里叶级数
根据式 12 ,傅里叶级数与傅里叶变换值相差一个常数:
代码 8:FS.m
3. sinc 插值
根据采样定理,可以使用 FFT 对函数的离散值进行 sinc
插值,dx
是可选的。
代码 9:fftinterp.m
为了对比验证,我们也可以直接实现 sinc
插值,但该代码的效率较低
代码 10:sinc_interp.m
致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者
热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 20 元,我们一周就能脱离亏损, 并在接下来的一年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。