Tài Liệu Kỹ Thuật & Công Thức

Triển Khai Toán Học Đầy Đủ

Hướng Dẫn Triển Khai

Trang này cung cấp các công thức sao chép-dán và phương pháp tính toán từng bước cho tất cả các chỉ số Run Analytics. Sử dụng cho việc triển khai tùy chỉnh, xác minh hoặc hiểu sâu hơn.

⚠️ Lưu Ý Triển Khai

  • Tất cả thời gian nên được chuyển đổi sang giây để tính toán
  • Nhịp chạy là nghịch đảo (% cao hơn = nhịp chậm hơn)
  • Luôn xác thực đầu vào trong phạm vi hợp lý
  • Xử lý các trường hợp ngoại lệ (chia cho 0, giá trị âm)

Chỉ Số Thành Tích Cốt Lõi

Tốc Độ Chạy Tới Hạn (CRS)

Công thức:

CRS (m/s) = (D₂ - D₁) / (T₂ - T₁)
Nhịp CRS/100m (giây) = (T₄₀₀ - T₂₀₀) / 2

🧪 Máy Tính Tương Tác - Kiểm Tra Công Thức

Nhịp CRS mỗi 100m:
1:49
Các bước tính toán:
CRS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Nhịp/100m = 100 / 0.917 = 109 giây = 1:49

Triển Khai 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" }

Điểm Căng Thẳng Tập Luyện Chạy (sTSS)

Công thức đầy đủ:

sTSS = (IF³) × Thời lượng (giờ) × 100
IF = NSS / FTP
NSS = Tổng quãng đường / Tổng thời gian (m/phút)

🧪 Máy Tính Tương Tác - Kiểm Tra Công Thức

sTSS được tính:
55
Các bước tính toán:
NSS = 3000m / 55phút = 54.5 m/phút
FTP = 100 / (93/60) = 64.5 m/phút
IF = 54.5 / 64.5 = 0.845
sTSS = 0.845³ × (55/60) × 100 = 55

Triển Khai 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

Hiệu Suất Chạy

Công thức:

Hiệu suất chạy = Thời gian km (giây) + Số bước chạy
Hiệu suất chạy₂₅ = (Thời gian × 25/Chiều dài đường) + (Số bước × 25/Chiều dài đường)

🧪 Máy Tính Tương Tác - Kiểm Tra Công Thức

Điểm hiệu suất chạy:
35
Tính toán:
Hiệu suất chạy = 20s + 15 bước = 35

Triển Khai JavaScript:

function calculateRunning Efficiency(timeSeconds, strideCount) {
  return timeSeconds + strideCount;
}

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

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

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

Cơ Học Bước Chạy

Tần Số Bước Chạy (SR)

Công thức:

SR = 60 / Thời gian chu kỳ (giây)
SR = (Số bước chạy / Thời gian tính bằng giây) × 60

🧪 Máy Tính Tương Tác - Kiểm Tra Công Thức

Tần số bước chạy (SPM):
72
Tính toán:
SR = (30 / 25) × 60 = 72 SPM

Triển Khai JavaScript:

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

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

Khoảng Cách Mỗi Bước (DPS)

Công thức:

DPS = Quãng đường / Số bước chạy
DPS = Quãng đường / (SR / 60)

Triển Khai 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)

Vận Tốc từ SR và DPS

Công thức:

Vận tốc (m/s) = (SR / 60) × DPS

Triển Khai JavaScript:

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

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

Chỉ Số Bước Chạy (SI)

Công thức:

SI = Vận tốc (m/s) × DPS (m/bước)

Triển Khai JavaScript:

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

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

Biểu Đồ Quản Lý Thành Tích (PMC)

Tính Toán CTL, ATL, TSB

Công thức:

CTL hôm nay = CTL hôm qua + (TSS hôm nay - CTL hôm qua) × (1/42)
ATL hôm nay = ATL hôm qua + (TSS hôm nay - ATL hôm qua) × (1/7)
TSB = CTL hôm qua - ATL hôm qua

Triển Khai 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

Tính Toán Nâng Cao

CRS từ Nhiều Quãng Đường (Phương Pháp Hồi Quy)

Triển Khai 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 }

Hệ Số Cường Độ từ Nhịp

Triển Khai 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)

Phân Tích Độ Đồng Đều Nhịp

Triển Khai 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 ? "Xuất sắc" :
                 coefficientOfVariation < 10 ? "Tốt" :
                 coefficientOfVariation < 15 ? "Trung bình" : "Biến đổi"
  };
}

// 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: "Xuất sắc" }

Phát Hiện Mệt Mỏi từ Số Bước Chạy

Triển Khai 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 ? "Tối thiểu" :
                  strideCountIncrease < 10 ? "Trung bình" :
                  strideCountIncrease < 20 ? "Đáng kể" : "Nghiêm trọng"
  };
}

// 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: "Nghiêm trọng" }

Xác Thực Dữ Liệu

Kiểm Tra Chất Lượng Dữ Liệu Bài Tập

Triển Khai 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(`Nhịp trung bình bất thường: ${Math.round(avgPace)}s mỗi 100m`);
  }

  // Check for reasonable stride counts (10-50 per 25m)
  const avgStridesPer25m = (workout.totalStrides / workout.totalDistance) * 25;
  if (avgStridesPer25m < 10 || avgStridesPer25m > 50) {
    issues.push(`Số bước bất thường: ${Math.round(avgStridesPer25m)} mỗi 25m`);
  }

  // Check for reasonable stride rate (30-150 SPM)
  const avgSR = calculateStrideRate(workout.totalStrides, workout.totalTime);
  if (avgSR < 30 || avgSR > 150) {
    issues.push(`Tần số bước bất thường: ${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(`Phát hiện khoảng cách lớn giữa phân đoạn ${i} và ${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: [] }

Hàm Hỗ Trợ

Tiện Ích Chuyển Đổi Thời Gian

Triển Khai 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"

Tài Nguyên Triển Khai

Tất cả các công thức trên trang này đều sẵn sàng cho sản xuất và được xác thực dựa trên tài liệu khoa học. Sử dụng chúng cho các công cụ phân tích tùy chỉnh, xác minh hoặc hiểu sâu hơn về tính toán thành tích chạy.

💡 Thực Hành Tốt Nhất

  • Xác thực đầu vào: Kiểm tra phạm vi hợp lý trước khi tính toán
  • Xử lý trường hợp ngoại lệ: Chia cho 0, giá trị âm, dữ liệu rỗng
  • Làm tròn phù hợp: CTL/ATL/TSB đến 1 chữ số thập phân, sTSS đến số nguyên
  • Lưu trữ độ chính xác: Giữ độ chính xác đầy đủ trong cơ sở dữ liệu, làm tròn khi hiển thị
  • Kiểm tra kỹ lưỡng: Sử dụng dữ liệu đã biết tốt để xác minh tính toán