Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support MEMS microphone #11

Open
jk opened this issue Jul 8, 2019 · 63 comments
Open

Support MEMS microphone #11

jk opened this issue Jul 8, 2019 · 63 comments
Assignees
Labels
notice This issue is resolved, but left open for posterity/visibility

Comments

@jk
Copy link

jk commented Jul 8, 2019

I received my enviro+ last week and over the weekend I managed to install the examples and build my own InfluxDB bridge to show all those measurements via Grafana. Had a lot of tinkering fun, thanks :)

But I'm missing a way to interface the MEMS microphone to read out noise levels. I suppose that support is under way, can someone give an ETA or directions where to read further.

@Bugierek
Copy link

Bugierek commented Jul 8, 2019

I agree to me it would be very useful to have code for mems mic readout.
If someone is doing prioritization of todo list I'd vote for that :) thanks

@Gadgetoid
Copy link
Member

The microphone is set up as a regular audio input via i2s, so any software capable of reading a standard audio device can access it.

The reason Python support is currently missing is because it's something of a challenge sampling a microphone input and performing any meaningful analysis on it on realtime in Python. It's a work in progress, though.

The solution involves a C daemon called FFsockeT the sole purpose of which is to sample the microphone, apply a (libfftw3) FFT and output the transformed data via a socket into a client application- the intent being that Python can consume this datae easily. The source for that is here- https://github.com/pimoroni/FFsockeT

I've been using sndpeek as a mechanism to visualise noise data, albeit I appreciate it has no practical application for those wishing to sample and log data as part of their environmental monitoring solution - https://soundlab.cs.princeton.edu/software/sndpeek/

Internally we also have a rough-and-ready Python application for sampling the microphone:

#
#""Show a text-mode spectrogram using live microphone data."""
import argparse
import math
import numpy as np
import shutil
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import colorsys
import ST7735

#setup display

LCD_CS = 7
LCD_DC = 9 
LCD_BACKLIGHT = 12


disp = ST7735.ST7735(
    port=0,
    cs=ST7735.BG_SPI_CS_FRONT,
    dc=LCD_DC,
    backlight=LCD_BACKLIGHT,
    rotation=90,
    )
WIDTH = disp.width
HEIGHT = disp.height
disp.begin()
img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)



usage_line = ' press <enter> to quit, +<enter> or -<enter> to change scaling '


def int_or_str(text):
    #"""Helper function for argument parsing."""
    try:
        return int(text)
    except ValueError:
        return text

try:
    columns, _ = shutil.get_terminal_size()
except AttributeError:
    columns = 80

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-l', '--list-devices', action='store_true',
                    help='list audio devices and exit')
parser.add_argument('-b', '--block-duration', type=float,
                    metavar='DURATION', default=50,
                    help='block size (default %(default)s milliseconds)')
parser.add_argument('-c', '--columns', type=int, default=columns,
                    help='width of spectrogram')
parser.add_argument('-d', '--device', type=int_or_str,
                    help='input device (numeric ID or substring)')
parser.add_argument('-g', '--gain', type=float, default=10,
                    help='initial gain factor (default %(default)s)')
parser.add_argument('-r', '--range', type=float, nargs=2,
                    metavar=('LOW', 'HIGH'), default=[100, 2000],
                    help='frequency range (default %(default)s Hz)')
args = parser.parse_args()

low, high = args.range
if high <= low:
    parser.error('HIGH must be greater than LOW')

# Create a nice output gradient using ANSI escape sequences.
# Stolen from https://gist.github.com/maurisvh/df919538bcef391bc89f
colors = 30, 34, 35, 91, 93, 97
chars = ' :%#\t#%:'
gradient = []
for bg, fg in zip(colors, colors[1:]):
    for char in chars:
        if char == '\t':
            bg, fg = fg, bg
        else:
            gradient.append('\x1b[{};{}m{}'.format(fg, bg + 10, char))

try:
    import sounddevice as sd

    if args.list_devices:
        print(sd.query_devices())
        parser.exit(0)

    samplerate = 4000 # sd.query_devices(args.device, 'input')['default_samplerate']

    delta_f = (high - low) / (WIDTH - 1)
    fftsize = math.ceil(samplerate / delta_f)
    low_bin = math.floor(low / delta_f)

    def callback(indata, frames, time, status):
        if status:
            text = ' ' + str(status) + ' '
            print('\x1b[34;40m', text.center(args.columns, '#'),
                  '\x1b[0m', sep='')
        if any(indata):
            #print(indata)
            cpy_img = img.copy()
            img.paste(cpy_img, (0,5))
            magnitude = np.abs(np.fft.rfft(indata[:, 0], n=fftsize))
            magnitude *= 500 / fftsize
            #print( magnitude)
            
            for index in range(len(magnitude[low_bin:low_bin + WIDTH])):
            	colour = colorsys.hsv_to_rgb(magnitude[index] , 1 ,1)
            	colour = tuple(int(255 * x) for x in colour)
            	#print(colour)
            	draw.line((index , 0, index + 1, 5), fill = colour)

            disp.display(img)
            
            #print(*line, sep='', end='\x1b[0m\n')
        else:
            print('no input')

    with sd.InputStream(device=args.device, channels=1, callback=callback,
                        blocksize=int(samplerate * args.block_duration / 1000),
                        samplerate=samplerate):
        while True:
            response = input()
            if response in ('', 'q', 'Q'):
                break
            for ch in response:
                if ch == '+':
                    args.gain *= 2
                elif ch == '-':
                    args.gain /= 2
                else:
                    #print('\x1b[31;40m', usage_line.center(args.columns, '#'),
                     #     '\x1b[0m', sep='')
                    break
except KeyboardInterrupt:
    parser.exit('Interrupted by user')
except Exception as e:
    parser.exit(type(e).__name__ + ': ' + str(e))

@Gadgetoid Gadgetoid self-assigned this Jul 8, 2019
@Gadgetoid
Copy link
Member

@Bugierek the someone would be me, and this is on my radar! (in fact I'm more or less the only software wrangler at the moment, for better or worse)

@Bugierek
Copy link

Bugierek commented Jul 8, 2019

Thanks for reply. I appreciate your effort to make it all working, great job!
At some point I managed to make the adafruit mems i2s mic work on Rpi so hopefully it's a similar task that I'll look into although I'm not a programmer ;)
In the beginning it would be enough just to get the signal from mic and scale/calibrate the level into absolute value of total SPL. I think nice FFT analysis could be interesting in the future but having a simple dB SPL or A weighted dBA level readout would be enough.
Thanks for working on it :)

@Gadgetoid
Copy link
Member

Gadgetoid commented Jul 8, 2019

I'm certainly no expert on these matters, but as I understand it A-weighting requires a FFT step in order to produce the per-frequency amplitude bands which are then weighted. The alternative being to use a digital filter to isolate the individual frequency bands one at a time before A-weighting them.

Getting a raw dB SPL without any kind of time to frequency domain conversion is - I believe - a folly since it wouldn't account for either the characterists of human hearing nor the variable frequency response of the microphone itself. Granted it may provide a useful relative measurement of noise level for a particular environment - ie: which times of day are more reletively noisy than others.

I also suspect for most environmental noise analysis that a certain subset of frequencies or events will be particularly of interest- things like obnoxiously driven cars, horns, large trucks passing, etc.

Honestly, this is one of the most difficult challenges I've faced in terms of general understanding of the core concepts. Sound is decidedly more information dense than light levels or temperature.

This is one of those problems where capturing chunks of audio throughout the day and throwing them at machine learning to classify frequency and density of "annoying noise events" would be, I guess, ideal. This looks like a deep rabbit hole, though- https://github.com/tyiannak/pyAudioAnalysis/

Some useful information here, too (for posterity) - https://makersportal.com/blog/2018/9/17/audio-processing-in-python-part-ii-exploring-windowing-sound-pressure-levels-and-a-weighting-using-an-iphone-x

And while I'm bundling information here, the datasheet for the MEMS microphone part - https://media.digikey.com/pdf/Data%20Sheets/Knowles%20Acoustics%20PDFs/SPH0645LM4H-B.pdf

@Bugierek
Copy link

Bugierek commented Jul 8, 2019

Yes you're right that it'd be best to have at least A weighted SPL values and even better some sort of FFT graph.Another way that people look at noise are full octave or third octave bands of frequencies, but it also requires FFT step to calculate bands of frequencies. Actually the Full or 3rd octave bands are the default way that acoustic consultants look at noise data :)

btw that's another project I've found on the subject. A bit outdated but still: https://github.com/SuperShinyEyes/spl-meter-with-RPi

@Esteidinger
Copy link

I received my enviro+ last week and over the weekend I managed to install the examples and build my own InfluxDB bridge to show all those measurements via Grafana. Had a lot of tinkering fun, thanks :)

But I'm missing a way to interface the MEMS microphone to read out noise levels. I suppose that support is under way, can someone give an ETA or directions where to read further.

Hi @jk , can you share your updates to push data to InfluxDB and Grafana? I would love to have that data locally for historical purposes. I already have a TIG stack running.

@jk
Copy link
Author

jk commented Jul 9, 2019

@david-peterson
Copy link

david-peterson commented Aug 23, 2019

A few notes for people following this issue.

I'm new to Raspberry Pi, and what follows is from my poking at this with a new Pi Zero and Enviro+ with a fresh Raspbian Stretch install from the latest 2019-04-08 image.

But I did get sound working!

If you Google search getting the MEMS mic to work, you'll like land on this article at Adafruit. Don't follow that as-is, it's pretty old and leads your through a lot of unnecessary work.

First, do not use rpi-update to get your system up to date. For the driver stuff, a simple apt-get update and apt-get upgrade is good enough. Or you can use the Pimoroni update script that does that plus updates your python libraries.

Second, you do not need to run rpi-source to download and recompile the kernel. Just install the kernel headers with sudo apt-get install raspberrypi-kernel-headers as mentioned in the second answer here on StackExchange

After that, get the kernel module source and follow the rest of the instructions from the Adafruit article.

Since I have a Pi Zero, I had to change the module source as instructed. And to test the volume control (in the bottom of the Adafruit article) I had to change the name from "Boost Capture Volume" to "Master Capture Volume" (which was down a ways in this thread).

But after modifying the source and building and loading the module I was able to record a wav file using arecord!

Then I had to modify the FFsocket source to open the MEMS mic kernel module by changing it from hw:adau7002 to hw:sndrpisimplecar. And with that I managed to get ffsocket to run and was able to use client.py to read the output and can see varying values in the output array.

I don't know what any of those values mean :-) but it seems to be doing something in response to noise near the Enviro+

@kflmiami420
Copy link

David thank you for your post I will follow your instructions on my Enviro+ plus board. I am working on using the ACD pin to read an external adafruit 1733 anemometer as well by modifying the Gas.py script to include a read function and convert voltage to m/s reading , Then adding another mode to enviro_demo.py to be able to get a display of wind speed.

@Bugierek
Copy link

Regarding obtaining the A-Weighted SPL I have found this example:
https://docs.smartcitizen.me/Components/Urban%20Sensor%20Board/Noise%20Sensor/
and here are some interesting Github repos related to it:

  1. https://github.com/fablabbcn/smartcitizen-kit-audio
  2. https://github.com/oscgonfer/AudioI2S

@Bugierek
Copy link

Bugierek commented Sep 23, 2019

I have found another implementation here, so it might be helpful to see how it was done on other platform :
https://github.com/Tinkerforge/sound-pressure-level-bricklet/

https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Sound_Pressure_Level.html

@vschinazi
Copy link

Hi @Gadgetoid I just wanted to follow up on this issue. It would be really great to have a python script to measure noise pollution. I am currently developing a project that will use the Enviro + sensor in 30+ classrooms and getting a measure of noise would be really amazing.
Thank you.

@kflmiami420
Copy link

kflmiami420 commented Oct 14, 2019 via email

@vschinazi
Copy link

You have to adapt a dead cat attachment to the noise sensor otherwise the hard walls and floors and ceiling will amplify your levels and give you improper levels .

Oh wow, thank you for the heads up! What do you recommend for that? Do you actually have a working python script for the microphone? Would you be able to share that?

@Gadgetoid
Copy link
Member

Sorry I should have mentioned that the noise/microphone code is currently pending review and merge in a pull-request which you can find here: #33

I'll keep this issue open because I don't believe Python is the best/only way to do this, and alternate setups which access the i2s microphone could be useful or interesting to others.

@Gadgetoid Gadgetoid added the notice This issue is resolved, but left open for posterity/visibility label Nov 5, 2019
@Bugierek
Copy link

Bugierek commented Nov 6, 2019

Hi,
I have found another piece of code that might help with getting the fft noise levels:
https://github.com/colin-guyon/rpi-audio-levels

Sorry for flooding this topic with bunch of links, I'm not a dev and can't really code, but hopefully in some of these examples there will be something useful and helpful to get it working well on Rpi.

@seaniedan
Copy link

There is some sound code written now, but when I do (on a fresh install of Raspbian):
git clone https://github.com/pimoroni/enviroplus-python
cd enviroplus-python
sudo ./install.sh
I get 'SyntaxError: invalid syntax' in the install script (see attached), and then (after reboot):
pi@raspberrypi:~/enviroplus-python/examples $ python3 ./noise-profile.py
Traceback (most recent call last):
File "./noise-profile.py", line 3, in
from enviroplus.noise import Noise
File "/usr/local/lib/python3.7/dist-packages/enviroplus-0.0.3-py3.7.egg/enviroplus/noise.py", line 1, in
ModuleNotFoundError: No module named 'sounddevice'
enviroplus_problems.txt

@seaniedan
Copy link

in case anyone is wondering, this seemed to help:
pip3 install sounddevice

@bluemeerkat
Copy link

Hi, I am another one interested in being able to measure noise pollution in terms of dBA, which would clearly be useful in an Environmental monitoring board. (In fact we wrongly assumed this would be provided before buying the board).
Before I try out some of the ideas suggested by @Bugierek, since most of a year has elapsed since this issue was first raised, I wondered if perhaps something has changed and Pimoroni (@Gadgetoid) might have some usable library either available or in development?

Now, I notice that there is now a noise.py library with three functions to obtain noise profile and mean amplitudes at a frequency range or ranges. But it's not clear what units these return and I don't think they fit the bill for dBA (which involves root-squared-mean values and A-weighting according to a curve). Am I wrong @Gadgetoid - or can these be easily adapted for dBA?

(Apologies if you see this twice - I thought I posted it yesterday - but it seems to have been my imagination :-) )

Thanks a lot.

@ftosteve
Copy link

Hi. Another who bought several Enviro+ hoping to measure dBA.
Looking around other repo's dBA looks quite intense.
I hope Pimoroni can help us all.
Thanks

@LucaTurina
Copy link

Hi. Also bought an Enviro+ hoping to measure dBA. Would love to get some input here! Thank you :-)

@riffo-online
Copy link

Hello to everyone! I bought Enviro+ mainly to acquire data related to indoor environments and mainly for noise level (dB or dBA).
I'm not an experienced programmer and I can't find an example "ready-to-use" on the Web to detect the noise level in dB or dBA.
Has anyone found something? it would be crucial for me!
THANK YOU very much to anyone who has suggestions on this!

@alaub81
Copy link

alaub81 commented Dec 11, 2020

Anybody else got this error on running the noise-profile.py:

Traceback (most recent call last):
  File "noise-profile.py", line 29, in <module>
    low, mid, high, amp = noise.get_noise_profile()
  File "/root/.local/lib/python3.7/site-packages/enviroplus/noise.py", line 67, in get_noise_profile
    recording = self._record()
  File "/root/.local/lib/python3.7/site-packages/enviroplus/noise.py", line 89, in _record
    dtype='float64'
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 275, in rec
    ctx.input_dtype, callback, blocking, **kwargs)
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 2578, in start_stream
    **kwargs)
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 1416, in __init__
    **_remove_self(locals()))
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 812, in __init__
    extra_settings, samplerate)
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 2651, in _get_stream_parameters
    info = query_devices(device)
  File "/root/.local/lib/python3.7/site-packages/sounddevice.py", line 564, in query_devices
    raise PortAudioError('Error querying device {}'.format(device))

Installed also the sounddevice and the libportaudio2
I am using a raspberry pi zero w. Everything else of the example scripts is working well.

@ftosteve
Copy link

Hi Gadgetoid.
Is there any news on the development obtaining dBA/SPL with the MEMs microphone?
I would find this extremely useful in my project.
I now have 20 of these HAT's with the intention of buying at least 60 for a factory monitoring system.
If you have any code you need testing, I would be happy to help. I can also gain access to a handheld calibrated SPL meter to check accuracy.
Thanks
Steve
PS: Have also been mailing your colleague Matt at Pimoroni about this subject and he pointed me here.

@seaniedan
Copy link

seaniedan commented Dec 17, 2020

Hey Steve, drop me a line - follow the link to my website. I have some ideas for you.

@ChristophDerndorfer
Copy link

@seaniedan @ftosteve, do you have any updates from your discussions that you can share publicly?

@ftosteve
Copy link

ftosteve commented Jan 2, 2021

Nothing from me sorry. I have been offline for a few weeks. I did look at seaniedan's link but nothing related to this subject.

@Cumberland-Pi
Copy link

I took a copy of your northcliff_spl_monitor. Until I commented out the mic line, I got an exception (couldn't find device)

def _record(self):
    return sounddevice.rec(
        int(self.duration * self.sample_rate),
        samplerate=self.sample_rate,
        #device = "dmic_sv",
        blocking=True,
        channels=1,
        dtype='float64'
    )

I got it working on my Enviro. I'm now trying to splice it into the app wot I wrote, which displays a horizontal bar chart of the measurements at various bands. I'll post the code if & when I get it cleaned up. It's a hacked mess at the moment.

Anyway, thanks for your code.

@ChristophDerndorfer
Copy link

@Cumberland-Pi, great news, and let us know if you need anyone to test your code even in early stages. :)

@roscoe81
Copy link
Contributor

roscoe81 commented Jan 9, 2021

@Cumberland-Pi I suspect that if the script couldn't find "dmic-sv", the I2S microphone setup (as per the Setup section of the README) hasn't been successfully completed. I might be wrong, but you might find that the northcliff_spl_monitor code won't run successfully without it because I found that the microphone level needed to be increased to get reasonable readings. I've also now updated my code to include the ability to provide graphical displays. The display types can be selected as command line arguments that are shown in the updated README.

@Cumberland-Pi
Copy link

@roscoe81
Thanks for the info, something to investigate, as I am getting strange results. Note to self - ALWAYS read the README before grabbing the code :-|
Also good to know you've added the graphical stuff. I'll have a look.
@ChristophDerndorfer. Cheers for the offer.

@ftosteve
Copy link

@roscoe81
Sorry for delay in testing, been snowed under. Finally got to try your instructions and code.
Took me a while to get past the the 'Use alsamixer to set adau7002 capture level to 100' line as after selecting the device with F6, the F4 to 'Capture' keeps closing the mixer...
I got around this, rightly or wrongly, by pressing F5(All) and setting level to 100 there.

Running your .py I get dB(A) reading on the screen that is about ~5dB(A) more than my phone app, which is not bad as an indicator.
Of course I am not sure how accurate my phone app/mic is so am reasonably happy to get that close.
On Monday I am back at work so will try and 'borrow' the calibrated SPL meter and see how close it really is.
As my application is for a factory, I am happy just to know it its above 100dB(A) or not.
Thanks loads for this by the way, very much appreciated...

On a side note. I want to replicate my pi/enviro devices 50+ times.
If I image the SD and put on the other devices, will all the settings be transferred across. For instance, the soundcard id, alsamixer 100% settings etc, etc?
Or are these settings stored somewhere else in the Pi?

Thanks again,
Steve

@roscoe81
Copy link
Contributor

@ftosteve
Glad that you found it useful and that's strange about the alsamixer setup. I've further tweaked the calibration in the latest code update but I'm still not totally happy with its measurements across the entire sound level range. It's in the experimental stage and I wouldn't recommend it being used in its current state to provide reliable sound level measurements.

I would expect that imaging the SD will replicate all the required settings.

@Cumberland-Pi
Copy link

Cumberland-Pi commented Jan 18, 2021

@roscoe81 Got my sound app mentioned above working, and I've incorporated your Noise class.

Here's the code:
(edited as I can't seem to link my github rep. so loaded python file as text)

spl_meter.txt

Comments always welcome.

I plan to splice in Ross' displays at some later date.

@roscoe81
Copy link
Contributor

I’ve updated my code to Version 1.0 that now uses streaming to overcome the microphone's startup "plop" that was identified in the excellent review here. It’s performance seems to be much better than the previous version.

@dguk25
Copy link

dguk25 commented Feb 27, 2021

thanks @roscoe81 for moving this forward
it's really frustrating that a board that's advertised for noise level sensing doesn't have ANY documentation around using this sensor! I also bought it on the presumption that this would work.
I've got your code working... but do you also see regular spikes even when completely silent?
really keen to get this board working for ambient light and noise level detection, but need it to be fairly reliable. the lux detection seems pretty good.
anyone got any other suggestions for a HAT that would support both noise and light detection out of the box?

@roscoe81
Copy link
Contributor

roscoe81 commented Mar 2, 2021

Thanks for the feedback @dguk25
I didn't see the spikes when I did the initial testing but I have experienced them, depending on the prior state of the Raspberry Pi Zero. It seemed that the code had problems with the timing of the callback and main loop. The latest version of my code now seems to address that issue. I also found that microphone drift was no longer an issue - presumably because the samples were being processed properly. I also added the ability to cycle through the display types via the proximity sensor. Please let me know if this latest version addresses the spike issue that you found.

@dguk25
Copy link

dguk25 commented Mar 2, 2021

Great work @roscoe81 !
No longer see the spikes and generally performs pretty well ;)
I'm interested in what you mean by "the sampling rate of 16kHz and the very basic A-curve compensation are still major limitations"... do you think the sensor is fundamentally limited, or just that further development is needed to harness it?
I'm looking to utilise it for ambient noise levels, but I'm starting to wonder if the directional nature of the MEMS microphone might be a hinderance.

@roscoe81
Copy link
Contributor

roscoe81 commented Mar 3, 2021

Glad that you're seeing progress @dguk25
The sampling rate is now 48kHz, so that limitation has now been addressed. The A-curve compensation is still limited by my code at the moment, due to it only having three frequency bands. Apart from the start-up "plop" and DC offset that were addressed by streaming in Version 1.0, I don't see any inherent limitations of the MEMS microphone in doing the job and I think the next steps are to add more frequency bands and to implement an asyncio coroutine to optimise processing capacity. They're on my to-do list and I suspect that the only potential roadblock is the limited processing power of the Raspberry Pi Zero. I've already seen that when I've tried to integrate the noise measurement code into my enviro-monitor.

I've now added a maximum sound level line (along with the time and date when it was recorded) to Display 1 in my latest code update. I've found that to be quite useful.

@roscoe81
Copy link
Contributor

I’ve now integrated noise level measurement into my enviro-monitor and it seems to work reasonably well.

@dguk25
Copy link

dguk25 commented Mar 13, 2021

I’ve now integrated noise level measurement into my enviro-monitor and it seems to work reasonably well.

Brilliant. Will check it out later today. Thanks for the note above as well. The maximum sound level line works really well 👍

@ChristophDerndorfer
Copy link

@roscoe81, thanks a lot for all your work! I've finally had a chance to test the current version northcliff_spl_monitor.py and it seems to work well. I hope to find some time next week to compare the measured noise levels with some apps I have installed on my phone.

Three issues I ran into while following the instructions in the README were:

  1. Using alsamixer to set adau7002 capture level to 50 doesn't work for me. I can start the alsamixer and switch to the adau7002 via F6 but as soon as I hit F4 to get to the capture mode the program quits and I'm back on the commandline. Maybe it's related to the fact that I'm SSHing into the RPi Zero W rather than an actual terminal but I haven't found a solution for this issue yet. Is anyone else here running into it?
  2. Upon the first execution of your script I got an error message about matplotlib not being available on my system. Running sudo pip3 install matplotlib quickly fixed the issue but maybe the requirement can be added to the README so others aren't confused about it.
  3. On my Pi Zero W starting the script takes about 14 seconds and so initially I had thought that it had crashed. Is that the same on your system?

And a final question: Is there any difference in the noise measurement implementation between enviro-monitor and the stand-alone script?

Thanks again and keep up the great work.

@ChristophDerndorfer
Copy link

Quick update on the alsamixer issue: When physically logged into the console via a keyboard I was able to change the capture level as documented. So the behaviour I was seeing definitely seems to be related to me being connected via SSH beforehand.

@roscoe81
Copy link
Contributor

Thanks for your feedback @ChristophDerndorfer
In term of your three issues.

  1. I haven't seen that issue with alsamixer and I log in via VNC
  2. I'll add that in the README.
  3. Yes, I have a similar startup time.

I've found that the measurements between the two implementations are identical but the cycle rates are slower on the enviro-monitor

@ChristophDerndorfer
Copy link

  1. Okay, that then seems to confirm what I thought that there's some sort of difference depending on whether alsamixer is started local or via SSH.
  2. Thanks, I think that will be useful.
  3. Thanks for the confirmation. I ran so many different test and library versions on that Pi Zero that I thought that the long startup might have been caused by some incompatibility issues or whatnot.

@ftosteve
Copy link

Not sure if will help anyone, but i've been scratching my head on this for ages.
If I followed all the help and did everything through console logged on a pi then everything worked fine.
However, every time I tried to sudo the code or remote debug(sudo) then my sound class kept giving an error about unable to find device "dmic_sv"...

After many obscure searches I stumbled upon https://www.alsa-project.org/main/index.php/Asoundrc.
In there it suggests you can create the devices in the ~/.asoundrc is AdaFruit instruct, but also in /etc/asound.conf for system wide configuration.
I did this and now I can see the "dmic_sv" running under sudo.

Reason, I need this, is my pi has no desktop and my code will run as a Service on boot, so ordinarily not logged in to console.
Hope this helps soem others too.

@dguk25
Copy link

dguk25 commented Mar 20, 2021

hi all . great to see this continually progressing. appreciate the work @roscoe81

I'm wondering about a couple of things:

  1. is it possible to have some kind of 'smoothing' to the noise detection, such that there is less fluctuation? even when sound levels seem steady, there is oscillation of around 5 dB. is that potentially due to air fluctuations?.... I've noticed the device is very sensitive to this (just waving hand in front of it registers as quite loud, presumably due to pressure fluctuation at the sensor). has anyone tried to reduce this with a microphone cover etc?

  2. how would you recommend streaming the data to a central server if I was to use a number of devices? is installing MQTT the best route and could this be incorporated into your code?

@roscoe81
Copy link
Contributor

roscoe81 commented Mar 20, 2021

Thanks for your feedback @dguk25.

  1. It would be a simple exercise to smooth the output so it only responded to spl changes beyond a set threshold. However, two issues would need to be considered. Firstly, it’s counter to the desire to provide as accurate noise level readings as possible. Secondly, fluctuations of 5dB are not large. It’s generally accepted that the minimum change in sound level that can be detected by most people is 3dB, so I would expect that the current sensitivity of the noise sensor is consistent with what’s required to monitor noise level changes that a listener would experience .
  2. My Enviro Monitor code sends maximum noise levels every 5 minutes as mqtt messages. That would allow you to send noise level data to a central system, whilst having manageable levels of mqtt traffic. It would be relatively easy to also send minimum and mean levels via mqtt, like I’ve done with the Luftdaten and Adafruit IO noise level capture options in that code. I haven’t done that yet, because I’ve been happy to just use maximum noise level data in my own mqtt data capture system. I expect that streaming the raw microphone data or the measured dB level on every loop via mqtt message would result in heavy mqtt traffic levels and it’s not something that I would recommend. I think it’s much better to do the processing locally and send summarised data via mqtt.

@jpiper
Copy link

jpiper commented Apr 13, 2021

I followed the instructions here and then the noise-amps-at-freqs.py and noise-profile.py scripts worked

@dguk25
Copy link

dguk25 commented Apr 30, 2021

I find I'm having to do this step each time I reboot the pi:

nano ~/.asoundrc

copying specific text, then running

arecord -D plughw:0 -c1 -r 48000 -f S32_LE -t wav -V mono -v file.wav

Otherwise it doesn't recognise the i2smic. Is there a way round this @roscoe81 ? Have I missed something in the setup.

@roscoe81
Copy link
Contributor

roscoe81 commented May 6, 2021

