Formula Kuasa Berbasikal
Asas Matematik Metrik Bike Analytics
Panduan Pelaksanaan
Halaman ini menyediakan formula salin-tampal dan kaedah pengiraan langkah demi langkah untuk semua metrik Bike Analytics. Gunakan ini untuk pelaksanaan tersuai, pengesahan, atau pemahaman yang lebih mendalam tentang latihan berasaskan kuasa.
⚠️ Nota Pelaksanaan
- Semua nilai kuasa dalam watt (W), masa dalam saat kecuali dinyatakan sebaliknya
- FTP dan CP adalah ambang khusus individu—tiada nilai universal
- Sentiasa sahkan input untuk julat yang munasabah (0-2000W biasa)
- Kendalikan kes tepi (pembahagian dengan sifar, kuasa negatif)
- Data kuasa memerlukan selang rakaman 1 saat untuk ketepatan
Metrik Prestasi Teras
1. Skor Tekanan Latihan (TSS)
Formula:
Contoh Kerja:
Senario: Tunggangan 2 jam, NP = 235W, FTP = 250W
- Kira IF: IF = 235 / 250 = 0.94
- Durasi dalam saat: 2 jam × 3600 = 7200 saat
- TSS = (7200 × 235 × 0.94) / (250 × 3600) × 100
- TSS = 1,590,720 / 900,000 × 100 = 176.7 TSS
Tafsiran: Tunggangan latihan keras (>150 TSS), jangkaan pemulihan 2-3 hari
Pelaksanaan JavaScript:
function calculateTSS(durationSeconds, normalizedPower, ftp) {
const intensityFactor = normalizedPower / ftp;
const tss = (durationSeconds * normalizedPower * intensityFactor) / (ftp * 3600) * 100;
return Math.round(tss);
}
// Contoh penggunaan:
const tss = calculateTSS(7200, 235, 250);
// Mengembalikan: 177
2. Kuasa Ternormal (NP)
Algoritma (purata bergerak 30 saat):
Mengapa Kuasa ke-4?
Hubungan kuartik (kuasa ke-4) mencerminkan kos fisiologi bukan linear bagi usaha berubah-ubah. Tunggangan dengan lonjakan dan pemulihan menelan lebih banyak tenaga daripada kuasa yang stabil pada purata yang sama.
Contoh:
- Tunggangan stabil: 200W selama 1 jam → NP = 200W, Purata = 200W
- Tunggangan berubah: Berselang-seli 300W/100W → Purata = 200W, NP = 225W
Purata kuasa sama, tetapi tunggangan berubah mempunyai NP 12% lebih tinggi disebabkan kos fisiologi lonjakan
Pelaksanaan JavaScript:
function calculateNormalizedPower(powerData) {
// powerData adalah array nilai kuasa 1-saat
// Langkah 1: Kira purata bergerak 30-saat
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);
}
// Langkah 2: Naikkan ke kuasa ke-4
const powered = rollingAvgs.map(p => Math.pow(p, 4));
// Langkah 3: Purata kuasa ke-4
const avgPowered = powered.reduce((sum, p) => sum + p, 0) / powered.length;
// Langkah 4: Ambil punca kuasa ke-4
const np = Math.pow(avgPowered, 0.25);
return Math.round(np);
}
// Contoh penggunaan:
const powerData = [/* array kuasa 1-saat */];
const np = calculateNormalizedPower(powerData);
// Mengembalikan: NP dalam watt
3. Faktor Intensiti (IF)
Formula:
Julat Tafsiran:
| Julat IF | Tahap Usaha | Contoh Latihan |
|---|---|---|
| < 0.75 | Pemulihan / Mudah | Tunggangan pemulihan aktif, Zon 1-2 |
| 0.75 - 0.85 | Daya Tahan | Tunggangan stabil jauh, asas aerobik |
| 0.85 - 0.95 | Tempo | Latihan sweet spot, interval tempo |
| 0.95 - 1.05 | Ambang | Interval FTP, usaha ujian masa |
| 1.05 - 1.15 | VO₂max | Interval 5-minit, perlumbaan kriterium |
| > 1.15 | Anaerobik | Pecutan pendek, serangan, letusan MTB |
Pengiraan Contoh:
Senario: NP = 235W, FTP = 250W
IF = 235 / 250 = 0.94
Tafsiran: Usaha tempo tinggi / sub-ambang, mampan untuk 2-3 jam
function calculateIF(normalizedPower, ftp) {
return (normalizedPower / ftp).toFixed(2);
}
// Contoh:
const if_value = calculateIF(235, 250);
// Mengembalikan: 0.94
4. Indeks Kebolehubahan (VI)
Formula:
Tafsiran Mengikut Disiplin:
| Disiplin | VI Biasa | Maksud |
|---|---|---|
| TT Jalan Raya / Usaha Stabil | 1.00 - 1.05 | Kuasa sangat konsisten, pacing optimum |
| Perlumbaan Jalan Raya | 1.05 - 1.10 | Beberapa lonjakan, secara amnya stabil |
| Kriterium | 1.10 - 1.20 | Pecutan dan serangan yang kerap |
| Basikal Gunung XC | 1.15 - 1.30+ | Sangat berubah, lonjakan berterusan |
Pengiraan Contoh:
Perlumbaan Jalan Raya: NP = 240W, Kuasa Purata = 230W
VI = 240 / 230 = 1.04 (pacing stabil)
Perlumbaan MTB: NP = 285W, Kuasa Purata = 235W
VI = 285 / 235 = 1.21 (sangat berubah, usaha letusan)
function calculateVI(normalizedPower, averagePower) {
return (normalizedPower / averagePower).toFixed(2);
}
// Contoh:
const vi_road = calculateVI(240, 230); // Mengembalikan: 1.04
const vi_mtb = calculateVI(285, 235); // Mengembalikan: 1.21
Kuasa Kritikal & W' (Kapasiti Anaerobik)
5. Kuasa Kritikal (CP) - Model Linear
Formula:
Pengiraan daripada Pelbagai Usaha:
Memerlukan 2-4 usaha maksimum pada durasi berbeza (cth., 3, 5, 12, 20 minit)
Data Contoh:
| Durasi | Kuasa (W) | Jumlah Kerja (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 |
Menggunakan regresi linear (Kerja = CP × Masa + W'):
- CP = 270W (kecerunan garis regresi)
- W' = 18.5 kJ (pintasan-y)
Pelaksanaan 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
// Regresi linear: 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, // watt
Wprime: Math.round(Wprime * 10) / 10 // kJ
};
}
// Contoh penggunaan:
const efforts = [
{duration: 180, power: 400},
{duration: 300, power: 365},
{duration: 720, power: 310},
{duration: 1200, power: 285}
];
const result = calculateCP_Linear(efforts);
// Mengembalikan: { CP: 270.0, Wprime: 18.5 }
6. Imbangan W' (W'bal) - Model Persamaan Pembezaan
Formula:
W'exp(t) = ∫(P(t) - CP) dt
W'rec(t) = W' × (1 - e^(-t/τ))
dan ΔCP = (CP - P(t))
Contoh Dunia Sebenar:
Spesifikasi Penunggang: CP = 270W, W' = 18.5 kJ
Senario 1 - Serangan Keras:
- Penunggang melonjak ke 400W selama 30 saat
- Perbelanjaan W': (400 - 270) × 30 = 3,900 J = 3.9 kJ
- W'bal tingal: 18.5 - 3.9 = 14.6 kJ
Senario 2 - Pemulihan:
- Selepas serangan, turun ke 200W (70W di bawah CP) selama 2 minit
- ΔCP = 270 - 200 = 70W
- τ = 546 × e^(-0.01 × 70) + 316 = 588 saat
- Pemulihan dalam 120s: 18.5 × (1 - e^(-120/588)) = 3.5 kJ pulih
- W'bal Baharu: 14.6 + 3.5 = 18.1 kJ
Pelaksanaan JavaScript:
function calculateWbalance(powerData, CP, Wprime) {
// powerData = array of {time: seconds, power: watts}
let wbal = Wprime * 1000; // Tukar ke joule
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) {
// Perbelanjaan di atas CP
const expenditure = (power - CP) * dt;
wbal -= expenditure;
} else {
// Pemulihan di bawah 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;
}
// Pastikan W'bal tidak melebihi maks atau menjadi negatif
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;
}
// Contoh penggunaan:
const powerData = [
{time: 0, power: 200},
{time: 1, power: 210},
// ... baki data tunggangan
];
const wbalHistory = calculateWbalance(powerData, 270, 18.5);
// Mengembalikan array nilai W'bal sepanjang masa
Carta Pengurusan Prestasi (PMC)
7. Pengiraan CTL, ATL, TSB
Formula (Purata Bergerak Wajaran Eksponen):
Definisi Metrik:
- CTL (Beban Latihan Kronik): Purata wajaran eksponen 42-hari - mewakili kecergasan
- ATL (Beban Latihan Akut): Purata wajaran eksponen 7-hari - mewakili keletihan
- TSB (Imbangan Tekanan Latihan): Bentuk = Kecergasan - Keletihan
Contoh Kerja (Blok Latihan 7-Hari):
| Hari | TSS | CTL | ATL | TSB | Status |
|---|---|---|---|---|---|
| Isnin | 100 | 75.0 | 80.0 | -5.0 | Latihan |
| Selasa | 50 | 74.4 | 75.7 | -1.3 | Pemulihan |
| Rabu | 120 | 75.5 | 82.0 | -6.5 | Latihan Keras |
| Khamis | 0 | 73.7 | 70.3 | +3.4 | Hari Rehat |
| Jumaat | 80 | 73.8 | 71.7 | +2.1 | Sederhana |
| Sabtu | 150 | 75.6 | 82.9 | -7.3 | Tunggangan Jauh |
| Ahad | 40 | 74.8 | 76.8 | -2.0 | Pemulihan |
Tafsiran TSB:
| Julat TSB | Status | Tindakan |
|---|---|---|
| < -30 | Risiko Tinggi | Amaran latihan berlebihan - kurangkan beban |
| -30 hingga -10 | Latihan Keras | Membina kecergasan, pantau pemulihan |
| -10 hingga +5 | Optimum | Zon latihan biasa |
| +5 hingga +15 | Sedia Berlumba | Bentuk puncak - berlumba hujung minggu ini |
| > +25 | Penurunan Latihan | Kehilangan kecergasan - tingkatkan beban |
Pelaksanaan JavaScript:
function calculatePMC(workouts) {
// workouts = [{date: "YYYY-MM-DD", tss: number}, ...]
let ctl = 0, atl = 0;
const results = [];
workouts.forEach(workout => {
// Kemaskini CTL (pemalar masa 42-hari)
ctl = ctl + (workout.tss - ctl) / 42;
// Kemaskini ATL (pemalar masa 7-hari)
atl = atl + (workout.tss - atl) / 7;
// Kira TSB (CTL semalam - ATL hari ini untuk pengiraan tradisional)
// Untuk kesederhanaan di sini menggunakan nilai semasa
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 "Risiko Tinggi";
if (tsb < -10) return "Latihan Keras";
if (tsb < 5) return "Optimum";
if (tsb < 15) return "Sedia Berlumba";
return "Penurunan Latihan";
}
// Contoh penggunaan:
const workouts = [
{date: "2025-01-01", tss: 100},
{date: "2025-01-02", tss: 50},
{date: "2025-01-03", tss: 120},
// ... lebih banyak latihan
];
const pmc = calculatePMC(workouts);
// Mengembalikan array dengan CTL, ATL, TSB untuk setiap hari
Nisbah Kuasa-ke-Berat & Metrik Mendaki
8. Nisbah Kuasa-ke-Berat
Formula:
Penanda Aras W/kg FTP:
| Tahap | W/kg Lelaki | W/kg Wanita | Kategori |
|---|---|---|---|
| Rekreasi | 2.5 - 3.5 | 2.0 - 3.0 | Penunggang kecergasan |
| Kompetitif | 3.5 - 4.5 | 3.0 - 4.0 | Kat 3-4, pelumba kumpulan umur |
| Lanjutan | 4.5 - 5.5 | 4.0 - 5.0 | Kat 1-2, amatur kuat |
| Amatur Elit | 5.5 - 6.0 | 5.0 - 5.5 | Tahap kebangsaan |
| Profesional | 6.0 - 7.0+ | 5.5 - 6.5+ | Jelajah Dunia, GC Jelajah Besar |
Pengiraan Contoh:
Senario: Penunggang dengan FTP = 275W, jisim badan = 70kg
W/kg = 275 / 70 = 3.93 W/kg
Tafsiran: Tahap kompetitif, berkemampuan dalam perlumbaan berbukit
function calculateWattsPerKg(power, bodyMassKg) {
return (power / bodyMassKg).toFixed(2);
}
// Contoh:
const wpkg = calculateWattsPerKg(275, 70);
// Mengembalikan: 3.93
9. VAM (Velocità Ascensionale Media)
Formula:
Penanda Aras VAM:
| VAM (m/j) | Tahap | Contoh |
|---|---|---|
| 600 - 900 | Rekreasi | Penunggang kelab di pendakian tempatan |
| 900 - 1200 | Kompetitif | Amatur baik di Alpe d'Huez |
| 1200 - 1500 | Amatur Elit | Pendaki tahap kebangsaan |
| 1500 - 1800 | Profesional | Domestique Jelajah Dunia |
| > 1800 | Pemenang Jelajah Besar | Pogačar, Vingegaard di pendakian utama |
Pengiraan Contoh:
Senario: Pendakian Alpe d'Huez
- Kenaikan ketinggian: 1100 meter
- Masa: 55 minit = 0.917 jam
- VAM = 1100 / 0.917 = 1200 m/j
Tafsiran: Prestasi mendaki tahap kompetitif
function calculateVAM(elevationGainMeters, timeMinutes) {
const hours = timeMinutes / 60;
return Math.round(elevationGainMeters / hours);
}
// Contoh:
const vam = calculateVAM(1100, 55);
// Mengembalikan: 1200 m/j
10. Anggaran VAM ke W/kg
Formula:
Pengiraan Contoh:
Senario: Pendakian dengan kecerunan purata 8%, VAM = 1200 m/j
W/kg = 1200 / 100 / (8 + 3)
W/kg = 12 / 11 = 4.36 W/kg
Semak silang: Dengan penunggang 70kg → 305W kuasa mampan semasa mendaki
function estimateWkgFromVAM(vam, gradientPercent) {
return (vam / 100 / (gradientPercent + 3)).toFixed(2);
}
// Contoh:
const wkg = estimateWkgFromVAM(1200, 8);
// Mengembalikan: 4.36