2011-03-12 5 views
5

현재 아이폰의 마이크에서 미리 정의 된 주파수 (16780Hz)로 크기를 계산하는 응용 프로그램을 만들고 있습니다.코어 오디오, Goertzel 알고리즘이 작동하지 않습니다.

버퍼에 소리 데이터가 있고이 작업을 위해 고안된 알고리즘 인 Goertzel을 사용하여 처리하려고합니다. Goertzel info. 문제가 시작되는 곳입니다.

소리가 정의 된 것 (16780Hz)보다 훨씬 낮은 (5000Hz) 주파수로 녹음 될 때 알고리즘은 매우 긍정적 인 결과를 나타냅니다. 실제로 올바른 주파수의 사운드가 녹음 될 때 생성되는 결과보다 훨씬 긍정적 인 결과를 얻습니다. 그것에서

-(void)startListeningWithFrequency:(float)frequency; 
{ 
OSStatus status; 
//AudioComponentInstance audioUnit; 
AudioComponentDescription desc; 
desc.componentType = kAudioUnitType_Output; 
desc.componentSubType = kAudioUnitSubType_RemoteIO; 
desc.componentFlags = 0; 
desc.componentFlagsMask = 0; 
desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc); 
status = AudioComponentInstanceNew(inputComponent, &audioUnit); 
checkStatus(status); 

UInt32 flag = 1; 
status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,kInputBus, &flag, sizeof(flag)); 
checkStatus(status); 

AudioStreamBasicDescription audioFormat; 
audioFormat.mSampleRate   = 44100.00;//44100.00; 
audioFormat.mFormatID   = kAudioFormatLinearPCM; 
audioFormat.mFormatFlags  = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; 
audioFormat.mFramesPerPacket = 1; 
audioFormat.mChannelsPerFrame = 1; 
audioFormat.mBitsPerChannel  = 16; 
// float 
audioFormat.mBytesPerPacket  = 2; 
audioFormat.mBytesPerFrame  = 2; 

status = AudioUnitSetProperty(audioUnit, 
           kAudioUnitProperty_StreamFormat, 
           kAudioUnitScope_Output, 
           kInputBus, 
           &audioFormat, 
           sizeof(audioFormat)); 
checkStatus(status); 
//status = AudioUnitSetProperty(audioUnit, 
//       kAudioUnitProperty_StreamFormat, 
//       kAudioUnitScope_Input, 
//       kOutputBus, 
//       &audioFormat, 
//       sizeof(audioFormat)); 
checkStatus(status); 
AURenderCallbackStruct callbackStruct; 
callbackStruct.inputProc = recordingCallback; 
callbackStruct.inputProcRefCon = self; 
status = AudioUnitSetProperty(audioUnit, 
           kAudioOutputUnitProperty_SetInputCallback, 
           kAudioUnitScope_Global, 
           kInputBus, &callbackStruct, sizeof(callbackStruct)); 
checkStatus(status); 
/* UInt32 shouldAllocateBuffer = 1; 
AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ShouldAllocateBuffer, kAudioUnitScope_Global, 1, &shouldAllocateBuffer, sizeof(shouldAllocateBuffer)); 
*/ 
status = AudioOutputUnitStart(audioUnit); 

} 
static OSStatus recordingCallback(void *inRefCon, 
           AudioUnitRenderActionFlags *ioActionFlags, 
           const AudioTimeStamp *inTimeStamp, 
           UInt32 inBusNumber, 
           UInt32 inNumberFrames, 
           AudioBufferList *ioData) { 
AudioBuffer buffer; 

buffer.mNumberChannels = 1; 
buffer.mDataByteSize = inNumberFrames * 2; 
//NSLog(@"%d",inNumberFrames); 
buffer.mData = malloc(inNumberFrames * 2); 

// Put buffer in a AudioBufferList 
AudioBufferList bufferList; 
bufferList.mNumberBuffers = 1; 
bufferList.mBuffers[0] = buffer; 



OSStatus status; 
status = AudioUnitRender(audioUnit, 
         ioActionFlags, 
         inTimeStamp, 
         inBusNumber, 
         inNumberFrames, 
         &bufferList); 
checkStatus(status); 
//double g = calculateGoertzel((const char *)(&bufferList)->mBuffers[0].mData,16789.0,96000.0); 
UInt16 *q = (UInt16 *)(&bufferList)->mBuffers[0].mData; 
int N = sizeof(q)/sizeof(UInt16); 
double Qr,Qi; 
double theta = 2.0*M_PI*16780/44100; 
double g = goertzel(q,44100,16780,N); 

NSLog(@"goertzel:%f", g); 
} 

이 16780Hz보다 훨씬 낮은 주파수의 수백의 숫자를 반환 관련된 모든 경우에 나는 오디오를 검색하는 방법을

다음
double goertzel(unsigned short *sample, int sampleRate, double Freq, int len) 
{ 

double realW = 2.0 * cos(2.0 * M_PI * Freq/sampleRate); 
double imagW = 2.0 * sin(2.0 * M_PI * Freq/sampleRate); 
double d1 = 0; 
double d2 = 0; 
int z; 
double y; 
for (int i = 0; i < len; i++) { 
    y=(double)(signed short)sample[i] +realW * d1 - d2; 
    d2 = d1; 
    d1 = y; 
} 
double rR = 0.5 * realW *d1-d2; 
double rI = 0.5 * imagW *d1-d2; 

return (sqrt(pow(rR, 2)+pow(rI,2)))/len; 
} /* end function goertzel */ 

은 다음과 같습니다

는 goertzel의 내 구현 16780Hz의 주파수의 경우 훨씬 더 작은 수를 반환합니다.

저는 매우 좌절하고 도움을 주시면 감사하겠습니다.

답변

3

그냥 추측 :

나이 퀴 스트 - 섀넌 샘플링 정리에 따르면, 샘플링 속도는 두 배 이상 측정하고자하는 주파수이어야한다. 그리고 네가 그렇지만 단지 간신히. 44.1kHz의 샘플링 속도는 22kHz 신호를 측정하기위한 바깥 쪽 가장자리입니다. 16kHz의 신호는 앨리어싱이 웨이브 분석에 문제를 일으킬 수있는 한계에 충분히 근접합니다. 여기 내 요점을 설명하기위한 그림이 있습니다. enter image description here

그래서 나는 더 높은 샘플 속도가 필요하다고 생각합니다. 알고리즘을 통해 순수한 16kHz 사인파를 실행 해보십시오. 왜 더 좋은지 알아보십시오. 앨리어싱은 테스트 데이터에 단일 주파수 만있는 경우 문제가되지 않습니다. 사인파에서 더 높은 응답을 얻으면 아마 높은 샘플링 속도가 필요할 것입니다.

+0

불행히도, 나는 사인파로만 테스트 해왔다. (더 이상의 제안? 샘플링 속도를 두 배로 늘려 보았습니다. – 123hal321

+0

샘플링 할 수 없다면 샘플 속도를 두 배로 늘리면 iPhone에서 작동하지 않을 수도 있습니다. 샘플링 속도를 다시 읽어야 샘플을 받아 들일 수 있습니다. 또한 세션 속성에서 샘플 속도를 먼저 설정하여 자동으로 그것이 무엇을해야하는지 생각하지 않도록 할 수 있습니다. 기본 샘플링 속도 : – Vagrant

+0

Float64 preferredSampleRate = audioFormat-> mSampleRate, XThrowIfError (AudioSessionSetProperty (kAudioSessionProperty_PreferredHardwareSampleRate이 는 sizeof (preferredSampleRate), preferredSampleRate)); – Vagrant

2

Goertzel 필터에 사용 된 공진기가 1 극 공진기에 대한 1도 근사 인 것처럼 보입니다. 이것은 단계 당 높은 위상 각에서 정확도와 안정성이 크게 떨어집니다. 삼각 함수에 대한 더 나은 근사를 사용하는 1 빈 DFT는 이러한 고주파수에서 더 잘 작동합니다.

iPhone 마이크의 주파수 응답이 높은 주파수에서 벗어날 가능성이 있습니다.

ADDED :

는 1 단 DFT를 들어

, 당신의 내부 루프에서 이것을 시도 :

d1 += (double)sample[i] * cos(2.0*M_PI*i*Freq/sampleRate); 
d2 += (double)sample[i] * sin(2.0*M_PI*i*Freq/sampleRate); 

를 다음 반환 :

dR = d1; 
dI = d2; 
magnitude = sqrt(dR*dR + dI*dI)/(double)len; 

참고하는 고정 주파수 및 샘플 속도에 대한 trig 함수는 오디오 콜백 외부에서 미리 계산되어 배열이나 찾아보기 테이블에 저장 될 수 있습니다. 이와 같은 최적화 작업을 수행하지 않으면 오디오 콜백 내에서 여러 배정도 초월 함수를 호출하는 속도가 너무 느려지거나 배터리 전력이 많이 소모되지만 일반적인 고속 PC에서는 OK를 시뮬레이트 할 수 있습니다.

DFT는 빈 주파수 Freq의 정확한 정수의 길이 인 길이에 대해 정의되지만, 다른 길이는 소위 스펙트럼 "누설"및/또는 스캘럽 오류의 다양한 양을 포함하는 근사치에 대해 작동합니다. 필터 주파수 응답의 폭은 대략 DFT 길이에 반비례합니다. 또한 주파수가 Fs/2에 가까울수록 복잡한 이미지 앨리어싱을 피하기 위해 DFT가 길어질 필요가 있습니다. 길이 N * Fs/(Fs/2 - Freq)의 길이가 더 길어질 수 있습니다. 적절한 길이를 얻기 위해 샘플을 저장하거나 큐에 넣어야합니다 (오디오 콜백에서 지정한 버퍼 길이 만 사용하면 안 됨).

+0

나에게 링크 나 포인터를 보내 주시겠습니까?/구현 방법. ty – 123hal321

+1

데이터 배열에 원하는 필터 빈도로 사인파와 코사인 파를 곱 해보고 두 벡터를 합한 다음 2D 또는 복소수를 계산하십시오. – hotpaw2

+0

Im 매우 유감스럽게 생각합니다.하지만 제게 보여 주길 바랍니다. 시도는 모두 비참했습니다. 필사적으로 노력해야합니다. 고맙습니다 – 123hal321

관련 문제