Algorithmic Definitions

This page provides formal mathematical definitions for all metrics computed by Synaptipy’s analysis modules. Every formula below corresponds directly to the implementation in src/Synaptipy/core/analysis/. Parameter names in the equations match the variable names in the source code.


1. Baseline / Resting Membrane Potential (RMP)

Module: passive_properties.py · Registry name: rmp_analysis

\[ V_{\text{RMP}} = \frac{1}{N} \sum_{i \in \mathcal{W}} V_i \]

where \(\mathcal{W} = \{ i : t_{\text{start}} \le t_i < t_{\text{end}} \}\) is the set of sample indices within the user-specified baseline window.

Baseline standard deviation:

\[ \sigma_{\text{RMP}} = \sqrt{ \frac{1}{N-1} \sum_{i \in \mathcal{W}} (V_i - V_{\text{RMP}})^2 } \]

Baseline drift is the slope \(\beta_1\) of the ordinary least-squares regression \(V_i = \beta_0 + \beta_1 \, t_i + \varepsilon_i\) fitted over \(\mathcal{W}\), reported in mV/s.

To prevent high-frequency electronic noise from inflating the slope estimate, the voltage array is pre-smoothed with a uniform moving average of window \(w_{50} = \lfloor 50\,\text{ms} / \Delta t \rfloor\) samples before regression. Only the valid (non-edge) portion of the convolution output is used:

\[ \tilde{V}_i = \frac{1}{w_{50}} \sum_{k=0}^{w_{50}-1} V_{i+k}, \quad i = 0,\ldots, N - w_{50} \]

This attenuates noise components above \(\approx 20\,\text{Hz}\) while preserving sub-Hz biological drift.

Auto-detect baseline selects the window \(\mathcal{W}^*\) that minimises the sliding-window variance:

\[ \mathcal{W}^* = \arg\min_{\mathcal{W}_k} \operatorname{Var}\!\bigl(V_{i \in \mathcal{W}_k}\bigr) \]

where \(\mathcal{W}_k\) slides in steps of step_duration with width window_duration.


2. Input Resistance (\(R_{\text{in}}\))

Module: passive_properties.py · Registry name: rin_analysis

\[ R_{\text{in}} \;(\text{M}\Omega) = \frac{|\Delta V|}{|\Delta I|} \]

where

\[ \Delta V = \bar{V}_{\text{response}} - \bar{V}_{\text{baseline}}, \qquad \Delta I = I_{\text{step}} \;(\text{pA}) \]

\(\bar{V}\) denotes the arithmetic mean over the respective time window. Current is converted internally: \(\Delta I_{\text{nA}} = |\Delta I_{\text{pA}}| / 1000\).

Conductance:

\[ G \;(\mu\text{S}) = \frac{1}{R_{\text{in}} \;(\text{M}\Omega)} \]

2.1 Series-Resistance Artifact Blanking

An uncompensated bridge balance produces an instantaneous voltage jump at stimulus onset. To prevent this \(R_s\) artifact from inflating \(\Delta V\), the first rs_artifact_blanking_ms milliseconds (default 0.5 ms) of the response window are excluded from all voltage measurements:

\[ \mathcal{W}_{\text{resp}}^{\text{blanked}} = \{ i : t_{\text{resp,start}} + t_{\text{blank}} \le t_i < t_{\text{resp,end}} \} \]

where \(t_{\text{blank}} = \texttt{rs\_artifact\_blanking\_ms} \times 10^{-3}\).

The same blanking logic is available for the RMP baseline window via the rs_artifact_blanking_ms parameter of run_rmp_analysis_wrapper.

2.2 Peak \(R_{\text{in}}\) and Steady-State \(R_{\text{in}}\) (\(I_h\) correction)

Cells expressing HCN channels (\(I_h\)) exhibit a voltage “sag” during sustained hyperpolarisation: the voltage first reaches a maximum deflection (Peak) and then partially recovers toward a lower steady-state. A single \(R_{\text{in}}\) value is therefore biologically ambiguous.

Peak \(R_{\text{in}}\) uses the sample of maximum absolute voltage deflection within the (blanked) response window:

\[ V_{\text{peak}} = V\!\left[\arg\max_i |V_i - \bar{V}_{\text{baseline}}|\right], \quad i \in \mathcal{W}_{\text{resp}}^{\text{blanked}} \]
\[ R_{\text{in,peak}} = \frac{|V_{\text{peak}} - \bar{V}_{\text{baseline}}|}{|\Delta I_{\text{nA}}|} \]

Steady-State \(R_{\text{in}}\) uses the mean voltage over the last 20% of the (blanked) response window, reflecting the membrane resistance after sag recovery:

\[ R_{\text{in,ss}} = \frac{|\bar{V}_{\text{last 20\%}} - \bar{V}_{\text{baseline}}|}{|\Delta I_{\text{nA}}|} \]

