Operácie

Simulátor sústavy 1. rádu: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
 
(27 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 17: Riadok 17:
== Analýza  a opis riešenia ==
== Analýza  a opis riešenia ==


Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami...
* Spojitý model
Podrobne opíšte použité komponenty (okrem základnej dosky s ATmega328P procesorom), pridajte linky na datasheety alebo opis obvodu.  
Prenosová funkcia systému prvého rádu je Y(s)/U(s) = K/(s·T + 1) = 1/(0,5·s + 1). Pri jednotkovom skoku vstupu sa výstup približuje k cieľovej hodnote s časovou konštantou T = 0,5 s. Rozsah vstupného aj výstupného signálu je 0 až 5 V s rozlíšením 0,01 V.


[[Súbor:GeminiAI-image3.jpg|400px|thumb|center|Celkový pohľad na zariadenie.]]
* Digitálna simulácia
Mikrokontrolér ATmega328P pracuje v diskrétnom čase, preto spojitý systém Y(s)/U(s) = 1/(0,5·s + 1) spracuje signál digitálne. Vstup je konštanta U = 200 (zodpovedá 2,00 V) zadaná v kóde. Aby sa systém mohol simulovať, musí byť model prevedený do rozdielovej rovnice, ktorú vyhodnocuje v každom vzorkovacom kroku.


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.
* Diskretizácia
Pri vzorkovacom čase Ts = 0,05s sa spojitý model diskretizuje metódou ZOH:
a = exp(–0,05/0,5) = 0,9048, b = 1 – a = 0,0952
Diferenčná rovnica: y[n] = 0,9048·y[n–1] + 0,0952·u[n]
V kóde sa táto rovnica realizuje ako inkrementálny výpočet, výstup sa každý krok posúva o jednu desatinu rozdielu medzi vstupom a výstupom, čo zodpovedá koeficientu b = 0,095.


[[Súbor:GeminiAI-image2.jpg|400px|thumb|center|Schéma zapojenia.]]
* Celočíselná aritmetika
Rozsah 0–5V je v kóde zapísaný v centivoltoch (U = 200 znamená 2,00V). Aby nedochádzalo k strate presnosti pri delení, premenná y_s obsahuje hodnotu v tisícinách centivoltu (SCALE = 1000). Každý krok sa y_s aktualizuje a prevedie sa späť na centivolty. Oba kanály sa posielajú cez UART do SerialPlot.
 
* Časovanie – Timer2
Timer2 CTC s prescalerom 1024 a OCR2A = 155, zodpovedá frekvencii prerušenia približne 100Hz (perióda 10ms). Pomocný counter sa zvyšuje a pri dosiahnutí hodnoty 5 sa counter vynuluje. Výsledný čas simulácie je Ts = 5 x 10ms = 0,05s.
 
* Prenosová charakteristika
Výstup y(t) sa blíži k vstupnej hodnote 2,00V. Časová konštanta T = 0,5s znamená, že po jej čase dosiahne výstup približne 63% hodnoty (1,26V).
 
[[Súbor:fotka2.png|400px|thumb|center]]




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


Algoritmus programu využíva toto a toto, základné funkcie takéto a voláma ich tuto...  
* Inicializácia
Výpis kódu je nižšie...
Na začiatku programu sa nastavia všetky potrebné parametre. UART0 sa inicializuje na prenosovú rýchlosť 9600 Bd. Timer2 sa nakonfiguruje v režime CTC s prescalerom 1024 a hodnotou OCR2A = 155, čím sa dosiahne frekvencia prerušenia približne 100 Hz. Vnútorný stav simulácie y_s a counter nastavené na 0.
 
* Prerušenie od Timer2
Každých 10ms vyvolá Timer2 prerušenie TIMER2_COMPA_vect. Jeho úloha je nastaviť timer = 1 po 10ms. Výpočet sa vykonáva v hlavnej slučke.
 
* Hlavná slučka
Hlavná slučka beží pomocou funkcie while a kontroluje timer. Po jeho aktivácií ho vynuluje a zvýši counter. Simulácia sa spustí až keď counter dosiahne hodnotu 5,takže každých 50ms. Potom sa zavolá funkcia filter_step(), ktorá vypočíta nový výstup y podľa diferenčnej rovnice systému prvého rádu. Výsledok spolu so vstupom U sa naformátuje do reťazca a odošle cez UART do SerialPlot, kde sa zobrazí priebeh prechodovej charakteristiky v reálnom čase.




<tabs>
<tabs>
<tab name="AVR C-code"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="main.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
 
#define F_CPU 16000000UL
#define BAUD 9600
 
#include <avr/io.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdio.h>
#include "uart.h"
#define U 200 // vstup 2.00 V 
#define SCALE 1000L // interna mierka
#define TIMER_OCR 155 // Timer 10 ms
volatile uint8_t timer = 0;
uint8_t counter = 0; // pocitadlo
int32_t y_s = 0; // vystup systemu
// Timer - 10 ms
static void timer_init(void)
{
    TCCR2A = (1 << WGM21); // vynulovanie casovaca
    TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // prescaler 1024
    OCR2A = TIMER_OCR; // porovnavacia hodnota
    TIMSK2 = (1 << OCIE2A); // povolenie prerusenia
}
ISR(TIMER2_COMPA_vect)
{
    timer = 1; // vystup casovaca
}
// Simulacia systemu 1. radu
static uint16_t filter_step(uint16_t u)
{
    y_s += ((int32_t)u * SCALE - y_s) / 10; // rovnica pre vypocet
    uint16_t y = (uint16_t)((y_s + SCALE / 2) / SCALE); // prevod na centivolty
    return y;
}


int main(void)
int main(void)
{
{
  unsigned int measuredValue;
    uart_init(); // spusti UART
    timer_init(); // spusti timer
    sei();        // globalne povolenie preruseni
char buf [20];
 
    while (1)
    {
        if (timer)
        {
            timer = 0;
counter ++;
if (counter>=5) // simulacia sa vyhodnocuje kazdych 50ms
{
counter = 0;
            uint16_t y = filter_step(U); // simulacia systemu


  while (1)
            // Formatovanie vystupu pre SerialPlot
  {
            snprintf(buf,sizeof(buf),"%u,%u\n",U,y);
    /*  relax  */
uart_puts(buf); // odoslanie cez UART
  }
}
        }
    }


  return(0);
    return 0;
}
}


</syntaxhighlight ></tab>
</syntaxhighlight ></tab>
<tab name="filename.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
#include <avr/io.h>
#include <util/setbaud.h>
#include "uart.h"
void uart_init( void )
{
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
}
void uart_putc(char c)
{
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
  UDR0 = c;
}
void uart_puts(const char *s)
{
while(*s)
{
uart_putc(*s);
s++;
}
}
char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
</syntaxhighlight ></tab>
<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#ifndef UART_H_
#define UART_H_
#define F_CPU 16000000UL
#define BAUD 9600
void uart_init( void );
   
void uart_putc( char c );
void uart_puts( const char *s );


void adc_init(void);                                   // A/D converter initialization
char uart_getc( void );


unsigned int adc_read(char a_pin);
#endif /* UART_H_ */
</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]]
Zdrojový kód: [[Médiá:projektMatusProkop.zip|projektMatusProkop.zip]]


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


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.
Program sme nahrali do Arduina a následne sme otvorili SerialPlot a sledovali priebeh oboch kanálov vstup zostával konštantný na 200 = 2V a výstup postupne rástol k tejto hodnote. Po uplynutí približne 1,5s sa výstup ustálil na cieľovej hodnote. Program sme niekoľkokrát resetovali a zakaždým sa priebeh zopakoval, čo potvrdilo správnu funkčnosť simulácie.
Na konci uvádzame fotku hotového zariadenia.  


