Техническая справка и формулы
Полная математическая реализация
Руководство по реализации
На этой странице представлены готовые к копированию формулы и пошаговые методы расчета всех метрик Run Analytics. Используйте их для собственных реализаций, проверки или углубленного понимания.
⚠️ Примечания по реализации
- Все значения времени должны быть преобразованы в секунды для расчетов
- Темп бега обратно пропорционален (более высокий % = более медленный темп)
- Всегда проверяйте входные данные на разумность диапазонов
- Обрабатывайте крайние случаи (деление на ноль, отрицательные значения)
Основные метрики производительности
Критическая скорость бега (CRS)
Формула:
CRS (м/с) = (D₂ - D₁) / (T₂ - T₁)
Темп CRS (мин/км) = 1000 / CRS (м/с) / 60
🧪 Интерактивный калькулятор - Тестирование формулы
Темп CRS:
4:15/км
Шаги расчета:
CRS (м/с) = (3600 - 1200) / (864 - 252) = 3.92 м/с
Темп = 1000 / 3.92 = 255 секунд = 4:15/км
CRS (м/с) = (3600 - 1200) / (864 - 252) = 3.92 м/с
Темп = 1000 / 3.92 = 255 секунд = 4:15/км
Реализация на JavaScript:
function calculateCRS(distance1, time1, distance2, time2) {
// Convert times to seconds if needed
const t1 = typeof time1 === 'string' ? timeToSeconds(time1) : time1;
const t2 = typeof time2 === 'string' ? timeToSeconds(time2) : time2;
// Calculate CRS in m/s
const crs_ms = (distance2 - distance1) / (t2 - t1);
// Calculate pace per km in seconds
const pace_per_km = 1000 / crs_ms;
// Convert to mm:ss format
const minutes = Math.floor(pace_per_km / 60);
const seconds = Math.round(pace_per_km % 60);
return {
crs_ms: crs_ms,
pace_seconds: pace_per_km,
pace_formatted: `${minutes}:${seconds.toString().padStart(2, '0')}/км`
};
}
// Example usage:
const result = calculateCRS(1200, 252, 3600, 864);
// Returns: { crs_ms: 3.92, pace_seconds: 255, pace_formatted: "4:15/км" }Балл беговой тренировочной нагрузки (sTSS)
Полная формула:
sTSS = (IF³) × Продолжительность (часы) × 100
IF = NSS / Пороговая скорость
NSS = Общая дистанция / Общее время (м/мин)
🧪 Интерактивный калькулятор - Тестирование формулы
Рассчитанный sTSS:
26
Шаги расчета:
NSS = 5000м / 25мин = 200.0 м/мин
Пороговая скорость = 1000 / (255/60) = 235.3 м/мин
IF = 200.0 / 235.3 = 0.850
sTSS = 0.850³ × (25/60) × 100 = 26
NSS = 5000м / 25мин = 200.0 м/мин
Пороговая скорость = 1000 / (255/60) = 235.3 м/мин
IF = 200.0 / 235.3 = 0.850
sTSS = 0.850³ × (25/60) × 100 = 26
Реализация на JavaScript:
function calculateSTSS(distance, timeMinutes, thresholdSpeed) {
// Calculate Normalized Run Speed
const nss = distance / timeMinutes;
// Calculate Intensity Factor
const intensityFactor = nss / thresholdSpeed;
// Calculate hours
const hours = timeMinutes / 60;
// Calculate sTSS using cubed intensity factor
const stss = Math.pow(intensityFactor, 3) * hours * 100;
return Math.round(stss);
}
// Example usage:
const stss = calculateSTSS(5000, 25, 235.3);
// Returns: 25
// Helper: Convert CRS Pace to Running Speed (m/min)
function crsPaceToSpeed(crsPacePerKmSeconds) {
// Speed in m/min = 1000m / (pace in minutes)
return 1000 / (crsPacePerKmSeconds / 60);
}
// Example: CRS of 4:15 (255 seconds)
const speed = crsPaceToSpeed(255); // Returns: 235.3 m/minЭффективность бега: Вертикальный коэффициент
Формула:
Вертикальный коэффициент (%) = (Вертикальная осцилляция ÷ Длина шага) × 100
🧪 Интерактивный калькулятор - Тестирование формулы
Вертикальный коэффициент:
6.4%
Расчет:
Вертикальный коэффициент = (8 ÷ 125) × 100 = 6.4%
Вертикальный коэффициент = (8 ÷ 125) × 100 = 6.4%
Эталоны:
- Элитные бегуны: < 6.0%
- Соревновательные: 6.1% - 8.0%
- Фитнес-бегуны: 8.1% - 10.0%
- Развивающиеся: > 10.0%
Реализация на JavaScript:
function calculateVerticalRatio(verticalOscillation, strideLength) {
// Both values in same units (cm or m)
return (verticalOscillation / strideLength) * 100;
}
// Example:
const vr = calculateVerticalRatio(8, 125);
// Returns: 6.4%Бег Механика шага
Частота шагов (Каденс)
Формула:
Каденс (SPM) = 60 / Время цикла (секунды)
Каденс (SPM) = (Количество шагов / Время в секундах) × 60
🧪 Интерактивный калькулятор - Тестирование формулы
Каденс (SPM):
180
Расчет:
Каденс = (180 / 60) × 60 = 180 SPM
Каденс = (180 / 60) × 60 = 180 SPM
Реализация на JavaScript:
function calculateCadence(stepCount, timeSeconds) {
return (stepCount / timeSeconds) * 60;
}
// Example:
const cadence = calculateCadence(180, 60);
// Returns: 180 SPMДлина шага
Формула:
Длина шага = Дистанция / (Количество шагов / 2)
Длина шага = Скорость / (Каденс / 120)
Реализация на JavaScript:
function calculateStrideLength(distanceMeters, stepCount) {
// Stride length is distance / number of stride pairs (left+right)
return distanceMeters / (stepCount / 2);
}
// Example (1000m, 800 steps):
const strideLength = calculateStrideLength(1000, 800);
// Returns: 2.50 м/шагСкорость из каденса и длины шага
Формула:
Скорость (м/с) = (Каденс / 60) × Длина шага (м)
Примечание: Каденс обычно измеряется в шагах в минуту (SPM). Для расчета скорости в м/с мы делим на 60, чтобы получить шаги в секунду.
Реализация на JavaScript:
function calculateVelocity(cadence, strideLength) {
// cadence in steps per minute (SPM), strideLength in meters
return (cadence / 60) * strideLength;
}
// Пример (Каденс 180, Длина шага 1.25м):
const velocity = calculateVelocity(180, 1.25);
// Возвращает: 3.75 м/с (4:27/км)Индекс шага (SI)
Формула:
SI = Скорость (м/с) × Длина шага (м)
Реализация на JavaScript:
function calculateStrideIndex(velocity, strideLength) {
return velocity * strideLength;
}
// Пример:
const si = calculateStrideIndex(3.75, 1.25);
// Возвращает: 4.69График управления производительностью (PMC) для бега
Расчеты CTL, ATL, TSB
Формулы:
CTL сегодня = CTL вчера + (TSS сегодня - CTL вчера) × (1/42)
ATL сегодня = ATL вчера + (TSS сегодня - ATL вчера) × (1/7)
TSB = CTL вчера - ATL вчера
Реализация на JavaScript:
function updateCTL(previousCTL, todayTSS) {
return previousCTL + (todayTSS - previousCTL) * (1/42);
}
function updateATL(previousATL, todayTSS) {
return previousATL + (todayTSS - previousATL) * (1/7);
}
function calculateTSB(yesterdayCTL, yesterdayATL) {
return yesterdayCTL - yesterdayATL;
}
// Calculate PMC for series of workouts
function calculatePMC(workouts) {
let ctl = 0, atl = 0;
const results = [];
workouts.forEach(workout => {
ctl = updateCTL(ctl, workout.tss);
atl = updateATL(atl, workout.tss);
const tsb = calculateTSB(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
});
});
return results;
}
// Example usage:
const workouts = [
{ date: '2025-01-01', tss: 50 },
{ date: '2025-01-02', tss: 60 },
{ date: '2025-01-03', tss: 45 },
// ... more workouts
];
const pmc = calculatePMC(workouts);
// Returns array with CTL, ATL, TSB for each dayРасширенные расчеты
CRS из нескольких дистанций (метод регрессии)
Реализация на JavaScript:
function calculateCRSRegression(distances, times) {
// Linear regression: distance = a + b*time
const n = distances.length;
const sumX = times.reduce((a, b) => a + b, 0);
const sumY = distances.reduce((a, b) => a + b, 0);
const sumXY = times.reduce((sum, x, i) => sum + x * distances[i], 0);
const sumXX = times.reduce((sum, x) => sum + x * x, 0);
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
const intercept = (sumY - slope * sumX) / n;
return {
crs: slope, // Критическая скорость бега (m/s)
anaerobic_capacity: intercept // Анаэробная емкость (м)
};
}
// Пример с несколькими тестовыми дистанциями:
const distances = [1200, 2400, 3600];
const times = [252, 540, 864]; // в секундах
const result = calculateCRSRegression(distances, times);
// Возвращает: { crs: 3.92, anaerobic_capacity: 211.7 }Фактор интенсивности по темпу
Реализация на JavaScript:
function calculateIntensityFactor(actualPaceMinKm, thresholdPaceMinKm) {
// Convert pace strings "mm:ss" to seconds if necessary
const actualSecs = typeof actualPaceMinKm === 'string' ? timeToSeconds(actualPaceMinKm) : actualPaceMinKm;
const thresholdSecs = typeof thresholdPaceMinKm === 'string' ? timeToSeconds(thresholdPaceMinKm) : thresholdPaceMinKm;
// IF is Threshold Pace / Actual Pace (faster pace = smaller seconds value)
return thresholdSecs / actualSecs;
}
// Example:
const if_value = calculateIntensityFactor("4:45", "4:15");
// Returns: 0.895 (running at 89.5% of threshold)Анализ постоянства темпа
Реализация на JavaScript:
function analyzePaceConsistency(segments) {
const paces = segments.map(kilometer => kilometer.distance / kilometer.time);
const avgPace = paces.reduce((a, b) => a + b) / paces.length;
const variance = paces.reduce((sum, pace) =>
sum + Math.pow(pace - avgPace, 2), 0) / paces.length;
const stdDev = Math.sqrt(variance);
const coefficientOfVariation = (stdDev / avgPace) * 100;
return {
avgPace,
stdDev,
coefficientOfVariation,
consistency: coefficientOfVariation < 5 ? "Отлично" :
coefficientOfVariation < 10 ? "Хорошо" :
coefficientOfVariation < 15 ? "Умеренно" : "Изменчиво"
};
}
// Example:
const segments = [
{ distance: 100, time: 70 },
{ distance: 100, time: 72 },
{ distance: 100, time: 71 },
// ...
];
const analysis = analyzePaceConsistency(segments);
// Returns: { avgPace: 1.41, stdDev: 0.02, coefficientOfVariation: 1.4, consistency: "Отлично" }Обнаружение усталости по количеству шагов
Реализация на JavaScript:
function detectFatigue(segments) {
const firstThird = segments.slice(0, Math.floor(segments.length/3));
const lastThird = segments.slice(-Math.floor(segments.length/3));
const firstThirdAvg = firstThird.reduce((sum, kilometer) =>
sum + kilometer.strideCount, 0) / firstThird.length;
const lastThirdAvg = lastThird.reduce((sum, kilometer) =>
sum + kilometer.strideCount, 0) / lastThird.length;
const strideCountIncrease = ((lastThirdAvg - firstThirdAvg) / firstThirdAvg) * 100;
return {
firstThirdAvg: Math.round(firstThirdAvg * 10) / 10,
lastThirdAvg: Math.round(lastThirdAvg * 10) / 10,
percentIncrease: Math.round(strideCountIncrease * 10) / 10,
fatigueLevel: strideCountIncrease < 5 ? "Минимальная" :
strideCountIncrease < 10 ? "Умеренная" :
strideCountIncrease < 20 ? "Значительная" : "Сильная"
};
}
// Example:
const segments = [
{ strideCount: 14 }, { strideCount: 14 }, { strideCount: 15 },
{ strideCount: 15 }, { strideCount: 16 }, { strideCount: 16 },
{ strideCount: 17 }, { strideCount: 18 }, { strideCount: 18 }
];
const fatigue = detectFatigue(segments);
// Returns: { firstThirdAvg: 14.3, lastThirdAvg: 17.7, percentIncrease: 23.8, fatigueLevel: "Сильная" }Проверка данных
Проверка качества данных тренировки
Реализация на JavaScript:
function validateWorkoutData(workout) {
const issues = [];
// Check for reasonable pace ranges (3:00-8:00 per km)
const avgPaceSecs = workout.totalTime / (workout.totalDistance / 1000);
if (avgPaceSecs < 180 || avgPaceSecs > 480) {
issues.push(`Необычный средний темп: ${Math.round(avgPaceSecs)}с на км`);
}
// Check for reasonable Vertical Ratio (4% - 15%)
if (workout.avgVerticalRatio < 4 || workout.avgVerticalRatio > 15) {
issues.push(`Необычный вертикальный коэффициент: ${workout.avgVerticalRatio}%`);
}
// Check for reasonable cadence (120-220 SPM)
const avgCadence = calculateCadence(workout.totalSteps, workout.totalTime);
if (avgCadence < 120 || avgCadence > 220) {
issues.push(`Необычная частота шагов: ${Math.round(avgCadence)} ШПМ`);
}
// Check for missing segments (gaps in time)
if (workout.segments && workout.segments.length > 1) {
for (let i = 1; i < workout.segments.length; i++) {
const gap = workout.segments[i].startTime -
(workout.segments[i-1].startTime + workout.segments[i-1].duration);
if (gap > 300) { // 5 minute gap
issues.push(`Обнаружен большой промежуток между сегментами ${i} и ${i+1}`);
}
}
}
return {
isValid: issues.length === 0,
issues
};
}
// Example:
const workout = {
totalDistance: 2000,
totalTime: 1800, // 30 minutes
totalStrides: 800,
segments: [/* kilometer data */]
};
const validation = validateWorkoutData(workout);
// Returns: { isValid: true, issues: [] }Вспомогательные функции
Утилиты преобразования времени
Реализация на JavaScript:
// Convert mm:ss to seconds
function timeToSeconds(timeString) {
const parts = timeString.split(':');
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
// Convert seconds to mm:ss
function secondsToTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = Math.round(seconds % 60);
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
// Convert seconds to hh:mm:ss
function secondsToTimeDetailed(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')}`;
}
// Examples:
timeToSeconds("1:33"); // Returns: 93
secondsToTime(93); // Returns: "1:33"
secondsToTimeDetailed(3665); // Returns: "1:01:05"Ресурсы для реализации
Все формулы на этой странице готовы к использованию и проверены на соответствие научной литературе. Используйте их для создания собственных аналитических инструментов, проверки или углубленного понимания расчетов беговых показателей.
💡 Лучшие практики
- Проверяйте входные данные: Проверяйте разумность диапазонов перед расчетами
- Обрабатывайте крайние случаи: Деление на ноль, отрицательные значения, пустые данные
- Округляйте правильно: CTL/ATL/TSB до 1 знака после запятой, sTSS до целого числа
- Сохраняйте точность: Храните полную точность в базе данных, округляйте для отображения
- Тщательно тестируйте: Используйте заведомо правильные данные для проверки расчетов
