Techninė informacija ir formulės

Išsamus matematinis įgyvendinimas

Įgyvendinimo vadovas

Šiame puslapyje pateikiamos paruoštos formulės ir nuoseklūs skaičiavimo metodai visoms „Swim Analytics“ metrikoms. Naudokite juos savo skaičiavimams, jų patikrinimui ar gilesniam supratimui.

⚠️ Įgyvendinimo pastabos

  • Visi laikai skaičiavimams turi būti paversti sekundėmis
  • Plaukimo tempas yra atvirkštinis (didesnis % = lėtesnis tempas)
  • Visada tikrinkite, ar įvesties duomenys yra loginėse ribose
  • Numatykite išimtinius atvejus (dalyba iš nulio, neigiamos reikšmės)

Pagrindinės rezultatų metrikos

Kritinis plaukimo greitis (CSS)

Formulė:

CSS (m/s) = (D₂ - D₁) / (T₂ - T₁)
CSS tempas/100m (sekundėmis) = (T₄₀₀ - T₂₀₀) / 2

🧪 Interaktyvi skaičiuoklė – išbandykite formulę

CSS tempas 100 metrų:
1:49
Skaičiavimo žingsniai:
CSS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Tempas/100m = 100 / 0.917 = 109 sekundės = 1:49

JavaScript įgyvendinimas:

function calculateCSS(distance1, time1, distance2, time2) {
  // Jei reikia, paverčiame laiką sekundėmis
  const t1 = typeof time1 === 'string' ? timeToSeconds(time1) : time1;
  const t2 = typeof time2 === 'string' ? timeToSeconds(time2) : time2;

  // Skaičiuojame CSS m/s
  const css_ms = (distance2 - distance1) / (t2 - t1);

  // Skaičiuojame tempą 100m sekundėmis
  const pace_per_100m = 100 / css_ms;

  // Konvertuojame į 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')}`
  };
}

// Pavyzdys:
const result = calculateCSS(200, 150, 400, 368);
// Grąžina: { css_ms: 0.917, pace_seconds: 109, pace_formatted: "1:49" }

Plaukimo treniruočių streso balas (sTSS)

Išsami formulė:

sTSS = (IF³) × Trukmė (valandomis) × 100
IF = NSS / FTP
NSS = Visas atstumas / Visas laikas (m/min)

🧪 Interaktyvi skaičiuoklė – išbandykite formulę

Apskaičiuotas sTSS:
55
Skaičiavimo žingsniai:
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

JavaScript įgyvendinimas:

function calculateSTSS(distance, timeMinutes, ftpMetersPerMin) {
  // Skaičiuojame normalizuotą plaukimo greitį
  const nss = distance / timeMinutes;

  // Skaičiuojame intensyvumo faktorių
  const intensityFactor = nss / ftpMetersPerMin;

  // Skaičiuojame valandas
  const hours = timeMinutes / 60;

  // Skaičiuojame sTSS naudodami intensyvumo faktoriun pakeltą kūbu
  const stss = Math.pow(intensityFactor, 3) * hours * 100;

  return Math.round(stss);
}

// Pavyzdys:
const stss = calculateSTSS(3000, 55, 64.5);
// Grąžina: 55

// Pagalbinė funkcija: konvertuojame CSS į slenkstį (FTP)
function cssToFTP(cssPacePer100mSeconds) {
  // FTP m/min = 100m / (tempas minutėmis)
  return 100 / (cssPacePer100mSeconds / 60);
}

// Pavyzdys: CSS 1:33 (93 sekundės)
const ftp = cssToFTP(93); // Grąžina: 64.5 m/min

SWOLF

Formulė:

SWOLF = Rato laikas (sekundėmis) + Grybšnių skaičius
SWOLF₂₅ = (Laikas × 25/Baseino ilgis) + (Grybšniai × 25/Baseino ilgis)

🧪 Interaktyvi skaičiuoklė – išbandykite formulę

SWOLF balas:
35
Skaičiavimas:
SWOLF = 20s + 15 grybšnių = 35

JavaScript įgyvendinimas:

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

// Pavyzdys:
const swolf = calculateSWOLF(20, 15);
// Grąžina: 35

const swolf50m = calculateNormalizedSWOLF(40, 30, 50);
// Grąžina: 35 (normalizuota į 25m baseiną)

Grybšnių mechanika

Grybšnių dažnis (SR)

Formulė:

SR = 60 / Ciklo laikas (sekundėmis)
SR = (Grybšnių skaičius / Laikas sekundėmis) × 60

🧪 Interaktyvi skaičiuoklė – išbandykite formulę

Grybšnių dažnis (SPM):
72
Skaičiavimas:
SR = (30 / 25) × 60 = 72 SPM

JavaScript įgyvendinimas:

function calculateStrokeRate(strokeCount, timeSeconds) {
  return (strokeCount / timeSeconds) * 60;
}

// Pavyzdys:
const sr = calculateStrokeRate(30, 25);
// Grąžina: 72 SPM

Atstumas per grybšnį (DPS)

Formulė:

DPS = Atstumas / Grybšnių skaičius
DPS = Atstumas / (SR / 60)

JavaScript įgyvendinimas:

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

// Pavyzdys (25m baseinas, 5m atsispyrimas):
const dps = calculateDPS(25, 12, 5);
// Grąžina: 1.67 m/grybšnis

// Keliems ratams:
const dps100m = calculateDPS(100, 48, 4 * 5);
// Grąžina: 1.67 m/grybšnis (4 ratai × 5m atsispyrimas)

Greitis skaičiuojant iš SR ir DPS

Formulė:

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

JavaScript įgyvendinimas:

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

// Pavyzdys:
const velocity = calculateVelocity(70, 1.6);
// Grąžina: 1.87 m/s

Grybšnių indeksas (SI)

Formulė:

SI = Greitis (m/s) × DPS (m/grybšnis)

JavaScript įgyvendinimas:

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

// Pavyzdys:
const si = calculateStrokeIndex(1.5, 1.7);
// Grąžina: 2.55

Rezultatų valdymo grafikas (PMC)

CTL, ATL, TSB skaičiavimai

Formulės:

CTL šiandien = CTL vakar + (TSS šiandien - CTL vakar) × (1/42)
ATL šiandien = ATL vakar + (TSS šiandien - ATL vakar) × (1/7)
TSB = CTL vakar - ATL vakar

JavaScript įgyvendinimas:

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

// Skaičiuojame PMC treniruočių serijai
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;
}

// Pavyzdys:
const workouts = [
  { date: '2025-01-01', tss: 50 },
  { date: '2025-01-02', tss: 60 },
  { date: '2025-01-03', tss: 45 },
  // ... daugiau treniruočių
];

const pmc = calculatePMC(workouts);
// Grąžina masyvą su CTL, ATL, TSB reikšmėmis kiekvienai dienai

Pažangūs skaičiavimai

CSS skaičiavimas iš kelių atstumų (regresijos metodas)

JavaScript įgyvendinimas:

function calculateCSSRegression(distances, times) {
  // Tiesinė regresija: 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, // Kritinis plaukimo greitis (m/s)
    anaerobic_capacity: intercept // Anaerobinio atstumo talpa (m)
  };
}

// Pavyzdys su keliais kontroliniais atstumais:
const distances = [100, 200, 400, 800];
const times = [65, 150, 340, 720]; // sekundėmis
const result = calculateCSSRegression(distances, times);
// Grąžina: { css: 1.18, anaerobic_capacity: 15.3 }

Intensyvumo faktorius skaičiuojant pagal tempą

JavaScript įgyvendinimas:

function calculateIntensityFactor(actualPace100m, thresholdPace100m) {
  // Paverčiame tempą į greitį (m/s)
  const actualSpeed = 100 / actualPace100m;
  const thresholdSpeed = 100 / thresholdPace100m;
  return actualSpeed / thresholdSpeed;
}

// Pavyzdys:
const if_value = calculateIntensityFactor(110, 93);
// Grąžina: 0.845 (plaukiama 84,5% slenksčio greičio)

Tempo nuoseklumo analizė

JavaScript įgyvendinimas:

function analyzePaceConsistency(laps) {
  const paces = laps.map(lap => lap.distance / lap.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 ? "Puikus" :
                 coefficientOfVariation < 10 ? "Geras" :
                 coefficientOfVariation < 15 ? "Vidutinis" : "Kintantis"
  };
}

// Pavyzdys:
const laps = [
  { distance: 100, time: 70 },
  { distance: 100, time: 72 },
  { distance: 100, time: 71 },
  // ...
];
const analysis = analyzePaceConsistency(laps);
// Grąžina: { avgPace: 1.41, stdDev: 0.02, coefficientOfVariation: 1.4, consistency: "Puikus" }

Nuovargio nustatymas pagal grybšnių skaičių

JavaScript įgyvendinimas:

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 ? "Minimalus" :
                  strokeCountIncrease < 10 ? "Vidutinis" :
                  strokeCountIncrease < 20 ? "Didelis" : "Labai didelis"
  };
}

// Pavyzdys:
const laps = [
  { strokeCount: 14 }, { strokeCount: 14 }, { strokeCount: 15 },
  { strokeCount: 15 }, { strokeCount: 16 }, { strokeCount: 16 },
  { strokeCount: 17 }, { strokeCount: 18 }, { strokeCount: 18 }
];
const fatigue = detectFatigue(laps);
// Grąžina: { firstThirdAvg: 14.3, lastThirdAvg: 17.7, percentIncrease: 23.8, fatigueLevel: "Labai didelis" }

Duomenų patikra

Treniruotės duomenų kokybės tikrinimas

JavaScript įgyvendinimas:

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

  // Tikriname, ar tempas yra loginėse ribose (1:00-5:00 per 100m)
  const avgPace = (workout.totalTime / workout.totalDistance) * 100;
  if (avgPace < 60 || avgPace > 300) {
    issues.push(`Neįprastas vidutinis tempas: ${Math.round(avgPace)}s per 100m`);
  }

  // Tikriname grybšnių skaičių (10-50 per 25m)
  const avgStrokesPer25m = (workout.totalStrokes / workout.totalDistance) * 25;
  if (avgStrokesPer25m < 10 || avgStrokesPer25m > 50) {
    issues.push(`Neįprastas grybšnių skaičius: ${Math.round(avgStrokesPer25m)} per 25m`);
  }

  // Tikriname grybšnių dažnį (30-150 SPM)
  const avgSR = calculateStrokeRate(workout.totalStrokes, workout.totalTime);
  if (avgSR < 30 || avgSR > 150) {
    issues.push(`Neįprastas grybšnių dažnis: ${Math.round(avgSR)} SPM`);
  }

  // Tikriname, ar nėra dingusių ratų (dideli laiko tarpai)
  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 minučių tarpas
        issues.push(`Aptiktas didelis tarpas tarp ${i} ir ${i+1} rato`);
      }
    }
  }

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