[[Súbor:GeminiAI-image1.jpg|400px|thumb|center|Aplikácia.]]
[[Súbor:fotka.png|1072x187px|thumb|center]]


'''Video:'''
'''Video:'''
<https://youtube.com/shorts/lXAZiGiiuj8
<center><youtube>_https://youtube.com/shorts/lXAZiGiiuj8</youtube></center>






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

Aktuálna revízia z 22:56, 7. jún 2026

Záverečný projekt predmetu MIPS / LS2026 - Matúš Prokop


Zadanie

Mojou úlohou bolo vytvoriť program pracujúci v reálnom čase simulujúci systém Y(s)/U(s)=K/(s*T+1), K=1 [-] a T = 0,5 [sek]. Na vykreslenie priebehu použite SerialPlot. Rozsahy u(t) a y(t) sú 0 až 5V. Rozlíšenie 0.01V. Vykreslite prechodovú charakteristiku odpovedajúcu vstupnej hodnote 2.00V. Použite celočíselnú aritmetiku.

Vývojová doska ACROB.

Literatúra:


Analýza a opis riešenia

  • Spojitý model

Prenosová funkcia systému prvého rádu je Y(s)/U(s) = K/(s·T + 1) = 1/(0,5·s + 1). Pri jednotkovom skoku vstupu sa výstup približuje k cieľovej hodnote s časovou konštantou T = 0,5 s. Rozsah vstupného aj výstupného signálu je 0 až 5 V s rozlíšením 0,01 V.

  • Digitálna simulácia

