Svět je v pohybu: změna, rytmus a periodicita
Jak matematicky popsat změnu v čase? Od derivace přes harmonické vlny až k Fourierově transformaci – s intuitivním výkladem a ukázkami v Pythonu.
V předchozí sérii jsme se zabývali tím, jak popsat stav trojrozměrného světa.
Ukázali jsme si, co jsou to pole — skalární i vektorová — a jak je matematicky uchopit.

Jenže samotný popis nás stál překvapivě hodně úsilí.
Museli jsme použít matematiku, kterou většina lidí nikdy plně nepochopí — a možná ani nepotřebuje pochopit do detailu.
A k čemu jsme se vlastně dostali?
Naučili jsme se popsat stav.
Něco jako když lidstvo poprvé vynalezlo fotoaparát.
Najednou jsme dokázali zachytit jeden konkrétní okamžik reality. V té době to byl revoluční objev.
Dnes?
Jedna fotka nám už nestačí.
Jsme zvyklí na video.
Chceme vidět pohyb.
Když vám znovu ukážu mapu počasí z 11. března 2026, pravděpodobně vás nijak nepřekvapí.
Je to jen statický obrázek.
Dopaminová odměna: téměř nulová.

Ale téměř okamžitě se objeví jiná otázka:
„Co se dělo potom?“
Jak se bude svět dál vyvíjet?
Jak se změní teplota, tlak, vítr?
Kdy začne kondenzovat voda — nebo lidsky řečeno: kdy bude pršet?
A právě tady se dostáváme k zásadnímu problému.
Pole nám říká, jak svět vypadá.
Ale neříká nám, jak se mění.
A pokud chceme pochopit realitu doopravdy, nestačí nám fotografie.
Potřebujeme film.
Od fotografie k filmu: přidáváme čas
Když se díváme na statický obrázek — „fotku“ — vidíme, že stav systému závisí pouze na prostorových souřadnicích.
Jinými slovy, pole je funkcí prostoru.
- u skalárního pole:
$$ f(x,y,z) $$
- u vektorového pole:
$$ \mathbf{F}(x, y, z) $$
Každému bodu v prostoru přiřazujeme buď číslo (skalár), nebo vektor (velikost a směr).
Takto jsme schopni popsat „fotku“ reality — jeden konkrétní okamžik.
Jenže pokud chceme tento statický obraz rozhýbat, nestačí nám prostor.
Musíme přidat čas.
V jazyce matematiky to znamená, že pole už není funkcí pouze prostoru, ale i času:
$$ f(x,y,z,t) $$
Film totiž není nic jiného než posloupnost jednotlivých snímků, které se v čase mění. V obecné teorii relativity bychom takovému prostoru řekli prostoročas, protože čas je čtvrtým rozměrem. Pojďme si to ukázat rovnou prakticky v Pythonu.
Jak vytvořit animaci skalárního pole v Pythonu
Teorie je fajn, ale teprve vizualizace ukáže, co vlastně znamená, že se pole mění v čase.
Vytvoříme si jednoduchý příklad skalárního pole, které závisí na souřadnicích $x, y$ a na čase $t$. Výsledkem bude animovaný GIF.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import Image
# Grid
nx, ny = 200, 200
x = np.linspace(-3, 3, nx)
y = np.linspace(-3, 3, ny)
X, Y = np.meshgrid(x, y)
# Scalar field
def scalar_field(t):
r2 = X**2 + Y**2
return np.sin(2 * X - 1.5 * t) * np.cos(2 * Y + 1.2 * t) * np.exp(-0.18 * r2)
# Figure
fig, ax = plt.subplots(figsize=(6, 6))
Z0 = scalar_field(0)
im = ax.imshow(Z0, extent=[x.min(), x.max(), y.min(), y.max()], origin='lower')
plt.colorbar(im, ax=ax)
title = ax.set_title("t = 0.00")
# Update function
def update(frame):
t = frame * 0.12
Z = scalar_field(t)
im.set_array(Z)
title.set_text(f"t = {t:.2f}")
return [im]
# Animation
anim = FuncAnimation(fig, update, frames=60, interval=80)
# Save GIF
gif_path = "scalar_field.gif"
anim.save(gif_path, writer="pillow", fps=12)
plt.close()
# Display in notebook
Image(filename=gif_path)
1. Import knihoven
Nejprve si načteme potřebné knihovny:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import Image
Co která dělá:
numpypoužíváme pro práci s čísly, poli a mřížkou bodůmatplotlib.pyplotslouží k vykreslování grafů a obrázkůFuncAnimationumí z jednotlivých snímků vytvořit animaciImagezobrazí hotový GIF přímo v notebooku
2. Vytvoření prostoru, ve kterém pole počítáme
Teď si připravíme dvourozměrnou oblast, ve které budeme pole sledovat.
nx, ny = 200, 200
x = np.linspace(-3, 3, nx)
y = np.linspace(-3, 3, ny)
X, Y = np.meshgrid(x, y)
Co se tady děje:
nx, ny = 200, 200určuje počet bodů v osách $x$ a $y$np.linspace(-3, 3, nx)vytvoří rovnoměrně rozložené body od $-3$ do $3$meshgridz těchto dvou jednorozměrných os vytvoří pravoúhlou síť bodů
Výsledkem jsou dvě matice:
Xobsahuje $x$-ové souřadnice všech bodůYobsahuje $y$-ové souřadnice všech bodů
Jinými slovy: vytvořili jsme si prostor, ve kterém budeme pole počítat.
3. Definice samotného skalárního pole
Teď definujeme funkci, která vrací hodnotu pole v čase $t$.
def scalar_field(t):
r2 = X**2 + Y**2
return np.sin(2 * X - 1.5 * t) * np.cos(2 * Y + 1.2 * t) * np.exp(-0.18 * r2)
Tohle je srdce celé ukázky.
Co znamená r2 = X**2 + Y**2
To je výraz pro druhou mocninu vzdálenosti od středu:
$$ r^2 = x^2 + y^2 $$
Čím dál jsme od středu, tím větší je tato hodnota.
Co dělá zbytek funkce
Pole je složeno ze tří částí:
sin(2 * X - 1.5 * t)
vytváří vlnění ve směru osy $x$cos(2 * Y + 1.2 * t)
přidává vlnění ve směru osy $y$exp(-0.18 * r2)
způsobí, že pole směrem od středu slábne
Dohromady dostaneme pole, které:
- má v prostoru strukturu
- v čase se mění
- a není stejně silné všude
Matematicky bychom to mohli zapsat takto:
$$ f(x,y,t)=\sin(2x-1.5t)\cos(2y+1.2t)e^{-0.18(x^2+y^2)}$$
Tohle není model konkrétní fyzikální situace. Je to spíš didaktický příklad, na kterém je dobře vidět, co znamená časově proměnné skalární pole.
4. Vytvoření obrázku pro první snímek
Teď si připravíme obrázek a vykreslíme první stav pole.
fig, ax = plt.subplots(figsize=(6, 6))
Z0 = scalar_field(0)
im = ax.imshow(Z0, extent=[x.min(), x.max(), y.min(), y.max()], origin='lower')
plt.colorbar(im, ax=ax)
title = ax.set_title("t = 0.00")
Co se děje krok za krokem:
plt.subplots(figsize=(6, 6))vytvoří plátno a osu grafuscalar_field(0)spočítá pole v čase (t = 0)imshow(...)zobrazí matici hodnot jako barevnou mapuextent=[...]zajistí, že osy odpovídají skutečným souřadnicímorigin='lower'nastaví počátek dole vlevocolorbar(...)přidá barevnou legenduset_title(...)vytvoří nadpis s aktuálním časem
Tím máme první „fotku“ systému.
5. Funkce, která mění jednotlivé snímky
Aby vznikla animace, musíme pro každý snímek přepočítat pole pro nový čas.
def update(frame):
t = frame * 0.12
Z = scalar_field(t)
im.set_array(Z)
title.set_text(f"t = {t:.2f}")
return [im]
Tahle funkce se zavolá znovu a znovu pro každý snímek animace.
Co přesně dělá:
frameje číslo snímku: 0, 1, 2, 3, ...t = frame * 0.12převede číslo snímku na časscalar_field(t)spočítá nové hodnoty poleim.set_array(Z)nahradí starý obrázek novými datytitle.set_text(...)aktualizuje nadpis
To je přesně ten moment, kdy se statická „fotka“ mění ve „film“.
6. Vytvoření animace
Teď spojíme všechny snímky dohromady.
anim = FuncAnimation(fig, update, frames=60, interval=80)
Význam parametrů:
figje obrázek, který se má animovatupdateje funkce, která upravuje každý snímekframes=60znamená, že animace bude mít 60 snímkůinterval=80říká, že mezi snímky bude 80 milisekund
Tím vznikne objekt animace.
7. Uložení do GIFu
Hotovou animaci uložíme jako GIF.
gif_path = "scalar_field.gif"
anim.save(gif_path, writer="pillow", fps=12)
Co to znamená:
gif_pathje název souboruwriter="pillow"použije knihovnu Pillow pro vytvoření GIFufps=12nastaví 12 snímků za sekundu
8. Zobrazení výsledku v notebooku
Nakonec GIF zobrazíme přímo v Colabu.
plt.close()
Image(filename=gif_path)
plt.close()zavře statický obrázek, aby se nezobrazoval navícImage(...)vloží hotový GIF do výstupu notebooku
Co je na tom matematicky důležité
Na tomhle jednoduchém příkladu je vidět zásadní rozdíl mezi dvěma situacemi:
Statické pole
Závisí jen na prostoru:
$$ f(x, y) $$
nebo obecně
$$ f(x, y, z) $$
Nestacionární pole
Závisí i na čase:
$$ f(x, y, t) $$
nebo obecně
$$ f(x, y, z, t) $$
A právě přidání času je ten krok, kterým se z popisu stavu stává popis děje.
Animace vektorového pole v Pythonu
V předchozím příkladu jsme si ukázali, jak se může v čase měnit skalární pole.
Jednoduše řečeno: v každém bodě prostoru se měnila hodnota — v našem případě barva.
Můžeme si to představit jako teplotu, která se během dne mění v každém místě.
Teď se posuneme o krok dál.
Podíváme se na vektorové pole.
V kontextu počasí to znamená, že v každém bodě prostoru nesledujeme jen jednu hodnotu, ale i směr.
Konkrétně:
- jak rychle vítr fouká
- a kam fouká
Jinými slovy, v každém bodě sledujeme vektor rychlosti větru, který se v čase mění.
V předchozím příkladu jsme pracovali se skalárním polem — každému bodu jsme přiřadili číslo.
Teď se posuneme o krok dál.
Místo čísla budeme každému bodu přiřazovat vektor, tedy velikost a směr.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import Image
# Grid
nx, ny = 20, 20
x = np.linspace(-3, 3, nx)
y = np.linspace(-3, 3, ny)
X, Y = np.meshgrid(x, y)
# Vector field
def vector_field(t):
U = -Y * np.cos(t) # x-component
V = X * np.sin(t) # y-component
return U, V
# Figure
fig, ax = plt.subplots(figsize=(6, 6))
U0, V0 = vector_field(0)
q = ax.quiver(X, Y, U0, V0)
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.set_title("t = 0.00")
# Update function
def update(frame):
t = frame * 0.1
U, V = vector_field(t)
q.set_UVC(U, V)
ax.set_title(f"t = {t:.2f}")
return [q]
# Animation
anim = FuncAnimation(fig, update, frames=60, interval=80)
# Save GIF
gif_path = "vector_field.gif"
anim.save(gif_path, writer="pillow", fps=12)
plt.close()
# Display
Image(filename=gif_path)
1. Vytvoření prostoru
Stejně jako předtím si vytvoříme mřížku bodů:
nx, ny = 20, 20
x = np.linspace(-3, 3, nx)
y = np.linspace(-3, 3, ny)
X, Y = np.meshgrid(x, y)
Rozdíl je v tom, že tentokrát používáme méně bodů.
Důvod je jednoduchý: vektorové pole budeme kreslit pomocí šipek a příliš hustá síť by byla nepřehledná.
2. Definice vektorového pole
Teď definujeme funkci, která vrací dvě složky vektoru:
def vector_field(t):
U = -Y * np.cos(t)
V = X * np.sin(t)
return U, V
Každý bod má tedy dvě hodnoty:
- $U(x,y,t)$ — složka ve směru osy $x$
- $V(x,y,t)$ — složka ve směru osy $y$
Matematicky:
$$ \mathbf{F}(x,y,t) = (U(x,y,t), V(x,y,t)) $$
Co to pole vlastně dělá?
Podívejme se na jednotlivé části:
U = -Y * cos(t)V = X * sin(t)
To znamená:
- směr vektoru závisí na poloze $(x,y)$
- a zároveň se mění v čase
Výsledkem je pole, které připomíná rotaci, která se v čase mění.
Intuitivně:
- body „obíhají“ kolem středu
- ale rychlost a orientace se mění
3. Vykreslení prvního snímku
fig, ax = plt.subplots(figsize=(6, 6))
U0, V0 = vector_field(0)
q = ax.quiver(X, Y, U0, V0)
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.set_title("t = 0.00")
Používáme funkci quiver, která kreslí šipky:
- každá šipka reprezentuje vektor
- směr = orientace šipky
- velikost = délka šipky
4. Aktualizace v čase
def update(frame):
t = frame * 0.1
U, V = vector_field(t)
q.set_UVC(U, V)
ax.set_title(f"t = {t:.2f}")
return [q]
Klíčový řádek:
q.set_UVC(U, V)
Ten aktualizuje všechny šipky najednou.
To je rozdíl oproti skalárnímu poli:
- tam jsme měnili barvy
- tady měníme směr a velikost šipek
5. Vytvoření animace
anim = FuncAnimation(fig, update, frames=60, interval=80)
Stejně jako předtím:
- 60 snímků
- každý reprezentuje jiný čas
6. Uložení a zobrazení
gif_path = "vector_field.gif"
anim.save(gif_path, writer="pillow", fps=12)
plt.close()
Image(filename=gif_path)
Místo statického obrázku — fotografie — jsme najednou dostali animaci.
Film.
A to je podstatně zajímavější.
Nevidíme už jen stav, ale i vývoj.
Vidíme, jak se pole mění, jak „teče“, kam směřuje.
To je další krok k popisu reálných situací — a nakonec i k jejich predikci.
A právě tady se objevuje zásadní otázka:
Jak tento pohyb vlastně popsat?
Jak popsat změnu: první krok k dynamice
Když se díváme na animaci, intuitivně vidíme, že se něco mění.
Ale intuice nestačí — potřebujeme způsob, jak tuto změnu kvantifikovat.
Podívejte se na přiložené video z termokamery, která sleduje ohřívání radiátoru.
Každý snímek tohoto videa představuje dvojrozměrné skalární pole teploty.
Každému bodu roviny je přiřazena jedna hodnota a ta je zobrazena barvou — od chladnější modré po teplejší červenou.
Pokud bychom analyzovali jediný snímek, popisovali bychom pouze stav systému v jednom okamžiku.
To už ale nestačí.
My chceme popsat, jak se toto pole vyvíjí v čase.
Jak se teplo šíří, jak se jednotlivé body ohřívají a jak se celý obraz postupně mění.
A tím se dostáváme k zásadní otázce:
Jak popsat změnu pole v čase?
Nejjednodušší odpověď je překvapivě intuitivní.
Podívejme se na jeden konkrétní bod na radiátoru.
Vyberme si třeba jedno místo a sledujme, co se s ním děje v čase.
Na začátku má určitou teplotu.
O chvíli později je o něco teplejší.
Za další okamžik zase jiná.
Jinými slovy: v každém bodě prostoru máme funkci času.
$$ T(t) $$
kde:
$ T $ je teplota a $ t $ je čas. Na toto pozor. Jedna se o stejné písmeno, zde záleží na velikosti.
Měření teploty radiátoru pro každý bod každé 2 minut by vypadalo nějak takto.

