Tehát most átdolgoztam a hangmagasság-számítási algoritmusomat egy harmonikus termékspektrum-algoritmus segítségével. Csak arra voltam kíváncsi, hogy a Harmonic Product Spectrum ezen magyarázata miért mondja ki, hogy az adatkészletre Hanning Window-t kell telepítenie. Mi lenne a hatása annak, ha más ablakfunkciókat hajtunk végre egy adathalmazon (majd FFT-sük)? Melyik Windowing funkció a legjobb a frekvencia érzékeléséhez? Íme a kódomban alkalmazott releváns módszerek:

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

Válasz

Az FFT csak korlátozott adatcsomag felett hajtható végre. Az alap matematika azon a feltételezésen alapul, hogy az időtartomány jele periodikus, vagyis az adatrészed megismétlődik időben. Ez tipikusan jelentős megszakítást eredményez a darab szélein. Nézzünk meg egy gyors példát: FFT méret = 1000 pont, Mintavételi frekvencia = 1000 Hz, Frekvencia felbontás = 1Hz. Ha 10 Hz-es szinuszhullámmal rendelkezik, akkor nem szakad meg, mivel pontosan 10 periódus illeszkedik az FFT ablakába és az élek értékei (és származékai) megegyeznek. Ennek a siganlnak az FFT értéke nulla lesz, kivéve a 10. számú tároló egyetlen értékét. Ez ugyanúgy működik egy 11 Hz-es szinuszhullám esetén is. A 10,3 HZ szinuszhullám esetében azonban sok megszakítás következik be, és az FFT energiája az összes tartályban maximum 10 vagy 11 körül lesz, majd “szoknyák”, amelyek oldalra gördülnek. Tehát egy kis frekvenciaváltozás az FFT képének hatalmas változását eredményezi.

Ennek elkerülésére az ablakosítást használják: A Windows gondoskodik arról, hogy a széleken lévő adatok nullaak legyenek, így nincs folytonosság. Az időtartományban történő szorzás azonban konvolúció a frekvenciatartományban, ami a spektrális vonalak és az oldalsó lebenyek kiszélesedését eredményezi. Az ablakválasztás vezérli a fő lebeny szélessége és az oldalsó lebeny távolsága és magassága közötti kompromisszumokat. Az alkalmazásspecifikus követelmények határozzák meg, hogy melyik ablakot kell használni, és több tucat választási lehetőség van. Hanning csak egy közülük. Alapjában véve a választott ablak, ha nincsenek jobb ötleteid. Személy szerint a Kaiser ablakokat részesítem előnyben, mivel azok folyamatos paraméterekkel rendelkeznek, amelyek széles tartományban szabályozhatják az ablak viselkedését.

Általában az FFT nem nagyszerű módszer a hangmagasság felismerésére. A legtöbb audiojel esetében a spektrum maximuma NEM az alapvető (általában a harmonikusok energiája nagyobb), a megfelelő felbontás eléréséhez hosszú adatokra van szükség, de ez nagyon lassúvá és lassúvá teszi az algoritmust a változásokra való reagáláshoz. Sokkal jobb lehetőségek a fázisú ciklusok, a késleltetett ciklusok, az autokorrelációk, a max / perc nyomkövető, a nulla keresztezésű nyomkövető stb.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük