Nachtrust scoren
Het meten van je bioritme is iets waar ik van het begin van het project op in heb gezet. Ondertussen meet ik al een aantal weken mijn activiteit en slaap-waak ritme met behulp van een Fitbit. In dit artikel ga ik het hebben over wat ik met die data ga doen.
Zie ook de volgende artikelen: Meten van bioritme en Bioritme meten met Fitbit
De data
De data die ik uiteindelijk ga gebruiken is de slaap data van mijn Fitbit. In deze data in JSON heeft de onderstaande inhoud en structuur. Voor elke gemeten dag heb ik een bestand met data in dit format.
Data structuur
Sluiten
Sleep
[Voor elke keer dat je geslapen hebt die dag]
awakeCount
awakeDuration
awakeningsCount
dateOfSleep
duration
efficiency
isMainSleep
logId
minuteData
[Voor elke minuut van slaap]
dateTime
value
minutesAfterWakeup
minutesAsleep
minutesAwake
minutesToFallAsleep
restlessCount
restlessDuration
startTime
timeInBed
summary
totalMinutesAsleep
totalSleepRecords
totalTimeInBed
Wat zit er in?
Nu ik weet hoe de data gestructureerd is kan ik kijken wat er precies in zit. Een aantal dingen vallen mij direct op:
- Fitbit probeert te meten hoe wakker ik ben elke minuut.Ik heb het eerder in een gesprek met dr. M. Gordijn gehad over waarom dat niet betrouwbaar is. Dit wordt opgeslagen als niveau's van wakker zijn, er zijn geen tussenwaardes;
1 Diepe slaap
2 Lichte slaap
3 Wakker - Er is een efficiency waarde in %. Deze is waarschijnlijk even betrouwbaar als het bovenstaande. Een snelle berekening
= (totalTimeInBed / totalMinutesAsleep) * 100
laat zien dat deze waarde direct gebaseerd is op het bovenstaande en daarmee erg onbetrouwbaar. - De slaap start en -eind tijd zitten er allebei in, samen met slaap lengte in minuten. Met deze waardes kun je het slaap-waak ritme bepalen. Goed kijken naar de data leert mij dat de start tijd erg betrouwbaar is, de eindtijd echter minder. Dat heeft waarschijnlijk te maken met mijn gewoonte om 's ochtends in bed te blijven liggen als ik wakker ben geworden.
Ondanks dat de slaap niveau's waarschijnlijk niet erg betrouwbaar zijn vind ik het toch interessant genoeg om hier wat beter naar te kijken.
Visualiseren
Gebaseerd op bestaande slaap-waak ritme schema's heb ik een visualisatie in elkaar geknutseld met mijn data als input. Hoe roder hoe dieper ik slaap volgens Fitbit. De zwarte lijnen representeren 00:30—het moment waarop ik streef om te slapen—en 09:30—het moment waarop ik wakker wordt.
Ik kan inderdaad wel een aantal momenten er uit halen waar ik weet dat ik wakker was, bijvoorbeeld om naar de wc te gaan. Maar verder lijkt de slaap niveau data erg willekeurig en onbetekenisvol.
Wat wel heel erg opvalt is hoe onregelmatig mijn ritme is en dat het, op een paar uitzonderingen na, steeds stabieler lijkt te worden. Dat is iets dat ik ook ervaar, dus het is goed om te zien dat de data dat ook reflecteert.
Score
Naast elke nacht staat een score, hoe lager hoe beter. De score is als volgt opgebouwd weergegeven in versimpelde code:
// Bereken BedtijdScore
BedtijdScore = slaapStart - slaapStartTarget
if(BedtijdScore < 0)
BedtijdScore * -0.7
else
BedtijdScore * 1
// Bereken WakkerScore
WakkerScore = slaapEind - slaapEindTarget
if(WakkerScore < 0)
WakkerScore * -1
else
WakkerScore * 0.7
// Bereken DuurScore
DuurScore = slaapDuur - slaapDuurTarget
if(DuurScore < 0)
DuurScore * -1
else
DuurScore * 0.7
// Bereken EindScore, gebruik gewogen gemiddelde
EindScore = (BedtijdScore * 6) + (WakkerScore * 1) + (DuurScore * 3)
EindScore / (6 + 1 + 3)
Originele code (js/jQuery)
Sluiten
// Bedtime score
parse.score.bedTime = parse.time.startDeep.mfmn - p.target.bedTime.mfmn; // Perfect = 0
if (parse.score.bedTime < 0) parse.score.bedTime *= (-1 * p.scores.weighing.offset[1]); // Too early to bed
else parse.score.bedTime *= p.scores.weighing.offset[0]; // Too late to bed
// Waketime score
parse.score.wakeTime = parse.time.end.mfmn - p.target.wakeTime.mfmn; // Perfect = 0
if (parse.score.wakeTime < 0) parse.score.wakeTime *= (-1 * p.scores.weighing.offset[0]); // Up too early
else parse.score.wakeTime *= p.scores.weighing.offset[1]; // Up too late
// SleepDuration score
if (p.scores.fixedWake) {
// If calculate with alarm time as wake time
parse.score.sleepTime = (p.target.wakeTime.mfmn - parse.time.startDeep.mfmn) - p.target.sleepTime.m; // Perfect = 0
}
else {
// If calculate with fitbit wake time as wake time
parse.score.sleepTime = (parse.time.minutesAsleep - p.target.sleepTime.m);
}
if (parse.score.sleepTime < 0) parse.score.sleepTime *= (-1 * p.scores.weighing.offset[0]); // Too short
else parse.score.sleepTime *= p.scores.weighing.offset[1]; // Too long
// Global score
parse.score.night = (
( parse.score.bedTime * p.scores.weighing.bedTime ) +
( parse.score.wakeTime * p.scores.weighing.wakeTime ) +
( parse.score.sleepTime * p.scores.weighing.sleepTime )
);
// Devide by multiplier sum to make weighted average
parse.score.night /= p.scores.weighing.bedTime + p.scores.weighing.wakeTime + p.scores.weighing.sleepTime;
// Use multiplier so score fits in range
parse.score.night *= p.scores.multiplier;
//Reverse range. From [a,b] to [b,a]
parse.score.night = (parse.score.night * -1) + p.scores.range[1];
// Make sure score isn't below range minimum
if (parse.score.night < p.scores.range[0]) parse.score.night = p.scores.range[0];
// Round all scores
parse.score.night = round(parse.score.night, p.scores.decimals);
parse.score.sleepTime = round(parse.score.sleepTime, p.scores.decimals);
parse.score.bedTime = round(parse.score.bedTime, p.scores.decimals);
parse.score.wakeTime = round(parse.score.wakeTime, p.scores.decimals);
Oude berekening
Sluiten
BedtijdScore = slaapStart - slaapStartTarget
als(BedtijdScore < 0) BedtijdScore * -1
BedtijdScore / 10
WakkerScore = slaapEind - slaapEindTarget
als(WakkerScore < 0) WakkerScore * -1
WakkerScore / 10
DuurScore = slaapDuur - slaapDuurTarget
als(DuurScore < 0) DuurScore * -1
DuurScore / 10
EindScore = (BedtijdScore + WakkerScore + DuurScore) / 3
Later zal ik opnieuw naar deze scores kijken, vooral met het oog op welke factoren het belangrijkste moeten wegen. Daarnaast ga ik misschien nog een slaap efficiëntie score gebruiken in deze berekening.
Het doel van deze score is tweeledig: Kijken hoe goed je een specifieke nacht hebt geslapen en kijken hoe stabiel je bioritme is. Voor deze laatste heb ik nog geen berekening.
Update
Ik heb nogmaals gekeken naar de berekeningen. De bovenstaande berekeningen zijn geupdate. Ik heb besloten om de efficientie data niet te gebruiken, omdat het niet betrouwbaar genoeg is. Verder gebruik ik nu een gewogen gemiddelde in plaats van een gelijkwaardig gemiddelde. Hierdoor kan ik minder betrouwbare data minder belangrijk maken in de berekening.
Ook heb ik in de berekening van BedtijdScore
, WakkerScore
en DuurScore
een wegingfactor toegevoegd om oa. eerder naar bed gaan minder te bestraffen dan later naar bed gaan.
Ten slotte heb ik een berekening gemaakt voor de BioritmeScore
. Deze score is als volgt opgebouwd:
// Pak alle eindscores van de afgelopen 7 nachten en maak gewogen gemiddelde
BioritmeScore = (
(EindScore[vandaag] * 1.00) +
(EindScore[vandaag-1] * 0.79) +
(EindScore[vandaag-2] * 0.60) +
(EindScore[vandaag-3] * 0.44) +
(EindScore[vandaag-4] * 0.31) +
(EindScore[vandaag-5] * 0.20) +
(EindScore[vandaag-6] * 0.11)
)
BioritmeScore / (1.00 + 0.79 + 0.60 + 0.44 + 0.31 + 0.20 + 0.11)
De weging factoren volgen uit de volgende exponentiele vergelijking: y = (1/81) * (x+2)^2
waar 1 ≤ x ≤ 7
.
Andere visualisaties
Ik ben van plan om andere visualisaties te maken gebaseerd op de berekeningen die ik nu heb gedaan. Ik heb al stappen genomen om dat technisch voor elkaar te krijgen. Denk hierbij bijvoorbeeld aan een goed beeld van het verloop over tijd van de verschillende scores.
Update: Nacht- & ritme score
Deze visualisatie geeft de score van een enkele nacht (grijs) en van de afgelopen 7 nachten (gekleurd). Anders dan de eerder getoonde visualisatie is dit veel meer hoe de gebruiker het uiteindelijk zal zien.
De kleuren worden als volgt bepaald:
if(score < 6)
Kleur = Rood
if(score >= 6)
Kleur = Oranje
if(score >= 8)
Kleur = Groen