Aplicando filtro de variante de tiempo en Python

Estoy intentando aplicar un filtro de paso de banda con frecuencias de corte que varían con el tiempo a una señal, usando Python. La rutina Actualmente estoy utilizando particiones de mi señal en segmentos de tiempo de igual longitud, luego, para cada segmento aplico un filtro con parámetros específicos de tiempo, antes de volver a fusionar la señal. Los parámetros se basan en estimaciones preexistentes.

El problema que parece tener es que hay "ondulaciones" en el borde de cada segmento de tiempo que aparecen después de que se haya aplicado el filtro. Esto provoca discontinuidades en mi señal, que interfieren con mi análisis de datos posterior al filtrado.

¿Esperaba que alguien me informara si hay alguna rutina para implementar filtros con parámetros variables en el tiempo en Python? Alternativamente, se agradecería mucho el consejo sobre cómo podría solucionar este problema.

EDITAR - A continuación se agrega un ejemplo de lo que quiero hacer.

Digamos que tengo una señal x (t). Quiero filtrar la primera mitad con un filtro de paso de banda con parámetros (100,200) Hz. La segunda mitad quiero filtrar con parámetros (140, 240) Hz. Repito sobre x (t), aplicando mi filtro a cada mitad y luego recombiné los resultados. Algún código de ejemplo podría parecer:

outputArray = np.empty(len(x))
segmentSize = len(x) / 2
filtParams  = [(100, 200), (140, 240)]

for i in range(2):
    tempData     = x[i*segmentSize:(i+1)*segmentSize]
    tempFiltered = bandPassFilter(tempData, parameters=filtParams[i])
    outputArray[i*segmentSize:(i+1)*segmentSize] = tempFiltered

(Para ahorrar espacio, supongamos que tengo una función que realiza el filtrado de paso de banda).

Como puede ver, los segmentos de datos no se superponen y simplemente se "pegan" nuevamente en la nueva matriz.

Editar 2 - Algún código de ejemplo de mi problema @ H.D.

En primer lugar, gracias por su importante contribución hasta el momento. El paquete de audiolazy parece una gran herramienta.

Pensé que sería un poco más útil si describiera mis objetivos con más detalle. Como he publicadoen otra parteEstoy intentando extraer elfrecuencia instantánea (IF) de una señal, utilizando la transformada de Hilbert. Mis datos contienen un ruido significativo, pero tengo una buena estimación del ancho de banda donde se encuentra mi señal de FI. Un problema al que me he enfrentado, sin embargo, es que el FI es a menudo no estacionario. Utilizando un enfoque de filtro "estático", por lo tanto, a menudo se me exige usar una región de paso de banda amplia, para garantizar que se capturen todas las frecuencias.

El siguiente código demuestra el efecto de aumentar el ancho de banda del filtro en una señal IF. Incluye una función de generación de señal, una implementación de un filtro de paso de banda utilizando el paquete scipy.signal y un método para extraer el IF de la señal filtrada resultante.

from audiolazy import *
import scipy.signal as sig
import numpy as np
from pylab import *

def sineGenerator( ts, f, rate, noiseLevel=None ):
    """generate a sine tone with time, frequency, sample rate and noise specified"""

    fs = np.ones(len(ts)) * f    
    y  = np.sin(2*np.pi*fs*ts)

    if noiseLevel: y = y + np.random.randn(len(y))/float(noiseLevel)
    return y

def bandPassFilter( y, passFreqs, rate, order ):
    """STATIC bandpass filter using scipy.signal Butterworth filter"""

    nyquist = rate / 2.0
    Wn      = np.array([passFreqs[0]/nyquist, passFreqs[1]/nyquist])    
    z, p, k = sig.butter(order, Wn, btype='bandpass', output='zpk')
    b, a    = sig.zpk2tf(z, p, k)

    return sig.lfilter(b, a, y)

if __name__ == '__main__':
     rate = 1e4
     ts   = np.arange(0, 10, 1/rate)

     # CHANGING THE FILTER AFFECTS THE LEVEL OF NOISE
     ys    = sineGenerator(ts, 600.0, 1e4, noiseLevel=1.0) # a 600Hz signal with noise
     filts = [[500, 700], [550, 650], [580, 620]]

    for f in filts:
        tempFilt = bandPassFilter( ys, f, rate, order=2 )
        tempFreq = instantaneousFrequency( tempFilt, rate )

        plot( ts[1:], tempFreq, alpha=.7, label=str(f).strip('[]') )

    ylim( 500, 750 )
    xlabel( 'time' )
    ylabel( 'instantaneous frequency (Hz)' )

    legend(frameon=False)
    title('changing filter passband and instantaneous frequency')
    savefig('changingPassBand.png')

Hay un solo componente de frecuencia en la señal (a 600Hz). La leyenda muestra los parámetros de filtro utilizados en cada caso. El uso de un filtro "estático" más estrecho da una salida "más limpia". Pero lo estrecho que puede ser mi filtro está limitado por lo que son las frecuencias. Por ejemplo, considere la siguiente señal con dos componentes de frecuencia (uno a 600Hz, otro a 650Hz).

En este ejemplo, me he visto obligado a usar un filtro de paso de banda más amplio, lo que ha dado lugar a un ruido adicional que se introduce en los datos de FI.

Mi idea es que al usar un filtro variable en el tiempo, puedo "optimizar" el filtro para mi señal en ciertos incrementos de tiempo. Entonces, para la señal anterior, es posible que desee filtrar alrededor de 580-620Hz durante los primeros 5 segundos, y luego de 630-670Hz durante los siguientes 5 segundos. Esencialmente quiero minimizar el ruido en la señal IF final.

Según el código de ejemplo que envió, escribí una función que usa audiolazy para implementar un filtro Butterworth estático en una señal.

def audioLazyFilter( y, rate, Wp, Ws ):
    """implement a Butterworth filter using audiolazy"""

    s, Hz = sHz(rate)
    Wp    = Wp * Hz # Bandpass range in rad/sample
    Ws    = Ws * Hz # Bandstop range in rad/sample

    order, new_wp_divpi = sig.buttord(Wp/np.pi, Ws/np.pi, gpass=dB10(.6), gstop=dB10(.1))
    ssfilt = sig.butter(order, new_wp_divpi, btype='bandpass')
    filt_butter = ZFilter(ssfilt[0].tolist(), ssfilt[1].tolist())

    return list(filt_butter(y))

Los datos de IF obtenidos utilizando este filtro junto con la rutina de transformación de Hilbert se comparan bien con los obtenidos usando scipy.signal:

AL_filtered = audioLazyFilter( ys, rate, np.array([580, 620]), np.array([570, 630]) )
SP_filtered = bandPassFilter( ys, [580, 620], rate, order=2 )
plot(ts[1:], instantaneousFrequency( SP_filtered, 1e4 ), alpha=.75, label='scipy.signal Butterworth filter')
plot(ts[1:], instantaneousFrequency( AL_filtered, 1e4 ), 'r', alpha=.75, label='audiolazy Butterworth filter')

Mi pregunta ahora es: ¿puedo combinar la rutina de audiolazy de Butterworth con las propiedades variables en el tiempo que describiste en tus publicaciones originales?

Respuestas a la pregunta(3)

Su respuesta a la pregunta