Operácie

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

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
Riadok 1: Riadok 1:
Záverečný projekt predmetu MIPS / LS2026 - '''Oleksandr Mykyta'''
Záverečný projekt predmetu MIPS / LS2026 - """Oleksandr Mykyta"""


== Zadanie ==
== 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:
Ú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:


<syntaxhighlight lang="">
<syntaxhighlight lang="">
Riadok 9: Riadok 10:
</syntaxhighlight>
</syntaxhighlight>


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


<syntaxhighlight lang="">
<syntaxhighlight lang="">
Riadok 15: Riadok 16:
</syntaxhighlight>
</syntaxhighlight>


pre frekvenciu <code>ω = 1 / T</code>, kde <code>T = 0,5 s</code>.
pre frekvenciu:
<code>ω = 1 / T</code>,
kde
<code>T = 0.5 s</code>.


Výstupný signál má mať tvar:
Výstupný signál má mať tvar:
Riadok 25: Riadok 29:
kde:
kde:
<code>A₀ = 128</code>,
<code>A₀ = 128</code>,
<code>A₁ = 100</code>
<code>A₁ = 100</code>.


__TOC__
__TOC__


== Analýza a opis riešenia ==
== 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.
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:
Základom je rovnica:
Riadok 39: Riadok 44:
</syntaxhighlight>
</syntaxhighlight>


Táto rovnica popisuje harmonické kmity a jej riešením sú funkcie <code>sin()</code> a <code>cos()</code>. To znamená, že ak vieme túto rovnicu numericky riešiť, vieme generovať sínus.
Táto rovnica popisuje """harmonické kmity""" a jej riešením sú funkcie <code>sin()</code> a <code>cos()</code>.


=== Teoretický základ a odvodenia ===
=== Teoretický základ a odvodenia ===
Riadok 45: Riadok 50:
==== Laplaceova transformacia ====
==== Laplaceova transformacia ====


Vychadzajme z prenosovej funkcie systému:
Vychádzajme z """prenosovej funkcie""" systému:


<syntaxhighlight lang="">
H(s) = Y(s) / X(s) = 1 / (T · s + 1)
H(s) = Y(s) / X(s) = 1 / (T · s + 1)
</syntaxhighlight>


Po úprave:
Po úprave:


<syntaxhighlight lang="">
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)
</syntaxhighlight>


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


<syntaxhighlight lang="">
T · dy(t)/dt + y(t) = x(t)
T · dy(t)/dt + y(t) = x(t)
 
</syntaxhighlight>
Týmto získame diferenciálnu rovnicu systému v časovej oblasti.


==== Diskretizácia ====
==== Diskretizácia ====


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


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


<syntaxhighlight lang="">
y'' ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²
y'' ≈ (y[n] − 2y[n−1] + y[n−2]) / T_s²
</syntaxhighlight>
Dosadenie:


Po dosadení do (y'' + ω²y = 0):
<syntaxhighlight lang="">
y'' + ω²y = 0
</syntaxhighlight>


Výsledok:
<syntaxhighlight lang="">
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]
 
</syntaxhighlight>
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) ====


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


<syntaxhighlight lang="">
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)
</syntaxhighlight>


Po sčítaní:
Po sčítaní:


<syntaxhighlight lang="">
sin(A + B) + sin(A − B) = 2 · sin(A) · cos(B)
sin(A + B) + sin(A − B) = 2 · sin(A) · cos(B)
</syntaxhighlight>


Dosadením:
Dosadenie:


A = (n−1)θ
<code>A = (n−1)θ</code> 
B = θ
<code>B = θ</code>


dostaneme:
Výsledok:


<syntaxhighlight lang="">
sin(nθ) + sin((n−2)θ) = 2 · cos(θ) · sin((n−1)θ)
sin(nθ) + sin((n−2)θ) = 2 · cos(θ) · sin((n−1)θ)
</syntaxhighlight>


Označením:
Definícia:


y[n] = sin(nθ)
<code>y[n] = sin(nθ)</code>


vznikne rekurentný vzťah:
Rekurentný vzťah:


<syntaxhighlight lang="">
y[n] = 2 · cos(θ) · y[n−1] − y[n−2]
y[n] = 2 · cos(θ) · y[n−1] − y[n−2]
 
