calc
tit.calc ¶
Temporal interference field calculation utilities.
Vectorised NumPy implementations of the TI/mTI modulation-amplitude envelope from Grossman et al. (2017), extended to an arbitrary even number of electrode pairs (mTI).
Public API¶
get_TI_vectors
TI modulation-amplitude vectors for a single electrode pair (K=1).
get_mTI_vectors
Modulation-amplitude vectors for K >= 1 electrode pairs; the
verified N>2 replacement for :func:get_nTI_vectors.
get_TI_avg
Direction-averaged modulation depth for K >= 1 electrode pairs.
get_magnitude_am
Direction-free magnitude-envelope AM, K >= 1 electrode pairs.
get_nTI_vectors
Deprecated. Recursive binary-tree N-field TI; not physically valid
for N > 2. Delegates to :func:get_mTI_vectors.
Attribution¶
The K >= 2 envelope and the _fibonacci_sphere /
_validate_field_list helpers originate from collaborator Larissa
Albantakis's branch alba/mTI_testing and are ported here with
attribution, not reimplemented. get_magnitude_am is likewise ported
from that branch's _botzanowski_magnitude_am_components.
get_TI_vectors ¶
Compute the TI modulation-amplitude vectors for two electric fields.
Sign-agnostic closed form (Hirata et al. 2024), equivalent to the
original Grossman et al. (2017) preprocess-then-branch formulation but
needs no magnitude-ordering swap or acute-angle sign flip of the
inputs: TI = 2*min(|E1|,|E2|) (as a vector, sign-corrected) when
min(|E1|,|E2|) <= sqrt(|E1.E2|), else TI = 2 * that same
sign-corrected vector's component perpendicular to h, whichever of
E1-E2/E1+E2 has the smaller norm.
Parameters¶
E1_org, E2_org : np.ndarray, shape (N, 3) Electric field vectors [V/m] from the two electrode pairs.
Returns¶
np.ndarray, shape (N, 3) TI vectors [V/m]: direction/magnitude of max envelope modulation.
References¶
Grossman, N. et al. (2017). Cell, 169(6), 1029-1041. Hirata, A. et al. (2024). Computers in Biology and Medicine, 178, 108697.
Source code in tit/calc.py
get_mTI_vectors ¶
Compute mTI modulation-amplitude vectors for K >= 1 electrode pairs.
fields is [E_1a, E_1b, ..., E_Ka, E_Kb], 2K arrays of shape
(N, 3), paired positionally into K channels by default. Pass
channels to override the grouping -- e.g. many electrode pairs
sharing just two carriers (Lee et al. 2022) becomes one channel of
summed fields. K=1 dispatches exactly to :func:get_TI_vectors; K>=2
returns best_direction * md from the verified
:func:_mti_modulation_depth envelope. hf_peak/hf_sar
(:mod:tit.fields) are unaffected by channels: they always sum
over every carrier field.
Parameters¶
fields : list of np.ndarray, each shape (N, 3)
Carrier field vectors, referenced by index from channels.
channels : sequence of (group_a, group_b), or None
Per-channel index groups into fields (see
:func:_resolve_channels); None is consecutive pairing,
identical to today's behaviour.
psi : array-like, shape (K,), or None
Per-pair envelope phase offset (radians); None means
phase-aligned pairs (psi_k=0), the standard case. Ignored
at K=1 (phase-invariant there).
Returns¶
np.ndarray, shape (N, 3) Modulation-amplitude vectors [V/m]; norm is the modulation depth.
Raises¶
ValueError
Invalid fields, channels, or psi; see
:func:_resolve_channels and :func:_validate_psi.
References¶
Grossman, N. et al. (2017). Cell, 169(6), 1029-1041 (K=1 closed form).
Source code in tit/calc.py
get_TI_avg ¶
Direction-averaged modulation depth for K >= 1 electrode pairs.
TI_max (:func:get_mTI_vectors) maximizes the envelope over
direction -- a best case for a neuron aligned with the optimal axis.
TI_avg instead averages the same coarse Fibonacci-sphere sweep
over all sampled directions, giving what a randomly-oriented neuron
sees on average. Local refinement (accurate for a single best
direction only) is skipped as irrelevant to an average.
Parameters¶
fields : list of np.ndarray, each shape (N, 3)
Carrier field vectors, referenced by index from channels.
channels : sequence of (group_a, group_b), or None
Per-channel index groups into fields; see
:func:get_mTI_vectors and :func:_resolve_channels.
psi : array-like, shape (K,), or None
Per-pair envelope phase offset (radians); see
:func:get_mTI_vectors.
Returns¶
np.ndarray, shape (N,) Modulation depth [V/m], averaged over sampled directions.
Source code in tit/calc.py
get_magnitude_am ¶
Direction-free amplitude-modulation envelope of ||E(t)||.
Not the direction-maximized modulation depth from
:func:get_mTI_vectors -- the AM envelope of the field magnitude
itself, no direction search, computed on the full 3-vectors:
P = 0.5*sum_i ||E_i||^2, Q = |sum_k E_ka . E_kb| (3D dot
products per pair), result = sqrt(2*(P+Q)) - sqrt(2*max(P-Q, 0)).
At K=1 this reduces to abs(|E1+E2| - |E1-E2|).
Parameters¶
fields : list of np.ndarray, each shape (N, 3) Field vectors for 2K sub-channels (K electrode pairs), K >= 1.
Returns¶
np.ndarray, shape (N,) Magnitude-AM envelope [V/m].
See Also¶
get_mTI_vectors : Direction-maximized modulation-amplitude vectors -- a different quantity from this magnitude envelope.
References¶
Botzanowski, B. et al. (2025). Bioelectronic Medicine, 11(1), 7.
Source code in tit/calc.py
get_nTI_vectors ¶
Deprecated: recursive binary-tree N-field TI. Use :func:get_mTI_vectors.
This paired fields via TI(TI(E1,E2), TI(E3,E4), ...), feeding
already-modulated envelope vectors back into :func:get_TI_vectors --
a formula derived only for two carrier fields. Measured against the
verified :func:_mti_modulation_depth envelope on random fields: signed
mean error +38.6% (range -90% to +416%) at N=4, +103% at N=8.
Parameters¶
fields : list of np.ndarray, each shape (N, 3)
Returns¶
np.ndarray, shape (N, 3)