psgscoring 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- psgscoring-0.2.0/LICENSE +28 -0
- psgscoring-0.2.0/PKG-INFO +372 -0
- psgscoring-0.2.0/README.md +336 -0
- psgscoring-0.2.0/psgscoring/__init__.py +34 -0
- psgscoring-0.2.0/psgscoring/_arousal.py +898 -0
- psgscoring-0.2.0/psgscoring/_core.py +2421 -0
- psgscoring-0.2.0/psgscoring.egg-info/PKG-INFO +372 -0
- psgscoring-0.2.0/psgscoring.egg-info/SOURCES.txt +12 -0
- psgscoring-0.2.0/psgscoring.egg-info/dependency_links.txt +1 -0
- psgscoring-0.2.0/psgscoring.egg-info/requires.txt +12 -0
- psgscoring-0.2.0/psgscoring.egg-info/top_level.txt +1 -0
- psgscoring-0.2.0/pyproject.toml +52 -0
- psgscoring-0.2.0/setup.cfg +4 -0
- psgscoring-0.2.0/tests/test_psgscoring.py +539 -0
psgscoring-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Bart Rombaut / Slaapkliniek AZORG
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer.
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
15
|
+
may be used to endorse or promote products derived from this software
|
|
16
|
+
without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
21
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
22
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
23
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
24
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
25
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
26
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
27
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
28
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: psgscoring
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: AASM 2.6-compliant respiratory event scoring for polysomnography
|
|
5
|
+
Author-email: Bart Rombaut <bart@slaapkliniek.be>
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/bartromb/psgscoring
|
|
8
|
+
Project-URL: Documentation, https://psgscoring.readthedocs.io
|
|
9
|
+
Project-URL: Repository, https://github.com/bartromb/psgscoring
|
|
10
|
+
Keywords: polysomnography,sleep,apnea,hypopnea,AASM,respiratory,scoring,signal-processing,PSG
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: numpy>=1.22
|
|
26
|
+
Requires-Dist: scipy>=1.8
|
|
27
|
+
Requires-Dist: mne>=1.0
|
|
28
|
+
Provides-Extra: full
|
|
29
|
+
Requires-Dist: yasa>=0.6; extra == "full"
|
|
30
|
+
Requires-Dist: reportlab; extra == "full"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
|
+
Requires-Dist: flake8; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# psgscoring
|
|
38
|
+
|
|
39
|
+
**AASM 2.6-compliant respiratory event scoring for polysomnography.**
|
|
40
|
+
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
[](CHANGES.md)
|
|
43
|
+
[](pyproject.toml)
|
|
44
|
+
[](tests/)
|
|
45
|
+
[](https://aasm.org)
|
|
46
|
+
[]()
|
|
47
|
+
|
|
48
|
+
A Python library implementing validated signal processing algorithms for automated detection of apneas, hypopneas, arousals, periodic limb movements, and SpO2 desaturations from standard PSG recordings.
|
|
49
|
+
|
|
50
|
+
No deep learning. No GPU. Pure signal processing with `scipy` and `numpy`.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install psgscoring
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or from source:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/bartromb/psgscoring.git
|
|
62
|
+
cd psgscoring
|
|
63
|
+
pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Dependencies:** `numpy>=1.22`, `scipy>=1.8`, `mne>=1.0`
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import mne
|
|
72
|
+
from psgscoring import run_full_analysis
|
|
73
|
+
|
|
74
|
+
# Load PSG recording
|
|
75
|
+
raw = mne.io.read_raw_edf("recording.edf", preload=True)
|
|
76
|
+
|
|
77
|
+
# Sleep stages from YASA or manual scoring (one label per 30s epoch)
|
|
78
|
+
hypno = ["W", "N1", "N2", "N2", "N3", "N3", "N2", "R", ...]
|
|
79
|
+
|
|
80
|
+
# Run full analysis
|
|
81
|
+
results = run_full_analysis(raw, hypno)
|
|
82
|
+
|
|
83
|
+
# Access results
|
|
84
|
+
ahi = results["respiratory"]["summary"]["ahi_total"]
|
|
85
|
+
oahi = results["respiratory"]["summary"]["oahi"]
|
|
86
|
+
odi = results["spo2"]["summary"]["odi"]
|
|
87
|
+
plmi = results["plm"]["summary"]["plm_index"]
|
|
88
|
+
|
|
89
|
+
print(f"AHI: {ahi:.1f}, OAHI: {oahi:.1f}, ODI: {odi:.1f}, PLMI: {plmi:.1f}")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Individual Functions
|
|
93
|
+
|
|
94
|
+
Each algorithm can be used independently:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import numpy as np
|
|
98
|
+
from psgscoring import (
|
|
99
|
+
linearize_nasal_pressure,
|
|
100
|
+
compute_mmsd,
|
|
101
|
+
preprocess_flow,
|
|
102
|
+
compute_dynamic_baseline,
|
|
103
|
+
detect_breaths,
|
|
104
|
+
compute_flattening_index,
|
|
105
|
+
bandpass_flow,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Load nasal pressure channel
|
|
109
|
+
nasal = raw.get_data(picks=["NasalPressure"])[0]
|
|
110
|
+
sf = raw.info["sfreq"] # e.g. 256 Hz
|
|
111
|
+
|
|
112
|
+
# 1. Linearize nasal pressure (Monserrat/Thurnheer)
|
|
113
|
+
nasal_lin = linearize_nasal_pressure(nasal)
|
|
114
|
+
|
|
115
|
+
# 2. Compute flow envelope
|
|
116
|
+
envelope = preprocess_flow(nasal, sf, is_nasal_pressure=True)
|
|
117
|
+
|
|
118
|
+
# 3. Dynamic baseline
|
|
119
|
+
baseline = compute_dynamic_baseline(envelope, sf)
|
|
120
|
+
|
|
121
|
+
# 4. Normalized flow (1.0 = normal, 0.0 = apnea)
|
|
122
|
+
flow_norm = np.clip(envelope / baseline, 0, 2)
|
|
123
|
+
|
|
124
|
+
# 5. MMSD for drift-independent validation
|
|
125
|
+
filtered = bandpass_flow(nasal_lin, sf)
|
|
126
|
+
mmsd = compute_mmsd(filtered, sf)
|
|
127
|
+
|
|
128
|
+
# 6. Breath-by-breath analysis
|
|
129
|
+
breaths = detect_breaths(filtered, sf)
|
|
130
|
+
for b in breaths[:5]:
|
|
131
|
+
fi = compute_flattening_index(b["insp_segment"])
|
|
132
|
+
print(f" Breath at {b['onset_s']:.1f}s, amp={b['amplitude']:.3f}, flat={fi:.2f}")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Algorithms
|
|
138
|
+
|
|
139
|
+
### A. Square-Root Linearization of Nasal Pressure
|
|
140
|
+
|
|
141
|
+
**Problem:** Nasal pressure transducers produce a signal proportional to flow² (Bernoulli's principle). A 50% flow reduction appears as a 75% amplitude reduction in the raw signal → systematic overestimation of hypopneas.
|
|
142
|
+
|
|
143
|
+
**Solution:**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
x_lin(t) = sign(x(t)) × √|x(t)|
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Applied before bandpass filtering, exclusively on the nasal pressure channel (hypopnea detection), not on the thermistor (apnea detection). This preserves the AASM dual-sensor paradigm.
|
|
150
|
+
|
|
151
|
+
**Function:** `linearize_nasal_pressure(data) → ndarray`
|
|
152
|
+
|
|
153
|
+
**References:**
|
|
154
|
+
- Thurnheer R, Xie X, Bloch KE. *Accuracy of nasal cannula pressure recordings for assessment of ventilation during sleep.* Am J Respir Crit Care Med. 2001;164(10):1914-1919. — Confirmed r²=0.88–0.96 vs pneumotachography.
|
|
155
|
+
- Montserrat JM, et al. *Effectiveness of CPAP treatment in daytime function in sleep apnea syndrome.* Am J Respir Crit Care Med. 2001;164(4):608-613.
|
|
156
|
+
- AASM Scoring Manual v2.6 Rule 3: *"nasal pressure transducer (with or without square root transformation of the signal)"*
|
|
157
|
+
|
|
158
|
+
### B. MMSD Apnea Validation
|
|
159
|
+
|
|
160
|
+
**Problem:** During long recordings, baseline drift from sensor displacement or mouth breathing creates false amplitude drops that the envelope method misinterprets as apneas.
|
|
161
|
+
|
|
162
|
+
**Solution:** The Mean Magnitude of Second Derivative (MMSD) measures the "sharpness" of the flow waveform — independent of absolute amplitude and drift:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
MMSD(t) = (1/N) × Σ |x''(i)| over 1-second window
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Active breathing has high MMSD (sharp wave transitions). True apnea has near-zero MMSD. If normalized MMSD > 40% of baseline during a candidate apnea, respiratory activity is still present → false positive rejected.
|
|
169
|
+
|
|
170
|
+
**Function:** `compute_mmsd(flow_data, sf, window_s=1.0) → ndarray`
|
|
171
|
+
|
|
172
|
+
**Reference:**
|
|
173
|
+
- Lee H, Park J, Kim H, Lee K-J. *Detection of apneic events from single channel nasal airflow using 2nd derivative method.* Physiol Meas. 2008;29:N37-N45. — 92% agreement with manual scoring (κ=0.78) on 24 PSG recordings.
|
|
174
|
+
|
|
175
|
+
### C. Dual-Sensor Detection (AASM 2.6)
|
|
176
|
+
|
|
177
|
+
The AASM recommends different sensors for different event types:
|
|
178
|
+
|
|
179
|
+
| Sensor | Role | Threshold |
|
|
180
|
+
|--------|------|-----------|
|
|
181
|
+
| Oronasal thermistor | Apnea (cessation) | < 10% baseline, ≥10s |
|
|
182
|
+
| Nasal pressure (√-linearized) | Hypopnea (partial) | 10–70% baseline, ≥10s |
|
|
183
|
+
|
|
184
|
+
**Apnea–Hypopnea Exclusion Mask:** After apnea detection, a ±5s margin around each apnea is masked out before hypopnea labeling, preventing double-counting of apnea flanks.
|
|
185
|
+
|
|
186
|
+
**Apnea Type Classification** uses four-step effort analysis on thoracic/abdominal RIP:
|
|
187
|
+
1. Amplitude ratio vs baseline (>40% = obstructive, <20% = central)
|
|
188
|
+
2. Coefficient of variation (paradoxical breathing)
|
|
189
|
+
3. Cross-correlation thorax–abdomen (out-of-phase = obstructive)
|
|
190
|
+
4. First/second half comparison (mixed event detection)
|
|
191
|
+
|
|
192
|
+
**Function:** `detect_respiratory_events(flow_data, thorax_data, abdomen_data, spo2_data, sf_flow, sf_spo2, hypno, ...) → dict`
|
|
193
|
+
|
|
194
|
+
**Reference:**
|
|
195
|
+
- Berry RB, et al. *The AASM Manual for the Scoring of Sleep and Associated Events.* Version 2.6. AASM; 2020.
|
|
196
|
+
|
|
197
|
+
### D. Temporally Constrained SpO2 Coupling
|
|
198
|
+
|
|
199
|
+
A hypopnea requires ≥3% SpO2 desaturation (Rule 1A) or an arousal (Rule 1B).
|
|
200
|
+
|
|
201
|
+
**Improvements over naive matching:**
|
|
202
|
+
- **Baseline:** 90th percentile of 120s pre-event SpO2 (or global sleep baseline if local is depressed during cluster apneas)
|
|
203
|
+
- **Nadir window:** Event onset → 30s post-event (reduced from 45s)
|
|
204
|
+
- **Temporal validation:** Nadir must fall ≥3s after event onset (circulatory delay). Early nadirs with small desaturation (<5%) are rejected as coincidental.
|
|
205
|
+
|
|
206
|
+
**Reference:**
|
|
207
|
+
- Uddin MB, Chow CM, Ling SH, Su SW. *A novel algorithm for automatic diagnosis of sleep apnea from airflow and oximetry signals.* Physiol Meas. 2021;42:015001.
|
|
208
|
+
|
|
209
|
+
### E. Two-Pass Rule 1B (Arousal Criterion)
|
|
210
|
+
|
|
211
|
+
**Novel approach:** Hypopnea candidates without ≥3% desaturation are stored as *rejected candidates* (not discarded). After arousal detection completes in a later pipeline stage, candidates are re-evaluated. An arousal within 15s of event termination → event reinstated as Rule 1B hypopnea with AHI recalculation.
|
|
212
|
+
|
|
213
|
+
**Function:** `reinstate_rule1b_hypopneas(rejected, arousal_events, resp_events, hypno) → (reinstated, updated_events)`
|
|
214
|
+
|
|
215
|
+
### F. Breath-by-Breath Analysis
|
|
216
|
+
|
|
217
|
+
Zero-crossing segmentation of bandpass-filtered flow (1–15s per breath cycle). Per breath:
|
|
218
|
+
- **Amplitude:** peak-to-trough distance (AASM definition)
|
|
219
|
+
- **Local baseline:** median of preceding 10 breaths
|
|
220
|
+
- **Flattening index:** fraction of inspiratory segment >80% of peak flow. Values >0.3 indicate flow limitation (relevant for RERA detection).
|
|
221
|
+
|
|
222
|
+
**Functions:** `detect_breaths()`, `compute_breath_amplitudes()`, `compute_flattening_index()`
|
|
223
|
+
|
|
224
|
+
### G. Cheyne-Stokes Respiration
|
|
225
|
+
|
|
226
|
+
Autocorrelation of very-low-frequency flow envelope (0.005–0.05 Hz, 20–200s periodicities). Peak correlation >0.3 in 40–120s lag range → periodic crescendo-decrescendo pattern. Clinical flag: association with heart failure (NYHA III–IV).
|
|
227
|
+
|
|
228
|
+
**Function:** `detect_cheyne_stokes(flow_env, sf, hypno) → dict`
|
|
229
|
+
|
|
230
|
+
### H. Two-Phase Arousal Detection
|
|
231
|
+
|
|
232
|
+
AASM-compliant spectral arousal detection with sigma-band spindle exclusion:
|
|
233
|
+
|
|
234
|
+
- **Phase 1:** Identify regions where combined arousal power (α_narrow 8–11Hz + θ 4–8Hz + β 16–30Hz) exceeds 2.0× per-stage baseline. Label contiguous segments ≥3s.
|
|
235
|
+
- **Phase 2:** Validate each candidate event:
|
|
236
|
+
- Pre-sleep: ≥60% of 10s pre-window is sleep
|
|
237
|
+
- Onset abruptness: first 1s power / 3s pre-power > 1.5×
|
|
238
|
+
- Spindle exclusion: reject if sigma >2× baseline AND arousal power < sigma
|
|
239
|
+
- REM EMG: EMG rise >2× baseline for ≥1s
|
|
240
|
+
|
|
241
|
+
**Function:** `detect_arousals(eeg_data, sf, hypno, emg_data=None) → dict`
|
|
242
|
+
|
|
243
|
+
### I. PLM Scoring (AASM 2.6)
|
|
244
|
+
|
|
245
|
+
- EMG ≥8µV above resting, 0.5–10s duration (auto V→µV conversion)
|
|
246
|
+
- Bilateral integration (±0.5s)
|
|
247
|
+
- Wake excluded; respiratory-associated (±0.5s of event end) excluded
|
|
248
|
+
- Series: ≥4 consecutive with 5–90s intervals
|
|
249
|
+
|
|
250
|
+
**Function:** `analyze_plm(leg_l, leg_r, sf, hypno, resp_events=None) → dict`
|
|
251
|
+
|
|
252
|
+
**Reference:**
|
|
253
|
+
- Zucconi M, et al. *WASM standards for recording and scoring PLM.* Sleep Med. 2006;7(2):175-183.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Output Structure
|
|
258
|
+
|
|
259
|
+
`run_full_analysis()` returns a dict:
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
{
|
|
263
|
+
"respiratory": {
|
|
264
|
+
"success": True,
|
|
265
|
+
"events": [
|
|
266
|
+
{"type": "obstructive", "onset_s": 1234.5, "duration_s": 15.2,
|
|
267
|
+
"stage": "N2", "desaturation_pct": 4.1, "min_spo2": 88.3, ...},
|
|
268
|
+
...
|
|
269
|
+
],
|
|
270
|
+
"summary": {
|
|
271
|
+
"ahi_total": 23.4,
|
|
272
|
+
"oahi": 20.1,
|
|
273
|
+
"central_index": 3.3,
|
|
274
|
+
"n_obstructive": 85,
|
|
275
|
+
"n_central": 14,
|
|
276
|
+
"n_mixed": 3,
|
|
277
|
+
"n_hypopnea": 65,
|
|
278
|
+
"severity": "moderate",
|
|
279
|
+
...
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
"spo2": {"summary": {"odi": 18.2, "mean_spo2": 93.1, "min_spo2": 71, ...}},
|
|
283
|
+
"plm": {"summary": {"plm_index": 8.3, "n_plm": 42, ...}},
|
|
284
|
+
"arousal": {"summary": {"arousal_index": 28.1, "n_respiratory_arousals": 45, ...}},
|
|
285
|
+
"cheyne_stokes": {"csr_detected": False, ...},
|
|
286
|
+
"position": {...},
|
|
287
|
+
"heart_rate": {...},
|
|
288
|
+
"snore": {...},
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Disclaimer
|
|
293
|
+
|
|
294
|
+
> **psgscoring is research software — not a medical device.**
|
|
295
|
+
>
|
|
296
|
+
> It is intended exclusively for use by qualified professionals (physicians,
|
|
297
|
+
> researchers, registered polysomnographic technologists) in a research or
|
|
298
|
+
> clinical research context. It has **not** been evaluated, cleared, or approved
|
|
299
|
+
> by the EU (MDR 2017/745), the U.S. FDA, or any equivalent regulatory authority.
|
|
300
|
+
> It does **not** carry a CE mark or FDA clearance.
|
|
301
|
+
>
|
|
302
|
+
> All computed indices (AHI, OAHI, ODI, PLMI, arousal index, RDI) are
|
|
303
|
+
> **research-grade estimates** that must be reviewed by a qualified clinician
|
|
304
|
+
> before any diagnostic or therapeutic decision. Automated sleep staging
|
|
305
|
+
> (~85% epoch agreement) does not meet the standard for unsupervised clinical use.
|
|
306
|
+
>
|
|
307
|
+
> A pilot validation study (target n=50) is in preparation. Until published,
|
|
308
|
+
> all results should be treated as provisional.
|
|
309
|
+
>
|
|
310
|
+
> See [DISCLAIMER.md](DISCLAIMER.md) for the full medical and clinical disclaimer.
|
|
311
|
+
|
|
312
|
+
## License
|
|
313
|
+
|
|
314
|
+
BSD-3-Clause — see [LICENSE](LICENSE).
|
|
315
|
+
|
|
316
|
+
## References
|
|
317
|
+
|
|
318
|
+
### Scoring guidelines
|
|
319
|
+
|
|
320
|
+
1. Berry RB, Quan SF, Abreu AR, et al. **The AASM Manual for the Scoring of Sleep and Associated Events: Rules, Terminology and Technical Specifications.** Version 2.6. American Academy of Sleep Medicine; 2020.
|
|
321
|
+
|
|
322
|
+
### Nasal pressure linearization
|
|
323
|
+
|
|
324
|
+
2. Thurnheer R, Xie X, Bloch KE. **Accuracy of nasal cannula pressure recordings for assessment of ventilation during sleep.** *Am J Respir Crit Care Med.* 2001;164(10):1914–1919. doi:10.1164/ajrccm.164.10.2101072
|
|
325
|
+
3. Montserrat JM, Farré R, Ballester E, et al. **Evaluation of nasal prongs for estimating nasal flow.** *Am J Respir Crit Care Med.* 1997;155(1):211–215. doi:10.1164/ajrccm.155.1.9001314
|
|
326
|
+
|
|
327
|
+
### MMSD apnea validation
|
|
328
|
+
|
|
329
|
+
4. Lee H, Park J, Kim H, Lee K-J. **New method for the detection of apneic events from nasal cannula pressure recordings using the second derivative.** *Comput Biol Med.* 2008;38:1105–1112. doi:10.1016/j.compbiomed.2008.08.007
|
|
330
|
+
|
|
331
|
+
### SpO2 desaturation coupling
|
|
332
|
+
|
|
333
|
+
5. Uddin MB, Chow CM, Ling SH, Su SW. **A novel algorithm for automatic diagnosis of sleep apnea from airflow and oximetry signals.** *Physiol Meas.* 2021;42:015001. doi:10.1088/1361-6579/abd47a
|
|
334
|
+
|
|
335
|
+
### PLM scoring
|
|
336
|
+
|
|
337
|
+
6. Zucconi M, Ferri R, Allen R, et al. **The official World Association of Sleep Medicine (WASM) standards for recording and scoring periodic leg movements in sleep (PLMS) and wakefulness (PLMW).** *Sleep Med.* 2006;7(2):175–183. doi:10.1016/j.sleep.2006.01.001
|
|
338
|
+
|
|
339
|
+
### Arousal scoring
|
|
340
|
+
|
|
341
|
+
7. Bonnet MH, Doghramji K, Roehrs T, et al. **The scoring of arousal in sleep: reliability, validity and alternatives.** *J Clin Sleep Med.* 2007;3(2):133–145. doi:10.5664/jcsm.26815
|
|
342
|
+
|
|
343
|
+
### Flattening index / flow limitation
|
|
344
|
+
|
|
345
|
+
8. Aittokallio T, Saaresranta T, Polo-Kantola P, et al. **Analysis of inspiratory flow shapes in patients with partial upper-airway obstruction during sleep.** *Chest.* 2001;119(1):37–44. doi:10.1378/chest.119.1.37
|
|
346
|
+
|
|
347
|
+
### Sleep staging (upstream)
|
|
348
|
+
|
|
349
|
+
9. Vallat R, Walker MP. **An open-source, high-performance tool for automated sleep staging.** *eLife.* 2021;10:e70092. doi:10.7554/eLife.70092
|
|
350
|
+
|
|
351
|
+
### Cheyne-Stokes respiration
|
|
352
|
+
|
|
353
|
+
10. Leung RST, Bradley TD. **Sleep apnea and cardiovascular disease.** *Am J Respir Crit Care Med.* 2001;164(12):2147–2165. doi:10.1164/ajrccm.164.12.2107045
|
|
354
|
+
|
|
355
|
+
## Citation
|
|
356
|
+
|
|
357
|
+
If you use psgscoring in published research, please cite:
|
|
358
|
+
|
|
359
|
+
```bibtex
|
|
360
|
+
@software{rombaut2026psgscoring,
|
|
361
|
+
author = {Rombaut, Bart},
|
|
362
|
+
title = {psgscoring: AASM 2.6-compliant respiratory event scoring for polysomnography},
|
|
363
|
+
year = {2026},
|
|
364
|
+
url = {https://github.com/bartromb/psgscoring},
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Acknowledgments
|
|
369
|
+
|
|
370
|
+
Sleep staging relies on [YASA](https://github.com/raphaelvallat/yasa) by Raphaël Vallat and Matthew P. Walker (*eLife*, 2021). Signal processing builds on [MNE-Python](https://mne.tools), [SciPy](https://scipy.org), and [NumPy](https://numpy.org).
|
|
371
|
+
|
|
372
|
+
Developed at Slaapkliniek AZORG, Aalst, Belgium.
|