Forum >> Programmazione Python >> Calcolo scientifico >> Verifica funzionamento di un filtro

Pagina: 1

Buongiorno a tutti, sono un novizio di Python e vi chiedo cortesemente aiuto per questo quesito:


Voglio verificare la risposta in frequenza di un filtro quindi prendo un rumore bianco e lo filtro per poi fare il rapporto spettrale e sovrapporre la risposta in frequenza nominale del filtro.


Ovviamente il risultato non coincide e non riesco a capire dove sbaglio....




1) creazione del filtro passa-basso Butterworth I ordine, 10 Hz




# creating I order, 10 Hz, low pass Butterworth filter
fc = 10 # Hz
wc = 2*np.pi*fc # rad/s
b, a = signal.butter(1, wc, 'low', analog=True)    # mi ritorna un sistema Num(s)/Den(s)
num=b
den=a

w, h = signal.freqs(b, a)    # ideal frequency response of filter
w = 0.5*w/np.pi                # rad/s to Hz
amp=20*np.log10(np.abs(h))    # amplitude to dB

'''
# ideal filter frequency response dB vs Hz
plt.plot(w, amp)
plt.xscale('log')
plt.grid()
plt.xlabel("Frequency Hz")
plt.ylabel("Amplitude dB")
plt.show()
'''
2) ricavo la risposta impulsiva del filtro da usare con la convoluzione nel dominio del tempo per filtrare un generico segnale




system=signal.lti(num, den)
t, impulse_resp = signal.impulse(system)
impulse_resp = impulse_resp[1:]     # removing first element due it's always 0.0
t = t[1:]

print("Risposta impulsiva:")        # filter impulse response (kernel of filter in time domain)
print(impulse_resp)

# normalizing kernel to 1.0
kernel=len(impulse_resp)
impulse_resp=impulse_resp /sum(impulse_resp)    # vado a normalizzare il kernel per il filtro
print(sum(impulse_resp))

# now I can use impulse response as kernel in time domain
3) creo un rumore bianco (ricavo lo spettro) e lo filtro con la convoluzione nel dominio del tempo (e rivavo lo spettro anche di questo)

# let's make some noise
mu, sigma = 0, 0.1
sample = 100000            # 100k samples
Fs=1000                    # SPS sampling frequency
x = np.arange(sample)
noise = np.random.normal(mu, sigma, len(x))  # noise

# time domain to frequency domain (noise)
#f, psd = signal.periodogram(noise, Fs)
f, psd = signal.welch(noise, Fs, scaling='spectrum')

# removing first element due related to 0 Hz (for log scale)
f=f[1:]
psd=psd[1:]


# filtering in time domain using convolution and filter impulse response
filtrato=np.convolve(noise, impulse_resp)    # filtering noise
filtrato=filtrato[:len(filtrato)-len(impulse_resp)+1]    # equalizing length due to kernel dimension

# time domain to frequency domain for filtered noise
#f, psd2 = signal.periodogram(filtrato, Fs)
f, psd2 = signal.welch(filtrato, Fs, scaling='spectrum')

# as above
f=f[1:]
psd2=psd2[1:]
4) rapporto degli spettri, plot della risposta in frequenza e confronto con la risposta in frequenza nominale del filtro:




# ratio filtered/unfiltered signal
legenda=[]
tf=psd2/psd
plt.plot(f,20*np.log10(tf))
legenda.append("real")
plt.plot(w, amp)
legenda.append("ideal")
plt.xscale('log')
plt.xlabel('Frequency Hz')
plt.ylabel('Attenuation dB')
plt.legend(legenda)
plt.show()

Magari voi che siete più esperti riuscite a capirlo subito...
Grazie in anticipo.



Allegati
Ciao caro, non ti ci vuole un programmatore, ma un esorcista. :D

Scherzi a parte non so come aiutarti, non so nulla di quello che hai menzionato.

Ti posso solo suggerire, nel caso non riceva aiuto, di rivolgerti anche agli altri canali della nostra comunità.

Un grosso in bocca al lupo.




Aaaaaallora.... devo aver fatto un po' di confusione mischiando analogico e digitale.

Il codice corretto dovrebbe essere questo (devo solo studiare perchè con il periodogram devo usare 10 anzichè 20):

from __future__ import unicode_literals


from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
import datetime
from obspy.core import read
import obspy
from obspy import *
from obspy.core import utcdatetime
#from obspy.signal import bandpass
#from numpy import mean, sqrt, square, arange
import operator
import sys
from obspy.signal.trigger import classic_sta_lta
from obspy.signal.trigger import carl_sta_trig
from scipy.signal import bessel, lsim
import pylab
import copy
from scipy import signal
import os
import time
import math
from scipy import integrate
from obspy import read
#import plotly.plotly as py
#import plotly.graph_objs as go


from obspy.signal.trigger import classic_sta_lta, plot_trigger
#intanto vado a leggere la traccia in SAC
from math import*



# creating I order, 10 Hz, low pass Butterworth filter
fc = 10 # Hz
wc = 2*np.pi*fc # rad/s
b, a = signal.butter(1, wc, 'low', analog=True)    # mi ritorna un sistema Num(s)/Den(s)

# verifica della funzione di trasferimento
w, h = signal.freqs(b, a)	# ideal frequency response of filter
w = 0.5*w/np.pi				# rad/s to Hz
amp=20*np.log10(np.abs(h))	# amplitude to dB

plt.plot(w, amp)
plt.xscale('log')
plt.xlabel('Frequency Hz')
plt.ylabel('Attenuation dB')
plt.grid()
#plt.ylim(-60, 0)
plt.show()


# creazione della base dei tempi
time=80.0	# durata del segnales
Fs=1000	# frequenza di campionamento Hz
t = np.linspace(0, time, (time*Fs)+1)

# let's make some noise
mu, sigma = 0, 0.1
noise = np.random.normal(mu, sigma, len(t))  # noise

# simulazione della risposta utilizzando lsim
u = noise
# U e T sono i vettori dei valori e la scala dei tempi
tout, yout, xout = lsim((b, a), U=u, T=t)

# passaggio al dominio della frequenza
f, psd = signal.periodogram(u, Fs)
psd_noise=psd[1:]

f, psd = signal.periodogram(yout, Fs)
psd_signal=psd[1:]

# removing first element due related to 0 Hz (for log scale)
f=f[1:]


# ratio filtered/unfiltered signal
legenda=[]
tf=psd_signal/psd_noise
#plt.plot(f,20*np.log10(tf))
plt.plot(f,10*np.log10(tf))

legenda.append("real")
plt.plot(w, amp)
legenda.append("ideal")
plt.xscale('log')
plt.xlabel('Frequency Hz')
plt.ylabel('Attenuation dB')
plt.legend(legenda)
plt.grid()
#plt.ylim(-60, 0)
plt.show()




A meno di errori di copia e incolla dovrebbe funzionare....


Pagina: 1



Esegui il login per scrivere una risposta.