tutorial functions español data python numpy scipy filtering smoothing

python - functions - Cómo filtrar/suavizar con SciPy/Numpy?



numpy windows (2)

Aquí hay un ejemplo de usar un ajuste loewess . Tenga en cuenta que data.dat el encabezado de data.dat .

De la trama, parece que este método funciona bien en subconjuntos de datos. Ajustar todos los datos a la vez no da un resultado razonable. Entonces, probablemente este no sea el mejor método aquí.

import pandas as pd import matplotlib.pylab as plt from statsmodels.nonparametric.smoothers_lowess import lowess data = pd.read_table("data.dat", sep=",", names=["time", "pressure"]) sub_data = data[data.time > 21.5] result = lowess(sub_data.pressure, sub_data.time.values) x_smooth = result[:,0] y_smooth = result[:,1] tot_result = lowess(data.pressure, data.time.values, frac=0.1) x_tot_smooth = tot_result[:,0] y_tot_smooth = tot_result[:,1] fig, ax = plt.subplots(figsize=(8, 6)) ax.plot(data.time.values, data.pressure, label="raw") ax.plot(x_tot_smooth, y_tot_smooth, label="lowess 1%", linewidth=3, color="g") ax.plot(x_smooth, y_smooth, label="lowess", linewidth=3, color="r") plt.legend()

Este es el resultado que obtengo:

Estoy tratando de filtrar / suavizar la señal obtenida de un transductor de presión de frecuencia de muestreo de 50 kHz. Una señal de muestra se muestra a continuación:

Me gustaría obtener una señal suave obtenida por loess en MATLAB (no estoy trazando los mismos datos, los valores son diferentes).

Calculé la densidad espectral de potencia usando la función psd () de matplotlib y la densidad espectral de potencia también se proporciona a continuación:

Intenté usar el siguiente código y obtuve una señal filtrada:

import csv import numpy as np import matplotlib.pyplot as plt import scipy as sp from scipy.signal import butter, lfilter, freqz def butter_lowpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype=''low'', analog=False) return b, a def butter_lowpass_filter(data, cutoff, fs, order=5): b, a = butter_lowpass(cutoff, fs, order=order) y = lfilter(b, a, data) return y data = np.loadtxt(''data.dat'', skiprows=2, delimiter='','', unpack=True).transpose() time = data[:,0] pressure = data[:,1] cutoff = 2000 fs = 50000 pressure_smooth = butter_lowpass_filter(pressure, cutoff, fs) figure_pressure_trace = plt.figure(figsize=(5.15, 5.15)) figure_pressure_trace.clf() plot_P_vs_t = plt.subplot(111) plot_P_vs_t.plot(time, pressure, linewidth=1.0) plot_P_vs_t.plot(time, pressure_smooth, linewidth=1.0) plot_P_vs_t.set_ylabel(''Pressure (bar)'', labelpad=6) plot_P_vs_t.set_xlabel(''Time (ms)'', labelpad=6) plt.show() plt.close()

El resultado que obtengo es:

Necesito más suavizado, intenté cambiar la frecuencia de corte, pero todavía no se pueden obtener resultados satisfactorios. No puedo obtener la misma suavidad de MATLAB. Estoy seguro de que se puede hacer en Python, pero ¿cómo?

Puede encontrar los datos aquí .

Actualizar

Apliqué suavizar lowess desde modelos de estadísticas, esto tampoco proporciona resultados satisfactorios.


Aquí hay un par de sugerencias.

Primero, pruebe la función lowess de los statsmodels de statsmodels con it=0 , y statsmodels un poco el argumento frac :

In [328]: from statsmodels.nonparametric.smoothers_lowess import lowess In [329]: filtered = lowess(pressure, time, is_sorted=True, frac=0.025, it=0) In [330]: plot(time, pressure, ''r'') Out[330]: [<matplotlib.lines.Line2D at 0x1178d0668>] In [331]: plot(filtered[:,0], filtered[:,1], ''b'') Out[331]: [<matplotlib.lines.Line2D at 0x1173d4550>]

Una segunda sugerencia es usar scipy.signal.filtfilt lugar de lfilter para aplicar el filtro Butterworth. filtfilt es el filtro hacia adelante-hacia atrás . Aplica el filtro dos veces, una vez hacia adelante y otra hacia atrás, lo que produce un retraso de fase cero.

Aquí hay una versión modificada de su script. Los cambios significativos son el uso de filtfilt lugar de lfilter y el cambio de cutoff de 3000 a 1500. Es posible que desee experimentar con ese parámetro: valores más altos dan como resultado un mejor seguimiento del inicio del aumento de presión, pero un valor que es demasiado alto no filtra las oscilaciones de 3kHz (aproximadamente) después de que la presión aumenta.

import numpy as np import matplotlib.pyplot as plt from scipy.signal import butter, filtfilt def butter_lowpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype=''low'', analog=False) return b, a def butter_lowpass_filtfilt(data, cutoff, fs, order=5): b, a = butter_lowpass(cutoff, fs, order=order) y = filtfilt(b, a, data) return y data = np.loadtxt(''data.dat'', skiprows=2, delimiter='','', unpack=True).transpose() time = data[:,0] pressure = data[:,1] cutoff = 1500 fs = 50000 pressure_smooth = butter_lowpass_filtfilt(pressure, cutoff, fs) figure_pressure_trace = plt.figure() figure_pressure_trace.clf() plot_P_vs_t = plt.subplot(111) plot_P_vs_t.plot(time, pressure, ''r'', linewidth=1.0) plot_P_vs_t.plot(time, pressure_smooth, ''b'', linewidth=1.0) plt.show() plt.close()

Aquí está la trama del resultado. Tenga en cuenta la desviación en la señal filtrada en el borde derecho. Para manejar eso, puede experimentar con los parámetros padtype y padlen de filtfilt o, si sabe que tiene suficientes datos, puede descartar los bordes de la señal filtrada.