Operácie

Generátor harmonického signálu: Rozdiel medzi revíziami

Zo stránky SensorWiki

Balogh (diskusia | príspevky)
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]…“
 
StudentMIPS (diskusia | príspevky)
initial
Riadok 1: Riadok 1:
Záverečný projekt predmetu MIPS / LS2026 - '''Meno Priezvisko'''
Záverečný projekt predmetu MIPS / LS2026 - Meno Priezvisko




== Zadanie ==
== Zadanie ==


Sem príde text zadania, ak bolo len voľne formulované, rozpíšte ho podrobnejšie
Ú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:


[[Obrázok:ard.jpg|400px|thumb|center|Vývojová doska ACROB.]]
1 / ((s·T)^2 + 1)


'''Literatúra:'''
Zároveň je potrebné zmerať jeden bod frekvenčnej charakteristiky systému:
* [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]
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 ==


Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami...
== Analýza a opis riešenia ==
Podrobne opíšte použité komponenty (okrem základnej dosky s ATmega328P procesorom), pridajte linky na datasheety alebo opis obvodu.  
 
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


[[Súbor:GeminiAI-image3.jpg|400px|thumb|center|Celkový pohľad na zariadenie.]]
Tým sa meria odozva systému presne v tomto bode frekvenčnej charakteristiky.


Nezabudnite doplniť schému zapojenia! V texte by ste mali opísať základné veci zo zapojenia, samotná schéma nie je dostačujúci opis.
Porovnaním vstupu x a výstupu y_sys je možné určiť zosilnenie a fázový posun.


[[Súbor:GeminiAI-image2.jpg|400px|thumb|center|Schéma zapojenia.]]


=== Realizácia v programe ===


=== Algoritmus a program ===
Celý výpočet prebieha v prerušení Timer1 s frekvenciou 1 kHz:


Algoritmus programu využíva toto a toto, základné funkcie sú takéto a voláma ich tuto...
- výpočet oscilátora 
Výpis kódu je nižšie...
- 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 lang="c++" style="background: LightYellow;">
<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)
{
{
  unsigned int measuredValue;
    uart_init();
    stdout = &mystdout;
 
    pwm_init();
    timer1_init();
 
    float Ts = 1.0 / SAMPLE_RATE;
 
    alpha = Ts / (T + Ts);


  while (1)
    float theta = (1.0 / T) * (1.0 / SAMPLE_RATE);
  {
    /*  relax  */
  }


  return(0);
    y1 = 1.0;
}
    y2 = 1.0 - (theta * theta) / 2.0;


</syntaxhighlight ></tab>
    OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0);
<tab name="filename.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#include <avr/io.h>


void adc_init(void);                                   // A/D converter initialization
    sei();


unsigned int adc_read(char a_pin);
    while (1)
</syntaxhighlight ></tab>
    {
    }
}
</syntaxhighlight></tab>
</tabs>
</tabs>


Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':


Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]
=== Overenie ===


=== Overenie ===
Funkcia systému bola overená pomocou výpisu dát cez UART. Do sériového portu sa posielajú dvojice hodnôt:


Ako ste overili funkciu, napríklad... Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia.
x, y_sys
Na konci uvádzame fotku hotového zariadenia.


[[Súbor:GeminiAI-image1.jpg|400px|thumb|center|Aplikácia.]]
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.


'''Video:'''
Zo signálov je možné pozorovať zmenu amplitúdy a fázový posun, čo predstavuje bod frekvenčnej charakteristiky systému.
<center><youtube>D0UnqGm_miA</youtube></center>




== Čo by som urobil inak ==
== Čo by som urobil inak ==


Zamyslite sa spätne nad problémom, ktorý ste riešili a napíšte, čo sa vám nepodarilo a nabudúce by ste spravili 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.


Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.


[[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.