A surface Laplacian
On a grid of electrodes (HD-EMG, ECoG), a Laplacian replaces each channel by itself minus the
mean of its neighbours. Whatever is spread over the whole grid (a distant source, the common
artefact) cancels; what is local to a few electrodes stays. Laplacian.from_grid(rows, cols) is
the 5-point version; from_positions handles any layout.
import numpy as np
import dspkfrom plating import signals
ROWS, COLS = 4, 4# No LFP here (its phase differs across channels, so it is not shared): the shared parts are the# common artefact and the hum, made larges = signals.synthetic(channels=ROWS * COLS, lfp_uv=0.0, common_uv=150.0, hum_uv=60.0)lap = dspk.ops.spatial.Laplacian.from_grid(ROWS, COLS)y = lap.apply(s.data)
ch = s.loudest_channelfor name, comp in (("common artefact", "common"), ("spikes", "spikes")): kept = np.std(lap.apply(s.components[comp])[ch]) / (np.std(s.components[comp][ch]) or 1) print(f"{name}: {100 * kept:.0f} % of its RMS kept on channel {ch}")
The whole script is playground/05_spatial/02_laplacian.py. Run it with uv run python playground/05_spatial/02_laplacian.py.