【发布时间】:2014-05-08 04:38:23
【问题描述】:
我一直在尝试使用 Apple Accelerate 框架中的 FFT 获得准确的频率,但我无法弄清楚为什么我的值偏离了真实频率。
我一直使用这篇文章 http://www.dspdimension.com/admin/pitch-shifting-using-the-ft/ 作为我实施的基础,在努力达到现在的点之后,我完全被难住了。
到目前为止,我已经在 -> Hanning 窗口 -> FFT -> 相位计算 -> 奇怪的最终输出中获得了音频。我认为我的数学在某个地方会有问题,但我现在真的没有想法。
输出比应有的低很多,例如,我输入 440Hz 并打印出 190Hz,或者我输入 880Hz 并打印出 400Hz。在大多数情况下,这些结果是一致的,但并非总是如此,而且任何事物之间似乎也没有任何共同因素......
这是我的代码:
enum
{
sampleRate = 44100,
osamp = 4,
samples = 4096,
range = samples * 7 / 16,
step = samples / osamp
};
NSMutableArray *fftResults;
static COMPLEX_SPLIT A;
static FFTSetup setupReal;
static uint32_t log2n, n, nOver2;
static int32_t stride;
static float expct = 2*M_PI*((double)step/(double)samples);
static float phase1[range];
static float phase2[range];
static float dPhase[range];
- (void)fftSetup
{
// Declaring integers
log2n = 12;
n = 1 << log2n;
stride = 1;
nOver2 = n / 2;
// Allocating memory for complex vectors
A.realp = (float *) malloc(nOver2 * sizeof(float));
A.imagp = (float *) malloc(nOver2 * sizeof(float));
// Allocating memory for FFT
setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);
// Setting phase
memset(phase2, 0, range * sizeof(float));
}
// For each sample in buffer...
for (int bufferCount = 0; bufferCount < audioBufferList.mNumberBuffers; bufferCount++)
{
// Declaring samples from audio buffer list
SInt16 *samples = (SInt16*)audioBufferList.mBuffers[bufferCount].mData;
// Creating Hann window function
for (int i = 0; i < nOver2; i++)
{
double hannMultiplier = 0.5 * (1 - cos((2 * M_PI * i) / (nOver2 - 1)));
// Applying window to each sample
A.realp[i] = hannMultiplier * samples[i];
A.imagp[i] = 0;
}
// Applying FFT
vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD);
// Detecting phase
vDSP_zvphas(&A, stride, phase1, stride, range);
// Calculating phase difference
vDSP_vsub(phase2, stride, phase1, stride, dPhase, stride, range);
// Saving phase
memcpy(phase2, phase1, range * sizeof(float));
// Extracting DSP outputs
for (size_t j = 0; j < nOver2; j++)
{
NSNumber *realNumbers = [NSNumber numberWithFloat:A.realp[j]];
NSNumber *imagNumbers = [NSNumber numberWithFloat:A.imagp[j]];
[real addObject:realNumbers];
[imag addObject:imagNumbers];
}
// Combining real and imaginary parts
[resultsCombined addObject:real];
[resultsCombined addObject:imag];
// Filling FFT output array
[fftResults addObject:resultsCombined];
}
}
int fftCount = [fftResults count];
NSLog(@"FFT Count: %d",fftCount);
// For each FFT...
for (int i = 0; i < fftCount; i++)
{
// Declaring integers for peak detection
float peak = 0;
float binNumber = 0;
// Declaring integers for phase detection
float deltaPhase;
static float trueFrequency[range];
for (size_t j = 1; j < range; j++)
{
// Calculating bin magnitiude
float realVal = [[[[fftResults objectAtIndex:i] objectAtIndex:0] objectAtIndex:j] floatValue];
float imagVal = [[[[fftResults objectAtIndex:i] objectAtIndex:1] objectAtIndex:j] floatValue];
float magnitude = sqrtf(realVal*realVal + imagVal*imagVal);
// Peak detection
if (magnitude > peak)
{
peak = magnitude;
binNumber = (float)j;
}
// Getting phase difference
deltaPhase = dPhase[j];
// Subtract expected difference
deltaPhase -= (float)j*expct;
// Map phase difference into +/- pi interval
int qpd = deltaPhase / M_PI;
if (qpd >= 0)
qpd += qpd&1;
else
qpd -= qpd&1;
deltaPhase -= M_PI * (float)qpd;
// Getting bin deviation from +/i interval
float deltaFrequency = osamp * deltaPhase / (2 * M_PI);
// Calculating true frequency at the j-th partial
trueFrequency[j] = (j * (sampleRate/samples)) + (deltaFrequency * (sampleRate/samples));
}
UInt32 mag;
mag = binNumber;
// Extracting frequency at bin peak
float f = trueFrequency[mag];
NSLog(@"True frequency = %fHz", f);
float b = roundf(binNumber*(sampleRate/nOver2));
NSLog(@" Bin frequency = %fHz", b);
}
【问题讨论】:
-
看看这里,我不认为您实际上是在将 FFT 输出索引转换为实际频率!!! stackoverflow.com/questions/4364823/…
-
我已经看过了,我已经得到了那里正在讨论的 bin 输出(最后 2 行代码),你指的是什么?我追求确切的频率,我认为我的问题在于我的相位计算,该页面似乎没有涉及到那个......除非我误解了你在说什么!
-
你能解释为什么相位会影响精确的频率吗?不应该只影响实力吗?
-
我的理解是,如果频率等于 bin 频率,那么它将没有相位差,但是如果频率与 bin 频率不同。那么它的相位可以用来计算它离 bin 频率有多远:即精确频率 = delta 频率 + bin 频率,其中 delta 频率是通过这个相位计算的。好吧,我认为至少是这样,因为我的程序不起作用!
-
fft 只有有限的频率分辨率等于 bin 宽度。该阶段没有按照您的预期进行。如果您点击 trumpetlicks 发布的链接,您应该没问题。
标签: ios objective-c signal-processing fft accelerate-framework