</syntaxhighlight>
Tento vzťah generuje stabilný sínusový signál bez zmeny amplitúdy.


==== Výpočet parametrov ====
==== Výpočet parametrov ====


Platí:
Vzťah:


<syntaxhighlight lang="">
θ = ω · T_s
θ = ω · T_s
</syntaxhighlight>


kde:
Konštanty:
T = 0,5 s
 
ω = 1 / T = 2 rad/s
<code>T = 0.5 s</code> 
SAMPLE_RATE = 1000 Hz T_s = 0,001 s
<code>ω = 1 / T = 2 rad/s</code> 
<code>SAMPLE_RATE = 1000 Hz</code> 
<code>T_s = 0.001 s</code>
 
Výsledok:


θ = 0,002
<code>θ = 0.002</code>


==== Aproximacia cos() ====
==== Aproximácia cos() ====


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


<syntaxhighlight lang="">
cos(θ) ≈ 1 − θ²/2
cos(θ) ≈ 1 − θ²/2
</syntaxhighlight>


Pre malé θ je táto aproximacia dostatočne presná.
Úprava:
 
Z toho:


<syntaxhighlight lang="">
2cos(θ) ≈ 2 · (1 − θ²/2)
2cos(θ) ≈ 2 · (1 − θ²/2)
</syntaxhighlight>


==== Inicializácia oscilátora ====
==== Inicializácia oscilátora ====


Pre správnu činnosť oscilátora sú potrebné počiatočné hodnoty:
Počiatočné hodnoty:


y1 = 1
<code>y1 = 1</code> 
y2 = 1 − θ²/2
<code>y2 = 1 − θ²/2</code>


Tieto hodnoty zabezpečia vznik sínusového priebehu.
==== Generovanie signálu ====


==== Generovanie signálu ====
Rozsah:


Oscilátor generuje hodnoty v rozsahu ⟨−1, 1⟩.
<code>⟨−1, 1⟩</code>


Požadovaný výstup:
Výstup:


<syntaxhighlight lang="">
x = A0 + A1 · y
x = A0 + A1 · y
</syntaxhighlight>


kde:
Konštanty:
A0 = 128
A1 = 100


Tým sa signál posunie do kladného rozsahu vhodného pre PWM.
<code>A0 = 128</code> 
<code>A1 = 100</code>


==== Diskretizacia systému 1 / (sT + 1) ====
==== Diskretizácia systému 1 / (sT + 1) ====


Zo spojitej rovnice:
Spojitá rovnica:


<syntaxhighlight lang="">
T · dy/dt + y = x
T · dy/dt + y = x
</syntaxhighlight>


Použitím Eulerovej metódy:
Eulerova metóda:


<syntaxhighlight lang="">
dy/dt ≈ (y[n] − y[n−1]) / T_s
dy/dt ≈ (y[n] − y[n−1]) / T_s
</syntaxhighlight>


Po úprave:
Úpravy:


<syntaxhighlight lang="">
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]
</syntaxhighlight>


Po zavedení:
Definícia parametra:


α = T_s / (T + T_s)
<code>α = T_s / (T + T_s)</code>


dostaneme praktický tvar:
Finálny tvar:


<syntaxhighlight lang="">
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])
</syntaxhighlight>


=== Algoritmus a program ===
=== 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:
Použité časti:
 
- """diskrétny oscilátor"""
* výpočet oscilátora
- """numerický model systému"""
* generovanie vstupu x
* výpočet výstupu systému
* výstup cez PWM
* odosielanie dát cez UART
 
<tabs>
<tab name="main.c"><syntaxhighlight lang="c++" style="background: LightYellow;">
#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);
Frekvencia prerušenia:


float theta = (1.0 / T) * (1.0 / SAMPLE_RATE);
<code>1 kHz</code>


y1 = 1.0;
Kroky:
y2 = 1.0 - (theta * theta) / 2.0;
- výpočet oscilátora
 
- generovanie """x"""
OSC_COEFF = 2.0 * (1.0 - (theta * theta) / 2.0);
- výpočet systému
 
- """PWM""" výstup
sei();
- """UART""" komunikácia
 
while (1)
{
}
 
} </syntaxhighlight></tab>
<tab name="uart.h"><syntaxhighlight lang="c++" style="background: LightYellow;">
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 
#ifndef UART_H_
#define UART_H_
 
