# Juoksu — miten palvelu toimii

Tämä dokumentti kuvaa henkilökohtaisen juoksuanalyysipalvelun
toimintaperiaatteen ja ne analyysit ja tunnusluvut, jotka palvelu laskee
automaattisesti. Se ei sisällä henkilökohtaista dataa eikä salaisuuksia, joten
sen voi jakaa sellaisenaan.

Palvelu on yhden juoksijan työkalu: se hakee juoksuharjoitukset
Intervals.icusta, tallentaa ne omalle palvelimelle ja näyttää niistä lasketut
luvut selaimessa suomeksi. Tavoite on erityisesti verrata saman pituisten
vetoharjoitusten kehitystä ajan mittaan.

## Mistä data tulee

- **Lähde:** Intervals.icu -palveluun tallentunut juoksuharjoitus ja sen
  FIT-tiedosto.
- **Mukaan otetaan** lajit `Run` (juoksu), `TrailRun` (polkujuoksu) ja
  `VirtualRun` (virtuaalijuoksu). Muut lajit ohitetaan.
- **Rajaus:** vain sovitun aloituspäivän jälkeiset harjoitukset. Vanhempaa
  historiaa ei tuoda.
- **Vain uudet:** synkronointi hakee harjoituksia viimeisimmän tuodun
  harjoituksen jälkeen ja ohittaa jo tallennetut. Se ei muokkaa eikä poista
  mitään Intervals.icussa, ja rajapintaa käytetään vain luku -tilassa.
- **Milloin data päivittyy:** automaattisesti joka yö klo 00.00 Suomen aikaa
  sekä käyttäjän painaessa `Tarkista uudet` -painiketta. Molemmat käyttävät
  samaa polkua, joten toisto ei tuota duplikaatteja.
- **Tallennus:** SQLite-tietokanta ja FIT-tiedostot palvelimella. Analyysi
  lasketaan tallennetusta FIT-tiedostosta, joten alkuperäistä mittaustiedostoa
  ei koskaan muuteta.

Jokaisella harjoituksella on tila: odottaa analyysia, valmis, korjattava,
FIT-tiedosto puuttuu tai virhe. Synkronoinnin viimeisin yritys, viimeisin
onnistuminen ja mahdollinen virhe näytetään käyttöliittymässä.

## Harjoitusten luokittelu

Palvelu jakaa juoksuharjoitukset kahteen luokkaan. Luokittelu ei kerro
harjoituksen kuormittavuudesta, vaan siitä, voidaanko sitä analysoida
vetotasolla.

**Laatuharjoitus** on maantiellä tai juoksuradalla tehty juoksu, jonka nimessä
on yksi tuettu `n x m` -merkintä. Merkintä kertoo vetojen määrän ja
nimellispituuden.

**Muu harjoitus** on kaikki muu: polkujuoksu, juoksumattojuoksu,
virtuaalijuoksu sekä juoksu, jonka nimestä vetosarjaa ei voi tulkita
yksiselitteisesti. Luokkaa "kevyt" tai "kova" ei päätellä automaattisesti.

### Tuetut nimet

Merkinnän erottimena käy `x`, `X` tai `×`. Yksikkö voi puuttua, jolloin luku
tulkitaan metreinä. Pituus voi olla myös desimaaliluku pilkulla tai pisteellä.
Esimerkkejä tuetuista nimistä:

- `8x3 min`
- `6x1000`
- `6x1000 m`
- `6x1 km`
- `10 × 400 m`
- `4x1,5 km`
- `3x1.6 km`
- `2x1,5 min`

### Normalisointi

Nimellispituus normalisoidaan aina perusyksikköön: **matka metreiksi ja kesto
sekunneiksi**. Siksi

- `4x1,5 km` ja `4x1500 m` ovat sama nimellispituus **1500 m** ja kuuluvat
  samaan vertailuryhmään,
- `6x1 km`, `6x1000` ja `6x1000 m` ovat kaikki **1000 m**,
- `2x1,5 min` on **90 s**.

Desimaaliluku hyväksytään vain, jos se vastaa tasaista metri- tai
sekuntimäärää: `4x1,5 km` on 1500 m, mutta metrin murto-osaksi jäävä pituus
(esimerkiksi `6x1000,5`) hylätään epäselvänä.

### Ei tueta

Epäselväksi tulkittava merkintä ei mene automaattiseen analyysiin, vaan
harjoitus käsitellään muuna harjoituksena ja syy kerrotaan näkymässä.
Esimerkkejä:

- `10x30 s` — sekunteja yksikkönä ei tueta
- `2x1 h` — tunteja yksikkönä ei tueta
- `6x1000,5` — desimaalipituus ei vastaa tasaista metrimäärää
- `2x3x1000` — useampi vetosarja samassa nimessä
- `3x(2x1000)` — sisäkkäinen vetosarja

## Vedot, palautukset ja kierrosjako

Vedot eivät perustu vauhtiennusteeseen vaan harjoituksen kierroksiin. Jokainen
FIT-kierros merkitään vedoksi, palautukseksi tai kierrosjaon ulkopuolelle
jääväksi osaksi (lämmittely, loppuverryttely). Palautukset ovat vain vetojen
välissä; ennen ensimmäistä ja viimeisen vedon jälkeen olevat kierrokset ovat
aina lämmittelyä tai loppuverryttelyä.

### Kierrosjaon lähteet

Kierrosjako valitaan tässä järjestyksessä:

1. **Käsin tehty kierrosjako** — käyttäjän merkintä korjattavien listalta.
   Voittaa aina muut ja säilyy alkuperäisen FIT-tiedoston rinnalla.
2. **Suunniteltu harjoitusrakenne** — Intervals.icuun harjoitukseen liitetty
   kalenterin työlista, jossa on lämmittely-, toisto- ja
   loppuverryttelyaskelmat. Käytetään, jos kierrosmäärä täsmää ja jokainen
   kierros osuu askelman kestoon tai matkaan toleranssin sisällä. Näin
   esimerkiksi kymmenen minuutin alkuverryttely ei tulkkiudu vedoksi.
3. **Kierrosten aktiivinen/lepo-tieto** — FIT-tiedoston oma merkintä.
4. **Nimellispituuteen osuvat kierrokset** — varamenetelmä, jossa kierros on
   ehdokasvedoksi, jos sen pituus on karkeasti nimellispituuden luokkaa.

### Toleranssit

- Vedon mitattu pituus saa poiketa nimellispituudesta **±5 %**.
- Kestovedolla toleranssi on vähintään **±2 s**, jotta pieni ajoitusheitto ei
  hylkää muuten kelvollista vetoa.
- Suunnitelman ja toteuman vertailussa käytetään samoja rajoja.
- Nimessä ilmoitetun vetomäärän on täsmättävä kierroksilta löytyvien vetojen
  kanssa. Ylimääräinen tai puuttuva kierros ei mene läpi arvaamalla.

### Korjattavat harjoitukset

Jos kierrosjako ei ole yksiselitteinen (esimerkiksi vetomäärä ei täsmää,
kierrosten aktiivisuustieto puuttuu tai suunniteltu rakenne ja toteuma
poikkeavat toisistaan), harjoitus siirtyy **korjattaviin**. Palvelu kertoo
syyksi ihmiselle luettavan selityksen, ja käyttäjä voi merkitä kierrokset
vedoiksi, palautuksiksi tai kokonaan huomiotta jätettäviksi. Merkintä
tallennetaan erikseen, analyysi lasketaan uudelleen eikä FIT-tiedostoa
muuteta.

## Laatuharjoituksen tunnusluvut

### Vetokohtaiset luvut

| Luku | Miten se lasketaan |
| --- | --- |
| Matka | Kierroksen mitattu matka metreinä |
| Liikkumisaika | Kierroksen liikkeessäoloaika sekunteina |
| Vauhti | Matka ja liikkumisaika yhdistettynä, `min:sek/km` |
| Vauhtitavoite | Suunnitellun harjoitusrakenteen vauhtitavoite, jos sellainen on |
| Vauhti kynnyksestä | Vauhti prosentteina harjoitushetken kynnysvauhdin nopeudesta (100 % = kynnysvauhti) |
| Jälkimmäisen puolikkaan syke | Keskisyke vedon liikkeessäoloajan jälkimmäiseltä puolikkaalta |
| Syke kynnyksestä | Sama syke prosentteina harjoitushetken kynnyssykkeestä |
| Sykepeitto | Osuus jälkimmäisestä puolikkaasta, jolta on kelvollisia sykenäytteitä |
| 5 s maksimisyke | Korkein täyden viiden sekunnin liukuva keskisyke vedon aikana |
| Sykekäyrä | Vedon syke ajan funktiona; kaikki vedot samassa kuvaajassa, liukusäädin korostaa yhden vedon |

Vedon sykeluvut hyväksytään yhteenvetoon vain, jos sykepeitto on vähintään
**80 %**. Katkoja ei interpoloida: puuttuvaa sykettä ei keksitä. Jos sykettä ei
ole lainkaan, matka, kesto ja vauhti näytetään silti.

### Harjoitusyhteenveto

- Vetojen yhteismatka ja -aika sekä niistä laskettu **vetovauhti**, jolloin
  eri pituiset vedot painottuvat oikein.
- **Jälkimmäisen puolikkaan keskisyke** yhdistettynä kestopainotuksella, joten
  pidemmät vedot vaikuttavat enemmän.
- **Sykepeitto** ja merkintä osittaisesta yhteenvedosta, jos osa vedoista jäi
  sykkeen osalta ulkopuolelle.
