Așa că tocmai mi-am revizuit algoritmul de calcul al pitchului folosind un algoritm de spectru de produse armonice. Eram curios doar de ce această explicație a Harmonic Product Spectrum afirmă că trebuie să implementați o fereastră Hanning pentru setul de date. Care ar fi efectul implementării altor funcții Window pe un set de date (și apoi FFT-ul acestuia)? Care funcție Windowing este de fapt cea mai bună pentru detectarea frecvenței? Iată metodele relevante pe care le-am folosit în codul meu:

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

Răspuns

FFT-ul poate fi efectuat numai pe o parte limitată de date. Matematica de bază se bazează pe presupunerea că semnalul domeniului de timp este periodic, adică o parte din date se repetă în timp. Acest lucru duce de obicei la o discontinuitate majoră la marginile bucății. Să vedem un exemplu rapid: dimensiunea FFT = 1000 de puncte, rata de eșantionare = 1000 Hz, rezoluția de frecvență = 1 Hz. Dacă aveți o undă sinusoidală de 10 Hz, nu aveți o discontinuitate, deoarece exact 10 perioade se potrivesc în fereastra FFT iar valorile (și derivatele) de la margini sunt aceleași. FFT-ul acestui siganl va fi zero, cu excepția unei singure valori în coșul # 10. Acest lucru funcționează și pentru o undă sinusoidală de 11 Hz. Cu toate acestea, pentru undă sinusoidală de 10,3 HZ veți ajunge la o mulțime de discontinuitate, iar FFT va avea energie în toate coșurile cu maxim 10 sau 11 și apoi „fuste” care se rostogolesc în lateral. Deci, o mică modificare a frecvenței duce la o schimbare masivă a imaginii FFT.

Windowing este folosit pentru a evita acest lucru: Windows asigură-te că datele de la margini sunt zero, deci nu există discontinuitate. Cu toate acestea, multiplicarea în domeniul timpului este convoluție în domeniul frecvenței și care are ca rezultat lărgirea liniilor spectrale și, de asemenea, în lobi laterali. Alegerea ferestrei controlează compromisurile între lățimea lobului principal și distanța și înălțimea lobului lateral. Cerințele specifice aplicației dvs. determină ce fereastră să utilizați și există zeci de opțiuni. Hanning este doar unul dintre ei. Practic este „fereastra de alegere” dacă nu aveți idei mai bune. Personal, prefer ferestrele Kaiser deoarece au un parametru continuu care poate controla comportamentul ferestrei pe o gamă largă.

În general, FFT nu este o metodă excelentă pentru detectarea înălțimii. Pentru majoritatea semnalelor audio, maximul din spectru NU este fundamental (de obicei armonicele au o energie mai mare), pentru a obține o rezoluție decentă, aveți nevoie de o lungă bucată de date, dar acest lucru face ca algoritmul să fie foarte lent și lent pentru a răspunde la schimbări. Opțiuni mult mai bune sunt buclele cu aspect de fază, buclele cu aspect de întârziere, corelările automate, urmăritorul max / min, urmăritorul de trecere zero etc.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *