Skip to content

Choose a detrending method

Detrending removes a slow background from a trace before period estimation. Think of it as levelling a sloping table before measuring the height of the objects on it: the correction should remove the slope without shaving down the objects.

Use the least invasive method that reveals the oscillation, inspect the raw, baseline, and detrended traces together, and keep none when drift does not move the answer. The registered action names this choice detrend_method; the friendly Python method calls it method.

What the methods do

Six commonly used detrending methods applied to the same deterministic trace

The grey trace is the centred input, orange is the estimated baseline, and teal is the output. The missing interval is never converted to zero. The figure is generated by the package's real detrending implementation; its audited private bundle retains the exact plotted values and standalone producer.

Method Use it when Main controls Important consequence
none Drift is negligible or does not change the period none Preserves the source exactly.
linear The baseline is approximately a straight ramp none Ordinary least squares can be pulled by isolated outliers.
robust_linear (huber, robust) The baseline is a ramp with occasional outliers none Fits one Huber-weighted line; it cannot follow curvature.
first_difference (diff, difference) A step-to-step change series is scientifically intended none Returns x[t] - x[t-1]; changes amplitude and phase response and loses the first sample.
running_mean (moving_average) A centred, easily interpreted local baseline is wanted window_hours, min_valid_fraction Drops half a window at each edge; a 24-hour window largely preserves a 24-hour sinusoid.
moving_median (median, running_median) Short spikes should not pull the local baseline window_hours, min_valid_fraction Drops half a window at each edge and can make the baseline step-like.
kernel (baseline) Matching BioDare2 Gaussian-baseline detrending window_hours, bandwidth_hours, min_valid_fraction Drops half a window at each edge and can absorb rhythmic amplitude.
lowess (loess) The baseline is smooth and curved without a useful global equation window_hours or lowess_fraction; lowess_iterations Local linear fits can follow the rhythm if their neighbourhood is too short.
savitzky_golay (savgol) A smooth local-polynomial baseline should retain broad shape window_hours, polynomial_degree Edge values are locally extrapolated; gaps are used only as internal fit interpolation and remain missing in output.
polynomial (cubic, poly3, poly6) One global polynomial describes the drift polynomial_degree High degrees can oscillate at the edges; named aliases force their stated degree.
amp_baseline (amp&baseline) Both baseline drift and progressive amplitude damping must be removed window_hours, bandwidth_hours, min_valid_fraction Rescales amplitude and has strong edge artefacts.
asymmetric_least_squares (asls, als) Positive peaks sit above a smooth lower envelope asls_smoothness, asls_asymmetry, asls_iterations One-sided by design; do not treat it as a neutral baseline for a symmetric waveform.
frequency Components slower than a declared cut-off should be removed low_cut_hours, high_cut_hours, filter_order Changes waveform shape and has filter transients near both ends.

Run one method

import circadian_workbench as cw

trace = cw.open("mouse01.awd")
result = trace.detrend(method="lowess", window_hours=72)

result.show()

The direct action accepts file, inline, demo, and array-backed recording inputs:

cw.call(
    "detrend",
    recording={"path": "mouse01.awd"},
    detrend_method="asymmetric_least_squares",
    asls_smoothness=1_000_000,
    asls_asymmetry=0.01,
    asls_iterations=10,
)

Controls shared by several methods

Parameter Default Meaning
window_hours 24.0 Biological duration of a centred local window. For LOWESS, it determines the sample fraction when lowess_fraction is omitted.
polynomial_degree 3 Global polynomial degree, or the local degree for Savitzky–Golay.
min_valid_fraction 0.5 Minimum finite share required in running, median, and kernel windows.
bandwidth_hours null Gaussian standard deviation for kernel methods; null uses one quarter of window_hours.
low_cut_hours 45.0 Longest period retained by frequency filtering.
high_cut_hours 4.0 Shortest period retained by frequency filtering.
filter_order 2 Butterworth filter order before forward-and-reverse application.
lowess_fraction null Fraction of finite samples used by each LOWESS fit; null derives it from window_hours.
lowess_iterations 3 Robust residual-reweighting passes after the initial LOWESS fit; 0 disables them.
asls_smoothness 1000000.0 Curvature penalty for asymmetric least squares; larger makes a smoother baseline.
asls_asymmetry 0.01 Weight for points above the asymmetric baseline; smaller values exclude positive peaks more strongly.
asls_iterations 10 Asymmetric reweighting passes, from 1 to 100.
smooth_window_hours 0.0 Optional centred smoothing after detrending; zero disables it.
exclude_hours null Optional leading duration excluded before the damping fit.

The complete action reference also documents recording, config, accepted types, units, and returned fields: detrend action.

Use a detrender during period estimation

Set period_detrend to any method or alias above. Every requested period estimator then receives the same detrended series.

period = cw.open(
    "mouse01.awd",
    settings={
        "period_detrend": "moving_median",
        "period_detrend_window_hours": 48,
    },
).period(method="lomb")

The corresponding period_detrend_* settings are listed in the complete configuration reference.

Choosing safely

  1. Run none first and record whether drift actually changes the period.
  2. Start with linear for a ramp or running_mean for a slow local background.
  3. Use robust linear or moving median when isolated spikes dominate the fit.
  4. Use LOWESS or Savitzky–Golay only with a neighbourhood longer than the feature you need to retain.
  5. Reserve first differences and asymmetric least squares for questions whose data-generating assumptions match those transformations.
  6. Compare the raw and detrended spectra; a new peak created only by one aggressive detrender is not evidence of a biological rhythm.

Detrending does not establish rhythmicity. Pair a period estimate with a method that supplies a significance test, such as the Lomb–Scargle false-alarm probability.