Vidíme, že růst teploty není lineární, tedy že v každém okamžiku neroste teplota o stejnou hodnotu. Ohřívání daného bodu ve skutečnosti zpomaluje. Ještě si ukážeme, jak jsem tento případ modeloval v Pythonu.
import numpy as np
import matplotlib.pyplot as plt
# Diskrétní časové body (minuty)
t = np.arange(0, 61, 2)
# Parametry modelu
T_env = 20.0 # počáteční teplota (°C)
T_final = 65.0 # ustálená teplota (°C)
tau = 10.0 # časová konstanta
# Model ohřívání
T = T_env + (T_final - T_env) * (1 - np.exp(-t / tau))
# Vykreslení
plt.figure(figsize=(8, 5))
plt.scatter(t, T)
plt.xlabel("Time [min]")
plt.ylabel("Temperature [°C]")
plt.title("Discrete measurement of radiator temperature")
plt.grid(True)
plt.show()1. Diskrétní časové body
t = np.arange(0, 61, 2)
Tímto vytvoříme časovou osu:
- od 0 do 60 minut
- s krokem 2 minuty
To odpovídá situaci, kdy měříme teplotu každé dvě minuty.
2. Parametry systému
T_env = 20.0
T_final = 65.0
tau = 12.0
Každý parametr má svůj fyzikální význam:
T_env— počáteční teplota (např. teplota místnosti)T_final— ustálená teplota radiátorutau— časová konstanta, která určuje, jak rychle se systém ohřívá
3. Model ohřívání
T = T_env + (T_final - T_env) * (1 - np.exp(-t / tau))
Tato rovnice popisuje typické chování mnoha fyzikálních systémů:
- na začátku teplota roste rychle
- postupně se růst zpomaluje
- a nakonec se blíží ustálené hodnotě
Matematicky jde o exponenciální přiblížení k rovnováze.
4. Vykreslení měření
plt.scatter(t, T)
Používáme scatter, nikoliv plot.
To je důležité.
Nechceme naznačit, že známe přesný průběh funkce.
Chceme ukázat pouze naměřené body.
5. Popisky a mřížka
plt.xlabel("Time [min]")
plt.ylabel("Temperature [°C]")
plt.title("Discrete measurement of radiator temperature")
plt.grid(True)
- osy říkají, co měříme
- nadpis dává kontext
- mřížka pomáhá s orientací
6. Zobrazení grafu
plt.show()
Tím se graf zobrazí přímo v notebooku.
Tento graf vypadá jednoduše, ale skrývá zásadní myšlenku:
Realita nám nedává funkce. Dává nám data.
Nemáme k dispozici spojitou křivku.
Máme pouze jednotlivé body.
A z těchto bodů se snažíme pochopit:
- jak se systém chová
- jak rychle se mění
- a co se bude dít dál
A právě tady přichází další otázka:
Jak z těchto diskrétních dat zjistit rychlost změny?
Jak odhadnout, jak rychle se radiátor ohřívá v daném okamžiku?
To je vlastně celkem jednoduché.
Změříme počáteční teplotu.
Počkáme zvolený časový interval a změříme ji znovu.
Teď víme, jakou teplotu měl radiátor na začátku a na konci intervalu.
Rozdíl těchto hodnot vydělíme délkou časového úseku a získáme rychlost změny.
Matematicky:
$$ \frac{T_1 - T_0}{\Delta t} = \frac{\Delta T}{\Delta t} $$
kde:
- $ T_0 $ je počáteční teplota
- $ T_1 $ je teplota po uplynutí času
- $ \Delta T = T_1 - T_0 $ je změna teploty
- $ \Delta t $ je časový interval
Tento výpočet nám dává průměrnou rychlost změny na daném časovém úseku.
Když se zaměříme na konkrétní časový okamžik třeba 10. minutu, můžeme spočítat rychlost změny. Z 10. minuty na 12. minutu vyroste teplota z 45,4 ˚C na 48,4 ˚C. To je o 3 ˚C. Časový interval je 2 minuty. Průměrná rychlost změny teploty je 1,5 ˚C za minutu.
Co se stane, když časový interval budeme měnit?
Vyzkoušíme si tento experiment v Pythonu.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Model teploty
def T(t):
T_env = 20
T_final = 65
tau = 12
return T_env + (T_final - T_env) * (1 - np.exp(-t / tau))
# Bod sledování
t0 = 10 # minuta
# Původní + menší kroky (logaritmicky)
delta_t_values = [5, 2, 1, 0.5, 0.1, 0.01] + list(np.logspace(-2, -4, 10))
rows = []
rates = []
for dt in delta_t_values:
T0 = T(t0)
T1 = T(t0 + dt)
rate = (T1 - T0) / dt
rates.append(rate)
rows.append({
"Δt": dt,
"T(t0)": round(T0, 3),
"T(t0 + Δt)": round(T1, 3),
"ΔT/Δt": round(rate, 6)
})
# Tabulka
df = pd.DataFrame(rows)
df = df.sort_values("Δt", ascending=False)
display(df)
# Graf
plt.figure(figsize=(8, 5))
plt.plot(delta_t_values, rates, marker='o')
plt.xscale('log') # klíčové!
plt.xlabel("Δt (log scale)")
plt.ylabel("ΔT/Δt")
plt.title("Convergence to derivative")
plt.grid(True)
plt.show()
| index | Δt | T(t0) | T(t0 + Δt) | ΔT/Δt |
|---|---|---|---|---|
| 0 | 5.0 | 45.443 | 52.107 | 1.332841 |
| 1 | 2.0 | 45.443 | 48.445 | 1.501172 |
| 2 | 1.0 | 45.443 | 47.007 | 1.563685 |
| 3 | 0.5 | 45.443 | 46.241 | 1.596257 |
| 4 | 0.1 | 45.443 | 45.605 | 1.622972 |
| 5 | 0.01 | 45.443 | 45.459 | 1.629064 |
| 6 | 0.01 | 45.443 | 45.459 | 1.629064 |
| 7 | 0.005994842503189409 | 45.443 | 45.453 | 1.629336 |
| 8 | 0.003593813663804626 | 45.443 | 45.449 | 1.629499 |
| 9 | 0.0021544346900318843 | 45.443 | 45.447 | 1.629597 |
| 10 | 0.001291549665014884 | 45.443 | 45.445 | 1.629656 |
| 11 | 0.000774263682681127 | 45.443 | 45.444 | 1.629691 |
| 12 | 0.0004641588833612782 | 45.443 | 45.444 | 1.629712 |
| 13 | 0.0002782559402207126 | 45.443 | 45.444 | 1.629724 |
| 14 | 0.0001668100537200059 | 45.443 | 45.443 | 1.629732 |
| 15 | 0.0001 | 45.443 | 45.443 | 1.629736 |