For a cell with strong \(I_h\): \(R_{\text{in,peak}} > R_{\text{in,ss}}\). For a cell without sag: \(R_{\text{in,peak}} \approx R_{\text{in,ss}}\).

Both metrics are returned by calculate_rin via rin_peak_mohm and rin_steady_state_mohm on the RinResult object and are exposed as CSV columns by the batch exporter.


3. Membrane Time Constant (\(\tau\))

Module: intrinsic_properties.py · Registry name: tau_analysis

3.1 Mono-exponential model

\[ V(t) = V_{\text{ss}} + (V_0 - V_{\text{ss}}) \, e^{-t/\tau} \]

Fitted via bounded non-linear least squares (scipy.optimize.curve_fit). An initial artifact-blanking period of artifact_blanking_ms is excluded from the fit window.

3.2 Bi-exponential model

\[ V(t) = V_{\text{ss}} + A_{\text{fast}} \, e^{-t/\tau_{\text{fast}}} + A_{\text{slow}} \, e^{-t/\tau_{\text{slow}}} \]

Constraint: \(\tau_{\text{fast}} < \tau_{\text{slow}}\) (swapped post-fit if violated).


4. Sag Ratio

Module: intrinsic_properties.py · Registry name: sag_ratio_analysis

4.1 Ratio form (default)

\[ \text{Sag Ratio} = \frac{V_{\text{peak}} - V_{\text{baseline}}}{V_{\text{ss}} - V_{\text{baseline}}} \]

A value > 1 indicates hyperpolarisation-activated sag (I_h current). A value of 1 indicates no sag.

4.2 Percentage form

\[ \text{Sag} \;(\%) = 100 \times \frac{V_{\text{peak}} - V_{\text{ss}}}{V_{\text{peak}} - V_{\text{baseline}}} \]

\(V_{\text{peak}}\) is the minimum of the Savitzky-Golay smoothed voltage in the peak window (configurable peak_smoothing_ms, default 5 ms, polynomial order 3).

\(V_{\text{ss}}\) is the arithmetic mean of the last portion of the hyperpolarising step (response_steady_state_window).

4.3 Rebound depolarisation

\[ \Delta V_{\text{rebound}} = \max\bigl(V_{i \in \mathcal{R}}\bigr) - V_{\text{baseline}} \]

where \(\mathcal{R}\) is a configurable window (default 100 ms) immediately following stimulus offset.


5. Capacitance (\(C_m\))

Module: passive_properties.py · Registry name: capacitance_analysis

5.1 Current-clamp mode

The preferred formula accounts for the series (access) resistance \(R_s\), which acts in series with \(R_{\text{in}}\) and therefore carries part of the RC time constant:

\[ C_m \;(\text{pF}) = \frac{\tau \;(\text{ms})}{R_{\text{in}} - R_s \;(\text{M}\Omega)} \]

When \(R_s\) is not available (e.g. the fast artifact window is too short to resolve), the approximation \(C_m = \tau / R_{\text{in}}\) is used and a warning is logged, since this over-estimates \(C_m\) by a factor of \(R_{\text{in}} / (R_{\text{in}} - R_s)\).

Both \(\tau\) and \(R_{\text{in}}\) are computed from the same hyperpolarising current-step trace. \(R_s\) is estimated via calculate_cc_series_resistance_fast (see Section 5.3).

5.2 Voltage-clamp mode

(Rs and Cm derivation follows Hamill et al., 1981; see §15.1 for full equations.)

\[ C_m = \frac{Q}{\Delta V} \]

where \(Q = \int_0^T \bigl( I(t) - I_{\text{ss}} \bigr) \, dt\) is the charge transfer of the capacitive transient, computed via trapezoidal integration (scipy.integrate.trapezoid).

5.3 Current-clamp series resistance (\(R_s^{\text{CC}}\))

The fast resistive voltage artifact at current-step onset, measured within a 0.1 ms window immediately after the step, reflects the series resistance before the membrane has had time to charge:

\[ R_s^{\text{CC}} \;(\text{M}\Omega) = \frac{|\Delta V_{\text{fast}} \;(\text{mV})|}{|I_{\text{step}} \;(\text{pA})|} \times 10^3 \]

The artifact window is intentionally kept to 0.1 ms (down from a previous 0.5 ms default) to avoid bleeding into the membrane-charging phase, which would artifactually inflate the \(R_s\) estimate.

Sampling-rate dependency and stability warning. This calculation resolves a 0.1 ms window to detect the fast resistive jump. At 10 kHz sampling the window contains only one sample, making the estimate highly unstable (a single noisy sample determines the entire \(R_s^{\text{CC}}\) value). At 20 kHz the window contains two samples; at 50 kHz, five samples. For reliable \(R_s^{\text{CC}}\) and derived \(C_m\) values, recordings should be sampled at \(\ge 20\) kHz. At 10 kHz, the VC transient method (Section 5.2) is more robust and should be preferred. The instability propagates directly into \(C_m\) via \(C_m = \tau / (R_{\text{in}} - R_s)\): an unreliable \(R_s\) estimate can produce \(C_m\) values that are biologically implausible.


6. Spike Detection and Action Potential Features

Module: spike_analysis.py · Registry name: spike_detection

6.1 Threshold crossing

Spikes are detected where \(V(t) > V_{\text{threshold}}\) with a minimum refractory period between crossings. The peak is the local maximum within peak_search_window samples after each crossing.

6.2 Onset detection (dV/dt-based)

(See also §15.2 for the full maximum-curvature method; cited in Sekerli et al., 2004.)

The action potential onset is defined as the first point where

\[ \frac{dV}{dt} > \theta_{dV/dt} \]

in the onset_lookback window preceding the spike peak. The derivative is computed via numpy.gradient(V) / dt and reported in V/s.

6.3 Amplitude

\[ A_{\text{spike}} = V_{\text{peak}} - V_{\text{threshold}} \]

6.4 Half-width

The half-amplitude level is

\[ V_{50} = V_{\text{threshold}} + 0.5 \times A_{\text{spike}} \]

Half-width is the time interval between the two crossings of \(V_{50}\) on the rising and falling phases, computed with linear interpolation for sub-sample precision.

6.5 Rise time (10-90%)

\[ t_{\text{rise}} = t_{V_{90}} - t_{V_{10}} \]

where \(V_{x} = V_{\text{threshold}} + (x/100) \times A_{\text{spike}}\). Crossings are linearly interpolated.

6.6 Decay time (90-10%)

\[ t_{\text{decay}} = t_{V_{10,\text{fall}}} - t_{V_{90,\text{fall}}} \]

on the falling phase of the action potential.

6.7 Afterhyperpolarisation (AHP)

(Savitzky-Golay smoothing applied to AHP waveforms; filter derivation in Savitzky & Golay, 1964.)

\[ \text{AHP depth} = V_{\text{threshold}} - V_{\text{AHP,min}} \]

where \(V_{\text{AHP,min}}\) is the minimum voltage in the ahp_window following the spike peak, smoothed with a Savitzky-Golay filter using a dynamic window \(w = \max(5,\ \lfloor 5\,\text{ms} / \Delta t \rfloor)\) samples, order 3. The window is rounded up to the nearest odd integer to satisfy the Savitzky-Golay constraint, ensuring the filter width tracks the recording’s sampling rate.

AHP duration is the time from the repolarisation crossing of \(V_{\text{threshold}}\) to recovery back to \(V_{\text{threshold}}\).

6.8 Afterdepolarisation (ADP)

\[ A_{\text{ADP}} = V_{\text{ADP,peak}} - V_{\text{fAHP,trough}} \]

where \(V_{\text{fAHP,trough}}\) is the fast AHP minimum within fahp_window_ms (default 5 ms) after the action potential peak, and \(V_{\text{ADP,peak}}\) is the largest local maximum in the subsequent adp_search_window_ms (default 20 ms). A point \(V_i\) is a local maximum if \(V_i > V_{i-1}\) and \(V_i > V_{i+1}\).

If no local maximum is found (monotonic recovery), \(A_{\text{ADP}} = \text{NaN}\).

6.9 Maximum and minimum dV/dt

\[ \left(\frac{dV}{dt}\right)_{\max} = \max_{t \in [\text{onset}, \text{peak}]} \frac{dV}{dt}(t) \]
\[ \left(\frac{dV}{dt}\right)_{\min} = \min_{t \in [\text{peak}, \text{AHP}]} \frac{dV}{dt}(t) \]

6.10 Absolute Peak Voltage and Overshoot

Classical neurophysiology reports the raw membrane potential at the AP peak and the extent to which it exceeds \(0\,\text{mV}\) (overshoot):

\[ V_{\text{peak,abs}} = V\bigl[i_{\text{peak}}\bigr] \]
\[ \text{Overshoot} \;(\text{mV}) = \max\!\bigl(0,\; V_{\text{peak,abs}}\bigr) \]

An overshoot of 0 indicates the AP peaked below \(0\,\text{mV}\) (e.g. in immature neurons or under pharmacological block of Na\(^+\) channels). Both metrics are returned as absolute_peak_mv and overshoot_mv in the per-spike feature dictionaries produced by calculate_spike_features.


7. Event Detection

7.1 Threshold-based detection

Module: synaptic_events.py · Registry name: event_detection_threshold

  1. Rolling median subtraction (window = rolling_baseline_window_ms).

  2. Noise estimate via Median Absolute Deviation: \(\hat{\sigma} = 1.4826 \times \text{MAD}\).

  3. Adaptive prominence: \(p = \max(\text{threshold}, \, 2\hat{\sigma})\).

  4. Peak detection via scipy.signal.find_peaks with the computed prominence, height, and refractory distance constraints.

  5. Events with duration \(< 0.2\,\text{ms}\) are rejected as non-physiological.

7.2 Template-match / matched-filter cross-correlation

Registry name: event_detection_deconvolution

A single bi-exponential kernel is constructed from the user-specified rise and decay time constants:

\[ K(t) = e^{-t/\tau_{\text{decay}}} - e^{-t/\tau_{\text{rise}}} \]

normalised to unit area. The kernel is cross-correlated (matched-filter) with the baseline-corrected trace - this is not deconvolution. Events are detected where the z-scored matched-filter output exceeds threshold_sd:

\[ z(t) = \frac{(V \star K)(t) - \mu_{\text{MAD}}}{\hat{\sigma}_{\text{MAD}}} \]

Note

Template bank construction: The filter scales a single user-defined decay constant by fixed multipliers (1×, 2×, 3×) to create a detection template bank, rather than extracting a dynamic, data-driven template. The three kernels provide tolerance for dendritic filtering without requiring a representative example event from the recording.

7.3 Baseline-peak detection

Registry name: event_detection_baseline_peak

Uses sliding-window variance minimisation to find the most stable baseline segment, estimates noise as \(\hat{\sigma} = 1.4826 \times \text{MAD}\) in that region, and detects peaks with prominence \(\ge 0.5 \times \text{threshold}\).

7.4 Local Pre-Event Baseline (Dynamic Amplitude for Summating Events)

Synaptic events that occur during the exponential decay of a preceding event (summation) ride on a shifted baseline. Using the global resting potential as the amplitude reference artificially inflates the measured amplitude of the second event (or any subsequent event in a burst).

For each detected event peak index \(i_k\), Synaptipy searches a window of pre_event_window_ms (default 2 ms, valid range 1-3 ms) immediately preceding the peak and computes a local foot voltage \(V_{\text{foot},k}\):

\[\begin{split} V_{\text{foot},k} = \begin{cases} \max_{j \in \mathcal{P}_k} V_j & \text{(negative polarity)} \\ \min_{j \in \mathcal{P}_k} V_j & \text{(positive polarity)} \end{cases} \end{split}\]

where \(\mathcal{P}_k = \{j : i_k - N_{\text{pre}} \le j < i_k\}\) and \(N_{\text{pre}} = \lfloor \texttt{pre\_event\_window\_ms} \times f_s / 1000 \rfloor\).

The local amplitude of event \(k\) is then:

\[\begin{split} A_{\text{local},k} = \begin{cases} V_{\text{foot},k} - V_k & \text{(negative polarity)} \\ V_k - V_{\text{foot},k} & \text{(positive polarity)} \end{cases} \end{split}\]

This definition ensures that in a summating train, each event’s amplitude reflects the true biological quantal size rather than the accumulated depolarisation from prior events. The values are returned as _local_baselines and _local_amplitudes in the metrics dict, together with the scalar summary mean_local_amplitude.


8. I-V Curve

Module: intrinsic_properties.py · Registry name: iv_curve_analysis

For each sweep \(n\):

\[ I_n = I_{\text{start}} + n \times I_{\text{step}}, \qquad \Delta V_n = \bar{V}_{\text{response},n} - \bar{V}_{\text{baseline},n} \]

Aggregate input resistance is the slope of the linear regression \(\Delta V = R_{\text{in}} \cdot \Delta I_{\text{nA}} + b\):

\[ R_{\text{in}} = \frac{\sum (\Delta I - \overline{\Delta I})(\Delta V - \overline{\Delta V})} {\sum (\Delta I - \overline{\Delta I})^2} \]

reported with \(R^2\) goodness-of-fit.


9. Burst Analysis

Module: burst_analysis.py · Registry name: burst_analysis

A burst begins when \(\text{ISI}_k \le \text{max\_isi\_start}\) and continues while \(\text{ISI}_k \le \text{max\_isi\_end}\). Groups with fewer than min_spikes spikes are discarded.

\[ f_{\text{burst}} = \frac{N_{\text{bursts}}}{T_{\text{recording}}} \]

10. Excitability (F-I Curve)

Module: excitability.py · Registry name: excitability_analysis

Per sweep \(n\) with injected current \(I_n\):

\[ f_n = \frac{N_{\text{spikes},n}}{T_{\text{sweep}}} \]

Rheobase = minimum \(I_n\) eliciting \(\ge 1\) spike.

F-I slope from linear regression \(f = \alpha \cdot I + \beta\) (Hz/pA).

Spike Frequency Adaptation per sweep:

\[ \text{SFA} = \frac{\text{ISI}_{\text{last}}}{\text{ISI}_{\text{first}}} \]

11. Phase Plane Analysis

Module: phase_plane.py · Registry name: phase_plane_analysis

\[ \frac{dV}{dt}(t) = \text{gaussian\_filter1d}\!\left( \frac{\Delta V}{\Delta t}, \; \sigma \right) \]

where \(\sigma\) is the Gaussian smoothing width.

Kink detection: the first point where \(dV/dt > \kappa\) (kink slope) in the lookback window preceding the spike peak, reflecting the axonal initiation site.


12. Spike Train Dynamics

