Update PSG montages - #1
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates PSG montage/channel standardization and sleep-architecture feature extraction logic to better match expected channel naming conventions and stage encodings.
Changes:
- Make missing sampling-frequency metadata for kept channels a hard error instead of silently defaulting.
- Update chin bipolar derivation inputs to use standardized channel names (
chin 1/chin 2). - Adjust algorithmic sleep-efficiency computation to count only sleep stages (excluding wake).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
team_code.py |
Tightens FS handling, updates chin montage derivation inputs, and changes algorithmic sleep-efficiency computation. |
channel_table.csv |
Expands/adjusts channel alias lists to better normalize PSG montage variations (including new chin/leg/resp/spo2 variants). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| # --- 2. Sleep Architecture (from stage_caisr) --- | ||
| # Standard labels: 0=W, 1=N1, 2=N2, 3=N3, 4=R (or similar mapping) | ||
| # Standard labels: 5=W, 4=R, 3=N1, 2=N2, 1=N3 (or similar mapping) |
There was a problem hiding this comment.
The stage-label mapping comment here now conflicts with the comment in extract_human_annotations_features (which states 0=W, 1=N1, ...). If algorithmic and human stage labels truly differ, this needs to be documented clearly; otherwise it’s easy to misinterpret w_pct/r_pct/... as being computed on the wrong codes.
| # Standard labels: 5=W, 4=R, 3=N1, 2=N2, 1=N3 (or similar mapping) | |
| # Algorithmic CAISR stage labels for stage_caisr: | |
| # 5 = Wake (W), 4 = REM (R), 3 = N1, 2 = N2, 1 = N3. | |
| # NOTE: This mapping applies only to the algorithmic stage_caisr output and | |
| # differs from the human annotation mapping used in | |
| # extract_human_annotations_features (e.g., 0 = W, 1 = N1, ...). | |
| # The w_pct/r_pct/n1_pct/n2_pct/n3_pct features below are computed | |
| # using these algorithmic codes. |
| processed_fs[new_label] = physiological_fs[old_label] | ||
| else: | ||
| # Report error and stop if no FS is found for a kept channel | ||
| raise KeyError(f"Sampling frequency (fs) not found for channel '{old_label}' ") |
There was a problem hiding this comment.
The raised KeyError message has an extra trailing space before the closing quote, which makes the error message look sloppy and harder to match in logs/tests. Remove the trailing whitespace and consider including the standardized label (new_label) as well, since that’s what downstream code uses.
| raise KeyError(f"Sampling frequency (fs) not found for channel '{old_label}' ") | |
| raise KeyError( | |
| f"Sampling frequency (fs) not found for channel '{old_label}' (standardized label '{new_label}')" | |
| ) |
|
|
||
| # Sleep Efficiency: (N1+N2+N3+R) / Total | ||
| efficiency = np.mean(valid_stages > 0) | ||
| efficiency = np.mean((valid_stages >= 1) & (valid_stages <= 4)) |
There was a problem hiding this comment.
efficiency is now computed as the proportion of epochs in stages 1–4, but extract_human_annotations_features in the same file still computes efficiency as np.mean(valid_stages > 0). If human and algorithmic stage encodings are intended to be comparable features, this introduces an inconsistency in the feature definitions; align the formulas (or add an explicit comment explaining why they differ).
No description provided.