Un Sistema tempo-invariante o sistema stazionario, talvolta abbreviato in TIV (dall’acronimo inglese Time-Invariant System), è un sistema dinamico in cui l’uscita non dipende esplicitamente dal tempo. I sistemi tempo-invarianti sono descritti matematicamente da equazioni autonome e dalla funzione di trasferimento, e sono caratterizzati dal fatto che se un ingresso x(t) produce l’uscita y(t) allora per ogni ingresso traslato x(t+delta) si ha un’uscita traslata dello stesso fattore y(t+delta).
Tra i sistemi stazionari maggiormente studiati ci sono quelli lineari.
Un’altra definizione di stazionarietà è quella statistica. Se si considerano i momenti statistici di ordine n, la media (primo momento) non varia nel tempo, ma la varianza (secondo momento) si.
Quasi-stazionarietà Locale
Questo tipo di sistema può essere approssimato a stazionario per campioni molto brevi. Pochi segnali nel mondo reale sono stazionari, ma quasi tutti possono essere approssimati a quasi-stazionari.
Analisi “a Blocchi / finestre”
Per avere quasi-stazionarietà si analizza il segnale “a blocchi”. La durata del blocco dipende dal contesto, bisogna controllare che tutti gli elementi del blocco appaiano “simili”. Se si analizza del parlato ad esempio si dovrebbe analizzare ogni fonema singolarmente.
Il Framing in ambito dell’elaborazione dei segnali reali prevede l’analisi di un segnale attraverso l’utilizzo di dei brevi (massimo 400ms) intervalli detti frame che possano più o meno approssimare le caratteristiche del segnale in quel determinato intervallo.
Si deve anche considerare la correlazione tra i dati presenti nel frame. L’analisi di più note diverse nello stesso frame, o di più simboli fonetici nello stesso frame porta ad un’approssimazione di diversi processi casuali che non funziona molto bene, quindi l’ideale è avere dati simili all’interno del frame.
Nella teoria dei segnali, il Valore efficace (spesso siglato con eff o con rms - dall’inglese root mean square) di una funzione periodica (e non solo), è il valore che avrebbe un “segnale costante” di pari potenza media:
xRMS=n1∑i=0N−1xi2
Ovvero, in regime di corrente elettrica alternata, il valore rms è equivalente al valore della corrente continua costante, in grado di produrre la stessa dissipazione di potenza, in un carico resistivo. In elettrotecnica, il valore efficace viene introdotto nel regime alternato e trifase, per un confronto con la corrente continua, semplificando l’espressione della potenza media ed evitando l’analisi istante per istante del suo andamento. Così, ad esempio, la tensione di rete del fornitore di energia elettrica civile (ma anche in ambito industriale) è dato come valore efficace pari a 240 V (anche Vca o VAC) = 240 volt rms (o Vrms). È quindi spesso più utile per capire l’andamento delle intensità e delle tensioni della corrente elettrica, in un circuito in regime alternato (sia di forma periodica che di forma arbitraria).
Lo Zero Crossings Rate (ZCR), o tasso di attraversamento dello zero, rappresenta il numero di volte in cui un segnale attraversa l’asse dello zero in un determinato intervallo di tempo o in un frame di segnale.
Il ZCR è particolarmente utile per distinguere suoni con caratteristiche spettrali diverse:
Differenziazione tra voce e musica: I suoni a più alta frequenza, come il rumore e molti strumenti a percussione, hanno un elevato ZCR, mentre le vocali e altri suoni a bassa frequenza tendono ad avere un basso ZCR.
Segmentazione e classificazione dei suoni: Il ZCR è utile per rilevare e classificare differenti tipi di suoni. Ad esempio, nella classificazione delle fricative nella voce (come “s” e “sh”), che hanno un tasso di attraversamento elevato, rispetto a vocali come “a” o “o”.
Riconoscimento del parlato: In combinazione con altre caratteristiche (come MFCC e energia), il ZCR è usato per segmentare e riconoscere il parlato.
In analisi matematica, la Trasformata di Fourier è una trasformata integrale, cioè un operatore che trasforma una funzione in un’altra funzione mediante un’integrazione. Trova numerose applicazioni nella fisica e nell’ingegneria ed è uno degli strumenti matematici maggiormente utilizzati nell’ambito delle scienze pure e applicate, permettendo di scrivere una funzione dipendente dal tempo come combinazione lineare (eventualmente continua) di funzioni di base esponenziali.
La trasformata di Fourier associa a una funzione i valori dei coefficienti di questi sviluppi lineari, dandone in questo modo una rappresentazione nel dominio delle frequenze che viene spesso chiamata spettro della funzione (la relazione con il concetto di spettro di un operatore può essere compresa se si considera l’operatore di convoluzione con la funzione in esame). A volte si intende per trasformata di Fourier la funzione che risulta dall’applicazione di questo operatore.
In termini semplici, la trasformata di Fourier permette di passare da una rappresentazione nel dominio del tempo (o spazio) a una rappresentazione nel dominio delle frequenze. Se abbiamo una funzione f(t) che descrive un segnale nel tempo, la sua trasformata di Fourier F(ω) ci darà una descrizione di quel segnale in termini delle sue frequenze componenti.
Si può sintetizzare il suono analogico tramite la trasformata inversa, ovvero la sintesi di Fourier.
L’analisi di Fourier si può presentare in diverse modalità in base al tipo di segnale da analizzare.
Tipi di segnale
Un segnale può essere continuo o discreto nel tempo.
Quando un segnale è continuo nel tempo, la trasformata di Fourier sarà discreta in frequenza, e viceversa.
Quindi tramite le operazioni di Campionamento e Quantizzazione si ottiene una trasformata di Fourier continua nel tempo.
Serie di Fourier
Nel caso di segnali periodici continui si realizza la conversione tempo / frequenza tramite la Serie di Fourier, che descrive un segnale una somma pesata di sinusoidi armoniche, multiple della frequenza principale di un multiplo k intero. Se il coefficiente k non fosse intero il segnale non potrebbe essere periodico.
Il segnale in frequenza è la densità spettrale di potenza, non energia, in quanto l’energia dei segnali periodici è infinita.
In matematica, la trasformata di Fourier a tempo discreto (DTFT) è una forma di analisi di Fourier applicabile a una sequenza di valori discreti.
La DTFT viene spesso utilizzata per analizzare campioni di una funzione continua. Il termine tempo discreto si riferisce al fatto che la trasformata opera su segnali aperiodici a tempo discreto. F{xs(t)}=∑n=−∞∞x(nTs)e−jω(nTs)
dove nTs indica multipli del periodo di campionamento Ts e la frequenza dello spettro ω è continua.
L’operazione di campionamento di un segnale periodico a tempo discreto genera un segnale con spettro periodico ripetuto ad intervalli Fs, con Fs Sampling frequency.
Bisogna quindi ritagliare la porzione di spettro fino a 2Fs mediante l’uso di un filtro Filtro passa banda per rispettare il Teorema di Nyquist ed evitare che si crei Aliasing.
Lo spettro di un segnale campionato è dato dalla Convoluzione dello spettro del segnale con quello di un Treno di impulsi. Xs(ωs)=X(ω)∗∑n=−∞+∞T1δ(ω−nωs)=Ts1∑n=−∞+∞X(ω−nωs)
Risulta quindi un segnale scalato e ripetuto ogni frequenza Fs=ωs.
Più generalmente è possibile trovare la DFT campionando il risultato in frequenza della DTFT lungo un solo periodo in N punti equidistanti (generalmente 1024 o 2048). La precisione della DFT cresce al crescere di N.
La DFT è molto sensibile al fenomeno di Spectral Leakage.
Notare che la DFT e la DTFT non sono la stessa cosa.
La DTFT è continua nel dominio della frequenza, il passaggio che collega le due è il campionamento dell’output della DTFT per generare la DFT e potervi lavorare con un computer che lavora a numeri finiti.
Quando si utilizzano segnali aperiodici che vengono periodicizzati estraendone un pezzo ed estendendolo tramite periodicizzazione, questi non sono segnali periodici puri, e la transizione brusca tra un periodo e il successivo crea componenti in frequenza aggiuntive.
Questo effetto, molto presente nella DFT può essere ridotto mediante l’utilizzo di finestrature pesate e Zero Padding.
La tecnica dello zero padding permette di aumentare la densità di campioni fino ad arrivare ad un numero (o multiplo di) di riferimento, senza intaccare in maniera significativa il segnale originale.
Il padding non cambia lo spettro di energia del segnale, ma nei sistemi che richiedono campioni multipli di un numero N, permette di aggiungere “tracce vuote” prima e/o dopo il segnale originale per arrivare ad un numero adeguato di campioni.
Padding
In numpy si può usare il padding tramite la funzione np.pad.
Questa funzione permette di effettuare un padding destro, sinistro o uniforme, e di scegliere con che valore costante “imbottire” il segnale.
Nella frequenza si può notare che l’asse delle x (frequenze) viene scalato in quanto vi è un maggior numero di campioni, ma si può risolvere dividendo per N∗=N1N2 dove 1 e 2 indicano il numero di campioni prima e dopo il padding.
La Short Term Fourier Transform (STFT) è una trasformata di Fourier utilizzata per determinare la frequenza sinusoidale e il contenuto di fase delle sezioni locali di un segnale al variare del tempo. In pratica, la procedura per calcolare gli STFT consiste nel dividere un segnale di tempo più lungo in segmenti più corti di uguale lunghezza e quindi calcolare la trasformata di Fourier separatamente su ciascun segmento più corto. Questo rivela lo spettro di Fourier su ogni segmento più corto. Di solito si tracciano gli spettri che cambiano in funzione del tempo, noto come spettrogramma o grafico a cascata. I display a larghezza di banda completa che coprono l’intera gamma di un SDR utilizzano comunemente trasformate di Fourier veloci (FFT) con 224 punti sui computer desktop.
Lo Spettrogramma, nell’ambito dell’analisi audio e della fonetica acustica, è la rappresentazione grafica - fornita da uno spettrografo - dell’intensità di un suono in funzione del tempo e della frequenza o, in altre parole, è la rappresentazione grafica della funzione reale i delle variabili reali t ed f: i(t,f).
L’asse delle ascisse rappresenta il tempo, le ordinate rappresentano la frequenza. Si usa una codifica a colori o scala di grigi per rappresentare quali frequenze hanno intensità maggiore.
Durata delle armoniche
Già dallo spettrogramma è possibile notare che generalmente le armoniche a frequenze più basse sono quelle che tendono a durare di più nel tempo, mentre quelle a frequenze più alte sono molto volatili.
import numpy as npimport librosaimport matplotlib.pyplot as pltN = 1000 # Numero di campioniFs = 8000 # Frequenza di campionamentonummap = { '1': (697, 1209), '2': (697, 1336), '3': (697, 1477), '4': (770, 1209), '5': (770, 1336), '6': (770, 1477), '7': (852, 1209), '8': (852, 1336), '9': (852, 1477), '0': (941, 1336), '*': (941, 1209), '#': (941, 1477),}frequencies = [697, 770, 852, 941, 1209, 1336, 1477]## UTILS# Funzione per trovare il valore più vicino a k in lstdef closest(lst, k): return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-k))]# Funzione per plottare la trasformata di Fourierdef plt_transform(freq, sp): plt.grid() plt.plot(freq, sp) plt.xlim([0, Fs/2]) plt.show()# Funzione per applicare la trasformata di Fourier in frequenze. Opzionalmente mostra il grafico della trasformata.def transform(y, Fs=Fs, plot=False): sp = np.fft.fft(y) # Trasformata di Fourier sp = np.abs(sp) # Metti i valori dell'energia in valore assoluto freq = np.fft.fftfreq(len(sp), 1/Fs) # Trova le frequenze associate ai valori della trasformata if(plot): plt_transform(freq, sp) # Plotta la trasformata se richiesto return sp, freq## CORE# Funzione per generare una cifra DTMFdef num_gen(num, N=1000, Fs=Fs): f1, f2 = nummap[num] # Frequenze associate alla cifra return .5*librosa.tone(f1, sr=Fs, length=N) + .5*librosa.tone(f2, sr=Fs, length=N) # Genera il tono come somma di sinusoidi# Funzione per trovare le frequenze associate a un tono DTMFdef find_freq(y, Fs=8000): sp, freq = transform(y, Fs) # Applica la trasformata di fourier z = zip(sp, freq) zs = sorted(z) # Ordina le frequenze per energia maggiore # Il codice successivo applica un filtro passa banda soltanto attorno alle frequenze stabilite in frequencies, con una tolleranza TOL. # Questo permette di ridurre il rumore esterno e facilitare i calcoli. TOL = Fs / len(sp) l = [(sp, freq) for sp, freq in zs if freq > 0 and any(abs(freq - target_freq) <= TOL for target_freq in frequencies)] return tuple(sorted((closest(frequencies, l[-1][1]), closest(frequencies, l[-2][1])))) # Associo le frequenze trovate a quelle più vicine che si trovano in frequencies# Funzione per associare il tono DTMF a una cifradef num_find(f1, f2): for key, value in nummap.items(): if value == (f1, f2): return key# Funzione per generare un numero DTMFdef gen_dtmf(str, F=2000, tone_length=1, silence_length=0.1): dtmf = np.array([]) # Inizializzo il segnale for c in str: # Per ogni cifra devo generare il tono e il silenzio dtmf = np.concatenate((dtmf, np.zeros(int(silence_length*Fs)), num_gen(c, F*tone_length), np.zeros(int(silence_length*Fs))), axis=0) return dtmf# Funzione per analizzare un segnale DTMFdef analyze_dtmf(data=None, Fs=Fs, single_tone_length=0.3): N = len(data) ret = "" step = round(Fs*single_tone_length) # Lunghezza di un tono tones = [data[i:i+step] for i in range(0, len(data), step)] # Separa i toni for tone in tones: #transform(tone, Fs, plot=True) # Abilita questo per stampare la trasformata di ogni tono trovato try: freq = find_freq(tone, Fs) # Trova le frequenze associate al tono except IndexError: continue try: ret += num_find(freq[0], freq[1]) # Trova la cifra associata alle frequenze except TypeError: continue return ret## SCRIPT# Leggere un numero da un file audio sulla memoriaw, Fs = librosa.load('dtmf-example.wav', sr=None) # Carico il file audiofreq = find_freq(w, Fs) # Trovo le frequenze associate al file audio# Generare tutti i toni e controllare che le frequenze combacinofor key in nummap.keys(): # Per ogni cifra w = num_gen(key, N=1000) # Genera il tono della cifra freq = find_freq(w, Fs) # Trova le frequenze associate al tono print(num_find(freq[0], freq[1]), end=", ") # Stampa la cifra associata alle frequenzeprint()input = '3348193454' # Numero da generarenum = gen_dtmf(input, tone_length=.5, silence_length=0.1) # Genera il tono del numeroipd.Audio(data=num, rate=Fs) # Riproduci il suono su weboutput = analyze_dtmf(num, Fs, librosa.get_duration(y=num, sr=Fs)/len(input)) # Analizza il numero generatoprint(output)