cycleTrendR provides a unified framework for trend estimation, cycle detection, spectral analysis, bootstrap confidence intervals, and change-point detection across any type of time series.
Version 0.3.0 introduces a major enhancement:
full support for multiple time formats through the argument dates_type;
a universal internal time index (timenum);
automatic switching between STL, Lomb–Scargle, Fourier, LOESS, GAM, and GAMM;
compatibility with daily, sub-daily, and numeric time series.
This vignette demonstrates how to use cycleTrendR in three real-world scenarios:
Daily data (Date)
Wearable / PhysioNet data (POSIXct)
Neuroscience / spike trains (numeric time)
adaptive_cycle_trend_analysis() accepts three types of temporal indexing:
| dates_type | Input class | Typical use case |
|---|---|---|
| “date” | Date | Epidemiology, climate, economics |
| “posix” | POSIXct | Wearable sensors, HR, EDA, EEG |
| “numeric” | numeric | Spike trains, firing rate, … |
The function automatically adapts:
STL only for “date”
Lomb–Scargle for “posix” and “numeric”
Fourier harmonics in time units of timenum
Trend estimation via LOESS, GAM, or GAMM
Change-points in the same scale as the input time
set.seed(1)
dates <- as.Date("2020-01-01") + 1:200
signal <- sin(2*pi*(1:200)/30) + rnorm(200, 0, 0.2)
res_date <- adaptive_cycle_trend_analysis(
signal = signal,
dates = dates,
dates_type = "date",
trendmethod = "loess",
usefourier = TRUE
)
#> Using original scale.
#> Regular time index: STL (if dates_type='date') + LOESS/GAM(M)#> Auto seasonality: dominant period approx 28.57 samples -> seasonalfrequency=29
#> loess.as proposed span (criterion=aicc) = 0.945
#> Fourier selection: criterion=AICc -> K=1 (from 0..6)
#> Warning in adaptive_cycle_trend_analysis(signal = signal, dates = dates, :
#> Model-based CI not implemented for this configuration; switching to
#> bootstrapiid.
#> Bootstrap CI (bootstrapiid): 1000 resamples
#> Warning in tseries::adf.test(signal, alternative = "stationary"): p-value
#> smaller than printed p-value
#> Warning in tseries::kpss.test(signal, null = "Level"): p-value greater than
#> printed p-value
This example illustrates:
STL decomposition
automatic seasonality detection
Fourier harmonics
LOESS trend
model-based or bootstrap CI
# Example: synthetic POSIXct HR-like signal
t <- as.POSIXct("2020-01-01 00:00:00") + seq(0, by = 60, length.out = 1000)
hr <- 70 + 5*sin(2*pi*(1:1000)/200) + rnorm(1000, 0, 1)
res_posix <- adaptive_cycle_trend_analysis(
signal = hr,
dates = t,
dates_type = "posix",
trendmethod = "gam",
usefourier = TRUE
)
#> Using original scale.
#> Regular time index: STL (if dates_type='date') + LOESS/GAM(M)
#> No STL/seasonality for dates_type != 'date'.
#> Fourier selection: criterion=AICc -> K=5 (from 0..6)
#> Warning in adaptive_cycle_trend_analysis(signal = hr, dates = t, dates_type =
#> "posix", : Model-based CI not implemented for this configuration; switching to
#> bootstrapiid.
#> Bootstrap CI (bootstrapiid): 1000 resamples
res_posix$Plot$TrendKey features:
Lomb–Scargle periodogram
GAM or GAMM trend
Fourier in seconds
change-points in POSIXct
robust CI
This is the recommended workflow for:
PhysioNet HR
PhysioNet EDA
accelerometry
EEG timestamps
time <- seq(0, 10, length.out = 2000)
spike_rate <- sin(2*pi*time*5) + rnorm(2000, 0, 0.2)
res_num <- adaptive_cycle_trend_analysis(
signal = spike_rate,
dates = time,
dates_type = "numeric",
trendmethod = "loess",
usefourier = TRUE
)
#> Using original scale.
#> Regular time index: STL (if dates_type='date') + LOESS/GAM(M)
#> No STL/seasonality for dates_type != 'date'.
#> loess.as proposed span (criterion=aicc) = 0.949
#> Fourier selection: criterion=AICc -> K=3 (from 0..6)
#> Warning in adaptive_cycle_trend_analysis(signal = spike_rate, dates = time, :
#> Model-based CI not implemented for this configuration; switching to
#> bootstrapiid.
#> Bootstrap CI (bootstrapiid): 1000 resamples
#> Warning in tseries::adf.test(signal, alternative = "stationary"): p-value
#> smaller than printed p-value
#> Warning in tseries::kpss.test(signal, null = "Level"): p-value greater than
#> printed p-value
res_num$Plot$TrendThis workflow is ideal for:
spike trains
firing rate
LFP power
simulated time series
any non-calendar time axis
Use “date” when the time axis is calendar-based
Use “posix” for sub-daily physiological signals
Use “numeric” for experimental or simulated time
Prefer GAM/GAMM for long or noisy signals
Use Fourier only when a dominant period is meaningful
Use bootstrap CI when residuals show autocorrelation