Bench test and calibration
Bench test of the module, wiring checks, and measuring µT per mA with a phone.
4 min readSource on GitHub
1. Bench test of the AD5328 module (no coils connected)
The module's output stage is undocumented. The firmware assumes:
- 2.5 V onboard reference (jumper 1-2);
- AD5328 GAIN = 1, giving 0–5 V from the DAC;
- module output = 4·V_DAC − 10 V, so code 0x000 → −10 V, 0x800 → 0 V, 0xFFF → +10 V.
Verify this before connecting coils:
- Module jumper on 1-2, 5 V from a USB supply, ESP32 wired as in docs/WIRING.md, no coils, arming switch not connected. First check the module's test pads against GND: 5V ≈ 5 V, 12V ≈ +12 V, −12V ≈ −12 V, VREF ≈ 2.50 V. If VREF reads 0 V or drifts, the reference jumper is on 2-3 or missing (docs/WIRING.md, "The AD5328 module").
- Flash the firmware (
cd firmware && pio run -e <board> -t upload, withesp32s3,esp32devoresp32e_lcd28) and connect the app (Connect → GodHelmet-XXXX). - Power-on state. Before the ESP32 boots (hold its EN button), measure AO1…AO8 against GND. Expect ≈ −10 V (DAC code 0). This is why the arming switch exists.
- After boot. All outputs should read 0 V ± 20 mV (mid-scale).
- Full scale. In the app, Helmet → Calibration → DC test on CH1 at +4.5 mA. With nothing connected, the output is the DAC voltage: expect about +9.9 V. At −4.5 mA expect about −9.9 V. Check every channel. CH1 must be AO1 (DAC A), and so on.
- If full scale is only 0 to −10 V or −10 to 0 V, the module expects the other gain setting: toggle "DAC gain ×2" in Helmet → Settings and repeat. If the swing is ±5 V, set "Module full scale" to 5.
2. Wiring and polarity check (coils connected, helmet off)
- Helmet → Wiring check → rotation test, 1000 ms dwell, 2 mA. Measure the voltage across each 2.2 kΩ resistor: about 4.4 V on the active channel and 0 V elsewhere, moving in CCW order (docs/PLACEMENT.md).
- DC test per coil with a compass in front of the coil face. Mark the face the compass's south end points to as N (it is the coil's north pole). Mount all coils N-face inward.
3. Field calibration (µT per mA at 20 mm)
The firmware converts the µT you choose into current using a per-channel factor: µT at 20 mm, on axis, per mA. The default 1.8 is the model of this coil with its core; the same winding without a core gives 0.73 (tools/coil_field.py). Measure every coil: the core material of these commodity coils is not documented (sellers list ferrite or iron), and the field falls about 12 % per mm at 20 mm, so the spacer must be accurate to ±0.3 mm for ±4 %.
You need:
- a phone with a magnetometer and phyphox (free; "Magnetometer" experiment, absolute values), or the optional I2C magnetometer;
- a 20 mm spacer (a stack of coins, a piece of wood).
Per coil:
- Lay the phone flat and find where its magnetometer sits (move a small magnet over it; usually near the top edge). Find the axis that changes most when the coil is held against the phone.
- Put the coil face 20 mm from the sensor, on axis, with nothing metallic nearby.
- Note the reading with the coil off (Earth's field and phone offsets).
- Start a DC test at +2 mA (Helmet → Calibration) and note the reading on.
- Repeat at −2 mA; the change should be the same size with the opposite sign.
- Enter |on − off| and the current; "Use for this channel" computes µT/mA. Save.
Or collect all readings in a CSV and fit them:
channel,mA,uT_on,uT_off
1,2,49.10,47.62
1,-2,46.15,47.62
...
python3 tools/calibrate.py measurements.csv
Type the printed values into Helmet → Calibration and save.
Expected values: about 1.8 µT/mA with the core (model range 1.4–2.2), 0.73 without. With 1.8, the 4.54 mA cap gives about 8 µT at 20 mm, about 1 µT at 45 mm and about 0.47 mT at the core face. An uncalibrated helmet with the old default (0.73) delivered about 2.4× the requested field; with the current default the error is small if the coil has a core and the field comes out lower (about 0.4×) if it has none.
To check the model itself, also measure on axis at 0, 2, 5, 10 and 40 mm and at 90° in the coil's mid-plane (reverse the current to cancel Earth's field). Model values per mA: 105 µT at the face, 60 at 2 mm, 25 at 5 mm, 8.1 at 10 mm, 0.33 at 40 mm; −0.6 µT at 90°, 20 mm from the coil's side. A fluxgate (FLC100) or MMC5983MA works from about 5 mm outwards; use a Hall sensor (DRV5055) only at 0–5 mm.
4. What the numbers mean
| Setting | Meaning |
|---|---|
| Intensity (µT) | Peak field 20 mm in front of each coil, i.e. roughly at the cortex under it |
| Max field (Helmet → Settings) | Your ceiling (default 5 µT, absolute limit 10 µT) |
| Max reachable | Hardware cap × weakest channel's µT/mA |
Literature values: Persinger helmet ≈ 1 µT; Octopus 5–10 µT; Shakti 1–9 µT. Presets default to 1 µT (2 µT for the circumcerebral research presets).