在 python 中逐步过滤/平滑信号(到左边的直线到右边没有过滤)

Posted

技术标签:

【中文标题】在 python 中逐步过滤/平滑信号(到左边的直线到右边没有过滤)【英文标题】:Progressively filter/smooth a signal in python (to straight line on the left to no filtering on the right) 【发布时间】:2021-02-04 22:52:26 【问题描述】:

一张图抵得上一千个字(为粗制滥造见谅):

如果解决方案保留两端的值和斜率,那就更好了。 此外,如果可以调整过渡的位置和清晰度,那就完美了。

但是我还没有找到任何解决方案...

非常感谢您的帮助

下面是一段代码开始:

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

def round_up_to_odd(f):
    return np.int(np.ceil(f / 2.) * 2 + 1)

def generateRandomSignal(n=1000, seed=None):
    """
    Parameters
    ----------
    n : integer, optional
        Number of points in the signal. The default is 1000.

    Returns
    -------
    sig : numpy array

    """
    np.random.seed(seed)
    print("Seed was:", seed)
    steps = np.random.choice(a=[-1, 0, 1], size=(n-1))
    roughSig = np.concatenate([np.array([0]), steps]).cumsum(0)
    sig = savgol_filter(roughSig, round_up_to_odd(n/20), 6)
    return sig

n = 1000
t = np.linspace(0,10,n)
seed = np.random.randint(0,high=100000)
#seed = 45136
sig = generateRandomSignal(seed=seed)

###############################
# ????
# sigFilt = adaptiveFilter(sig)
###############################

# Plot
plt.figure()
plt.plot(t, sig, label="Signal")
# plt.plot(t, sigFilt, label="Signal filtered")
plt.legend()

【问题讨论】:

我只是想知道我下面的回答是否有帮助。 【参考方案1】:

简单卷积进行平滑处理。但是,如下所述,这里我们首先需要强平滑,最后不需要平滑。我将移动平均方法与窗口的动态大小一起使用。在下面的示例中,窗口大小呈线性变化。

def dynamic_smoothing(x, start_window_length=(len(x)//2), end_window_length=1):
    d_sum = np.cumsum(a, dtype=float)
    smoothed = list()
    for i in range(len(x)):
        # compute window length
        a = i / len(x)
        w = int(np.round(a * start_window_length + (1.0-a) * end_window_length))
        # get the window
        w0 = max(0, i - w) # the window must stay inside the array 
        w1 = min(len(x), i + w)
        smoothed.append(sum(x[w0:w1])/(w1+w0))
    return np.array(smoothed)

【讨论】:

感谢您的回复。我刚刚测试了你的解决方案。它确实平滑了信号,但不是我想要的方式:逐渐(左侧更平滑,右侧没有平滑,如图所示)。也许我错过了什么?我假设 w 是 window_length 但也许你有别的想法。 感谢您的更新。这是一个工作版本: def dynamic_smoothing(x, start_window_length=None, end_window_length=1): if not start_window_length: start_window_length = len(x)//2 smoothed = [] for i in range(len(x)): # 计算窗口长度 a = float(i) / len(x) w = int(np.round(a * start_window_length+(1.0-a) * end_window_length)) # 得到窗口 w0 = max(0, i - w) # 窗口必须留在数组内 w1 = min(len(x), i + w) smoothed.append(sum(x[w0:w1])/(w1-w0)) return np.array(smoothed) 这个想法很棒,它回答了我的问题。您可以继续,删除 UPD 上方的答案部分,然后复制粘贴我将修改的代码,我会接受答案。非常感谢!注意:窗口长度的线性减小虽然不是最好的,但我会自己修改!唯一的缺点是很难强制执行第一个点值和斜率。 注意,接受的答案有一些错误:start_window_length=(len(x)//2) 必须放在函数内部,d_sum 没有使用,a = float(i) / len (x),smoothed.append(sum(x[w0:w1])/(w1-w0)),最后一行没用,start_window_length和end_window_length必须切换……我把这个评论放在这里给以后的用户。跨度>

以上是关于在 python 中逐步过滤/平滑信号(到左边的直线到右边没有过滤)的主要内容,如果未能解决你的问题,请参考以下文章

5.信号处理 --常用信号平滑去噪的方法

如何在python中对信号应用过滤器

信号处理 --常用信号平滑去噪的方法

Python中的信号过滤

Python-图像平滑

数字信号去噪基于matlab粒子滤波器与FBSMAP平滑方法数字信号去噪含Matlab源码 2179期