Skip to content

Effort: Edwards zones use %HRR instead of %HRmax; Banister uses the men's multiplier for women #2835

Open

Description

@yashkgp

StrainScorer.swift differs from two sources it cites (checked at main 8e4b0c1):

1. Edwards zones use %HRR; Edwards (1993) defines them on %HRmax.
With HRmax 190 / RHR 50, 133 bpm is zone 3 in Edwards (70 %HRmax) but zone 1 here (59 %HRR). If %HRR is intentional (WHOOP-style, see #2438), the header and ANALYTICS.md should call it an Edwards-style variant. Source: https://pmc.ncbi.nlm.nih.gov/articles/PMC9391561/

2. Banister uses the men's 0.64 multiplier for women.
Should be 0.64·e^(1.92x) for men and 0.86·e^(1.67x) for women (Morton, Fitz-Clarke & Banister 1990, https://pubmed.ncbi.nlm.nih.gov/2246166/). Small displayed impact (about +1 Effort point), because the ceiling uses the same 0.64. Experiment path only.

Minor:

  • ckWeights are the 60 s Cole–Kripke weights, applied here to 30 s epochs.
  • Walch 2019 is 3-class, not 4-class as ANALYTICS.md says.

Activity

  1. ryanbr commented on Oct 25, 2026

    @ryanbr
    Owner

    Checked all four against main. Two confirmed, one confirmed and worse than stated, one not reproduced. Naming the commit you read is what made this quick to verify, so thank you for that.

    1. Edwards zones on %HRR: CONFIRMED

    The code says it itself. The header reads "Edwards 1993 (5-zone TRIMP)" and describes the cut-offs as "1..5 at 50/60/70/80/90 %HRR", and the table is declared as "Edwards zone cut-offs as (%HRR threshold, weight)". Edwards defines them on %HRmax, so your 133 bpm example is right: zone 3 by the source, zone 1 as implemented.

    Your suggested remedy is the right one, and the reason is worth stating. Moving the thresholds to %HRmax would change every user's Effort number, which needs its own justification and field evidence rather than a citation repair. Naming it an Edwards-STYLE variant, in both the header and ANALYTICS.md, makes the deviation honest at no behavioural cost. %HRR is also the deliberate choice here, since the whole file is built on Karvonen reserve.

    2. Banister women's multiplier: CONFIRMED, including your impact estimate

    banisterBMen = 1.92 and banisterBWomen = 1.67 are both present and selected by sex, while banisterScale = 0.64 is a single constant used for everyone. So a woman gets the women's exponent with the men's coefficient, which is neither published pair.

    Your note that the displayed impact is about one point is also right, and the mechanism is exact: the scale cancels. It multiplies the per-sample rate, the sedentary floor subtracted from it, and banisterDailyCeiling, so it appears in the numerator and the denominator of the same ratio. The one place it does NOT cancel is the constant + 1.0 added to the denominator, which is why the residue is a point rather than the 34% the coefficients differ by.

    That makes this a correctness-of-citation matter on an experimental path rather than a scoring bug, which is the right order of priority but not a reason to leave it wrong.

    3. ckWeights as 60 s weights on 30 s epochs: NOT REPRODUCED

    The line directly above the constant reads "te Lindert 30 s Cole-Kripke weights [A₋₄..A₊₂]. SI = 0.001·Σ wᵢ·Aᵢ; sleep iff SI<1", and the values [106, 54, 58, 76, 230, 74, 67] with the 0.001 scale and the < 1 test are te Lindert and Van Someren's published 30-second rescaling, not Cole and Kripke's one-minute weights.

    So the epoch length and the weights agree. I suspect the name ckWeights is what reads wrong, since it carries the family name rather than the variant, and a rename would remove the trap for the next reader. If you have a source showing those seven values as a 60 s set, I would rather see it than assume the matter settled.

    4. Walch 2019 as 3-class: CONFIRMED, and it cuts the wrong way

    Walch et al. 2019 report a three-class task, wake/NREM/REM, at about 72%, alongside a separate two-class sleep/wake result near 90%. There is no four-class wake/light/deep/REM figure in it.

    Both ANALYTICS.md and SleepStager.swift say "The EEG-free 4-class ceiling is ~65-73% epoch agreement (Walch 2019)". The range is in the right neighbourhood for three-class work, which is presumably how it survived review, but the label is wrong.

    The consequence is not cosmetic, and it runs against this project's interest rather than for it: the sentence sits inside the honest-hedging paragraph whose next line is that light/deep separation is the weakest link. Citing a ceiling measured WITHOUT any light/deep separation makes that hedge weaker than the evidence warrants. The four-class task is harder than the one the number came from, so the real ceiling for what NOOP outputs is lower, not 65-73%.

    Sources: the paper is at https://academic.oup.com/sleep/article/42/12/zsz180/5549536 and a review putting average three-stage wearable accuracy at 69.7% is at https://pmc.ncbi.nlm.nih.gov/articles/PMC10948771/

    Where this leaves things

    Items 1, 2 and 4 are all real and all repairable without touching a scored number: two citation labels and one coefficient on an experimental path. Item 3 reads as a naming trap rather than a defect.

    I would rather land them as separate changes than as one tidy-up, because item 2 alters an output on the Banister path, however slightly, while 1 and 4 alter only words. Grouping them would mean one review covering both a behaviour change and a documentation repair, which is how the smaller half goes unexamined.

  2. bartmuskala commented on Oct 26, 2026

    @bartmuskala

    #2438 was referenced in item 1. Will this be addressed as well? Preparations have been made and we can proceed upon you feedback @ryanbr .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions