suboptimumg.loganalysis.filtering#

FFT plotting and digital lowpass filtering utilities.

suboptimumg.loganalysis.filtering.lowpass_filter(dfs, columns, cutoff_hz, time_col='time_s', order=4)[source]#

Apply a Butterworth lowpass filter to one or more columns.

On first call for a given column the current data is saved to <col>_pre_lp. Subsequent calls always filter from <col>_pre_lp so that re-filtering at a different cutoff does not stack, while still preserving any upstream filtering (e.g. zscore_filter) that was applied before this function.

A <col>_original backup is also created on the very first filter call (zscore or lowpass) to allow full reset via undo_filters().

Parameters:
  • dfs (DataFrame or list[DataFrame]) – Accepts a single DataFrame or a list; applies to all.

  • columns (str or list[str]) – Column name(s) to filter.

  • cutoff_hz (float) – Cutoff frequency in Hz.

  • time_col (str) – Time column to derive sampling frequency from.

  • order (int) – Butterworth filter order (applied forward-backward, so effective order is 2x).

Returns:

  • Same type as *dfs, with filtered columns overwritten and*

  • _pre_lp backups created on first filter.

Return type:

DataFrame | list[DataFrame]

suboptimumg.loganalysis.filtering.lowpass_filter_by_distance(dfs, columns, cutoff_freq_per_meter, distance_col='distance', order=4)[source]#

Apply a Butterworth lowpass in the spatial domain (1/m).

Same semantics as lowpass_filter() but the sample rate is derived from a distance column instead of time.

Parameters:
  • dfs (DataFrame or list[DataFrame])

  • columns (str or list[str])

  • cutoff_freq_per_meter (float) – Cutoff in cycles per meter (1/m).

  • distance_col (str)

  • order (int)

Return type:

Same type as dfs.

suboptimumg.loganalysis.filtering.plot_fft(df, columns, domain='time', time_col='time_s', distance_col='distance', stacked=True, cutoff=None, log_x=True, log_y=False, xlim=None)[source]#

Plot FFT magnitude spectrum of one or more columns.

Parameters:
  • df (pd.DataFrame)

  • columns (str or list[str])

  • domain (str) – "time" or "distance".

  • time_col (str)

  • distance_col (str)

  • stacked (bool) – True -> one subplot per column; False -> all on one plot.

  • cutoff (float or None) – If given, draw a vertical dashed line at this frequency.

  • log_x (bool) – Logarithmic x-axis.

  • log_y (bool) – Logarithmic y-axis.

  • xlim ((start, end) or None) – Restrict the FFT to a subdomain of the x-axis (time in seconds or distance in meters, depending on domain). None uses the full range.

Return type:

go.Figure

Note

No max_display_hz downsampling is applied here — the FFT output is already in the frequency domain and thinning would corrupt the spectrum shape.

suboptimumg.loganalysis.filtering.undo_filters(df, columns)[source]#

Restore columns to their original (pre-filter) state.

Copies data back from <col>_original and removes all backup columns (_original, _pre_lp, _raw).

Parameters:
  • df (pd.DataFrame)

  • columns (str or list[str]) – Column name(s) to restore.

Returns:

The same DataFrame, modified in-place and returned.

Return type:

pd.DataFrame

suboptimumg.loganalysis.filtering.zscore_filter(dfs, columns, window_s=2.0, threshold=4.8, time_col='time_s')[source]#

Mask outliers using a rolling-window z-score.

For each sample, a z-score is computed relative to the local rolling mean and standard deviation. Samples exceeding threshold are replaced with NaN and linearly interpolated.

Always re-filters from <col>_original (the true intake data) so that re-running with different parameters does not stack. If a <col>_pre_lp backup exists (lowpass was already applied), it is updated to the new zscore output so subsequent lowpass calls chain correctly.

Parameters:
  • dfs (DataFrame or list[DataFrame])

  • columns (str or list[str]) – Column name(s) to filter.

  • window_s (float) – Rolling window size in seconds.

  • threshold (float) – Z-score threshold – samples with |z| > threshold are masked.

  • time_col (str) – Time column used to convert window_s to a sample count.

Returns:

  • Same type as *dfs, with outliers masked to NaN and*

  • _original backups created on first call.

Return type:

DataFrame | list[DataFrame]