Så jag reviderade bara min algoritm för tonhöjdsberäkning med hjälp av en harmonisk produktspektrumalgoritm. Jag var bara nyfiken på varför denna förklaring av Harmonic Product Spectrum säger att du måste implementera ett Hanning-fönster i datamängden. Vad skulle effekten av att implementera andra fönsterfunktioner på en datamängd (och sedan FFTing den)? Vilken Windowing-funktion är faktiskt bäst för frekvensdetektering? Här är de relevanta metoderna jag har använt i min kod:

/** * 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); } 

Svar

FFT kan endast utföras över en begränsad bit data. Den grundläggande matematiken baseras på antagandet att tidsdomänens signal är periodisk, dvs. din bit av data upprepas i tid. Det resulterar vanligtvis i en större diskontinuitet vid kanterna på biten. Låt oss titta på ett snabbt exempel: FFT-storlek = 1000 poäng, samplingsfrekvens = 1000 Hz, frekvensupplösning = 1Hz. Om du har en 10 Hz sinusvåg har du inte diskontinuitet eftersom exakt 10 perioder passar in i ditt FFT-fönster och värdena (och derivaten) vid kanterna är desamma. FFT för denna siganl kommer att vara noll förutom ett enda värde i fack # 10. Detta fungerar lika bra för en sinusvåg på 11 Hz. För 10,3 Hz sinusvåg slutar du dock med mycket diskontinuitet och FFT kommer att ha energi i alla soptunnor med maximalt cirka 10 eller 11 och sedan ”kjolar” som rullar ut till sidorna. Så en liten förändring i frekvens resulterar i en massiv förändring av FFT-bilden.

Windowing används för att undvika detta: Windows ser till att data vid kanterna är noll, så det finns ingen diskontinuitet. Multiplikation i tidsdomänen är emellertid faltning i frekvensdomänen och det resulterar i en utvidgning av spektrallinjer och även i sidlober. Valet av fönster styr avvägningarna mellan huvudlobbredd och sidlobavstånd och höjd. Dina applikationsspecifika krav avgör vilket fönster du ska använda och det finns dussintals val. Hanning är bara en av dem. Det är i princip det fönster du väljer om du inte har några bättre idéer. Personligen föredrar jag Kaiser-fönster eftersom de har en kontinuerlig parameter som kan kontrollera fönstrets beteende över ett brett intervall.

I allmänhet är FFT inte en bra metod för tonhöjdsavkänning. För de flesta ljudsignaler är maximalt i spektrumet INTE det grundläggande (vanligtvis övertoner har högre energi), för att få anständig upplösning behöver du långa bitar av data men det gör algoritmen mycket långsam och trög att svara på förändringar. Mycket bättre alternativ är fas-tittade slingor, fördröjda slingor, autokorrelationer, max / min tracker, zero crossing tracker, etc.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *