On-device gamma spectrometry and isotope identification for RadiaCode detectors, on an ESP32-S3 touchscreen.
The peak-search-and-gate pipeline had reached the point where each field test added another veto, and vetoes only subtract sensitivity: ~28 tuned constants and 6 boolean gates. Measured on the real uranium capture, it was correct at 300s and 600s, wrong at 900s and 1200s, correct again at 1800s - more data made it worse. Identification is now a Poisson maximum-likelihood fit of the whole spectrum against per-nuclide response templates. Nuclides compete through the likelihood, so the competitive-assignment, share-margin and better-explained-elsewhere tie-breakers are gone, along with ~20 of the constants. Detection is one threshold that means the same thing for every nuclide: 3 sigma on a fitted amplitude. Four things this needed, each found by measurement: - 16 broad continuum bumps, not 4 exponentials. chi2 62 -> 3.3, and stopped nuclide templates being recruited as continuum filler. - Full Fisher covariance, not the diagonal, which claimed Co-60 12.8 sigma on background containing none. - Chain-coupled columns at secular equilibrium. Six free U-238 amplitudes let Tl-208 eat Bi-214's 609 keV line - the NATURAL MIX bug. - FIT_MIN_KEV 150: the X-ray region is unmodelled, and Ba-133 scored 70% on real ore largely on its 81 keV line. Also: - spectrum_window: analysis runs on counts since a baseline that rolls forward on a confirmed rate step, so a source presented to a long accumulation is seen without pressing RESET. - PSRAM was never actually enabled. BOARD_HAS_PSRAM alone does nothing; memory_type selects the sdkconfig. getPsramSize() was 0, the template matrix could not allocate, and analyzeSpectrum() silently fell back to the old path while looking perfectly healthy on serial. - The fit no longer runs inside DataGuard. Holding the mutex for the 1-3s fit blocked every draw and touch on core 1. - BACKGROUND is no longer claimed after 120s. This ore needs ~600s, so the device announced "background" with a real source in front of it. - quality.weakestKeySigma held the strongest sigma while labelled weakest, so grade, progress and "measurement complete" were all wrong. - Chain members are listed as evidence (Pb-212/Tl-208/Ac-228) instead of one representative. - DataGuard added to the UI screens that read g_data on core 1. host/ is an offline replay harness that compiles the real analysis sources against shims and replays captured spectra, with sweep and presentation modes. host/spectra/ holds three real captures. Verified on hardware: uranium ore identified at 5.0 sigma and held; thorium mantle correct; WiFi/BLE coexistence measured across a full OTA check with the fit resident. Known: Eu-152 reads ~5.4 sigma on the ore - genuine template degeneracy with Pb-214, not a threshold problem. Am-241 is no longer identifiable below the fit range. |
||
|---|---|---|
| ESP32-S3-Touch | ||
| RadiaCode-Spectrometer | ||
| tools | ||
| .gitignore | ||
| CLAUDE.md | ||
| LICENSE | ||
| sample_test.xml | ||