Skip to content
Advertisement

Progressively filter/smooth a signal in python (to straight line on the left to no filtering on the right)

A picture is worth a thousand words (sorry for the shoddy work):

Example of filtering

If the solution is preserving the value and the slope at both ends it is better. If, in addition, the position and sharpness of the transition can be adjusted it is perfect.

But I have not found any solution yet…

Thank you very much for your help

Here is a piece of code to get started:

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()

Advertisement

Answer

Simple convolution does smoothing. However, as mentioned below, here we need strong smoothing first and no smoothing towards the end. I used the moving average approach with the dynamic size of the window. In the example below, the window size changes linearly.

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)
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement