MATLAB toolbox accompanying Chen et al., PNAS 2025 on the temporal dynamics of human sleep spindles. It lets you detect spindles as time-frequency peaks, then fit a point-process generalized-linear-model (GLM) that jointly captures multiple factors influencing moment-to-moment spindle occurrence:
- Sleep stage (discrete N2 / N3)
- Slow-oscillation (SO) power — a continuous measure of sleep depth
- Slow-oscillation (SO) phase — cortical up/down state
- Spindle history — the timing of previous spindles (short-term and infraslow)
The key finding of the paper: short-term timing patterns are the dominant determinant of spindle timing, more so than sleep depth or cortical up/down state. Each subject has a near-fingerprint-like refractory + excitatory structure (typical peaks: ~1.8 s refractory period, ~2.9 s excitatory period, peak at ~3.5 s post-spindle), with variability increasing over age.
Shuqiang Chen, Mingjian He, Ritchie E. Brown, Uri T. Eden, Michael J. Prerau. "Individualized temporal patterns drive human sleep spindle timing." Proceedings of the National Academy of Sciences, 122(2): e2405276121 (2025). doi: 10.1073/pnas.2405276121
A machine-readable citation is in CITATION.cff — GitHub's "Cite this repository" button uses it.
To clone the Spindle_dynamics_toolbox.git repository to your own computer or remote workstation, start by creating a directory for it. Then, within that directory in your terminal, run the clone command.
mkdir Spindle_dynamics_toolboxgit clone git@github.com:preraulab/Spindle_dynamics_toolbox.git Spindle_dynamics_toolboxTo run this repository, the following MATLAB toolboxes must be installed:
- Signal Processing Toolbox
- Statistics and Machine Learning Toolbox
- Parallel Computing Toolbox
To install the toolboxes above, in MATLAB: HOME → Add-Ons → Get Add-Ons. Detailed instructions here.
This repository includes .mex files to enable fast execution of the multitaper spectrogram. macOS may block execution due to user's security settings. If you see a security warning window pop up like:
"multitaper_spectrogram_coder_mex.... not opened ..."
Follow these steps to allow execution:
- Go to System Settings → Privacy & Security.
- Scroll down and look for a message indicating that the MEX file was blocked.
- Click "Allow Anyway"
- Restart MATLAB.
Details of the multitaper spectrogram can be found here.
- Background and Toolbox Overview
- Pipeline Overview
- Quick Start
- Raw Data to Model Fitting
- Model Results And Visualizations
- Key Model Details
- Repository Structure
- Datasets Used in the Paper
- Citations
- Status
Sleep spindles are cortical electrical waveforms observed during sleep, considered critical for memory consolidation and sleep stability. Abnormalities in sleep spindles have been found in neuropsychiatric disorders and aging and are suggested to contribute to functional deficits. Numerous studies have demonstrated that spindle activity dynamically and continuously evolves over time and is mediated by a variety of intrinsic and extrinsic factors including sleep stage, slow oscillation (SO) activity (0.5–1.5 Hz), and infraslow activity. Despite these known dynamics, the relative influences on the moment-to-moment likelihood of a spindle event occurring at a specific time are not well-characterized. Moreover, standard analyses almost universally report average spindle rate (known as spindle density) over fixed stages or time periods — thus ignoring timing patterns completely. Without a systematic characterization of spindle dynamics, our ability to identify biomarkers for aging and disordered conditions remains critically limited.
Using a rigorous statistical framework, Chen et al. 2025 demonstrate that short-term timing patterns are the dominant determinant of spindle timing, whereas sleep depth, cortical up/down-state, and long-term (infraslow) patterns — features thought to be primary drivers of spindle occurrence — are less important. They also show that these short-term timing patterns are fingerprint-like and show increased variability over age. This study provides a new lens on spindle production mechanisms, which will allow studies of the role of spindle timing patterns in memory consolidation, aging, and disease.
This code toolbox implements an integrated framework for characterizing instantaneous spindle temporal dynamics influenced by multiple factors, including sleep stage/depth (SO Power), cortical up/down states (SO Phase), and the past history of spindles. It consists of two major components:
-
Provides an interactive interface for users to explore data and create basic visualizations:
- Load example data or upload their own data.
- Specify model factors and add interactions between them.
- Customize settings to generate an overview figure.
-
Offers researchers a detailed workflow to:
- Dive into the toolbox's functionalities.
- Address specific scientific questions using example data or their own data.
Designed as a user-friendly toolbox, we aim to:
- Streamline research workflows.
- Ensure reproducibility.
- Inspire researchers to apply and adapt it to diverse datasets for broader applications.
EEG (polysomnography)
│
▼
┌──────────────────────────────┐
│ Multitaper spectrogram │ multitaper_spectrogram (MEX)
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ TF-sigma peak detection │ extract_*.m, find_frequency_peaks
│ 12–16 Hz peaks → spindles │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ Covariates │
│ • sleep stage │ (discrete)
│ • SO power │ (continuous; compute_mtspect_power)
│ • SO phase │ (0 – 2π; cortical up/down state)
│ • spindle history │ (past spindle times; build_design_mt)
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ Point-process GLM │ conditional-intensity regression
│ λ(t | covariates, history) │ (MATLAB glmfit / fitglm)
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ Analysis & visualization │
│ • KS plot (goodness-of-fit)│ KSplot
│ • history curve │ plot_hist_curve
│ • SO-phase preference │ plot_sop_prefphase
│ • stage × phase preference │ plot_stage_prefphase
│ • deviance explained │ compute_dev_exp
└──────────────────────────────┘
After installing the package, execute the quick_start GUI function in the MATLAB command line:
> quick_start;The following GUI should be generated (shown below, left panel):
Quick Start GUI
Follow the 4 steps to make your choices. Here is an example of the settings (shown above, right panel), which specifies the model primarily used in the paper:
- Load data: Load Example Data, which is the same MESA subject as in Figure 6 from the paper.
- Select factors: Click on "Stage", "SOphase", "History".
- Choose history: Click on "Long-term (90 sec)"
- Select interactions: Choose "stage:SOphase interaction"
Once you click "Run the Model", an overview figure will be generated for exploration:
Overview of the spindle dynamics
Use the scrollzoompan interface to slide around the figure. To view the exact same epoch as the paper, set Zoom to 90 and Pan to 30145.
Click on "Load User Data" to browse and load your own data. Ensure the file meets the following requirements:
-
File format:
- Must be a
.matfile.
- Must be a
-
Required variables (variable names are case-insensitive):
EEG: (double, 1D vector) raw EEG data. Other accepted names:eeg_data,raw_EEG,dataFs: (double, scalar) Sampling frequency of the EEG data in Hz. Other accepted names:sampling_ratestage_val: (double, 1D vector) Sleep stages (1: N3, 2: N2, 3: N1, 4: REM, 5: Wake). Other accepted names:stage_vals,stages,stage,stageval,stagevalsstage_time: (double, 1D vector) Corresponding times for the sleep stages (seconds). Other accepted names:stage_t,time_stages,stage_times
Walk-through of the data loading, preprocessing, model specification, and model fitting steps in the example script. To run everything and generate all figures with a single command:
> Example_Script;specify_mdl consolidates all model specifications — model factors (BinarySelect), interactions (InteractSelect), and other options — into a single struct (ModelSpec).
[ModelSpec] = specify_mdl(BinarySelect, InteractSelect, 'hist_choice', hist_choice, 'control_pt', control_pt);% Input:
% <Required inputs>
% - BinarySelect: (1x4 vector, double), indicates which factors are selected
% Factors in fixed order: SOphase, stage, SOpower, history
% e.g., [1,1,0,1] means select SOphase, stage, and history
% - InteractSelect: (1xn cell), each entry is an interaction term in the form of A:B
% Case- and order-insensitive; accepts separators ':', '&', '-'
% e.g., {'stage:SOphase', 'stage:history'}
%
% <Optional inputs>
% - hist_choice: (string) 'short' (default, up to 15 s) or 'long' (up to 90 s)
% - control_pt: (1xk vector, double), spline control point locations
% default: [0:15:90 120 150]
% - binsize: (double), point-process bin size in seconds (default: 0.1)
% - hard_cutoffs: (1x2 vector, double), frequency cutoff in Hz (default: [12 16])
%
% Output:
% ModelSpec: struct containing all model specificationspreprocessToDesignMatrix extracts spindle event information (res_table), saves preprocessed binned data (BinData), and builds the design matrix X:
[X, BinData, res_table] = preprocessToDesignMatrix(EEG, Fs, stage_val, stage_time, ModelSpec);% Input (all required):
% - EEG: (double, 1D) raw EEG data
% - Fs: (double, scalar) sampling frequency in Hz
% - stage_val: (double, 1D) stage values where 1–5 = N3, N2, N1, REM, Wake
% - stage_time: (double, 1D) corresponding time of the stages (s)
% - ModelSpec: struct (from specify_mdl)
%
% Output:
% - X: (double, matrix) design matrix
% - BinData: (struct) data saved per binsize
% - res_table: (table) event info and signals. Key fields include:
% peak_ctimes : detected event central times (s)
% peak_freqs : detected event frequencies (Hz)
% SOpow : slow oscillation power
% SOphase : slow oscillation phaseMATLAB's glmfit fits the point-process GLM:
[b, dev, stats] = glmfit(X, y, 'poisson');X— design matrixy— point-process binary train (response)b— fitted parametersdev— deviancestats— MATLAB struct with coefficient covariance, p-values, residuals, etc.
The history modulation curve estimates a multiplicative modulation of the spindle event rate due to a prior event at any given time lag, answering: How much more likely is a spindle now, given an event was observed X seconds ago? plot_hist_curve.m computes and plots it, along with history features (refractory period, excitatory period, peak time, peak height, infraslow multiplier).
[xlag, yhat, yu, yl, hist_features] = plot_hist_curve(stats, ModelSpec, BinData);Output fields:
xlag,yhat— history lag (s) and modulation valueyu,yl— 95% CI boundshist_features.ref_period— refractory period (s)hist_features.exc_period— excited period (s)hist_features.p_time— peak time (s)hist_features.p_height— peak heighthist_features.AUC_is— infraslow multiplier (area under 40–70 s / 30)
Figure 1: History Modulation Curve
We observe that history modulation begins with a refractory period, ramps up to a peak within an excitatory period, and gradually decreases back to 1 (no modulation for events long ago).
Sleep spindles have been widely reported to preferentially occur in the cortical up-state. plot_stage_prefphase.m visualizes how the preferred phase shifts with discrete sleep stage:
[pp, pp_CI] = plot_stage_prefphase(b, stats, ModelSpec);pp— preferred phase (rad) per stagepp_CI— 95% CI per stage
plot_sop_prefphase.m visualizes how the preferred phase shifts with continuous SO power:
[phi0, sop0, sop_pp_mat] = plot_sop_prefphase(b, stats, ModelSpec);phi0— phase eval points (500 evenly from −π to π)sop0— SOP eval points (510 evenly from −5 to 30)sop_pp_mat— spindle-rate heatmap over (phi0, sop)
Figure 2: Phase Shift: Stage vs. SO Power
Spindles tend to occur at the SO peak (phase ~0) during light sleep, and the preferred phase shifts earlier to the SO rising phase in deeper sleep for this participant.
If the model is correct, the time-rescaling theorem maps event times into a homogeneous Poisson process. After rescaling, Kolmogorov-Smirnov (KS) plots compare the inter-spindle-interval distribution to the model prediction. A well-fit model's KS plot follows the 45° line within its significance bounds (black). Curves outside these bounds (red) indicate lack-of-fit.
[ks, ksT] = KSplot(CIF, y, ploton);CIF— conditional intensity functiony— binary event trainploton— if 1, plotks— KS statisticksT— 0 = passes KS test, 1 = fails
Figure 3: KS plot for models with different components
The stage-only or phase-only models fail the KS test. A single-history-component model passes it, and the full all-factors model achieves an even smaller KS statistic.
The framework allows quantitative comparison of relative contributions via deviance analysis — the point-process equivalent of ANOVA in linear regression. compute_dev_exp.m computes proportional deviance explained by each factor:
[dev_exp_sta, dev_exp_sop] = compute_dev_exp(BinData);dev_exp_sta— deviance explained from[stage, phase, history]dev_exp_sop— deviance explained from[SOP, phase, history]
Figure 4: Proportional Deviance Explained By Different Factors
The history component explains the most deviance, surpassing sleep stage and SO phase.
Spindles are treated as a marked point process. The conditional intensity function λ(t | History, Covariates) gives the instantaneous spindle rate given past spindle times and covariate values. For each participant:
log λ(t) = β₀ + β_stage · stage(t) + β_SOP · SOP(t) + β_SOφ · f(SO_phase(t)) + β_hist · h(history(t))
where f(SO_phase) and h(history) are basis expansions (spline / indicator functions).
The history function h(·) reveals each participant's characteristic timing structure:
- Refractory period —
exp(β_hist · h(τ)) < 1at lag τ (suppressed rate) - Excitatory period —
exp(β_hist · h(τ)) > 1at lag τ (elevated rate) - Infraslow clustering — extending the history window to ~90 s reveals a secondary bump around ~55 s in some participants
KSplot.m produces the time-rescaled KS diagnostic. After time-rescaling under the fitted model, inter-spindle intervals should be uniformly distributed. Deviations from the KS confidence bands indicate model misspecification.
compute_dev_exp.m compares nested models (e.g., stage-only vs stage+SOP vs stage+SOP+SO_phase vs stage+SOP+SO_phase+history). The paper shows that adding history produces by far the largest deviance-explained improvement.
The toolbox is organized as follows, with key functions:
.REPO_ROOT
├── quick_start.m Quick-start GUI for overview figure exploration
├── Example_Script.m Main script, from raw data to model results and visualizations
│ Uses example data in example_data/
├── example_data/ Example data
├── image_folder/ Saved figures
└── helper_function/ Helper functions and vendored toolboxes
├── major_function/
│ specify_mdl.m Model specifications
│ preprocessToDesignMatrix.m Data preprocessing
│ plot_hist_curve.m History modulation curve
│ plot_stage_prefphase.m SO preferred phase as a function of sleep stage
│ plot_sop_prefphase.m SO preferred phase as a function of SO power
│ KSplot.m KS statistics, plot, and test
│ compute_dev_exp.m Proportional deviance explained
│
├── TFsigma_peak_detector/ Spindle detection algorithm (TF-peak)
├── multitaper/ Multitaper spectrogram toolbox (vendored)
└── utils/ Various utility functions
- Wamsley et al. — 17 healthy controls (ages 26–45), two-night recordings
- MESA (Multi-Ethnic Study of Atherosclerosis) — 1,008 participants, single-night recordings
- Middle-aged group: 433 participants (ages 54–65)
- Older group: 575 participants (ages 66–94)
Both datasets are external. The example_data/ folder provides a small single-subject demo for getting started.
Full API reference: https://preraulab.github.io/Spindle_dynamics_toolbox/
The code in this repository is companion to the paper:
Shuqiang Chen, Mingjian He, Ritchie E. Brown, Uri T. Eden, Michael J. Prerau. "Individualized temporal patterns drive human sleep spindle timing." Proceedings of the National Academy of Sciences, 122(2): e2405276121 (2025). doi: 10.1073/pnas.2405276121
which should be cited for all use.
BSD 3-Clause. See LICENSE.
All implementations are functional but subject to refinement. Next optimization: deal with perfect predictors (e.g., Wake and REM) to save runtime.
Last updated by Shuqiang Chen, 02/11/2025
For questions or suggestions please email Shuqiang Chen at shuqiang@bu.edu





