Dokumentacja techniczna i formuły

Kompletna implementacja matematyczna

Przewodnik implementacji

Ta strona zawiera formuły gotowe do skopiowania oraz metodologie krok po kroku dla wszystkich wskaźników Run Analytics. Użyj ich do własnych implementacji, weryfikacji lub głębszego zrozumienia.

⚠️ Uwagi dotyczące implementacji

  • Wszystkie czasy powinny być konwertowane na sekundy do obliczeń
  • Tempo biegu jest odwrotne (wyższy % = wolniejsze tempo)
  • Zawsze sprawdzaj poprawność danych wejściowych pod kątem rozsądnych zakresów
  • Obsługuj przypadki skrajne (dzielenie przez zero, wartości ujemne)

Podstawowe wskaźniki wydajności

Krytyczna prędkość biegowa (CRS)

Formuła:

CRS (m/s) = (D₂ - D₁) / (T₂ - T₁)
Tempo CRS/100m (sekundy) = (T₄₀₀ - T₂₀₀) / 2

🧪 Interaktywny kalkulator - Przetestuj formułę

Tempo CRS na 100m:
1:49
Kroki obliczeń:
CRS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Tempo/100m = 100 / 0.917 = 109 sekund = 1:49

Implementacja JavaScript:

function calculateCRS(distance1, time1, distance2, time2) {
  // Konwertuj czasy na sekundy, jeśli potrzeba
  const t1 = typeof time1 === 'string' ? timeToSeconds(time1) : time1;
  const t2 = typeof time2 === 'string' ? timeToSeconds(time2) : time2;

  // Oblicz CRS w m/s
  const css_ms = (distance2 - distance1) / (t2 - t1);

  // Oblicz tempo na 100m w sekundach
  const pace_per_100m = 100 / css_ms;

  // Konwertuj do formatu mm:ss
  const minutes = Math.floor(pace_per_100m / 60);
  const seconds = Math.round(pace_per_100m % 60);

  return {
    css_ms: css_ms,
    pace_seconds: pace_per_100m,
    pace_formatted: `${minutes}:${seconds.toString().padStart(2, '0')}`
  };
}

// Przykład użycia:
const result = calculateCRS(200, 150, 400, 368);
// Zwraca: { css_ms: 0.917, pace_seconds: 109, pace_formatted: "1:49" }

Wynik obciążenia treningowego (sTSS)

Pełna formuła:

sTSS = (IF³) × Czas trwania (godziny) × 100
IF = NSS / FTP
NSS = Całkowity dystans / Całkowity czas (m/min)

🧪 Interaktywny kalkulator - Przetestuj formułę

Obliczone sTSS:
55
Kroki obliczeń:
NSS = 3000m / 55min = 54.5 m/min
FTP = 100 / (93/60) = 64.5 m/min
IF = 54.5 / 64.5 = 0.845
sTSS = 0.845³ × (55/60) × 100 = 55

Implementacja JavaScript:

function calculateSTSS(distance, timeMinutes, ftpMetersPerMin) {
  // Oblicz znormalizowaną prędkość biegu
  const nss = distance / timeMinutes;

  // Oblicz współczynnik intensywności
  const intensityFactor = nss / ftpMetersPerMin;

  // Oblicz godziny
  const hours = timeMinutes / 60;

  // Oblicz sTSS używając współczynnika intensywności do sześcianu
  const stss = Math.pow(intensityFactor, 3) * hours * 100;

  return Math.round(stss);
}

// Przykład użycia:
const stss = calculateSTSS(3000, 55, 64.5);
// Zwraca: 55

// Funkcja pomocnicza: Konwertuj CRS na FTP
function cssToFTP(cssPacePer100mSeconds) {
  // FTP w m/min = 100m / (tempo w minutach)
  return 100 / (cssPacePer100mSeconds / 60);
}

// Przykład: CRS 1:33 (93 sekundy)
const ftp = cssToFTP(93); // Zwraca: 64.5 m/min

Efektywność biegu

Formuła:

Efektywność biegu = Czas kilometra (sekundy) + Liczba kroków
Efektywność biegu₂₅ = (Czas × 25/Długość trasy) + (Kroki × 25/Długość trasy)

🧪 Interaktywny kalkulator - Przetestuj formułę

Wynik efektywności biegu:
35
Obliczenia:
Efektywność biegu = 20s + 15 kroków = 35

Implementacja JavaScript:

function calculateRunningEfficiency(timeSeconds, strideCount) {
  return timeSeconds + strideCount;
}

function calculateNormalizedRunningEfficiency(timeSeconds, strideCount, trackLength) {
  const normalizedTime = timeSeconds * (25 / trackLength);
  const normalizedStrides = strideCount * (25 / trackLength);
  return normalizedTime + normalizedStrides;
}

// Przykład:
const swolf = calculateRunningEfficiency(20, 15);
// Zwraca: 35

const swolf50m = calculateNormalizedRunningEfficiency(40, 30, 50);
// Zwraca: 35 (znormalizowane do 25m)

Mechanika kroków

Częstotliwość kroków (SR)

Formuła:

SR = 60 / Czas cyklu (sekundy)
SR = (Liczba kroków / Czas w sekundach) × 60

🧪 Interaktywny kalkulator - Przetestuj formułę

Częstotliwość kroków (SPM):
72
Obliczenia:
SR = (30 / 25) × 60 = 72 SPM

Implementacja JavaScript:

function calculateStrideRate(strideCount, timeSeconds) {
  return (strideCount / timeSeconds) * 60;
}

// Przykład:
const sr = calculateStrideRate(30, 25);
// Zwraca: 72 SPM

Dystans na krok (DPS)

Formuła:

DPS = Dystans / Liczba kroków
DPS = Dystans / (SR / 60)

Implementacja JavaScript:

function calculateDPS(distance, strideCount, pushoffDistance = 0) {
  const effectiveDistance = distance - pushoffDistance;
  return effectiveDistance / strideCount;
}

// Przykład (trasa 25m, 5m odbicia):
const dps = calculateDPS(25, 12, 5);
// Zwraca: 1.67 m/krok

// Dla wielu segmentów:
const dps100m = calculateDPS(100, 48, 4 * 5);
// Zwraca: 1.67 m/krok (4 segmenty × 5m odbicia)

Prędkość z SR i DPS

Formuła:

Prędkość (m/s) = (SR / 60) × DPS

Implementacja JavaScript:

function calculateVelocity(strideRate, dps) {
  return (strideRate / 60) * dps;
}

// Przykład:
const velocity = calculateVelocity(70, 1.6);
// Zwraca: 1.87 m/s

Wskaźnik kroku (SI)

Formuła:

SI = Prędkość (m/s) × DPS (m/krok)

Implementacja JavaScript:

function calculateStrideIndex(velocity, dps) {
  return velocity * dps;
}

// Przykład:
const si = calculateStrideIndex(1.5, 1.7);
// Zwraca: 2.55

Wykres zarządzania wydajnością (PMC)

Obliczenia CTL, ATL, TSB

Formuły:

CTL dzisiaj = CTL wczoraj + (TSS dzisiaj - CTL wczoraj) × (1/42)
ATL dzisiaj = ATL wczoraj + (TSS dzisiaj - ATL wczoraj) × (1/7)
TSB = CTL wczoraj - ATL wczoraj

Implementacja 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;
}

// Oblicz PMC dla serii treningów
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;
}

// Przykład użycia:
const workouts = [
  { date: '2025-01-01', tss: 50 },
  { date: '2025-01-02', tss: 60 },
  { date: '2025-01-03', tss: 45 },
  // ... więcej treningów
];

const pmc = calculatePMC(workouts);
// Zwraca tablicę z CTL, ATL, TSB dla każdego dnia

Zaawansowane obliczenia

CRS z wielu dystansów (metoda regresji)

Implementacja JavaScript:

function calculateCRSRegression(distances, times) {
  // Regresja liniowa: dystans = a + b*czas
  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 {
    css: slope, // Krytyczna prędkość biegowa (m/s)
    anaerobic_capacity: intercept // Beztlenowa pojemność dystansowa (m)
  };
}

// Przykład z wieloma dystansami testowymi:
const distances = [100, 200, 400, 800];
const times = [65, 150, 340, 720]; // w sekundach
const result = calculateCRSRegression(distances, times);
// Zwraca: { css: 1.18, anaerobic_capacity: 15.3 }

Współczynnik intensywności z tempa

Implementacja JavaScript:

function calculateIntensityFactor(actualPace100m, thresholdPace100m) {
  // Konwertuj tempo na prędkość (m/s)
  const actualSpeed = 100 / actualPace100m;
  const thresholdSpeed = 100 / thresholdPace100m;
  return actualSpeed / thresholdSpeed;
}

// Przykład:
const if_value = calculateIntensityFactor(110, 93);
// Zwraca: 0.845 (bieg na 84.5% progu)

Analiza równości tempa

Implementacja 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 ? "Doskonała" :
                 coefficientOfVariation < 10 ? "Dobra" :
                 coefficientOfVariation < 15 ? "Umiarkowana" : "Zmienna"
  };
}

// Przykład:
const segments = [
  { distance: 100, time: 70 },
  { distance: 100, time: 72 },
  { distance: 100, time: 71 },
  // ...
];
const analysis = analyzePaceConsistency(segments);
// Zwraca: { avgPace: 1.41, stdDev: 0.02, coefficientOfVariation: 1.4, consistency: "Doskonała" }

Wykrywanie zmęczenia na podstawie liczby kroków

Implementacja 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 ? "Minimalne" :
                  strideCountIncrease < 10 ? "Umiarkowane" :
                  strideCountIncrease < 20 ? "Znaczne" : "Ciężkie"
  };
}

// Przykład:
const segments = [
  { strideCount: 14 }, { strideCount: 14 }, { strideCount: 15 },
  { strideCount: 15 }, { strideCount: 16 }, { strideCount: 16 },
  { strideCount: 17 }, { strideCount: 18 }, { strideCount: 18 }
];
const fatigue = detectFatigue(segments);
// Zwraca: { firstThirdAvg: 14.3, lastThirdAvg: 17.7, percentIncrease: 23.8, fatigueLevel: "Ciężkie" }

Walidacja danych

Kontrole jakości danych treningowych

Implementacja JavaScript:

function validateWorkoutData(workout) {
  const issues = [];

  // Sprawdź rozsądne zakresy tempa (1:00-5:00 na 100m)
  const avgPace = (workout.totalTime / workout.totalDistance) * 100;
  if (avgPace < 60 || avgPace > 300) {
    issues.push(`Nietypowe średnie tempo: ${Math.round(avgPace)}s na 100m`);
  }

  // Sprawdź rozsądną liczbę kroków (10-50 na 25m)
  const avgStridesPer25m = (workout.totalStrides / workout.totalDistance) * 25;
  if (avgStridesPer25m < 10 || avgStridesPer25m > 50) {
    issues.push(`Nietypowa liczba kroków: ${Math.round(avgStridesPer25m)} na 25m`);
  }

  // Sprawdź rozsądną częstotliwość kroków (30-150 SPM)
  const avgSR = calculateStrideRate(workout.totalStrides, workout.totalTime);
  if (avgSR < 30 || avgSR > 150) {
    issues.push(`Nietypowa częstotliwość kroków: ${Math.round(avgSR)} SPM`);
  }

  // Sprawdź brakujące segmenty (przerwy w czasie)
  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-minutowa przerwa
        issues.push(`Wykryto dużą przerwę między segmentami ${i} i ${i+1}`);
      }
    }
  }

  return {
    isValid: issues.length === 0,
    issues
  };
}

// Przykład:
const workout = {
  totalDistance: 2000,
  totalTime: 1800, // 30 minut
  totalStrides: 800,
  segments: [/* dane kilometrów */]
};
const validation = validateWorkoutData(workout);
// Zwraca: { isValid: true, issues: [] }

Funkcje pomocnicze

Narzędzia konwersji czasu

Implementacja JavaScript:

// Konwertuj mm:ss na sekundy
function timeToSeconds(timeString) {
  const parts = timeString.split(':');
  return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}

// Konwertuj sekundy na mm:ss
function secondsToTime(seconds) {
  const minutes = Math.floor(seconds / 60);
  const secs = Math.round(seconds % 60);
  return `${minutes}:${secs.toString().padStart(2, '0')}`;
}

// Konwertuj sekundy na 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')}`;
}

// Przykłady:
timeToSeconds("1:33"); // Zwraca: 93
secondsToTime(93); // Zwraca: "1:33"
secondsToTimeDetailed(3665); // Zwraca: "1:01:05"

Zasoby implementacji

Wszystkie formuły na tej stronie są gotowe do produkcji i zwalidowane względem literatury naukowej. Użyj ich do tworzenia własnych narzędzi analitycznych, weryfikacji lub głębszego zrozumienia obliczeń wydajności biegowej.

💡 Najlepsze praktyki

  • Waliduj dane wejściowe: Sprawdź rozsądne zakresy przed obliczeniami
  • Obsługuj przypadki skrajne: Dzielenie przez zero, wartości ujemne, brak danych
  • Zaokrąglaj odpowiednio: CTL/ATL/TSB do 1 miejsca po przecinku, sTSS do liczby całkowitej
  • Przechowuj precyzję: Zachowaj pełną precyzję w bazie danych, zaokrąglaj tylko do wyświetlania
  • Testuj dokładnie: Użyj sprawdzonych danych do weryfikacji obliczeń