I haven't come across that issue @dguk25 and the i2smic is recognised on my unit after each reboot, so I'm not sure that I can help you. The only thing I can suggest is to ask if you set up the auto load at boot in "Auto Load at Boot" in these instructions.

@dguk25
Copy link

dguk25 commented May 6, 2021 via email

@jeolives
Copy link

For anyone in the future who is also trying to make noise-amps-at-freqs.py and noise-profile.py work on their Enviro/+, and it spits out the "adau7002" device not found error - but doesn't want to modify FFsocket as per #11 (comment) :

  1. Follow the Adafruit instructions from https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/raspberry-pi-wiring-test up to and including the i2scmic.py script - set it up so that it loads automatically, but when presented with the option to reboot, don't do that yet with n.
  2. After running the installer script, change directory by cd Raspberry-Pi-Installer-Scripts. Then cd i2s_mic_module
  3. In your text editor of choice, edit the file snd-i2smic-rpi.c. Edit the following line: .card = "snd_rpi_i2s_card", // -> snd_soc_card.name to .card = "adau7002", // -> snd_soc_card.name
  4. Run the following commands in order make clean, make, make install
  5. If this hasn't been done automatically by the script, modify your /boot/config.txt with dtparam=i2s=on (some distros like DietPi)
  6. Now you can reboot
  7. ssh back into your pi, create a new config file in your home directory ~ called .asoundrc with your text editor of choice. Copy and paste the following from @roscoe81:
#This section makes a reference to your I2S hardware, adjust the card name
#to what is shown in arecord -l after card x: before the name in []
#You may have to adjust channel count also but stick with default first
pcm.dmic_hw {
type hw
card adau7002
channels 2
format S32_LE
}

#This is the software volume control, it links to the hardware above and after
#saving the .asoundrc file you can type alsamixer, press F6 to select
#your I2S mic then F4 to set the recording volume and arrow up and down
#to adjust the volume
#After adjusting the volume - go for 50 percent at first, you can do
#something like
#arecord -D dmic_sv -c2 -r 48000 -f S32_LE -t wav -V mono -v myfile.wav
pcm.dmic_sv {
type softvol
slave.pcm dmic_hw
control {
name "Master Capture Volume"
card adau7002
}
min_dB -3.0
max_dB 30.0
}

Format it like so:
image

After running these steps, test if everything works through:

  • Running alsamixer, pressing F4 on your keyboard, and seeing the following screen:
    image
  • Running noise-amps-at-freqs.py and noise-profile.py and having an output on the Enviro/+'s screen.

@Dashbrook
Copy link

Dashbrook commented Apr 16, 2024

Thank you to everyone who has contributed to this awesome thread! Thanks especially to @roscoe81 I can now record from the mic. What is going over my head through is just getting a simple output to a csv e.g. a csv with the noise level every minute or the average noise level in the past minute.

E.g. similar to the other outputs here https://angelaambroz.com/blog/posts/2021/Mar/08/pi_project_2_indoor_environment_monitor/

@r-carroll
Copy link

Also want to chime in and mention that with the help of @roscoe81's repo here I was able to successfully get accurate dbA readings. It will be my goal in the next few weeks to write up a script that saves readings to a database every few seconds to get a historical sound pressure record.

IMG_1152

@HOD42
Copy link

HOD42 commented May 11, 2024

That really is EXCELLENT news! Thank you. I'll be experimenting more with this functionality and hopefully improve my Grafana dashboard.

@Gadgetoid
Copy link
Member

Sorry for the lack of response here. I don't have a good answer for why it slipped me by, other than: ARGH.

I think it goes without saying that the effort of @roscoe81 is greatly, greatly appreciated. I am not in possession of the time, expertise and headspace to produce as well-rounded a solution. Our software always straddles some awkward line between "feature complete, usable example" and "very basic starter for makers to take and run with" and it doesn't always work out.

Should this library try to implement @roscoe81's code? I believe we should probably have a basic setup in the Enviro library, but also link to @roscoe81's excellent project as a more complete solution. This is so we can direct credit where credit is due, lend some exposure to a good project, but also not simply kick the can for proper noise monitoring support completely down the road.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
notice This issue is resolved, but left open for posterity/visibility
Projects
None yet
Development

No branches or pull requests