Search code examples
python-3.xmatplotlibfilterscipysmoothing

Put a smooth line through data points (with filters)


I am trying to apply a filter to the peak datapoints of my impulse plot and smoothen them out but it doesn't seem to work. Required file signal.csv

scipy savgol_filter

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks, savgol_filter

df = pd.read_csv('signal.csv')
df.plot(grid = 1,
        c = (0,0,255/255),
        linewidth = 0.5,
        figsize = (10,5),
        legend = False,
        xlim = [df.index[0], df.index[-1]],
        ylim = 0)
plt.xlabel('Zeit / ms')
plt.ylabel('UHF-Signal / mV')
plt.title('UHF')

x = df.T.to_numpy()[1]
peaks, _ = find_peaks(x, distance = 150, height = 4)
sgf = savgol_filter(peaks, 51, 3)
plt.plot(sgf, x[peaks], c = 'orange')
plt.plot(peaks, x[peaks], 'o', c = 'red')
plt.show()

enter image description here

scipy butter filter

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks, butter, filtfilt

df = pd.read_csv('signal.csv')
df.plot(grid = 1,
        c = (0,0,255/255),
        linewidth = 0.5,
        figsize = (10,5),
        legend = False,
        xlim = [df.index[0], df.index[-1]],
        ylim = 0)
plt.xlabel('Zeit / ms')
plt.ylabel('UHF-Signal / mV')
plt.title('UHF')

x = df['1'].values
peaks, _ = find_peaks(x, distance = 150, height = 4)
c, e = butter(10, 0.3)
z = filtfilt(c, e, peaks)
plt.plot(z, x[peaks], c = 'orange')
plt.plot(peaks, x[peaks], 'o', c = 'red')
plt.show()

enter image description here

As you can see the result is the same. How can I smoothen out the orange line? I want something like this:

enter image description here

Thanks in advance


Solution

  • You are smoothing the wrong variable. peaks are indices into x (which really are heights / y-values, which makes everything a bit confusing). Substituting

    sgf = savgol_filter(x[peaks], 5, 3)
    plt.plot(peaks, sgf, c = 'orange', linewidth=3)
    

    for the corresponding lines in your code yields the following plot:

    enter image description here

    The fit is not great but neither of the methods you are using will deal with the sharp transition around x=2000 very well. I would try a Kalman filter next, or -- if the decay constant for all of your exponentials is the same -- try to fit the exponentials directly to the data using non-negative deconvolution as discussed here.