Question

I have the following setup https://sketchfab.com/show/7e2912f5f8794a7b96ef3ac5930e090a (It's a 3d viewer, use your mouse to view all angles)

The box has two nondirectional electret microphones(black dots). On the ground there are some elements falling down like water or similar(symbolized by the sphere) and creating noises. On top, someone is speaking in the box. Distances are roughly accurate, so the mouth is pretty close.

Inside the box there are two different amplifiers(but the same electret microphones) with two different amplification circuits(the mouth-one is louder in general and has some normalization circuitry integrated. Long story short, I can record this into a raw audio file with 44100 Hz, 16Bit and Stereo, while the left channel is the upper, the right channel is the lower microphone amplifier output.

Goal is to - even though the electret microphones are not directed and even though there are different amplifiers - subtract the lower microphone(facing the ground) from the upper microphone(facing the speaker) to have noise cancellation.

I tried(With Datei being the raw-filename). This includes a high or low pass filter and a routine to put the final result back into a raw mono file (%s.neu.raw)

The problem is - well - undefinable distortion. I can hear my voice but it's not bearable at all. If you need a sample I can upload one.

EDIT: New code.

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);
}
Was it helpful?

Solution 2

Ideas too big for a comment.

1) Looks like OP is filtering the l signal jetzt = vorher + (alpha*(l - vorher)) and then subtracting the r with dif = r - g*jetzt. It seems to make more sense to subtract l and r first and apply that difference to the filter.

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) The byte splicing may be off. Suggested simplification

// 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) Use of float vs. double. Usually the more limiting float creates computational noise, but the magnitude of OP's complaint suggest that this issue is unlikely the problem. Still worth considering.

4) Endian of the 16-bit samples may be backwards. Further, depending on A/D encoding the samples may be 16-bit unsigned rather than 16-bit signed.

5) The phase of the 2 signals could be 180 out from each other due to wiring and mic pick-up. Is so try diff = gain_l*l + gain_r*r.

OTHER TIPS

Your code doesn't take differences of path length into consideration.

The path difference d2 – d1 between the sound source and the two mics corresponds to a time delay of (d2 – d1) / v, where v is the speed of sound (330 m/s).

Illustration of path difference with two microphones

Suppose d2 – d1 is equal to 10 cm. In this case, any sound wave whose frequency is a multiple of 3300 Hz (i.e., whose period is a multiple of (0.10/330) seconds) will be at exactly the same phase at both microphones. This is how you want things to be at all frequencies.

However, a sound wave at an odd multiple of half that frequency (1650 Hz, 4950 Hz, 8250 Hz, etc.) will have changed in phase by 180° by the time it reaches the second mic. As a result, your subtraction operation will actually have the opposite effect — you'll be boosting these frequencies instead of making them quieter.

The end result will be similar to what you get if you push all the alternate sliders on a graphic equaliser in opposite directions. This is probably what you're experiencing now.

Try estimating the length of this path difference and delaying the samples in one channel by a corresponding amount. At a sampling rate of 44100 Hz, one centimetre corresponds to about 0.75 samples. If the sound source is moving around, then things get a bit complicated. You'll have to find a way of estimating the path difference dynamically from the audio signals themselves.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top