Signal Processing¶
Lightweight 1D signal-processing helpers used by the FFT / smoothing workflows:
apodization windows, FFT zero-fill sizing, echo-centre detection, and a small
Signal_Processing class for smoothing, baseline subtraction, and
normalization. Every routine takes and returns plain NumPy arrays.
The module-level functions (apodization_window,
zerofill_length, echo_center) are called
directly; the smoothing / baseline / normalization helpers live on the
Signal_Processing class.
Note
savitzky_golay() requires scipy (the math extra:
pip install -e .[math]); everything else is NumPy-only.
apodization_window()¶
Returns an apodization window of length n to multiply onto a time-domain
signal before an FFT. name is one of:
'None', 'Hann', 'Hamming', 'Blackman', 'Bartlett', 'Flat-top',
'Kaiser', 'Gaussian', 'Tukey'.
param is the shape parameter for the three parametric windows and is ignored
by the rest:
| Window | param meaning |
Typical |
|---|---|---|
Kaiser |
β | 8.6 |
Gaussian |
σ as a fraction of n |
0.15 |
Tukey |
α taper fraction (0 → rectangular, 1 → Hann) |
0.5 |
zerofill_length()¶
Target FFT length for a zero-fill choice: 'None' (returns length),
'×2' / '×4' / '×8' (or the ASCII 'x2'…), or 'Next pow₂' (the smallest
power of two ≥ length). Feed the result to numpy.fft.fft(signal, n).
n = sigproc.zerofill_length(len(signal), '×4')
spectrum = np.fft.fft(signal, n)
freq = np.fft.fftfreq(n, dt)
echo_center()¶
Returns the index of the echo centre in a 1D magnitude envelope. Pass an
offset-invariant envelope such as sqrt(I**2 + Q**2) so the carrier modulation
from a field/frequency offset has already cancelled and only the echo shape
remains — then the centre is the envelope peak, refined by a local
centre-of-mass and rounded to the nearest sample.
window is the half-width (in points) of the centre-of-mass window around the
peak. With window <= 0 (default) it is sized automatically from the crest
width: walk out from the peak until the envelope drops below 70 % of the peak
height, then take the narrower of the two sides. Measuring from the crest
(rather than a baseline-relative half-maximum) keeps the result on the peak even
when the pre-echo baseline is elevated — there a half-maximum can sit at the
baseline level, the window blows up, and a slow FID decay drags the
centre-of-mass far past the true peak. A positive window forces that exact
half-width.
This is used to start an FFT "from the centre of the echo": find k, drop the
first k points, and the dead-time first-order phase ramp disappears.
Signal_Processing()¶
Creates the helper object exposing the methods below.
savitzky_golay()¶
Savitzky–Golay smoothing (requires scipy). window must be odd and greater
than order; it is auto-corrected (forced odd, clamped to the data length) if
not. Raises RuntimeError when scipy is missing.
moving_average()¶
Centred moving-average smoothing; edges are padded by reflection so the output
has the same length as y. NumPy-only.
baseline_poly()¶
Fits a polynomial of the given order and subtracts it from the full curve.
region selects which points the polynomial is fitted to, so the baseline can
be estimated from signal-free regions (e.g. the trace tails):
region |
Points used for the fit |
|---|---|
'all' |
every point (default) |
'first' |
the first npts points |
'last' |
the last npts points |
'ends' |
the first and last npts points |
npts is ignored when region='all' (or when it would select the whole
curve).
# remove a linear baseline estimated from the first and last 50 points
y_corr = sp.baseline_poly(x, y, order=1, region='ends', npts=50)
normalize()¶
Normalizes y. mode:
mode |
Result |
|---|---|
'minmax' |
rescaled to [0, 1] |
'max' |
divided by max(|y|) |
'area' |
divided by its absolute area (unit area) |