Så jeg reviderte bare algoritmen for tonehøydeberegning ved hjelp av en harmonisk produktspektrumalgoritme. Jeg var bare nysgjerrig på hvorfor denne forklaringen av Harmonic Product Spectrum sier at du trenger å implementere et Hanning-vindu i datasettet. Hva ville effekten være av å implementere andre Window-funksjoner på et datasett (og deretter FFTing det)? Hvilken Windowing-funksjon er faktisk best for frekvensdeteksjon? Her er de relevante metodene jeg har brukt i koden min:
/** * 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 bare utføres over et begrenset stykke data. Den grunnleggende matematikken er basert på antagelsen om at tidsdomenesignalet er periodisk, dvs. at dataen din blir gjentatt i tide. Det resulterer vanligvis i en stor diskontinuitet i kantene av bunnen. La oss se på et raskt eksempel: FFT-størrelse = 1000 poeng, samplingsfrekvens = 1000 Hz, frekvensoppløsning = 1 Hz. Hvis du har en 10 Hz sinusbølge, har du ikke diskontinuitet siden nøyaktig 10 perioder passer inn i FFT-vinduet ditt. og verdiene (og derivatene) ved kantene er de samme. FFT for denne siganl vil være null bortsett fra en enkelt verdi i bin # 10. Dette fungerer også like bra for en sinusbølge på 11 Hz. Imidlertid, for 10,3 HZ sinusbølge, ender du opp med mye diskontinuitet, og FFT vil ha energi i alle søppelkasser med maksimalt rundt 10 eller 11 og deretter «skjørt» som ruller sti av til sidene. Så en liten endring i frekvens resulterer i en massiv endring i FFT-bildet.
Windowing brukes for å unngå dette: Windows sørger for at dataene i kantene er null, så det er ingen diskontinuitet. Imidlertid er multiplikasjon i tidsdomenet sammenblanding i frekvensdomenet, og det resulterer i utvidelse av spektrale linjer og også i sidelapper. Valget av vindu styrer avveiningen mellom hovedlobbredde og sidelappavstand og høyde. Dine applikasjonsspesifikke krav avgjør hvilket vindu du skal bruke, og det er dusinvis av valg. Hanning er bare en av dem. Det er i utgangspunktet det valgte vinduet hvis du ikke har noen bedre ideer. Personlig foretrekker jeg Kaiser-vinduer, ettersom de har en kontinuerlig parameter som kan kontrollere vindusoppførselen over et bredt spekter.
Generelt er FFT ikke en god metode for tonehøyde-deteksjon. For de fleste lydsignaler er IKKE det maksimale i spekteret det grunnleggende (vanligvis harmoniske har høyere energi). For å få anstendig oppløsning trenger du lange data, men det gjør algoritmen veldig treg og treg for å svare på endringer. Mye bedre alternativer er fasekikkede sløyfer, forsinkede sløyfer, autokorrelasjoner, maks / min tracker, zero crossing tracker, etc.