Operácie

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

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
slight fixes of formatting
StudentMIPS (diskusia | príspevky)
d formatting update
Riadok 1: Riadok 1:
Záverečný projekt predmetu MIPS / LS2026 - '''Oleksandr Mykyta'''
Záverečný projekt predmetu MIPS / LS2026 - '''Oleksandr Mykyta'''


== Zadanie ==
== Zadanie ==
Riadok 19: Riadok 18:


kde:
kde:
A₀ = 128
A₀ = 128
A₁ = 100
A₁ = 100
 
 
__TOC__


**TOC**


== Analýza  a opis riešenia ==
== Analýza  a opis riešenia ==
Riadok 32: Riadok 29:
Základom je rovnica:
Základom je rovnica:


y\'\' + ω²y = 0
y'' + ω²y = 0
 
Táto rovnica popisuje harmonické kmity (napr. pružina) a jej riešením sú funkcie sin() a cos(). To znamená, že ak vieme túto rovnicu numericky riešiť, vieme generovať sinus.


Táto rovnica popisuje harmonické kmity (napr. pružina) 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.


=== Teoretický základ a odvodenia ===
=== Teoretický základ a odvodenia ===
Riadok 47: Riadok 43:
Po úprave:
Po úprave:


Y(s) · (T · s + 1) = X(s)
Y(s) · (T · s + 1) = X(s)
T · s · Y(s) + Y(s) = X(s)
T · s · Y(s) + Y(s) = X(s)


Riadok 55: Riadok 51:


Týmto získame diferenciálnu rovnicu systému v časovej oblasti.
Týmto získame diferenciálnu rovnicu systému v časovej oblasti.


==== Diskretizácia ====
==== Diskretizácia ====
Riadok 63: Riadok 58:
Pre druhú deriváciu použijeme aproximáciu:
Pre druhú deriváciu použijeme aproximáciu:


y\'\' ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²
y'' ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²


