|
| 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