Formules de Puissance en Cyclisme

Fondement Mathématique des Métriques Bike Analytics

Guide d'Implémentation

Cette page fournit des formules prêtes à copier-coller et des méthodes de calcul étape par étape pour toutes les métriques Bike Analytics. Utilisez-les pour des implémentations personnalisées, la vérification ou une compréhension approfondie de l'entraînement basé sur la puissance.

⚠️ Notes d'Implémentation

  • Toutes les valeurs de puissance en watts (W), temps en secondes sauf indication contraire
  • FTP et CP sont des seuils individuels—aucune valeur universelle
  • Toujours valider les entrées pour des plages raisonnables (0-2000W typique)
  • Gérer les cas limites (division par zéro, puissance négative)
  • Les données de puissance répétées des intervalles d'enregistrement de 1 seconde pour la précision

Vélo Métriques de Performance Essentielles

1. Training Stress Score (TSS)

Formule :

TSS = (durée_secondes × NP × IF) / (FTP × 3600) × 100
où IF = NP / FTP

Exemple Détaillé :

Scénario :Sortie de 2 heures, NP = 235W, FTP = 250W

  1. Calculateur IF : IF = 235 / 250 = 0.94
  2. Durée en secondes : 2 heures × 3600 = 7200 secondes
  3. TSS = (7200 × 235 × 0.94) / (250 × 3600) × 100
  4. TSS = 1,590,720 / 900,000 × 100 =176.7 TSS

Interprétation : Sortie d'entraînement difficile (>150 TSS), prévoir 2-3 jours de récupération

Implémentation JavaScript :

function calculateTSS(durationSeconds, normalizedPower, ftp) {
  const intensityFactor = normalizedPower / ftp;
  const tss = (durationSeconds * normalizedPower * intensityFactor) / (ftp * 3600) * 100;
  return Math.round(tss);
}

// Example usage:
const tss = calculateTSS(7200, 235, 250);
// Returns: 177

2. Puissance Normalisée (NP)

Algorithme (moyenne mobile de 30 secondes) :

1. Calculez la puissance moyenne de roulement sur 30 secondes pour l'ensemble du trajet
2. Augmentez chaque valeur de 30 secondes à la 4ème puissance
3. Faites la moyenne de toutes ces valeurs ^4
4. Prenez la 4ème racine de cette moyenne
NP = ⁴√ (moyenne de [30s_avg^4])

Pourquoi la Puissance 4 ?

La relation quartique (puissance 4) reflète le coût physiologique non linéaire des efforts variables. Une sortie avec des accélérations et des récupérations coûte plus d'énergie qu'une puissance constante à la même moyenne.

Exemple :

  • Sortie régulière : 200W pendant 1 heure → NP = 200W, Moyenne = 200W
  • Sortie variable : Alternance 300W/100W → Moyenne = 200W, NP = 225W

Même puissance moyenne, mais la sortie variable à un NP 12% plus élevé en raison du coût physiologique des accélérations

Implémentation JavaScript :

function calculateNormalizedPower(powerData) {
  // powerData is array of 1-second power values

  // Step 1: Calculate 30-second rolling averages
  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);
  }

  // Step 2: Raise to 4th power
  const powered = rollingAvgs.map(p => Math.pow(p, 4));

  // Step 3: Average of 4th powers
  const avgPowered = powered.reduce((sum, p) => sum + p, 0) / powered.length;

  // Step 4: Take 4th root
  const np = Math.pow(avgPowered, 0.25);

  return Math.round(np);
}

// Example usage:
const powerData = [/* 1-second power array */];
const np = calculateNormalizedPower(powerData);
// Returns: NP in watts

3. Facteur d'intensité (IF)

Formule :

PROTÉGER15X = NP / PROTÉGER10X

Plages d'Interprétation :

Plage IFNiveau d'EffortExemple d'Entraînement
< 0.75Récupération / FacileSortie de récupération active, Zone 1-2
0.75 - 0.85EnduranceLongue sortie régulière, base aérobie
0.85 - 0.95TempoEntraînement sweet spot, intervalles tempo
0.95 - 1.05SeuilIntervalles FTP, effort contre-la-montre
1.05 - 1.15VO₂maxIntervalles de 5 minutes, course de critérium
> 1.15AnaérobieSprints courts, attaques, accélérations VTT

Exemple de Calcul :

Scénario :NP = 235W, FTP = 250W

IF = 235 / 250 =0.94

Interprétation : Effort tempo élevé / sous-seuil, pendentif soutenable 2-3 heures

function calculateIF(normalizedPower, ftp) {
  return (normalizedPower / ftp).toFixed(2);
}

// Example:
const if_value = calculateIF(235, 250);
// Returns: 0.94

4.Indice de Variabilité (VI)

Formule :

VI = NP / Puissance moyenne

Interprétation par Discipline :

DisciplineVI TypiqueSignification
Route CLM / Effort Régulier1.00 - 1.05Puissance très constante, allure optimale
Course sur Route1.05 - 1.10Quelques accélérations, généralement régulières
Critérium1.10 - 1.20Accélérations et attaques fréquentes
VTT XC1.15 - 1.30+Très variable, accélérations constantes

Exemple de Calcul :

Course sur Route :NP = 240W, Puissance Moy = 230W

VI = 240 / 230 =1.04(allure régulière)

Course VTT :NP = 285W, Puissance Moy = 235W

VI = 285 / 235 =1.21(très variable, efforts par à-coups)

function calculateVI(normalizedPower, averagePower) {
  return (normalizedPower / averagePower).toFixed(2);
}

// Example:
const vi_road = calculateVI(240, 230);  // Returns: 1.04
const vi_mtb = calculateVI(285, 235);   // Returns: 1.21

Critical Power & W' (Capacité Anaérobie)

5. Critical Power (CP) - Modèle Linéaire

Formule :

Temps = W' / (Puissance - CP)
Réorganisé : Puissance × Temps = CP × Temps + W'

Calcul à Partir de Plusieurs Efforts :

Nécessite 2-4 efforts maximaux à différentes durées (par ex., 3, 5, 12, 20 minutes)

Exemple de Données :

DuréePuissance (W)Travail Total (kJ)
3 min (180s)400W72 kJ
5 min (300s)365W109,5 kJ
12 min (720s)310W223,2 kJ
20 min (1200s)285W342 kJ

En utilisant la régression linéaire (Travail = CP × Temps + W') :

  • CP = 270W(pente de la ligne de régression)
  • W' = 18.5 kJ(ordonnée à l'origine)

Implémentation JavaScript :

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

  // Linear regression: work = CP * time + 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
  };
}

// Example usage:
const efforts = [
  {duration: 180, power: 400},
  {duration: 300, power: 365},
  {duration: 720, power: 310},
  {duration: 1200, power: 285}
];

const result = calculateCP_Linear(efforts);
// Returns: { CP: 270.0, Wprime: 18.5 }

6. W' Balance (W'bal) - Modèle d'Équation Différentielle

Formules :

Dépense (quand P > CP) :
W'exp(t) = ∫(P(t) - CP) dt
Récupération (quand P < CP) :
W'rec(t) = W' × (1 - e^(-t/τ))
où τ = 546 × e^(-0,01 × ΔCP) + 316
et ΔCP = (CP - P(t))

Exemple Concret :

Caractéristiques du cycliste :CP = 270W, W' = 18.5 kJ

Scénario 1 - Attaque Difficile :

  • Le coureur accélère à 400W pendant 30 secondes
  • Dépense de W' : (400 - 270) × 30 = 3,900 J = 3.9 kJ
  • W'bal restant : 18.5 - 3.9 =14.6 kJ

Scénario 2 - Récupération :

  • Après l'attaque, redescend à 200W (70W sous CP) pendant 2 minutes
  • ΔCP = 270 - 200 = 70W
  • τ = 546 × e^(-0.01 × 70) + 316 = 588 secondes
  • Récupération en 120s : 18.5 × (1 - e^(-120/588)) =3.5 kJ récupérés
  • Nouveau W'bal : 14.6 + 3.5 =18.1 kJ

Implémentation JavaScript :

function calculateWbalance(powerData, CP, Wprime) {
  // powerData = array of {time: seconds, power: watts}
  let wbal = Wprime * 1000; // Convert to 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) {
      // Expenditure above CP
      const expenditure = (power - CP) * dt;
      wbal -= expenditure;
    } else {
      // Recovery below 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;
    }

    // Ensure W'bal doesn't exceed max or go negative
    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;
}

// Example usage:
const powerData = [
  {time: 0, power: 200},
  {time: 1, power: 210},
  // ... rest of ride data
];

const wbalHistory = calculateWbalance(powerData, 270, 18.5);
// Returns array of W'bal values over time

Tableau de gestion des performances (PMC) pour le cyclisme

7.Calculs CTL, ATL, TSB

Formules (Moyennes Mobiles Exponentiellement Pondérées) :

CTL_aujourd'hui = CTL_hier + (TSS_aujourd'hui - CTL_hier) / 42
ATL_aujourd'hui = ATL_hier + (TSS_aujourd'hui - ATL_hier) / 7
TSB_aujourd'hui = CTL_hier - ATL_hier

Définitions des Métriques :

  • CTL (Chronic Training Load) :Moyenne exponentiellement pondérée sur 42 jours - représente la forme
  • ATL (Acute Training Load) :Moyenne exponentiellement pondérée sur 7 jours - représente la fatigue
  • TSB (Training Stress Balance) :Forme = Condition - Fatigue

