在python中平滑曲线,边界处没有错误?

2024-10-01 13:32:04 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下与两个numpy数组xy关联的曲线:

curve

如何在python中正确地平滑它,并且在xmax附近没有问题?(如果我应用高斯滤波器,曲线会在末尾向上)

数据在这里(两列):http://lite4.framapad.org/p/xqhpGJpV5R


Tags: 数据orgnumpyhttp数组曲线末尾xmax
2条回答

最简单的方法是在滤波之前对信号进行去趋势化处理。你所看到的边缘效应主要是由于信号不是静止的(即有一个斜率)。在

首先,让我们演示一下这个问题:

import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import gaussian_filter1d

x, y = np.loadtxt('spectrum.dat').T

# Smooth with a guassian filter
smooth = gaussian_filter1d(y, 10)

fig, ax = plt.subplots()
ax.loglog(x, y, color='black')
ax.loglog(x, smooth, color='red')
plt.show()

enter image description here

哎哟!边缘效应在数据的末尾(右边的大小)尤其糟糕,因为这是斜率最陡的地方。如果你在开始时有一个更陡的坡度,你会看到一个更强的边缘效应。在


好消息是有很多方法可以纠正这种情况。@ChristianK的答案显示了如何使用平滑样条来有效地实现低通滤波器。我将演示使用其他一些信号处理方法来完成相同的任务。哪一个“最好”取决于你的需要。平滑样条线是直接向前的。使用“更富想象力”的信号处理方法,可以精确控制过滤掉的频率。在

您的数据在log-log空间中看起来像一条抛物线,所以让我们用log-log空间中的二阶多项式来反趋势,然后应用过滤器。在

举个简单的例子:

^{pr2}$

enter image description here

请注意,我们仍然有一些边缘效应。这是因为我使用的高斯滤波器会引起相移。如果我们真的想变得花哨,我们可以去趋势化,然后使用零相位滤波器进一步最小化边缘效应。在

import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as signal

def main():
    x, y = np.loadtxt('spectrum.dat').T

    logx, logy = np.log(x), np.log(y)
    smooth_log = detrend_zero_phase(logx, logy)
    smooth = np.exp(smooth_log)

    fig, ax = plt.subplots()
    ax.loglog(x, y, 'k-')
    ax.loglog(x, smooth, 'r-')
    plt.show()

def zero_phase(y):
    # Low-pass filter...
    b, a = signal.butter(3, 0.05)

    # Filtfilt applies the filter twice to avoid phase shifts.
    return signal.filtfilt(b, a, y)

def detrend_zero_phase(x, y):
    # Fit a second order polynomial (Can't just use scipy.signal.detrend here,
    # because we need to know what the trend is to add it back in.)
    model = np.polyfit(x, y, 2)
    trend = np.polyval(model, x)

    # Apply a zero-phase filter to the detrended curve.
    smooth = zero_phase(y - trend)

    # Add the trend back in
    return smooth + trend

main()

enter image description here

如果您的所有数据在日志空间中的修改速度一样慢,我将执行以下操作:

  1. 在线性尺度上对对数数据进行大幅降采样
  2. 计算平滑样条
  3. 转换回线性比例

例如:

import numpy as np
from scipy.interpolate import interp1d, splrep, splev
import pylab

x = np.log10(x)
y = np.log10(y)

ip = interp1d(x,y)
xi = np.linspace(x.min(),x.max(),10)
yi = ip(xi)

tcl = splrep(xi,yi,s=1)
xs = np.linspace(x.min(), x.max(), 100)
ys = splev(xs, tcl)

xi = np.power(10,xi)
yi = np.power(10,yi)
xs = np.power(10,xs)
ys = np.power(10,ys)

f = pylab.figure()
pl = f.add_subplot(111)
pl.loglog(aset.x,aset.y,alpha=0.4)
pl.loglog(xi,yi,'go ',linewidth=1, label='linear')
pl.loglog(xs,ys,'r-',linewidth=1, label='spline')
pl.legend(loc=0)
f.show()

这就产生了:

enter image description here

相关问题 更多 >