- **Korkein 5 s maksimisyke** vetoja vastaavalta ajalta.
- **Kynnyssyke** ja **kynnysvauhti** sellaisina kuin ne olivat voimassa
  harjoituspäivänä, sekä erotus lyönteinä minuutissa kynnyssykkeeseen.
- Palautusten määrä ja kestot taustatietona; ne eivät vaikuta vertailuun.

Kynnysarvot tulevat Intervals.icusta, joten prosenttiluvut ovat vertailukelpoisia
myös silloin, kun kynnys muuttuu vuosien aikana.

## Muun harjoituksen tunnusluvut

Muusta harjoituksesta näytetään perusmittarit, mutta ei vetokohtaista
analyysia eikä kevyt/kova-luokittelua:

- liikkumisaika, kokonaiskesto ja matka
- keskisyke aikaperusteisesti sekä sykepeitto
- 5 s maksimisyke
- aika sykealueilla (Intervals.icun laskemat)
- nopeus jaettuna keskisykkeellä muodossa `(km/h) / bpm` — suurempi arvo
  tarkoittaa enemmän nopeutta samaa keskisyketta kohden, mutta ei yksinään
  todista kunnon paranemista
- syke kumulatiivisena aikana
- sykejakauma histogrammina **2 lyönnin** lokeroissa, alkaen aina **70
  lyönnistä** ja jatkuen korkeimpaan sykealueeseen, jotta kaikki alueet
  näkyvät

## Sykealueet

Kaikki näkymät ja kuvaajat käyttävät näitä sovittuja nimiä ja värejä.

| Alue | Nimi | Väri |
| --- | --- | --- |
| 1 | PK1 | `#06d6a0` |
| 2 | PK2 | `#61a5c2` |
| 3 | VK1 | `#ffda85` |
| 4 | VK2 | `#ff875c` |
| 5 | MK | `#ef476f` |

## Miten sykettä käsitellään

- Kaikki laskenta on aikaperusteista, ei näytemäärään perustuvaa.
- Kahden peräkkäisen sykenäytteen suurin hyväksytty väli on **5 s**; pidempi
  väli katkaisee peiton eikä siihen arvioida sykettä.
- **5 s maksimisyke** on korkein täyden viiden sekunnin liukuva keskisyke, joten
  yksittäinen mittauspiikki ei määrää tulosta.
- Kuvaajien pisteet harvennetaan tarvittaessa enintään 1800 pisteeseen, jotta
  analyysi pysyy pienenä.

## Vertailuryhmät

Vertailuryhmän muodostaa **sama nimellispituus**: esimerkiksi kaikki `1000 m`
vedot kuuluvat samaan ryhmään riippumatta vetojen määrästä, palautuksista tai
siitä, juostiinko harjoitus maantiellä vai radalla. Koska pituudet
normalisoidaan metreiksi, `4x1,5 km` ja `4x1500 m` ovat samassa `1500 m`
ryhmässä. Ryhmästä näytetään
aikasarja ja taulukko vauhdista, jälkimmäisen puolikkaan sykkeestä, 5 s
maksisykkeestä ja kynnyssykkeestä, ja jokaisesta harjoituksesta pääsee
porautumaan yksittäisiin vetoihin.

## Mitä palvelu ei tee

- Ei kirjoita Intervals.icuun eikä muuta alkuperäisiä FIT-tiedostoja.
- Ei arvioi harjoituksen kuormittavuutta tai keveyttä automaattisesti.
- Ei käytä kaltevuuskorjattua vauhtia (GAP), vaan todellista mitattua vauhtia.
- Ei tulkitse tuloksia lääketieteellisesti eikä anna harjoitusohjeita.

## Tämän dokumentin ylläpito

Tämä tiedosto (`docs/toiminta.md`) on dokumentin ainoa lähde, ja palvelu
tarjoilee sen sellaisenaan. Kun analyysin sääntöjä, raja-arvoja, sykealueita tai
tunnuslukuja muutetaan, tämä tiedosto päivitetään samassa muutoksessa.
Testi `tests/test_toiminta_doc.py` varmistaa, että

- dokumentti on saatavilla ilman kirjautumista ja oikealla sisältötyypillä,
- sykealueiden nimet ja värit vastaavat koodin määritelmää,
- dokumentissa mainitut raja-arvot (sykepeitto, liukuva ikkuna, näyteväli,
  nimellispituuden toleranssi, histogrammin lokero ja alaraja) vastaavat koodin
  vakioita,
- dokumentin nimirivit tulkitaan koodissa juuri niin kuin dokumentti väittää,
- eikä dokumentissa ole salaisuuksia tai pitkiä avainta muistuttavia merkkijonoja.

Testi siis kaatuu, jos koodi ja tämä kuvaus erkanevat toisistaan.
