Fórmulas de Potência em Ciclismo

Fundamentos Matemáticos das Métricas do Bike Analytics

Guia de Implementação

Esta página apresenta fórmulas prontas a copiar/colar e métodos de cálculo passo a passo para todas as principais métricas do Bike Analytics. Usa‑as em implementações personalizadas, validação de resultados ou simplesmente para compreender melhor o treino baseado em potência.

⚠️ Notas de Implementação

  • Todos os valores de potência em watts (W), tempo em segundos salvo indicação em contrário
  • FTP e CP são limiares específicos de cada atleta – não existem valores universais
  • Valida sempre as entradas para intervalos razoáveis (0–2000 W típico)
  • Gere casos extremos (divisão por zero, potência negativa, dados em falta)
  • Dados de potência ideais em amostragem de 1 segundo para máxima precisão

Métricas de Desempenho Fundamentais

1. Training Stress Score (TSS)

Fórmula:

TSS = (duração_segundos × NP × IF) / (FTP × 3600) × 100
onde IF = NP / FTP

Exemplo Resolvido:

Cenário: Saída de 2 horas, NP = 235 W, FTP = 250 W

  1. Calcular IF: IF = 235 / 250 = 0,94
  2. Duração em segundos: 2 horas × 3600 = 7200 segundos
  3. TSS = (7200 × 235 × 0,94) / (250 × 3600) × 100
  4. TSS = 1 590 720 / 900 000 × 100 = 176,7 TSS

Interpretação: Treino exigente (>150 TSS), prevê‑se 2–3 dias de recuperação

Implementação em JavaScript:

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

// Exemplo de utilização:
const tss = calculateTSS(7200, 235, 250);
// Devolve: 177

2. Normalized Power (NP)

Algoritmo (média móvel de 30 segundos):

1. Calcular a média móvel de 30 segundos da potência para toda a saída
2. Elevar cada valor de 30 s à 4.ª potência
3. Calcular a média de todos esses valores elevados a ^4
4. Calcular a raiz 4.ª dessa média
NP = ⁴√(média de [média_30s^4])

Porque a 4.ª potência?

A relação de 4.ª potência reflete o custo fisiológico não linear dos esforços variáveis. Uma saída com acelerações e recuperações “custa” mais do que uma saída a potência constante com a mesma média.

Exemplo:

  • Saída constante: 200 W durante 1 hora → NP = 200 W, Média = 200 W
  • Saída variável: alternando 300 W/100 W → Média = 200 W, NP ≈ 225 W

Mesma potência média, mas a saída variável tem NP ~12% maior devido ao custo fisiológico das acelerações

Implementação em JavaScript:

function calculateNormalizedPower(powerData) {
  // powerData é um array de valores de potência de 1 segundo

  // Passo 1: calcular médias móveis de 30 segundos
  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);
  }

  // Passo 2: elevar à 4.ª potência
  const powered = rollingAvgs.map(p => Math.pow(p, 4));

  // Passo 3: média das 4.ªs potências
  const avgPowered = powered.reduce((sum, p) => sum + p, 0) / powered.length;

  // Passo 4: raiz 4.ª
  const np = Math.pow(avgPowered, 0.25);

  return Math.round(np);
}

// Exemplo de utilização:
const powerData = [/* array de potência de 1 segundo */];
const np = calculateNormalizedPower(powerData);
// Devolve: NP em watts

3. Intensity Factor (IF)

Fórmula:

IF = NP / FTP

Intervalos de Interpretação:

Intervalo IF Nível de esforço Exemplo de treino
< 0,75 Recuperação / Fácil Saída de recuperação ativa, Zona 1–2
0,75 – 0,85 Resistência Saída longa constante, base aeróbica
0,85 – 0,95 Tempo Treinos “sweet spot”, intervalos tempo
0,95 – 1,05 Limiar Intervalos de FTP, esforço de contrarrelógio
1,05 – 1,15 VO₂max Intervalos de 5 minutos, critérium
> 1,15 Anaeróbico Sprints curtos, ataques, acelerações em MTB

Exemplo de Cálculo:

Cenário: NP = 235 W, FTP = 250 W

IF = 235 / 250 = 0,94

Interpretação: esforço tempo alto/sub‑limiar, sustentável durante 2–3 horas

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

// Exemplo:
const if_value = calculateIF(235, 250);
// Devolve: 0.94

4. Variability Index (VI)

Fórmula:

VI = NP / Potência Média

Interpretação por Disciplina:

Disciplina VI típico Significado
Contrarrelógio / Esforço constante 1,00 – 1,05 Potência muito consistente, ritmo ótimo
Prova de estrada 1,05 – 1,10 Algumas acelerações, geralmente constante
Critérium 1,10 – 1,20 Acelerações frequentes e ataques
Mountain bike XC 1,15 – 1,30+ Muito variável, acelerações constantes

Exemplo de Cálculo:

Prova de estrada: NP = 240 W, Potência média = 230 W

VI = 240 / 230 = 1,04 (ritmo relativamente constante)

Prova de MTB: NP = 285 W, Potência média = 235 W

VI = 285 / 235 = 1,21 (perfil muito variável, esforços explosivos)

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

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

Potência Crítica e W' (Capacidade Anaeróbica)

5. Critical Power (CP) – Modelo Linear

Fórmula:

Tempo até à exaustão = W' / (Potência − CP)
Reescrita: Potência × Tempo = CP × Tempo + W'

Cálculo a partir de Vários Esforços:

Requer 2–4 esforços máximos a durações diferentes (por exemplo, 3, 5, 12, 20 minutos).

Dados de Exemplo:

Duração Potência (W) Trabalho Total (kJ)
3 min (180 s) 400 W 72 kJ
5 min (300 s) 365 W 109,5 kJ
12 min (720 s) 310 W 223,2 kJ
20 min (1200 s) 285 W 342 kJ

Usando regressão linear (Trabalho = CP × Tempo + W'):

  • CP = 270 W (inclinação da reta)
  • W' = 18,5 kJ (interceção no eixo Y)

Implementação em JavaScript:

function calculateCP_Linear(efforts) {
  // efforts = [{duration: segundos, power: watts}, ...]

  const times = efforts.map(e => e.duration);
  const work = efforts.map(e => e.power * e.duration / 1000); // kJ

  // Regressão linear: trabalho = CP * tempo + 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
  };
}

// Exemplo de utilização:
const efforts = [
  {duration: 180, power: 400},
  {duration: 300, power: 365},
  {duration: 720, power: 310},
  {duration: 1200, power: 285}
];

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

6. Monitorização de W'bal (Balanço de W')

Ideia Geral:

W' representa a “bateria anaeróbica” – trabalho que podes realizar acima da CP antes da exaustão. W'bal acompanha em tempo real quanto dessa bateria ainda está disponível.

Princípios:

  • Quando a potência > CP ⇒ gastas W'
  • Quando a potência < CP ⇒ W' recupera gradualmente
  • A velocidade de recuperação depende de quão abaixo da CP estás e do tempo

Equação Diferencial Simplificada (modelo Skiba):

W'bal(t) = W' − ∫0t max(0, P(τ) − CP) · e−(t−τ)/τrec

Na prática, implementa‑se numericamente com um ciclo sobre os dados de potência de 1 segundo.

7. Modelo Potência‑Duração

O Bike Analytics segue modelos validados na literatura (Monod & Scherrer; Jones 2019) para representar a relação entre potência máxima sustentável e duração do esforço.

Exemplo de Ajuste Exponencial:

P(t) = CP + W' / t

Ajustar esta função a vários recordes de potência ao longo do tempo fornece estimativas robustas de CP e W', bem como previsões de tempo até à exaustão para potências específicas.

CTL, ATL e TSB – Performance Management Chart

8. Cálculo de CTL (Chronic Training Load)

Fórmula (média móvel exponencial de 42 dias):

CTLhoje = CTLontem + (TSShoje − CTLontem) / 42

Representa a carga de treino crónica (forma). Aumenta lentamente com TSS consistente; cai lentamente em períodos de descanso.

9. Cálculo de ATL (Acute Training Load)

Fórmula (média móvel exponencial de 7 dias):

ATLhoje = ATLontem + (TSShoje − ATLontem) / 7

Representa a carga de treino aguda (fadiga). Reage rapidamente a mudanças de volume/intensidade.

10. Cálculo de TSB (Training Stress Balance)

Fórmula:

TSB = CTL − ATL

TSB positivo indica frescura; TSB muito negativo indica fadiga acumulada.

Implementação em JavaScript (CTL/ATL/TSB juntos):

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

  workouts.forEach(workout => {
    // Atualizar CTL (constante de tempo de 42 dias)
    ctl = ctl + (workout.tss - ctl) / 42;

    // Atualizar ATL (constante de tempo de 7 dias)
    atl = atl + (workout.tss - atl) / 7;

    // Calcular TSB (aqui simplificado)
    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 "Risco Elevado";
  if (tsb < -10) return "Treino Intenso";
  if (tsb < 5) return "Ótimo";
  if (tsb < 15) return "Pronto para Competir";
  return "Desadaptação";
}

Potência‑Peso e Métricas de Escalada

11. Ratio Potência‑Peso (W/kg)

Fórmula:

W/kg = Potência (W) / Massa Corporal (kg)

Referências de FTP em W/kg:

Nível Homem W/kg Mulher W/kg Categoria
Recreativo 2,5 – 3,5 2,0 – 3,0 Ciclista amador
Competitivo 3,5 – 4,5 3,0 – 4,0 Cat 3–4, masters
Avançado 4,5 – 5,5 4,0 – 5,0 Cat 1–2, amador forte
Amador Elite 5,5 – 6,0 5,0 – 5,5 Nível nacional
Profissional 6,0 – 7,0+ 5,5 – 6,5+ World Tour, GC de Grandes Voltas

Exemplo de Cálculo:

Cenário: ciclista com FTP = 275 W, massa corporal = 70 kg

W/kg = 275 / 70 = 3,93 W/kg

Interpretação: nível competitivo, capaz em provas com muitas subidas

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

// Exemplo:
const wpkg = calculateWattsPerKg(275, 70);
// Devolve: 3.93

12. VAM (Velocità Ascensionale Media)

Fórmula:

VAM (m/h) = Ganho de Elevação (m) / Tempo (horas)

Referências de VAM:

VAM (m/h) Nível Exemplo
600 – 900 Recreativo Ciclista de clube numa subida local
900 – 1200 Competitivo Bom amador no Alpe d'Huez
1200 – 1500 Amador elite Escalador de nível nacional
1500 – 1800 Profissional Gregário World Tour
> 1800 Vencedor de Grandes Voltas Pogačar, Vingegaard em subidas chave

Exemplo de Cálculo:

Cenário: subida ao Alpe d'Huez

  • Ganho de elevação: 1100 metros
  • Tempo: 55 minutos = 0,917 horas
  • VAM = 1100 / 0,917 = ~1200 m/h

Interpretação: performance de escalada de nível competitivo

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

// Exemplo:
const vam = calculateVAM(1100, 55);
// Devolve: 1200 m/h

13. Estimativa de W/kg a partir de VAM

Fórmula aproximada:

W/kg ≈ VAM (m/h) / 100 / (Inclinação% + 2)

Esta aproximação assume densidade do ar, Crr e massa constantes. Útil para estimar W/kg de subidas famosas com base em tempos registados.

Modelos de Potência em Estrada

14. Modelo de Potência Total em Ciclismo de Estrada

Equação de Potência:

Ptotal = Paero + Pgravidade + Prolamento + Pcinética
Paero = CdA × 0,5 × ρ × V³
Pgravidade = m × g × sin(θ) × V
Prolamento = Crr × m × g × cos(θ) × V
Pcinética = m × a × V

Implementação em JavaScript:

function calculatePowerRequired(params) {
  const {
    velocityKph,
    CdA = 0.32,              // m²
    rho = 1.225,             // kg/m³
    mass = 83,               // kg (ciclista + bicicleta)
    gradientPercent = 0,     // %
    Crr = 0.004,             // resistência de rolamento
    accelerationMps2 = 0     // m/s²
  } = params;

  // Converter velocidade para m/s
  const V = velocityKph / 3.6;

  // Converter inclinação em ângulo
  const theta = Math.atan(gradientPercent / 100);

  // Calcular cada componente
  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)
  };
}

// Exemplo: contrarrelógio a 40 km/h
const power_tt = calculatePowerRequired({
  velocityKph: 40,
  CdA: 0.22,
  mass: 83,
  gradientPercent: 0
});
// Devolve: { total: 221, aero: 185, gravity: 0, rolling: 36, kinetic: 0 }

// Exemplo: subida de 8% a 15 km/h
const power_climb = calculatePowerRequired({
  velocityKph: 15,
  CdA: 0.38,
  mass: 75,
  gradientPercent: 8
});
// Devolve: { total: 265, aero: 27, gravity: 244, rolling: 11, kinetic: 0 }

Funções Auxiliares

Utilitários de Conversão de Unidades

Implementação em JavaScript:

// Conversões de tempo
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')}`;
}

// Conversões de velocidade
function kphToMps(kph) {
  return kph / 3.6;
}

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

// Conversões de energia
function joulesTokJ(joules) {
  return joules / 1000;
}

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

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

// Exemplos:
formatDuration(7265);        // Devolve: "2:01:05"
kphToMps(40);                // Devolve: 11.11 m/s
wattsToKJ(250, 3600);        // Devolve: 900 kJ (1 hora a 250 W)

Recursos de Implementação

Todas as fórmulas desta página estão prontas para produção e foram validadas contra a literatura científica e dados reais de medidores de potência. Usa‑as para ferramentas de análise personalizadas, verificação independente ou para aprofundar o entendimento dos cálculos de treino.

💡 Boas Práticas

  • Validar entradas: verifica intervalos de potência razoáveis (0–2000 W) e durações positivas.
  • Tratar casos extremos: divisão por zero, dados nulos/indefinidos, FTP em falta.
  • Arredondar de forma consistente: CTL/ATL/TSB a 1 casa decimal, TSS a inteiro, W/kg a 2 casas decimais.
  • Guardar com precisão: mantém a precisão total na base de dados; arredonda apenas para apresentação.
  • Zonas horárias: gere UTC vs hora local de forma consistente em análises multi‑dia.
  • Calibração do medidor de potência: lembra os utilizadores de fazer “zero offset” regularmente.
  • Validação de FTP: sinaliza valores de FTP suspeitos (>500 W ou <100 W para adultos).
  • Testar a fundo: usa ficheiros de treino conhecidos para validar todos os cálculos.