-
1. Data: 2012-10-09 01:43:37
Temat: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: "Robbo" <n...@g...com>
Witam,
Używam mikrokontrolera ATmega128. W moim programie użytkownik ustawia
wartość prądu (liczba całkowita od 0 do 1000) oraz czas (od 1 do 40 sekund).
Prąd ma narosnąć od 0 do wartości ustawionej w ustawionym czasie. Funkcja
służąca do obliczania aktualnej wartości prądu podczas jego narastania jest
wywoływana z pewną częstotliwością (od 10 do 60Hz, zależnie od ustawienia w
parametrach programu). Zatem narastanie prądu odbywa się w liczbie kroków
wyrażonej wzorem: K = czas[s] * częstotliwość[Hz].
Żeby uniknąć obliczeń zmiennoprzecinkowych, zastosowałem algorytm Bresenhama
do kreślenia odcinków. Zapowiada się, że będzie to działać bardzo szybko,
gdy K >= wartość prądu.
Gdy K < wartość prądu, to algorytm Bresenhama normalnie kreśli odcinek w
pętli "idąc po zmiennej Y". Tymczasem ja działam w osi odciętych, czyli X (u
mnie jest to liczba kroków, w których prąd ma narosnąć). Bez większych
problemów przerobiłem ten algorytm tak, aby dla K < wartość prądu, "szedł on
po zmiennej X". Przy czym po tej przeróbce uzyskałem podpętlę (while), która
niekiedy będzie wykonywać się wiele razy (dla pojedynczego kroku w osi X),
co spowolni algorytm. Inną metodą, zamiast tej podpętli, byłoby zastosowanie
dzielenia, co też nie jest rozwiązaniem, gdyż dzielenie realizowane jest
przez kompilator także w pętli.
Poniżej przedstawiłem algorytm, który stosuję -- na razie to jest wersja
kreśląca grafikę (tak łatwiej mi obserwować działanie tego algorytmu), a nie
funkcja wywoływana z pewną częstotliwością i sterująca prądem.
Algorytm działa prawidłowo. Przy czym może działać niekiedy wolno (pętla
while może wykonywać się wiele razy) dla K < wartość prądu -- no i to jest
mój problem.
Mam pytanie do Was, jak przyspieszyć ten algorytm?
A jeśli się nie da, to byłbym wdzięczny za naprowadzenie na jakiś inny
sposób zaprogramowania opisanego problemu (narastania wartości w pewnej
liczbie kroków).
Ilustracja graficzna działania poniżej zaprezentowanego algorytmu:
http://imageshack.us/a/img341/925/74439722.png
K = czas * czestotliwosc;
if (K >= wartoscPradu) {
for (t = 0; t <= K; t++) {
drawPixel(px, py);
y += wartoscPradu + 1;
if (y >= K + 1)
y -= K + 1, py++;
px++;
}
} else {
for (t = 0; t <= K; t++) {
while (1) {
x += K + 1;
if (x >= wartoscPradu + 1) {
drawPixel(px, py);
x -= wartoscPradu + 1, px++;
py++;
break;
}
py++;
}
}
}
Pozdrawiam i z góry dziękuję za pomoc,
Robbo
-
2. Data: 2012-10-09 04:12:09
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: Dondu <m...@g...com>
cyt:
"Algorytm może działać zarówno na liczbach zmiennoprzecinkowych jak i całkowitych,
ale ze względów wydajnościowych wykorzystuje się najczęściej realizacje
całkowitoliczbowe. Zatem jeżeli początkowa wartość zmiennej decyzyjnej d lub jej
przyrosty wychodzą nam ułamkowe, to mnożymy zarówno zmienną decyzyjną d jak i jej
przyrosty tak by uzyskać liczby całkowite. Możemy tak zrobić gdyż do decyzji bierzemy
pod uwagę jedynie znak zmiennej decyzyjnej d."
źródło: http://www.algorytm.org/podstawy-grafiki/algorytm-br
esenhama.html
-
3. Data: 2012-10-09 09:29:35
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: Michoo <m...@v...pl>
On 09.10.2012 01:43, Robbo wrote:
> Witam,
>
> Używam mikrokontrolera ATmega128. W moim programie użytkownik ustawia
> wartość prądu (liczba całkowita od 0 do 1000) oraz czas (od 1 do 40
> sekund). Prąd ma narosnąć od 0 do wartości ustawionej w ustawionym
> czasie. Funkcja służąca do obliczania aktualnej wartości prądu podczas
> jego narastania jest wywoływana z pewną częstotliwością (od 10 do 60Hz,
> zależnie od ustawienia w parametrach programu). Zatem narastanie prądu
> odbywa się w liczbie kroków wyrażonej wzorem: K = czas[s] *
> częstotliwość[Hz].
Albo czegoś nie zrozumiałem, albo to jest zwykła proporcja:
I(s)=I(S0)+(I(Se)-I(S0))*((s-S0)/(Se-S0))
I(s)=I(S0)+(I(Se)-I(S0))/(Se-S0) * (s-S0)
gdzie s - czas, S0 - czas początkowy, Se - czas końcowy
Przekształcasz to sobie na:
I(t)=I(T0)+t*dI
I(t)=I(t-1)+dI
Raz wyliczasz iloraz różnicowy dI, potem masz w każdym cyklu jedno
dodawanie i jeden shift.
--
Pozdrawiam
Michoo
-
4. Data: 2012-10-09 10:06:39
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: Piotr Gałka <p...@C...pl>
Użytkownik "Robbo" <n...@g...com> napisał w wiadomości
news:5073652e$0$26682$65785112@news.neostrada.pl...
> Mam pytanie do Was, jak przyspieszyć ten algorytm?
> A jeśli się nie da, to byłbym wdzięczny za naprowadzenie na jakiś inny
> sposób zaprogramowania opisanego problemu (narastania wartości w pewnej
> liczbie kroków).
>
Jestem lepszy w EMC niż algorytmach ale zaproponuję to, co mi się nasunęło.
Może w przypadku K<I podzielić I/n (n=2,4,8,...) aż będzie K>I, a potem
pętla już jak dla przypadku K>I, tylko py++ zastąpić py+=n.
"Schodki" wyjdą większe niż z twojej części else, ale jeśli dzielenie przed
pętlą nie byłoby problemem to może być n=2,3,4,5,.... i wtedy to chyba już
wyjdzie prawie to samo.
P.G.
-
5. Data: 2012-10-09 10:18:07
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: Piotr Gałka <p...@C...pl>
Użytkownik "Piotr Gałka" <p...@C...pl> napisał w
wiadomości news:5073db09$1@news.home.net.pl...
>
> Użytkownik "Robbo" <n...@g...com> napisał w wiadomości
> news:5073652e$0$26682$65785112@news.neostrada.pl...
>> Mam pytanie do Was, jak przyspieszyć ten algorytm?
>> A jeśli się nie da, to byłbym wdzięczny za naprowadzenie na jakiś inny
>> sposób zaprogramowania opisanego problemu (narastania wartości w pewnej
>> liczbie kroków).
>>
> Jestem lepszy w EMC niż algorytmach ale zaproponuję to, co mi się
> nasunęło.
>
> Może w przypadku K<I podzielić I/n (n=2,4,8,...) aż będzie K>I, a potem
> pętla już jak dla przypadku K>I, tylko py++ zastąpić py+=n.
> "Schodki" wyjdą większe niż z twojej części else, ale jeśli dzielenie
> przed pętlą nie byłoby problemem to może być n=2,3,4,5,.... i wtedy to
> chyba już wyjdzie prawie to samo.
Poprawka.
Jednak nie prawie to samo bo będą stałe przyrosty a czasem brak przyrostu.
Przyrosty zmienne są jednak bliższe ideału.
P.G.
-
6. Data: 2012-10-09 12:19:48
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: "Robbo" <n...@g...com>
Witam,
Dziękuję za odpowiedź, która mam nadzieję naprowadzi mnie na właściwe tory.
> Albo czegoś nie zrozumiałem, albo to jest zwykła proporcja:
Tak. Prąd ma przyrastać w K krokach o wartość maxPrąd/K w każdym kroku.
> I(s)=I(S0)+(I(Se)-I(S0))*((s-S0)/(Se-S0))
> I(s)=I(S0)+(I(Se)-I(S0))/(Se-S0) * (s-S0)
> gdzie s - czas, S0 - czas początkowy, Se - czas końcowy
Czas będzie zawsze liczony od zera. Prąd początkowy także będzie narastać od
zera.
Więc jeśli I(S0) = 0, S0 = 0. Zatem powyższe formuły można uprościć do:
I(s) = I(Se) * (s/Se)
I(s) = I(Se)/Se*s
> Przekształcasz to sobie na:
> I(t)=I(T0)+t*dI
> I(t)=I(t-1)+dI
>
> Raz wyliczasz iloraz różnicowy dI, potem masz w każdym cyklu jedno
> dodawanie i jeden shift.
Tu bym prosił o wyjaśnienie. Mało spałem i chyba nie do końca myślę, dlatego
proszę o wybaczenie.
Czy dI będzie wartością zmiennoprzecinkową?
W jaki sposób będzie użyty shift?
Czy chodzi o to, że przy wyliczaniu dI robimy shift w lewo, aby nie tracić
precyzji, a działać na liczbach całkowitych. Potem działamy na dużych
wartościach dI, a tuż przed użyciem wartości I robimy shift w prawo?
Robbo
-
7. Data: 2012-10-09 12:50:29
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: Michoo <m...@v...pl>
On 09.10.2012 12:19, Robbo wrote:
> Czas będzie zawsze liczony od zera. Prąd początkowy także będzie
> narastać od zera.
> Więc jeśli I(S0) = 0, S0 = 0. Zatem powyższe formuły można uprościć do:
> I(s) = I(Se) * (s/Se)
> I(s) = I(Se)/Se*s
Dokładnie. Ale tak długo jak zmiany są liniowe to wystarcza raz policzyć
iloraz różnicowy.
>
>> Przekształcasz to sobie na:
>> I(t)=I(T0)+t*dI
>> I(t)=I(t-1)+dI
>>
>> Raz wyliczasz iloraz różnicowy dI, potem masz w każdym cyklu jedno
>> dodawanie i jeden shift.
>
> Tu bym prosił o wyjaśnienie. Mało spałem i chyba nie do końca myślę,
> dlatego proszę o wybaczenie.
>
> Czy dI będzie wartością zmiennoprzecinkową?
Stałoprzecinkową, np. o 16 bitach części całkowitej i 16 po przecinku:
uint16_t I=0;
uint32_t I_accu=0;
uint32_t dI;
time_t last_time=0;
void new_setting(/**/){
dI=(I_target<<16)/time_slices;
}
void calc(time_t t){
I_accu+=dI*(t-last_time);
I=I_accu>>16;
last_time=t;
}
--
Pozdrawiam
Michoo
-
8. Data: 2012-10-09 16:49:30
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: "Robbo" <n...@g...com>
Serdeczne Bóg zapłać. Wszystko ładnie działa.
Robbo
-
9. Data: 2012-10-10 00:40:36
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: AlexY <a...@i...pl>
Użytkownik Robbo napisał:
> Serdeczne Bóg zapłać. Wszystko ładnie działa.
Jakie bóg zapłać? Chłopaki piwa by się napili ;)
--
AlexY
http://nadzieja.pl/inne/spam.html
http://www.pg.gda.pl/~agatek/netq.html
-
10. Data: 2012-10-10 12:03:17
Temat: Re: ATmega, jak zaprogramować narastanie wartości sygnału, bez użycia operacji zmiennoprzecinkowych?
Od: "Robbo" <n...@g...com>
Nie ma problemu. Chętnie wyślę pocztą dobre piwo z małego browaru, a nie
sikacz z koncernu.
R.