그래서 방금 고조파 제품 스펙트럼 알고리즘을 사용하여 피치 계산 알고리즘을 수정했습니다. Harmonic Product Spectrum에 대한이 설명에서 데이터 세트에 해닝 창을 구현해야한다고 말하는 이유가 궁금했습니다. 데이터 세트에 다른 Window 기능을 구현 한 다음 FFT를 수행하면 어떤 효과가 있습니까? 실제로 주파수 감지에 가장 적합한 윈도우 기능은 무엇입니까? 내 코드에서 사용한 관련 방법은 다음과 같습니다.

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

Answer

FFT는 제한된 데이터 청크에 대해서만 수행 할 수 있습니다. 기본 수학은 시간 도메인 신호가 주기적이라는 가정을 기반으로합니다. 즉, 데이터 청크가 시간에 따라 반복됩니다. 이는 일반적으로 청크의 가장자리에서 중대한 불연속성을 초래합니다. 간단한 예를 살펴 보겠습니다. FFT 크기 = 1000 포인트, 샘플 속도 = 1000Hz, 주파수 해상도 = 1Hz. 10Hz 사인파가있는 경우 정확히 10 개의주기가 FFT 창에 맞기 때문에 불연속성이 없습니다. 가장자리의 값 (및 파생)은 동일합니다. 이 siganl의 FFT는 bin # 10의 단일 값을 제외하고 0입니다. 이것은 11Hz 사인파에도 적용됩니다. 그러나 10.3 HZ 사인파의 경우 많은 불연속성이 발생하고 FFT는 최대 약 10 또는 11의 모든 빈에 에너지를 갖게 된 다음 측면으로 뒤 따르는 “치마”를 갖게됩니다. 따라서 주파수의 작은 변화는 FFT 그림에 큰 변화를 가져옵니다.

윈도우는이를 방지하는 데 사용됩니다. Windows는 가장자리의 데이터가 0인지 확인하여 불연속성이 없도록합니다. 그러나 시간 영역에서의 곱셈은 주파수 영역에서의 컨볼 루션이며 그 결과 스펙트럼 라인과 사이드 로브가 확장됩니다. 창 선택은 메인 로브 폭과 사이드 로브 간격 및 높이 간의 균형을 제어합니다. 애플리케이션 별 요구 사항은 사용할 창을 결정하며 수십 가지 선택 사항이 있습니다. 해닝은 그들 중 하나 일뿐입니다. 기본적으로 “더 나은 아이디어가없는 경우 선택하는 창”입니다. 개인적으로 Kaiser 창은 넓은 범위에서 창 동작을 제어 할 수있는 연속 매개 변수가 있기 때문에 선호합니다.

일반적으로 FFT는 피치 감지에 좋은 방법이 아닙니다. 대부분의 오디오 신호의 경우 스펙트럼의 최대 값은 기본이 아닙니다 (일반적으로 고조파는 더 높은 에너지를 가짐). 적절한 해상도를 얻으려면 긴 데이터 조각이 필요하지만 알고리즘이 변경에 응답하는 데 매우 느리고 느리게 만듭니다. 훨씬 더 나은 옵션은 위상 검토 루프, 지연 검토 루프, 자동 상관, 최대 / 최소 추적기, 제로 교차 추적기 등입니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다