Wieler Vermogensformules
Wiskundige Fundering van Bike Analytics Metrieken
Implementatiegids
Deze pagina biedt copy-paste formules en stapsgewijze berekeningsmethoden voor alle Bike Analytics metrieken. Gebruik deze voor eigen implementaties, verificatie of dieper begrip van op vermogen gebaseerde training.
⚠️ Implementatie Notities
- Alle vermogenswaarden in watts (W), tijd in seconden tenzij anders aangegeven
- FTP en CP zijn individuele drempelwaarden—geen universele waarden
- Valideer invoer altijd op redelijke bereiken (0-2000W typisch)
- Handel randgevallen af (delen door nul, negatief vermogen)
- Vermogensdata vereist 1-seconde registratie-intervallen voor nauwkeurigheid
Kern Prestatie Metrieken
1. Training Stress Score (TSS)
Formule:
Uitgewerkt Voorbeeld:
Scenario: 2 uur rit, NP = 235W, FTP = 250W
- Bereken IF: IF = 235 / 250 = 0.94
- Duur in seconden: 2 uur × 3600 = 7200 seconden
- TSS = (7200 × 235 × 0.94) / (250 × 3600) × 100
- TSS = 1,590,720 / 900,000 × 100 = 176.7 TSS
Interpretatie: Zware trainingsrit (>150 TSS), verwacht 2-3 dagen herstel
JavaScript Implementatie:
function calculateTSS(durationSeconds, normalizedPower, ftp) {
const intensityFactor = normalizedPower / ftp;
const tss = (durationSeconds * normalizedPower * intensityFactor) / (ftp * 3600) * 100;
return Math.round(tss);
}
// Voorbeeld gebruik:
const tss = calculateTSS(7200, 235, 250);
// Geeft: 177
2. Normalized Power (NP)
Algoritme (30-seconden voortschrijdend gemiddelde):
Waarom de 4e Macht?
De kwartische (4e macht) relatie weerspiegelt de niet-lineaire fysiologische kosten van variabele inspanningen. Een rit met surges en herstel kost meer energie dan steady vermogen bij hetzelfde gemiddelde.
Voorbeeld:
- Steady rit: 200W voor 1 uur → NP = 200W, Gemiddelde = 200W
- Variabele rit: Afwisselend 300W/100W → Gemiddelde = 200W, NP = 225W
Zelfde gemiddelde vermogen, maar variabele rit heeft 12% hogere NP door fysiologische kosten van surges
JavaScript Implementatie:
function calculateNormalizedPower(powerData) {
// powerData is array van 1-seconde vermogenswaarden
// Stap 1: Bereken 30-seconden voortschrijdende gemiddelden
const rollingAvgs = [];
for (let i = 29; i < powerData.length; i++) {
const window = powerData.slice(i - 29, i + 1);
const avg = window.reduce((sum, p) => sum + p, 0) / 30;
rollingAvgs.push(avg);
}
// Stap 2: Verhef tot 4e macht
const powered = rollingAvgs.map(p => Math.pow(p, 4));
// Stap 3: Gemiddelde van 4e machten
const avgPowered = powered.reduce((sum, p) => sum + p, 0) / powered.length;
// Stap 4: Neem 4e machtswortel
const np = Math.pow(avgPowered, 0.25);
return Math.round(np);
}
// Voorbeeld gebruik:
const powerData = [/* 1-seconde vermogensarray */];
const np = calculateNormalizedPower(powerData);
// Geeft: NP in watts
3. Intensity Factor (IF)
Formule:
Interpretatie Bereiken:
| IF Bereik | Inspanningsniveau | Voorbeeld Workout |
|---|---|---|
| < 0.75 | Herstel / Gemakkelijk | Actieve herstelrit, Zone 1-2 |
| 0.75 - 0.85 | Duur | Lange rustige rit, aerobe basis |
| 0.85 - 0.95 | Tempo | Sweet spot training, tempo intervallen |
| 0.95 - 1.05 | Drempel | FTP intervallen, tijdrit inspanning |
| 1.05 - 1.15 | VO₂max | 5-minuten intervallen, criterium race |
| > 1.15 | Anaeroob | Korte sprints, aanvallen, MTB bursts |
Voorbeeld Berekening:
Scenario: NP = 235W, FTP = 250W
IF = 235 / 250 = 0.94
Interpretatie: Hoog tempo / sub-drempel inspanning, vol te houden voor 2-3 uur
function calculateIF(normalizedPower, ftp) {
return (normalizedPower / ftp).toFixed(2);
}
// Voorbeeld:
const if_value = calculateIF(235, 250);
// Geeft: 0.94
4. Variability Index (VI)
Formule:
Interpretatie per Discipline:
| Discipline | Typische VI | Betekenis |
|---|---|---|
| Weg Tijdrit / Vlakke Rit | 1.00 - 1.05 | Zeer consistent vermogen, optimale pacing |
| Wegwedstrijd | 1.05 - 1.10 | Enige surges, over het algemeen stabiel |
| Criterium | 1.10 - 1.20 | Frequente acceleraties en aanvallen |
| Mountainbike XC | 1.15 - 1.30+ | Zeer variabel, constante surges |
Voorbeeld Berekening:
Wegwedstrijd: NP = 240W, Gem. Vermogen = 230W
VI = 240 / 230 = 1.04 (stabiele pacing)
MTB Race: NP = 285W, Gem. Vermogen = 235W
VI = 285 / 235 = 1.21 (zeer variabel, burst inspanningen)
function calculateVI(normalizedPower, averagePower) {
return (normalizedPower / averagePower).toFixed(2);
}
// Voorbeeld:
const vi_road = calculateVI(240, 230); // Geeft: 1.04
const vi_mtb = calculateVI(285, 235); // Geeft: 1.21
Critical Power & W' (Anaerobe Capaciteit)
5. Critical Power (CP) - Lineair Model
Formule:
Berekening uit Meerdere Inspanningen:
Vereist 2-4 maximale inspanningen op verschillende duren (bijv. 3, 5, 12, 20 minuten)
Voorbeeld Data:
| Duur | Vermogen (W) | Totaal Werk (kJ) |
|---|---|---|
| 3 min (180s) | 400W | 72 kJ |
| 5 min (300s) | 365W | 109.5 kJ |
| 12 min (720s) | 310W | 223.2 kJ |
| 20 min (1200s) | 285W | 342 kJ |
Gebruik lineaire regressie (Werk = CP × Tijd + W'):
- CP = 270W (helling van regressielijn)
- W' = 18.5 kJ (y-as afsnijding)
JavaScript Implementatie:
function calculateCP_Linear(efforts) {
// efforts = [{duration: seconds, power: watts}, ...]
const times = efforts.map(e => e.duration);
const work = efforts.map(e => e.power * e.duration / 1000); // kJ
// Lineaire regressie: werk = CP * tijd + W'
const n = efforts.length;
const sumT = times.reduce((a, b) => a + b, 0);
const sumW = work.reduce((a, b) => a + b, 0);
const sumTW = times.reduce((sum, t, i) => sum + t * work[i], 0);
const sumTT = times.reduce((sum, t) => sum + t * t, 0);
const CP = (n * sumTW - sumT * sumW) / (n * sumTT - sumT * sumT);
const Wprime = (sumW - CP * sumT) / n;
return {
CP: Math.round(CP * 10) / 10, // watts
Wprime: Math.round(Wprime * 10) / 10 // kJ
};
}
// Voorbeeld gebruik:
const efforts = [
{duration: 180, power: 400},
{duration: 300, power: 365},
{duration: 720, power: 310},
{duration: 1200, power: 285}
];
const result = calculateCP_Linear(efforts);
// Geeft: { CP: 270.0, Wprime: 18.5 }
6. W' Balans (W'bal) - Differentiaalvergelijking Model
Formules:
W'exp(t) = ∫(P(t) - CP) dt
W'rec(t) = W' × (1 - e^(-t/τ))
en ΔCP = (CP - P(t))
Praktijkvoorbeeld:
Renner specificaties: CP = 270W, W' = 18.5 kJ
Scenario 1 - Harde Aanval:
- Renner sprint naar 400W voor 30 seconden
- W' verbruik: (400 - 270) × 30 = 3,900 J = 3.9 kJ
- W'bal resterend: 18.5 - 3.9 = 14.6 kJ
Scenario 2 - Herstel:
- Na aanval, zakt naar 200W (70W onder CP) voor 2 minuten
- ΔCP = 270 - 200 = 70W
- τ = 546 × e^(-0.01 × 70) + 316 = 588 seconden
- Herstel in 120s: 18.5 × (1 - e^(-120/588)) = 3.5 kJ hersteld
- Nieuwe W'bal: 14.6 + 3.5 = 18.1 kJ
JavaScript Implementatie:
function calculateWbalance(powerData, CP, Wprime) {
// powerData = array van {time: seconds, power: watts}
let wbal = Wprime * 1000; // Converteer naar joules
const wbalHistory = [];
for (let i = 1; i < powerData.length; i++) {
const dt = powerData[i].time - powerData[i-1].time;
const power = powerData[i].power;
if (power > CP) {
// Verbruik boven CP
const expenditure = (power - CP) * dt;
wbal -= expenditure;
} else {
// Herstel onder CP
const deltaCP = CP - power;
const tau = 546 * Math.exp(-0.01 * deltaCP) + 316;
const recovery = (Wprime * 1000 - wbal) * (1 - Math.exp(-dt / tau));
wbal += recovery;
}
// Zorg dat W'bal niet boven max of onder nul komt
wbal = Math.max(0, Math.min(wbal, Wprime * 1000));
wbalHistory.push({
time: powerData[i].time,
wbal: wbal / 1000, // kJ
percent: (wbal / (Wprime * 1000)) * 100
});
}
return wbalHistory;
}
// Voorbeeld gebruik:
const powerData = [
{time: 0, power: 200},
{time: 1, power: 210},
// ... rest van ritdata
];
const wbalHistory = calculateWbalance(powerData, 270, 18.5);
// Geeft array van W'bal waarden over tijd
Prestatie Management Grafiek (PMC)
7. CTL, ATL, TSB Berekeningen
Formules (Exponentieel Gewogen Voortschrijdende Gemiddelden):
Metriek Definities:
- CTL (Chronische Trainingsbelasting): 42-daags exponentieel gemiddelde - vertegenwoordigt conditie
- ATL (Acute Trainingsbelasting): 7-daags exponentieel gemiddelde - vertegenwoordigt vermoeidheid
- TSB (Training Stress Balans): Vorm = Conditie - Vermoeidheid
Uitgewerkt Voorbeeld (7-Daags Trainingsblok):
| Dag | TSS | CTL | ATL | TSB | Status |
|---|---|---|---|---|---|
| Ma | 100 | 75.0 | 80.0 | -5.0 | Trainen |
| Di | 50 | 74.4 | 75.7 | -1.3 | Herstel |
| Wo | 120 | 75.5 | 82.0 | -6.5 | Harde Training |
| Do | 0 | 73.7 | 70.3 | +3.4 | Rustdag |
| Vr | 80 | 73.8 | 71.7 | +2.1 | Gemiddeld |
| Za | 150 | 75.6 | 82.9 | -7.3 | Lange Rit |
| Zo | 40 | 74.8 | 76.8 | -2.0 | Herstel |
Vermogen-Gewicht & Klim Metrieken
8. Vermogen-Gewicht Ratio
Formule:
FTP W/kg Benchmarks:
| Niveau | Man W/kg | Vrouw W/kg | Categorie |
|---|---|---|---|
| Recreatief | 2.5 - 3.5 | 2.0 - 3.0 | Fitness fietser |
| Competitief | 3.5 - 4.5 | 3.0 - 4.0 | Cat 3-4, amateur racer |
| Geavanceerd | 4.5 - 5.5 | 4.0 - 5.0 | Cat 1-2, sterke amateur |
| Elite Amateur | 5.5 - 6.0 | 5.0 - 5.5 | Nationaal niveau |
| Professioneel | 6.0 - 7.0+ | 5.5 - 6.5+ | World Tour, Grand Tour GC |
9. VAM (Velocità Ascensionale Media)
Formule:
VAM Benchmarks:
| VAM (m/u) | Niveau | Voorbeeld |
|---|---|---|
| 600 - 900 | Recreatief | Clubfietser op lokale klim |
| 900 - 1200 | Competitief | Goede amateur op Alpe d'Huez |
| 1200 - 1500 | Elite Amateur | Nationale klimmer |
| 1500 - 1800 | Professioneel | World Tour knecht |
| > 1800 | Grand Tour Winnaar | Pogačar, Vingegaard op sleutelritten |