具有无向麦克风和不同放大器的噪声消除功能

时间:2013-10-29 23:15:04

标签: c audio cancellation noise-reduction

我有以下设置https://sketchfab.com/show/7e2912f5f8794a7b96ef3ac5930e090a(这是一个3D查看器,使用鼠标查看所有角度)

盒子有两个非定向驻极体麦克风(黑点)。在地面上有一些元素像水或类似物一样落下(由球体表示)并产生噪音。最重要的是,有人在盒子里说话。距离大致准确,所以嘴巴非常接近。

盒子里面有两个不同的放大器(但是相同的驻极体麦克风),有两个不同的放大电路(一个声音很大,一般声音很大,并且有一些标准化电路集成。长话短说,我可以把它录制成原始的音频文件有44100 Hz,16Bit和Stereo,而左声道是上部,右声道是下部麦克风放大器输出。

目标是 - 即使驻极体麦克风没有定向,即使有不同的放大器 - 从上部麦克风(面向扬声器)减去下部麦克风(面向地面)以消除噪音。

我试过(将Datei作为raw-filename)。这包括高通或低通滤波器以及将最终结果放回原始单声道文件的例程(%s.neu.raw)

问题是 - 好 - 不可确定的失真。我能听到我的声音,但根本不可忍受。如果您需要样品,我可以上传一个。

编辑:新代码。

static void *substractf( char *Datei)
{
  char ergebnis[80];                                                  
  sprintf(ergebnis,"%s.neu.raw",Datei);
  FILE* ausgabe = fopen(ergebnis, "wb");
  FILE* f = fopen(Datei, "rb");                    
  if (f == NULL)
    return;
  double g = 0.1;
  double RC = 1.0/(1215*2*3.14);
  double dt = 1.0/44100;
  double alpha = dt/(RC+dt);
  double noise_gain = 18.0;
  double voice_gain = 1.0;
  struct {
    uint8_t noise_lsb;
    int8_t  noise_msb;
    uint8_t voice_lsb;
    int8_t  voice_msb;
  } sample;  

  while (fread(&sample, sizeof sample, 1, f) == 1) 
  {
    int16_t noise_source = sample.noise_msb * 256 + sample.noise_lsb;
    int16_t voice_source = sample.voice_msb * 256 + sample.voice_lsb;
    double signal, difference_voice_noise;            
    difference_voice_noise = voice_gain*voice_source - noise_gain*noise_source;
    signal = (1.0 - alpha)*signal + alpha*difference_voice_noise;  
    putc((char) ( (signed)signal       & 0xff),ausgabe);
    putc((char) (((signed)signal >> 8) & 0xff),ausgabe);  
  }   
  fclose(f);                             
  fclose(ausgabe);  
  char output[300];                                 
  sprintf(output,"rm -frv \"%s\"",Datei);
  system(output);
}

2 个答案:

答案 0 :(得分:1)

您的代码不会考虑路径长度的差异。

声源与两个麦克风之间的路径差 d 2 - d 1 对应于时间延迟为( d 2 - d 1 )/ v ,其中< em> v 是声速(330 m / s)。

Illustration of path difference with two microphones

假设 d 2 - d 1 等于10 cm。在这种情况下,频率为3300Hz的倍数的任何声波(即,其周期是(0.10 / 330)秒的倍数)将在两个麦克风处处于完全相同的相位。这就是你想要所有频率的东西。

然而,在到达第二个麦克风时,频率的一半(1650赫兹,4950赫兹,8250赫兹等)的奇数倍的声波将在相位上改变180°。因此,您的减法操作实际上会产生相反的效果 - 您将提升这些频率而不是让它们更安静。

最终结果与您在图形均衡器上以相反方向推动所有备用滑块时的结果类似。这可能就是你现在所经历的。

尝试估算此路径差异的长度,并将一个通道中的样本延迟相应的量。在44100Hz的采样率下,1厘米对应于约0.75个样本。如果声源四处移动,那么事情会变得有点复杂。您必须找到一种从音频信号本身动态估计路径差异的方法。

答案 1 :(得分:0)

想法太大而无法发表评论。

1)看起来OP正在过滤l信号jetzt = vorher + (alpha*(l - vorher)),然后用r减去dif = r - g*jetzt。首先减去lr并将该差异应用于过滤器似乎更有意义。

float signal = 0.0; (outside loop)
...
float dif;
// Differential (with gain adjustments)
dif = gain_l*l - gain_r*r;
// Low pass filter (I may have this backwards)
signal = (1.0 - alpha)*signal + alpha*dif;
// I am not certain if diff or signal should be written
// but testing  limit would be useful.
if ((dif > 32767) || (dif < -32767)) report();
int16_t sig = dif;
// I see no reason for the following test
// if (dif != 0)
putc((char) ( (unsigned)dif       & 0xff),ausgabe);
putc((char) (((unsigned)dif >> 8) & 0xff),ausgabe);

2)字节拼接可能已关闭。建议的简化

// This assumes incoming data is little endian, 
// Maybe data is in big endian and _that_ is OP problem?
struct {
  uint8_t l_lsb;
  int8_t  l_msb;
  uint8_t r_lsb;
  int8_t  r_msb;
} sample;
...
while (fread(&sample, sizeof sample, 1, f) == 1) {
   int16_t left  = sample.l_msb * 256 + sample.l_lsb;
   int16_t right = sample.r_msb * 256 + sample.r_lsb;

3)floatdouble的使用。通常,限制越float会产生计算噪音,但OP投诉的严重程度表明此问题不太可能 问题。还是值得考虑的。

4)16位样本的字节序可能是向后的。此外,根据A / D编码,采样可以是16位无符号而不是16位有符号。

5)由于接线和麦克风拾取,2个信号的相位可以相互180°。是这样尝试diff = gain_l*l + gain_r*r