| Title: | Actigraphy Data Parsing and Analysis for R |
|---|---|
| Description: | Provides tools for importing, parsing, and analysing raw actigraphy data from wrist-worn devices. Implements a full sleep analysis pipeline — off-wrist detection, main sleep period detection, nap detection, and WASO computation — validated epoch-for-epoch against the Condor circadiaBase Python reference pipeline using ActTrust hardware. Also computes standard non-parametric circadian rhythm variables (interdaily stability, intradaily variability, relative amplitude, L5, M10). Device-specific parameter presets can be swapped to adapt the pipeline to other actigraph models. Designed to complement slumbR in the Circadia Lab ecosystem. |
| Authors: | Lucas França [aut, cre] (ORCID: <https://orcid.org/0000-0003-0853-1319>), Mario Leocadio-Miguel [aut] (ORCID: <https://orcid.org/0000-0002-7248-3529>), Julia Ribeiro da Silva Vallim [aut] (ORCID: <https://orcid.org/0000-0001-8708-8479>) |
| Maintainer: | Lucas França <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.6 |
| Built: | 2026-07-16 12:50:39 UTC |
| Source: | https://github.com/circadia-bio/zeitR |
Returns a named character vector of hex colours keyed on the four state
labels produced by label_states(). Pass the output to the colours
argument of any actogram function to override individual colours.
actogram_colours()actogram_colours()
Named character vector with elements "wake", "sleep", "nap",
and "off-wrist".
actogram_colours() # wake sleep nap off-wrist # "#C25E2A" "#3B2F6B" "#F0A500" "#D9C8A0"actogram_colours() # wake sleep nap off-wrist # "#C25E2A" "#3B2F6B" "#F0A500" "#D9C8A0"
Returns a named list of all device- and study-specific parameter values used
by the zeitR pipeline when processing ActTrust recordings. Passing this list
(or a modified copy) to run_pipeline() via the params argument fully
controls which values each detector stage receives, without having to touch
the individual function calls.
acttrust_params()acttrust_params()
The list is organised into four named sections that map directly to the four pipeline stages:
offwristParameters for detect_offwrist_bimodal(). These values
were validated against the Condor circadiaBase pipeline using ActTrust
hardware. The refinement stage (.bimodal_refine_acttrust) is
device-specific and currently only validated for ActTrust.
sleepParameters for detect_sleep_crespo(). sleep_quantile
(0.365) is the ActTrust CSPD wrapper value; the original Crespo (2012)
algorithm uses 1/3.
napParameters for detect_naps_crespo(), passed as the params
argument. Equivalent to .cspd_nap_params().
wasoParameters for compute_waso().
To adapt the pipeline for a different device, copy the list, modify the
relevant values, and pass it to run_pipeline():
p <- acttrust_params()
p$sleep$sleep_quantile <- 1/3 # use the original Crespo threshold
result <- run_pipeline("recording.txt", params = p)
A named list with elements offwrist, sleep, nap, and waso.
run_pipeline() for the pipeline entry point.
Scans a recording tibble for three classes of timestamp problem:
check_consistency(x, gap_s = 120, datetime_col = "datetime")check_consistency(x, gap_s = 120, datetime_col = "datetime")
x |
A tibble as returned by |
gap_s |
|
datetime_col |
|
Gaps — intervals between consecutive epochs longer than gap_s
seconds.
Backward jumps — timestamps that go backwards in time.
Year artefacts — timestamps in the years 1970 or 2000, which typically indicate firmware epoch-counter rollover bugs.
A tibble with one row per detected issue and columns:
rowinteger — row index in x where the issue occurs.
datetimePOSIXct — timestamp at that row.
issuecharacter — one of "gap", "backward_jump", or
"year_artefact".
detailcharacter — human-readable description.
Returns a zero-row tibble if no issues are found.
## Not run: rec <- read_acttrust("recordings/P001.txt") issues <- check_consistency(rec) issues ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") issues <- check_consistency(rec) issues ## End(Not run)
Computes the mean of times on the 0-24 h clock using the unit-circle
method: convert each time to a unit-vector angle, average the sin and
cos components, and back-project via atan2. This correctly handles
midnight wrap (e.g. times at 23:30 and 00:30 average to 00:00, not 12:00).
circ_mean_h(x)circ_mean_h(x)
x |
|
The older threshold approach (shift values >= 12 h by -24 h before averaging) produces badly biased estimates when times straddle noon – critically for sleep offset in late sleepers – and is superseded by this function (Fix 20 in the JRSV pipeline, ICC for sleep offset 0.502 -> 0.897 on N=404).
A single numeric in [0, 24), or NA_real_ if x is empty
after NA removal.
Pewsey, A., Neuhauser, M., & Ruxton, G. D. (2013). Circular Statistics in R. Oxford University Press.
circ_mean_h(c(23.5, 0.5)) # midnight wrap -> 0 circ_mean_h(c(23.0, 1.0)) # -> 0 circ_mean_h(c(7.0, 9.0)) # -> 8circ_mean_h(c(23.5, 0.5)) # midnight wrap -> 0 circ_mean_h(c(23.0, 1.0)) # -> 0 circ_mean_h(c(7.0, 9.0)) # -> 8
Computes the circular SD using the mean resultant length formula:
sqrt(-2 * log(R_bar)) * 24 / (2*pi), where R_bar is the mean
resultant length of the unit-circle representation of the times.
Linear SD inflates when times straddle midnight; this measure is
invariant to the wrap point (Fix 24 in the JRSV pipeline).
circ_sd_h(x)circ_sd_h(x)
x |
|
A single non-negative numeric (hours), or NA_real_.
Mardia, K. V., & Jupp, P. E. (2000). Directional Statistics (2nd ed.). Wiley.
circ_sd_h(c(23.5, 0.5)) # small SD for times close to midnight circ_sd_h(c(6.0, 18.0)) # large SD for times 12 h apartcirc_sd_h(c(23.5, 0.5)) # small SD for times close to midnight circ_sd_h(c(6.0, 18.0)) # large SD for times 12 h apart
Convenience wrapper combining estimate_ee() and classify_pa_intensity()
in one call: converts raw ActTrust(R)/GT3X+ activity counts straight to a PA
intensity factor via the published "batista2026" (or future) equation
set, without needing to handle the intermediate MET values.
classify_pa_counts( counts, device = c("ACTT", "GT3X+"), placement = c("hip", "wrist"), equation_set = "batista2026" )classify_pa_counts( counts, device = c("ACTT", "GT3X+"), placement = c("hip", "wrist"), equation_set = "batista2026" )
counts |
Numeric vector of activity counts (counts/min, over the same
epoch length used by the source equation set – 1-minute for
|
device |
|
placement |
|
equation_set |
|
An ordered factor, same length as counts and same levels as
classify_pa_intensity().
estimate_ee(), classify_pa_intensity(), pa_equations() for
the coefficients and their generalisability caveats.
classify_pa_counts(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip")classify_pa_counts(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip")
Bins metabolic equivalent (MET) values into the four PA intensity classes used throughout Batista et al. (2026) and consistent with WHO PA intensity conventions: light, moderate, vigorous, very vigorous.
classify_pa_intensity(mets)classify_pa_intensity(mets)
mets |
Numeric vector of MET values, e.g. from |
An ordered factor with levels c("light", "moderate", "vigorous", "very_vigorous"), same length as mets. Bands: [0,3) light,
[3,6) moderate, [6,9) vigorous, [9,Inf) very vigorous.
mets <- estimate_ee(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip") classify_pa_intensity(mets)mets <- estimate_ee(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip") classify_pa_intensity(mets)
Applies the JRSV classification rule set to a raw episode table from
extract_sleep_episodes(), assigning each episode a sleep_type of
"main" or "secondary". The execution order follows Fix 27:
classify_sleep_episodes( episodes, data, max_tib_h = 16, max_main_tib_h = 14, min_main_tib_h = 4, nocturnal_onset_start = 18, nocturnal_onset_end = 6, temp_thresh = 28, light_thresh_window = 5, light_thresh_recovery = 10, min_fragment_tib_h = 1, rolling_window_min = 15L, max_split_iterations = 3L, collision_gap_h = 4, verbose = FALSE )classify_sleep_episodes( episodes, data, max_tib_h = 16, max_main_tib_h = 14, min_main_tib_h = 4, nocturnal_onset_start = 18, nocturnal_onset_end = 6, temp_thresh = 28, light_thresh_window = 5, light_thresh_recovery = 10, min_fragment_tib_h = 1, rolling_window_min = 15L, max_split_iterations = 3L, collision_gap_h = 4, verbose = FALSE )
episodes |
A tibble as returned by |
data |
A tibble as returned by |
max_tib_h |
|
max_main_tib_h |
|
min_main_tib_h |
|
nocturnal_onset_start |
|
nocturnal_onset_end |
|
temp_thresh |
|
light_thresh_window |
|
light_thresh_recovery |
|
min_fragment_tib_h |
|
rolling_window_min |
|
max_split_iterations |
|
collision_gap_h |
|
verbose |
|
Fix 25 – exclude truncated episodes at the recording end.
Fix 26a – infer adaptive nocturnal window from int_temp
and light. Falls back to nocturnal_onset_start/nocturnal_onset_end
if fewer than 2 candidate episodes pass the temperature and light filter.
Fix 29 / Rule 1 – split TBT 14–16 h episodes at their
activity peak (recursive, up to max_split_iterations). Fragments still
exceeding max_main_tib_h after splitting are excluded.
Rule 2 – exclude episodes with TBT > max_tib_h (16 h)
directly, without attempting a split.
Fix 26c – recover sleep nights missed by the scorer for dates
with no classified main episode. Sleep and wake within the candidate
window are determined by Cole-Kripke epoch scoring on ZCMn (not the
period-level CSPD state). Adjacent sleep runs are merged when the
intervening gap has wrist temperature >= temp_thresh and ambient
light <= light_thresh_recovery.
Rules 3–5 – classify each episode as "main" or
"secondary" using the nocturnal window and min_main_tib_h.
Fix 26b – resolve sleep-date collisions: when two main
episodes share a noon-threshold sleep date and are separated by
>= collision_gap_h hours, reassign the later one to the next calendar date.
Rule 6 – keep the longest main episode per sleep date;
demote all others to "secondary".
Rule 7 – exclude all episodes (main and secondary) on dates that have no valid main sleep after Rule 6.
A tibble with the same columns as episodes plus sleep_type
("main" or "secondary") and is_nap (logical, TRUE when
sleep_type == "secondary", for backwards compatibility with the
zeitr_result$nights schema).
extract_sleep_episodes(), run_pipeline_native()
Reproduces the general wrist-actigraph processing chain – per-axis
DC removal and band-pass filter, vector norm, epoch-level integration –
that converts raw acceleration samples into the epoch-level activity
metrics used throughout the rest of zeitR (e.g. read_acttrust()'s
activity/ZCMn columns) and the wider PA-intensity literature (see
pa_equations()).
compute_activity_counts( x, y, z, sampling_rate, epoch_sec = 60, filter_low = 0.5, filter_high = 2.7, zcm_threshold = 0.01, tat_threshold = 0.05, metrics = c("PIM", "TAT", "ZCM") )compute_activity_counts( x, y, z, sampling_rate, epoch_sec = 60, filter_low = 0.5, filter_high = 2.7, zcm_threshold = 0.01, tat_threshold = 0.05, metrics = c("PIM", "TAT", "ZCM") )
x, y, z
|
Numeric vectors of raw triaxial acceleration samples (same
units – typically g – and length, uniformly sampled at
|
sampling_rate |
|
epoch_sec |
|
filter_low, filter_high
|
|
zcm_threshold |
|
tat_threshold |
|
metrics |
|
A tibble with one row per epoch: epoch (integer index, 1-based)
plus one column per requested metric.
Filtering reuses mrpheus::remove_dc() and mrpheus::bandpass_filter()
– the same zero-phase Butterworth implementation already validated as
part of mrpheus's YASA-parity PSG pipeline – rather than a new,
unvalidated filter written from scratch. This makes mrpheus a required
package for this function specifically (a Suggests dependency of
zeitR, checked at runtime; the rest of zeitR does not need it).
Reusing a validated filter primitive does not make the whole function
validated, though: the PIM/TAT/ZCM epoch-aggregation logic below (what
happens after filtering) is still an original implementation with
nothing to check it against – no raw-to-counts converter exists to
compare it to, and Condor's/ActiGraph's exact onboard threshold constants
are proprietary and unpublished. Built from the general processing
description in Batista et al. (2026, PLoS ONE) and standard actigraphy
literature. Treat its output as a reasonable approximation of
device-computed counts, not a validated reproduction – and prefer
device-computed counts (read_acttrust()) over this function whenever
they're available.
Each of x, y, z has its DC offset removed
(mrpheus::remove_dc()) – important for the z-axis in particular,
which typically carries a ~1 g gravity offset – then is independently
band-pass filtered with a zero-phase (mrpheus::bandpass_filter())
Butterworth filter (filter_low-filter_high Hz).
A vector norm is computed per sample: sqrt(x^2 + y^2 + z^2) on the
filtered axes, matching the order described for ActTrust in Batista
et al. (2026): filter first, then combine axes.
Samples are grouped into non-overlapping epochs of
epoch_sec * sampling_rate samples. Trailing samples that don't fill
a complete final epoch are dropped, with a warning.
Per epoch:
PIM (proportional integration mode) – sum of the absolute filtered norm across the epoch.
TAT (time above threshold) – seconds within the epoch where the
absolute filtered norm exceeds tat_threshold.
ZCM (zero crossing mode) – number of sign changes beyond a
zcm_threshold dead-band, summed across the three filtered axes,
within the epoch.
zcm_threshold and tat_threshold have no published reference value –
they are exposed as tunable parameters rather than given a false-precision
default. The values shipped here are small, physically motivated starting
points (see Arguments), not calibrated constants.
pa_equations(), estimate_ee(), classify_pa_counts() to go
from PIM counts to METs and PA intensity bands; read_acttrust() for
device-computed counts (preferred over this function when available);
mrpheus::bandpass_filter(), mrpheus::remove_dc() for the underlying
filter primitives.
set.seed(1) n <- 25 * 60 * 5 # 5 minutes at 25 Hz x <- rnorm(n, sd = 0.05) y <- rnorm(n, sd = 0.05) z <- rnorm(n, sd = 0.05) + 1 # gravity on the z-axis ## Not run: compute_activity_counts(x, y, z, sampling_rate = 25, epoch_sec = 60) ## End(Not run)set.seed(1) n <- 25 * 60 * 5 # 5 minutes at 25 Hz x <- rnorm(n, sd = 0.05) y <- rnorm(n, sd = 0.05) z <- rnorm(n, sd = 0.05) + 1 # gravity on the z-axis ## Not run: compute_activity_counts(x, y, z, sampling_rate = 25, epoch_sec = 60) ## End(Not run)
Calculates chronobiological phenotyping metrics from classified nightly sleep
data. Mirrors compute_cpd_metrics() and nights_to_cpd_df() from Julia
Ribeiro da Silva Vallim's pipeline_functions_fix27.py, with two updates
to match the fix29 notebook:
MSF and MSW are computed with the circular mean to correctly handle mid-sleep times that wrap midnight.
Truncated episodes starting after noon on the last recording day are excluded before metric computation.
compute_cpd_metrics(x, ...) ## S3 method for class 'zeitr_result' compute_cpd_metrics( x, min_tib_h = 3, min_tib_eve_h = 3, tz = "UTC", holidays = x$holidays, free_days = x$free_days, ... ) ## Default S3 method: compute_cpd_metrics( x, min_tib_h = 3, min_tib_eve_h = 3, tz = "UTC", holidays = NULL, free_days = c("Saturday", "Sunday"), ... )compute_cpd_metrics(x, ...) ## S3 method for class 'zeitr_result' compute_cpd_metrics( x, min_tib_h = 3, min_tib_eve_h = 3, tz = "UTC", holidays = x$holidays, free_days = x$free_days, ... ) ## Default S3 method: compute_cpd_metrics( x, min_tib_h = 3, min_tib_eve_h = 3, tz = "UTC", holidays = NULL, free_days = c("Saturday", "Sunday"), ... )
x |
A |
... |
Not used; reserved for forward compatibility with future methods. |
min_tib_h |
|
min_tib_eve_h |
|
tz |
|
holidays |
Holidays to treat as free days in addition to the days in
|
free_days |
A character vector of day names ( |
Dispatches on the class of x:
data.frame / tibble – treated as a nights table (same behaviour
as the original function signature).
zeitr_result – extracts x$nights and inherits x$holidays and
x$free_days automatically.
Mid-sleep is computed per night as:
where onset = bts + SOL and offset = gts - SOI (both in decimal hours).
MSW and MSF use the circular mean of per-night mid-sleep values
(values >= 12 h shifted by -24 before averaging, then wrapped to [0, 24)),
matching calculate_msf() / calculate_msw() from the fix29 notebook.
MSFsc adjusts MSF by the free-day-eve sleep onset and the weighted
weekly mean sleep duration when free-day duration exceeds weekday duration.
CPD is the RMS distance of each night's mid-sleep from MSFsc in the
time x sequence plane.
A named list with n_nights_cpd, n_free_days, n_workdays,
msw_h, msw_hms, msf_h, msf_hms, msfsc_h, msfsc_hms,
sjl_h, sjl_min, sjla_h, sjla_min, cpd_s, cpd_min, cpd_h.
compute_sleep_metrics(), run_pipeline_native()
Computes the standard non-parametric circadian rhythm analysis variables from an actigraphy recording, following Gonçalves et al. (2014) and Van Someren et al. (1999). All variables are derived from the 24-hour average activity profile built from hourly means (p = 24).
compute_npcra( x, epoch_s = NULL, L5_hours = 5, M10_hours = 10, window_days = NULL, trim_to_d1 = TRUE )compute_npcra( x, epoch_s = NULL, L5_hours = 5, M10_hours = 10, window_days = NULL, trim_to_d1 = TRUE )
x |
A |
epoch_s |
|
L5_hours |
|
M10_hours |
|
window_days |
|
trim_to_d1 |
|
The following variables are computed:
ISInterdaily stability — consistency of the 24 h rest-activity pattern across days (range 0–1; higher = more stable).
IVIntradaily variability — fragmentation of the rest-activity rhythm (>= 0; higher = more fragmented).
RARelative amplitude — contrast between the most active 10 h window (M10) and least active 5 h window (L5) (range 0–1).
L5Mean activity during the least active 5 consecutive hours.
L5_onsetClock time of the L5 window onset (hh:mm).
M10Mean activity during the most active 10 consecutive hours.
M10_onsetClock time of the M10 window onset (hh:mm).
A tibble with columns participant_id, window_start (if
window_days is set), IS, IV, RA, L5, L5_onset, M10,
M10_onset, n_days, n_epochs.
Gonçalves, B. S. B., Adamowicz, T., Louzada, F. M., Moreno, C. R., & Araujo, J. F. (2014). A fresh look at the use of nonparametric analysis in actimetry. Sleep Medicine Reviews, 20, 84–91. doi:10.1016/j.smrv.2014.06.002
Van Someren, E. J. W., Swaab, D. F., Colenda, C. C., Cohen, W., McCall, W. V., & Rosenquist, P. B. (1999). Bright light therapy: Improved sensitivity to its effects on rest-activity rhythms in Alzheimer patients by application of nonparametric methods. Chronobiology International, 16(4), 505–518. doi:10.3109/07420529908998724
## Not run: rec <- read_actigraphy("recordings/P001.txt") # Single estimate over the full recording compute_npcra(rec) # Per-fortnight estimates compute_npcra(rec, window_days = 14) ## End(Not run)## Not run: rec <- read_actigraphy("recordings/P001.txt") # Single estimate over the full recording compute_npcra(rec) # Per-fortnight estimates compute_npcra(rec, window_days = 14) ## End(Not run)
Calculates mean sleep metrics separately for all nights, weekday nights,
and weekend/holiday nights. Output column names and derived metrics mirror
compute_sleep_metrics() from Julia Ribeiro da Silva Vallim's
pipeline_functions_fix27.py.
compute_sleep_metrics(x, ...) ## S3 method for class 'zeitr_result' compute_sleep_metrics( x, min_tib_h = 5, tz = "UTC", holidays = x$holidays, free_days = x$free_days, ... ) ## Default S3 method: compute_sleep_metrics( x, min_tib_h = 5, tz = "UTC", holidays = NULL, free_days = c("Saturday", "Sunday"), ... )compute_sleep_metrics(x, ...) ## S3 method for class 'zeitr_result' compute_sleep_metrics( x, min_tib_h = 5, tz = "UTC", holidays = x$holidays, free_days = x$free_days, ... ) ## Default S3 method: compute_sleep_metrics( x, min_tib_h = 5, tz = "UTC", holidays = NULL, free_days = c("Saturday", "Sunday"), ... )
x |
A |
... |
Not used; reserved for forward compatibility with future methods. |
min_tib_h |
|
tz |
|
holidays |
Holidays to treat as free days in addition to the days in
|
free_days |
A character vector of day names ( |
Dispatches on the class of x:
data.frame / tibble – treated as a nights table (same behaviour
as the original function signature).
zeitr_result – extracts x$nights and inherits x$holidays and
x$free_days automatically.
A night is assigned to the free-day group when the get-up date falls on
one of the days in free_days or matches an entry in holidays. Day-of-week
is determined via the ISO 8601 weekday number (format(date, "%u")) rather
than weekdays(), which is locale-dependent. All remaining nights are
workday nights.
sleep_onset_h uses a circular mean (values >= 12 h are shifted by -24 h
before averaging, then wrapped to [0, 24)). sleep_offset_h uses a plain
arithmetic mean.
fps_h (free period sleep) equals fpr_tib_h - (latencia_min + inertia_min) / 60 – TBT net of sleep onset latency and sleep inertia.
dp_midsleep_min and dp_tst_min are standard deviations of per-night
mid-sleep (minutes) and TST (minutes), respectively.
A named list with metrics for three groups (overall, wd =
workday, fd = free day):
n_overall, n_wd, n_fd
Night counts.
sleep_onset_h, sleep_offset_h
Circular mean onset and arithmetic mean offset in decimal hours.
fpr_tib_hMean TBT in hours.
fps_hMean free period sleep (TBT - SOL - SOI) in hours.
tst_hMean TST in hours.
latencia_min, inertia_min
Mean SOL and SOI in minutes.
waso_minMean WASO in minutes.
sleep_eff_pctMean sleep efficiency in percent (0-100).
tst_24h_hSame as tst_h (24-h TST for main sleep only).
dp_midsleep_min, dp_tst_min
SD of mid-sleep and TST in minutes.
Workday and free-day metrics carry the suffix _wd and _fd.
compute_cpd_metrics(), run_pipeline_native()
## Not run: # From a zeitr_result: holidays and free_days forwarded automatically result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo", holidays = my_holidays, free_days = c("Saturday", "Sunday")) sm <- compute_sleep_metrics(result, tz = "America/Sao_Paulo") # Non-standard schedule: Friday + Saturday as free days sm <- compute_sleep_metrics(result$nights, tz = "America/Sao_Paulo", holidays = my_holidays, free_days = c("Friday", "Saturday")) sm$tst_h # mean TST in hours sm$sleep_onset_h # mean sleep onset (circular, decimal hours) sm$dp_midsleep_min # within-person SD of mid-sleep in minutes ## End(Not run)## Not run: # From a zeitr_result: holidays and free_days forwarded automatically result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo", holidays = my_holidays, free_days = c("Saturday", "Sunday")) sm <- compute_sleep_metrics(result, tz = "America/Sao_Paulo") # Non-standard schedule: Friday + Saturday as free days sm <- compute_sleep_metrics(result$nights, tz = "America/Sao_Paulo", holidays = my_holidays, free_days = c("Friday", "Saturday")) sm$tst_h # mean TST in hours sm$sleep_onset_h # mean sleep onset (circular, decimal hours) sm$dp_midsleep_min # within-person SD of mid-sleep in minutes ## End(Not run)
Computes the Sleep Regularity Index (Phillips et al. 2017): a measure of day-to-day consistency in the sleep/wake pattern, based on the probability that an epoch's sleep/wake state matches the state at the same clock time exactly 24 h later (or earlier), averaged across the whole recording. Ranges from -100 (perfectly inverted day-to-day) to +100 (perfectly regular); 0 corresponds to chance-level agreement.
compute_sri(x, epoch_s = NULL, max_gap_min = 30)compute_sri(x, epoch_s = NULL, max_gap_min = 30)
x |
A |
epoch_s |
|
max_gap_min |
|
Ported from Fix 30 of the Python reference pipeline (SRI_vallim):
rather than deriving sleep/wake from a pyActigraphy scoring algorithm
(Sadeh, Cole-Kripke, Roenneberg, Scripps – all of which showed
substantially worse agreement with manual reference scoring in Julia's
concordance analysis, ICC 0.19-0.67 vs 0.82 here), compute_sri() derives
sleep/wake directly from the epoch-level state column already produced
by zeitR's own pipelines (run_pipeline() / run_pipeline_native()) –
the same classification compute_sleep_metrics() and
compute_cpd_metrics() already treat as ground truth for this recording.
Off-wrist handling mirrors Fix 30 exactly: off-wrist epochs
(state == 4) are treated as missing. Gaps of max_gap_min minutes or
less are interpolated (forward-filled from the last valid epoch, or
back-filled from the next valid epoch when the gap starts at the very
beginning of the recording); longer gaps are left as missing and excluded
from the day-to-day comparison entirely, rather than being counted as a
non-match.
where if the sleep/wake state at epoch
matches the state 24 h later, otherwise, and is the number
of epoch pairs where both epochs have a valid (non-missing) state.
A tibble with columns participant_id, sri, n_pairs (number
of valid 24h-apart epoch comparisons used), and n_epochs (total
epochs after off-wrist gap interpolation, before the 24h-pairing step).
sri is NA if the recording is shorter than 24 h, or if no valid
pairs remain after off-wrist exclusion.
Phillips, A. J. K., Clerx, W. M., O'Brien, C. S., Sano, A., Barger, L. K., Picard, R. W., Lockley, S. W., Klerman, E. B., & Czeisler, C. A. (2017). Irregular sleep/wake patterns are associated with poorer academic performance and delayed circadian and sleep/wake timing. Scientific Reports, 7, 3216. doi:10.1038/s41598-017-03171-4
compute_npcra(), compute_sleep_metrics(),
run_pipeline_native()
## Not run: result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo") compute_sri(result) ## End(Not run)## Not run: result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo") compute_sri(result) ## End(Not run)
Scores each epoch within detected sleep periods as wake or sleep using
score_epochs_cole_kripke(), then computes per-night statistics. This is a
faithful port of the Python condor_pipeline detect_waso: night
boundaries are built by .nights_df() (the search_gap = FALSE path of the
reference nights_df), each night's ZCM is scored with Cole-Kripke, and the
epoch-level state is rebuilt from a zero (wake) base so that within-night
WASO-wake epochs and all epochs outside detected nights are scored as wake.
compute_waso(x, wake_thresh = 60L, search_gap = FALSE)compute_waso(x, wake_thresh = 60L, search_gap = FALSE)
x |
A tibble as returned by |
wake_thresh |
|
search_gap |
|
The following metrics are computed for each detected night / nap:
| Metric | Definition |
tbt |
Total Bed Time — epochs from bed time to get-up time |
tst |
Total Sleep Time — tbt - waso - sol - soi |
waso |
Wake After Sleep Onset — wake epochs between sleep onset and final wake |
sol |
Sleep Onset Latency — epochs from bed time to first sleep epoch |
soi |
Sleep Offset Inertia — trailing wake epochs at end of sleep period |
nw |
Number of awakenings — count of wake-onset transitions |
eff |
Sleep efficiency — tst / tbt
|
A list with two elements:
nightsA tibble with one row per detected night/nap and
columns night, is_nap, bed_time, get_up_time, tbt, tst,
waso, sol, soi, nw, eff.
dataThe input tibble x with state and sleep updated
with epoch-level Cole-Kripke wake/sleep scores.
Cole, R. J., Kripke, D. F., Gruen, W., Mullaney, D. J., & Gillin, J. C. (1992). Automatic sleep/wake identification from wrist activity. Sleep, 15(5), 461–469. doi:10.1093/sleep/15.5.461
## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) prep <- detect_naps_crespo(prep) result <- compute_waso(prep) result$nights ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) prep <- detect_naps_crespo(prep) result <- compute_waso(prep) result$nights ## End(Not run)
Faithful port of the Python nap_wrapper: runs the full CSPD model in nap
mode (detect_naps = TRUE) on the currently-awake epochs (state == 0) and
merges the detected naps into the sleep state. Must be run after
detect_sleep_crespo().
detect_naps_crespo(x, epoch_h = NULL, params = .cspd_nap_params())detect_naps_crespo(x, epoch_h = NULL, params = .cspd_nap_params())
x |
A tibble as returned by |
epoch_h |
|
params |
CSPD nap configuration list (default |
Nap detection uses a nap-mode MSP (a high zero-proportion combined with a
low adaptive-median activity, .crespo_nap_msp()) followed by the same
bed-time / get-up-time refiners as the main sleep detection, with the nap
parameter set (.cspd_nap_params()) and nap-specific minimum-length
post-processing. Detected naps are written as state == 1 (merged into
"sleep"), matching nap_wrapper, which assigns
state[wake] = 1 - refined_output (i.e. naps are not a distinct state).
The input tibble x with state and sleep columns updated. Nap
epochs become state == 1 and sleep == 1; off-wrist (state == 4) and
existing main-sleep epochs are preserved.
Crespo, C., Aboy, M., Fernández, J. R., & Mojón, A. (2012). Automatic identification of activity-rest periods based on actigraphy. Journal of Medical and Biological Engineering, 32(4), 249–256. doi:10.5405/jmbe.1033
detect_sleep_crespo() for main sleep period detection.
## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) prep <- detect_naps_crespo(prep) ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) prep <- detect_naps_crespo(prep) ## End(Not run)
Detects periods where the actigraph was not worn using the bimodal algorithm developed by Condor Instruments. The algorithm proceeds in three stages:
detect_offwrist_bimodal( x, hws = 10L, activity_quantile = 0.15, min_norm_activity = 0.015, nbins = 100L, min_offwrist_length = 10L, min_temp_threshold = 0.35 )detect_offwrist_bimodal( x, hws = 10L, activity_quantile = 0.15, min_norm_activity = 0.015, nbins = 100L, min_offwrist_length = 10L, min_temp_threshold = 0.35 )
x |
A tibble as returned by |
hws |
|
activity_quantile |
|
min_norm_activity |
|
nbins |
|
min_offwrist_length |
|
min_temp_threshold |
|
Feature extraction — rolling median of PIM activity and rolling
signal/variance of internal temperature are computed over a symmetric
window of half-width hws epochs.
Bimodal temperature threshold — among epochs with low activity
median (below the activity_quantile quantile of normalised activity),
a 2-component Gaussian Mixture Model is fitted to the normalised
temperature distribution. The threshold between the two components is
taken as the minimum of the GMM density between the two means (or the
minimum of the smoothed histogram if that is lower). Ashman's D is
computed as a bimodality quality metric.
Initial classification & refinement — epochs simultaneously
exhibiting low activity median AND low temperature are marked as
off-wrist. Short spurious off-wrist runs shorter than
min_offwrist_length epochs are removed.
Off-wrist epochs are encoded as state == 4 (matching the Python
pipeline convention). The offwrist column is set to 0.25 for
off-wrist epochs for actogram overlay plotting.
The input tibble x with state and offwrist columns updated.
Off-wrist epochs have state == 4 and offwrist == 0.25.
The bimodal off-wrist algorithm was developed by Julius A. P. P. de Paula at Condor Instruments (2023). It is not published in peer-reviewed literature but the source code is available in the circadiaBase pipeline repository. The Ashman D statistic is described in:
Ashman, K. M., Bird, C. M., & Zepf, S. E. (1994). Detecting bimodality in astronomical datasets. The Astronomical Journal, 108, 2348. doi:10.1086/117248
## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) sum(prep$state == 4) # number of off-wrist epochs ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) sum(prep$state == 4) # number of off-wrist epochs ## End(Not run)
Identifies the main sleep period(s) in an actigraphy recording using the algorithm described in Crespo et al. (2012). The method applies an adaptive median filter to the activity signal, mitigates spuriously long zero runs, and thresholds the result at a quantile of the filtered signal. Morphological closing and opening operations are then used to smooth the binary sleep/wake estimate.
detect_sleep_crespo( x, epoch_h = NULL, median_filter_h = 8, pad_h = 1, sleep_quantile = 0.365, morph_size = 61L, consec_zeros_thr = 15L, awake_zeros_thr = 2L, sleep_zeros_thr = 30L, zero_mitigation_q = 0.33, min_short_window_thr = 1, refine = TRUE, condition = 0L )detect_sleep_crespo( x, epoch_h = NULL, median_filter_h = 8, pad_h = 1, sleep_quantile = 0.365, morph_size = 61L, consec_zeros_thr = 15L, awake_zeros_thr = 2L, sleep_zeros_thr = 30L, zero_mitigation_q = 0.33, min_short_window_thr = 1, refine = TRUE, condition = 0L )
x |
A tibble as returned by |
epoch_h |
|
median_filter_h |
|
pad_h |
|
sleep_quantile |
|
morph_size |
|
consec_zeros_thr |
|
awake_zeros_thr |
|
sleep_zeros_thr |
|
zero_mitigation_q |
|
min_short_window_thr |
|
refine |
|
condition |
|
The input tibble x with state and sleep columns updated.
Sleep epochs have state == 1 and sleep == 1; off-wrist epochs
(state == 4) are preserved and excluded from the sleep column. With
refine = TRUE the sleep epochs delimit the refined sleep PERIODS (the
Python refined_output); per-epoch wake/sleep within them is scored later
by compute_waso().
Crespo, C., Aboy, M., Fernández, J. R., & Mojón, A. (2012). Automatic identification of activity-rest periods based on actigraphy. Journal of Medical and Biological Engineering, 32(4), 249–256. doi:10.5405/jmbe.1033
detect_naps_crespo() for secondary sleep period (nap) detection.
## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) prep <- detect_offwrist_bimodal(prep) prep <- detect_sleep_crespo(prep) ## End(Not run)
Applies the published ActTrust(R)/GT3X+ regression equation
(sqrt(MET) = b0 + b1 * sqrt(activity_counts)) from
pa_equations() to convert raw activity counts into estimated metabolic
equivalents (METs).
estimate_ee( counts, device = c("ACTT", "GT3X+"), placement = c("hip", "wrist"), equation_set = "batista2026" )estimate_ee( counts, device = c("ACTT", "GT3X+"), placement = c("hip", "wrist"), equation_set = "batista2026" )
counts |
Numeric vector of activity counts (counts/min, over the same
epoch length used by the source equation set – 1-minute for
|
device |
|
placement |
|
equation_set |
|
Numeric vector of estimated METs, same length as counts.
pa_equations() for the underlying coefficients and their
limitations, classify_pa_intensity() to convert METs into intensity
bands.
estimate_ee(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip")estimate_ee(c(0, 5000, 25000, 50000), device = "ACTT", placement = "hip")
Converts the epoch-level data tibble from run_pipeline() or
run_pipeline_native() into the tidy hypnogram format expected by
hypnoR metric functions.
export_hypnogram( result, subject_id = NULL, source = "zeitR", drop_offwrist = FALSE, epoch_sec = NULL )export_hypnogram( result, subject_id = NULL, source = "zeitR", drop_offwrist = FALSE, epoch_sec = NULL )
result |
A |
subject_id |
|
source |
|
drop_offwrist |
|
epoch_sec |
|
The coarse (3-state) stage mapping used by zeitR is:
state |
ZCMn |
Stage |
0 |
any | "W" |
1, 7 |
> 0 |
"Sleep" |
1, 7 |
== 0 |
"Quiet sleep" |
4 |
any | "W"
|
Zero-count epochs within sleep (ZCMn == 0) are mapped to "Quiet sleep"
as the standard actigraphy proxy for quiet/deep sleep. When ZCMn is not
present in the data, all sleep epochs are mapped to "Sleep".
The stage column is an ordered factor with levels
c("W", "Sleep", "Quiet sleep"), matching hypnoR's coarse resolution
contract. "Quiet sleep" is not produced by actigraphy but the level is
present so downstream hypnoR functions do not throw factor-level errors.
subject_id is taken from result$subject_id when not explicitly
supplied. Both run_pipeline() and run_pipeline_native() derive this
from the input filename stem automatically, so in most cases no manual
override is needed.
A tibble with columns:
epochInteger epoch index, 1-based.
timePOSIXct timestamp for the start of each epoch.
stageOrdered factor: c("W", "Sleep", "Quiet sleep").
subject_idCharacter subject identifier (omitted when not available).
sourceCharacter scorer label.
run_pipeline(), run_pipeline_native(), label_states()
## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") # subject_id inferred from filename automatically hyp <- export_hypnogram(result) hyp$subject_id # "P001" # Override when filename does not match study code hyp <- export_hypnogram(result, subject_id = "STUDY_001") # Batch: subject_id inferred for every file automatically results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo") hyps <- lapply(results, export_hypnogram) # Drop off-wrist epochs hyp_clean <- export_hypnogram(result, drop_offwrist = TRUE) ## End(Not run)## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") # subject_id inferred from filename automatically hyp <- export_hypnogram(result) hyp$subject_id # "P001" # Override when filename does not match study code hyp <- export_hypnogram(result, subject_id = "STUDY_001") # Batch: subject_id inferred for every file automatically results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo") hyps <- lapply(results, export_hypnogram) # Drop off-wrist epochs hyp_clean <- export_hypnogram(result, drop_offwrist = TRUE) ## End(Not run)
Converts the epoch-level state vector produced by detect_sleep_crespo()
into a per-episode tibble analogous to the Python SleepPipeline's
results.nights. Contiguous on-wrist sleep periods are delimited by
.nights_df(); per-epoch wake/sleep within each period is scored by
score_epochs_cole_kripke() to derive WASO, SOL, SOI, TST, EFF, and NW.
All time metrics are returned in minutes.
extract_sleep_episodes(data, wake_thresh = 60L)extract_sleep_episodes(data, wake_thresh = 60L)
data |
A tibble as returned by |
wake_thresh |
|
A tibble with one row per detected episode and columns bts
(POSIXct), gts (POSIXct), tbt, tst, sol, soi, waso
(minutes), nw (integer), eff (0-1), nap (logical, always FALSE
– classification into main/secondary happens in
classify_sleep_episodes()).
classify_sleep_episodes(), run_pipeline_native()
Converts the integer state column produced by the zeitR pipeline into a
human-readable factor. Useful for display, plotting, and export — the
internal state column always stays integer to preserve Python reference
parity.
label_states(x)label_states(x)
x |
integer (or numeric) vector of epoch states, as found in
|
| Integer | Label |
0 |
"wake" |
1 |
"sleep" |
4 |
"off-wrist" |
7 |
"nap"
|
Any value not in the table above is silently converted to NA.
An ordered factor with levels
c("wake", "sleep", "nap", "off-wrist"), the same length as x.
label_states(c(0L, 1L, 0L, 4L, 1L, 7L)) # [1] wake sleep wake off-wrist sleep nap # Levels: wake < sleep < nap < off-wrist ## Not run: result <- run_pipeline("recordings/P001.txt") result$data$state_label <- label_states(result$data$state) ## End(Not run)label_states(c(0L, 1L, 0L, 4L, 1L, 7L)) # [1] wake sleep wake off-wrist sleep nap # Levels: wake < sleep < nap < off-wrist ## Not run: result <- run_pipeline("recordings/P001.txt") result$data$state_label <- label_states(result$data$state) ## End(Not run)
Returns the regression coefficients and count-based cut-points for estimating energy expenditure (METs) and classifying physical activity (PA) intensity from ActTrust(R) (Condor Instruments) or ActiGraph(R) GT3X+ activity counts, hip or wrist placement.
pa_equations(equation_set = "batista2026")pa_equations(equation_set = "batista2026")
equation_set |
|
A tibble with one row per device x placement combination and columns:
device"ACTT" or "GT3X+".
placement"hip" or "wrist".
b0, b1
Intercept and slope of
sqrt(MET) = b0 + b1 * sqrt(activity_counts).
cut3, cut6, cut9
Published count/min cut-points
(95% CI midpoints) at the 3, 6, and 9 MET thresholds – i.e. the
count value at which the fitted equation crosses that MET level.
Provided for reference; classify_pa_intensity() classifies on
estimated METs directly rather than re-deriving these.
These equations come from a single controlled-laboratory validation study (Batista et al. 2026; N = 56 healthy adults aged 18-35; treadmill walking/running at 3-9 km/h only). Treat them as one available equation set, not a universal standard:
The paper's own Discussion section compares its GT3X+ (hip) cut-points
against two other published GT3X+ studies (Sasaki et al. 2011;
Santos-Lozano et al. 2013) and finds differences of 2-65% depending on
the MET threshold – and those two reference studies differ from each
other by 16-39%. The paper attributes that spread mainly to
sample-level characteristics rather than device or methodological
artefacts, but that reading applies to the comparison between Sasaki
and Santos-Lozano – it doesn't fully carry over to comparisons against
this paper's own equations, since all three studies used different
modelling approaches (Sasaki et al.: ActiGraph's two-regression model;
Santos-Lozano et al.: an artificial neural network; this paper: a
simple sqrt-transformed linear model with a device x placement
interaction). Cross-study cut-point differences therefore reflect model
choice as well as sample, not sample alone – and that's checkable to
different degrees: this paper's linear coefficients (b0/b1 below)
are transparent enough to compare term-by-term against Sasaki et al.'s
two-regression model, so a discrepancy there is at least diagnosable.
Santos-Lozano et al.'s cut-points come from an ANN, which has no
inspectable coefficients – there is no way to say why it disagrees
with the equations here, only that it does.
The ACTT (hip)/ACTT (wrist) equations are the first published cut-points for ActTrust(R) at all, so there is nothing yet to cross-check them against.
Validated only for laboratory treadmill walking/running in healthy young adults. Applying these equations to free-living data, other age groups (children, older adults), clinical populations, or other activity types is an extrapolation the source study explicitly flags as untested.
equation_set is exposed as an explicit argument (rather than hard-coding
a single table) so a future validation study covering a different
population or device can be added as an alternative set without changing
the estimate_ee() / classify_pa_intensity() API.
estimate_ee(), classify_pa_intensity()
pa_equations()pa_equations()
Renders epoch-level sleep/wake states as a raster with one row per calendar day and time-of-day (00:00 to 24:00) on the x-axis. The oldest day is at the top, following standard chronobiology convention.
plot_actogram( result, tz = NULL, title = NULL, colours = NULL, date_label_every = 7L, epoch_min = 1, base_size = 13 )plot_actogram( result, tz = NULL, title = NULL, colours = NULL, date_label_every = 7L, epoch_min = 1, base_size = 13 )
result |
A |
tz |
|
title |
|
colours |
Named character vector mapping state labels ( |
date_label_every |
|
epoch_min |
|
base_size |
|
A ggplot object.
plot_actogram_double(), plot_actogram_activity(),
actogram_colours(), label_states()
## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") # Default colours plot_actogram(result) # Custom colours plot_actogram(result, colours = c(wake = "#E8D5B0", sleep = "#1C1A2E", nap = "#F0A500", "off-wrist" = "#C25E2A")) # Label every 14 days plot_actogram(result, date_label_every = 14L) ## End(Not run)## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") # Default colours plot_actogram(result) # Custom colours plot_actogram(result, colours = c(wake = "#E8D5B0", sleep = "#1C1A2E", nap = "#F0A500", "off-wrist" = "#C25E2A")) # Label every 14 days plot_actogram(result, date_label_every = 14L) ## End(Not run)
Same double-plot layout as plot_actogram_double() — each day appears in
both the left and right column of adjacent rows — but each epoch is rendered
as a vertical bar whose height is proportional to the raw activity count
(default: ZCMn, the zero-crossing mean from ActTrust). Bars are coloured
by sleep/wake state, so the plot simultaneously conveys activity intensity
and state classification.
plot_actogram_activity( result, tz = NULL, title = NULL, colours = NULL, activity_col = "ZCMn", activity_cap_quantile = 0.99, log_scale = FALSE, date_label_every = 7L, epoch_min = 1, base_size = 13 )plot_actogram_activity( result, tz = NULL, title = NULL, colours = NULL, activity_col = "ZCMn", activity_cap_quantile = 0.99, log_scale = FALSE, date_label_every = 7L, epoch_min = 1, base_size = 13 )
result |
A |
tz |
|
title |
|
colours |
Named character vector mapping state labels ( |
activity_col |
|
activity_cap_quantile |
|
log_scale |
|
date_label_every |
|
epoch_min |
|
base_size |
|
Bar heights are capped at the activity_cap_quantile quantile of
non-zero epochs to prevent outlier activity bursts from compressing the
visible range for the rest of the recording. A thin baseline stub
(2 % of row height) is drawn for zero-activity epochs so that sleep periods
and off-wrist blocks remain faintly visible.
Actigraphy activity counts are typically right-skewed, with occasional
bursts far above the typical waking level. On the default linear scale
this compresses most of the meaningful variation among low-to-moderate
activity epochs into a thin sliver near the baseline. Set log_scale = TRUE to apply a log1p() transform (log(1 + x), so zero-activity
epochs map to 0 rather than -Inf) before capping and normalising –
this expands the low-activity range at the cost of visually compressing
the difference between already-high activity bursts.
A ggplot object.
plot_actogram(), plot_actogram_double(), actogram_colours()
## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") plot_actogram_activity(result) # Cap at 95th percentile to highlight moderate activity plot_actogram_activity(result, activity_cap_quantile = 0.95) # Log scale: reveals structure among low-activity epochs that a linear # scale would otherwise compress near the baseline plot_actogram_activity(result, log_scale = TRUE) ## End(Not run)## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") plot_actogram_activity(result) # Cap at 95th percentile to highlight moderate activity plot_actogram_activity(result, activity_cap_quantile = 0.95) # Log scale: reveals structure among low-activity epochs that a linear # scale would otherwise compress near the baseline plot_actogram_activity(result, log_scale = TRUE) ## End(Not run)
The classic chronobiology double-plot format. Each recording day is drawn twice: in the left column of its own row (x = 00:00 to 24:00) and in the right column of the row above (x = 24:00 to 48:00). This means consecutive pairs of days share a row, making circadian phase drift visible as a diagonal band across rows.
plot_actogram_double( result, tz = NULL, title = NULL, colours = NULL, date_label_every = 7L, epoch_min = 1, base_size = 13 )plot_actogram_double( result, tz = NULL, title = NULL, colours = NULL, date_label_every = 7L, epoch_min = 1, base_size = 13 )
result |
A |
tz |
|
title |
|
colours |
Named character vector mapping state labels ( |
date_label_every |
|
epoch_min |
|
base_size |
|
Row shows day on the left and day on the right.
Every day therefore appears twice in the plot (except the first, which has
no left-column predecessor, and the last, which has no right-column
successor). A dashed vertical line marks the 24 h boundary between the
two columns.
A ggplot object.
plot_actogram(), plot_actogram_activity(), actogram_colours()
## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") plot_actogram_double(result) ## End(Not run)## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") plot_actogram_double(result) ## End(Not run)
Transforms the output of read_acttrust() (or any reader that returns a
compatible tibble) into the working data frame expected by all detection
functions. Specifically:
prepare_actigraphy(x)prepare_actigraphy(x)
x |
A tibble as returned by |
Clamps int_temp and ext_temp to the physiological range [0, 42] °C.
Adds min-max scaled temperature columns int_temp_ and ext_temp_
(range [0, 1]) for plotting.
Ensures state, offwrist, and sleep columns are present and
initialised to 0.
The original tibble is never modified; a copy is returned.
A tibble of the same dimensions as x with additional or updated
columns: state, offwrist, sleep, int_temp_, ext_temp_.
## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") prep <- prepare_actigraphy(rec) ## End(Not run)
A device-agnostic wrapper that reads a raw actigraphy file and returns a
zeitr_recording object with $epochs (a tidy tibble) and $metadata
(a named list of device and recording information).
read_actigraphy(path, device = "acttrust", tz = "UTC", ...)read_actigraphy(path, device = "acttrust", tz = "UTC", ...)
path |
|
device |
|
tz |
|
... |
Additional arguments forwarded to the device-specific reader
(e.g. |
Currently supported devices:
"acttrust" — Condor Instruments ActTrust / ActTrust2 (.txt)
"axivity" — Axivity AX3/AX6 (.cwa), via read_axivity()
(requires the axR package; converts raw acceleration to epoch-level
counts with compute_activity_counts() – see read_axivity()'s
Details for validation caveats)
A zeitr_recording S3 object — a named list with:
$epochsA tibble with one row per epoch and columns
datetime, activity, int_temp, ext_temp, ZCMn,
state, offwrist, sleep.
$metadataA named list with subject, device_id,
device_model, firmware_version, interval_s, source_file,
and participant_id (derived from the filename stem).
read_actigraphy_dir() to read a whole directory at once.
## Not run: rec <- read_actigraphy("recordings/P001.txt") rec$epochs rec$metadata ## End(Not run)## Not run: rec <- read_actigraphy("recordings/P001.txt") rec$epochs rec$metadata ## End(Not run)
Applies read_actigraphy() to every file matching pattern in folder.
Returns a zeitr_study object — a named list of zeitr_recording objects,
one per file. Files that fail to parse are skipped with a warning.
read_actigraphy_dir( folder, device = "acttrust", pattern = "*.txt", tz = "UTC", ... )read_actigraphy_dir( folder, device = "acttrust", pattern = "*.txt", tz = "UTC", ... )
folder |
|
device |
|
pattern |
|
tz |
|
... |
Additional arguments forwarded to |
A zeitr_study S3 object — a named list of zeitr_recording
objects. Names are participant IDs (filename stems).
study_summary() to summarise a zeitr_study.
## Not run: study <- read_actigraphy_dir("recordings/", tz = "America/Sao_Paulo") study_summary(study) ## End(Not run)## Not run: study <- read_actigraphy_dir("recordings/", tz = "America/Sao_Paulo") study_summary(study) ## End(Not run)
Parses a Condor ActTrust .txt export into a tidy tibble. The file
format consists of a variable-length key-value header block followed by
semicolon-delimited epoch rows. The header ends at the line beginning with
DATE/TIME.
read_acttrust(path, tz = "UTC", encoding = "latin1")read_acttrust(path, tz = "UTC", encoding = "latin1")
path |
|
tz |
|
encoding |
|
A tibble with one row per epoch and the following columns:
datetimePOSIXct — epoch timestamp.
activitydouble — PIM activity count.
int_tempdouble — internal (on-body) temperature, degC.
ext_tempdouble — external (ambient) temperature, degC.
NA if unavailable.
ZCMndouble — normalised zero-crossing mode count.
NA if unavailable.
lightdouble — total light intensity (lux).
NA if unavailable.
statedouble — state column, initialised to 0.
offwristdouble — off-wrist indicator, initialised to 0.
sleepdouble — sleep indicator, initialised to 0.
The tibble carries a "zeitr_acttrust" class and a metadata attribute
(a named list with subject, device_id, device_model,
firmware_version, interval_s, source_file).
## Not run: rec <- read_acttrust("recordings/P001.txt") rec attr(rec, "metadata") ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") rec attr(rec, "metadata") ## End(Not run)
Bridges axR::axivity_read_cwa()'s raw per-sample output (triaxial
acceleration at the device's native sampling rate) into the same
epoch-level, 9-column shape read_acttrust() produces – so an Axivity
recording can flow through the rest of zeitR (run_pipeline(),
compute_npcra(), compute_sri(), etc.) exactly like an ActTrust one.
read_axivity( path, tz = "UTC", epoch_sec = 60, filter_low = 0.25, filter_high = 2.5, zcm_threshold = 0.01, tat_threshold = 0.05 )read_axivity( path, tz = "UTC", epoch_sec = 60, filter_low = 0.25, filter_high = 2.5, zcm_threshold = 0.01, tat_threshold = 0.05 )
path |
|
tz |
|
epoch_sec |
|
filter_low, filter_high
|
|
zcm_threshold, tat_threshold
|
|
A tibble with one row per epoch and the same columns as
read_acttrust() (datetime, activity, int_temp, ext_temp,
ZCMn, light, state, offwrist, sleep), plus one extra column
not present there: TAT (time above threshold, seconds/epoch, from
compute_activity_counts()). activity is PIM. ext_temp is always
NA – Axivity devices have a single on-body temperature sensor, no
separate ambient sensor. The tibble carries a "zeitr_axivity" class
and a metadata attribute (a named list with device_id,
session_id, sample_rate, epoch_sec, filter_low, filter_high,
cwa_metadata (axR's raw device metadata string), source_file).
The raw-to-counts conversion itself is compute_activity_counts() –
already documented there as an unvalidated approximation of onboard
device processing (no reference converter exists to check it against).
Axivity devices additionally have no published or validated
filter/threshold preset at all (unlike ActTrust and GT3X+, which at
least have a documented processing description to approximate). The
filter_low/filter_high defaults here (0.25/2.5 Hz) are
compute_activity_counts()'s GT3X+-style preset, reused because it's
the closer starting point of the two existing options for a
research-grade wrist accelerometer like the AX3 – not because it has
been checked against real Axivity output. Treat activity/ZCMn from
this function as a rough approximation only; validate against a
reference (e.g. GGIR) before relying on it for any published analysis.
ZCMn is compute_activity_counts()'s raw ZCM count with no
additional normalisation applied – named ZCMn only for column-name
compatibility with read_acttrust()'s CK-scoring input, not because a
normalisation step has actually been performed.
axivity_read_cwa() reports sample_rate per sample (block-level, as
stored in the .cwa file). This function takes the single most common
value across the whole recording and uses it for the entire conversion;
if any samples report a different rate (a genuine rate change mid
recording, or a corrupt block), a warning names the discrepancy but the
dominant rate is still used throughout. Epoch boundaries and grouping for
light/int_temp averaging are derived from this same dominant rate,
matching compute_activity_counts()'s own epoch grouping exactly
(including which trailing samples get dropped).
axivity_read_cwa() tags timestamp as UTC by convention (the device's
own real-time clock, not a true UTC source) – exactly like
read_acttrust() does for ActTrust's DATE/TIME column. tz here
re-labels the same clock reading under the recording's actual local time
zone (via lubridate::force_tz(); no shift in wall-clock value), rather
than converting it – set it to the time zone the device's clock was
actually set to for correct circadian alignment downstream.
read_actigraphy() (device = "axivity"),
compute_activity_counts() for the underlying raw-to-counts
conversion and its validation caveats, read_acttrust() for the
column shape this matches.
## Not run: rec <- read_axivity("recordings/P001.cwa", tz = "America/Sao_Paulo") rec attr(rec, "metadata") ## End(Not run)## Not run: rec <- read_axivity("recordings/P001.cwa", tz = "America/Sao_Paulo") rec attr(rec, "metadata") ## End(Not run)
Orchestrates the complete pipeline for a single ActTrust recording:
run_pipeline( path, tz = "UTC", gap_s = 120, params = acttrust_params(), offwrist_args = list(), sleep_args = list(), nap_args = list(), quiet = FALSE )run_pipeline( path, tz = "UTC", gap_s = 120, params = acttrust_params(), offwrist_args = list(), sleep_args = list(), nap_args = list(), quiet = FALSE )
path |
|
tz |
|
gap_s |
|
params |
Device parameter preset, as returned by |
offwrist_args |
|
sleep_args |
|
nap_args |
|
quiet |
|
Read — read_acttrust()
Consistency check — check_consistency()
Prepare — prepare_actigraphy()
Off-wrist detection — detect_offwrist_bimodal()
Main sleep period detection — detect_sleep_crespo()
Nap detection — detect_naps_crespo()
WASO + nightly statistics — compute_waso()
A zeitr_result S3 object — a named list with:
subject_idcharacter — derived from the input filename stem.
source_filecharacter — absolute path to the input file.
datatibble — final epoch-level data frame with all state
columns populated.
nightstibble — per-night sleep statistics.
issuestibble — timestamp consistency issues (0 rows if none).
metadatalist — device and subject metadata from the file header.
run_pipeline_batch() for processing a directory of files.
## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") result$nights result$data ## End(Not run)## Not run: result <- run_pipeline("recordings/P001.txt", tz = "America/Sao_Paulo") result$nights result$data ## End(Not run)
Applies run_pipeline() to every file matching pattern in folder,
returning a list of zeitr_result objects. Files that fail are skipped
with a warning.
run_pipeline_batch(folder, pattern = "*.txt", parallel = FALSE, ...)run_pipeline_batch(folder, pattern = "*.txt", parallel = FALSE, ...)
folder |
|
pattern |
|
parallel |
|
... |
Additional arguments forwarded to |
A named list of zeitr_result objects, one per successfully
processed file. Names are the file stem (subject IDs).
## Not run: results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo") lapply(results, function(r) r$nights) # Parallel: process a large cohort across 4 workers future::plan(future::multisession(workers = 4)) results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo", parallel = TRUE) ## End(Not run)## Not run: results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo") lapply(results, function(r) r$nights) # Parallel: process a large cohort across 4 workers future::plan(future::multisession(workers = 4)) results <- run_pipeline_batch("recordings/", tz = "America/Sao_Paulo", parallel = TRUE) ## End(Not run)
Orchestrates the vendor-independent (Vallim) sleep analysis pipeline for a
single ActTrust recording. Shares the read / prepare / off-wrist / CSPD
epoch-scorer stages with run_pipeline(), then replaces Condor's
nights_df classification with the rule set developed by Julia Ribeiro da
Silva Vallim and ported from her condor pipeline (Fixes 25, 26a/b/c, 27, 29).
run_pipeline_native( path, tz = "UTC", gap_s = 120, params = acttrust_params(), offwrist_args = list(), sleep_args = list(), classify_args = list(), holidays = NULL, free_days = c("Saturday", "Sunday"), quiet = FALSE )run_pipeline_native( path, tz = "UTC", gap_s = 120, params = acttrust_params(), offwrist_args = list(), sleep_args = list(), classify_args = list(), holidays = NULL, free_days = c("Saturday", "Sunday"), quiet = FALSE )
path |
|
tz |
|
gap_s |
|
params |
Device parameter preset, as returned by |
offwrist_args |
|
sleep_args |
|
classify_args |
|
holidays |
Holidays to treat as free days in addition to the days in
|
free_days |
A character vector of day names ( |
quiet |
|
Steps:
Read – read_acttrust()
Consistency check – check_consistency()
Prepare – prepare_actigraphy()
Off-wrist detection – detect_offwrist_bimodal()
Epoch scoring – detect_sleep_crespo() (CSPD; same scorer as run_pipeline())
Episode extraction – extract_sleep_episodes()
Episode classification – classify_sleep_episodes() (JRSV rules)
Fine-grained state – compute_waso() (Cole-Kripke within periods, for result$data)
A zeitr_result S3 object with the same structure as run_pipeline(),
except nights additionally contains:
sleep_typecharacter – "main" or "secondary".
bed_time, get_up_time
POSIXct – from JRSV bts/gts convention (last sleep epoch for get-up, not first wake epoch).
The is_nap column is retained for backwards compatibility
(is_nap == (sleep_type == "secondary")).
run_pipeline() for the vendor (Condor) pipeline,
extract_sleep_episodes(), classify_sleep_episodes()
## Not run: result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo") result$nights ## End(Not run)## Not run: result <- run_pipeline_native("recordings/P001.txt", tz = "America/Sao_Paulo") result$nights ## End(Not run)
Applies run_pipeline_native() to every file matching pattern in
folder, returning a named list of zeitr_result objects. Files that
fail are skipped with a warning.
run_pipeline_native_batch(folder, pattern = "*.txt", parallel = FALSE, ...)run_pipeline_native_batch(folder, pattern = "*.txt", parallel = FALSE, ...)
folder |
|
pattern |
|
parallel |
|
... |
Additional arguments forwarded to |
A named list of zeitr_result objects.
## Not run: results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo") lapply(results, function(r) r$nights) # Parallel: process a large cohort across 4 workers future::plan(future::multisession(workers = 4)) results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo", parallel = TRUE) ## End(Not run)## Not run: results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo") lapply(results, function(r) r$nights) # Parallel: process a large cohort across 4 workers future::plan(future::multisession(workers = 4)) results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo", parallel = TRUE) ## End(Not run)
Applies the Cole-Kripke algorithm to a vector of zero-crossing mode (ZCM)
activity counts, scoring each epoch as wake (1) or sleep (0) using a
weighted sum of activity in a surrounding window.
score_epochs_cole_kripke( zcm, P = 0.000464, weights_before = c(34.5, 133, 529, 375, 408, 400.5, 1074, 2048.5, 2424.5), weights_after = c(1920, 149.5, 257.5, 125, 111.5, 120, 69, 40.5) )score_epochs_cole_kripke( zcm, P = 0.000464, weights_before = c(34.5, 133, 529, 375, 408, 400.5, 1074, 2048.5, 2424.5), weights_after = c(1920, 149.5, 257.5, 125, 111.5, 120, 69, 40.5) )
zcm |
|
P |
|
weights_before |
|
weights_after |
|
Each epoch's score is computed as:
where is the ZCM count at epoch , and
are the before and after weight vectors from Cole et al. (1992),
and . Epochs with are scored as wake.
An integer vector the same length as zcm, with 1 indicating
wake and 0 indicating sleep.
Cole, R. J., Kripke, D. F., Gruen, W., Mullaney, D. J., & Gillin, J. C. (1992). Automatic sleep/wake identification from wrist activity. Sleep, 15(5), 461–469. doi:10.1093/sleep/15.5.461
## Not run: rec <- read_acttrust("recordings/P001.txt") scores <- score_epochs_cole_kripke(rec$ZCMn) table(scores) # 0 = sleep, 1 = wake ## End(Not run)## Not run: rec <- read_acttrust("recordings/P001.txt") scores <- score_epochs_cole_kripke(rec$ZCMn) table(scores) # 0 = sleep, 1 = wake ## End(Not run)
Computes compute_sleep_metrics() and compute_cpd_metrics() for every
participant in a batch of pipeline results and stacks them into a single
tibble with one row per participant – the sleep-timing/chronotype
counterpart to study_summary(), which covers NPCRA activity-rhythm
variables instead.
study_sleep_metrics( results, min_tib_h = 5, min_tib_eve_h = 3, tz = "UTC", holidays = NULL, free_days = NULL )study_sleep_metrics( results, min_tib_h = 5, min_tib_eve_h = 3, tz = "UTC", holidays = NULL, free_days = NULL )
results |
A named list of |
min_tib_h |
|
min_tib_eve_h |
|
tz |
|
holidays, free_days
|
Forwarded to both |
compute_sleep_metrics() and compute_cpd_metrics() each return a single
named list per participant with no participant identifier, and there was
previously no batch wrapper analogous to study_summary() for them. This
is that wrapper – intended to make these chronobiological phenotyping
metrics database-ready for tools like syncR::sync(), which expect one
row per participant with a shared participant_id column across sources.
If either metric computation fails for a participant (e.g. no free days
found, or no nights pass the min_tib_h filter), that participant's row
is filled with NA for the affected metrics and a warning is emitted –
the rest of the study is unaffected.
A tibble with one row per participant: participant_id, all
compute_sleep_metrics() columns (n_overall/n_wd/n_fd and the
twelve sleep-timing metrics with _wd/_fd suffixes), and all
compute_cpd_metrics() columns (n_nights_cpd, n_free_days,
n_workdays, msw_h/msf_h/msfsc_h and their _hms forms, sjl_h,
sjla_h, cpd_s/cpd_min/cpd_h).
study_summary() for the NPCRA (activity-rhythm) analogue,
compute_sleep_metrics(), compute_cpd_metrics(),
run_pipeline_native_batch()
## Not run: results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo") study_sleep_metrics(results) # Feed straight into syncR::sync() sync(zeit = study_sleep_metrics(results)) ## End(Not run)## Not run: results <- run_pipeline_native_batch("recordings/", tz = "America/Sao_Paulo") study_sleep_metrics(results) # Feed straight into syncR::sync() sync(zeit = study_sleep_metrics(results)) ## End(Not run)
Computes per-participant summary statistics from a zeitr_study object
(as returned by read_actigraphy_dir()). For each recording, the function
computes NPCRA variables (IS, IV, RA, L5, M10) and basic recording quality
metrics.
study_summary(study, epoch_s = NULL, L5_hours = 5, M10_hours = 10)study_summary(study, epoch_s = NULL, L5_hours = 5, M10_hours = 10)
study |
A |
epoch_s |
|
L5_hours |
|
M10_hours |
|
A tibble with one row per participant and columns:
participant_idParticipant identifier (filename stem).
n_epochsTotal number of epochs in the recording.
n_daysRecording duration in days.
startPOSIXct — first epoch timestamp.
endPOSIXct — last epoch timestamp.
ISInterdaily stability.
IVIntradaily variability.
RARelative amplitude.
L5Mean activity in the least active 5 h window.
L5_onsetClock time of L5 midpoint.
M10Mean activity in the most active 10 h window.
M10_onsetClock time of M10 midpoint.
compute_npcra() for single-recording NPCRA, read_actigraphy_dir()
to create a zeitr_study, study_sleep_metrics() for the sleep-timing/
chronotype analogue (CPD, MSF/MSW, social jetlag).
## Not run: study <- read_actigraphy_dir("recordings/", tz = "America/Sao_Paulo") study_summary(study) ## End(Not run)## Not run: study <- read_actigraphy_dir("recordings/", tz = "America/Sao_Paulo") study_summary(study) ## End(Not run)