如何在MATLAB中平滑绘图?

20

我在图表上绘制了大约9000个点:

[完整的分辨率]

alt text

实际上,这个图形的平滑度不如我想要的那样高。有没有一种方法可以将图形平滑到所需的程度?

或者通过某种阈值处理方式,以便我可以选择性地平滑出太过崎岖的部分?

我不确定,但快速傅里叶变换有帮助吗?

5个回答

30
如果您有“曲线拟合工具箱”,则可以使用smooth函数。默认方法是大小为5的移动平均值(方法可以更改)。例如:
% some noisy signal
Fs = 200; f = 5;
t = 0:1/Fs:1-1/Fs;
y = sin(2*pi*f*t) + 0.6*randn(size(t));
subplot(411)
plot(y), title('Noisy signal')

% smoothed signal
subplot(412)
plot( smooth(y, 5, 'moving') ), title('smooth')
ylim([-2 2])

如果没有,你可以使用核心MATLAB中的filter函数来使用自己的窗口函数:

% equivalent to a moving average window
wndwSize = 5;
h = ones(1,wndwSize)/wndwSize;
subplot(413)
plot( filter(h, 1, y) ), title('filter + square window')

% Guassian
h = pdf('Normal',-floor(wndwSize/2):floor(wndwSize/2),0,1);
subplot(414)
plot( filter(h, 1, y) ), title('filter + Guassian window')

screenshot


17

一个简单(临时的)方法是在每个点处使用加权平均值(由 alpha 可调),与其邻居一起:

data(2:n-1) = alpha*data(2:n-1) + (1-alpha)*0.5*(data(1:n-2)+data(3:n))

或者一些变形。是的,要更加复杂一些,你可以先对数据进行傅里叶变换,然后截断高频部分。就像这样:

f = fft(data)
f(n/2+1-20:n/2+20) = zeros(40,1)
smoothed = real(ifft(f))

这将削减最高的20个频率。请注意对称地削减它们,否则反变换不再是实数。您需要仔细选择截止频率以获得适当级别的平滑度。这是一种非常简单的滤波(在频域中的盒式滤波),因此如果失真无法接受,可以尝试轻轻衰减高阶频率。


c=ifft(fft(a))总是应该给出c=a吗?对于某些情况是正确的,但对于a=[2 3 4 5 6 1 2 4 7 3 3 21 1 4 5 77 3 2 256 3 312 1 5 76 4 3 3 2 6 7 3 3 56 5 645 4 4 4 4],我在c中得到了一些虚数。有什么猜测为什么会这样吗? - Lazer
1
@eSKay:对我来说完全正确。但是由于四舍五入,c可能会获得一个小的虚数部分。我已经修复了上面的代码,将实数放在ifft的外面,就像它本应该的那样。 - Victor Liu
@Victor Liu 好的。在你的平滑计算中,“n”是什么? - Lazer
@eSKay:n 是数据的长度。 - Victor Liu

5

FFT并不是一个坏主意,但在这里可能有些过度。滑动平均法会给出通常较差的结果,除了用于晚交的作业(和白噪声)之外,应该避免使用。

我建议使用Savitzky-Golay滤波器(在Matlab中使用sgolayfilt(...))。这将为您提供最佳结果-在保持曲线形状的同时进行一些局部平滑处理。

-Paul


请注意,Savitzky-Golay是Matlab中“smooth”函数(至少2014a+版本)中的选项之一。 - David Parks

3
有时候,您应该避免使用移动平均值,因为它对异常值不够稳健。在这种情况下,移动中位数是更好的选择。

1
我会首先尝试显示一个数据点的移动平均值,例如 5 或 10。这样,数值上的单一差异只会对图表产生较小的影响。当然,这取决于您需要图表有多精确。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接