Skip to content

Commit 087b34c

Browse files
committed
Name the system PiSLM and add a full installation manual
Rename the project from the working title "noise monitor" to PiSLM (Raspberry Pi Sound Level Meter) across the tree: - directory examples/python/mcc172/noise_monitor -> pislm - noise_monitor.py -> pislm.py, noise-monitor.service -> pislm.service - protocol version string noise-monitor/3 -> pislm/3 - config env var NOISE_MONITOR_CONFIG -> PISLM_CONFIG - systemd unit name, GPIO consumer string, and all prose references Add INSTALL.md: a complete field installation manual covering the bill of materials (and why a Pi 4 rather than a Zero 2 W), hardware assembly and grounding per the MCC 172 spec, the power budget, the GPIO trigger wiring with the pins the HAT reserves, OS setup, daqhats and uldaq installation (including the udev rule for non-root USB access), Python dependencies, static-IP networking for a direct laptop link, low-power/low-noise tuning, configuration and end-to-end calibration with an acoustic calibrator (including the correction formula), first run and systemd enablement, a pre-session field checklist, and a troubleshooting table. README links to it for new builds. Verified after the rename: 49/49 with the DSP pool and 47/47 inline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019SaEpdKhSDouXvxZ31kccq
1 parent 88e7fdb commit 087b34c

11 files changed

Lines changed: 437 additions & 36 deletions

File tree

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
# PiSLM — Installation Manual
2+
3+
Complete build guide for a **PiSLM** node: a Raspberry Pi 4 with an
4+
MCC 172 DAQ HAT and a Data Translation DT9837A, giving 6 calibrated IEPE
5+
channels streamed to a laptop as sound-level-meter data.
6+
7+
Work through the sections in order. Sections 1–4 are hardware, 5–9 are
8+
software, 10–13 are configuration and commissioning.
9+
10+
---
11+
12+
## 1. Bill of materials
13+
14+
### Required
15+
16+
| Item | Spec / note |
17+
|------|-------------|
18+
| Raspberry Pi 4 Model B | **4 GB** recommended (2 GB works with a shorter RAM buffer). The DSP needs the A72's single-core speed; a Zero 2 W / Pi 3 cannot run 6 ch with bands. |
19+
| Official Pi 4 PSU | 5.1 V / 3 A USB-C. Do not use a phone charger — supply dips show up as noise. |
20+
| microSD card | 32 GB, A1/A2 class. **OS only** — no measurement data is written to it. |
21+
| MCC 172 DAQ HAT | 2 IEPE channels, 51.2 kS/s/ch. Address 0 (all address jumpers removed). |
22+
| DT9837A | 4 IEPE channels, USB-powered. Optional if 2 channels are enough. |
23+
| IEPE microphones | With a **calibrated sensitivity in mV/Pa** (from the datasheet or a calibration certificate). |
24+
| Ethernet cable | Cat5e or better, Pi ↔ laptop (direct or via switch). |
25+
| Heatsink or fan case | The MCC 172 spec limits operation to 0–55 °C. |
26+
27+
### Recommended
28+
29+
| Item | Why |
30+
|------|-----|
31+
| Powered USB hub | Keeps the DT9837A's 4 IEPE supplies off the Pi's 1.2 A USB budget. Required if you also attach USB storage. |
32+
| Sound level calibrator | 94 dB / 114 dB @ 1 kHz — the only way to verify the calibration end to end (§12). |
33+
| Jumper wires + 2-pin screw terminal | For the GPIO synchronized-start trigger (§4). |
34+
| Acoustic calibrator adapter | Matches the calibrator cavity to your microphone diameter. |
35+
36+
---
37+
38+
## 2. Hardware assembly
39+
40+
**Power off the Pi and unplug it before touching the header.**
41+
42+
1. **Seat the MCC 172** on the Pi's 40-pin header, pressing evenly until it
43+
is fully home. With one HAT, leave **all address jumpers removed**
44+
(address 0) — one board must be at address 0 for the OS to read the HAT
45+
EEPROM.
46+
2. **Fit the heatsink/fan** before mounting the HAT if your case requires it;
47+
the HAT covers the SoC.
48+
3. **Connect the DT9837A** to a USB 3.0 port on the Pi (blue), or to a
49+
powered hub. Use the supplied USB cable — the DT9837A is bus-powered.
50+
4. **Connect the microphones**:
51+
- MCC 172: 10-32 coaxial jacks (CH0, CH1), or the screw terminals — but
52+
**only one source per channel**, never both at once.
53+
- DT9837A: BNC inputs (CH0–CH3).
54+
5. **Ethernet** from the Pi to the laptop or switch.
55+
56+
### Grounding (affects measurement quality)
57+
58+
The MCC 172 electrical specification states: *connect the signal source and
59+
the Raspberry Pi to a common ground; if the source is floating, connect the
60+
MCC 172 to earth ground via the DGND screw terminal to minimise common-mode
61+
noise.*
62+
63+
- The DT9837A shares ground with the Pi through USB, so no extra bonding is
64+
needed between the two devices.
65+
- Avoid ground loops: power the Pi from **one** supply, and prefer a single
66+
earth reference for the whole measurement chain.
67+
68+
---
69+
70+
## 3. Power
71+
72+
| Load | Draw |
73+
|------|-----:|
74+
| Raspberry Pi 4 (under load) | ~5.5 W |
75+
| MCC 172 (incl. 2 IEPE supplies) | 0.7 W (140 mA @ 5 V max) |
76+
| DT9837A (incl. 4 IEPE supplies) | up to 2.5 W (USB bus-powered) |
77+
| **Total** | **~8.7 W** |
78+
79+
The official 5.1 V / 3 A (15.3 W) PSU covers this with margin. The Pi 4's
80+
total USB budget is 1.2 A; the DT9837A's ≤500 mA fits, but add a **powered
81+
hub** if you also attach USB storage.
82+
83+
**Battery operation**: any USB-PD bank that holds 5 V / 3 A works. At ~8.7 W
84+
(≈7.5 W with §11 tuning), a 20 000 mAh (74 Wh) bank runs roughly 8 hours.
85+
86+
---
87+
88+
## 4. GPIO synchronized-start trigger (optional)
89+
90+
Wire this if you want both devices to begin their scans on the same edge.
91+
Skip it for single-device use or if start alignment does not matter.
92+
93+
```
94+
GPIO 17 (BCM, header pin 11) --+-- MCC 172 "TRIG" (J5 pin 1)
95+
+-- DT9837A "Ext Trigger" input
96+
GND (header pin 9) ------------+-- MCC 172 "GND" (J5 pin 2)
97+
+-- DT9837A ground
98+
```
99+
100+
- **Rising edge only** — the DT9837A's external digital trigger supports no
101+
other edge. 3.3 V GPIO satisfies both inputs (MCC 172 V_IH 1.48 V max).
102+
- **Do not use** the pins the MCC 172 occupies: BCM 0, 1, 5, 6, 8–13, 16,
103+
19, 20, 26. Safe alternatives to 17: **27, 22**.
104+
- Keep the trigger wire short and away from the microphone cables.
105+
106+
> This aligns the **start** of the scans (≈±1 sample per device plus each
107+
> ADC's fixed group delay). It does **not** lock the ADC clocks, which still
108+
> drift a few ppm relative to each other — see §14.
109+
110+
---
111+
112+
## 5. Operating system
113+
114+
1. Flash **Raspberry Pi OS (64-bit, Lite)** with Raspberry Pi Imager. In the
115+
Imager's settings (gear icon) pre-configure: hostname `pislm`, your user,
116+
SSH enabled, and locale. Lite (no desktop) is preferred — less background
117+
load and lower power.
118+
2. Boot the Pi, log in over SSH, and update:
119+
120+
```sh
121+
sudo apt update && sudo apt full-upgrade -y
122+
sudo reboot
123+
```
124+
125+
3. Confirm SPI is not claimed by anything else. GPIO-header LCDs and other
126+
SPI HATs **will** break the MCC 172 — remove their overlays from
127+
`/boot/firmware/config.txt` if any were ever installed.
128+
129+
---
130+
131+
## 6. Install the daqhats library (MCC 172)
132+
133+
```sh
134+
cd ~
135+
git clone https://github.com/mccdaq/daqhats.git
136+
cd daqhats
137+
sudo ./install.sh
138+
```
139+
140+
The installer reads the HAT EEPROM and may prompt for a reboot. Verify:
141+
142+
```sh
143+
daqhats_list_boards
144+
```
145+
146+
You should see the MCC 172 at address 0. If not, re-seat the HAT and check
147+
that no other SPI device is configured.
148+
149+
---
150+
151+
## 7. Install uldaq (DT9837A)
152+
153+
Skip this section if you are not using the DT9837A.
154+
155+
```sh
156+
sudo apt install -y gcc g++ make libusb-1.0-0-dev
157+
158+
# C library (check the project page for the current release tag)
159+
cd ~
160+
wget https://github.com/mccdaq/uldaq/releases/download/v1.2.1/libuldaq-1.2.1.tar.bz2
161+
tar -xvjf libuldaq-1.2.1.tar.bz2
162+
cd libuldaq-1.2.1
163+
./configure && make
164+
sudo make install
165+
sudo ldconfig
166+
167+
# Python binding
168+
sudo apt install -y python3-pip
169+
pip3 install uldaq --break-system-packages
170+
```
171+
172+
Allow non-root USB access:
173+
174+
```sh
175+
sudo tee /etc/udev/rules.d/99-dt9837a.rules >/dev/null <<'EOF'
176+
# Data Translation DT9837A — allow access for the plugdev group
177+
SUBSYSTEM=="usb", ATTRS{idVendor}=="0a2d", MODE="0666", GROUP="plugdev"
178+
EOF
179+
sudo udevadm control --reload-rules && sudo udevadm trigger
180+
sudo usermod -aG plugdev "$USER"
181+
```
182+
183+
Log out and back in, then verify the device enumerates:
184+
185+
```sh
186+
lsusb | grep -i "data translation"
187+
```
188+
189+
---
190+
191+
## 8. Install Python dependencies
192+
193+
```sh
194+
sudo apt install -y python3-numpy python3-scipy python3-libgpiod
195+
```
196+
197+
- `numpy` / `scipy` — required for levels, metrics, and band filtering.
198+
- `python3-libgpiod` — for the GPIO trigger (§4). PiSLM also accepts
199+
libgpiod v1 or `RPi.GPIO`, whichever the OS provides.
200+
201+
Verify:
202+
203+
```sh
204+
python3 -c "import numpy, scipy, gpiod; print('deps ok')"
205+
```
206+
207+
---
208+
209+
## 9. Install PiSLM
210+
211+
PiSLM lives in the daqhats checkout from §6:
212+
213+
```sh
214+
cd ~/daqhats/examples/python/mcc172/pislm
215+
ls # pislm.py, config.ini, devices.py, ...
216+
```
217+
218+
Nothing to build — it is plain Python.
219+
220+
---
221+
222+
## 10. Network setup
223+
224+
For a direct Pi ↔ laptop link, give the Pi a static address on the wired
225+
interface:
226+
227+
```sh
228+
sudo nmcli con mod "Wired connection 1" \
229+
ipv4.method manual ipv4.addresses 192.168.50.1/24
230+
sudo nmcli con up "Wired connection 1"
231+
```
232+
233+
Set the laptop's wired interface to `192.168.50.2/24`. Verify from the
234+
laptop:
235+
236+
```sh
237+
ping 192.168.50.1
238+
```
239+
240+
Gigabit Ethernet carries the full raw stream (6 ch ≈ 20 Mbit/s) with room to
241+
spare, and keeps RF away from the microphone lines.
242+
243+
---
244+
245+
## 11. Low-power / low-noise tuning (recommended)
246+
247+
On a wired, headless measurement node, disable the radios and video:
248+
249+
```sh
250+
sudo tee -a /boot/firmware/config.txt >/dev/null <<'EOF'
251+
252+
# --- PiSLM: headless measurement node ---
253+
dtoverlay=disable-wifi
254+
dtoverlay=disable-bt
255+
EOF
256+
sudo systemctl disable --now bluetooth
257+
sudo reboot
258+
```
259+
260+
Saves roughly 0.5–1 W and removes the on-board radios as a noise source.
261+
Keep Wi-Fi enabled if a tablet will connect wirelessly for live readout.
262+
263+
---
264+
265+
## 12. Configure and calibrate
266+
267+
Edit `config.ini`. The settings you **must** get right:
268+
269+
```ini
270+
[devices]
271+
enabled = mcc172, dt9837a ; omit dt9837a for a 2-channel node
272+
273+
[mcc172]
274+
channels = 0, 1
275+
iepe_enable = true
276+
sensitivity_ch0 = 50 ; ← YOUR microphone, in mV/Pa
277+
sensitivity_ch1 = 50
278+
279+
[dt9837a]
280+
channels = 0, 1, 2, 3
281+
iepe_enable = true
282+
sensitivity_ch0 = 50
283+
; ... ch1..ch3
284+
```
285+
286+
**Sensitivity is the calibration.** Enter each microphone's mV/Pa value and
287+
the data comes back in **pascals**, so all levels and metrics are true SPL
288+
re 20 µPa. Left at the default `1000`, the data stays in volts.
289+
290+
Other settings worth reviewing (see the comments in the file): `sample_rate`,
291+
`[weighting] frequency/time`, `[level] output_rate`, `[storage]
292+
buffer_seconds`, `[bands]`, `[dsp] workers`, `[trigger] sync_start`.
293+
294+
### Verify with an acoustic calibrator
295+
296+
1. Start PiSLM by hand (§13, step 1).
297+
2. Fit the calibrator to the microphone and switch it on (94 dB @ 1 kHz).
298+
3. From the laptop, ask for the level:
299+
300+
```sh
301+
printf '{"id":1,"cmd":"get_metrics","seconds":5,"channels":[0]}\n' \
302+
| nc 192.168.50.1 5000
303+
```
304+
305+
4. `Leq` should read **94 dB ±0.5** (A-weighting is ≈0 dB at 1 kHz). If it is
306+
off by a constant, correct `sensitivity_chN`:
307+
308+
```
309+
new_sensitivity = old_sensitivity × 10^((measured_dB − 94) / 20)
310+
```
311+
312+
Repeat per channel. Record the final values — this is your calibration
313+
record.
314+
315+
---
316+
317+
## 13. First run and automatic start
318+
319+
**Step 1 — run by hand** (always do this before enabling the service):
320+
321+
```sh
322+
cd ~/daqhats/examples/python/mcc172/pislm
323+
python3 pislm.py
324+
```
325+
326+
Expected output: each device detected, the DSP worker count, and the two
327+
listening ports. From the laptop:
328+
329+
```sh
330+
printf '{"id":1,"cmd":"status"}\n' | nc 192.168.50.1 5000
331+
```
332+
333+
Stop with Ctrl-C.
334+
335+
**Step 2 — install the service:**
336+
337+
```sh
338+
cd ~/daqhats/examples/python/mcc172/pislm
339+
sudo cp pislm.service /etc/systemd/system/
340+
sudoedit /etc/systemd/system/pislm.service # fix User= and the paths
341+
sudo systemctl daemon-reload
342+
sudo systemctl enable --now pislm
343+
```
344+
345+
**Step 3 — check it:**
346+
347+
```sh
348+
systemctl status pislm
349+
journalctl -u pislm -f
350+
```
351+
352+
After editing `config.ini`: `sudo systemctl restart pislm`.
353+
354+
---
355+
356+
## 14. Field checklist
357+
358+
Before each measurement session:
359+
360+
- [ ] Microphones connected; IEPE enabled for every channel in use
361+
- [ ] `sensitivity_chN` matches the microphone actually fitted
362+
- [ ] Calibrator check passed (§12) — note the deviation
363+
- [ ] Windscreens fitted outdoors
364+
- [ ] `systemctl status pislm` active; laptop can reach both ports
365+
- [ ] `buffer_seconds` long enough to cover your longest event
366+
- [ ] Laptop has disk space if recording raw (6 ch ≈ 8.8 GB/hour)
367+
368+
**Remember:** the two devices' ADC clocks are independent (a few ppm apart).
369+
Per-channel levels and metrics are unaffected, but **cross-device phase or
370+
correlation analysis is not valid** — keep channel pairs that need phase
371+
coherence on the same device.
372+
373+
---
374+
375+
## 15. Troubleshooting
376+
377+
| Symptom | Cause / fix |
378+
|---------|-------------|
379+
| `daqhats_list_boards` finds nothing | HAT not fully seated, or another SPI device configured. Check `/boot/firmware/config.txt` for display/SPI overlays. |
380+
| `No DT9837A device found` | udev rule not applied, or user not in `plugdev`. Re-log in; check `lsusb`. |
381+
| `overrun` events, scan stops | The Pi cannot keep up. Lower `sample_rate`, lower `[bands] f_max`, or confirm `[dsp] workers` is `-1` (not `0`). |
382+
| Levels ~0 dB or nonsense | IEPE off, or `sensitivity` left at 1000 (data in volts, not Pa). |
383+
| Level is off by a fixed amount | Recalibrate with the calibrator (§12). |
384+
| Hum / mains buzz | Ground loop. Use one PSU, bond DGND to earth for floating sources, keep cables away from mains. |
385+
| `trigger GPIO unavailable` | Missing `python3-libgpiod`, or the pin collides with the MCC 172 (§4). |
386+
| Service dies at boot, works by hand | Wrong `User=`/paths in the unit, or it started before the HAT was ready — `Restart=always` retries; check `journalctl -u pislm`. |
387+
| Client cannot connect | Check the Pi's IP and that `config.ini` binds `host = 0.0.0.0`. |
388+
389+
---
390+
391+
## 16. Next steps
392+
393+
- **Write your client** against [`PROTOCOL.md`](PROTOCOL.md) — the complete
394+
wire specification (both ports, frame types, every command).
395+
- **Operating notes and tuning** are in [`README.md`](README.md).

0 commit comments

Comments
 (0)