Exemple Détaillé (Bloc d'Entraînement de 7 Jours) :

JourTSSCTLATLTSBStatut
Lun10075.080.0-5.0Entraînement
Mar5074.475.7-1.3Récupération
Mer12075.582.0-6.5Entraînement Difficile
Jeu073.770.3+3.4Jour de Repos
Ven8073.871.7+2.1Modéré
Sam15075.682.9-7.3Longue Sortie
Dim4074.876.8-2.0Récupération

Interprétation TSB :

Plage TSBStatutAction
< -30Risque ÉlevéAlerte surentraînement - réduire la charge
-30 à -10Entraînement IntensifConstruction de forme, surveiller la récupération
-10 à +5OptimalZone d'entraînement normale
+5 à +15Prêt à CourirForme de pointe - courir ce week-end
> +25DésentraînementPerte de forme - augmenter la charge

Implémentation JavaScript :

function calculatePMC(workouts) {
  // workouts = [{date: "YYYY-MM-DD", tss: number}, ...]
  let ctl = 0, atl = 0;
  const results = [];

  workouts.forEach(workout => {
    // Update CTL (42-day time constant)
    ctl = ctl + (workout.tss - ctl) / 42;

    // Update ATL (7-day time constant)
    atl = atl + (workout.tss - atl) / 7;

    // Calculate TSB (yesterday's CTL - today's ATL for traditional calculation)
    // For simplicity here using current values
    const tsb = ctl - atl;

    results.push({
      date: workout.date,
      tss: workout.tss,
      ctl: Math.round(ctl * 10) / 10,
      atl: Math.round(atl * 10) / 10,
      tsb: Math.round(tsb * 10) / 10,
      status: getTSBStatus(tsb)
    });
  });

  return results;
}

function getTSBStatus(tsb) {
  if (tsb < -30) return "High Risk";
  if (tsb < -10) return "Training Hard";
  if (tsb < 5) return "Optimal";
  if (tsb < 15) return "Race Ready";
  return "Detraining";
}

// Example usage:
const workouts = [
  {date: "2025-01-01", tss: 100},
  {date: "2025-01-02", tss: 50},
  {date: "2025-01-03", tss: 120},
  // ... more workouts
];

const pmc = calculatePMC(workouts);
// Returns array with CTL, ATL, TSB for each day

Rapport Poids-Puissance & Métriques d'Ascension

8. Rapport Poids-Puissance

Formule :

W/kg = Puissance (watts) / Masse corporelle (kg)

Repères FTP W/kg :

NiveauHomme W/kgFemme W/kgCatégorie
Récréatif2.5 - 3.52.0 - 3.0Cycliste loisir
Compétitif3.5 - 4.53.0 - 4.0Cat 3-4, coureur par groupes d'âge
Avancé4.5 - 5.54.0 - 5.0Cat 1-2, amateur fort
Élite Amateur5.5 - 6.05.0 - 5.5Niveau national
Professionnel6.0 - 7.0+5.5 - 6.5+World Tour, Grand Tour GC

Exemple de Calcul :

Scénario :Cycliste avec FTP = 275W, masse corporelle = 70kg

W/kg = 275 / 70 =3.93 W/kg

Interprétation : Niveau officiel, capable en courses vallonnées

function calculateWattsPerKg(power, bodyMassKg) {
  return (power / bodyMassKg).toFixed(2);
}

// Example:
const wpkg = calculateWattsPerKg(275, 70);
// Returns: 3.93

9. VAM (Velocità Ascensionale Media)

Formule :

VAM (m/h) = Gain d'altitude (m) / Temps (heures)

Repères VAM :

VAM (m/h)NiveauExemple
600 - 900RécréatifCycliste club sur montée locale
900 - 1200CompétitifBon amateur sur Alpe d'Huez
1200 - 1500Élite AmateurGrimpeur niveau national
1500 - 1800ProfessionnelÉquipier World Tour
> 1800Vainqueur Grand TourPogačar, Vingegaard sur montées clés

Exemple de Calcul :

Scénario :Montée de l'Alpe d'Huez

  • Dénivelé positif : 1100 mètres
  • Temps : 55 minutes = 0.917 heures
  • VAM = 1100 / 0.917 =1200 m/h

Interprétation : Performance de grimpeur niveau compétitif

function calculateVAM(elevationGainMeters, timeMinutes) {
  const hours = timeMinutes / 60;
  return Math.round(elevationGainMeters / hours);
}

// Example:
const vam = calculateVAM(1100, 55);
// Returns: 1200 m/h

10. Estimation W/kg à Partir de VAM

Formule :

W/kg ≈ VAM (m/h) / 100 / (Gradient% + 3)

Exemple de Calcul :

Scénario :Montée avec pente moyenne de 8%, VAM = 1200 m/h

W/kg = 1200 / 100 / (8 + 3)

W/kg = 12 / 11 =4.36 W/kg

Vérification croisée : Avec un cycliste de 70kg → 305W de puissance soutenue en montée

function estimateWkgFromVAM(vam, gradientPercent) {
  return (vam / 100 / (gradientPercent + 3)).toFixed(2);
}

// Example:
const wkg = estimateWkgFromVAM(1200, 8);
// Returns: 4.36

Équation de Puissance Aérodynamique

11. Besoins en Puissance Totale

Formule Complète :

P_total = P_aéro + P_gravité + P_roulage + P_cinétique

Formules des Composantes :

Traînée Aérodynamique :
P_aéro = CdA × 0,5 × ρ × V³
Gravitationnelle (Montée) :
P_gravité = m × g × sin(θ) × V
Résistance au Roulement :
P_rolling = Crr × m × g × cos(θ) × V
Cinétique (Accélération) :
P_cinétique = m × a × V

Constantes & Variables :

  • CdA= Coefficient de traînée × surface frontale (m²)
    • Vélo route typique sur cocottes : 0.35-0.40 m²
    • Dans le cintre : 0.32-0.37 m²
    • Position contre-la-montre : 0.20-0.25 m²
  • ρ= Densité de l'air (1.225 kg/m³ au niveau de la mer, 15°C)
  • V= Vitesse (m/s)
  • m= Masse totale (cycliste + vélo, kg)
  • g= Gravité (9.81 m/s²)
  • θ= Angle de pente (radians ou degrés convertis)
  • Crr= Coefficient de résistance au roulement (~0.004 pour bons pneus route)
  • a= Accélération (m/s²)

Exemple Détaillé (CLM sur Route Plate) :

Scénario :

  • Vitesse : 40 km/h = 11.11 m/s
  • CdA : 0.22 m² (bonne position CLM)
  • Masse totale : 75kg (cycliste) + 8kg (vélo) = 83kg
  • Route plate (pente = 0°)
  • Vitesse constante (accélération = 0)

Calcul :

  1. P_aero= 0.22 × 0.5 × 1.225 × 11.11³ =185W
  2. P_gravity= 0W (route plate)
  3. P_rolling= 0.004 × 83 × 9.81 × 11.11 =36W
  4. P_cinétique= 0W (vitesse constante)
  5. P_total = 185 + 0 + 36 + 0 = 221W

Interprétation : Besoin de 221W pour maintenir 40 km/h en position CLM sur plaque de route

Implémentation JavaScript :

function calculatePowerRequired(params) {
  const {
    velocityKph,
    CdA = 0.32,              // m²
    rho = 1.225,             // kg/m³
    mass = 83,               // kg (rider + bike)
    gradientPercent = 0,     // %
    Crr = 0.004,             // rolling resistance
    accelerationMps2 = 0     // m/s²
  } = params;

  // Convert velocity to m/s
  const V = velocityKph / 3.6;

  // Convert gradient to angle
  const theta = Math.atan(gradientPercent / 100);

  // Calculate each component
  const P_aero = CdA * 0.5 * rho * Math.pow(V, 3);
  const P_gravity = mass * 9.81 * Math.sin(theta) * V;
  const P_rolling = Crr * mass * 9.81 * Math.cos(theta) * V;
  const P_kinetic = mass * accelerationMps2 * V;

  return {
    total: Math.round(P_aero + P_gravity + P_rolling + P_kinetic),
    aero: Math.round(P_aero),
    gravity: Math.round(P_gravity),
    rolling: Math.round(P_rolling),
    kinetic: Math.round(P_kinetic)
  };
}

// Example: TT at 40 km/h
const power_tt = calculatePowerRequired({
  velocityKph: 40,
  CdA: 0.22,
  mass: 83,
  gradientPercent: 0
});
// Returns: { total: 221, aero: 185, gravity: 0, rolling: 36, kinetic: 0 }

// Example: 8% climb at 15 km/h
const power_climb = calculatePowerRequired({
  velocityKph: 15,
  CdA: 0.38,
  mass: 75,
  gradientPercent: 8
});
// Returns: { total: 265, aero: 27, gravity: 244, rolling: 11, kinetic: 0 }

Fonctions Auxiliaires

Utilitaires de Conversion d'Unités

Implémentation JavaScript :

// Time conversions
function hoursToSeconds(hours) {
  return hours * 3600;
}

function minutesToSeconds(minutes) {
  return minutes * 60;
}

function secondsToHours(seconds) {
  return seconds / 3600;
}

function formatDuration(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.round(seconds % 60);
  return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}

// Speed conversions
function kphToMps(kph) {
  return kph / 3.6;
}

function mpsToKph(mps) {
  return mps * 3.6;
}

// Energy conversions
function joulesTo kJ(joules) {
  return joules / 1000;
}

function kJToJoules(kJ) {
  return kJ * 1000;
}

function wattsToKJ(watts, durationSeconds) {
  return (watts * durationSeconds) / 1000;
}

// Examples:
formatDuration(7265);        // Returns: "2:01:05"
kphToMps(40);                // Returns: 11.11 m/s
wattsToKJ(250, 3600);        // Returns: 900 kJ (1 hour at 250W)

Ressources d'Implémentation

Toutes les formules de cette page sont prêtes pour la production et validées par rapport à la littérature scientifique et aux données réelles de capteurs de puissance. Utilisez-les pour des outils d'analyse personnalisés, la vérification ou une compréhension approfondie des calculs d'entraînement adaptés à la puissance.

💡 Meilleures Pratiques

  • Valider les entrées :Vérifier les plages de puissance raisonnables (0-2000W), durées positives
  • Gérer les cas limites :Division par zéro, données null/undefined, FTP manquant
  • Arrondir de manière appropriée :CTL/ATL/TSB à 1 décimales, TSS en entier, W/kg à 2 décimales
  • Stocker la précision :Conserver la précision complète en base de données, arrondie uniquement pour l'affichage
  • Horaires des Fuseaux :Gérer UTC vs. heure locale de manière cohérente pour l'analyse multi-jours
  • Calibrage du capteur de puissance :Rappeler aux utilisateurs de faire le zéro avant les sorties
  • Validation FTP :Signaler les valeurs FTP suspectes (>500W ou <100W pour adultes)
  • Testeur minutieusement :Utiliser des fichiers de sortie validés pour vérifier les calculs