2013-05-27 2 views
0

Accelerate vDSP 프레임 워크를 사용하여 기존 FFT 기반 저역 통과 필터를 iOS로 이식하려고합니다.iOS 저속 통과 FFT 필터 미러링 결과 가속

FFT가 샘플의 1/4에 대해 예상대로 작동하는 것처럼 보입니다. 그러나 그 후에 결과는 틀린 것처럼 보이고, 훨씬 더 이상한 것은 미러됩니다 (상반기의 대부분을 미러링하는 신호의 마지막 절반으로).

아래 테스트 응용 프로그램의 결과를 볼 수 있습니다. 먼저 샘플링 된 원래 데이터를 플로팅하고 예상되는 필터링 된 결과의 예제 (15Hz보다 높은 신호 필터링), 마지막으로 현재 FFT 코드의 결과 (원하는 결과와 예제 FFT 결과는 원래의 데이터)

아래와

FFT Results

내 로우 패스 필터의 실제 코드가 같이 라이브러리의 비 2 제곱 크기 처리 된 원래 코드에서

double *lowpassFilterVector(double *accell, uint32_t sampleCount, double lowPassFreq, double sampleRate) 
{ 
    double stride = 1; 

    int ln = log2f(sampleCount); 
    int n = 1 << ln; 

    // So that we get an FFT of the whole data set, we pad out the array to the next highest power of 2. 
    int fullPadN = n * 2; 
    double *padAccell = malloc(sizeof(double) * fullPadN); 
    memset(padAccell, 0, sizeof(double) * fullPadN); 
    memcpy(padAccell, accell, sizeof(double) * sampleCount); 

    ln = log2f(fullPadN); 
    n = 1 << ln; 

    int nOver2 = n/2; 

    DSPDoubleSplitComplex A; 
    A.realp = (double *)malloc(sizeof(double) * nOver2); 
    A.imagp = (double *)malloc(sizeof(double) * nOver2); 

    // This can be reused, just including it here for simplicity. 
    FFTSetupD setupReal = vDSP_create_fftsetupD(ln, FFT_RADIX2); 

    vDSP_ctozD((DSPDoubleComplex*)padAccell,2,&A,1,nOver2); 

    // Use the FFT to get frequency counts 
    vDSP_fft_zripD(setupReal, &A, stride, ln, FFT_FORWARD); 


    const double factor = 0.5f; 
    vDSP_vsmulD(A.realp, 1, &factor, A.realp, 1, nOver2); 
    vDSP_vsmulD(A.imagp, 1, &factor, A.imagp, 1, nOver2); 
    A.realp[nOver2] = A.imagp[0]; 
    A.imagp[0] = 0.0f; 
    A.imagp[nOver2] = 0.0f; 

    // Set frequencies above target to 0. 

    // This tells us which bin the frequencies over the minimum desired correspond to 
    NSInteger binLocation = (lowPassFreq * n)/sampleRate; 

    // We add 2 because bin 0 holds special FFT meta data, so bins really start at "1" - and we want to filter out anything OVER the target frequency 
    for (NSInteger i = binLocation+2; i < nOver2; i++) 
    { 
     A.realp[i] = 0; 
    } 

    // Clear out all imaginary parts 
    bzero(A.imagp, (nOver2) * sizeof(double)); 
    //A.imagp[0] = A.realp[nOver2]; 


    // Now shift back all of the values 
    vDSP_fft_zripD(setupReal, &A, stride, ln, FFT_INVERSE); 

    double *filteredAccell = (double *)malloc(sizeof(double) * fullPadN); 

    // Converts complex vector back into 2D array 
    vDSP_ztocD(&A, stride, (DSPDoubleComplex*)filteredAccell, 2, nOver2); 

    // Have to scale results to account for Apple's FFT library algorithm, see: 
    // http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH202-15952 
    double scale = (float)1.0f/fullPadN;//(2.0f * (float)n); 
    vDSP_vsmulD(filteredAccell, 1, &scale, filteredAccell, 1, fullPadN); 

    // Tracks results of conversion 
    printf("\nInput & output:\n"); 
    for (int k = 0; k < sampleCount; k++) 
    { 
     printf("%3d\t%6.2f\t%6.2f\t%6.2f\n", k, accell[k], padAccell[k], filteredAccell[k]); 
    } 


    // Acceleration data will be replaced in-place. 
    return filteredAccell; 
} 

입력 데이터; 내 Accelerate 코드에서 가장 가까운 2의 제곱으로 입력을 채 웁니다. 아래 샘플 테스트의 경우 원본 샘플 데이터는 1000 샘플이므로 1024로 채워집니다. 결과에 영향을 미치지는 않을지 모르지만 가능한 차이점을 위해 포함합니다. 당신이 솔루션을 실험 할 경우

, 당신은합니다 (FFTTest 폴더에) 여기에 그래프를 생성하는 샘플 프로젝트 다운로드 할 수있는 통찰력을위한

FFT Example Project code

감사합니다, 나는 일을하지했습니다 전에 FFT를 사용했기 때문에 뭔가 중요한 것을 놓친 것처럼 느껴졌습니다.

+0

하나의 큰 문제의 정당한 권력은보다 더 FFT 길이를 지원하고있는 주파수에 벽돌 벽 필터를 적용하려고 이와 같은 도메인은 시간 영역에서 거대한 인공물을 생성합니다. 이를 피하기 위해 윈도우 화 방법을 사용해야합니다. –

+0

해결책을 찾았습니까? – NTNT

답변

2

실제 (복잡하지 않은) 결과를 원한다면 IFFT 이전의 데이터는 공액 대칭이어야합니다. 결과가 대칭이면, IFFT 전에는 허수 성분을 0으로하지 마십시오. IFFT가 통과하기 전에 빈을 제로로 만드는 것만으로 통과 대역에서 엄청난 양의 리플을 가진 필터를 생성합니다.

가속화 프레임 워크는 당신의 방법 (보다는 어떤 구현 문제 당신이 가진 수 있습니다) 2.