Source code for suboptimumg.log_analysis.utils
import numpy as np
import numpy.typing as npt
[docs]
def safe_gradient(
signal: npt.NDArray[np.float64], dt: npt.NDArray[np.float64]
) -> npt.NDArray[np.float64]:
"""Compute a time derivative that is robust to zero-width time steps,
so that duplicate timestamps do not produce inf or NaN values.
Parameters
----------
signal : npt.NDArray[np.float64]
The signal to differentiate.
dt : npt.NDArray[np.float64]
Time step array. Must be the same length as ``signal``.
Returns
-------
npt.NDArray[np.float64]
``d(signal)/dt`` with NaNs from zero-width steps filled by
linear interpolation between the nearest valid neighbours.
"""
# Compute the raw gradient, masking out any points where dt == 0
# to avoid division-by-zero producing inf or incorrect values.
result = np.full_like(signal, np.nan)
mask = dt != 0
result[mask] = np.gradient(signal[mask]) / dt[mask]
nans = np.isnan(result)
if nans.any():
# Fill masked positions by linearly interpolating from valid neighbours.
idx = np.arange(len(result))
result[nans] = np.interp(idx[nans], idx[~nans], result[~nans])
return result