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 6: Riadok 6:
Na tento účel bol použitý oscilátor realizovaný ako prenosová funkcia:
Na tento účel bol použitý oscilátor realizovaný ako prenosová funkcia:


<syntaxhighlight lang="">
<code>
H(s) = 1 / ((s · T)^2 + 1)
H(s) = 1 / ((s · T)^2 + 1)
</syntaxhighlight>
</code>


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="">
<code>
H(s) = 1 / (s · T + 1)
H(s) = 1 / (s · T + 1)
</syntaxhighlight>
</code>


pre frekvenciu:
pre frekvenciu:
Riadok 23: Riadok 23:
Výstupný signál má mať tvar:
Výstupný signál má mať tvar:


<syntaxhighlight lang="">
<code>
A₀ + A₁ · sin(ωt + φ)
A₀ + A₁ · sin(ωt + φ)
</syntaxhighlight>
</code>


kde:
kde:
Riadok 39: Riadok 39:
Základom je rovnica:
Základom je rovnica:


<syntaxhighlight lang="">
<code>
y'' + ω²y = 0
y'' + ω²y = 0
</syntaxhighlight>
</code>


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>. To znamená, že ak vieme túto rovnicu numericky riešiť, vieme generovať sínus.
Riadok 51: Riadok 51:
Vychadzajme z prenosovej funkcie systému:
Vychadzajme z prenosovej funkcie systému:


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


Po úprave:
Po úprave:


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


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


<syntaxhighlight lang="">
<code>
T · dy(t)/dt + y(t) = x(t)
T · dy(t)/dt + y(t) = x(t)
</syntaxhighlight>
</code>


Týmto získame diferenciálnu rovnicu systému v časovej oblasti.
Týmto získame diferenciálnu rovnicu systému v časovej oblasti.
Riadok 76: Riadok 76:
Pre druhú deriváciu použijeme aproximáciu:
Pre druhú deriváciu použijeme aproximáciu:


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


Po dosadení do <code>y'' + ω²y = 0</code>:
Po dosadení do <code>y'' + ω²y = 0</code>:


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


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.
Riadok 92: Riadok 92:
Presnejší prístup vychádza z trigonometrických identít:
Presnejší prístup vychádza z trigonometrických identít:


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


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


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


Dosadením:
Dosadením:
Riadok 110: Riadok 110:
dostaneme:
dostaneme:


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


Označením:
Označením:
Riadok 120: Riadok 120:
vznikne rekurentný vzťah:
vznikne rekurentný vzťah:


<syntaxhighlight lang="">
<code>
y[n] = 2 · cos(θ) · y[n−1] − y[n−2]
y[n] = 2 · cos(θ) · y[n−1] − y[n−2]
</syntaxhighlight>
</code>


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.
Riadok 130: Riadok 130:
Platí:
Platí:


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


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


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


Z toho:
Z toho:


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


==== Inicializácia oscilátora ====
==== Inicializácia oscilátora ====
Riadok 172: Riadok 172:
Požadovaný výstup:
Požadovaný výstup:


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


kde:
kde:
Riadok 185: Riadok 185:
Zo spojitej rovnice:
Zo spojitej rovnice:


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


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


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


Po úprave:
Po úprave:


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


Po zavedení:
Po zavedení:
Riadok 209: Riadok 209:
dostaneme praktický tvar:
dostaneme praktický tvar:


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


=== Algoritmus a program ===
=== Algoritmus a program ===
Riadok 421: Riadok 421:
'''Video:'''
'''Video:'''


<center><youtube>VIDEO_PLACEHOLDER</youtube></center>
<center><youtube>MkgRE0QNgtk</youtube></center>


Video demonštruje reálne správanie systému. Je na ňom viditeľné generovanie sínusového signálu, jeho spracovanie systémom a výstupné dáta zobrazené v '''SerialPlot'''. Video slúži na overenie, že implementácia funguje podľa očakávania.
Video demonštruje reálne správanie systému. Je na ňom viditeľné generovanie sínusového signálu, jeho spracovanie systémom a výstupné dáta zobrazené v '''SerialPlot'''. Video slúži na overenie, že implementácia funguje podľa očakávania.

Verzia z 15:56, 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(). 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

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

Generovanie signálu

Oscilátor generuje hodnoty v rozsahu:

[-1, 1]

Požadovaný výstup:

x = A0 + A1 · y

kde:

A0 = 128 A1 = 100

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)
{
}

}
#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_ */
#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);
}

Zdrojový kód: MykytaOleksandr_sources.zip

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 SerialPlot, kde je viditeľný vstupný sínusový signál a výstup systému.


Namerené priebehy vstupu a výstupu zo Serial Plot

Pri overovaní bolo sledované, či:

amplitúda výstupu zodpovedá očakávaniu systém vykazuje fázový posun priebeh signálu je stabilný bez driftu výstup reaguje správne na vstupný sínus

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


Video:

Video demonštruje reálne správanie systému. Je na ňom viditeľné generovanie sínusového signálu, jeho spracovanie systémom a výstupné dáta zobrazené v SerialPlot. Video slúži na overenie, že implementácia funguje podľa očakávania.

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