我正在尝试识别嵌入式系统上的一系列音频帧 - 音频帧是可变时间的频率或两个频率的插值。我知道我试图识别的声音(即线性插值的开始和结束频率以及每个音频帧的持续时间),但它们是由另一个嵌入式系统产生的,因此麦克风和扬声器价格便宜且有些不准确。输出是方波。有什么建议如何去做吗?
我现在要做的是使用 FFT 来获取所有频率的幅度,检测峰值,查看检测持续时间/2 ms 前并检查它是否与音频帧有些匹配,最后只是检查是否有任何声音我我正在寻找匹配的序列。
到目前为止,我使用 FFT 来处理麦克风输入 - 在应用 Hann 窗口之后 - 然后根据远离平均值的标准偏差为每个频率区间分配一个峰值系数。这并没有很好地工作,因为它认为房间里安静时会有高峰。关于如何更准确地检测峰值的任何想法?另外我认为由于方波/插值有很多谐波?如果峰值不是真的以两倍频率排列,我可以做谐波乘积频谱吗?
在这里,我用 2226 和 1624 Hz 的插值绘制了噪声(几乎是无声的房间)。 https://i.stack.imgur.com/R5Gs2.png
我以 91 微秒 -> 10989 Hz 采样。我应该更频繁地取样吗?
我在这里添加了在我的笔记本电脑和嵌入式系统上录制时插值声音的示例。 https://easyupload.io/m/5l72b0
#define MIC_SAMPLE_RATE 10989 // Hz
#define AUDIO_SAMPLES_NUMBER 1024
MicroBitAudioProcessor::MicroBitAudioProcessor(DataSource& source) : audiostream(source)
{
arm_rfft_fast_init_f32(&fft_instance, AUDIO_SAMPLES_NUMBER);
buf = (float *)malloc(sizeof(float) * (AUDIO_SAMPLES_NUMBER * 2));
output = (float *)malloc(sizeof(float) * AUDIO_SAMPLES_NUMBER);
mag = (float *)malloc(sizeof(float) * AUDIO_SAMPLES_NUMBER / 2);
}
float henn(int i){
return 0.5 * (1 - arm_cos_f32(2 * 3.14159265 * i / AUDIO_SAMPLES_NUMBER));
}
int MicroBitAudioProcessor::pullRequest()
{
int s;
int result;
auto mic_samples = audiostream.pull();
if (!recording)
return DEVICE_OK;
int8_t *data = (int8_t *) &mic_samples[0];
int samples = mic_samples.length() / 2;
for (int i=0; i < samples; i++)
{
s = (int) *data;
result = s;
data++;
buf[(position++)] = (float)result;
if (position % AUDIO_SAMPLES_NUMBER == 0)
{
position = 0;
float maxValue = 0;
uint32_t index = 0;
// Apply a Henn window
for(int i=0; i< AUDIO_SAMPLES_NUMBER; i++)
buf[i] *= henn(i);
arm_rfft_fast_f32(&fft_instance, buf, output, 0);
arm_cmplx_mag_f32(output, mag, AUDIO_SAMPLES_NUMBER / 2);
}
}
return DEVICE_OK;
}
uint32_t frequencyToIndex(int freq) {
return (freq / ((uint32_t)MIC_SAMPLE_RATE / AUDIO_SAMPLES_NUMBER));
}
float MicroBitAudioProcessor::getFrequencyIntensity(int freq){
uint32_t index = frequencyToIndex(freq);
if (index <= 0 || index >= (AUDIO_SAMPLES_NUMBER / 2) - 1) return 0;
return mag[index];
}