Joten muutin juuri sävelaskennan algoritmia harmonisen tuotespektrialgoritmin avulla. Olin vain utelias siitä, miksi tässä harmonisen tuotespektrin selityksessä todetaan, että sinun on toteutettava Hanning-ikkuna tietojoukkoon. Mikä olisi muiden Window-toimintojen toteuttamisen vaikutus tietojoukkoon (ja sitten sen FFT: n tekeminen)? Mikä Windowing-toiminto on todellakin paras taajuuden havaitsemiseen? Tässä ovat olennaiset menetelmät, joita olen käyttänyt koodissani:
/** * 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); }
Vastaa
FFT voidaan suorittaa vain rajoitetulla tietopalalla. Perusmatematiikka perustuu oletukseen, että aikavyöhykesignaali on jaksollinen, ts. Tietojesi toistuu ajassa. Tämä johtaa tyypillisesti merkittävään epäjatkuvuuteen palan reunoilla. Katsotaanpa nopea esimerkki: FFT-koko = 1000 pistettä, näytteenottotaajuus = 1000 Hz, taajuuden tarkkuus = 1 Hz. Jos sinulla on 10 Hz: n siniaalto, sinulla ei ole epäjatkuvuutta, koska tarkalleen 10 jaksoa mahtuu FFT-ikkunaan ja reunojen arvot (ja johdannaiset) ovat samat. Tämän siganlin FFT on nolla lukuun ottamatta yksittäistä arvoa säiliössä # 10. Tämä toimii yhtä hyvin myös 11 Hz: n siniaallolla. 10,3 HZ: n siniaallon kohdalla päädyt kuitenkin paljon epäjatkuvuuteen ja FFT: llä on energiaa kaikissa säiliöissä, joiden enimmäismäärä on noin 10 tai 11, ja sitten ”hameet”, jotka vierivät polkua sivuille. Joten pieni taajuuden muutos johtaa massiiviseen muutokseen FFT-kuvassa.
Tämän estämiseksi käytetään ikkunointia: Windows varmistaa, että reunojen tiedot ovat nollia, joten keskeytyksiä ei ole. Aikatoimialueen kertolasku on kuitenkin taajuusalueen konvoluutio, mikä johtaa spektriviivojen ja myös sivulohkojen laajenemiseen. Ikkunan valinta säätelee pääkoron leveyden ja sivukappaleen välin ja korkeuden kompromisseja. Sovelluskohtaiset vaatimukset määräävät, mitä ikkunaa käytetään, ja valintoja on kymmeniä. Hanning on vain yksi heistä. Se on periaatteessa valintaikkuna, jos sinulla ei ole parempia ideoita. Henkilökohtaisesti pidän parempana Kaiser-ikkunoista, koska niissä on jatkuva parametri, joka voi hallita ikkunan käyttäytymistä laajalla alueella.
Yleensä FFT ei ole hyvä tapa äänenkorkeuden havaitsemiseen. Suurimmalle osalle äänisignaaleista spektrin enimmäismäärä EI ole perustavanlaatuinen (tyypillisesti yliaaltojen energia on suurempi), jotta saat kunnollisen tarkkuuden, tarvitset pitkiä tietoja, mutta se tekee algoritmista hyvin hitaan ja hidas muutoksiin vastaamiseksi. Paljon parempia vaihtoehtoja ovat vaihehakuiset silmukat, viiveilmoitetut silmukat, autokorrelaatiot, max / min-seuranta, nolla-rajan seuranta jne.