Rujukan Teknikal & Formula

Pelaksanaan Matematik Lengkap

Panduan Pelaksanaan

Halaman ini menyediakan formula siap salin dan kaedah pengiraan langkah demi langkah untuk semua metrik Run Analytics. Gunakan untuk pelaksanaan tersuai, pengesahan, atau pemahaman yang lebih mendalam.

⚠️ Nota Pelaksanaan

  • Semua masa perlu ditukar kepada saat untuk pengiraan
  • Kadar larian adalah songsang (% lebih tinggi = kadar lebih perlahan)
  • Sentiasa sahkan input untuk julat yang munasabah
  • Kendali kes tepi (pembahagian dengan sifar, nilai negatif)

Metrik Prestasi Teras

Kelajuan Larian Kritikal (CRS)

Formula:

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

🧪 Kalkulator Interaktif - Uji Formula

CRS Kadar per 100m:
1:49
Langkah pengiraan:
CRS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Kadar/100m = 100 / 0.917 = 109 saat = 1:49

Pelaksanaan 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 css_ms = (distance2 - distance1) / (t2 - t1);

  // Calculate pace per 100m in seconds
  const pace_per_100m = 100 / css_ms;

  // Convert to mm:ss format
  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')}`
  };
}

// Example usage:
const result = calculateCRS(200, 150, 400, 368);
// Returns: { css_ms: 0.917, pace_seconds: 109, pace_formatted: "1:49" }

Skor Tekanan Latihan Larian (sTSS)

Formula Lengkap:

sTSS = (IF³) × Tempoh (jam) × 100
IF = NSS / FTP
NSS = Jumlah Jarak / Jumlah Masa (m/min)

🧪 Kalkulator Interaktif - Uji Formula

sTSS Dikira:
55
Langkah pengiraan:
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

Pelaksanaan JavaScript:

function calculateSTSS(distance, timeMinutes, ftpMetersPerMin) {
  // Calculate Normalized Run Speed
  const nss = distance / timeMinutes;

  // Calculate Intensity Factor
  const intensityFactor = nss / ftpMetersPerMin;

  // 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(3000, 55, 64.5);
// Returns: 55

// Helper: Convert CRS to FTP
function cssToFTP(cssPacePer100mSeconds) {
  // FTP in m/min = 100m / (pace in minutes)
  return 100 / (cssPacePer100mSeconds / 60);
}

// Example: CRS of 1:33 (93 seconds)
const ftp = cssToFTP(93); // Returns: 64.5 m/min

Kecekapan Larian

Formula:

Kecekapan Larian = Masa Kilometer (saat) + Kiraan Langkah
Kecekapan Larian₂₅ = (Masa × 25/Panjang Trek) + (Langkah × 25/Panjang Trek)

🧪 Kalkulator Interaktif - Uji Formula

Skor Kecekapan Larian:
35
Pengiraan:
Kecekapan Larian = 20s + 15 langkah = 35

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

// Example:
const swolf = calculateRunningEfficiency(20, 15);
// Returns: 35

const swolf50m = calculateNormalizedRunningEfficiency(40, 30, 50);
// Returns: 35 (normalized to 25m)

Mekanik Langkah

Kadar Langkah (SR)

Formula:

SR = 60 / Masa Kitaran (saat)
SR = (Bilangan Langkah / Masa dalam saat) × 60

🧪 Kalkulator Interaktif - Uji Formula

Kadar Langkah (SPM):
72
Pengiraan:
SR = (30 / 25) × 60 = 72 SPM

Pelaksanaan JavaScript:

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

// Example:
const sr = calculateStrideRate(30, 25);
// Returns: 72 SPM

Jarak Per Langkah (DPS)

Formula:

DPS = Jarak / Kiraan Langkah
DPS = Jarak / (SR / 60)

Pelaksanaan JavaScript:

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

// Example (25m track, 5m push-off):
const dps = calculateDPS(25, 12, 5);
// Returns: 1.67 m/stride

// For multiple segments:
const dps100m = calculateDPS(100, 48, 4 * 5);
// Returns: 1.67 m/stride (4 segments × 5m push-off)

Halaju daripada SR dan DPS

Formula:

Halaju (m/s) = (SR / 60) × DPS

Pelaksanaan JavaScript:

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

// Example:
const velocity = calculateVelocity(70, 1.6);
// Returns: 1.87 m/s

Indeks Langkah (SI)

Formula:

SI = Halaju (m/s) × DPS (m/langkah)

Pelaksanaan JavaScript:

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

// Example:
const si = calculateStrideIndex(1.5, 1.7);
// Returns: 2.55

Carta Pengurusan Prestasi (PMC)

Pengiraan CTL, ATL, TSB

Formula:

CTL hari ini = CTL semalam + (TSS hari ini - CTL semalam) × (1/42)
ATL hari ini = ATL semalam + (TSS hari ini - ATL semalam) × (1/7)
TSB = CTL semalam - ATL semalam

Pelaksanaan 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

Pengiraan Lanjutan

CRS daripada Pelbagai Jarak (Kaedah Regresi)

Pelaksanaan 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 {
    css: slope, // Critical running velocity (m/s)
    anaerobic_capacity: intercept // Anaerobic distance capacity (m)
  };
}

// Example with multiple test distances:
const distances = [100, 200, 400, 800];
const times = [65, 150, 340, 720]; // in seconds
const result = calculateCRSRegression(distances, times);
// Returns: { css: 1.18, anaerobic_capacity: 15.3 }

Faktor Keamatan daripada Kadar

Pelaksanaan JavaScript:

function calculateIntensityFactor(actualPace100m, thresholdPace100m) {
  // Convert pace to speed (m/s)
  const actualSpeed = 100 / actualPace100m;
  const thresholdSpeed = 100 / thresholdPace100m;
  return actualSpeed / thresholdSpeed;
}

// Example:
const if_value = calculateIntensityFactor(110, 93);
// Returns: 0.845 (running at 84.5% of threshold)

Analisis Ketekalan Kadar

Pelaksanaan 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 ? "Cemerlang" :
                 coefficientOfVariation < 10 ? "Baik" :
                 coefficientOfVariation < 15 ? "Sederhana" : "Berubah-ubah"
  };
}

// 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: "Cemerlang" }

Pengesanan Keletihan daripada Kiraan Langkah

Pelaksanaan 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 ? "Minima" :
                  strideCountIncrease < 10 ? "Sederhana" :
                  strideCountIncrease < 20 ? "Ketara" : "Teruk"
  };
}

// 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: "Teruk" }

Pengesahan Data

Pemeriksaan Kualiti Data Latihan

Pelaksanaan JavaScript:

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

  // Check for reasonable pace ranges (1:00-5:00 per 100m)
  const avgPace = (workout.totalTime / workout.totalDistance) * 100;
  if (avgPace < 60 || avgPace > 300) {
    issues.push(`Kadar purata luar biasa: ${Math.round(avgPace)}s per 100m`);
  }

  // Check for reasonable stride counts (10-50 per 25m)
  const avgStridesPer25m = (workout.totalStrides / workout.totalDistance) * 25;
  if (avgStridesPer25m < 10 || avgStridesPer25m > 50) {
    issues.push(`Kiraan langkah luar biasa: ${Math.round(avgStridesPer25m)} per 25m`);
  }

  // Check for reasonable stride rate (30-150 SPM)
  const avgSR = calculateStrideRate(workout.totalStrides, workout.totalTime);
  if (avgSR < 30 || avgSR > 150) {
    issues.push(`Kadar langkah luar biasa: ${Math.round(avgSR)} SPM`);
  }

  // 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(`Jurang besar dikesan antara segmen ${i} dan ${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: [] }

Fungsi Pembantu

Utiliti Penukaran Masa

Pelaksanaan 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"

Sumber Pelaksanaan

Semua formula di halaman ini bersedia untuk pengeluaran dan disahkan terhadap kesusasteraan saintifik. Gunakan untuk alat analitik tersuai, pengesahan, atau pemahaman yang lebih mendalam tentang pengiraan prestasi larian.

💡 Amalan Terbaik

  • Sahkan input: Semak julat yang munasabah sebelum mengira
  • Kendali kes tepi: Pembahagian dengan sifar, nilai negatif, data null
  • Bulatkan dengan sesuai: CTL/ATL/TSB kepada 1 perpuluhan, sTSS kepada integer
  • Simpan ketepatan: Kekalkan ketepatan penuh dalam pangkalan data, bulatkan untuk paparan
  • Uji dengan teliti: Gunakan data yang diketahui baik untuk mengesahkan pengiraan