Forum: Compiler & IDEs Bilineare Interpolation mit Festkomma


von Thomas (Gast)


Lesenswert?

Hallo,

versuche mich an einer bilinearen Interpolation von Stützstellen.
Da das ganze auf einem ATMega644 laufen soll versuche ich es so klein 
wie möglich zu halten.

Der Algorithmus an sich sollte schon Funktionieren.
Nur mit der Festkommaarithmetik bin ich unglücklich.

Vielleicht kann mir jemand einen Tip geben wie es besser geht !?

Das ist bis jetzt rausgekommen :
1
//x1|y1   x2|y1
2
//    |   |
3
//   -a---b-
4
//    | * |       * ux|uy
5
//    |   |
6
//   -c---d-
7
//    |   |
8
//x1|y2   x2|y2
9
//
10
//
11
// Wertebereich für die Stützstellen a,b,c,d 0 .. 255
12
//
13
// Werte für x1,y2 von 3..72
14
//
15
// Werte für y1,y2 von 20..100
16
//
17
18
19
20
struct  tQuadel  {
21
          uint8_t    a,b,    // die vier zu interpolierenden Eckwerte.
22
                c,d,
23
24
                x1,y1,  // die Eckwerte im Feld
25
                x2,y2,
26
27
                ux,uy,  // die zu interpolierende Stelle
28
                r;    // das result
29
        };
30
31
32
uint8_t calcBilinearInterpolation (struct tQuadel *quad)
33
{
34
  uint16_t  r1,    // für zwischenergebnisse
35
        r2,
36
        fx,    // Faktor
37
        fy;
38
39
  if ( (quad->x1 == quad->x2) || (quad->y1 == quad->y2) ) return 0;    // Wir machen keine Div durch 0
40
41
42
43
  fx    =  ((quad->ux - quad->x1) * 100) / (quad->x2 - quad->x1);    // Faktor für Gewichtung in X um 100 aufgeblasen
44
  fy    =  ((quad->uy - quad->y1) * 100) / (quad->y2 - quad->y1);    // Faktor für Gewichtung in Y um 100 aufgeblasen
45
46
  r1    =  quad->a * fx + quad->b * (100 - fx);            // LineareInterpolation zwischen a und b -> r1
47
  r2    =  quad->c * fx + quad->d * (100 - fx);            // LineareInterpolation zwischen c und d -> r2
48
49
  r1    =  r1      * fy + r2      * (100 - fy);            // LineareInterpolation zwischen a+b und c+d -> r
50
51
  quad->r  =  r1 / 100;                          // und wieder einfache Genauigkeit
52
53
  return quad->r;
54
}

von Thomas (Gast)


Lesenswert?

Wenn ich in meinem Wertebereich uint16_t bleiben will kann ich doch für 
meinen Faktor anstelle der 100 einfach 256 eintragen.
Denn ich blase den normierten Wert fx,fy der eigentlich 1 ist auf die 
256 auf ?

2^8 * 2^8 = 655535

von Ja (Gast)


Lesenswert?

Das untere Listing ist vom Compiler.

Es sind mit den Bibliotheksdivisionen ca 350 Befehle.
Seht ihr da noch irgendwo Optimierungspotential oder Fehler ?



1
0000026e <calcBilinearInterpolation>:
2
 26e:  0f 93         push  r16
3
 270:  1f 93         push  r17
4
 272:  cf 93         push  r28
5
 274:  df 93         push  r29
6
 276:  ec 01         movw  r28, r24
7
 278:  2c 81         ldd  r18, Y+4  ; 0x04
8
 27a:  6e 81         ldd  r22, Y+6  ; 0x06
9
 27c:  26 17         cp  r18, r22
10
 27e:  09 f4         brne  .+2        ; 0x282 <calcBilinearInterpolation+0x14>
11
 280:  63 c0         rjmp  .+198      ; 0x348 <calcBilinearInterpolation+0xda>
12
 282:  4d 81         ldd  r20, Y+5  ; 0x05
13
 284:  0f 81         ldd  r16, Y+7  ; 0x07
14
 286:  40 17         cp  r20, r16
15
 288:  09 f4         brne  .+2        ; 0x28c <calcBilinearInterpolation+0x1e>
16
 28a:  5e c0         rjmp  .+188      ; 0x348 <calcBilinearInterpolation+0xda>
17
 28c:  30 e0         ldi  r19, 0x00  ; 0
18
 28e:  98 85         ldd  r25, Y+8  ; 0x08
19
 290:  70 e0         ldi  r23, 0x00  ; 0
20
 292:  62 1b         sub  r22, r18
21
 294:  73 0b         sbc  r23, r19
22
 296:  80 e0         ldi  r24, 0x00  ; 0
23
 298:  92 1b         sub  r25, r18
24
 29a:  0e 94 9c 02   call  0x538  ; 0x538 <__divmodhi4>
25
 29e:  fb 01         movw  r30, r22
26
 2a0:  24 2f         mov  r18, r20
27
 2a2:  30 e0         ldi  r19, 0x00  ; 0
28
 2a4:  99 85         ldd  r25, Y+9  ; 0x09
29
 2a6:  60 2f         mov  r22, r16
30
 2a8:  70 e0         ldi  r23, 0x00  ; 0
31
 2aa:  62 1b         sub  r22, r18
32
 2ac:  73 0b         sbc  r23, r19
33
 2ae:  80 e0         ldi  r24, 0x00  ; 0
34
 2b0:  94 1b         sub  r25, r20
35
 2b2:  0e 94 9c 02   call  0x538  ; 0x538 <__divmodhi4>
36
 2b6:  ab 01         movw  r20, r22
37
 2b8:  60 e0         ldi  r22, 0x00  ; 0
38
 2ba:  71 e0         ldi  r23, 0x01  ; 1
39
 2bc:  db 01         movw  r26, r22
40
 2be:  ae 1b         sub  r26, r30
41
 2c0:  bf 0b         sbc  r27, r31
42
 2c2:  89 81         ldd  r24, Y+1  ; 0x01
43
 2c4:  90 e0         ldi  r25, 0x00  ; 0
44
 2c6:  a8 9f         mul  r26, r24
45
 2c8:  90 01         movw  r18, r0
46
 2ca:  a9 9f         mul  r26, r25
47
 2cc:  30 0d         add  r19, r0
48
 2ce:  b8 9f         mul  r27, r24
49
 2d0:  30 0d         add  r19, r0
50
 2d2:  11 24         eor  r1, r1
51
 2d4:  88 81         ld  r24, Y
52
 2d6:  90 e0         ldi  r25, 0x00  ; 0
53
 2d8:  8c 01         movw  r16, r24
54
 2da:  e0 9f         mul  r30, r16
55
 2dc:  c0 01         movw  r24, r0
56
 2de:  e1 9f         mul  r30, r17
57
 2e0:  90 0d         add  r25, r0
58
 2e2:  f0 9f         mul  r31, r16
59
 2e4:  90 0d         add  r25, r0
60
 2e6:  11 24         eor  r1, r1
61
 2e8:  28 0f         add  r18, r24
62
 2ea:  39 1f         adc  r19, r25
63
 2ec:  24 9f         mul  r18, r20
64
 2ee:  80 01         movw  r16, r0
65
 2f0:  25 9f         mul  r18, r21
66
 2f2:  10 0d         add  r17, r0
67
 2f4:  34 9f         mul  r19, r20
68
 2f6:  10 0d         add  r17, r0
69
 2f8:  11 24         eor  r1, r1
70
 2fa:  8b 81         ldd  r24, Y+3  ; 0x03
71
 2fc:  90 e0         ldi  r25, 0x00  ; 0
72
 2fe:  a8 9f         mul  r26, r24
73
 300:  90 01         movw  r18, r0
74
 302:  a9 9f         mul  r26, r25
75
 304:  30 0d         add  r19, r0
76
 306:  b8 9f         mul  r27, r24
77
 308:  30 0d         add  r19, r0
78
 30a:  11 24         eor  r1, r1
79
 30c:  8a 81         ldd  r24, Y+2  ; 0x02
80
 30e:  90 e0         ldi  r25, 0x00  ; 0
81
 310:  dc 01         movw  r26, r24
82
 312:  ea 9f         mul  r30, r26
83
 314:  c0 01         movw  r24, r0
84
 316:  eb 9f         mul  r30, r27
85
 318:  90 0d         add  r25, r0
86
 31a:  fa 9f         mul  r31, r26
87
 31c:  90 0d         add  r25, r0
88
 31e:  11 24         eor  r1, r1
89
 320:  28 0f         add  r18, r24
90
 322:  39 1f         adc  r19, r25
91
 324:  64 1b         sub  r22, r20
92
 326:  75 0b         sbc  r23, r21
93
 328:  26 9f         mul  r18, r22
94
 32a:  c0 01         movw  r24, r0
95
 32c:  27 9f         mul  r18, r23
96
 32e:  90 0d         add  r25, r0
97
 330:  36 9f         mul  r19, r22
98
 332:  90 0d         add  r25, r0
99
 334:  11 24         eor  r1, r1
100
 336:  80 0f         add  r24, r16
101
 338:  91 1f         adc  r25, r17
102
 33a:  89 2f         mov  r24, r25
103
 33c:  9a 87         std  Y+10, r25  ; 0x0a
104
 33e:  df 91         pop  r29
105
 340:  cf 91         pop  r28
106
 342:  1f 91         pop  r17
107
 344:  0f 91         pop  r16
108
 346:  08 95         ret
109
 348:  80 e0         ldi  r24, 0x00  ; 0
110
 34a:  df 91         pop  r29
111
 34c:  cf 91         pop  r28
112
 34e:  1f 91         pop  r17
113
 350:  0f 91         pop  r16
114
 352:  08 95         ret

von Thomas (Gast)


Lesenswert?

Kann man da noch ein bisschen Geschwindigkeit rauskitzeln ?
(wenn man in C programmiert)

von Uwe .. (uwegw)


Lesenswert?

Wie du schon geschrieben hast, ein Faktor von 256 wäre besser, weil sich 
das einfach durch hinzufügen bzw. Weglassen eines Bytes machen lässt. 
Bei den Multiplikationen bringt das nicht viel, weil der AVR in Hardware 
multipliziert, aber die letzte Division geht schneller.

von Thomas (Gast)


Lesenswert?

Hmmm ja,
wobei der Compiler daraus immer noch ein "mul" macht.

Ich habe auch kein anderes Verfahren zum interpolieren gefunden das 
besser passt.
Beim <Inverse Distance Weightning> hätte ich sogar noch eine Wurzel und 
Quadrat pro Stützstelle.
Das dürfte von Haus aus nicht besser werden.

Danke für Deine Zeit :)

von Uwe .. (uwegw)


Lesenswert?

Was macht er denn bei x<<8 ?

von Uwe .. (uwegw)


Lesenswert?

Mit avr-gcc (WinAVR 20100110) 4.3.3 und Optimierung -Os wird bei mir 
sowohl das Schieben um Acht Bits als auch die Multiplkation mit 256 zu 
Highbyte kopieren und Lowbyte löschen umgesetzt... (und bei der Division 
durch 256 ebenso)

von Thomas (Gast)


Lesenswert?

Man sehe und Staune !
1
thomas@quark:~/workspace/injektor test/Release$ diff div.lss shift.lss 
2
thomas@quark:~/workspace/injektor test/Release$

von Thomas (Gast)


Lesenswert?

Egal was für eine Optimierung.
Der GCC scheint garnicht so blöd...
1
thomas@quark:~/workspace/injektor test/Release$ diff div.lss shift.lss 
2
thomas@quark:~/workspace/injektor test/Release$ gcc -v
3
Using built-in specs.
4
COLLECT_GCC=gcc
5
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
6
Target: x86_64-linux-gnu
7
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.0-10' --with-bugurl=file:///usr/share/doc/gcc-4.6/REAgs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-multiarith-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-inclettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --enable-clocal--enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=ge--enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
8
Thread model: posix
9
gcc version 4.6.1 20110526 (prerelease) (Debian 4.6.0-10) 
10
thomas@quark:~/workspace/injektor test/Release$

von Thomas (Gast)


Lesenswert?

Wenn ich das richtig sehe kann die ALU immer nur um eine Stelle logisch 
sowie arithmetisch Schieben !?
Das erklärt einiges.

Dann sind die 2^8 zufällig richtig gut erwischt... ;)

von Simon K. (simon) Benutzerseite


Lesenswert?

Ja, die AVRs haben keinen Barrel Shifter. Da gehts immer nur 
Einerstellenweise (Im Binärsystem).

Ich erweitere auch oft gerne mit 2^8 oder 2^16, falls man eine hohe 
Genauigkeit benötigt. Man kann ja sogar das Teilen durch Kommazahlen mit 
2^(n*8) erweitern, sodass man keine Gleitkommatypen mehr benötigt :-)

Unter Anderem habe ich sowas beispielsweise bei der Umwandlung von 
geographischen Koordinaten (NMEA) in einen linearen 24 Bit Bereich 
benutzt. Da muss die Genauigkeit ja sehr hoch sein.

von Thomas (Gast)


Lesenswert?

Ähm das mit der Genauigkeit verwirrt mich.

Der maximalen Fehler den ich mache ist doch Wertebereich * kleinste 
Darstellbare Zahl im Faktor:
(Für n = 1)

Liege ich damit richtig ?

Dann ist n eine hübsche Stellschraube :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.