Module: firing_dynamics.py · Registry name: train_dynamics

ISI = numpy.diff(spike_times)

Coefficient of Variation (CV):

\[ \text{CV} = \frac{\sigma_{\text{ISI}}}{\mu_{\text{ISI}}} \]

\(\text{CV} = 0\): perfectly regular; \(\text{CV} = 1\): Poisson process.

CV₂ (Holt et al., 1996):

\[ \text{CV}_2 = \frac{1}{N-1} \sum_{i=1}^{N-1} \frac{2 \,|\text{ISI}_{i+1} - \text{ISI}_i|}{\text{ISI}_{i+1} + \text{ISI}_i} \]

Measures local variability; insensitive to slow firing-rate changes.

Local Variation (LV) (Shinomoto et al., 2003):

\[ \text{LV} = \frac{3}{N-1} \sum_{i=1}^{N-1} \left( \frac{\text{ISI}_i - \text{ISI}_{i+1}}{\text{ISI}_i + \text{ISI}_{i+1}} \right)^{\!2} \]

\(\text{LV} < 1\): regular; \(\text{LV} \approx 1\): Poisson; \(\text{LV} > 1\): bursty.


13. Optogenetic Synchronisation

Module: evoked_responses.py · Registry name: optogenetic_sync

TTL edge detection: binarise the stimulus channel at ttl_threshold, then find rising edges via numpy.diff.

Optical latency:

\[ \bar{L} = \frac{1}{N_{\text{resp}}} \sum_{j=1}^{N_{\text{resp}}} (t_{\text{event},j} - t_{\text{stim},j}) \]

Response probability:

\[ P_{\text{resp}} = \frac{N_{\text{stim with event}}}{N_{\text{stim}}} \]

Jitter:

\[ \text{Jitter} = \sigma(L_j) \]

14. Signal Preprocessing

14.1 Digital filters

All Butterworth IIR filters are applied as zero-phase via scipy.signal.sosfiltfilt (second-order sections):

Filter

Transfer function

Lowpass

\(H(s) = \prod_{k=1}^{N/2} \frac{1}{s^2 + b_k s + 1}\) at cutoff \(f_c\)

Highpass

Complement of lowpass at \(f_c\)

Bandpass

Cascade of highpass at \(f_L\) and lowpass at \(f_H\)

Notch

\(H(z)\) from scipy.signal.iirnotch at centre \(f_0\), quality \(Q\)

Comb

Cascaded notch at \(f_0, 2f_0, \ldots, Nf_0\)

14.2 Baseline subtraction

Method

Formula

Mode

\(V' = V - \text{mode}(V)\) (rounded to configured precision)

Mean

\(V' = V - \bar{V}\)

Median

\(V' = V - \tilde{V}\)

Linear detrend

\(V' = V - (\beta_0 + \beta_1 t)\) via scipy.signal.detrend

Time window

\(V' = V - \bar{V}_{\mathcal{W}}\) for user-specified \(\mathcal{W}\)

14.3 Artifact blanking

For stimulus artefact suppression, three interpolation modes are available:

Method

Description

hold

Replace artefact window with the last pre-artefact sample value

zero

Set artefact window to zero

linear

Linearly interpolate between the pre- and post-artefact boundary values

14.4 Trace quality assessment

SNR: \(\text{SNR} = P_{\text{signal}} / P_{\text{noise}}\)

Baseline drift: slope \(\beta_1\) of OLS regression over the full trace.

Line noise: Welch PSD amplitude at 50/60 Hz.


References

Spike detection and AP threshold

  • Sekerli, M., Del Negro, C. A., Lee, R. H., & Bhatt, D. L. (2004). Estimating action potential thresholds from neuronal time-series: new metrics and evaluation of methodologies. IEEE Transactions on Biomedical Engineering, 51(9), 1665-1672. doi:10.1109/TBME.2004.827827

    • Used in: §6.2 (onset detection via \(d^2V/dt^2\) maximum curvature) and §15.2 (dynamic AP threshold fallback).

  • Henze, D. A., & Buzsaki, G. (2001). Action potential threshold of hippocampal pyramidal cells in vivo is increased by recent spiking activity. Neuroscience, 105(1), 121-130. doi:10.1016/S0306-4522(01)00167-1

    • Used in: motivation for per-spike dynamic threshold (§15.2).

Patch-clamp methodology

  • Hamill, O. P., Marty, A., Neher, E., Sakmann, B., & Sigworth, F. J. (1981). Improved patch-clamp techniques for high-resolution current recording from cells and cell-free membrane patches. Pflugers Archiv, 391(2), 85-100. doi:10.1007/BF00656997

    • Used in: series-resistance measurement (§5.2, §15.1) and whole-cell capacitance estimation.

  • Neher, E., & Sakmann, B. (1976). Single-channel currents recorded from membrane of denervated frog muscle fibres. Nature, 260(5554), 799-802. doi:10.1038/260799a0

    • Foundation for whole-cell patch-clamp passive-property analysis.

Signal processing

  • Savitzky, A., & Golay, M. J. E. (1964). Smoothing and differentiation of data by simplified least squares procedures. Analytical Chemistry, 36(8), 1627-1639. doi:10.1021/ac60214a047

    • Used in: Savitzky-Golay smoothing of AHP waveforms (§6.7), dV/dt computation (§6.9, §15.2).

  • Virtanen, P., Gommers, R., Oliphant, T. E., et al. (2020). SciPy 1.0: Fundamental algorithms for scientific computing in Python. Nature Methods, 17, 261-272. doi:10.1038/s41592-019-0686-2

    • Provides scipy.optimize.curve_fit used in tau (§3), capacitance (§5.2), and PPR decay fitting (§15.5).

Spike-train statistics

  • Holt, G. R., Softky, W. R., Koch, C., & Douglas, R. J. (1996). Comparison of discharge variability in vitro and in vivo in cat visual cortex neurons. Journal of Neurophysiology, 75(5), 1806-1814. doi:10.1152/jn.1996.75.5.1806

    • Used in: CV and CV2 computation (§12).

  • Shinomoto, S., Shima, K., & Tanji, J. (2003). Differences in spiking patterns among cortical neurons. Neural Computation, 15(12), 2823-2842. doi:10.1162/089976603322518759

    • Used in: local variation (LV) metric (§12).

NWB / FAIR data

  • Rubel, O., Tritt, A., Ly, R., et al. (2022). The Neurodata Without Borders ecosystem for neurophysiological data science. eLife, 11:e78362. doi:10.7554/eLife.78362

    • Standard used for NWB export and FAIR metadata compliance.

  • Garcia, S., Guarino, D., Jaillet, F., et al. (2014). Neo: an object model for handling electrophysiology data in multiple formats. Frontiers in Neuroinformatics, 8, 10. doi:10.3389/fninf.2014.00010

    • Provides the I/O layer for all supported file formats.

15. Advanced Biophysics (Publication Audit)

15.1 Voltage-Clamp Series Resistance and True Membrane Capacitance

Classical area-under-the-curve (AUC) Cm estimation is biologically invalid without Rs compensation. The implementation uses:

Step 1 - Series Resistance (Ohm’s law at the instant of the voltage step):

\[ R_s \;[\text{MOhm}] = \frac{|\Delta V \;[\text{mV}]|}{|I_{\text{peak}} \;[\text{pA}]|} \times 10^{3} \]

where \(I_{\text{peak}}\) is the baseline-subtracted transient peak and \(\Delta V\) is the command voltage step amplitude.

Step 2 - Transient time constant (mono-exponential fit):

A mono-exponential \(I(t) = A \exp(-t / \tau)\) is fitted to the decaying phase of the transient using scipy.optimize.curve_fit. The fit starts at the transient peak and uses the last 20% of the transient window as a steady-state reference.

Step 3 - Membrane Capacitance:

\[ C_m \;[\text{pF}] = \frac{\tau \;[\text{s}]}{R_s \;[\Omega]} \times 10^{12} = \frac{\tau \;[\text{s}]}{R_s \;[\text{MOhm}] \times 10^{6}} \times 10^{12} \]

If the exponential fit fails (insufficient samples or poor convergence), the function falls back to the charge-integral (AUC) method for \(C_m\) while still reporting the Ohm’s-law \(R_s\).

15.2 Dynamic AP Threshold via Maximum Curvature (\(d^2V/dt^2\))

(Method described in Sekerli et al., 2004; dynamic threshold motivated by Henze & Buzsaki, 2001.)

A fixed dV/dt threshold fails during spike trains because Na\(^+\) channel inactivation progressively slows the AP upstroke. The physiological onset is instead defined as the point of maximum curvature of the voltage trace:

\[ \text{threshold index} = \operatorname{argmax}_{j \in \mathcal{W}} \frac{d^2V}{dt^2}(j) \]

where \(\mathcal{W}\) is a lookback window of onset_lookback seconds immediately before each spike peak. Both \(dV/dt\) and \(d^2V/dt^2\) are computed via numpy.gradient on the voltage array.

Fallback rule: if the \(d^2V/dt^2\) maximum lies at the edge of \(\mathcal{W}\) (index 0 or \(|\mathcal{W}|-1\)), the estimate is unreliable (boundary artefact). In that case the algorithm uses a dynamic per-spike threshold: the first \(dV/dt\) crossing above \(\theta_{\text{dyn}}\) within \(\mathcal{W}\), where

\[ \theta_{\text{dyn}} = \max\!\left(0.20 \cdot \max_{j \in \mathcal{W}} \frac{dV}{dt}(j),\ \ 2{,}000\,\text{mV/s}\right) \]

The 20 % fraction of the spike-specific peak rising rate captures onset consistently across spikes with attenuated upstrokes (Na\(^+\) inactivation in high-frequency trains). The 2,000 mV/s floor prevents false triggering during subthreshold depolarisations at rest. A hardcoded 20 V/s absolute threshold is not used.

15.3 Separation of Fast AHP and Medium AHP

A single AHP measurement conflates fast (\(\text{K}_V\), BK channels) and medium (\(\text{K}_{Ca}\), SK channels) dynamics. Two independent searches are made:

Metric

Window

Dominant channel

\(\text{fAHP depth}\)

1-5 ms post-peak

Na\(^+\) channel-mediated repolarisation overshoot, BK

\(\text{mAHP depth}\)

10-50 ms post-peak

SK/IK Ca\(^{2+}\)-activated K\(^+\)

\[ \text{fAHP depth} = V_{\text{threshold}} - \min_{t \in [t_{\text{peak}}+1\text{ ms},\; t_{\text{peak}}+5\text{ ms}]} V(t) \]
\[ \text{mAHP depth} = V_{\text{threshold}} - \min_{t \in [t_{\text{peak}}+10\text{ ms},\; t_{\text{peak}}+50\text{ ms}]} V(t) \]

Positive depth = hyperpolarisation relative to AP threshold.

15.4 Multi-Kernel Dendritic Tolerance in Template Matching

Cable theory predicts that synaptic currents arriving at distal dendrites appear 2-3x slower at the soma due to RC filtering. A bank of three bi-exponential kernels is generated by scaling the user-specified decay constant by fixed multipliers 1x, 2x, and 3x:

\[ k_s(t) = \exp\!\left(-t / (s \cdot \tau_{\text{decay}})\right) - \exp\!\left(-t / \tau_{\text{rise}}\right), \quad s \in \{1, 2, 3\} \]

These are not data-driven or dynamically fitted templates - the multipliers are fixed constants that approximate the somatic, proximal- dendrite, and distal-dendrite filtering regimes. Each kernel is normalised to unit peak amplitude and cross-correlated (matched- filter) with the baseline-corrected data. The three filtered traces are z-scored independently using the median absolute deviation (MAD), then combined pointwise by taking the maximum:

\[ z_{\text{combined}}(t) = \max_{s \in \{1,2,3\}} z_s(t) \]

Peak detection is then applied to \(z_{\text{combined}}\) at the user-specified threshold. This ensures that both fast somatic (narrow) and slow dendritic (broadened) events cross the detection threshold, without requiring the user to re-tune \(\tau_{\text{decay}}\) for distal inputs.

15.5 PPR Residual Fitting - Bi-Exponential Upgrade

The P1 decay tail is now first fitted with a bi-exponential model before falling back to a mono-exponential. Bi-exponential fits capture mixed conductance kinetics (e.g. AMPA fast-deactivation + NMDA slow-deactivation):

\[ I_{\text{decay}}(t) = A_f \exp\!\left(-t / \tau_f\right) + A_s \exp\!\left(-t / \tau_s\right) \]

The fitting uses scipy.optimize.curve_fit with maxfev=4000. If convergence fails (typically when fewer than 8 samples span the decay window), the implementation falls back to the mono-exponential \(A \exp(-t/\tau)\).

The reported dominant \(\tau\) for the bi-exponential case is the amplitude-weighted mean time constant:

\[ \tau_{\text{dominant}} = \frac{|A_f| \tau_f + |A_s| \tau_s}{|A_f| + |A_s|} \]

15.6 Noise Floor Detrending in Quiescent Baseline RMS

find_quiescent_baseline_rms applies scipy.signal.detrend(chunk, type="linear") to each candidate window before computing variance. This removes slow drift (electrode drift, drug wash-in ramps) from the variance estimate so that only high-frequency thermal noise is captured. Without detrending, a recording with a slowly drifting baseline can report an inflated RMS noise floor that suppresses legitimate small-amplitude events.

Sliding-window algorithm and event exclusion

The RMS noise floor is computed by advancing a window of fixed length \(w = \lfloor 50\,\text{ms} \times f_s \rfloor\) samples across the pre-event region in non-overlapping steps. For each candidate window \(\mathcal{W}_k = \{i : k \cdot w \le i < (k+1) \cdot w\}\):

  1. Preliminary event screen: the window is rejected if its peak-to-peak amplitude exceeds a detection threshold \(\theta_{\text{pp}}\) (default \(= 2 \times\) the current RMS estimate, updated iteratively). This prevents biological transients – action potential bursts, large EPSPs, stimulus artefacts – from entering the noise calculation.

  2. Local linear detrend: scipy.signal.detrend(V[\mathcal{W}_k], type="linear") removes the first-order trend \(\hat{V}_i = \beta_0 + \beta_1 t_i\) from the window, estimated via OLS on the window samples.

  3. RMS of the detrended residuals:

\[ \sigma_k = \sqrt{ \frac{1}{w} \sum_{i \in \mathcal{W}_k} \bigl(V_i - \hat{V}_i\bigr)^2 } \]
  1. The final noise floor is the median of all accepted \(\sigma_k\) values:

\[ \hat{\sigma}_{\text{noise}} = \operatorname{median}_k \sigma_k \]

Median aggregation is used rather than mean because the preliminary screen may still admit occasional windows containing the tail of a burst; the median is resistant to such outliers.

Why 50 ms windows? At typical patch-clamp sampling rates (10-50 kHz) a 50 ms window contains 500-2,500 samples – enough to robustly estimate a linear trend and its residuals while remaining short enough to stay within a quiescent inter-burst interval in most in vitro preparations.


16. Immutable Trace Correction Pipeline

Module: core/processing_pipeline.py · Function: apply_trace_corrections

To prevent math artefacts caused by order-dependent GUI interactions, all backend analysis must pass raw data through apply_trace_corrections() before feature extraction. The function enforces the following four-step sequence unconditionally:

Step A - Liquid Junction Potential (LJP) Subtraction

\[ V_{\text{true}}(t) = V_{\text{recorded}}(t) - \text{LJP} \]

The LJP arises from the electrochemical potential difference between the patch pipette solution and the bath. Correcting it is mandatory for any voltage-dependent analysis (AP threshold, RMP, I-V curve).

Biophysical limitations of post-hoc LJP subtraction. Subtracting a scalar LJP from a recorded voltage trace corrects the reported membrane potential for passive properties (RMP, \(R_{\text{in}}\), \(\tau\)). However, it does not retroactively correct the driving forces that voltage-gated channels experienced during the recording itself.

During the experiment, the actual transmembrane voltage at every time point was \(V_{\text{recorded}}(t) + V_{\text{patch}}\), where \(V_{\text{patch}}\) includes the uncorrected LJP offset. Ion channels that gate as a function of voltage (Na\(^+\), K\(^+\), Ca\(^{2+}\) channels) activated, inactivated, and determined their driving forces at these uncorrected voltages. Therefore:

  1. AP threshold and waveform are minimally affected by small LJPs (\(< 5\) mV) because the absolute voltage error is the same at every sample and threshold detection is differential. Larger LJPs (\(> 10\) mV) produce systematic errors in reported threshold and half-width.

  2. Current amplitudes and conductances computed from \(I = g(V - E_\text{rev})\) use the corrected \(V\) but the reversal potential \(E_\text{rev}\) was set relative to the uncorrected voltage during the experiment. Post-hoc LJP correction changes the apparent driving force and therefore alters any reported conductance derived from current measurements.

  3. Pharmacological and modulation studies that depend on absolute channel open probability at a specified voltage should account for the LJP when comparing across preparations or to published data.

In summary: post-hoc LJP subtraction is the accepted standard for reporting passive membrane properties in the literature, but its limitation must be acknowledged in any analysis that draws conclusions about the voltage-dependence of active conductances.

Step B - P/N Leak Subtraction

\[ I_{\text{corrected}}(t) = I_{\text{signal}}(t) - \frac{1}{K} \sum_{k=1}^{K} I_{\text{leak},k}(t) \cdot p \]

where \(K\) is the number of sub-threshold P/N repetitions and \(p = 1/N\) is the scaling factor (default \(p=1\)). This removes capacitive transients and steady-state leak currents before any further correction.

Step C - Pre-Event Noise Floor Zeroing

\[ V'(t) = V_{\text{corrected}}(t) - \operatorname{median}_{t \in \mathcal{W}_{\text{pre}}} V_{\text{corrected}}(t) \]

The median of the immediate pre-event window \(\mathcal{W}_{\text{pre}}\) is subtracted as a scalar. Because Steps A and B have already been applied, this median reflects only the residual noise floor.

Step D - Signal Filtering

Any user-requested digital filters (low-pass, notch, etc.) are applied after Steps A-C. Filtering first would smear step-transients from leak subtraction across the waveform and corrupt the P/N correction.

Immutability guarantee: regardless of the order in which the user toggles preprocessing options in the GUI, the execution order A → B → C → D is always enforced by apply_trace_corrections().


17. 5-Pillar Analyser Architecture

The Synaptipy Analyser UI is structured around exactly five primary tabs, each corresponding to a module-level aggregator entry in the AnalysisRegistry:

Pillar

Registry name

Label

Sub-analyses

1

passive_properties

Intrinsic Properties

RMP, Rin, Tau, Sag, I-V, Capacitance

2

single_spike

Spike Analysis

Spike Detection, Phase Plane

3

firing_dynamics

Excitability

Excitability, Burst Analysis, Spike Train Dynamics

4

synaptic_events

Synaptic Events

Threshold, Deconvolution, Baseline+Peak+Kinetics

5

evoked_responses

Optogenetics

Optogenetic Sync, Paired-Pulse Ratio

Leaf registrations (e.g. spike_detection, phase_plane_analysis) are covered by their parent module tab via MetadataDrivenAnalysisTab.get_covered_analysis_names() and do not appear as independent top-level tabs.

Custom plugin analyses registered by the user are appended after the five core pillars in alphabetical order.