Mikrokontrolér ATmega328P pracuje v diskrétnom čase, preto spojitý systém Y(s)/U(s) = 1/(0,5·s + 1) spracuje signál digitálne. Vstup je konštanta U = 200 (zodpovedá 2,00 V) zadaná v kóde. Aby sa systém mohol simulovať, musí byť model prevedený do rozdielovej rovnice, ktorú vyhodnocuje v každom vzorkovacom kroku.

  • Diskretizácia

Pri vzorkovacom čase Ts = 0,05s sa spojitý model diskretizuje metódou ZOH: a = exp(–0,05/0,5) = 0,9048, b = 1 – a = 0,0952 Diferenčná rovnica: y[n] = 0,9048·y[n–1] + 0,0952·u[n] V kóde sa táto rovnica realizuje ako inkrementálny výpočet, výstup sa každý krok posúva o jednu desatinu rozdielu medzi vstupom a výstupom, čo zodpovedá koeficientu b = 0,095.

  • Celočíselná aritmetika

Rozsah 0–5V je v kóde zapísaný v centivoltoch (U = 200 znamená 2,00V). Aby nedochádzalo k strate presnosti pri delení, premenná y_s obsahuje hodnotu v tisícinách centivoltu (SCALE = 1000). Každý krok sa y_s aktualizuje a prevedie sa späť na centivolty. Oba kanály sa posielajú cez UART do SerialPlot.

  • Časovanie – Timer2

Timer2 CTC s prescalerom 1024 a OCR2A = 155, zodpovedá frekvencii prerušenia približne 100Hz (perióda 10ms). Pomocný counter sa zvyšuje a pri dosiahnutí hodnoty 5 sa counter vynuluje. Výsledný čas simulácie je Ts = 5 x 10ms = 0,05s.

  • Prenosová charakteristika

Výstup y(t) sa blíži k vstupnej hodnote 2,00V. Časová konštanta T = 0,5s znamená, že po jej čase dosiahne výstup približne 63% hodnoty (1,26V).


Algoritmus a program

  • Inicializácia

Na začiatku programu sa nastavia všetky potrebné parametre. UART0 sa inicializuje na prenosovú rýchlosť 9600 Bd. Timer2 sa nakonfiguruje v režime CTC s prescalerom 1024 a hodnotou OCR2A = 155, čím sa dosiahne frekvencia prerušenia približne 100 Hz. Vnútorný stav simulácie y_s a counter sú nastavené na 0.

  • Prerušenie od Timer2

Každých 10ms vyvolá Timer2 prerušenie TIMER2_COMPA_vect. Jeho úloha je nastaviť timer = 1 po 10ms. Výpočet sa vykonáva v hlavnej slučke.

  • Hlavná slučka

Hlavná slučka beží pomocou funkcie while a kontroluje timer. Po jeho aktivácií ho vynuluje a zvýši counter. Simulácia sa spustí až keď counter dosiahne hodnotu 5,takže každých 50ms. Potom sa zavolá funkcia filter_step(), ktorá vypočíta nový výstup y podľa diferenčnej rovnice systému prvého rádu. Výsledok spolu so vstupom U sa naformátuje do reťazca a odošle cez UART do SerialPlot, kde sa zobrazí priebeh prechodovej charakteristiky v reálnom čase.


#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdio.h>

#include "uart.h"

#define U 200			// vstup 2.00 V  
#define SCALE 1000L		// interna mierka 

#define TIMER_OCR 155 // Timer 10 ms 

volatile uint8_t timer = 0;
uint8_t counter = 0; // pocitadlo 

int32_t y_s = 0; // vystup systemu 

// Timer - 10 ms 
static void timer_init(void)
{
    TCCR2A = (1 << WGM21); // vynulovanie casovaca 

    TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // prescaler 1024 

    OCR2A = TIMER_OCR; // porovnavacia hodnota 

    TIMSK2 = (1 << OCIE2A); // povolenie prerusenia 
}

ISR(TIMER2_COMPA_vect)
{
    timer = 1; // vystup casovaca
}

// Simulacia systemu 1. radu 
static uint16_t filter_step(uint16_t u)
{
    y_s += ((int32_t)u * SCALE - y_s) / 10; // rovnica pre vypocet

    uint16_t y = (uint16_t)((y_s + SCALE / 2) / SCALE); // prevod na centivolty

    return y;
}

int main(void)
{
    uart_init();  // spusti UART
    timer_init(); // spusti timer
    sei();        // globalne povolenie preruseni
	
	char buf [20];

    while (1)
    {
        if (timer)
        {
            timer = 0;
			
			counter ++;
			
			if (counter>=5) // simulacia sa vyhodnocuje kazdych 50ms 
			{
				
			counter = 0;
			
            uint16_t y = filter_step(U); // simulacia systemu

            // Formatovanie vystupu pre SerialPlot 
            snprintf(buf,sizeof(buf),"%u,%u\n",U,y);
			uart_puts(buf); // odoslanie cez UART
			}
        }
    }

    return 0;
}
#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
#include <util/setbaud.h>

#include "uart.h"


void uart_init( void ) 
{
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;

#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif

    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}


void uart_putc(char c) 
{
   loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
   UDR0 = c;
}


void uart_puts(const char *s)
{
	while(*s)
	{
		uart_putc(*s);
		s++;
	}
}

char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
#ifndef UART_H_
#define UART_H_
#define F_CPU 16000000UL
#define BAUD 9600

void uart_init( void );
     
void uart_putc( char c );
void uart_puts( const char *s );

char uart_getc( void );

#endif /* UART_H_ */


Zdrojový kód: projektMatusProkop.zip

Overenie

Program sme nahrali do Arduina a následne sme otvorili SerialPlot a sledovali priebeh oboch kanálov vstup zostával konštantný na 200 = 2V a výstup postupne rástol k tejto hodnote. Po uplynutí približne 1,5s sa výstup ustálil na cieľovej hodnote. Program sme niekoľkokrát resetovali a zakaždým sa priebeh zopakoval, čo potvrdilo správnu funkčnosť simulácie.

Video: