# QTFM Simple Gradiometer Guide

This app subtracts one sensor from another, and only when their QTFM
millisecond timestamps identify the same measurement packet. With two sensors
that is the familiar A−B trace.

## Connecting sensors

- **SENSORS** in the header sets how many sensors are connected, gated and
  recorded — anywhere from 2 to 8.
- **SENSOR SETUP** opens a separate window holding every sensor card. It opens
  automatically at startup and can be left open beside the main window or
  closed at any time; the connections stay open either way. Keeping the cards
  out of the main window means the plot area never shrinks, and the setup
  window arranges eight cards in two or three columns so they fit without a
  scrollbar.
- Each card shows that sensor's live scalar field, so every connected sensor
  stays readable even when it is not one of the two being plotted.
- The setup window has its own command bar, identical to the one in the main
  window, so filter and ASCII commands can be sent while working on the
  connections. Each bar keeps its own target selection.
- **TERMINAL** (in either window's header) opens a raw serial view for one
  selected sensor. The **STARTS WITH** box limits the display to lines
  beginning with any of the given characters — `!` for scalar data lines,
  `#` for firmware status lines — and PAUSE/CLEAR control the display. The
  view keeps the most recent 2,000 lines.
- Reducing the sensor count disconnects the sensors that are removed.

## Saved settings

The user-adjusted settings — sensor count, plotted pair, RECORD DIFFERENCES,
each sensor's COM port, baud and data-rate selection, the display window, ASD
options, and the terminal filter — are saved automatically when the app
closes and re-applied on the next start. They live in a human-readable
`qtfm_settings.json` in the folder the executable runs from (the `App`
folder, or `Source` when running from source). Delete the file to return to
defaults; upgrading the app never overwrites it.

## Choosing what is plotted

- The plots are always the same three: one sensor, a second sensor, and their
  difference. The **PLOT** selectors in the Gradiometer Setup bar choose which
  two of A–H fill those slots — any pair, at any time, even while recording.
- The bottom plot is `first − second`, so selecting C and H plots C, H and C−H.
  Picking the sensor already shown in the other slot swaps the pair
  (A−B becomes B−A).
- The plot selection is independent of CSV recording: the recorded file
  always holds every sensor's field, whichever pair is on screen.
- Changing the pair keeps each sensor's buffered history, so the two sensor
  plots refill immediately. The difference restarts, because a buffered
  difference belongs to the pair that produced it.
- The difference readout above the plots counts matched exact-timestamp
  packets live, so it is visible that gradiometer data is arriving even before
  the first plottable value, and alongside the value afterwards.
- Every time-series trace is drawn in QuSpin golden rod. On the ASD tab, where
  all three share one plot, golden rod / QuSpin blue / green identify the plot
  slot — not the sensor letter.

## Recommended wired configuration

For a new wired synchronization:

1. Fully start every sensor.
2. Use the same data rate and environmental/filter settings on all of them.
3. Connect a UMCC cable from the chosen Master sensor's **Sync_Out** to each
   other sensor's **Sync_In**.
4. Set exactly one sensor to **MASTER** and every other sensor to **SLAVE**.
5. Wait for every mode badge to confirm the requested mode.
6. Click **SYNC SENSORS** in the Time Series graph header.
7. Wait for `#Sensors Sync Complete`.
8. Confirm the app reports equal timestamp intervals, zero sample phase, and
   exact timestamp groups before relying on the difference plots.

This follows QuSpin's
[Gen-2 wired Master/Slave procedure](https://quspin.com/qtfm-gen-2/qtfm-gen-2-user-guide/syncing-your-gen-2-qtfm-sensors/).

## Valid and invalid role combinations

- **One Master + all others Slave:** required to initiate a wired
  synchronization.
- **More than one Master:** invalid and will give improper data. The app
  disables the difference trace and names the offending sensors.
- **All Slaves:** cannot initiate a new wired sync. If the sensors are already
  running and their live timestamps prove equal-rate, phase-aligned operation,
  the app permits exact-packet subtraction.

Timestamp agreement does not replace the physical wired-sync requirement when
performing a new wired synchronization. The cable continuously carries the
Master clock to the Slaves.

## What happens when the sync cable is absent

Setting a sensor to Slave without a valid input clock may produce
`needs input clock`. The data stream may pause because the Slave is waiting for
the Master clock.

The app handles this by:

- displaying a cable/input-clock warning;
- timing out an unconfirmed mode request after two seconds;
- restoring the Master, Slave, data-rate, and reboot controls;
- keeping the gradiometer disabled until valid aligned data returns.

The serial write confirmation means the command reached the COM port. It does
not mean the sensor successfully entered the requested hardware mode.

## Reboot recovery

The independent **REBOOT SENSOR** button queues ASCII `e` to that sensor. The
app reports when the byte is actually written, waits three seconds, restores
the controls, and queries the mode and startup settings again. If the COM port
itself fails, disconnect and reconnect that sensor.

## CSV recording

Choose **START RECORDING** and select a base filename. The app writes one
`<name>_gradiometer.csv` file containing the PC time, the exact device
millisecond timestamp, and one field column per sensor. Each sensor's serial
number appears once, in its own column name.

By default the file contains **no difference columns** — with several sensors
they multiply the file size while adding nothing that cannot be recomputed.
Checking **RECORD DIFFERENCES** before starting opts into a self-contained
file that also stores a `reference − sensor` column for every other sensor,
where the reference is the first **PLOT** sensor at the moment recording
starts. The choice and the reference are fixed for the lifetime of that
recording.

A row is written only when **every** recorded sensor reports that exact
millisecond timestamp, so partially matched timestamps are dropped rather
than padded, and any difference computed from a row is an exact gradiometer
pair.

Use **STOP & SAVE** before moving or opening the recording file.

## Computing differences from a recording

**PARSE RECORDING** in the main window's recording bar opens a window that
computes any `X − Y` channels from a recorded CSV — no Python installation
needed, so it works from the packaged executable. Browse to the recording,
add pairs with the selectors (or type them, e.g. `A-B A-C`), optionally
include the sensor field columns, and click **PARSE**.

The same functionality is available as a standalone script for scripting and
automation. `Source/tools/gradiometer_parser.py` needs only a standard Python
installation:

```powershell
# See which sensors (and serial numbers) a recording contains
python tools\gradiometer_parser.py recording_gradiometer.csv --list

# Write A−B and A−C into recording_differences.csv
python tools\gradiometer_parser.py recording_gradiometer.csv --pairs A-B A-C

# Also copy the sensor field columns used, to a chosen output file
python tools\gradiometer_parser.py recording_gradiometer.csv --pairs C-H `
    --include-fields --output survey_ch.csv
```

Any pairing works, in either direction, and recordings from older application
versions that still contain difference columns are accepted (the extra
columns are ignored).

## Gradiometer requirements

The difference trace updates only when:

- at least two sensors are selected;
- every sensor provides millisecond timestamps;
- all data rates match;
- no more than one sensor reports Master;
- timestamp cadence and phase are aligned across all sensors;
- the raw millisecond timestamps match exactly for the packets being subtracted.

Note that the gate covers **every** connected sensor, not only the two being
plotted, because the recorded CSV spans all of them. If one sensor of eight
loses its timestamp, the difference pauses until it returns.

If a Sync In sensor reports `ISR.Er1` or stops producing scalar data for five
seconds, the sensor firmware protects it by returning it to Master mode; the
app reports the change and restores the controls.

If the difference is not updating, open the in-app **USER GUIDE** and inspect
the timestamp-alignment message before changing analysis settings.
