Формулы мощности в велоспорте
Математическая основа метрик Bike Analytics
Руководство по реализации
Эта страница предоставляет готовые формулы и пошаговые методы расчета для всех метрик Bike Analytics. Используйте их для пользовательских реализаций, верификации или более глубокого понимания тренировок на основе мощности.
⚠️ Примечания по реализации
- Все значения мощности в ваттах (Вт), время в секундах, если не указано иное
- FTP и CP — индивидуальные пороги, универсальных значений не существует
- Всегда проверяйте входные данные на разумные диапазоны (обычно 0-2000 Вт)
- Обрабатывайте граничные случаи (деление на ноль, отрицательная мощность)
- Данные мощности требуют интервалов записи в 1 секунду для точности
Основные показатели производительности
1. Оценка тренировочного стресса (TSS)
Формула:
Рабочий пример:
Сценарий: 2-часовая поездка, NP = 235 Вт, FTP = 250 Вт
- Рассчитаем IF: IF = 235 / 250 = 0.94
- Продолжительность в секундах: 2 часа × 3600 = 7200 секунд
- TSS = (7200 × 235 × 0.94) / (250 × 3600) × 100
- TSS = 1,590,720 / 900,000 × 100 = 176.7 TSS
Интерпретация: Интенсивная тренировочная поездка (>150 TSS), ожидается 2-3 дня восстановления
Реализация на JavaScript:
function calculateTSS(durationSeconds, normalizedPower, ftp) {
const intensityFactor = normalizedPower / ftp;
const tss = (durationSeconds * normalizedPower * intensityFactor) / (ftp * 3600) * 100;
return Math.round(tss);
}
// Пример использования:
const tss = calculateTSS(7200, 235, 250);
// Возвращает: 177
2. Нормализованная мощность (NP)
Алгоритм (30-секундное скользящее среднее):
Почему 4-я степень?
Квартичная (4-я степень) зависимость отражает нелинейную физиологическую стоимость переменных усилий. Поездка с рывками и восстановлениями требует больше энергии, чем равномерная мощность при той же средней.
Пример:
- Равномерная поездка: 200 Вт в течение 1 часа → NP = 200 Вт, Средняя = 200 Вт
- Переменная поездка: Чередование 300 Вт/100 Вт → Средняя = 200 Вт, NP = 225 Вт
Одинаковая средняя мощность, но переменная поездка имеет на 12% выше NP из-за физиологической стоимости рывков
Реализация на JavaScript:
function calculateNormalizedPower(powerData) {
// powerData — массив значений мощности с интервалом 1 секунда
// Шаг 1: Рассчитать 30-секундные скользящие средние
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);
}
// Шаг 2: Возвести в 4-ю степень
const powered = rollingAvgs.map(p => Math.pow(p, 4));
// Шаг 3: Среднее 4-х степеней
const avgPowered = powered.reduce((sum, p) => sum + p, 0) / powered.length;
// Шаг 4: Извлечь корень 4-й степени
const np = Math.pow(avgPowered, 0.25);
return Math.round(np);
}
// Пример использования:
const powerData = [/* массив мощности с интервалом 1 секунда */];
const np = calculateNormalizedPower(powerData);
// Возвращает: NP в ваттах
3. Фактор интенсивности (IF)
Формула:
Диапазоны интерпретации:
| Диапазон IF | Уровень усилия | Пример тренировки |
|---|---|---|
| < 0.75 | Восстановление / Легко | Активное восстановление, Зона 1-2 |
| 0.75 - 0.85 | Выносливость | Длительная равномерная поездка, аэробная база |
| 0.85 - 0.95 | Темп | Тренировка sweet spot, темповые интервалы |
| 0.95 - 1.05 | Порог | FTP интервалы, усилие на разделке |
| 1.05 - 1.15 | VO₂max | 5-минутные интервалы, критериум |
| > 1.15 | Анаэробный | Короткие спринты, атаки, рывки MTB |
Пример расчета:
Сценарий: NP = 235 Вт, FTP = 250 Вт
IF = 235 / 250 = 0.94
Интерпретация: Высокий темп / субпороговое усилие, можно поддерживать 2-3 часа
function calculateIF(normalizedPower, ftp) {
return (normalizedPower / ftp).toFixed(2);
}
// Пример:
const if_value = calculateIF(235, 250);
// Возвращает: 0.94
4. Индекс вариабельности (VI)
Формула:
Интерпретация по дисциплинам:
| Дисциплина | Типичный VI | Значение |
|---|---|---|
| Шоссейная разделка / Равномерное усилие | 1.00 - 1.05 | Очень стабильная мощность, оптимальный темп |
| Шоссейная гонка | 1.05 - 1.10 | Некоторые рывки, в целом равномерно |
| Критериум | 1.10 - 1.20 | Частые ускорения и атаки |
| Горный велосипед XC | 1.15 - 1.30+ | Очень изменчиво, постоянные рывки |
Пример расчета:
Шоссейная гонка: NP = 240 Вт, Средняя мощность = 230 Вт
VI = 240 / 230 = 1.04 (равномерный темп)
MTB гонка: NP = 285 Вт, Средняя мощность = 235 Вт
VI = 285 / 235 = 1.21 (очень изменчиво, рывковые усилия)
function calculateVI(normalizedPower, averagePower) {
return (normalizedPower / averagePower).toFixed(2);
}
// Пример:
const vi_road = calculateVI(240, 230); // Возвращает: 1.04
const vi_mtb = calculateVI(285, 235); // Возвращает: 1.21
Критическая мощность и W' (анаэробная емкость)
5. Критическая мощность (CP) - Линейная модель
Формула:
Расчет на основе нескольких усилий:
Требуется 2-4 максимальных усилия разной продолжительности (например, 3, 5, 12, 20 минут)
Пример данных:
| Продолжительность | Мощность (Вт) | Общая работа (кДж) |
|---|---|---|
| 3 мин (180с) | 400 Вт | 72 кДж |
| 5 мин (300с) | 365 Вт | 109.5 кДж |
| 12 мин (720с) | 310 Вт | 223.2 кДж |
| 20 мин (1200с) | 285 Вт | 342 кДж |
Используя линейную регрессию (Работа = CP × Время + W'):
- CP = 270 Вт (наклон линии регрессии)
- W' = 18.5 кДж (пересечение с осью Y)
Реализация на JavaScript:
function calculateCP_Linear(efforts) {
// efforts = [{duration: секунды, power: ватты}, ...]
const times = efforts.map(e => e.duration);
const work = efforts.map(e => e.power * e.duration / 1000); // кДж
// Линейная регрессия: 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, // ватты
Wprime: Math.round(Wprime * 10) / 10 // кДж
};
}
// Пример использования:
const efforts = [
{duration: 180, power: 400},
{duration: 300, power: 365},
{duration: 720, power: 310},
{duration: 1200, power: 285}
];
const result = calculateCP_Linear(efforts);
// Возвращает: { CP: 270.0, Wprime: 18.5 }
6. Баланс W' (W'bal) - Модель дифференциального уравнения
Формулы:
W'exp(t) = ∫(P(t) - CP) dt
W'rec(t) = W' × (1 - e^(-t/τ))
и ΔCP = (CP - P(t))
Реальный пример:
Характеристики велосипедиста: CP = 270 Вт, W' = 18.5 кДж
Сценарий 1 - Мощная атака:
- Гонщик делает рывок до 400 Вт на 30 секунд
- Расход W': (400 - 270) × 30 = 3,900 Дж = 3.9 кДж
- Оставшийся W'bal: 18.5 - 3.9 = 14.6 кДж
Сценарий 2 - Восстановление:
- После атаки снижается до 200 Вт (на 70 Вт ниже CP) на 2 минуты
- ΔCP = 270 - 200 = 70 Вт
- τ = 546 × e^(-0.01 × 70) + 316 = 588 секунд
- Восстановление за 120с: 18.5 × (1 - e^(-120/588)) = 3.5 кДж восстановлено
- Новый W'bal: 14.6 + 3.5 = 18.1 кДж
Реализация на JavaScript:
function calculateWbalance(powerData, CP, Wprime) {
// powerData = массив {time: секунды, power: ватты}
let wbal = Wprime * 1000; // Преобразовать в джоули
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) {
// Расход выше CP
const expenditure = (power - CP) * dt;
wbal -= expenditure;
} else {
// Восстановление ниже 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;
}
// Убедиться, что W'bal не превышает макс. и не становится отрицательным
wbal = Math.max(0, Math.min(wbal, Wprime * 1000));
wbalHistory.push({
time: powerData[i].time,
wbal: wbal / 1000, // кДж
percent: (wbal / (Wprime * 1000)) * 100
});
}
return wbalHistory;
}
// Пример использования:
const powerData = [
{time: 0, power: 200},
{time: 1, power: 210},
// ... остальные данные поездки
];
const wbalHistory = calculateWbalance(powerData, 270, 18.5);
// Возвращает массив значений W'bal во времени
График управления производительностью (PMC)
7. Расчеты CTL, ATL, TSB
Формулы (экспоненциально взвешенные скользящие средние):
Определения метрик:
- CTL (Хроническая тренировочная нагрузка): 42-дневное экспоненциально взвешенное среднее - представляет физическую форму
- ATL (Острая тренировочная нагрузка): 7-дневное экспоненциально взвешенное среднее - представляет усталость
- TSB (Баланс тренировочного стресса): Форма = Физическая форма - Усталость
Рабочий пример (7-дневный тренировочный блок):
| День | TSS | CTL | ATL | TSB | Статус |
|---|---|---|---|---|---|
| Пн | 100 | 75.0 | 80.0 | -5.0 | Тренировка |
| Вт | 50 | 74.4 | 75.7 | -1.3 | Восстановление |
| Ср | 120 | 75.5 | 82.0 | -6.5 | Интенсивная тренировка |
| Чт | 0 | 73.7 | 70.3 | +3.4 | День отдыха |
| Пт | 80 | 73.8 | 71.7 | +2.1 | Умеренно |
| Сб | 150 | 75.6 | 82.9 | -7.3 | Длительная поездка |
| Вс | 40 | 74.8 | 76.8 | -2.0 | Восстановление |
Интерпретация TSB:
| Диапазон TSB | Статус | Действие |
|---|---|---|
| < -30 | Высокий риск | Предупреждение о перетренированности - снизить нагрузку |
| -30 до -10 | Интенсивная тренировка | Наращивание формы, контроль восстановления |
| -10 до +5 | Оптимально | Нормальная тренировочная зона |
| +5 до +15 | Готов к гонке | Пиковая форма - гонка в эти выходные |
| > +25 | Детренировка | Потеря формы - увеличить нагрузку |
Реализация на JavaScript:
function calculatePMC(workouts) {
// workouts = [{date: "YYYY-MM-DD", tss: число}, ...]
let ctl = 0, atl = 0;
const results = [];
workouts.forEach(workout => {
// Обновить CTL (42-дневная постоянная времени)
ctl = ctl + (workout.tss - ctl) / 42;
// Обновить ATL (7-дневная постоянная времени)
atl = atl + (workout.tss - atl) / 7;
// Рассчитать TSB (вчерашний CTL - сегодняшний ATL для традиционного расчета)
// Для простоты здесь используются текущие значения
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 "Высокий риск";
if (tsb < -10) return "Интенсивная тренировка";
if (tsb < 5) return "Оптимально";
if (tsb < 15) return "Готов к гонке";
return "Детренировка";
}
// Пример использования:
const workouts = [
{date: "2025-01-01", tss: 100},
{date: "2025-01-02", tss: 50},
{date: "2025-01-03", tss: 120},
// ... больше тренировок
];
const pmc = calculatePMC(workouts);
// Возвращает массив с CTL, ATL, TSB для каждого дня
Соотношение мощности к весу и метрики подъема
8. Соотношение мощности к весу
Формула:
Эталоны FTP Вт/кг:
| Уровень | Мужчины Вт/кг | Женщины Вт/кг | Категория |
|---|---|---|---|
| Любительский | 2.5 - 3.5 | 2.0 - 3.0 | Фитнес-гонщик |
| Соревновательный | 3.5 - 4.5 | 3.0 - 4.0 | Кат 3-4, возрастной гонщик |
| Продвинутый | 4.5 - 5.5 | 4.0 - 5.0 | Кат 1-2, сильный любитель |
| Элитный любитель | 5.5 - 6.0 | 5.0 - 5.5 | Национальный уровень |
| Профессионал | 6.0 - 7.0+ | 5.5 - 6.5+ | Мировой тур, Гранд-тур GC |
Пример расчета:
Сценарий: Велосипедист с FTP = 275 Вт, масса тела = 70 кг
Вт/кг = 275 / 70 = 3.93 Вт/кг
Интерпретация: Соревновательный уровень, способен на холмистых гонках
function calculateWattsPerKg(power, bodyMassKg) {
return (power / bodyMassKg).toFixed(2);
}
// Пример:
const wpkg = calculateWattsPerKg(275, 70);
// Возвращает: 3.93
9. VAM (Velocità Ascensionale Media)
Формула:
Эталоны VAM:
| VAM (м/ч) | Уровень | Пример |
|---|---|---|
| 600 - 900 | Любительский | Клубный гонщик на местном подъеме |
| 900 - 1200 | Соревновательный | Хороший любитель на Альп-д'Юэз |
| 1200 - 1500 | Элитный любитель | Скалолаз национального уровня |
| 1500 - 1800 | Профессионал | Доместик мирового тура |
| > 1800 | Победитель Гранд-тура | Погачар, Вингегор на ключевых подъемах |
Пример расчета:
Сценарий: Подъем Альп-д'Юэз
- Набор высоты: 1100 метров
- Время: 55 минут = 0.917 часа
- VAM = 1100 / 0.917 = 1200 м/ч
Интерпретация: Результат соревновательного уровня подъема
function calculateVAM(elevationGainMeters, timeMinutes) {
const hours = timeMinutes / 60;
return Math.round(elevationGainMeters / hours);
}
// Пример:
const vam = calculateVAM(1100, 55);
// Возвращает: 1200 м/ч
10. Оценка Вт/кг по VAM
Формула:
Пример расчета:
Сценарий: Подъем со средним градиентом 8%, VAM = 1200 м/ч
Вт/кг = 1200 / 100 / (8 + 3)
Вт/кг = 12 / 11 = 4.36 Вт/кг
Перекрестная проверка: При гонщике 70 кг → 305 Вт устойчивой мощности на подъеме
function estimateWkgFromVAM(vam, gradientPercent) {
return (vam / 100 / (gradientPercent + 3)).toFixed(2);
}
// Пример:
const wkg = estimateWkgFromVAM(1200, 8);
// Возвращает: 4.36
Уравнение аэродинамической мощности
11. Общие требования к мощности
Полная формула:
Формулы компонентов:
P_аэро = CdA × 0.5 × ρ × V³
P_гравитация = m × g × sin(θ) × V
P_качение = Crr × m × g × cos(θ) × V
P_кинетическая = m × a × V
Константы и переменные:
- CdA = Коэффициент сопротивления × фронтальная площадь (м²)
- Типичный шоссейный велосипед на капотах: 0.35-0.40 м²
- На дропах: 0.32-0.37 м²
- Позиция TT: 0.20-0.25 м²
- ρ = Плотность воздуха (1.225 кг/м³ на уровне моря, 15°C)
- V = Скорость (м/с)
- m = Общая масса (гонщик + велосипед, кг)
- g = Гравитация (9.81 м/с²)
- θ = Угол градиента (радианы или градусы преобразованные)
- Crr = Коэффициент сопротивления качению (~0.004 для хороших шоссейных шин)
- a = Ускорение (м/с²)
Рабочий пример (разделка на плоской дороге):
Сценарий:
- Скорость: 40 км/ч = 11.11 м/с
- CdA: 0.22 м² (хорошая позиция TT)
- Общая масса: 75 кг (гонщик) + 8 кг (велосипед) = 83 кг
- Плоская дорога (градиент = 0°)
- Постоянная скорость (ускорение = 0)
Расчет:
- P_аэро = 0.22 × 0.5 × 1.225 × 11.11³ = 185 Вт
- P_гравитация = 0 Вт (плоская дорога)
- P_качение = 0.004 × 83 × 9.81 × 11.11 = 36 Вт
- P_кинетическая = 0 Вт (постоянная скорость)
- P_общая = 185 + 0 + 36 + 0 = 221 Вт
Интерпретация: Необходимо 221 Вт для поддержания 40 км/ч в позиции TT на плоской дороге
Реализация на JavaScript:
function calculatePowerRequired(params) {
const {
velocityKph,
CdA = 0.32, // м²
rho = 1.225, // кг/м³
mass = 83, // кг (гонщик + велосипед)
gradientPercent = 0, // %
Crr = 0.004, // сопротивление качению
accelerationMps2 = 0 // м/с²
} = params;
// Преобразовать скорость в м/с
const V = velocityKph / 3.6;
// Преобразовать градиент в угол
const theta = Math.atan(gradientPercent / 100);
// Рассчитать каждый компонент
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)
};
}
// Пример: TT на 40 км/ч
const power_tt = calculatePowerRequired({
velocityKph: 40,
CdA: 0.22,
mass: 83,
gradientPercent: 0
});
// Возвращает: { total: 221, aero: 185, gravity: 0, rolling: 36, kinetic: 0 }
// Пример: 8% подъем на 15 км/ч
const power_climb = calculatePowerRequired({
velocityKph: 15,
CdA: 0.38,
mass: 75,
gradientPercent: 8
});
// Возвращает: { total: 265, aero: 27, gravity: 244, rolling: 11, kinetic: 0 }
Вспомогательные функции
Утилиты преобразования единиц
Реализация на JavaScript:
// Преобразования времени
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')}`;
}
// Преобразования скорости
function kphToMps(kph) {
return kph / 3.6;
}
function mpsToKph(mps) {
return mps * 3.6;
}
// Преобразования энергии
function joulesTo kJ(joules) {
return joules / 1000;
}
function kJToJoules(kJ) {
return kJ * 1000;
}
function wattsToKJ(watts, durationSeconds) {
return (watts * durationSeconds) / 1000;
}
// Примеры:
formatDuration(7265); // Возвращает: "2:01:05"
kphToMps(40); // Возвращает: 11.11 м/с
wattsToKJ(250, 3600); // Возвращает: 900 кДж (1 час на 250 Вт)
Ресурсы для реализации
Все формулы на этой странице готовы к использованию в производстве и проверены на соответствие научной литературе и реальным данным измерителей мощности. Используйте их для пользовательских аналитических инструментов, верификации или более глубокого понимания расчетов тренировок на основе мощности.
💡 Лучшие практики
- Проверяйте входные данные: Проверяйте разумные диапазоны мощности (0-2000 Вт), положительную продолжительность
- Обрабатывайте граничные случаи: Деление на ноль, null/undefined данные, отсутствующий FTP
- Округляйте правильно: CTL/ATL/TSB до 1 десятичного знака, TSS до целого, Вт/кг до 2 десятичных знаков
- Храните точность: Сохраняйте полную точность в базе данных, округляйте только для отображения
- Часовые пояса: Последовательно обрабатывайте UTC против локального времени для многодневного анализа
- Калибровка измерителя мощности: Напоминайте пользователям о нулевом смещении перед поездками
- Проверка FTP: Отмечайте подозрительные значения FTP (>500 Вт или <100 Вт для взрослых)
- Тестируйте тщательно: Используйте проверенные файлы поездок для верификации расчетов