V tabulce i v grafu si můžeme všimnout určitého vzorce. Když zvolíme velký časový interval, vyjde nám menší průměrná rychlost změny teploty než při menším intervalu. Důvod je jednoduchý — ohřívání se postupně zpomaluje a radiátor se ve 12. minutě ohřívá pomaleji než v 11. minutě. Pokud tedy vezmeme delší interval, zahrneme do něj jak rychlejší, tak pomalejší změny, a výsledná průměrná rychlost je proto menší.
Když interval postupně zmenšujeme, začínáme se soustředit na stále kratší úsek času. Od určité chvíle (v našem případě přibližně od $ \Delta t = 0,01 $) si můžeme všimnout, že se hodnota téměř nemění a rychlost oteplování se stabilizuje přibližně kolem hodnoty $ 1,623 \ \mathrm{^\circ C/min} $.
Na tomto jednoduchém experimentu si můžeme uvědomit důležitou skutečnost: počítač neumí pracovat se spojitými funkcemi tak, jak je popisuje matematika. Místo toho pracuje s konečným množstvím hodnot — s jednotlivými body. Každou spojitou funkci proto musíme nahradit její aproximací pomocí diskrétních bodů.
Když tedy simulujeme nějaký děj, je velmi důležité, jaký zvolíme časový krok. Pro přesné simulace potřebujeme co nejmenší interval, to ale přináší problém — zpomaluje to výpočet a zvyšuje nároky na paměť. Musíme proto vždy hledat určitý kompromis mezi přesností a výpočetní náročností.
Intervaly bychom mohli zmenšovat stále víc a víc.
Počítač ale neumí pracovat s nekonečně malými čísly, a proto pokud chceme znát přesnou hodnotu změny v konkrétním okamžiku, musíme se obrátit na matematiku.
Jak tedy získáme přesnou hodnotu v daném bodě?
Dobře, nebudu vás napínat. Existuje pojem, kterého se mnoho studentů bakalářského studia obává. Říká se mu derivace.
Představme si, že budeme časový interval postupně zmenšovat:
$$ 0{,}1 \rightarrow 0{,}01 \rightarrow 0{,}001 \rightarrow \dots \rightarrow 10^{-6} \rightarrow \dots $$
A budeme sledovat, k jaké hodnotě se výraz
$$ \frac{\Delta T}{\Delta t} $$
blíží.
Matematicky tento proces zapíšeme pomocí limity:
$$ \lim_{\Delta t \to 0} \frac{\Delta T}{\Delta t} $$
A právě této limitě říkáme derivace.
$$ \frac{dT}{dt} $$
„Derivace není nic jiného než hodnota, ke které se stabilizuje naše měření, když zmenšujeme časový interval.“
Vysvětlení kódu
1. Import knihoven
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
Používáme tři základní nástroje:
numpypro numerické výpočtypandaspro práci s tabulkamimatplotlibpro vykreslení grafu
2. Model teploty
def T(t):
T_env = 20
T_final = 65
tau = 12
return T_env + (T_final - T_env) * (1 - np.exp(-t / tau))
Tato funkce modeluje ohřívání radiátoru v čase.
T_envje počáteční teplotaT_finalje ustálená teplotatauurčuje, jak rychle se systém ohřívá
Výsledkem je funkce $ T(t) $, která popisuje teplotu v čase.
3. Bod, ve kterém sledujeme změnu
t0 = 10
Vybereme si konkrétní okamžik — například 10. minutu — a budeme sledovat, jak se v tomto bodě mění teplota.
4. Volba časových intervalů
delta_t_values = [5, 2, 1, 0.5, 0.1, 0.01] + list(np.logspace(-2, -4, 10))
Zde kombinujeme:
- „velké“ intervaly (5, 2, 1, …)
- velmi malé intervaly generované funkcí
logspace
np.logspace(-2, -4, 10) vytvoří hodnoty mezi $ 10^{-2}$ a $10^{-4}$.
To je důležité, protože chceme sledovat chování při opravdu malých $ \Delta t $.
5. Výpočet průměrné změny
for dt in delta_t_values:
T0 = T(t0)
T1 = T(t0 + dt)
rate = (T1 - T0) / dt
Pro každý interval:
- spočítáme teplotu v čase $ t_0 $
- spočítáme teplotu v čase $ t_0 + \Delta t $
- vypočteme průměrnou změnu
$$ \frac{T(t_0 + \Delta t) - T(t_0)}{\Delta t} $$
To je přesně výraz, který jsme odvodili z měření.
6. Uložení výsledků do tabulky
rows.append({
"Δt": dt,
"T(t0)": round(T0, 3),
"T(t0 + Δt)": round(T1, 3),
"ΔT/Δt": round(rate, 6)
})
Každý výsledek uložíme jako jeden řádek tabulky:
- použitý interval $ \Delta t $
- teplota na začátku
- teplota na konci
- vypočtená rychlost změny
7. Vytvoření a seřazení tabulky
df = pd.DataFrame(rows)
df = df.sort_values("Δt", ascending=False)
display(df)
Data převedeme do tabulky a seřadíme od největšího intervalu po nejmenší.
Díky tomu je dobře vidět, jak se výsledek zpřesňuje.
8. Vykreslení grafu
plt.plot(delta_t_values, rates, marker='o')
Každý bod v grafu odpovídá jednomu výpočtu $ \frac{\Delta T}{\Delta t} $.
9. Logaritmická osa
plt.xscale('log')
Tohle je klíčový krok.
Protože hodnoty $ \Delta t $ se liší o několik řádů, použijeme logaritmickou osu.
Díky tomu:
- malé hodnoty nezmizí
- konvergence je jasně viditelná
10. Interpretace
Na grafu vidíme, že:
- pro velké $ \Delta t $ je odhad nepřesný
- jak interval zmenšujeme, hodnota se stabilizuje
- pro velmi malé $ \Delta t $ už se téměř nemění
Co tím vlastně děláme
Numericky jsme simulovali proces:
$$ \lim_{\Delta t \to 0} \frac{\Delta T}{\Delta t} $$
A viděli jsme, že výsledek se blíží konkrétní hodnotě.
Na závěr si ukážeme jak spočítat rychlost změny v 10. minutě přesně. A nebudeme to dělat ručně, ale pomůžeme si Pythonem a knihovnou SymPy.
import sympy as sp
from IPython.display import display, Math
# =========================
# 1. Define symbols
# =========================
t = sp.symbols('t', real=True, positive=True)
T_env, T_final, tau = sp.symbols('T_env T_final tau', real=True, positive=True)
display(Math(r"\text{Define symbols: } t,\; T_{\mathrm{env}},\; T_{\mathrm{final}},\; \tau"))
print("\n")
# =========================
# 2. Temperature model
# =========================
T = T_env + (T_final - T_env) * (1 - sp.exp(-t / tau))
display(Math(r"\text{Temperature model:}"))
display(Math(r"T(t) = T_{\mathrm{env}} + \left(T_{\mathrm{final}} - T_{\mathrm{env}}\right)\left(1 - e^{-t/\tau}\right)"))
print("\n\n")
# =========================
# 3. Derivative
# =========================
dT_dt = sp.diff(T, t)
display(Math(r"\text{Time derivative:}"))
display(Math(r"\frac{dT}{dt} = " + sp.latex(dT_dt)))
print("\n\n")
# =========================
# 4. Simplify
# =========================
dT_dt_simplified = sp.simplify(dT_dt)
display(Math(r"\text{Simplified derivative:}"))
display(Math(r"\frac{dT}{dt} = " + sp.latex(dT_dt_simplified)))
print("\n\n")
# =========================
# 5. Substitute values
# =========================
params = {T_env: 20, T_final: 65, tau: 12}
display(Math(r"\text{Substitute parameters: } T_{\mathrm{env}}=20,\; T_{\mathrm{final}}=65,\; \tau=12"))
T_numeric = T.subs(params)
dT_dt_numeric_expr = dT_dt_simplified.subs(params)
display(Math(r"\text{Temperature after substitution:}"))
display(Math(r"T(t) = " + sp.latex(T_numeric)))
print("\n")
display(Math(r"\text{Derivative after substitution:}"))
display(Math(r"\frac{dT}{dt} = " + sp.latex(dT_dt_numeric_expr)))
print("\n\n")
# =========================
# 6. Evaluate at t = 10
# =========================
t0 = 10
value_exact = dT_dt_numeric_expr.subs(t, t0)
value_numeric = sp.N(value_exact)
display(Math(r"\text{Evaluate derivative at } t = 10"))
display(Math(r"\left.\frac{dT}{dt}\right|_{t=10} = " + sp.latex(value_exact)))
print("\n")
display(Math(r"\left.\frac{dT}{dt}\right|_{t=10} \approx " + sp.latex(value_numeric)))
print("\n\n")
print(f"Numerical value at t = 10 min: {value_numeric:.6f} °C/min")V této ukázce si krok za krokem ukážeme, jak pomocí knihovny SymPy:
- definovat matematický model,
- spočítat jeho derivaci analyticky,
- dosadit konkrétní hodnoty,
- vyhodnotit výsledek v čase.
1. Definice symbolů
t = sp.symbols('t', real=True, positive=True)
T_env, T_final, tau = sp.symbols('T_env T_final tau', real=True, positive=True)
Zde definujeme proměnné jako symboly, nikoliv čísla.
To znamená, že pracujeme s obecným matematickým výrazem.
t→ časT_env→ okolní teplotaT_final→ konečná teplotatau→ časová konstanta
Díky tomu může SymPy počítat přesně (symbolicky).
2. Definice modelu
T = T_env + (T_final - T_env) * (1 - sp.exp(-t / tau))
Tady definujeme samotný model:
$$ T(t) = T_{\mathrm{env}} + (T_{\mathrm{final}} - T_{\mathrm{env}})\left(1 - e^{t/\tau}\right) $$
Jedná se o typický exponenciální model ohřívání.
Důležité:
- stále jde o symbolický výraz, ne o čísla
- můžeme s ním dál matematicky pracovat
3. Výpočet derivace
dT_dt = sp.diff(T, t)
Tento řádek spočítá derivaci podle času.
Výsledek:
$$ \frac{dT}{dt} = \frac{T_{\mathrm{final}} - T_{\mathrm{env}}}{\tau} e^{-t/\tau} $$
To je klíčový moment — dostáváme přesný analytický vztah, ne aproximaci.
4. Zjednodušení výrazu
dT_dt_simplified = sp.simplify(dT_dt)
SymPy často vrací složitější výrazy, proto je zjednodušíme.
Výsledek je:
- přehlednější
- lépe interpretovatelný
- vhodný pro další práci
5. Dosazení konkrétních hodnot
params = {T_env: 20, T_final: 65, tau: 12}
T_numeric = T.subs(params)
dT_dt_numeric_expr = dT_dt_simplified.subs(params)
Zde přecházíme z obecného modelu na konkrétní případ.
Dosazujeme:
- $ T_{\mathrm{env}} = 20 $
- $ T_{\mathrm{final}} = 65 $
- $ \tau = 12 $
Výsledkem je:
$$ T(t) = 20 + 45(1 - e^{-t/12}) $$
a derivace:
$$ \frac{dT}{dt} = \frac{45}{12} e^{-t/12} $$
Stále jde ale o funkci času, ne o jedno číslo.
6. Vyhodnocení v čase (t = 10)
t0 = 10
value_exact = dT_dt_numeric_expr.subs(t, t0)
value_numeric = sp.N(value_exact)
Nejprve dosadíme čas:
- získáme přesný symbolický výsledek
Poté:
- převedeme na číslo (
sp.N)
Výsledek reprezentuje:
$$ \left.\frac{dT}{dt}\right|_{t=10} $$
tedy rychlost změny teploty v 10. minutě.
7. Výstup a interpretace
print(f"Numerical value at t = 10 min: {value_numeric:.6f} °C/min")
Získáme konkrétní hodnotu v jednotkách:
- °C/min → jak rychle se teplota mění
Přesně spočítaný výsledek analytickou metodou je přibližně $1{,}629743$. Výsledek spočítaný numericky s časovým krokem $0{,}0001$ je $1{,}629736$. Rozdíl se projeví až na pátém desetinném místě.
To je v praxi mimořádně přesný výsledek. Pro představu: takto malá odchylka je výrazně menší než nejistota běžných měření teploty, která se typicky pohybuje v řádu setin až desetin stupně. V kontextu reálného měření je tedy taková chyba zanedbatelná.
Z toho plyne důležitý závěr: v simulacích často nemusíme používat extrémně malý časový krok. Můžeme si dovolit delší interval, který zrychlí výpočet a přitom zůstane pro naše účely dostatečně přesný.
To je ostatně jeden ze základních principů numerických výpočtů: nehledáme absolutně nejpřesnější možné řešení za každou cenu, ale takové řešení, které je dostatečně přesné vzhledem k problému, který chceme popsat.
Ještě se vraťme k našemu radiátoru.
Celou předchozí část jsme se zabývali změnou teploty v jednom konkrétním bodě.
Měli jsme tedy funkci jedné proměnné:
$$ T = f(t) $$
Pokud ale chceme popsat celý radiátor, musíme do modelu zahrnout i prostor.
Pokud budeme uvažovat například pouze jeho přední stěnu, jedná se o dvourozměrný objekt a teplota bude funkcí času a prostorových souřadnic $x$ a $y$:
$$ T = f(x, y, t) $$
Pokud bychom chtěli popsat celý radiátor v trojrozměrném prostoru, musíme přidat ještě třetí souřadnici $z$. Teplota pak bude funkcí čtyř proměnných:
$$ T = f(x, y, z, t) $$
A v tomto okamžiku nastává důležitá změna.
Už nemáme funkci jedné proměnné, ale funkci více proměnných.
Proto nemůžeme použít obyčejnou derivaci
$$ \frac{dT}{dt} $$
Místo toho používáme parciální derivaci:
$$ \frac{\partial T}{\partial t} $$
Parciální derivace podle času říká:
Jak se mění teplota v čase, pokud zůstaneme na jednom konkrétním místě v prostoru.
Jinými slovy:
- souřadnice $x, y, z$ necháme konstantní
- sledujeme pouze změnu v čase
„Místo klasického d používáme symbol ∂, který značí parciální derivaci — tedy derivaci funkce více proměnných podle jedné z nich.“
$$ \frac{\partial T(x, y, z, t)}{\partial t} $$
Symbol $ \partial $ znamená, že derivujeme funkci více proměnných pouze podle jedné z nich.
Naučili jsme se popsat změnu.
Umíme ji měřit, aproximovat a dokonce i přesně spočítat.
Zbývají nám ale dvě zásadní otázky:
- Co změnu způsobuje?
- Jak se změna chová?
Otázka „co změnu způsobuje“ patří do oblasti fyziky.
Právě ta popisuje zákony, které řídí různé děje v přírodě. Pro simulace je to klíčové téma, ale k tomu se dostaneme později v jiném článku.
Teď se zaměřme na druhou otázku:
Jak se tato změna chová?
Je náhodná?
Má nějaký vzor?
Nebo se dokonce opakuje?
Ne všechny změny jsou náhodné
Všechny děje se nedějí náhodně. Některé děje se opakují podle určitého vzorce. Teplota v určitém místě venku od rána stoupá k maximu a od večera do rána klesá k minimu. Žárovka nesvítí stále stejně intenzivně, ale její intenzita se mění 50 × za sekundu.
Dalším příkladem je zvuk.
Když rozezníme hudební nástroj, například kytaru, vznikají kmity, které se šíří prostorem. Na zpomaleném záběru můžeme vidět, jak se struna periodicky pohybuje nahoru a dolů.
Kmity, které se šíří prostorem, způsobují vibrace na okolních předmětech.
Na videu můžeme pozorovat, jak tyto vibrace vytvářejí pravidelné obrazce na povrchu desky. Tyto obrazce se nazývají Chladniho obrazce.
Můžeme si všimnout, že změna není náhodná, ale že má strukturu. Žárovka bliká 50 × za sekundu. Struna vytváří pravidelnou vlnu a zvuk v prostoru rozvibruje desku, na které vznikají pravidelné obrazce.
S těmito pokusy trochu předbíháme.
Naši předci si opakujících se dějů všimli mnohem dříve — a úplně jinde, než na naší planetě. Stačilo se podívat na oblohu.
Při pozorování si postupně začali všímat, že se polohy vesmírných objektů opakují.
Jedním z nejjednodušších příkladů jsou fáze Měsíce. Úplněk se opakuje přibližně jednou za 29,5 dne.
Postupně si začali všímat i pohybu Slunce — jak během dne, tak v průběhu celého roku. Poloha Slunce na obloze se mění, ale zároveň se s určitou pravidelností vrací.
A tím to nekončilo. Do jejich pozorování postupně přibyly i planety, jejichž pohyb byl složitější, ale stále vykazoval určité opakující se vzorce.
Na videu můžete vidět pozici slunce na obloze v určitou hodinu po dobu celého roku. Video bylo natáčeno tři roky, aby byl ověřen opakující se vzorec. Obrazec, který vznikne se nazývá Analema.
Víme, že existují opakující se děje, které se nazývají periodické. Zbývá nám otázka:
Jak je matematicky popsat?
Naši předci začínali s daty.
Pozorovali oblohu, zapisovali si polohy vesmírných objektů a postupně si začali všímat opakujících se vzorů. Věděli, kdy nastane úplněk, kdy dojde k zatmění Měsíce nebo Slunce, a kdy se planety a hvězdy vrátí na určitou polohu.
Vidíme zde přirozený proces poznání:
- nejprve data
- v datech hledáme vzory
- ze vzorů odvozujeme pravidla
- a teprve nakonec vzniká obecná teorie
Ve škole se tento proces často obrací.
Nejdříve dostaneme hotovou teorii, definice a vzorce.
A teprve potom se z nich odvozují konkrétní případy.
To je efektivní z hlediska výuky, ale z hlediska pochopení to může být náročné.
Student vidí výsledek, ale ne cestu, která k němu vedla.
A právě proto mohou přírodní a technické vědy působit obtížně.
Ne proto, že by byly samy o sobě nepochopitelné, ale proto, že přeskakujeme přirozený proces objevování.
Když tedy lidé našli v datech opakující se vzory, vyvstala další otázka:
Jak takové opakování popsat jednoduše a přesně?
Tabulky fungují, ale nejsou příliš praktické.
Pokud chceme předpovídat a počítat, potřebujeme jednodušší model.
A právě tady přichází klíčová myšlenka:
Potřebujeme něco, co se přirozeně opakuje.
A co se opakuje dokonale?
Kruh.
Pohyb po kružnici
Pohyb po kružnici má jednu zásadní vlastnost:
Po jedné otáčce jsme zpět na začátku.
A celý děj se může opakovat znovu a znovu.
To přesně odpovídá tomu, co lidé pozorovali:
- Slunce se vrací na stejnou pozici
- Měsíc prochází stejnými fázemi
- hvězdy se vracejí na stejná místa
Kruh se tak stal přirozeným kandidátem na první matematický model periodických dějů.

Na animaci vidíme bod, který se pohybuje po kružnici. Tento pohyb je periodický — po jedné otáčce se opakuje.
Kruh je tedy přirozený model opakujících se dějů.
Ve skutečnosti ale většinou nesledujeme celý pohyb v prostoru. Zajímá nás jen to, jak se nějaká veličina mění v čase.
A právě to zatím neumíme popsat.
Představme si jednoduchý experiment.
Necháme bod obíhat po kružnici, ale nebudeme sledovat jeho polohu v rovině.
Budeme sledovat pouze jeho výšku.

Na levé straně vidíme bod, který se pohybuje po kružnici.
Tento pohyb je periodický — po jedné otáčce se bod vrací zpět na začátek a celý děj se opakuje.
Na pravé straně sledujeme něco jiného.
Nezajímá nás celá poloha bodu v prostoru, ale pouze jeho výška. Jinými slovy sledujeme projekci bodu na svislou osu.
A právě tato projekce se v čase zapisuje jako křivka.
Křivka roste, klesá a opakuje se. Není náhodná — má přesnou strukturu.
Tato křivka má jméno sinus a matematicky se zapisuje takto:
$$ y = \sin(t) $$
Sinus nevzniká jako abstraktní funkce. Je to záznam jedné konkrétní veličiny — výšky bodu, který se pohybuje po kružnici.
Když zaznamenáme pohyb na ose x dostaneme funkci kosinus:
$$ y = \cos(t) $$

Udělali jsme velký krok.
Máme matematickou funkci, která popisuje periodický pohyb. Jakmile máme funkci, můžeme takový děj nejen popsat, ale i analyzovat a měnit jeho vlastnosti.
Podívejme se na křivku, kterou jsme vytvořili, a zkusme pojmenovat parametry, které můžeme ovlivnit.
Amplituda
Začněme svislou osou, tedy osou $y$.
Vidíme, že v našem případě nabývá funkce hodnot od $-1$ do $1$. Matematicky tomu říkáme obor hodnot.
Co když ale popisovaný děj nenabývá hodnot v tomto rozmezí?

V takovém případě stačí funkci vynásobit konstantou:
$$ y(t) = A \sin(t) $$
Tím se změní rozsah hodnot:
$$ y(t) \in \langle -A, A \rangle $$
Této konstantě říkáme amplituda a značí se $A$.
V našem konkrétním případě platí:
$A=1$
Amplituda určuje, jak velká je výchylka daného děje — například u zvuku určuje hlasitost.
Vertikální posun
Zůstaňme ještě chvíli u svislé osy ($y$).
Co když popisujeme děj, který nenabývá záporných hodnot? V našem případě se hodnoty pohybují od $-1$ do $1$. Existují ale veličiny, které záporné hodnoty nemají — například hlasitost zvuku nebo tlak vzduchu.

Jak tedy zajistíme, aby funkce nebyla nikdy záporná?
Je to jednodušší, než se zdá. Stačí k ní přičíst konstantu, která celý graf posune do kladných hodnot.
Této konstantě říkáme vertikální posun.
Funkce pak má tvar:
$$ y(t) = A \sin(t) + C $$
Frekvence a perioda
Přejděme nyní k ose (x), tedy k času (t). Při pohledu na graf si můžeme všimnout důležité vlastnosti: funkce se po určité době začne opakovat. V případě základní sinusové funkce k tomu dochází v čase
$$ t = 2\pi \approx 6{,}28. $$
Tento časový úsek nazýváme perioda.
Slovo perioda pochází z řeckého periodos, kde peri znamená „kolem“ a hodos „cesta“. Doslovně tedy „cesta dokola“, což přesně odpovídá tomu, co funkce dělá — po určité době se vrací na začátek a celý průběh se opakuje.
Podobně jako jsme u amplitudy násobili hodnoty na ose $y$, můžeme nyní násobit proměnnou $t$. Tím ovlivňujeme, jak rychle se funkce opakuje. Pokud například chceme, aby se do intervalu $2\pi$ vešly dva celé kmity, jednoduše vynásobíme proměnnou $t$ dvěma.

Tento násobek nazýváme frekvence. Udává, kolikrát se děj opakuje za jednotku času. Značí se buď latinským písmenem $f$, nebo — zejména ve fyzice — řeckým písmenem $\omega$ (úhlová frekvence).
Upravený tvar funkce pak vypadá takto:
$$ y(t) = A \sin(\omega t) + C. $$
Vztah mezi frekvencí a periodou je velmi jednoduchý a zároveň zásadní. Základní sinusová funkce má periodu
$$ T = 2 \pi, $$
což znamená, že po tomto čase se její průběh zopakuje.
Frekvence pak určuje, kolikrát se tento cyklus „vejde“ do daného časového úseku. Jinými slovy, říká nám, jak rychle se funkce opakuje.
Tento vztah můžeme matematicky vyjádřit následovně:
$$ \omega = \frac{2\pi}{T}. $$
Z toho je vidět důležitá souvislost: čím kratší je perioda $T$, tím větší je frekvence $\omega$ — a tedy tím rychleji funkce kmitá.
Fázový posun
Nyní už umíme popsat téměř vše. Chybí nám pouze způsob, jak funkci posunout na ose $x$ tedy v čase. Podobně jako jsme použili parametr $C$ pro vertikální posun na ose $y$, existuje i parametr pro horizontální posun.
Tento posun se zapisuje jako přičtení konstanty k argumentu funkce, tedy k členu $ \omega t $. Označuje se řeckým písmenem $ \varphi $ (fí) a říká se mu fázový posun. Určuje, v jakém „bodě cyklu“ se funkce nachází v čase $ t=0 $.
Celkový tvar funkce pak vypadá následovně:
$$ y(t) = A \sin(\omega t + \varphi) + C. $$
Vlna
Popsat periodický děj, který se opakuje v čase, nám dalo docela práci. Ve skutečnosti jsme ale celou dobu sledovali jen změnu v jednom konkrétním bodě — tedy závislost na čase $ y(t) $.
Pozorný čtenář si ale může položit zásadní otázku:
co prostor? Neexistují děje, které se mění nejen v čase, ale i v prostoru — a přitom si zachovávají pravidelnost?
Odpověď zní: ano, a říkáme jim vlny.
Na videu je krásně vidět, jak se kovové drátky vlní a jejich poloha se mění v čase i prostoru. Jedná se o typickou ukázku harmonické vlny. Stejný princip si můžeme snadno nasimulovat například v Pythonu.

V animaci i ve videu vidíme, jak se vlna šíří prostorem. Jednotlivé body (například části provazu nebo drátků) pouze kmitají nahoru a dolů, ale samotný tvar vlny se posouvá.
V daném okamžiku tedy závisí výchylka na dvou věcech:
- na čase $t$,
- na poloze $x$.
Matematicky to vyjádříme tak, že jde o funkci dvou proměnných:
$$ y(x, t) $$.
Tím se dostáváme od jednoduchého kmitání v čase k obecnějšímu popisu dějů, které probíhají současně v čase i prostoru.
Jak ale takovou vlnu matematicky popsat? U kmitání v čase jsme si postupně zavedli amplitudu, periodu, frekvenci, vertikální posun i fázový posun. Teď budeme na stejném principu pokračovat dál, jen už nebudeme sledovat jediný bod, ale celý děj šířící se prostorem.
Na animaci harmonické vlny si postupně ukážeme, které parametry musíme zavést, co přesně vyjadřují a jak navazují na to, co už známe z popisu kmitání v čase. Díky tomu uvidíme, že popis vlny není úplně nová matematika, ale přirozené rozšíření dosavadního modelu o prostorovou souřadnici.
Začněme tím nejjednodušším. Představme si jeden konkrétní bod v prostoru, například bod s souřadnicí $ x = 0 $. V tomto bodě se vlna chová úplně stejně, jako jsme si už ukázali — tedy jako kmitání v čase:
$$ y(0, t) = A \sin(\omega t + \varphi). $$
Teď ale uděláme malý krok. Co když se podíváme na jiný bod, například $ x=1? $ Vykreslíme si výchylku pro bod $ x = 0 $ a $ x = 1 $ za celý časový úsek.

Vidíme, že obě křivky mají stejný tvar, ale jedna je vůči druhé „zpožděná“. Vlna totiž potřebuje určitý čas, aby se z jednoho bodu prostoru dostala do druhého. Jednotlivé body tedy nekmitají nezávisle, ale jsou navzájem propojené posunem.
Tento posun můžeme chápat dvěma způsoby. Buď jako zpoždění v čase, nebo jako posun v prostoru. A právě druhý pohled je pro popis vlny velmi užitečný. Posouvat funkci na ose $x$ už umíme — stačí k argumentu sinusové funkce přičíst vhodný člen. Tentokrát však tento posun nebude konstantní, ale bude záviset na poloze v prostoru, tedy na souřadnici $x$.
Zavedeme proto nový parametr, kterému říkáme vlnové číslo a značíme ho $k$. Tento parametr určuje, jak rychle se vlna mění v prostoru a jak hustě jsou za sebou uspořádány její vrcholy a minima.
Díky tomu můžeme zapsat obecnější tvar harmonické vlny:
$$ y(x, t) = A \sin(\omega t - kx + \varphi). $$
Tato rovnice v sobě spojuje dva důležité pohledy na tentýž děj. Člen $\omega t$ popisuje, jak se vlna vyvíjí v čase, zatímco člen $kx$ vyjadřuje, jak se mění v prostoru.
Znaménko minus zde není náhodné. Má fyzikální význam: říká nám, že se vlna šíří ve směru rostoucí osy $x$. Pokud bychom místo něj použili plus, vlna by se šířila opačným směrem.
Teď už máme kompletní matematický popis harmonické vlny. A co je důležité — nevytvořili jsme nic úplně nového. Pouze jsme známý model kmitání rozšířili o prostorovou souřadnici.
Parametry vlnové funkce
Rovnice harmonické vlny může mít několik ekvivalentních tvarů podle toho, jaké parametry chceme použít a co chceme zdůraznit. Nejčastěji se setkáme s těmito zápisy:
$$ y(x,t) = A \sin(\omega t - kx + \varphi),$$
$$ y(x,t) = A \sin\left(2\pi\left(ft - \frac{x}{\lambda}\right) + \varphi\right), $$
$$ y(x,t) = A \sin\left(\omega\left(t - \frac{x}{v}\right) + \varphi\right). $$
Všechny tyto rovnice popisují stejný fyzikální děj, liší se pouze tím, jaké veličiny používají.
Parametr $A$ je amplituda — maximální výchylka od rovnovážné polohy. Udává „sílu“ nebo velikost kmitání.
Parametr $\omega$ je úhlová frekvence a popisuje, jak rychle se děj mění v čase. Je svázána s frekvencí $f$ vztahem:
$$ \omega = 2\pi f. $$
Frekvence $f$ říká, kolikrát se děj zopakuje za jednotku času (například za sekundu). S frekvencí souvisí perioda $T$, což je doba jednoho cyklu:
$$ T = \frac{1}{f}. $$
Parametr $k$ je vlnové číslo, které popisuje změnu v prostoru — tedy jak rychle se vlna „opakovaně střídá“ podél osy $x$. Je svázáno s vlnovou délkou $\lambda$ vztahem:
$$ k = \frac{2\pi}{\lambda}.$$
Vlnová délka $\lambda$ udává vzdálenost mezi dvěma sousedními vrcholy (nebo jinými odpovídajícími body) vlny.
Parametr $v$ je rychlost šíření vlny, tedy jak rychle se vlna pohybuje prostorem. Je dán vztahem:
$$ v = \lambda f = \frac{\omega}{k}.$$
Kromě frekvence, která popisuje, kolikrát se děj opakuje v čase, můžeme zavést její prostorový analog — vlnočet (značí se $ \tilde{\nu} $, někdy také $ \sigma $).
Vlnočet udává, kolik „vln“ (period) se vejde do jednotkové délky. Je definován jako:
$$ \tilde{\nu} = \frac{1}{\lambda}.$$
Zatímco vlnová délka $ \lambda $ říká, jak je vlna „dlouhá“, vlnočet říká, jak je „nahuštěná“ v prostoru.
Velmi úzce souvisí s vlnovým číslem $ k $, které jsme již zavedli:
$ k = 2\pi \tilde{\nu}. $
To znamená, že:
- vlnočet počítá počet vln na jednotku délky,
- vlnové číslo $k$ je totéž, ale v úhlové míře (v radiánech).
Nakonec $\varphi$ je fázový posun, který určuje počáteční stav vlny — tedy kde se vlna „nachází“ v čase (t = 0) a prostoru (x = 0).
Každý z těchto parametrů má jasný fyzikální význam a dohromady tvoří kompletní popis vlnového děje. Výběr konkrétního tvaru rovnice pak závisí na tom, zda chceme zdůraznit časové vlastnosti (frekvence, perioda), prostorové vlastnosti (vlnová délka), nebo samotné šíření vlny (rychlost).
Vlnová rovnice ve vícerozměrném světě
Doposud jsme popisovali vlnu jako funkci jedné prostorové souřadnice a času, tedy $y(x,t)$. Tento zápis je ale vhodný pouze pro jednoduché případy, například vlnění na provazu. Ve skutečnosti se většina dějů odehrává ve více rozměrech — zvuk, světlo nebo vlny na hladině se šíří ve dvou či třech rozměrech prostoru. Abychom takové situace mohli popsat, musíme rozšířit naši funkci na více prostorových proměnných:
$$ u(x,y,z,t). $$
Zároveň provedeme drobnou změnu v značení. Doposud jsme používali $y$ jako označení výchylky, což by nyní vedlo ke zmatku, protože $y$ chceme používat také jako prostorovou souřadnici. Proto budeme sledovanou veličinu označovat písmenem $u$.
Ani v tomto obecnějším případě se však nemění princip. Vlna je stále kombinací kmitání v čase a pravidelnosti v prostoru. Jen místo výrazu $kx$ musíme zohlednit celý prostor. To elegantně zapíšeme pomocí skalárního součinu:
$$ \mathbf{k} \cdot \mathbf{r}, $$
kde $\mathbf{r} = (x,y,z)$ je poloha v prostoru a $\mathbf{k}$ je vektor vlnového čísla, který určuje směr šíření vlny.
Obecný tvar harmonické vlny v prostoru pak můžeme zapsat jako:
$$ u(\mathbf{r}, t) = A \sin(\omega t - \mathbf{k} \cdot \mathbf{r} + \varphi). $$
Tato rovnice je přímým zobecněním předchozího jednorozměrného případu. Nezavádíme žádnou novou matematiku — pouze nahrazujeme jednu souřadnici celým prostorem.
Proč se v rovnici objevuje právě skalární součin $\mathbf{k} \cdot \mathbf{r}$? Co vlastně znamená?
Klíčová myšlenka je, že vlna se nešíří „ve všech směrech najednou stejně“, ale má konkrétní směr šíření. A nás zajímá, jak daleko jsme postoupili právě v tomto směru.
V jednorozměrném případě jsme psali $kx$, což vlastně znamená:
„jak daleko jsem podél osy $x$“
Ve více rozměrech už ale nemáme jednu osu, ale celý prostor. Potřebujeme tedy zjistit:
„jak daleko jsem ve směru, kterým se vlna šíří“
A přesně to dělá skalární součin:
$$ \mathbf{k} \cdot \mathbf{r}. $$
Ten totiž vybírá pouze tu část polohového vektoru $\mathbf{r}$, která leží ve směru vektoru $\mathbf{k}$. Jinými slovy:
- $\mathbf{k}$ určuje směr šíření vlny,
- $\mathbf{k} \cdot \mathbf{r}$ nám říká „efektivní vzdálenost“ v tomto směru.
Lépe to popíše animace.

Na obrázku vidíme harmonickou vlnu šířící se ve dvourozměrném prostoru. Barevné pruhy představují místa se stejnou hodnotou výchylky — tedy body, které kmitají ve stejné fázi. Tyto „vlnoplochy“ jsou zde rovinné (v 2D přímky) a postupně se posouvají prostorem.
Směr tohoto posunu je určen vektorem $\mathbf{k}$, který se nazývá vektor vlnového čísla. Tento vektor má dva důležité významy:
- jeho směr udává, kam se vlna šíří,
- jeho velikost určuje, jak rychle se vlna mění v prostoru (tedy jak hustě jsou vlny „nahuštěné“).
Z obrázku je také patrné, že samotné vlnoplochy jsou kolmé na vektor $\mathbf{k}$. To znamená, že vlna se nešíří „podél pruhů“, ale napříč nimi — ve směru kolmém na místa se stejnou fází.
Matematicky je tato vlna popsána výrazem:
$$ u(\mathbf{r}, t) = A \sin(\omega t - \mathbf{k} \cdot \mathbf{r}),$$
kde skalární součin $\mathbf{k} \cdot \mathbf{r}$ vyjadřuje, jak daleko jsme postoupili právě ve směru šíření vlny.
Celý obrázek tak krásně ilustruje klíčovou myšlenku: vlna není jen kmitání v čase, ale struktura, která se organizovaně posouvá prostorem — a směr i „hustotu“ této struktury určuje právě vektor $\mathbf{k}$.
Takovéto vlnění si můžeme představit například jako ideální model vln na moři. Pokud se podíváme na hladinu z větší vzdálenosti, často uvidíme přibližně rovnoběžné „hřebeny“ vln, které se posouvají jedním směrem. Právě tyto hřebeny odpovídají vlnoplochám — tedy místům se stejnou fází.
Je však důležité dodat, že reálné vlny na moři jsou mnohem složitější. Nejsou dokonale rovinné, skládají se z mnoha různých vln a jejich tvar se neustále mění vlivem větru, překážek a interakcí mezi jednotlivými vlnami. Rovinná vlna, kterou zde popisujeme, je tedy ideální zjednodušený model, který nám pomáhá pochopit základní principy šíření vlnění.
Popis kódu harmonické vlny ve 2D prostoru
1. Import knihoven
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
from IPython.display import Image
Na začátku importujeme potřebné knihovny.
numpypoužíváme pro numerické výpočty a práci s polimatplotlib.pyplotslouží k vykreslování grafůFuncAnimationumožňuje vytvářet animacePillowWriterslouží k uložení animace jako GIFImagezIPython.displayumožní GIF zobrazit přímo v notebooku
2. Definice parametrů vlny
A = 1.0
lam = 3.0
f = 0.5
Zde definujeme základní fyzikální parametry vlny.
Aje amplituda, tedy maximální výchylkalamje vlnová délka $\lambda$fje frekvence $f$, tedy počet kmitů za sekundu
Tyto tři veličiny určují základní chování vlny.
3. Výpočet odvozených parametrů
k_mag = 2 * np.pi / lam
omega = 2 * np.pi * f
Zadané parametry převedeme na veličiny, které se často používají přímo v rovnici harmonické vlny.
Vlnové číslo
$$ k = \frac{2\pi}{\lambda} $$
Proměnná k_mag představuje velikost vlnového čísla. Udává, jak rychle se vlna mění v prostoru.
Úhlová frekvence
$$ \omega = 2\pi f $$
Proměnná omega udává, jak rychle se vlna mění v čase.
4. Směr šíření vlny
theta = np.deg2rad(35)
k_hat = np.array([np.cos(theta), np.sin(theta)])
k_vec = k_mag * k_hat
V tomto kroku určujeme, kam se vlna bude šířit.
Nejprve zvolíme úhel:
theta = 35°
Funkce np.deg2rad(35) převede stupně na radiány, protože goniometrické funkce v Pythonu pracují právě s radiány.
Poté vytvoříme jednotkový vektor:
$$ \hat{\mathbf{k}} = (\cos\theta, \sin\theta) $$
Tento vektor má délku 1 a určuje pouze směr.
Nakonec jej vynásobíme velikostí vlnového čísla:
$$ \mathbf{k} = k \hat{\mathbf{k}} $$
Tím získáme skutečný vektor vlnového čísla k_vec, který obsahuje:
- směr šíření vlny
- i informaci o prostorové periodicitě
5. Vytvoření prostoru
x = np.linspace(-6, 6, 300)
y = np.linspace(-6, 6, 300)
X, Y = np.meshgrid(x, y)
Zde vytváříme dvourozměrný prostor, ve kterém budeme vlnu sledovat.
Osy
xobsahuje 300 bodů od $-6$ do $6$yobsahuje 300 bodů od $-6$ do $6$
Mřížka bodů
Funkce np.meshgrid(x, y) vytvoří dvě 2D pole:
Xobsahuje $x$-ové souřadnice všech bodůYobsahuje $y$-ové souřadnice všech bodů
Díky tomu můžeme v každém bodě roviny vypočítat hodnotu vlny.
6. Výpočet prostorové fáze
phase_space = k_vec[0] * X + k_vec[1] * Y
Tento řádek je matematicky nejdůležitější.
Počítá výraz
$$ \mathbf{k} \cdot \mathbf{r} $$
kde:
- $\mathbf{k} = (k_x, k_y)$
- $\mathbf{r} = (x, y)$
Po rozepsání dostaneme:
$$ \mathbf{k} \cdot \mathbf{r} = k_x x + k_y y$$
A právě to dělá tento kód:
k_vec[0] * Xodpovídá členu $k_x x$k_vec[1] * Yodpovídá členu $k_y y$
Výsledek phase_space tedy říká, jaká je prostorová fáze v každém bodě roviny.
To je klíčové, protože rovinná vlna v prostoru závisí právě na tom, jak daleko jsme postoupili ve směru šíření vlny, nikoli jen na samotné vzdálenosti od počátku.
7. Vytvoření obrázku
fig, ax = plt.subplots(figsize=(6.5, 6.5))
im = ax.imshow(
A * np.sin(-phase_space),
extent=[x.min(), x.max(), y.min(), y.max()],
origin="lower",
animated=True,
)
Zde vytváříme samotný graf.
fig, ax = plt.subplots(...)vytvoří plátno a osuimshow(...)zobrazí 2D pole hodnot jako barevný obrázek
Na začátku vykreslujeme výraz:
$$ u(\mathbf{r}, 0) = A \sin(-\mathbf{k}\cdot\mathbf{r}) $$
tedy počáteční stav v čase (t = 0).
Důležité parametry:
extent=...nastaví skutečné souřadnice osorigin="lower"zajistí, že počátek osy bude dole vlevoanimated=Trueumožní obrázek později měnit v animaci
8. Popisky os a název
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("Plane harmonic wave in 2D")
Tato část pouze popisuje obrázek:
- osu $x$
- osu $y$
- název grafu
9. Šipka určující směr šíření
arrow_start = (-4.8, -4.8)
arrow_dx = 2.5 * k_hat[0]
arrow_dy = 2.5 * k_hat[1]
ax.arrow(
arrow_start[0],
arrow_start[1],
arrow_dx,
arrow_dy,
length_includes_head=True,
head_width=0.25,
)
Zde přidáváme do obrázku šipku, která znázorňuje směr vektoru $\mathbf{k}$.
arrow_starturčuje, odkud šipka začínáarrow_dxaarrow_dyurčují její délku ve směru os $x$ a $y$
Používáme přitom jednotkový vektor k_hat, takže šipka ukazuje správný směr, ale její délku si volíme jen kvůli čitelnosti obrázku.
10. Označení vektoru $ \mathbf{k} $
ax.text(
arrow_start[0] + arrow_dx + 0.2,
arrow_start[1] + arrow_dy + 0.2,
"k",
)
Tento řádek přidá vedle šipky text "k", aby bylo jasné, že šipka představuje vektor vlnového čísla.
11. Text s časem a rovnicí
time_text = ax.text(
0.02,
0.98,
"",
transform=ax.transAxes,
va="top",
)
Zde vytváříme prázdný textový objekt, který budeme během animace průběžně aktualizovat.
Používáme souřadnice v relativním systému os:
0.02znamená 2 % od levého okraje0.98znamená 98 % od spodního okraje
Díky tomu text zůstává vždy ve stejném místě obrázku.
12. Stejné měřítko os
ax.set_aspect("equal")
Tento příkaz zajistí, že jednotka na ose $x$ bude stejně dlouhá jako jednotka na ose $y$.
To je důležité, protože jinak by se prostor deformoval a vlna by mohla vizuálně vypadat zkresleně.
13. Funkce pro aktualizaci snímku
def update(frame):
t = frame / 20.0
U = A * np.sin(omega * t - phase_space)
im.set_array(U)
time_text.set_text(f"u(r, t) = A sin(ωt - k·r)\nt = {t:.2f} s")
return im, time_text
Tato funkce je srdcem celé animace. Pro každý snímek spočítá nový stav vlny.
Převod čísla snímku na čas
t = frame / 20.0
Číslo snímku převedeme na fyzikální čas. Například:
frame = 0znamená $t = 0$frame = 20znamená $t = 1$
Výpočet vlny
U = A * np.sin(omega * t - phase_space)
Zde počítáme hodnotu rovinné harmonické vlny v každém bodě prostoru:
$$ u(\mathbf{r}, t) = A \sin(\omega t - \mathbf{k}\cdot\mathbf{r}) $$
To je přesně matematický model, který chceme vizualizovat.
Aktualizace obrázku
im.set_array(U)
Tím nahradíme staré hodnoty novými.
Aktualizace textu
time_text.set_text(...)
V levém horním rohu obrázku se průběžně zobrazuje rovnice a aktuální čas.
14. Vytvoření animace
ani = FuncAnimation(
fig,
update,
frames=80,
interval=60,
blit=True,
)
Zde říkáme matplotlibu, aby vytvořil animaci.
figje obrázek, který se má animovatupdateje funkce, která počítá jednotlivé snímkyframes=80znamená, že animace bude mít 80 snímkůinterval=60určuje prodlevu mezi snímky v milisekundáchblit=Truezrychluje vykreslování tím, že se překreslují jen změněné části
15. Uložení animace
gif_path = "plane_wave_2d.gif"
ani.save(gif_path, writer=PillowWriter(fps=20))
plt.close(fig)
Animaci uložíme do souboru plane_wave_2d.gif.
PillowWriter(fps=20)nastavuje rychlost přehrávání na 20 snímků za sekunduplt.close(fig)zavře obrázek, aby se zbytečně nezobrazoval dvakrát
16. Výstup a zobrazení
print(gif_path)
Image(filename=gif_path)
Nakonec:
- vypíšeme název souboru
- a zobrazíme GIF přímo v notebooku
Co když je realita složitější?
Ukázali jsme si jednoduchou harmonickou vlnu v prostoru. Bystrého čtenáře ale napadne, že svět určitě není takto ideálně uspořádaný. Když se podíváme třeba na hladinu moře, nějakou pravidelnost sice můžeme zahlédnout, ale celkový obraz je mnohem složitější — jednotlivé vlny se skládají, ovlivňují a výsledkem je spíše zdánlivě chaotický průběh.
Jak tedy takový reálný svět popsat? Jak zachytit složité děje pomocí matematiky? Jak asi tušíte, odpověď nebude na jednu větu ani na jeden odstavec.
Abychom si tento problém přiblížili, ponoříme se do světa zvuku, hudby a melodie. Pro jednoduchost si ale situaci trochu zidealizujeme. Představme si dvourozměrnou místnost, ve které máme dokonalý zdroj zvuku — generátor tónu. Ten bude z reproduktoru vysílat čistý tón o frekvenci 440 Hz. Tento tón je známý jako referenční tón, kterému se říká komorní A.
Fyzikálně to znamená, že membrána reproduktoru začne kmitat s frekvencí 440 kmitů za sekundu. Tím uvede do pohybu okolní vzduch a vznikne zvuková vlna, která se začne šířit prostorem. V každém bodě pak dochází k velmi malým změnám tlaku — střídají se oblasti zhuštění a zředění vzduchu.
Toto šíření zvukové vlny si můžeme znázornit například následující animací.

Když do prostoru umístíme mikrofon, například kamkoliv v blízkosti reproduktoru, můžeme začít měřit lokální změny tlaku vzduchu. Mikrofon funguje jako převodník — převádí mechanické kmitání (změny tlaku) na elektrický signál.
Tím vlastně provádíme důležitý krok: z prostorové vlny $u(\mathbf{r}, t)$ si vybereme jeden konkrétní bod $\mathbf{r}_0$ a sledujeme, co se v něm děje v čase:
$$u(t) = u(\mathbf{r}_0, t).$$
Jinými slovy, mikrofon „nevidí“ celou vlnu v prostoru, ale pouze její průběh v jednom místě. Výsledkem je časový signál, který reprezentuje změny tlaku v závislosti na čase.
Právě tento signál — funkce $$u(t)$$ — je to, s čím budeme dále pracovat.

Na obrázku vidíme časový záznam signálu v prvních 20 milisekundách. V tomto případě je jeho popis velmi jednoduchý. Průběh je harmonický — tedy ideální sinusovka — a pravidelně se opakuje.
Z grafu můžeme odečíst periodu, tedy dobu jednoho cyklu. Ta je přibližně $T \approx 2{,}27 ,\text{ms}$. Z periody pak snadno určíme frekvenci jako převrácenou hodnotu:
$$f = \frac{1}{T} = \frac{1}{0{,}00227} \approx 440 ,\text{Hz}.$$
To znamená, že signál odpovídá čistému tónu A. V tomto ideálním případě je tedy popis vlny triviální — stačí znát jedinou frekvenci a máme kompletní informaci o průběhu signálu.
To bylo jednoduché, teď si přehrajeme trochu složitější zvuk.
Mikrofón v místnosti by naměřil za ideálních podmínek tento průběh.

U čistého tónu byla situace jednoduchá. Signál měl sinusový průběh a jeho popis byl triviální — stačilo znát jedinou frekvenci.
Teď se ale díváme na něco úplně jiného. Akord A dur je složený z více tónů a jeho časový průběh už rozhodně nepřipomíná jednoduchou sinusovku. Křivka je složitější, nepravidelná a na první pohled z ní není vůbec jasné, co se vlastně děje.
Přirozeně tak vzniká otázka:
Jak takový signál popsat?
Jak z této křivky poznat, že obsahuje právě tyto konkrétní tóny? Jak zjistit, z jakých frekvencí se skládá?
Podobnou otázku si na začátku 19. století položil Joseph Fourier. Nezajímala ho hudba, ale šíření tepla. Zkoumal, jak se teplota mění v čase a prostoru, a dostával průběhy, které nebylo možné jednoduše popsat jednou rovnicí.
Právě proto jsme si v předchozím textu ukazovali změny teploty například na radiátoru — jde o stejný typ problému. Máme složitý průběh, který sice umíme změřit, ale neumíme ho snadno popsat.
Fourier tedy řešil v zásadě stejnou otázku jako my nyní:
Jak popsat složitý průběh pomocí jednodušších stavebních bloků?
Zkusme si tu otázku zjednodušit.
Představme si, že místo celého akordu máme jen dva čisté tóny. Například tón A (440 Hz) a k němu přidáme další tón.
Každý z těchto tónů by sám o sobě vytvořil jednoduchou sinusovku. Co se ale stane, když je zahrajeme současně?
Signály se jednoduše sečtou.

Na výsledném grafu vidíme, že součet dvou jednoduchých sinusovek vytvoří mnohem složitější průběh.
A teď přichází zásadní myšlenka:
Co když to funguje i opačně?
Co když každý složitý signál, na který se díváme, není nic jiného než součet mnoha jednoduchých sinusových funkcí?
Právě s touto myšlenkou přišel Fourier. Ukázal, že i velmi složité průběhy lze rozložit na součet jednoduchých harmonických složek.
Dobře, ale jak se takový rozklad provede prakticky? Jak z naměřeného průběhu získat jednotlivé sinusové složky?
Myšlenka je překvapivě jednoduchá. Vezmeme naměřený signál a postupně ho porovnáváme s harmonickými funkcemi různých frekvencí. Pro každou frekvenci zjišťujeme, jak moc se s daným signálem shoduje.
Pokud se testovaná sinusovka se signálem téměř „mine“, jejich příspěvky se při sčítání vyruší. Pokud ale daná frekvence v signálu skutečně je, začne se výsledek naopak zesilovat.
Tímto způsobem lze zjistit, které frekvence jsou v signálu obsaženy a jak silně jsou zastoupeny.
Pro náš akord A dur zkusíme následující postup. Budeme procházet frekvence od 200 Hz do 900 Hz s krokem 1 Hz. Pro každou z těchto frekvencí si vygenerujeme odpovídající sinusovou vlnu.
Tu pak v každém časovém okamžiku vynásobíme hodnotou našeho naměřeného signálu. Jinými slovy, porovnáváme dvě vlny bod po bodu. Tento postup provedeme pro celý časový záznam.
Následně všechny tyto součiny sečteme a výsledek vydělíme počtem bodů. Tím získáme číslo, které nám říká, jak dobře daná frekvence odpovídá našemu signálu.
Pokud testovaná frekvence v signálu není, kladné a záporné příspěvky se při sčítání navzájem vyruší a výsledek bude blízký nule. Pokud naopak frekvence odpovídá některé složce signálu, jednotlivé příspěvky se začnou sčítat a výsledná hodnota výrazně naroste.
V takovém případě dostaneme vysoké číslo a můžeme říct, že daná frekvence je v signálu obsažena.
Ukažme si tento princip na několika konkrétních frekvencích. Vybereme tři případy: jednu frekvenci, která v signálu vůbec není, jednu, která v něm je přesně, a jednu, která je jí blízká. Konkrétně zkusíme frekvence 220 Hz, 440 Hz a 550 Hz.
Začněme frekvencí 220 Hz. Do grafu vykreslíme náš signál a k němu přidáme sinusovku o této frekvenci. Zároveň si vybereme několik bodů, ve kterých budeme obě křivky porovnávat.


Z grafu vidíme, že se střídají kladné a záporné příspěvky. V některých bodech mají obě křivky stejná znaménka, jinde naopak opačná. Při sečtení se tyto příspěvky vzájemně vyruší a výsledná hodnota je velmi malá, blízká nule. To znamená, že frekvence 220 Hz v signálu prakticky není obsažena.
Teď zkusme totéž pro frekvenci 440 Hz.


Zde je situace zásadně odlišná. Obě vlny jsou ve velké části času „ve fázi“, tedy mají stejné znaménko. Jejich součiny jsou proto převážně kladné a při sčítání se navzájem posilují. Výsledkem je výrazně větší číslo. To je jasný signál, že tato frekvence je v našem signálu skutečně přítomná.
Nakonec se podívejme na frekvenci 550 Hz.


Tato frekvence už je blízká jedné ze složek signálu, ale nesedí přesně. V grafu proto vidíme, že se chvílemi vlny „potkávají“ a dávají kladné příspěvky, jindy se ale rozcházejí a příspěvky se částečně ruší. Celkový součet je tedy větší než u 220 Hz, ale menší než u 440 Hz.
To nám říká důležitou věc:
nejen že umíme poznat, zda je frekvence v signálu obsažena, ale dokážeme také rozlišit, jak blízko k ní jsme.
Předchozí příklad má ale jedno omezení. Porovnávali jsme pouze několik vybraných bodů, což může být zavádějící. Pokud bychom měli smůlu na výběr bodů, mohlo by se stát, že frekvence 550 Hz by „náhodou“ vyšla lépe než frekvence, která v signálu skutečně je.
V reálném světě proto postupujeme jinak. Mikrofon nám poskytuje velké množství vzorků — typicky desítky tisíc hodnot za sekundu. Pro každý z těchto bodů provedeme násobení s testovací sinusovkou a teprve potom všechny příspěvky sečteme.
Tímto způsobem se jednotlivé chyby „vyprůměrují“ a správné frekvence začnou jasně vystupovat, zatímco nesprávné se vyruší.
Pokud tento postup provedeme pro celé spektrum frekvencí, získáme graf, který ukazuje, jak silně je každá frekvence v signálu zastoupena.

Z grafu je patrné, že signál obsahuje složky v okolí 440 Hz, 555 Hz a 660 Hz. Přesněji řečeno jde o frekvence 440 Hz, 554,37 Hz a 659,25 Hz, které odpovídají tónům tvořícím akord A dur.
Vidíme tedy, že i když časový průběh signálu působil složitě a na první pohled nepřehledně, při pohledu do frekvenční oblasti se jeho struktura začne vyjasňovat. Místo jedné komplikované křivky najednou vidíme několik výrazných vrcholů, které odpovídají jednotlivým tónům obsaženým v signálu.
Fourierova transformace
Doposud jsme postupovali čistě intuitivně. Vzali jsme naměřený signál, vybrali testovací frekvenci, vygenerovali odpovídající sinusovku a obě funkce mezi sebou bod po bodu násobili. Nakonec jsme všechny tyto součiny sečetli.
To už samo o sobě skoro je matematický vzorec. Pokud máme naměřené hodnoty signálu
$$ u_0, u_1, u_2, \dots, u_{N-1}, $$
a k nim testovací sinusovku o frekvenci $f$, můžeme napsat
$$ S(f) = \frac{1}{N}\sum_{n=0}^{N-1} u_n \sin(2\pi f t_n).$$
Tento výraz říká, jak dobře testovaná frekvence odpovídá našemu signálu. Pokud v signálu daná frekvence není, kladné a záporné příspěvky se při sčítání vyruší a výsledek bude malý. Pokud tam naopak je, bude hodnota $S(f)$ výrazně větší.
Toto je ale zatím jen polovina příběhu. Problém je, že skutečný signál nemusí být vůči testovací sinusovce přesně „zarovnaný“. Může být fázově posunutý. Proto nestačí testovat pouze sinus.
Jak se tedy vypořádat s tím, že stejná frekvence může být v signálu přítomná v libovolné fázi?
Následně si ukažme stejný příklad znovu — tentokrát ale signál mírně upravíme. Jednotlivé tóny akordu nebudou začínat ve stejném okamžiku, ale budou vůči sobě fázově posunuté.
Na první pohled se tím změní průběh signálu v čase. Křivka bude vypadat jinak, i když frekvence, které ji tvoří, zůstávají stejné.

Pokud nyní použijeme náš předchozí postup a budeme testovat pouze sinusové funkce, zjistíme, že výsledky už nejsou tak jednoznačné. I frekvence, které jsou v signálu skutečně obsažené, mohou vycházet menší, než bychom očekávali.
V následujícím grafu jsem proto použil jednodušší příklad složený pouze ze dvou tónů: 440 Hz a 550 Hz. Druhý tón jsem navíc fázově posunul o
$$\frac{\pi}{2}.$$
Výsledek je překvapivý — i když frekvence 550 Hz v signálu skutečně je, při testování samotnou sinusovkou se v grafu prakticky neobjeví.
To ukazuje zásadní problém našeho dosavadního postupu. Nestačí se ptát jen na to, zda v signálu daná frekvence je, ale také musíme zohlednit, v jaké fázi se nachází.
A tím se dostáváme k důležité otázce:
Jak zachytit frekvenci v signálu nezávisle na tom, v jaké fázi se nachází?
Zkusme se na problém podívat jinak.
Doposud jsme testovali shodu signálu se sinusovkou jedné konkrétní „orientace“. Jenže sinusovku můžeme po ose času posouvat — tedy měnit její fázi.
Co kdybychom tedy nezkoušeli jen jednu konkrétní sinusovku, ale všechny její možné posuny?
Každou sinusovou vlnu můžeme posunout v čase, a tím získat celou rodinu funkcí, které mají stejnou frekvenci, ale liší se fází.
Místo jedné otázky:
„Je v signálu tato frekvence?“
tak pokládáme silnější otázku:
„Existuje nějaké fázové posunutí této frekvence, které se se signálem dobře shoduje?“
Ukazuje se, že není potřeba testovat všechny možné posuny zvlášť. Stačí vzít dvě speciální funkce:
- sinus
- kosinus
Tyto dvě funkce jsou vůči sobě posunuté právě o čtvrt periody. Dohromady tedy pokrývají všechny možné fáze.
Můžeme si to představit tak, že:
- sinus zachytí „jednu složku“ signálu
- kosinus zachytí „kolmou složku“
a teprve jejich kombinace nám dá úplnou informaci o dané frekvenci — nezávisle na fázi.
Proto pro každou frekvenci počítáme dvě hodnoty:
$$ S(f) = \frac{1}{N} \sum u_n \sin(2\pi f t_n), $$
$$ C(f) = \frac{1}{N} \sum u_n \cos(2\pi f t_n). $$
Přidali jsme tedy ještě druhý součin — tentokrát s kosinem. Postup je úplně stejný jako u sinu. Pro každou frekvenci tak získáme dvě čísla.
Jak z nich ale dostat jedno finální číslo, které bude reprezentovat amplitudu?
Mohli bychom je jednoduše sečíst, ale to by přineslo problém. Hodnoty ze sinu a kosinu mohou mít různá znaménka a při prostém sečtení by se mohly částečně nebo úplně vyrušit — i v případě, že je daná frekvence v signálu silně zastoupena.
Místo toho si můžeme obě hodnoty představit jako dvě na sebe kolmé složky. Sinus zachycuje jednu „projekci“ signálu, kosinus druhou. Společně tedy tvoří jakýsi bod v rovině.
A pokud chceme zjistit „celkovou velikost“ této frekvenční složky, musíme se na ně podívat jako na celek. Přirozeným způsobem, jak to udělat, je spočítat délku tohoto bodu:
$$ A(f) = \sqrt{S(f)^2 + C(f)^2}. $$
Tím získáme číslo, které už nezávisí na fázi a skutečně reprezentuje, jak silně je daná frekvence v signálu obsažena.
Dostali jsme se tedy k situaci, kdy pro každou frekvenci počítáme dvě hodnoty — jednu pomocí sinu a druhou pomocí kosinu — a z nich následně skládáme výslednou amplitudu.
To funguje, ale není to příliš elegantní. Pořád pracujeme se dvěma funkcemi, dvěma výpočty a jedním výsledkem.
Nabízí se tedy otázka:
Neexistuje způsob, jak to celé zapsat jedním výrazem?
Ukazuje se, že ano. Sinus a kosinus totiž nejsou dvě zcela nezávislé funkce. Ve skutečnosti jde o dvě projekce jedné a té samé rotace.
Tuto myšlenku lze zapsat pomocí komplexní exponenciály:
$$ e^{i\theta} = \cos\theta + i\sin\theta. $$
To znamená, že místo dvou funkcí můžeme použít jediný výraz, který v sobě obsahuje obě složky najednou.
Komplexní exponenciálu tady vysvětlovat momentálně nebudu a nechám si to na jiný článek. Necháme to tady jako dogma a vzorec. Ano, já vím, je to proti mojí filozofii, ale vysvětlení by nám zabralo velmi dlouho a myslím, že tento fakt můžeme prostě přijmout.
Pro každou frekvenci tedy získáváme dvě hodnoty — kosinusovou a sinusovou složku. Společně určují jak velikost, tak i fázi dané frekvence v signálu.
Místo toho, abychom s nimi pracovali odděleně, můžeme si je představit jako dvě složky jednoho bodu:
$$ (C(f), S(f)). $$
Tento bod můžeme zapsat jako jedno komplexní číslo:
$$ F(f) = C(f) - i S(f). $$
Za $C(f)$ a $S(f)$ dosadíme:
$$ F(f) = \frac{1}{N} \sum u_n \cos(2\pi f t_n) - i \frac{1}{N} \sum u_n \sin(2\pi f t_n) $$
Vytkneme sumu
$$ F(f) = \frac{1}{N} \sum u_n \left[ \cos(2\pi f t_n) - i\sin(2\pi f t_n) \right] .$$
Výraz v závorce můžeme nahradit a dostaneme:
$$ F(f) = \frac{1}{N} \sum_{n=0}^{N-1} u_n e^{-i 2\pi f t_n}. $$
Doposud jsme pracovali s diskrétními daty — tedy s hodnotami signálu v jednotlivých časových okamžicích. To odpovídá tomu, jak funguje reálné měření, například pomocí mikrofonu.
Z fyzikálního pohledu ale uvažujeme signál jako spojitou funkci času (u(t)).
Můžeme si představit, že náš časový interval rozdělíme na (N) malých částí o délce $\Delta t$. Náš součet pak můžeme zapsat ve tvaru:
$$ F(f) = \frac{1}{N} \sum_{n=0}^{N-1} u(t_n), e^{-i2\pi f t_n}.$$
Pokud nyní vezmeme limitu, kdy počet vzorků $N \to \infty$ a délka jednotlivých intervalů $\Delta t \to 0$, přechází tento součet v integrál:
$$ F(f) = \lim_{\Delta t \to 0} \sum u(t_n) e^{-i2\pi f t_n} \Delta t = \int u(t) e^{-i2\pi f t} dt.$$
A komu tím prospějete?

K čemu to vlastně je?
Možná vás při čtení napadla otázka: k čemu je to všechno dobré?
Fourierova transformace je jeden z nejpoužívanějších nástrojů moderní vědy a techniky. Objevuje se všude tam, kde pracujeme se signály, daty nebo vlněním.
Používá se například:
- při zpracování zvuku (komprese, filtrace, rozpoznávání řeči)
- při analýze obrazu (JPEG komprese, rozmazání, detekce hran)
- v medicíně (MRI, CT)
- v fyzice a inženýrství (analýza vibrací, signálů, spekter)
- v komunikacích (WiFi, mobilní sítě)
- v analytické chemii (spektroskopie, identifikace látek)
Ve všech těchto případech děláme v podstatě totéž:
převádíme složitý signál z časové (nebo prostorové) oblasti do oblasti frekvencí.
A právě ve frekvenční oblasti se často skrytá struktura dat ukáže mnohem jasněji.
Na závěr si ukážeme jednoduchý, ale velmi výmluvný experiment – jak Fourierova transformace funguje na reálném zvuku.
Na elektronickém pianu jsem nahrál jeden tón (C4) pomocí mikrofonu v programu Audacity. Už při pohledu na průběh signálu v čase je vidět důležitá věc: reálný zvuk není ideální sinusovka.
Na začátku tónu vzniká tzv. attack – krátká fáze, kdy kladívko udeří do struny (nebo v případě elektronického piana se simuluje náběh zvuku). V této části je signál výrazně „divoký“: obsahuje mnoho frekvencí a rychlé změny amplitudy. Takový úsek není vhodný pro klasickou Fourierovu transformaci, která předpokládá alespoň přibližně stacionární signál.
Na opačném konci signálu se zase projevuje decay – tón postupně doznívá a amplituda klesá. To samo o sobě není problém, ale pokud pokles probíhá příliš rychle, opět to zhoršuje kvalitu frekvenční analýzy.
Proto jsem z nahrávky vybral pouze takovou část, která splňuje dva klíčové požadavky:
- signál je dostatečně pravidelný (kvaziperiodický),
- amplituda se mění jen pomalu.
Tento kompromis je v praxi zásadní. Fourierova transformace totiž neanalyzuje „celý zvuk jako celek“, ale vždy konkrétní časový úsek, u kterého předpokládáme, že se jeho vlastnosti příliš nemění.
Výsledkem je segment signálu, který se sice stále liší od ideální sinusovky, ale už velmi dobře reprezentuje samotný tón. Právě na takovém úseku dává frekvenční rozklad smysl a můžeme z něj spolehlivě určit základní frekvenci i harmonické složky.
Tento krok – správný výběr části signálu – je v reálných aplikacích často důležitější než samotný výpočet Fourierovy transformace.

