Generátor harmonického signálu: Rozdiel medzi revíziami
Zo stránky SensorWiki
Vytvorená stránka „Záverečný projekt predmetu MIPS / LS2026 - '''Meno Priezvisko''' == Zadanie == Sem príde text zadania, ak bolo len voľne formulované, rozpíšte ho podrobnejšie 400px|thumb|center|Vývojová doska ACROB. '''Literatúra:''' * [http://ap.urpi.fei.stuba.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob] * [http://www.humanbenchmark.com/tests/reactiontime/index.php Vyskúšajte si zmerať reakciu on-line]…“ |
initial |
||
| Riadok 1: | Riadok 1: | ||
Záverečný projekt predmetu MIPS / LS2026 - | Záverečný projekt predmetu MIPS / LS2026 - Meno Priezvisko | ||
== Zadanie == | == Zadanie == | ||
Úlohou je generovať harmonický signál bez použitia funkcií sin() alebo cos(). Namiesto toho sa má použiť oscilátor realizovaný ako prenosová funkcia: | |||
1 / ((s·T)^2 + 1) | |||
Zároveň je potrebné zmerať jeden bod frekvenčnej charakteristiky systému: | |||
1 / (s·T + 1) | |||
na frekvencii ω = 1 / T, pričom T = 0,5 s. | |||
Výstupný signál má mať tvar: | |||
A₀ + A₁·sin(ωt + φ) | |||
kde: | |||
A₀ = 128 | |||
A₁ = 100 | |||
__TOC__ | __TOC__ | ||
== Analýza a opis riešenia == | |||
Cieľom riešenia je vytvoriť sínusový signál bez použitia matematických funkcií sin() alebo cos(). Tento problém sa rieši pomocou diskrétneho oscilátora, ktorý vychádza z diferenciálnej rovnice harmonického kmitania. | |||
Základom je rovnica: | |||
y'' + ω²y = 0 | |||
Táto rovnica popisuje harmonické kmity (napr. pružina alebo LC obvod) a jej riešením sú funkcie sin() a cos(). To znamená, že ak vieme túto rovnicu numericky riešiť, vieme generovať sínus bez použitia knižničných funkcií. | |||
=== Diskretizácia === | |||
Mikrokontrolér pracuje v diskrétnom čase, preto je potrebné nahradiť derivácie rozdielmi medzi vzorkami (metóda konečných diferencí). | |||
Použije sa aproximácia druhej derivácie: | |||
y'' ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s² | |||
Po dosadení do diferenciálnej rovnice dostaneme: | |||
y[n] = (2 / (1 + ω²T_s²))·y[n−1] − (1 / (1 + ω²T_s²))·y[n−2] | |||
Táto rovnica predstavuje numerickú aproximáciu oscilátora. V praxi však nie je ideálna, pretože amplitúda signálu sa môže časom meniť. | |||
=== Diskrétny oscilátor === | |||
Na generovanie stabilného sínusu sa použije presný diskrétny model založený na trigonometrickej identite: | |||
sin(nθ) = 2cos(θ)·sin((n−1)θ) − sin((n−2)θ) | |||
Po označení: | |||
y[n] = sin(nθ) | |||
dostaneme rekurentný vzťah: | |||
y[n] = 2cos(θ)·y[n−1] − y[n−2] | |||
Tento vzťah generuje stabilný sínusový signál bez zmeny amplitúdy. | |||
=== Výpočet parametrov === | |||
Platí: | |||
θ = ω·T_s | |||
kde: | |||
T = 0,5 s | |||
ω = 1 / T = 2 rad/s | |||
SAMPLE_RATE = 1000 Hz → T_s = 0,001 s | |||
θ = 2 · 0,001 = 0,002 | |||
=== Aproximácia cos() === | |||
Keďže nie je dovolené použiť funkciu cos(), použije sa aproximácia (Taylorov rozvoj): | |||
cos(θ) ≈ 1 − θ²/2 | |||
Z toho: | |||
2cos(θ) ≈ 2·(1 − θ²/2) | |||
Tento výraz sa použije ako koeficient oscilátora v programe. | |||
=== Inicializácia oscilátora === | |||
Pre správnu činnosť oscilátora sú potrebné počiatočné hodnoty: | |||
y1 = 1 | |||
y2 = 1 − θ²/2 | |||
Tieto hodnoty zabezpečia vznik sínusového priebehu. | |||
=== Generovanie signálu === | |||
Oscilátor generuje hodnoty v rozsahu ⟨−1, 1⟩. | |||
Požadovaný výstup je: | |||
A₀ + A₁·sin(...) | |||
Preto sa signál upraví: | |||
x = A0 + A1 · y | |||
kde: | |||
A0 = 128 | |||
A1 = 100 | |||
Tým sa signál posunie do kladného rozsahu vhodného pre PWM. | |||
=== Systém 1 / (sT + 1) === | |||
Systém je realizovaný ako filter prvého rádu: | |||
T·dy/dt + y = x | |||
Po diskretizácii (dopredná Eulerova metóda) dostaneme: | |||
y_sys[n] = y_sys[n−1] + α·(x − y_sys[n−1]) | |||
kde: | |||
α = T_s / (T + T_s) | |||
Pre dané hodnoty: | |||
α ≈ 0,001996 | |||
=== Meranie frekvenčnej charakteristiky === | |||
Na vstup systému je privádzaný sínusový signál s frekvenciou: | |||
ω = 1 / T | |||
Tým sa meria odozva systému presne v tomto bode frekvenčnej charakteristiky. | |||
Porovnaním vstupu x a výstupu y_sys je možné určiť zosilnenie a fázový posun. | |||
=== Realizácia v programe === | |||
Celý výpočet prebieha v prerušení Timer1 s frekvenciou 1 kHz: | |||
- výpočet oscilátora | |||
- generovanie vstupu x | |||
- výpočet výstupu systému | |||
- výstup cez PWM | |||
- odoslanie dát cez UART | |||
<tabs> | <tabs> | ||
<tab name="AVR C-code"><syntaxhighlight | <tab name="AVR C-code"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
#define F_CPU 16000000UL | |||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <avr/interrupt.h> | |||
#include <stdio.h> | |||
#include "uart.h" | |||
#define SAMPLE_RATE 1000.0 | |||
#define T 0.5 | |||
#define A0 128 | |||
#define A1 100 | |||
float OSC_COEFF; | |||
volatile float y = 0; | |||
volatile float y1 = 0; | |||
volatile float y2 = 0; | |||
volatile float y_sys = 0; | |||
float alpha; | |||
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE); | |||
ISR(TIMER1_COMPA_vect) | |||
{ | |||
y = OSC_COEFF * y1 - y2; | |||
y2 = y1; | |||
y1 = y; | |||
float x = A0 + A1 * y; | |||
y_sys = y_sys + alpha * (x - y_sys); | |||
OCR0A = (uint8_t)(y_sys); | |||
printf("%d,%d\n", (int)x, (int)y_sys); | |||
} | |||
void timer1_init() | |||
{ | |||
TCCR1B |= (1 << WGM12); | |||
OCR1A = 15999; | |||
TCCR1B |= (1 << CS10); | |||
TIMSK1 |= (1 << OCIE1A); | |||
} | |||
void pwm_init() | |||
{ | |||
DDRD |= (1 << PD6); | |||
TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); | |||
TCCR0B |= (1 << CS01); | |||
} | |||
int main(void) | int main(void) | ||
{ | { | ||
uart_init(); | |||
stdout = &mystdout; | |||
pwm_init(); | |||
timer1_init(); | |||
float Ts = 1.0 / SAMPLE_RATE; | |||
alpha = Ts / (T + Ts); | |||
float theta = (1.0 / T) * (1.0 / SAMPLE_RATE); | |||
y1 = 1.0; | |||
y2 = 1.0 - (theta * theta) / 2.0; | |||
OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0); | |||
sei(); | |||
while (1) | |||
</syntaxhighlight ></tab> | { | ||
} | |||
} | |||
</syntaxhighlight></tab> | |||
</tabs> | </tabs> | ||
=== Overenie === | |||
Funkcia systému bola overená pomocou výpisu dát cez UART. Do sériového portu sa posielajú dvojice hodnôt: | |||
x, y_sys | |||
Tieto hodnoty je možné zobraziť napríklad pomocou Serial Plotteru, kde je viditeľný vstupný sínusový signál a výstup systému. | |||
Zo signálov je možné pozorovať zmenu amplitúdy a fázový posun, čo predstavuje bod frekvenčnej charakteristiky systému. | |||
== Čo by som urobil inak == | == Čo by som urobil inak == | ||
Pri riešení by bolo možné použiť presnejšiu metódu diskretizácie systému 1/(sT + 1), napríklad bilineárnu transformáciu, ktorá by zlepšila presnosť modelu. | |||
Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximácie, napríklad pomocou lookup tabuľky. | |||
Ďalším zlepšením by mohlo byť automatické vyhodnotenie amplitúdy a fázového posunu priamo v mikrokontroléri namiesto spracovania na PC. | |||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] | ||
Verzia z 19:03, 17. apríl 2026
Záverečný projekt predmetu MIPS / LS2026 - Meno Priezvisko
Zadanie
Úlohou je generovať harmonický signál bez použitia funkcií sin() alebo cos(). Namiesto toho sa má použiť oscilátor realizovaný ako prenosová funkcia:
1 / ((s·T)^2 + 1)
Zároveň je potrebné zmerať jeden bod frekvenčnej charakteristiky systému:
1 / (s·T + 1)
na frekvencii ω = 1 / T, pričom T = 0,5 s.
Výstupný signál má mať tvar:
A₀ + A₁·sin(ωt + φ)
kde: A₀ = 128 A₁ = 100
Analýza a opis riešenia
Cieľom riešenia je vytvoriť sínusový signál bez použitia matematických funkcií sin() alebo cos(). Tento problém sa rieši pomocou diskrétneho oscilátora, ktorý vychádza z diferenciálnej rovnice harmonického kmitania.
Základom je rovnica:
y + ω²y = 0
Táto rovnica popisuje harmonické kmity (napr. pružina alebo LC obvod) a jej riešením sú funkcie sin() a cos(). To znamená, že ak vieme túto rovnicu numericky riešiť, vieme generovať sínus bez použitia knižničných funkcií.
Diskretizácia
Mikrokontrolér pracuje v diskrétnom čase, preto je potrebné nahradiť derivácie rozdielmi medzi vzorkami (metóda konečných diferencí).
Použije sa aproximácia druhej derivácie:
y ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²
Po dosadení do diferenciálnej rovnice dostaneme:
y[n] = (2 / (1 + ω²T_s²))·y[n−1] − (1 / (1 + ω²T_s²))·y[n−2]
Táto rovnica predstavuje numerickú aproximáciu oscilátora. V praxi však nie je ideálna, pretože amplitúda signálu sa môže časom meniť.
Diskrétny oscilátor
Na generovanie stabilného sínusu sa použije presný diskrétny model založený na trigonometrickej identite:
sin(nθ) = 2cos(θ)·sin((n−1)θ) − sin((n−2)θ)
Po označení:
y[n] = sin(nθ)
dostaneme rekurentný vzťah:
y[n] = 2cos(θ)·y[n−1] − y[n−2]
Tento vzťah generuje stabilný sínusový signál bez zmeny amplitúdy.
Výpočet parametrov
Platí:
θ = ω·T_s
kde: T = 0,5 s ω = 1 / T = 2 rad/s SAMPLE_RATE = 1000 Hz → T_s = 0,001 s
θ = 2 · 0,001 = 0,002
Aproximácia cos()
Keďže nie je dovolené použiť funkciu cos(), použije sa aproximácia (Taylorov rozvoj):
cos(θ) ≈ 1 − θ²/2
Z toho:
2cos(θ) ≈ 2·(1 − θ²/2)
Tento výraz sa použije ako koeficient oscilátora v programe.
Inicializácia oscilátora
Pre správnu činnosť oscilátora sú potrebné počiatočné hodnoty:
y1 = 1 y2 = 1 − θ²/2
Tieto hodnoty zabezpečia vznik sínusového priebehu.
Generovanie signálu
Oscilátor generuje hodnoty v rozsahu ⟨−1, 1⟩.
Požadovaný výstup je:
A₀ + A₁·sin(...)
Preto sa signál upraví:
x = A0 + A1 · y
kde: A0 = 128 A1 = 100
Tým sa signál posunie do kladného rozsahu vhodného pre PWM.
Systém 1 / (sT + 1)
Systém je realizovaný ako filter prvého rádu:
T·dy/dt + y = x
Po diskretizácii (dopredná Eulerova metóda) dostaneme:
y_sys[n] = y_sys[n−1] + α·(x − y_sys[n−1])
kde:
α = T_s / (T + T_s)
Pre dané hodnoty:
α ≈ 0,001996
Meranie frekvenčnej charakteristiky
Na vstup systému je privádzaný sínusový signál s frekvenciou:
ω = 1 / T
Tým sa meria odozva systému presne v tomto bode frekvenčnej charakteristiky.
Porovnaním vstupu x a výstupu y_sys je možné určiť zosilnenie a fázový posun.
Realizácia v programe
Celý výpočet prebieha v prerušení Timer1 s frekvenciou 1 kHz:
- výpočet oscilátora - generovanie vstupu x - výpočet výstupu systému - výstup cez PWM - odoslanie dát cez UART
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "uart.h"
#define SAMPLE_RATE 1000.0
#define T 0.5
#define A0 128
#define A1 100
float OSC_COEFF;
volatile float y = 0;
volatile float y1 = 0;
volatile float y2 = 0;
volatile float y_sys = 0;
float alpha;
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
ISR(TIMER1_COMPA_vect)
{
y = OSC_COEFF * y1 - y2;
y2 = y1;
y1 = y;
float x = A0 + A1 * y;
y_sys = y_sys + alpha * (x - y_sys);
OCR0A = (uint8_t)(y_sys);
printf("%d,%d\n", (int)x, (int)y_sys);
}
void timer1_init()
{
TCCR1B |= (1 << WGM12);
OCR1A = 15999;
TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
}
void pwm_init()
{
DDRD |= (1 << PD6);
TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
TCCR0B |= (1 << CS01);
}
int main(void)
{
uart_init();
stdout = &mystdout;
pwm_init();
timer1_init();
float Ts = 1.0 / SAMPLE_RATE;
alpha = Ts / (T + Ts);
float theta = (1.0 / T) * (1.0 / SAMPLE_RATE);
y1 = 1.0;
y2 = 1.0 - (theta * theta) / 2.0;
OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0);
sei();
while (1)
{
}
}
Overenie
Funkcia systému bola overená pomocou výpisu dát cez UART. Do sériového portu sa posielajú dvojice hodnôt:
x, y_sys
Tieto hodnoty je možné zobraziť napríklad pomocou Serial Plotteru, kde je viditeľný vstupný sínusový signál a výstup systému.
Zo signálov je možné pozorovať zmenu amplitúdy a fázový posun, čo predstavuje bod frekvenčnej charakteristiky systému.
Čo by som urobil inak
Pri riešení by bolo možné použiť presnejšiu metódu diskretizácie systému 1/(sT + 1), napríklad bilineárnu transformáciu, ktorá by zlepšila presnosť modelu.
Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximácie, napríklad pomocou lookup tabuľky.
Ďalším zlepšením by mohlo byť automatické vyhodnotenie amplitúdy a fázového posunu priamo v mikrokontroléri namiesto spracovania na PC.