【问题标题】:Noise-cancellation with undirected microphones and different amplifiers使用无指向性麦克风和不同的放大器消除噪音
【发布时间】:2013-11-09 08:34:34
【问题描述】:

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

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

盒子里面有两个不同的放大器(但相同的驻极体麦克风),有两个不同的放大电路(通常嘴巴的声音更大,并且集成了一些归一化电路。长话短说,我可以把它录制成原始的44100Hz、16Bit、Stereo的音频文件,左声道为上,右声道为下麦克风放大器输出。

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

我试过(以 Datei 为原始文件名)。这包括一个高通或低通滤波器和一个将最终结果放回原始单声道文件 (%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);
}

【问题讨论】:

  • while(wo !=EOF) { wo = getc(f); 是一个小问题。 wo 需要在 getc() 之后立即进行 EOF 测试。事先进行测试,让我们 wo 等于 EOF 进行 1 个循环。
  • @chux 我不明白。它应该是什么样子?
  • while ((c = getc(f)) != EOF) {
  • 2 个想法:1) 使用 double 而不是 float。 A/D 转换的声音的保真度约为 20-22 位(浮点数为 23),但有时会注意到各种数学噪声。 2)不是减法,而是加法。有时麦克风的线交叉,您需要在软件中撤消它。
  • 另外 2 个想法:1)使用 r-g*l-r(或 r+g*l)而不是 r - fileter_l。 (做过滤减法)使用struct { int16_t l,r; } sample; while (fread(sample, sizeof sample, f) > 0) {来简化你正在做的所有字节拼接。

标签: c audio cancellation noise-reduction


【解决方案1】:

您的代码没有考虑路径长度的差异。

声源和两个麦克风之间的路径差d2——d1对应a (d2 – d1) / v 的时间延迟,其中 v 是声速 (330 m/s)。

假设 d2 – d1 等于 10 厘米。在这种情况下,任何频率为 3300 Hz 倍数的声波(即其周期为 (0.10/330) 秒的倍数)在两个麦克风处将处于完全相同的相位。这就是您希望事物在所有频率上的样子。

但是,在该频率(1650 Hz、4950 Hz、8250 Hz 等)的奇数倍的声波到达第二个麦克风时,其相位将发生 180° 的变化。结果,您的减法运算实际上会产生相反的效果——您将提高这些频率,而不是让它们变得更安静。

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

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

【讨论】:

【解决方案2】:

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

1) 看起来 OP 正在过滤 l 信号 jetzt = vorher + (alpha*(l - vorher)),然后用 dif = r - g*jetzt 减去 r。首先减去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) 由于接线和麦克风拾音,两个信号的相位可能相差 180 度。是这样试试diff = gain_l*l + gain_r*r

【讨论】:

  • 好的。我包含它并创建了pastebin.com/Ly2R6tJA 不幸的是,无论我使用 gain_ll + gain_rr 还是 gain_rr - gain_ll 还是 gain_ll - gain_r i>r,尖峰总是加起来。 while (fread(&sample, ... 部分看起来像 squeamish ossifrage 建议的那样延迟一个频道?
  • 您可以在drive.google.com/file/d/0Bx2f1564appiY1owNHdoNHVpekU/…找到一个示例原始文件以供参考
  • 我想礼貌地提醒您您的回复。提前谢谢你。
  • 我不明白。什么是 ping?
  • @Gewinn 注意:根据@squeamish 的讨论,减去第二个信号仅在特定频率下才有意义。这支持你的jetzt = vorher + (alpha*(l - vorher)); dif = r - g*jetzt;
猜你喜欢
  • 2020-02-16
  • 2011-04-27
  • 2015-11-26
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-18
相关资源
最近更新 更多