Zvuk jsem uložil ve formátu WAV, který nepoužívá žádnou kompresi. To znamená, že data nejsou nijak „zjednodušená“ ani ztrátová (jako například u MP3), ale obsahují přímo vzorky signálu. Díky tomu je tento formát velmi vhodný pro analýzu – Fourierova transformace pracuje přímo s hodnotami signálu, a čím věrnější data máme, tím přesnější je výsledek.
Při exportu jsem zvolil několik důležitých parametrů:
- Mono (jednokanálový zvuk)
Stereo nahrávka obsahuje dva kanály (levý a pravý), tedy dvě nezávislé časové řady. Pro náš experiment to nemá žádnou výhodu – analyzujeme jeden tón, který je v obou kanálech prakticky stejný. Mono tedy znamená jednodušší práci: místo dvou signálů máme jeden a vyhneme se nutnosti je kombinovat nebo řešit jejich rozdíly. - Sample rate 44100 Hz
Vzorkovací frekvence říká, kolikrát za sekundu měříme amplitudu signálu. Hodnota 44 100 Hz znamená, že máme 44 100 vzorků za sekundu. Podle Nyquistova teorému to umožňuje zachytit frekvence až do přibližně 22 kHz, což pokrývá celé slyšitelné spektrum člověka. Pro náš účel je to více než dostatečné a zároveň jde o standardní hodnotu, se kterou dobře pracují všechny nástroje. - Signed 16-bit PCM
Každý vzorek signálu je uložen jako celé číslo v rozsahu přibližně od −32 768 do 32 767. „Signed“ znamená, že hodnoty mohou být kladné i záporné (odpovídají výchylce signálu nahoru a dolů), a „16-bit“ určuje rozlišení amplitudy. Tento formát nabízí dobrý kompromis mezi přesností a velikostí souboru – je dostatečně jemný pro analýzu a přitom není zbytečně objemný. „PCM“ (Pulse Code Modulation) pak znamená, že jde o přímý, lineární zápis vzorků bez dalšího zpracování.
Tato kombinace (WAV + mono + 44.1 kHz + 16-bit PCM) je v praxi standardem pro základní zpracování zvuku a poskytuje čistý a spolehlivý vstup pro Fourierovu transformaci.
Teď si ukážeme krok po kroku jak se signálem pracovat a jak pomocí Fourierovy trasformace získat frekvenci(e) tónu.
Nejprve importujeme knihovny, které budeme potřebovat. numpy použijeme pro numerické výpočty, matplotlib pro vykreslení grafů a wavfile z knihovny SciPy pro načtení zvukového souboru ve formátu WAV.
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
V dalším kroku načteme soubor C_piano.wav. Funkce wavfile.read() vrací dvě hodnoty: vzorkovací frekvenci a samotná data signálu. V našem případě tedy získáme informaci, kolikrát za sekundu byl signál vzorkován, a zároveň pole amplitud uložených v souboru.
sample_rate, data = wavfile.read("C_piano.wav")
Pokud by byl soubor uložen jako stereo, měl by dva kanály — levý a pravý. Proto kontrolujeme počet dimenzí pole. Pokud má nahrávka dva kanály, zprůměrujeme je a vytvoříme z nich jeden společný signál. Tím získáme mono záznam, se kterým se bude pracovat jednodušeji.
if data.ndim == 2:
data = data.mean(axis=1)
Poté převedeme datový typ na float64. To je důležité, protože další výpočty — zejména násobení oknem a Fourierova transformace — chceme provádět nad reálnými čísly s dostatečnou přesností. Původní WAV soubor bývá často uložen jako celočíselné hodnoty.
data = data.astype(np.float64)
Abychom si ověřili, co jsme vlastně načetli, vytvoříme časovou osu. Pomocí np.arange(len(data)) vytvoříme posloupnost indexů jednotlivých vzorků a vydělením sample_rate je převedeme na čas v sekundách. Tím získáme pro každý vzorek jeho polohu na časové ose.
time = np.arange(len(data)) / sample_rate
Následující blok vykreslí celý zaznamenaný signál. Na vodorovné ose je čas, na svislé amplituda signálu. Tento graf nám pomůže vizuálně zkontrolovat, kde tón začíná, jak se vyvíjí a kde zhruba leží oblast vhodná pro další analýzu.
plt.figure(figsize=(14, 4))
plt.plot(time, data)
plt.title("Recorded piano signal")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude")
plt.grid(True)
plt.show()

Protože ruční výpočet diskrétní Fourierovy transformace je výpočetně náročný, nebudeme analyzovat celý signál, ale jen jeho kratší část. Zvolíme délku segmentu N = 2048 vzorků a vezmeme prvních 2048 hodnot z připraveného pole. Metoda .copy() zajistí, že budeme pracovat s vlastní kopií dat, ne jen s pohledem do původního pole.
N = 2048
segment = data[:N].copy()
Na vybraný segment aplikujeme Hannovo okno. To je velmi důležitý krok. Kdybychom signál prostě „usekli“ na začátku a na konci, vznikly by na okrajích umělé skoky, které by zhoršily výsledné spektrum. Hannovo okno amplitudu na krajích plynule zeslabí, a tím omezí tzv. spectral leakage.
window = np.hanning(N)
segment_windowed = segment * window
Poté si vykreslíme upravený segment. Na grafu je vidět, že amplituda na začátku i na konci klesá k nule. To není chyba, ale záměrný efekt okenní funkce.
plt.figure(figsize=(14, 4))
plt.plot(np.arange(N) / sample_rate, segment_windowed)
plt.title("Windowed segment")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude")
plt.grid(True)
plt.show()

Nyní přichází hlavní část: ruční implementace diskrétní Fourierovy transformace. Funkce dft_manual(x) vychází přímo z definice DFT. Pro každou výslednou frekvenční složku k procházíme všechny vzorky n v čase a sčítáme jejich příspěvky v komplexní exponenciální podobě.
def dft_manual(x):
x = np.asarray(x, dtype=np.complex128)
N = len(x)
X = np.zeros(N, dtype=np.complex128)
for k in range(N):
s = 0.0j
for n in range(N):
s += x[n] * np.exp(-2j * np.pi * k * n / N)
X[k] = s
return X
Na začátku funkce převedeme vstupní signál na komplexní pole. To je nutné, protože Fourierova transformace pracuje s komplexními čísly. Proměnná X bude obsahovat výsledné spektrum — tedy informaci o tom, jak silně jsou v signálu zastoupeny jednotlivé frekvence.
Vnější smyčka prochází jednotlivé frekvenční indexy k. Pro každý z nich se ve vnitřní smyčce sečtou příspěvky všech časových vzorků. Výraz
$$ e^{-2j\pi kn/N}$$
odpovídá komplexní sinusoidě dané frekvence. Fourierova transformace tedy v principu zjišťuje, jak dobře se signál „shoduje“ s jednotlivými sinusovkami různých frekvencí.
Tuto ruční implementaci pak skutečně použijeme na náš segment.
X_manual = dft_manual(segment_windowed)
Pro srovnání zároveň spočítáme i Fourierovu transformaci pomocí hotové funkce np.fft.fft(). Ta vrací matematicky stejný výsledek, ale používá rychlý algoritmus FFT, takže je nesrovnatelně efektivnější.
X_fft = np.fft.fft(segment_windowed)
Abychom mohli výsledek interpretovat fyzikálně, potřebujeme převést indexy spektra na skutečné frekvence v hertzech. Každý index k odpovídá frekvenci
$$ f_k = \frac{k \cdot f_s}{N} $$
kde (f_s) je vzorkovací frekvence a (N) délka analyzovaného segmentu.
freqs = np.arange(N) * sample_rate / N
half = N // 2
Proměnná half označuje polovinu délky spektra. U reálného signálu je totiž druhá polovina spektra zrcadlovým obrazem první, takže pro analýzu nám obvykle stačí jen kladné frekvence.
Protože Fourierova transformace vrací komplexní čísla, pro grafické zobrazení nás obvykle zajímá jejich velikost, tedy absolutní hodnota. Ta říká, jak silně je daná frekvence v signálu zastoupena.
magnitude_manual = np.abs(X_manual)
magnitude_fft = np.abs(X_fft)
Dále omezíme zobrazení jen na frekvence do 5000 Hz. Vyšší frekvence by v našem případě graf zbytečně rozšiřovaly, zatímco podstatné informace o základním tónu a prvních harmonických složkách leží mnohem níže.
max_freq = 5000
mask = (freqs >= 0) & (freqs <= max_freq)
Pak vykreslíme dvě spektra do jednoho grafu — ruční DFT a knihovní FFT. Pokud jsme vše implementovali správně, měly by obě křivky téměř přesně splývat.
plt.figure(figsize=(14, 5))
plt.plot(freqs[mask], magnitude_manual[mask], label="Manual DFT")
plt.plot(freqs[mask], magnitude_fft[mask], "--", label="NumPy FFT")
plt.title("Spectrum (0–5000 Hz)")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Magnitude")
plt.legend()
plt.grid(True)
plt.show()

Na výsledném grafu vidíme frekvenční spektrum nahraného tónu. Nejvyšší pík odpovídá základní frekvenci (tzv. fundamentu) – tedy frekvenci, kterou vnímáme jako samotnou výšku tónu (například C4). Kromě něj se ale v grafu objevují i další menší píky. Ty představují harmonické frekvence, tedy frekvence, které jsou celočíselnými násobky té základní:
$$f, 2f, 3f, 4f,…f,$$
Například pokud je základní frekvence přibližně 260 Hz, harmonické složky se objeví zhruba na 520 Hz, 780 Hz, 1040 Hz atd.
Tyto harmonické nevznikají náhodně. V případě klavíru jsou důsledkem fyziky struny: když struna kmitá, nekmitá jen „celá“, ale zároveň i po částech (polovina, třetina, čtvrtina délky atd.). Každý z těchto způsobů kmitání odpovídá jedné harmonické frekvenci. Výsledný zvuk je tedy ve skutečnosti superpozicí více sinusových vln různých frekvencí a amplitud.
Důležité je, že různé nástroje mají různé rozložení těchto harmonických. I když zahrají stejný tón (stejnou základní frekvenci), liší se v tom, jak silné jsou jednotlivé harmonické složky. Právě tento „otisk“ frekvenčního spektra nazýváme barva zvuku (timbre). Díky němu dokážeme rozeznat klavír od houslí nebo kytary, i když hrají stejný tón.
Fourierova transformace nám tedy neukazuje jen „jaký tón hrajeme“, ale odhaluje i jeho vnitřní strukturu – jak je složený z jednotlivých frekvenčních komponent. To je zásadní krok od jednoduchého vnímání zvuku k jeho hlubšímu fyzikálnímu pochopení.
Abychom dominantní frekvenci určili automaticky, najdeme index nejvyšší hodnoty v první polovině spektra a převedeme ho na frekvenci v hertzech.
peak_index = np.argmax(magnitude_manual[:half])
peak_frequency = freqs[peak_index]
print(f"Dominant frequency (manual DFT): {peak_frequency:.2f} Hz")
Tento výstup nám řekne, jaká frekvence v signálu dominuje. V našem experimentu vyšla hodnota přibližně 258,4 Hz, což velmi dobře odpovídá tónu C4, jehož teoretická frekvence je přibližně 261,63 Hz.
Na závěr ještě numericky ověříme, jak moc se ruční výpočet liší od knihovní FFT. Vypočítáme maximální absolutní rozdíl mezi oběma výsledky.
max_difference = np.max(np.abs(X_manual - X_fft))
print("Max absolute difference:", max_difference)
Pokud je tento rozdíl velmi malý, znamená to, že naše ruční implementace je správná. A právě to je hlavní smysl tohoto experimentu: ne jen použít hotovou funkci, ale pochopit, co Fourierova transformace skutečně dělá, a ověřit si to na reálném signálu.
Na výsledném grafu jsme tedy přešli od „slyšeného tónu“ k jeho fyzikálnímu rozkladu. Vidíme, že zvuk není jedna frekvence, ale struktura – součet mnoha složek, které mají přesný matematický vztah. Fourierova transformace nám v tomhle smyslu funguje jako lupa: umožňuje rozložit složitý signál na elementární stavební kameny.
Tím se ale dostáváme k mnohem hlubší myšlence. Harmonické frekvence nejsou jen vlastností zvuku – jsou důsledkem řešení fyzikálních rovnic, které popisují chování systému. Struna na klavíru, sloupec vzduchu v píšťale nebo membrána reproduktoru – všechny tyto systémy se řídí stejným typem rovnic, které připouštějí pouze určité „povolené“ režimy kmitání. A právě tyto režimy se v našem spektru objevují jako jednotlivé píky.
Fourierova transformace tedy není jen nástroj pro analýzu signálu. Je to most mezi:
- pozorováním (co slyšíme),
- matematikou (rozklad na sinusy),
- a fyzikou (jak systém skutečně kmitá).
Co nás čeká dál: od frekvencí k fyzice
To, co jsme si ukázali na jednom tónu, je jen začátek.
Ve skutečnosti se stejná myšlenka objevuje napříč celou fyzikou – vždy, když řešíme systém, který se mění v prostoru a čase. A právě tam vstupují do hry parciální diferenciální rovnice (PDE).
V dalších částech se podíváme na to, jak Fourierova transformace (a obecně rozklad na vlastní módy) pomáhá řešit:
- šíření tepla
Jak se teplo rozlévá v materiálu? Proč se nerovnosti vyhlazují? - proudění tekutin
Jak vznikají víry, turbulence a stabilní proudy? - elektromagnetické pole
Jak se šíří světlo? Proč existují vlny a jak souvisí s frekvencí?
Ve všech těchto případech budeme znovu a znovu dělat totéž:
rozložíme složitý problém na jednodušší „vlnové“ komponenty
a pochopíme chování systému skrze jeho základní módy
To, co začalo jedním tónem na pianu, nás tak dovede až k rovnicím, které popisují celý fyzikální svět.