#include <stdio.h>
 
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)
 
void uart_init( void );
int uart_putc( char c, FILE *stream );
void uart_puts( const char *s );
char uart_getc( void );
void delay(int delay);
 
#endif /* UART_H_ */
</syntaxhighlight></tab>
<tab name="uart.c"><syntaxhighlight lang="c++" style="background: LightYellow;">
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
 
void uart_init( void )
{
  #include <util/setbaud.h>
 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  #if USE_2X
    UCSR0A |= (1 << U2X0);
  #else
    UCSR0A &= ~(1 << U2X0);
  #endif
 
 
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);
}
 
int uart_putc(char c, FILE *stream)
{
    if (c == '\n')
    {
        loop_until_bit_is_set(UCSR0A, UDRE0);
        UDR0 = '\r';
    }
 
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
 
    return 0;
}
 
 
void uart_puts(const char *s)
{
}
 
char uart_getc(void)
{
    loop_until_bit_is_set(UCSR0A, RXC0);
    return UDR0;
}
 
void delay(int delay)
{
  for (int i=1; i<=delay; i++)
  _delay_ms(1);
}
</syntaxhighlight></tab>
</tabs>


=== Overenie ===
=== Overenie ===


Funkcia systému bola overená pomocou výpisu dát cez UART. Do sériového portu sa posielajú dvojice hodnôt:
Výpis:
 
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.
<code>x, y_sys</code>


Zo signálov je možné pozorovať zmenu amplitúdy a fázový posun, čo predstavuje bod frekvenčnej charakteristiky systému.
Pozorované javy:
- """zmena amplitúdy"""
- """fázový posun"""


== Č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.
- použiť """bilineárnu transformáciu"""
 
- presnejší výpočet """cos(θ)"""
Taktiež by bolo možné implementovať presnejší výpočet cos(θ) bez aproximacie, napríklad pomocou lookup tabuľky.
- merať """amplitúdu a fázu""" priamo v MCU
 
Ď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 13:24, 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.

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""" a jej riešením sú funkcie sin() a cos().

Teoretický základ a odvodenia

Laplaceova transformacia

Vychádzajme 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 transformácie""" dostaneme:

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

Diskretizácia

Mikrokontrolér pracuje v """diskrétnom čase""".

Pre druhú deriváciu:

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

Dosadenie:

y'' + ω²y = 0

Výsledok:

y[n] = (2 / (1 + ω²T_s²)) · y[n−1] − (1 / (1 + ω²T_s²)) · y[n−2]

Diskrétny oscilátor (presný model)

Trigonometrické identity:

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)

Dosadenie:

A = (n−1)θ B = θ

Výsledok:

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

Definícia:

y[n] = sin(nθ)

Rekurentný vzťah:

y[n] = 2 · cos(θ) · y[n−1] − y[n−2]

Výpočet parametrov

Vzťah:

θ = ω · T_s

Konštanty:

T = 0.5 s ω = 1 / T = 2 rad/s SAMPLE_RATE = 1000 Hz T_s = 0.001 s

Výsledok:

θ = 0.002

Aproximácia cos()

Taylorov rozvoj:

cos(θ) ≈ 1 − θ²/2

Úprava:

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

Inicializácia oscilátora

Počiatočné hodnoty:

y1 = 1 y2 = 1 − θ²/2

Generovanie signálu

Rozsah:

⟨−1, 1⟩

Výstup:

x = A0 + A1 · y

Konštanty:

A0 = 128 A1 = 100

Diskretizácia systému 1 / (sT + 1)

Spojitá rovnica:

T · dy/dt + y = x

Eulerova metóda:

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

Úpravy:

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]

Definícia parametra:

α = T_s / (T + T_s)

Finálny tvar:

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

Algoritmus a program

Použité časti: - """diskrétny oscilátor""" - """numerický model systému"""

Frekvencia prerušenia:

1 kHz

Kroky: - výpočet oscilátora - generovanie """x""" - výpočet systému - """PWM""" výstup - """UART""" komunikácia

Overenie

Výpis:

x, y_sys

Pozorované javy: - """zmena amplitúdy""" - """fázový posun"""

Čo by som urobil inak

- použiť """bilineárnu transformáciu""" - presnejší výpočet """cos(θ)""" - merať """amplitúdu a fázu""" priamo v MCU