Robbo
Guest
Mon Oct 08, 2012 11:43 pm
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
Dondu
Guest
Tue Oct 09, 2012 4:12 am
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-bresenhama.html
Michoo
Guest
Tue Oct 09, 2012 7:29 am
On 09.10.2012 01:43, Robbo wrote:
Quote:
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
Piotr Gałka
Guest
Tue Oct 09, 2012 8:06 am
Użytkownik "Robbo" <niemam@gmail.com> napisał w wiadomości
news:5073652e$0$26682$65785112@news.neostrada.pl...
Quote:
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, 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.
Piotr Gałka
Guest
Tue Oct 09, 2012 8:18 am
Użytkownik "Piotr Gałka" <piotr.galka@CUTTHISmicromade.pl> napisał w
wiadomości news:5073db09$1@news.home.net.pl...
Quote:
Użytkownik "Robbo" <niemam@gmail.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 KI, 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.
Robbo
Guest
Tue Oct 09, 2012 10:19 am
Witam,
Dziękuję za odpowiedź, która mam nadzieję naprowadzi mnie na właściwe tory.
Quote:
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.
Quote:
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
Quote:
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
Michoo
Guest
Tue Oct 09, 2012 10:50 am
On 09.10.2012 12:19, Robbo wrote:
Quote:
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.
Quote:
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
Robbo
Guest
Tue Oct 09, 2012 2:49 pm
Serdeczne Bóg zapłać. Wszystko ładnie działa.
Robbo
AlexY
Guest
Tue Oct 09, 2012 10:40 pm
Użytkownik Robbo napisał:
Quote:
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
Robbo
Guest
Wed Oct 10, 2012 10:03 am
Nie ma problemu. Chętnie wyślę pocztą dobre piwo z małego browaru, a nie
sikacz z koncernu.
R.
Michoo
Guest
Thu Oct 11, 2012 7:52 pm
On 10.10.2012 00:40, AlexY wrote:
Quote:
Użytkownik Robbo napisał:
Serdeczne Bóg zapłać. Wszystko ładnie działa.
Jakie bóg zapłać? Chłopaki piwa by się napili ;)
Łączę zainteresowanie elektroniką i piwem:
http://grota.be/photos/016/chmiel.jpg
http://grota.be/photos/016/gotowanie.jpg
http://grota.be/photos/016/temp.png
--
Pozdrawiam
Michoo