Optimierung von Rechnungen und If Schleife

Gast #1569302
Lesenswert?

int choosetable(){
if(startup==1){ allticks=15000; }
uint32_t calcticks=allticks;
if (allticks >= 3191) {
  if(allticks>= 11905 ){
                     coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[0]))/1800));
               coiloff=coilon+loadtime;
             startup=0;
             return 0;
             }//253-1260
  if(allticks>= 7075  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[2]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//1261-2120
  if(allticks>= 5034  ){
              coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[3]))/1800));
              coiloff=coilon+loadtime;
              return 0;
             }//2121-2980
  if(allticks>= 3906  ){
                       coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[4]))/1800));
                  coiloff=coilon+loadtime;
             return 0;
             }//2981-3840
  if(allticks>= 3191  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[5]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//3841-4700
}else{
  if(allticks>= 2698  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[6]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//4701-5560
  if(allticks>= 2336  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[7]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//5561-6420
  if(allticks>= 2060  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[8]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//6421-7280
  if(allticks>= 1843  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[9]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//7281-8140
  if(allticks>= 1667  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[10]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//8141-9000
  }
return 0;
}


Oben angefügt habe ich einen Codeabschnitt meines Programms mit dem ich 
leider so meine Probleme habe.

Die If Schleifen brauchen im Worst-case 25µs bei 20 Mhz und die Rechnung 
für den Wert coilon leider 70 µs.
Das Problem bei des Sache ist nur, dass es sich hier um eine 
zeitkritische Anwendung handelt bei der Werte für einen gesamten 
Durchlauf von 20-50 µs äußerst praktisch wären.

Gibt es Möglichkeiten den Code zu optimieren um Zeit zu sparen ?

Wenn ich oben calcticks als 16 bit Variable passiert spart es Zeit aber 
das Ergebniss wird zu ungenau. Dasselbe passiert wenn ich statt zu 
dividieren schieben um 11 benutze. Gibt es andere Möglichkeiten der 
optimierung ? Vor allem die IFs stören mich.


Bitte helft mir ich hab schon masseenhaft Foren ergebnisslos durchsucht.

mfg Manax
#1569470
Lesenswert?

Man kann es erstmal übersichtlicher schreiben:
1
void choosetable( void )
2
{
3
  uint8_t idx;
4

5
  if( startup==1 )
6
    allticks=15000;
7

8
  switch( allticks ){
9
    case 11905 ... 65535: idx = 0; startup = 1; break;
10
    case 7057 ... 11904: idx = 2; break;
11
    case 5034 ... 7056: idx = 3; break;
12
    case 3906 ... 5033: idx = 4; break;
13
    case 3191 ... 3905: idx = 5; break;
14
    case 2698 ... 3190: idx = 6; break;
15
    case 2336 ... 2697: idx = 7; break;
16
    case 2060 ... 2335: idx = 8; break;
17
    case 1843 ... 2059: idx = 9; break;
18
    case 1667 ... 1842: idx = 10; break;
19
    default: return;
20
  }
21
  coilon = allticks - loadtime
22
  - ((uint32_t)allticks*(vorzuendung+zzp1[idx]))/1800;
23
  coiloff = coilon+loadtime;
24
}

Wenn Du mal in Worten beschreiben würdest, wozu das gut ist, könnte man 
wohl auch noch optimieren.


Peter
Gast #1570111
Lesenswert?

Rolf Magnus schrieb:
>> case 11905 ... 65535: idx = 0; startup = 1; break;
>
> Man sollte sich aber bewußt darüber sein, daß das kein Standard-C,
> sondern eine Erweiterung des gcc ist.

als Pseudocode betrachten, ist lesbarer.
MfG
#1570142
Lesenswert?

Manax schrieb:
> Wenn ich oben calcticks als 16 bit Variable passiert spart es Zeit aber
> das Ergebniss wird zu ungenau. Dasselbe passiert wenn ich statt zu
> dividieren schieben um 11 benutze.

Warum ist das zu ungenau ?
Was sind das überhaupt für nen Haufen Werte?
Sind das Konstanten, kannst Du doch beim Compilieren den Korrekturfaktor 
2048/1800 einfach mit reinrechnen lassen.
Die Division ist jedenfalls das mit Abstand teuerste.
Und wenns ein ATmega ist, ist die Multipikation auch nicht so schlimm.

Wenn "allticks" bei jedem Aufruf konstant hoch- oder runterzählt, dann 
kann man die Rechnung auf eine einzige Addition verkürzen.
Die Tabelle enthält dann nicht mehr Faktoren, sondern die Schrittweite.
Das ist dann am schnellsten.

> Vor allem die IFs stören mich.

Die stören vielleicht optisch, von der Rechenzeit her sind es Pinats.

Was mich daran stört, ist das 10-fach Copy&Paste-Monster.
Es wird doch fast immer das gleiche gemacht, als ab damit ans Ende und 
nicht 10-mal kopieren.


Peter
Gast #1570143
Lesenswert?

Vielen dank für eure schnelle Hilfe.
Der Hinweis mit dem case hat mich gerettet wusste gar nicht,dass das so 
funktioniert. (Spart mir schonmal 7µs ) macht die Sache übersichtlicher 
und vor allem erweiterbar.

Assembler kann ich leider nicht programmieren.
Ich würde die Division gerne rausziehen allerdings ist 
vorzuendung+zzp[idx] ein so kleiner Wert, dass die Rechnung viel zu 
ungenau wird.Allticks ist eine Variable.


Zur grundsätzlichen Funktion des Programms:

Dieser Programmteil soll die Zündverzögerung einer Zündung mit 
Verstellkurve errechnen. Der Wert in µs ist gesucht mit einem globalen 
Wert (in 0.2 Grad Schritten )und einem speziellen auf die Drehzahl 
abgestimmten Wert (in 0.2 Grad Schritten).


mfg Manax
Gast #1570642
Lesenswert?

Peter Dannegger schrieb:
> Man kann es erstmal übersichtlicher schreiben:
> void choosetable( void )
> {
>   uint8_t idx;
>   if( startup==1 )
>     allticks=15000;>
>   switch( allticks ){
>     case 11905 ... 65535: idx = 0; startup = 1; break;
>     case 7057 ... 11904: idx = 2; break;
>     case 5034 ... 7056: idx = 3; break;
>     case 3906 ... 5033: idx = 4; break;
>     case 3191 ... 3905: idx = 5; break;
>     case 2698 ... 3190: idx = 6; break;
>     case 2336 ... 2697: idx = 7; break;
>     case 2060 ... 2335: idx = 8; break;
>     case 1843 ... 2059: idx = 9; break;
>     case 1667 ... 1842: idx = 10; break;
>     default: return;
> }

Könnte mir jemand diese GCC Erweiterung erklären, da ich nur Standard 
c(++) behersche.
Prüft der Switch ob sich Werte dazwischen befinden? z.B. zwischen 1667 
... 1842 und wenn ja, wird idx zu 10 gesetzt?
Gast #1570816
Lesenswert?

> Könnte mir jemand diese GCC Erweiterung erklären, da ich nur Standard
> c(++) behersche.

Das GCC-Handbuch kann das.

> Prüft der Switch ob sich Werte dazwischen befinden?

Nicht dazwischen, aber ob sie sich in dem angegebenen Bereich befinden, 
also inklusive den angegebenen Grenzwerten.

> z.B. zwischen 1667 ... 1842 und wenn ja, wird idx zu 10 gesetzt?

Ja.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren