Referencia Técnica dan Fórmulas
Implementasi Matemática Completa
Guía Implementasi
Esta página proporciona fórmulas listas untuk copiar dan pegar, así sebagai mésemua cálculo paso paso untuk semua metrik SwimAnalytics. Úsalas untuk implementaciones personalizadas, verificación atau comprensión lebih dari profunda.
⚠️ Notas Implementasi
- Todos tiempos deben convertirse segundos untuk cálculos
- El ritmo renang es inverso (mayor % = ritmo lebih dari lento)
- Valida siempre entradas untuk rangos razonables
- Maneja casos límite (división oleh cero, valores negativos)
Metrik Performa Principales
Critical Swim Speed (CSS)
Fórmula:
CSS (m/s) = (D₂ - D₁) / (T₂ - T₁)
CSS Ritmo/100m (segundos) = (T₄₀₀ - T₂₀₀) / 2
🧪 Calculadora Interactiva - Prueba Fórmula
Ritmo CSS oleh 100m:
1:49
Pasos cálculo:
CSS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Ritmo/100m = 100 / 0.917 = 109 segundos = 1:49
CSS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Ritmo/100m = 100 / 0.917 = 109 segundos = 1:49
Implementasi di JavaScript:
function calculateCSS(distance1, time1, distance2, time2) {
// Convert tibulan to seconds if needed
const t1 = typeof time1 === 'string' ? timeToSeconds(time1) : time1;
const t2 = typeof time2 === 'string' ? timeToSeconds(time2) : time2;
// Calculate CSS 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 = calculateCSS(200, 150, 400, 368);
// Returns: { css_ms: 0.917, pace_seconds: 109, pace_formatted: "1:49" }
Swim Training Stress Score (sTSS)
Fórmula Completa:
sTSS = (IF³) × Duración (horas) × 100
IF = NSS / FTP
NSS = Distancia Total / Waktu Total (m/min)
🧪 Calculadora Interactiva - Prueba Fórmula
sTSS Calculado:
55
Pasos cálculo:
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
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
Implementasi di JavaScript:
function calculateSTSS(distance, timeMinutes, ftpMetersPerMin) {
// Calculate Normalized Swim 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 CSS to FTP
function cssToFTP(cssPacePer100mSeconds) {
// FTP in m/min = 100m / (pace in minutes)
return 100 / (cssPacePer100mSeconds / 60);
}
// Example: CSS of 1:33 (93 seconds)
const ftp = cssToFTP(93); // Returns: 64.5 m/min
SWOLF
Fórmula:
SWOLF = Waktu Largo (segundos) + Cuenta Kayuhan
SWOLF₂₅ = (Waktu × 25/Longitud Piscina) + (Kayuhan × 25/Longitud Piscina)
🧪 Calculadora Interactiva - Prueba Fórmula
Skor SWOLF:
35
Cálculo:
SWOLF = 20s + 15 kayuhans = 35
SWOLF = 20s + 15 kayuhans = 35
Implementasi di JavaScript:
function calculateSWOLF(timeSeconds, strokeCount) {
return timeSeconds + strokeCount;
}
function calculateNormalizedSWOLF(timeSeconds, strokeCount, poolLength) {
const normalizedTime = timeSeconds * (25 / poolLength);
const normalizedStrokes = strokeCount * (25 / poolLength);
return normalizedTime + normalizedStrokes;
}
// Example:
const swolf = calculateSWOLF(20, 15);
// Returns: 35
const swolf50m = calculateNormalizedSWOLF(40, 30, 50);
// Returns: 35 (normalized to 25m)
Mecánica Kayuhan
Stroke Rate (SR)
Fórmula:
SR = 60 / Waktu Ciclo (segundos)
SR = (Número Kayuhan / Waktu di segundos) × 60
🧪 Calculadora Interactiva - Prueba Fórmula
Stroke Rate (SPM):
72
Cálculo:
SR = (30 / 25) × 60 = 72 SPM
SR = (30 / 25) × 60 = 72 SPM
Implementasi di JavaScript:
function calculateStrokeRate(strokeCount, timeSeconds) {
return (strokeCount / timeSeconds) * 60;
}
// Example:
const sr = calculateStrokeRate(30, 25);
// Returns: 72 SPM
Distance Per Stroke (DPS)
Fórmula:
DPS = Distancia / Cuenta Kayuhan
DPS = Distancia / (SR / 60)
Implementasi di JavaScript:
function calculateDPS(distance, strokeCount, pushoffDistance = 0) {
const effectiveDistance = distance - pushoffDistance;
return effectiveDistance / strokeCount;
}
// Example (25m pool, 5m push-off):
const dps = calculateDPS(25, 12, 5);
// Returns: 1.67 m/stroke
// For multiple laps:
const dps100m = calculateDPS(100, 48, 4 * 5);
// Returns: 1.67 m/stroke (4 laps × 5m push-off)
Kecepatan partir SR dan DPS
Fórmula:
Kecepatan (m/s) = (SR / 60) × DPS
Implementasi di JavaScript:
function calculateVelocity(strokeRate, dps) {
return (strokeRate / 60) * dps;
}
// Example:
const velocity = calculateVelocity(70, 1.6);
// Returns: 1.87 m/s
Stroke Index (SI)
Fórmula:
SI = Kecepatan (m/s) × DPS (m/kayuhan)
Implementasi di JavaScript:
function calculateStrokeIndex(velocity, dps) {
return velocity * dps;
}
// Example:
const jika = calculateStrokeIndex(1.5, 1.7);
// Returns: 2.55
Grafik Manajemen Performa (PMC)
Cálculos CTL, ATL, TSB
Fórmulas:
CTL hoy = CTL ayer + (TSS hoy - CTL ayer) × (1/42)
ATL hoy = ATL ayer + (TSS hoy - ATL ayer) × (1/7)
TSB = CTL ayer - ATL ayer
Implementasi di 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
Cálculos Avanzados
CSS dari Múltiples Distancias (Método Regresión)
Implementasi di JavaScript:
function calculateCSSRegression(distances, tibulan) {
// Linear regression: distance = + b*time
const n = distances.length;
const sumX = tibulan.reduce((a, b) => + b, 0);
const sumY = distances.reduce((a, b) => + b, 0);
const sumXY = tibulan.reduce((sum, x, i) => sum + x * distances[i], 0);
const sumXX = tibulan.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 swimming velocity (m/s)
anaerobic_capacity: intercept // Anaerobic distance capacity (m)
};
}
// Example with multiple test distances:
const distances = [100, 200, 400, 800];
const tibulan = [65, 150, 340, 720]; // in seconds
const result = calculateCSSRegression(distances, tibulan);
// Returns: { css: 1.18, anaerobic_capacity: 15.3 }
Factor Intensidad dari Ritmo
Implementasi di 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 (swimming at 84.5% of threshold)
Análisis Consistencia Ritmo
Implementasi di JavaScript:
function analyzePaceConsistency(laps) {
const paces = laps.map(lap => lap.distance / lap.time);
const avgPace = paces.reduce((a, b) => + 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 ? "Excelente" :
coefficientOfVariation < 10 ? "Buena" :
coefficientOfVariation < 15 ? "Moderada" : "Variable"
};
}
// Example:
const laps = [
{ distance: 100, time: 70 },
{ distance: 100, time: 72 },
{ distance: 100, time: 71 },
// ...
];
const analysis = analyzePaceConsistency(laps);
// Returns: { avgPace: 1.41, stdDev: 0.02, coefficientOfVariation: 1.4, consistency: "Excelente" }
Detección Kelelahan rata-ratante Cuenta Kayuhan
Implementasi di JavaScript:
function detectFatigue(laps) {
const firstThird = laps.slice(0, Math.floor(laps.length/3));
const lastThird = laps.slice(-Math.floor(laps.length/3));
const firstThirdAvg = firstThird.reduce((sum, lap) =>
sum + lap.strokeCount, 0) / firstThird.length;
const lastThirdAvg = lastThird.reduce((sum, lap) =>
sum + lap.strokeCount, 0) / lastThird.length;
const strokeCountIncrease = ((lastThirdAvg - firstThirdAvg) / firstThirdAvg) * 100;
return {
firstThirdAvg: Math.round(firstThirdAvg * 10) / 10,
lastThirdAvg: Math.round(lastThirdAvg * 10) / 10,
percentIncrease: Math.round(strokeCountIncrease * 10) / 10,
fatigueLevel: strokeCountIncrease < 5 ? "Mínima" :
strokeCountIncrease < 10 ? "Moderada" :
strokeCountIncrease < 20 ? "Significativa" : "Severa"
};
}
// Example:
const laps = [
{ strokeCount: 14 }, { strokeCount: 14 }, { strokeCount: 15 },
{ strokeCount: 15 }, { strokeCount: 16 }, { strokeCount: 16 },
{ strokeCount: 17 }, { strokeCount: 18 }, { strokeCount: 18 }
];
const fatigue = detectFatigue(laps);
// Returns: { firstThirdAvg: 14.3, lastThirdAvg: 17.7, percentIncrease: 23.8, fatigueLevel: "Severa" }
Validación Datos
Lihatificación Calidad Datos Latihan
Implementasi di 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(`Ritmo promedio inusual: ${Math.round(avgPace)}s oleh 100m`);
}
// Check for reasonable stroke counts (10-50 per 25m)
const avgStrokesPer25m = (workout.totalStrokes / workout.totalDistance) * 25;
if (avgStrokesPer25m < 10 || avgStrokesPer25m > 50) {
issues.push(`Cuenta kayuhans inusual: ${Math.round(avgStrokesPer25m)} oleh 25m`);
}
// Check for reasonable stroke rate (30-150 SPM)
const avgSR = calculateStrokeRate(workout.totalStrokes, workout.totalTime);
if (avgSR < 30 || avgSR > 150) {
issues.push(`Frecuencia kayuhan inusual: ${Math.round(avgSR)} SPM`);
}
// Check for missing laps (gaps in time)
if (workout.laps && workout.laps.length > 1) {
for (let i = 1; i < workout.laps.length; i++) {
const gap = workout.laps[i].startTime -
(workout.laps[i-1].startTime + workout.laps[i-1].duration);
if (gap > 300) { // 5 minute gap
issues.push(`Hueco grande detectado entre largos ${i} dan ${i+1}`);
}
}
}
return {
isValid: issues.length === 0,
issues
};
}
// Example:
const workout = {
totalDistance: 2000,
totalTime: 1800, // 30 minutes
totalStrokes: 800,
laps: [/* lap data */]
};
const validation = validateWorkoutData(workout);
// Returns: { isValid: true, issues: [] }
Funciones Auxiliares
Utilidades Conversión Waktu
Implementasi di 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"
Recursos Implementasi
Todas fórmulas di ini página adalahn listas untuk producción dan validadas contra literatura científica. Úsalas untuk herramientas analitik personalizadas, verificación atau comprensión lebih dari profunda cálculos performa di renang.
💡 Mejores Prácticas
- Valida entradas: Lihatifica rangos razonables antes calcular
- Maneja casos límite: División oleh cero, valores negativos, data nulos
- Redondea apropiadamente: CTL/ATL/TSB 1 decimal, sTSS entero
- Almacena ketepatan: Mantén ketepatan completa di base data, redondea untuk mostrar
- Prueba exhaustivamente: Usa data conocidos dan correctos untuk verificar cálculos