Quindi ho appena rivisto il mio algoritmo di calcolo del tono utilizzando un algoritmo di spettro del prodotto armonico. Ero solo curioso di sapere perché questa spiegazione di Harmonic Product Spectrum afferma che è necessario implementare una finestra Hanning per il set di dati. Quale sarebbe leffetto dellimplementazione di altre funzioni Window su un set di dati (e poi FFT)? Quale funzione di Windowing è effettivamente la migliore per il rilevamento della frequenza? Di seguito sono riportati i metodi pertinenti che ho utilizzato nel mio codice:

/** * Calculates the Frequency based off of the byte array, * @param bytes The audioData you want to analyze * @return The calculated frequency in Hertz. */ private int getFrequency(byte[] bytes){ double[] audioData = this.bytesToDoubleArray(bytes); audioData = applyHanningWindow(audioData); Complex[] complex = new Complex[audioData.length]; for(int i = 0; i<complex.length; i++){ complex[i] = new Complex(audioData[i], 0); } Complex[] fftTransformed = FFT.fft(complex); //return calculateFrequency(fftTransformed); System.out.println("Max size:" + (fftTransformed.length*getFFTBinSize(fftTransformed.length)/4)); return calculateFundamentalFrequency(fftTransformed,4); } private double[] applyHanningWindow(double[] data){ return applyHanningWindow(data, 0, data.length); } private double[] applyHanningWindow(double[] signal_in, int pos, int size) { for (int i = pos; i < pos + size; i++) { int j = i - pos; // j = index into Hann window function signal_in[i] = (double)(signal_in[i] * 0.5 * (1.0 - Math.cos(2.0 * Math.PI * j / size))); } return signal_in; } /** * Harmonic Product Spectrum * @param fftData * @param n * @return */ private int calculateFundamentalFrequency(Complex[] fftData, int n){ Complex[][] data = new Complex[n][fftData.length/n]; for(int i = 0; i<n; i++){ for(int j = 0; j<data[0].length; j++){ data[i][j] = fftData[j*(i+1)]; } } Complex[] result = new Complex[fftData.length/n];//Combines the arrays for(int i = 0; i<result.length; i++){ Complex tmp = new Complex(1,0); for(int j = 0; j<n; j++){ tmp = tmp.times(data[j][i]); } result[i] = tmp; } //Calculates Maximum Magnitude of the array double max = Double.MIN_VALUE; int index = -1; for(int i = 0; i<result.length; i++){ Complex c = result[i]; double tmp = c.getMagnitude(); if(tmp>max){ max = tmp;; index = i; } } return index*getFFTBinSize(fftData.length); } 

Answer

La FFT può essere eseguita solo su un blocco limitato di dati. La matematica di base si basa sul presupposto che il segnale nel dominio del tempo sia periodico, ovvero il blocco di dati viene ripetuto nel tempo. Ciò si traduce in genere in una maggiore discontinuità ai bordi del blocco. Vediamo un rapido esempio: dimensione FFT = 1000 punti, frequenza di campionamento = 1000 Hz, risoluzione in frequenza = 1 Hz. Se hai unonda sinusoidale a 10 Hz, non hai discontinuità poiché esattamente 10 periodi rientrano nella finestra FFT ei valori (e le derivate) ai bordi sono gli stessi. La FFT di questo sigillo sarà zero ad eccezione di un singolo valore nel bin # 10. Questo funziona anche per unonda sinusoidale a 11 Hz. Tuttavia, per unonda sinusoidale di 10,3 HZ si finisce con molta discontinuità e la FFT avrà energia in tutti i contenitori con un massimo di circa 10 o 11 e quindi le “gonne” che rotolano si allontanano ai lati. Quindi un piccolo cambiamento nella frequenza si traduce in un enorme cambiamento nellimmagine FFT.

La creazione di finestre viene utilizzata per evitare questo: Windows si assicura che i dati ai bordi siano zero, quindi non ci sono discontinuità. Tuttavia, la moltiplicazione nel dominio del tempo è convoluzione nel dominio della frequenza e ciò si traduce in un allargamento delle righe spettrali e anche nei lobi laterali. La scelta della finestra controlla i compromessi tra la larghezza del lobo principale e la spaziatura e laltezza dei lobi laterali. I requisiti specifici dellapplicazione determinano quale finestra utilizzare e sono disponibili dozzine di scelte. Hanning è solo uno di loro. È “fondamentalmente” la finestra di scelta se non hai idee migliori “. Personalmente, preferisco le finestre Kaiser poiché hanno un parametro continuo che può controllare il comportamento della finestra su un ampio intervallo.

In generale FFT non è un ottimo metodo per il rilevamento del tono. Per la maggior parte dei segnali audio il massimo nello spettro NON è fondamentale (tipicamente le armoniche hanno unenergia maggiore), per ottenere una risoluzione decente sono necessari lunghi pezzi di dati ma ciò rende lalgoritmo molto lento e lento a rispondere ai cambiamenti. Opzioni molto migliori sono i loop di fase, loop di ritardo, autocorrelazioni, tracker max / min, tracker zero crossing, ecc.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *