ikostoski / esp32-i2s-slm

Sound Level Meter with ESP32 and I2S MEMS microphone
GNU General Public License v3.0
244 stars 56 forks source link

Varying microphone self noise (INMP441) after restarts #19

Open stas-sl opened 1 year ago

stas-sl commented 1 year ago

Hi, thanks for the great project!

This is probably not your issue, but I just would like to share my experience with this mic for measuring environment noise.

While doing some experiments I noticed a few issues:

  1. Even in quite room, the lowest sound level I could get was only 36 dBA, although according to specs it should be 33 dBA
  2. But really confusing was that self noise could change +-5 dBFS after each restart. Though if applying A-weighting it is less noticeable, but anyway.

My setup is quite simple:

I tried quite a lot of things trying to investigate and/or fix it:

  1. Powering ESP32 from usb or battery
  2. Turning WiFi on/off or lowering its power
  3. Trying IDF 4.4.3 or IDF 5.0/5.1, micropython
  4. Trying different ESP32 boards (including S3)
  5. Trying different INMP441 instances (I have only 2). They actually vary a bit and with one mic I could get lower dBA overall than with other. However they both have the same issue of changing self-noise frequencies/level after restarts.
  6. Trying different wires/pins.
  7. Trying different sample rates/bits per sample. Actually some combinations work better than others.

Unfortunately I don't have other mics to compare. ICS 43434 should work better, but it is quite hard to get it here.

Also I found a few ways to reproduce the issue:

  1. By completely powering on/off
  2. By pressing Reset button
  3. By removing mic from the breadboard and reinserting it again
  4. By calling i2s_driver_uninstall and then i2s_driver_install again
  5. By calling i2s_stop/i2s_start

To investigate it further I made a sketch that does i2s_driver_install/i2s_driver_uninstall every minute and randomly changes sample rate/bits per sample every 5 minutes, and run it for a few hours.

Although it was quite quiet environment (night time), you can see from the chart below, that changing sample rate/bits per channel affects self-noise quite a bit, which might be understandable, but what's more frustrating is that if sample rate and bits per sample doesn't change, noise levels could change after just driver re-installation.

image

Running it for 10 hours and faceting the chart by sample rate/bits per channel and removing gaps inside one chart we can get this:

image

From it we can see, that some sample rates/bits per sample doing better than others:

  1. 10000 samples expectable performs quite bad
  2. 24/32 bits with 44100/48000 sample rate also has quite bad variability.
  3. 16 bit with 44100/48000 seems to be quite stable.
  4. 32 bit with 22050 rate also seems to be OK (surprisingly)

Here is how different noise waves looks like. Those are just two samples with same rate/bits (32 bit@48K), but one is before restart, another - after:

image

Here are a few self-noise spectrums (1024 point FFT):

image

Looks like it is quite similar at high frequencies, but it could vary quite a lot at lower/mid.

TBH, I'm not sure what is the best way to deal with this issue (except buying a better mic). Actually, I don't know for sure if this is a hardware or software issue. And if it is fixable or not. Probably would go for now with 16 bit@48KHz for better stability, albeit loosing some precision. Would be thankful for any advice/explanation why this happens, as I'm quite new to electronics/audio domain.

Update:

However seems like there is another weird issue when using bit depth < 32, see https://github.com/atomic14/esp32-tft-audio-monitor/issues/2

stas-sl commented 1 year ago

As ESP32 has 2 I2S ports, and I have 2 INMP441 mics, I decided to connect them both at the same time. The mics were located as close to each other as possible, so the signal should be equal. Also I calculated both A-weighted and non-weighted levels.

image

Region A: Here you can see the issue, that I described above. One of mics after restart produces some very low frequency noise which results in ~ +7 dBFS (Z). However as can be seen from 2 plots below, after A-weighting those frequencies go away and almost have no effect on resulting noise levels. So, probably, I overestimated the impact of this issue.

Region B: Here I played a 3kHz tone. You can see that there is visible difference in measurements between 2 mics about 3 dB (either after A-weighting or not). And it seems to be consistent after restarts.

Region C: Here I played a 1kHz tone. Surprisingly both mics produced very similar levels in this case unlike when I played 3kHz tone before, so we can conclude that this offset between mics is not a constant and depends on signal frequencies.

Region D: Here is just silence. As I said I could not reach 33 dBA minimal level, but it is quite close. For one mic it is about 34.5 dBA, for another one it is about 1-1.5 dBA higher.

Overall those errors are probably quite acceptable, and one shouldn't expect more from 1.5$ device.

Moskus commented 1 year ago

I'm also experiencing some weird varying microphone self noise problems with my latest setup, using SPH0645LM4H microphones on ESP32 devkit V1 boards. LpA levels seems to vary from 33 dB to 43 dB in a quiet environment (and located at the same place).

Using LoRa-boards (TTGO v2.1 1.6.1) and the same microphones I got much lower and much more stable values, around 30 dBA, which is probably as low as the mics can go (29 dB theoretically).

Apparently, I'm not smart enough to change the sample bits correctly as setting SAMPLE_BITS to anything else than 32 bits gives no data (or at least no dBA values). Do you have an example code I could look at?

stas-sl commented 1 year ago

@Moskus, I haven't worked with SPH0645LM4H mic, but I hope you've seen Ivan's and Mike's notes about it. It seems to require some additional tricks to work and has only 18 bits resolution.

I'm afraid my code is more messy, than Ivan's as I have experimented quite a lot. Basically you should be able to adjust Ivan's code to your needs, but you might need to change some other constants besides SAMPLE_BITS. I think there are 3 interconnected settings: SAMPLE_BITS, MIC_BITS and SAMPLE_T. You should understand difference between them:

  1. SAMPLE_BITS is I2S setting, could be 16/24/32 bits.
  2. MIC_BITS is from your mic specification. I suppose it has 18 bits resolution. So if SAMPLE_BITS set to 24/32 MIC_BITS should be set to 18. Though if you set SAMPLE_BITS to less than 18 (e.g. 16), then you should lower MIC_BITS to 16 as well for correct scaling to a float number between -1 and 1.
  3. SAMPLE_T could be int32_t or int16_t. Obviously for SAMPLE_BITS=16 it should be int16_t, for SAMPLE_BITS=32 it should be int32_t. What's less obvious is that for SAMPLE_BITS=24 it should be also int32_t, as there are no 24bit data types.

This is my understanding how it should be, though I can't guarantee that it will work right away. It might require a bit (a lot) of experimenting & debugging, especially with SPH0645LM4H mic.

Also keep in mind that there might be another weird issue that I mentioned at the bottom of my initial post if you are going to use less than 32 bits per sample. Because of it I ended up using 32 bits.

Moskus commented 1 year ago

Thanks for getting back to me, @stas-sl. You're right! The sample bits for the mic is only18 dB, that explains my need for a custom calibration issue, but removing this and setting the MIC_BITS to 18 sets me back to square one. Levels are accurate from LpA = 40 and up to at least over 100 dB (impressed by that), but below 38-40 dB the level is set more by chance.

The weird part is that it seems to be connected to the actual board used. I've deployed the same code to 9 boards, and have been logging them for a couple of days, here's before any activity occurred this morning. Screenshot 2023-08-17 080831 The microphones aren't located at the same place, but I can assure you the background noise level does not vary 15 dB!! The accurate background noise level is around 28-30 dB according to my (even recently calibrated) Norsonic 140.

I first blamed the microphones, but swapping/replacing microphones gives the same result. That leaves only the boards (or the power supplies). I have some INMP441s too, I'll test them too.

(I still get no values if I set SAMPLE_BITS to anything lower than 32 bit, and I don't know enought digital signal processing to understand why...)

Lat9898 commented 1 year ago

Did you guys have also expressed that it is only working with the wrong channel. like fx i set L/R to GND so it is only working with right channel which is the opposite of what I2S teori is telling us. But when i test only mic everything is working according to the teori, what could be the possible issue and Any idea how can i solve it.