Po dosadení do (y\'\' + ω²y = 0):
Po dosadení do (y'' + ω²y = 0):


y[n] = (2 / (1 + ω²T_s²)) · y[n−1] − (1 / (1 + ω²T_s²)) · y[n−2]
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, ale nie je ideálna z hľadiska stability amplitúdy.
Táto rovnica predstavuje numerickú aproximáciu oscilátora, ale nie je ideálna z hľadiska stability amplitúdy.


==== Diskrétny oscilátor (presný model) ====
==== Diskrétny oscilátor (presný model) ====
Riadok 76: Riadok 70:
Presnejší prístup vychádza z trigonometrických identít:
Presnejší prístup vychádza z trigonometrických identít:


sin(A + B) = sin(A)cos(B) + cos(A)sin(B)
sin(A + B) = sin(A)cos(B) + cos(A)sin(B)
sin(A − B) = sin(A)cos(B) − cos(A)sin(B)
sin(A − B) = sin(A)cos(B) − cos(A)sin(B)


Riadok 85: Riadok 79:
Dosadením:
Dosadením:


A = (n−1)θ
A = (n−1)θ
B = θ
B = θ


Riadok 101: Riadok 95:


Tento vzťah generuje stabilný sínusový signál bez zmeny amplitúdy.
Tento vzťah generuje stabilný sínusový signál bez zmeny amplitúdy.


==== Výpočet parametrov ====
==== Výpočet parametrov ====
Riadok 110: Riadok 103:


kde:
kde:
T = 0,5 s
T = 0,5 s
ω = 1 / T = 2 rad/s
ω = 1 / T = 2 rad/s
SAMPLE_RATE = 1000 Hz → T_s = 0,001 s
SAMPLE_RATE = 1000 Hz → T_s = 0,001 s
 
θ = 0,002 


θ = 0,002


==== Aproximacia cos() ====
==== Aproximacia cos() ====
Riadok 128: Riadok 120:


2cos(θ) ≈ 2 · (1 − θ²/2)
2cos(θ) ≈ 2 · (1 − θ²/2)


==== Inicializácia oscilátora ====
==== Inicializácia oscilátora ====
Riadok 134: Riadok 125:
Pre správnu činnosť oscilátora sú potrebné počiatočné hodnoty:
Pre správnu činnosť oscilátora sú potrebné počiatočné hodnoty:


y1 = 1
y1 = 1
y2 = 1 − θ²/2
y2 = 1 − θ²/2


Tieto hodnoty zabezpečia vznik sínusového priebehu.
Tieto hodnoty zabezpečia vznik sínusového priebehu.


==== Generovanie signálu ====
==== Generovanie signálu ====
Riadok 149: Riadok 139:


kde:
kde:
A0 = 128
A0 = 128
A1 = 100
A1 = 100


Tým sa signál posunie do kladného rozsahu vhodného pre PWM.
Tým sa signál posunie do kladného rozsahu vhodného pre PWM.


==== Diskretizacia systému 1 / (sT + 1) ====
==== Diskretizacia systému 1 / (sT + 1) ====
Riadok 167: Riadok 156:
Po úprave:
Po úprave:


y[n] = x - (T / T_s) · y[n] − (T / T_s) · y[n−1]
y[n] = x (T / T_s) · y[n] − (T / T_s) · y[n−1]
y[n] · (1 + (T / T_s)) = x − (T / T_s) · y[n−1]
y[n] · (1 + (T / T_s)) = x − (T / T_s) · y[n−1]
y[n] = (T_s / (T + T_s)) · x + (T / (T + T_s)) · y[n−1]
y[n] = (T_s / (T + T_s)) · x + (T / (T + T_s)) · y[n−1]
Riadok 177: Riadok 166:
dostaneme praktický tvar:
dostaneme praktický tvar:


y[n] = α · x + (1 - α) · y[n−1]
y[n] = α · x + (1 α) · y[n−1]
y[n] = y[n−1] + α · (x − y[n−1])
y[n] = y[n−1] + α · (x − y[n−1])


=== Algoritmus a program ===
=== Algoritmus a program ===


Celý výpočet prebieha v prerušení Timer1 s frekvenciou 1 kHz:
Algoritmus programu využíva diskrétny oscilátor a numerickú aproximáciu systému 1 / (sT + 1). Základné výpočty prebiehajú 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 
- odosielanie dát cez UART 


* výpočet oscilátora
* generovanie vstupu x
* výpočet výstupu systému
* výstup cez PWM
* odosielanie dát cez UART


<tabs>
<tabs>
Riadok 221: Riadok 208:
ISR(TIMER1_COMPA_vect)
ISR(TIMER1_COMPA_vect)
{
{
    y = OSC_COEFF * y1 - y2;
y = OSC_COEFF * y1 - y2;


    y2 = y1;
```
    y1 = y;
y2 = y1;
y1 = y;


    float x = A0 + A1 * y;
float x = A0 + A1 * y;


    y_sys = y_sys + alpha * (x - y_sys);
y_sys = y_sys + alpha * (x - y_sys);


    OCR0A = (uint8_t)(y_sys);
OCR0A = (uint8_t)(y_sys);
 
printf("%d,%d\n", (int)x, (int)y_sys);
```


    printf("%d,%d\n", (int)x, (int)y_sys);
}
}


void timer1_init()
void timer1_init()
{
{
    TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << WGM12);
 
```
OCR1A = 15999;


    OCR1A = 15999;
TCCR1B |= (1 << CS10);


    TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
```


    TIMSK1 |= (1 << OCIE1A);
}
}


void pwm_init()
void pwm_init()
{
{
    DDRD |= (1 << PD6);
DDRD |= (1 << PD6);
 
```
TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
TCCR0B |= (1 << CS01);
```


    TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
    TCCR0B |= (1 << CS01);
}
}


int main(void)
int main(void)
{
{
    uart_init();
uart_init();
    stdout = &mystdout;
stdout = &mystdout;


    pwm_init();
```
    timer1_init();
pwm_init();
timer1_init();


    float Ts = 1.0 / SAMPLE_RATE;
float Ts = 1.0 / SAMPLE_RATE;


    alpha = Ts / (T + Ts);
alpha = Ts / (T + Ts);


    float theta = (1.0 / T) * (1.0 / SAMPLE_RATE);
float theta = (1.0 / T) * (1.0 / SAMPLE_RATE);


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


    OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0);
OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0);


    sei();
sei();


    while (1)
while (1)
    {
{
    }
}
}
</syntaxhighlight></tab>
```
</tabs>
 
} </syntaxhighlight></tab> </tabs>


=== Overenie ===
=== Overenie ===
Riadok 291: Riadok 288:


Zo signálov je možné pozorovať zmenu amplitúdy a fázový posun, čo predstavuje bod frekvenčnej charakteristiky 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 diskretizacie systému 1/(sT + 1), napríklad bilineárnu transformaciu, ktorá by zlepšila presnosť modelu.
Pri riešení by bolo možné použiť presnejšiu metódu diskretizacie systému 1 / (sT + 1), napríklad bilineárnu transformaciu, ktorá by zlepšila presnosť modelu.


Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximacie, napríklad pomocou lookup tabuľky.
Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximacie, 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 mikrokontroleri namiesto spracovania na PC.
Ďalším zlepšením by mohlo byť automatické vyhodnotenie amplitúdy a fázového posunu priamo v mikrokontroleri namiesto spracovania na PC.


[[Category:AVR]] [[Category:MIPS]]
[[Category:AVR]] [[Category:MIPS]]

Verzia z 12:54, 18. apríl 2026

Záverečný projekt predmetu MIPS / LS2026 - Oleksandr Mykyta

Zadanie

Úlohou bolo generovať harmonický signál bez použitia funkcií sin() alebo cos(). Na tento účel bol použitý oscilátor realizovaný ako prenosová funkcia:

H(s) = 1 / ((s · T)^2 + 1)

Zároveň bolo potrebné zmerať jeden bod frekvenčnej charakteristiky systému:

H(s) = 1 / (s · T + 1)

pre frekvenciu ω = 1 / T, kde T = 0,5 s.

Výstupný signál má mať tvar:

A₀ + A₁ · sin(ωt + φ)

kde: A₀ = 128 A₁ = 100

    • 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) 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.

Teoretický základ a odvodenia

Laplaceova transformacia

Vychadzajme z prenosovej funkcie systému:

H(s) = Y(s) / X(s) = 1 / (T · s + 1)

Po úprave:

Y(s) · (T · s + 1) = X(s) T · s · Y(s) + Y(s) = X(s)

Použitím inverznej Laplaceovej transformacie (kde s predstavuje deriváciu) dostaneme:

T · dy(t)/dt + y(t) = x(t)

Týmto získame diferenciálnu rovnicu systému v časovej oblasti.

Diskretizácia

Mikrokontrolér pracuje v diskrétnom čase, preto je potrebné nahradiť derivácie rozdielmi medzi vzorkami.

Pre druhú deriváciu použijeme aproximáciu:

y ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²

Po dosadení do (y + ω²y = 0):

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, ale nie je ideálna z hľadiska stability amplitúdy.

Diskrétny oscilátor (presný model)

Presnejší prístup vychádza z trigonometrických identít:

sin(A + B) = sin(A)cos(B) + cos(A)sin(B) sin(A − B) = sin(A)cos(B) − cos(A)sin(B)

Po sčítaní:

sin(A + B) + sin(A − B) = 2 · sin(A) · cos(B)

Dosadením:

A = (n−1)θ B = θ

dostaneme:

sin(nθ) + sin((n−2)θ) = 2 · cos(θ) · sin((n−1)θ)

Označením:

y[n] = sin(nθ)

vznikne rekurentný vzťah:

y[n] = 2 · cos(θ) · 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

θ = 0,002

Aproximacia cos()

Keďže nie je dovolené použiť funkciu cos(), použije sa Taylorov rozvoj:

cos(θ) ≈ 1 − θ²/2

Pre malé θ je táto aproximacia dostatočne presná.

Z toho:

2cos(θ) ≈ 2 · (1 − θ²/2)

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:

x = A0 + A1 · y

kde: A0 = 128 A1 = 100

Tým sa signál posunie do kladného rozsahu vhodného pre PWM.

Diskretizacia systému 1 / (sT + 1)

Zo spojitej rovnice:

T · dy/dt + y = x

Použitím Eulerovej metódy:

dy/dt ≈ (y[n] − y[n−1]) / T_s

Po úprave:

y[n] = x − (T / T_s) · y[n] − (T / T_s) · y[n−1] y[n] · (1 + (T / T_s)) = x − (T / T_s) · y[n−1] y[n] = (T_s / (T + T_s)) · x + (T / (T + T_s)) · y[n−1]

Po zavedení:

α = T_s / (T + T_s)

dostaneme praktický tvar:

y[n] = α · x + (1 − α) · y[n−1] y[n] = y[n−1] + α · (x − y[n−1])

Algoritmus a program

Algoritmus programu využíva diskrétny oscilátor a numerickú aproximáciu systému 1 / (sT + 1). Základné výpočty prebiehajú 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
  • odosielanie 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 diskretizacie systému 1 / (sT + 1), napríklad bilineárnu transformaciu, ktorá by zlepšila presnosť modelu.

Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximacie, 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 mikrokontroleri namiesto spracovania na PC.