floating point coprocessor

OP #1312916
Lesenswert?

Hallo Leute,
ich brauche für mein Projekt sehr viele Berechnungen, die ich in 
kürzester Zeit rechnen muss. Ich verwende einen 8bit-AVR(die bekanntlich 
nicht die schnellsten sind). Auf einen ARM oder ähnliches umzusteigen 
ist schon zu spät.
Lohnt es sich, einen math-Coprocessor zu benutzen? Hat man dadurch große 
Ersparnisse?

Ich habe an sowas wie den hier gedacht: 
http://www.sparkfun.com/commerce/pr.....info.php?products_id=8129

Hat jemand Erfahrungen mit sowas gemacht? Oder kennt jemand vielleicht 
ein besseres Modell?

Gruß, Yaro
Gast #1312951
Lesenswert?

Die FPU ist selber nicht die schnellste und wahrscheinlich nur eine 
Software-FPU.

Alternativ kann man auch schnellere uCs nehmen  z.B. mit 20Mhz oder eine 
extra uC als FPU programmieren. Es gibt auch Look up Tabellen.
OP #1312953
Lesenswert?

Ja... den Rechenaufwand abschätzen ist nicht ganz so einfach, wie ich es 
mir vorgestellt hatte...
Hatte noch nie ein so Zeitintensives Projekt, dass ich jeden einzelnen 
Takt zählen musste, wie ich es jetzt tue. Aber man lernt bekanntlich nie 
aus.

Ist die Zeitersparniss mit diesem CoProzessor groß genug, dass es sich 
empfielt, ihn zu benutzen?

Gruß, Yaro
OP #1312966
Lesenswert?

Ich benutze schon einen 20MHz AVR.
Ich denke, ein FPU ist schneller, weil es 32bit Architektur hat.

Lookup-Tabellen habe ich schon einige implementiert, aber für einige 
Anwendungen müssten sie so groß sein, dass sie nicht in den Flash 
passen.

Gruß, Yaro


Edit: der Link am Anfang hat nicht funktioniert, hier ist er nochmal:
http://www.sparkfun.com/commerce/product_info.php?products_id=8129
Gast #1312983
Lesenswert?

moin moin,

als FPU nutze ich einen C8051F365( 1Takt Core) der mit 98MHz tackert.
In einem 8051ED2 (22MHz, 6Takte-Core) braucht ein SIN ca. 900µs.
Die FPU ist über SPI angebunden, der MainMC kann also auch was anderes 
sein.
Mit FPU inklusive SPI braucht es für einen SIN-Wert nur 95µs.
Die FloatLib ist auch im MC vorhanden, teilweise rechnen beide 
gleichzeitig und das spart.

Mit Gruß
Pieter
Gast #1313060
Lesenswert?

Eine gute  FPU bringt sicher Zeitersparnis. Aber diese FPU ist nicht 
sonderlich schnell (siehe Datenblatt). Sinus berechnen 100 µs - ohne 
senden, empfangen, sonstiges.

Evtl kannst du mehrere nehmen oder eine andere.

Oder zusätzliche Lookup Tabelle in externem EEpron etc...
#1313065
Lesenswert?

an einen AVR ne FPU stricken, naja...
Wenn man merkt, es reicht hinten und vorne nicht - umsteigen.
Ich behaupte mal, den Performance-Gewinn büsst du durch Transferzeiten 
wieder ein. Sinn macht es erst dann, wenn du Funktionen auslagern 
kannst, in der Zwischenzeit was anderes machst und dann weiter im 
eigentlichen Text. Ob ein AVR-Compiler sowas kann? Eher wirst du stupide 
warten müssen.
Gibt Rechenleistung satt, ARM.
Gast #1313071
Lesenswert?

> Hatte noch nie ein so Zeitintensives Projekt, dass ich jeden einzelnen
Takt zählen musste,

Ja was rechnest du denn ?

Wirklich floating point, oder taete es auch soundsoviel bit fixed point 
?

Sinus und Wurzel, oder nur Addition und Multiplikation ?

Eine richtige floating-point-implementation auf einem 8 bit Rechner ist 
langsam, locker 1000 mal langsamer als ein arithmetic-coprozessor, der 
es meist in 1 Takt macht, aber in vielen Faellen braucht man gar keine 
floating point Funktionen um etwas korrekt auszurechnen.
OP #1313851
Lesenswert?

Ich brauche öfters Winkelfunktionen (sin, cos usw.), und muss auch ab 
und zu floats teilen und multiplizieren. Wurzeln brauche ich auch 
manchmal, aber meißt mit einer nicht ganz so großen genauigkeit, da habe 
ich eine Ersatzfunktion geschrieben, die deutlich schneller ist.
Lookup-Tabellen habe ich auch schon einige erstellt, klappt aber leider 
nicht für alle anwendungen. Optimirt habe ich auch schonn einge Menge, 
nur scheints, als ob das alles nicht genug sein wird. Ich komme im 
Moment mit der Leistung zwar noch hin, aber das sollte nicht mehr lange 
der Fall sein, denn ich brauche immer mehr Winkelfunktionen, die ich 
kaum ersetzen kann, und die Genaugkeit der floats ist auch z.T. 
notwendig.

Der co.Prozessor hat eine 32bit Architektur, deswegen habe ich gehofft, 
dass er viel schneller ist. Aber 100µs für einen sin, ist ja 
genausoviel, wie ein ATmega (mit 16MHz) braucht, da kann ich ja gleich 
einen zweiten ATmega  anschließen...
Wie kann denn sowas eigentlich sein? das Ding arbeitet mit 30MHz mit 
einer 32bit Architektur, und ist dabei genauso schnell, wie ein AVR mit 
einer 8bit Architektur und 16MHz

Kennt jemand eine FPU, die deutlich schneller ist, als diese hier?
Den sonnst lohnt es sich ja wirklich nicht, sie anzuschließen...

Gruß, Yaro
#1313939
Lesenswert?

Yaroslav Gevorkov schrieb:

> Wie kann denn sowas eigentlich sein? das Ding arbeitet mit 30MHz mit
> einer 32bit Architektur, und ist dabei genauso schnell, wie ein AVR mit
> einer 8bit Architektur und 16MHz

An 32 Bits glaube ich eher nicht. Das Äussere passt aber prima zu 
Microchips 16bittern dsPIC30F2011 und 3012. Das Tempo auch.
#1313945
Lesenswert?

Yaroslav Gevorkov schrieb:

> Kennt jemand eine FPU, die deutlich schneller ist, als diese hier?
> Den sonnst lohnt es sich ja wirklich nicht, sie anzuschließen...

Anno 386/486 gab es mal ein paar fixe externe Varianten. Von Weitek und 
so. Könnte aber sein, dass dir beim Anschluss rasch die Pins ausgehen. 
;-)

Schnelle externe FPU und pinsparender serieller Anschluss beisst sich 
etwas.

Aber komplette Controller, die sich für sowas ähnlich der uM-FPU 
programmieren lassen, gibt es durchaus. Diverse ARM7 und Cortex-M3 in 
TQFP48 beispielsweise. Weniger Pins gibt es zwar auch, aber kleiner ist 
ein SO28 effektiv auch nicht.
#1313978
Lesenswert?

Dann dürte das schnellste der Parallax Propeller sein, gibt's als DIP40. 
Da streiten sich dann 8 Stück 32bit Prozessoren mit je 20 MIPS darum, 
wer den Job übernehmen darf. Könnte bei geeigneter Programmierung 
schnell genug sein, wobei aber kein Hardware-Multiplier mitspielt. Das 
Interface darfst du selbst erfinden, denn konzeptbedingt hat der kein 
vordefiniertes, und programmieren darfst du das in Assembler. 
Grösstenteils jedenfalls.

Andere 32bit Typen als DIP kenne ich nicht. Höchstens als Header-Board.
#1314042
Lesenswert?

Yaroslav Gevorkov schrieb:
> ich brauche für mein Projekt sehr viele Berechnungen, die ich in
> kürzester Zeit rechnen muss.

Das ist Wischiwaschi ohne jede Aussage.

Bevor Du ein Problem löst, mußt Du es erstmal kennen.

Also schätze mal ab, wieviel Rechnungen welcher Art Du in welcher Zeit 
benötigst.

Insbesondere beim Zeitbedarf  verschätzen sich viele.
Letztens war hier auch einer, der wollte alle 10ms Werte auf ein LCD 
ausgeben. Also völlig unsinnig schnell, das hätte keiner ablesen können.
Bei ergonomischer Ausgabe ergab sich dann eine CPU-Auslastung von gerade 
mal 1%.


Peter
Gast #1314160
Lesenswert?

> Pins sind nicht das große Problem, 9 Stück hätte ich übrig,

Für mindestens 32 bit float coprozesor ?

Du beliebst zu scherzen.

Wie wäre es mit 102 pins ? 32 a Wert, 32 b Wert 32 Ergebnis, und 6 für 
die Operation.


Vergiss den Ansatz, wechsel den Prozessor, gleich in einem mit schneller 
Arithmetik.
Gast #1314194
Lesenswert?

Was ich nicht verstehe:
Warum ist es zu spät den µC zu wechseln, wenn du aber bereit bist noch 
mal grundlegend die Hardwarekonfiguration (FPU hinzufügen) zu ändern?

Ich hab mal auf nem 32bit DSP  (Blackfin) gemessen, was ne floatingpoint 
library braucht und wies mit fixpoint arithmetik das verhältnis war 
1:1000 also wirds mit nem 8bit processor mindestens 5 mal so lange 
dauern.

Aber insgesammt schließe ich mich meinem vorschrebern an:
lös das ganze von anfang an in fixpoint.

was hast du den nfür ne anwendung? erzähl mal! wo kommen die 
Eingangsdaten daten und was machst du damit und was soll rauskommen.

Es gibt zwar extreme Fälle, wo es mit 32bit fixpoint enorm schwierig ist 
und man auf 64 asuweichen muss, aber die sind sehr speziell.

Im extremfall nimm nen SPI flash (SD-Karte) mit ein paar MB und pack den 
randvoll mit LUTs für alle deine Funktionen. musst dann halt so 
programmieren, dass due das ergebnis ein paar zyklen vorher anforderst.
Hab aber keine Ahnung ob sich das lohnt, oder ob die Kommunikation zu 
langsam ist.
Gast #1314199
Lesenswert?

@Yaroslav

überlege vllt dochmal nochmal ein externes flash (z.b. at45db161, das 
hat 2mbyte) zu verwenden.
ich brauche z.b. filterkoeffizienten die ich im avr berechnen möchte. 
die ursprüngliche formel enthält x^y (wobei x keineswegs eine schöne 
gerade zahl ist, sondern 1,095irgendwas), tan div. divisionen 
multiplikationen und additionen. ein sprung war es die berechnung von 
x^y und tan in eine tabelle zu packen ... das hat mir einen enormen 
geschwindigkeitszuwachs gegeben. nur bin ich aus speicherplatzgründen 
dazu übergegangen die filterkoeffizienten vorberechnet in das flash zu 
packen. von den 2 mbyte sind somit gerademal 128kbyte übriggeblieben. 
nun hab ich 4 verschiedene filtertypen mit 512 frequenz und jeweils 64 
verschiedenen resonanzpunkten.
und die geschwindigkeitssteigerung möcht ich gar nicht erst erwähnen.
ok ich habs noch nicht ermittelt wie schnell es ist, aber ich habe für 
eine berechnung vorher 1.5ms benötigt (schon die erste 
optimierungsstufe) und nun muß ich nur ein paar bytes an das dataflash 
schicken und habe einen fast fertigen koeffizienten-satz (besteht aus 4 
long worten).
OP #1314241
Lesenswert?

@vlad: zu Spät den Controller zu wechseln ist es, weil ich das Projekt 
zum Herbst fertig haben muss, und mir einfach die Zeit fehlt, 2Wochen zu 
investiren, um z.B. mit einem ARM gut genug umgehen zu können.
Eine FPU kann ich über SPI anbinden und brauche nichtmal das 
fertig-designte Board umzudesignen (es ist auch so schon kein Platz mehr 
drauf).
Das mit externem Speicher habe ich mir auch schon überlegt, aber mir 
scheint die Lösung mit 2 Prozessoren besser. (aber ich werde noch weiter 
drüber nachdenken)
Das Projekt ist ein Hexapod. Er hat ziemlich lange beine und soll mit 
denen auch elegant umgehen können. Dafür braucht man undglaublich viel 
Mathematik, und leider auch sehr viele Winkelfunktionen.

@avr: Die xmegas sind schon tolle Dinger! Leider gibt es sie aber nur in 
SMD, und auch auf sie muss man sich erstmal umstellen.
Ich verwende einen ATmega 644 mit 20MHz, das Board ist schon fertig.
Aber über den Dataflash werde ich nochmal nachdenken.

@TheMason:Ich habe auch schon einige Funktionen so beschleunigt, aber 
bisher nur da, wo ich nur wenig Genauigkeit brauchte.
Das Problem beim jetzigen Projekt ist, dass ich wirklich die volle 
Bandbreite der sin und arcsin Funktionen ausnutzen muss.
Ich werde mir nochmal überlegen, welche Genauigkeit ich brauche, und 
vielleicht einen externen speicher verwenden.

Gruß, Yaro
Gast #1314410
Lesenswert?

>Eine FPU kann ich über SPI anbinden und brauche nichtmal das
>fertig-designte Board umzudesignen (es ist auch so schon kein Platz mehr
>drauf).

wenn kein Platz ist, wie bekommst du dann die FPU drauf?
aber egal


Ich würd wie gesagt das ganze in fixpoint rechnen.
Was ist das für ein Projekt? Uni/privat/job?
kannst du den Code Zeigen? interessiert mich einfach ob das wirklic so 
schwierig ist. Was für ein AVR hast du? wenn du ne komplette float lib 
(sin, tan, sqrt, ...) verwendest muss der doch schon davon recht voll 
sein.

Machen auf Arbeit bei uns auch alles in fixpoint, weil unser Blackfin 
(32bit 500MHz dualcore DSP - derer sind es zwei) keine FPU hat. Und es 
geht natürlich auch.
Gast #1314445
Lesenswert?

> Das Projekt ist ein Hexapod. Er hat ziemlich lange beine und soll mit
> denen auch elegant umgehen können. Dafür braucht man
> undglaublich viel Mathematik, und leider auch sehr viele
> Winkelfunktionen.

Und die müssen unbedingt in float sein? Du schriebst was von 
Genauigkeit. float ist weniger genau als 32bit fixed-point. Nur der 
Wertebereich ist größer, da sich die Schrittweite an den Wert anpasst.

> Das Problem beim jetzigen Projekt ist, dass ich wirklich die volle
> Bandbreite der sin und arcsin Funktionen ausnutzen muss.

Naja, das Ergebnis eines sin liegt z.B. im Bereich +/- 1. Da würde dir 
ein 32-bit-fixed-point-Wert eine Schrittweite von 4,7*10^-10 geben. 
Floating-Point hatte da nur bei sehr kleinen Werten Vorteile, sonst nur 
Nachteile, da die Mantisse inklusive Vorzeichen nur 24 Bit hat.
OP #1314538
Lesenswert?

@vlad: ich benutze einen ATmega644p, er hat 64kB Flash, also genug 
Platz, um funktionen unterzubringen.
tan brauche ich nicht, nur sin cos und arccos. Außerdem brauche ich 
öfters Wurzeln.
Bei arccos brauche ich keine große Genauigkeit, deswegen habe ich das 
mit einer lookup-Tabelle gemacht. (diese Funktionen habe ich nciht mit 
reingestellt, weil sie nur sehr wenig Takte brauchen).
Die zusätzliche FPU hätte ich an ein seperates Board gehängt, dass ich 
sowieso verwende. mit SPI könnte ich es dann gut anschließen.

Ich kann hier ja mal ein Beispiel geben (im Anhang). Dies ist eine 
Funktion, der man einen bestimmten Punkt im Raum angibt, und sie dann 
die jeweiligen Wiinkel der 3 Servos rausgibt. Hier habe ich auch die 
erwähnten arccos lookups verwendet. Nicht über die vielen Casts wundern, 
sie sind tatsächlich notwendig =). Die ausführung dieser Funktion dauert 
zwischen 3 und 6 Tausend Takten (abhängig vom Punkt, der angefahren 
werden soll).
Im moment bin ich gerade noch dabei, den Code zu schreiben, er ist also 
lange noch nicht fertig, deswgen kann ich auch keinen vollen Code 
zeigen.
Gerade jetzt arbeite ich daran, funktionen für den gang um einen 
bestimmten Radius zu erstellen. Diese habe ich zwar zum großen Teil 
schon auf Pappier, aber noch nicht in Code umgesetzt. Wenn ich das aber 
tuhe, stoße ich bald schon an die leistungsgrenze.
Ich habe auch noch vor, sehr viele andere funktionen zu schreiben, die 
sicherlich noch mehr Leistung brauchen werden, deswegen bemühe ich mich 
jetzt schon darum, vorzusorgen, um später nicht das Nachsehen zu haben.
1
void setdeg(int8_t x1signed,uint8_t x2,uint8_t x3, uint8_t *alpha1, uint8_t *alpha2, uint8_t *alpha3){
2
  uint8_t x1,a1,a2,a2m,a2p,a3, neg = 0;
3
  float ds,d12,d123,temp1,temp2;
4
  uint8_t os = 130, us = 150, s = 28;
5

6
  if(x1signed < 0){
7
    x1 = (uint8_t)(x1signed * (-1)) * 2;
8
    neg = 1;
9
  }else{
10
    x1 = (uint8_t)x1signed * 2;
11
  }
12

13
  d12 = (float)sqrt((float)((uint32_t)(uint16_t)(x1*x1) + (uint32_t)(uint16_t)(x2*x2)));
14
  a1 = arccos1024flash((uint16_t)(((x2*256)/d12)*4), arccostab1024flash);
15
  if(a1 <= 10){
16
    a1 = arccos4096flashmini((uint16_t)(((uint32_t)x2*4096)/d12), arccostab4096flashmini);
17
  }
18
  ds = d12 - s;
19
  d123 = (float)sqrt((float)(ds*ds + (uint32_t)(uint16_t)(x3*x3)));
20
  a2m = arccos1024flash((uint16_t)((ds*128/d123)*8), arccostab1024flash);
21
  if(a2m <= 10){
22
    a2m = arccos4096flashmini((uint16_t)(ds*4096/d123), arccostab4096flashmini);
23
  }
24
  a2p = arccos1024flash((uint16_t)(((uint16_t)(os*os)+d123*d123-(uint16_t)(us*us))*514/(os*d123)), arccostab1024flash);
25
  if(a2p <= 10){
26
    a2p = arccos4096flashmini((uint16_t)(((uint16_t)(os*os)+d123*d123-(uint16_t)(us*us))*2048/(os*d123)), arccostab4096flashmini);
27
  }
28
  a2 = a2p - a2m;
29
  a3 = arccos1024flash((uint16_t)(((uint16_t)(us*us)+(uint16_t)(os*os)-d123*d123)*514/((uint16_t)(us*os))), arccostab1024flash);
30
  if(a3 <= 10){
31
    a3 = arccos4096flashmini((uint16_t)(((uint16_t)(us*us)+(uint16_t)(os*os)-d123*d123)*2048/((uint16_t)(us*os))), arccostab4096flashmini);
32
  }
33

34

35
  if(neg){
36
    a1 = 90 - a1;
37
  }else{
38
    a1 += 90;
39
  }
40

41
  a2 += 90;
42

43
  *alpha1 = a1;
44
  *alpha2 = a2;
45
  *alpha3 = a3;
46
}

@Rolf: Das Projekt ist eigentlich Privat, aber ich will es als 
"besondere Lernleistung" ins ABI mit einbringen, deswegen muss es auch 
im Herbst fertig sein.
Mit fixpoint habe ich leider noch nie zutun gehabt, gut Möglich, dass es 
tatsächlich besser geeignet ist.

Edit: ich habe mir gerade ein Tutorial angeschaut, und wenn das, was 
dort gesagt urde richtig ist, dann habe ich Fixpoint schon verwendet, 
nämlich bei meinen arccos-funktionen (habe dann allerdings die 
Nachkommastellen vernachlässigt, weil ich sie nicht brauche).
Ich bruache insgesammt keine extrem große genauigkeit, allerdings 
brauche ich bei einigen eher seltenen Anwendungen schon so ca. 10 
Nachkommastellen. Deswegen habe ich da, wo ich diese Nachkommastellen 
brauche, auch floats eingesetzt.
Kann man sin und cos in fixedpoint rechnen? Wenn ja, wieviel schneller 
wird es dadurch (wenn man genauigkeit ungefähr beibehalten will)?

Insgesammt habe ich jetzt überlegt die Aufteilung der Rechenleistung 
besser zu gestalten, indem ich auf Reaktionszeit verzichte. So wie ich 
mir das jetzt überlegt habe (mit 2 Controllern), wobei der eine die 
dringenden Aufgaben rechnet, und der andere die, die etwas warten 
können, sollte ich mit der Zeit ganz gut hinkommen.
Angehängte Dateien:
Gast #1314571
Lesenswert?

> brauche ich bei einigen eher seltenen Anwendungen schon so ca.
> 10 Nachkommastellen. Deswegen habe ich da, wo ich diese
> Nachkommastellen brauche, auch floats eingesetzt.

Diese Genauigkeit hat float aber gar nicht. Etwa 6 signifikante Stellen 
(also Vor- und Nachkommastellen zusammen) hast du bei float.

> Kann man sin und cos in fixedpoint rechnen?

Klar. Vielleicht hilft dir das:

AVR-CORDIC könnte interessant sein, gefunden über
Beitrag "Sinus und Cosinus in einem µC ohne Fließkomma berechnen"
OP #1314589
Lesenswert?

Im selben forum habe ich folgendes gelesen:
Der Hauptvorteil vom CORDIC ist, dass man keine Multiplikationen
braucht, deshalb wird er gerne für Hardwareimplementierungen verwendet.
Wenn man aber sowieso schon einen Multiplizierer im Controller hat ist
Cordic nicht mehr unbedingt die beste Wahl.
Die ATmegas haben einen hardware-multiplikator.

Aber der Einwand mit den Floats ist richtig! Die sin-Funktion der 
Bibliothek liefert ja sowieso double zurück, da kann ich dann ja auch 
gleich double verwenden, bringt ja nicht viel mehr Aufwand (außer später 
dann, beim rechnen damit).
Aber wie gesagt, ich habe die Strukturierung des Programms nochmal 
überdacht, und dadurch (allerdings mit einigen kleinen Verlusten bei der 
Performance) eine Menge Zeit gewonnen. Die 1500Takte, die sin braucht, 
wirken sich dann nicht mehr so dramatisch aus.

Gruß, Yaro
Gast #1314660
Lesenswert?

Ich denke, Du kannst noch einiges kürzen. Dadurch wird der Code auch 
schneller.

Habe den folgenden Code leider nicht compilieren können, da ich auf den 
System, auf dem ich hier arbeite, keinen C Compiler habe. Bin mir 
deshalb fast sicher, dass noch ein paar Syntaxfehler drin sind.

Aber Du kannst Dir ja mal anschauen was ich gemacht habe, um die Idee zu 
verstehen:
1
/**
2
 * FUNCTION: 
3
 *   setDeg
4
 *
5
 * DESCRIPTION:
6
 *   Berechnet den Winkel für die Servos.
7
 *
8
 * PARAMETER:
9
 *   x1sgined  X-Koordinate, vorzeichenbehaftet
10
 *   x2        X-Koordinate, vorzeichenlos
11
 *   x3        X-Koordinate, vorzeichenlos
12
 *   *alpha1   Zeiger auf den Winkel für 1. Servo
13
 *   *alpha2   Zeiger auf den Winkel für 2. Servo
14
 *   *alpha3   Zeiger auf den Winkel für 3. Servo
15
 *
16
 * RESULT:
17
 *   (kein Rückgabewert)
18
 */
19

20
void setdeg(int8_t x1signed, uint8_t x2, uint8_t x3, uint8_t *alpha1, uint8_t *alpha2, uint8_t *alpha3)
21
{
22
  uint8_t a1;     /* 1. Winkel  */
23
  uint8_t a2;     /* 2. Winkel */
24
  uint8_t a2m; 
25
  uint8_t a2p;
26
  uint8_t a3;     /* 3. Winkel */
27
  uint32_t x1_2;  /* Quadrat der Koordinate X1 */
28
  uint32_t x2_2;  /* Quadrat der Korrdinate X2 */
29
  uint32_t x3_2;  /* Quadrat der Koordinate X3 */
30
  uint8_t os = 130, us = 150, s = 28;
31
  uint16_t os_2 = 16900, us = 22500, s = 784, us_os = 19500;
32
  float ds,d12,d123;
33

34
  /* X1-Koordinate vorbereiten */
35
  uint8_t x1 = (uint8_t)x1signed;
36
  
37
  if(x1signed < 0)
38
  {
39
    x1 *= -2;
40
  }
41
  else
42
  {
43
    x1 *= 2;
44
  }
45
  
46
  /* Koordinaten quadrieren */
47
  x1_2 = x1 * x1;
48
  x2_2 = x2 * x2;
49
  x3_2 = x3 * x3;
50
  
51
  /* Hilfsvariable d12 berechnen */
52
  d12 = sqrt((float)(x1_2 + x2_2));
53
  
54
  /* Winkel a1 berechnen */
55
  a1 = arccos1024flash((uint16_t)(1024*x2/d12), arccostab1024flash);
56
  
57
  if(a1 <= 10)
58
  {
59
    a1 = arccos4096flashmini(4096*(uint16_t)((uint32_t)x2/d12), arccostab4096flashmini);
60
  }
61
  
62
  /* Hilfsvariablen ds und d123 berechnen */
63
  ds = d12 - s;
64
  d123 = sqrt((float)(ds*ds + x3_2));
65
  
66
  /* winkel a2 berechnen */
67
  uint16_t h1 = (uint16_t)(ds / d123);
68
  a2m = arccos1024flash(1024 * h1, arccostab1024flash);
69
  
70
  if(a2m <= 10)
71
  {
72
    a2m = arccos4096flashmini(4096 * h1, arccostab4096flashmini);
73
  }
74
  
75
  uint16_t h2 = (uint16_t)((os_2 + d123 * d123-us_2)) / (os * d123);
76
  
77
  a2p = arccos1024flash(514 * h2), arccostab1024flash);
78
  
79
  if(a2p <= 10)
80
  {
81
    a2p = arccos4096flashmini(2048 * h2), arccostab4096flashmini);
82
  }
83
  
84
  a2 = a2p - a2m;
85
  
86
  /* Winkel a3 berechnen */
87
  uint16_t h3 = (uint16_t)((us_2 + os_2-d123*d123)/us_os);
88
  
89
  a3 = arccos1024flash(514 * h3, arccostab1024flash);
90
  
91
  if(a3 <= 10)
92
  {
93
    a3 = arccos4096flashmini(2048 * h3, arccostab4096flashmini);
94
  }
95

96

97
  /* Winkel a1 und a2 spiegeln */
98
  if(x1signed < 0)
99
  {
100
    a1 = 90 - a1;
101
  }
102
  else
103
  {
104
    a1 += 90;
105
  }
106

107
  a2 += 90;
108

109
  /* Winkel an den Aufrufer zurückgeben */
110
  *alpha1 = a1;
111
  *alpha2 = a2;
112
  *alpha3 = a3;
113
}
OP #1314673
Lesenswert?

Wofür ich so genaue wert brauche ist z.B. folgendes:
Der Hexa muss um einen bestimmten Radius gehen (Kurve), dabei müssen die 
Füße auch einem bestimmten Radius folgen. Der Radius solltte nicht 
größer als 3m werden. Die auflösung, in der die Füße bewegt werden 
sollen, soll 1-2mm sein. Die Drehung mache ich mit einer Drehmatrix, die 
sin und cos des Winkels braucht, um den gedreht werden soll.
Bei maximalem Radius 2m und bester Auflösung 1mm ergibt sich mit 
arctan(1/2000) ein Winkel von 0.02864788737°. Da der Radius so weit weg 
ist, machen sich sogar kleine Veränderungen des Winkels auf die 
Schrittweite bemerkbar. Bei kleinerem Radius ist die Genauigkeit dann 
nicht mehr so wichtig.
Der Sinus von diesem (kleinstnötigen)Winkel ist 0,000499999°.
Eine Genauigkeit von mindestens 6 Nachkommastellen würde wahrscheinlich 
ausreichen.
Wieso die Auflösung so ganau sein muss ist leicht zu erklären: wenn der 
fuß auf dem Boden steht, und sich bewegt (d.h. den Körper bewegt), muss 
er ziemlich genau sein, damit sich die Füße in ihrer gesammteheit nicht 
in verscheidene Richtungen bewegen, und damit Spannungen erzeugen.

Kennt ihr vielleicht ein gutet tutorial, wo man fixpointrechnung gut 
lernen kann?

Gruß, Yaro

Edit: hallo "Gast", du hast deinen Beitrag gerade dann geschrieben, als 
ich meinen geschrieben habe, ich lese ihn mir gleich durch, und 
beantworte ihn auch schnellstmöglich.
OP #1314723
Lesenswert?

@Gast: Erstmal vielen Dank, dass du dir so viel Mühe gemacht hast, den 
Code zu überarbeiten!

Viele Sachen, die du geändert hast, bringen aber leider keine 
Verbesserung, weil der Preprozessor sie schon rechnet. Zum beispiel das 
quadrieren der Konstanten gehört dazu. Moderne Compiler berücksichtigen 
sowas.

das hier:
1
/* X1-Koordinate vorbereiten */
2
  uint8_t x1 = (uint8_t)x1signed;
3
  
4
  if(x1signed < 0)
5
  {
6
    x1 *= -2;
7
  }
8
  else
9
  {
10
    x1 *= 2;
11
  }
habe ich zum Anlass genommen, diese Routine noch weiter zu verbessern:
1
  /* X1-Koordinate vorbereiten */
2
  if(x1signed < 0){
3
    neg = 1;
4
  }
5
  x1 = (uint8_t)(x1signed << 1);

das hier:
1
a1 = arccos1024flash((uint16_t)(1024*x2/d12), arccostab1024flash);
ist wirklich schlauer, als das, was ich gemacht habe. (mit 256 und dann 
mit 4 multipliziert).
Gedacht war es von mir eigentlich so: warum eine 16bit Multiplikation 
machen, wenn man eine 8bit Multiplikationen machen kann und sie dann 2 
mal logisch nach links schieben kann (das mach der Compiler, wenn man *4 
rechnet), was schneller ist (allerdings würde damit auch genauigkeit 
eingebüßt werden). Berücksichtigt habe ich nicht, dass 256 ja keine 8bit 
mehr sind...

das hier:
1
/* winkel a2 berechnen */
2
  uint16_t h1 = (uint16_t)(ds / d123);
3
  a2m = arccos1024flash(1024 * h1, arccostab1024flash);
4
  
5
  if(a2m <= 10)
6
  {
7
    a2m = arccos4096flashmini(4096 * h1, arccostab4096flashmini);
8
  }
verfehlt den Zweck, denn so gibt es keinen genauigkeitsgewinn von 
arccos1024flash auf arccos4096flashmini, weil der Wert gerundet wird, 
bevor er mit 1024/4096 multipliziert wird. Er muss zuerst multipliziert 
und anschlißend geteilt werden, sodass wenigstens einige 
Nachkommastellen mehr vorhanden sind.
Genauso ist es bei den folgenden Berechnungen.

Totzdem einen herzlihen Dank, dass du dir die Mühe gemacht hast! 
Verbessern kann man Code immer, egal wie durchdacht er ist!

Gruß, Yaro
Gast #1314729
Lesenswert?

> Kennt ihr vielleicht ein gutet tutorial, wo man fixpointrechnung gut
lernen kann?


Aber Jaroslav, Rechnen mit ganzen Zahlen sollte man in der Grundschule 
gelernt haben. Du stellst deine Rechnungen so um, dass mit ganzen Zahlen 
in ZehntelMillimeter und Bogensekunden gerechnet wird (dafür wirst du 
dann mehr als 8 bit brauchen, selbst 32bit werden teilweise nicht 
reichen), und fertig ist deine Fixpunktberechnung. Sie ist nur eine 
Frage der Maßeinheit.
#1314741
Lesenswert?

>Kennt ihr vielleicht ein gutet tutorial, wo man fixpointrechnung gut lernen kann?

Du scheinst ja von Mathematik etwas zu verstehen.
Somit sollte die grundlagen recht einfach zu verstehen sein.
der trick ist halt, dass man sich für seine Variable eine gewisse 
skalierung sucht.

du willst eine genauigkeit von 0,0005 haben.
das sind 1/2000.
Das heißt am gbesten skalierst du diese Zahl mit 2048, das heißt 11bit
das heißt ab dem 12. beginnt dann der vorkomma-anteil.
24.54233 entspräche 50262
-> 24.54233 * 2048 = 24.54233 * 2^11 = 24.54233 * (1<<11)

wenn du zahlen addierst musst du darauf chaten, dass sie die selbe 
skalierung haben.
beim Multiplizieren addieren sich die exponenten.
zu beachten ist immer, dass der wertebereich nicht überläuft.

Das härteste sind die mathematischen Basisfunktionen (integerwurzel, 
fixpoint-sin, cos, tan, acos, asin) die man natürlich selbst 
implementieren muss, oder man sucht sich ne kleine Bibliothek
OP #1314763
Lesenswert?

Alles klar, dann ist es ja wirklich so einfach, wie ich es bereits 
angewendet habe =)
Dabei ergebit sich dann das erwähnte Problem, dass man auf den Überlauf 
achten muss.
Ein weiteres, weit größeres problem ist, dass der Code deutlich 
unübersichtlicher wird. Das ist es, was mich die ganze Zeit davon 
abhällt, Festkommazahlen zu verwenden. Die eine Sache ist, eine Seite 
Code damit zu schreiben, aber eine andere ist es, 20Seiten Code so zu 
schreiben.

Ich werde mir das alles nochmal anschauen, und dann entscheiden, wie ich 
es mache.
Wahrscheinlich wird es darauf hinauslaufen, dass ich meißtens float 
benutzen werde, und in Fällen, wo ich besondere Genauigkeit brauche, 
dann mit Festkommazahlen Rechnen werde.

Vielen Dank für die kompetente Hilfe!
#1314872
Lesenswert?

Yaroslav Gevorkov schrieb:
> Ein weiteres, weit größeres problem ist, dass der Code deutlich
> unübersichtlicher wird. Das ist es, was mich die ganze Zeit davon
> abhällt, Festkommazahlen zu verwenden. Die eine Sache ist, eine Seite
> Code damit zu schreiben, aber eine andere ist es, 20Seiten Code so zu
> schreiben.

Tja, umsonst ist nur der Tod ;-)

>
> Ich werde mir das alles nochmal anschauen, und dann entscheiden, wie ich
> es mache.
> Wahrscheinlich wird es darauf hinauslaufen, dass ich meißtens float
> benutzen werde, und in Fällen, wo ich besondere Genauigkeit brauche,
> dann mit Festkommazahlen Rechnen werde.

Ich würde es genau umgedreht machen.
In derregel fixpoint und nur bei besonders kniffligen stellen floats 
benutzen.

Das float per se ungenauer sind asl Fixpoint würd ich nicht behaupten.
In den meisten fällen ist es wahrscheinlich umgekehrt.
die genauigkeit von float, richtet sich nicht größe der Zahl.
Float ist quasi sowas wie die wissenschaftliche schreibweise mit 
mantisse und exponenten. 1.434e+10. Wobei es so definiert ist, dass es 
nur eine stelle vor dem Komma gibt.
also statt 100.23e+3 wird 1.0023e+5 gespeichert

da die erste Stelle ist immer 1 und wird nicht gespeichert.
das heist für den Nachkommateil der Zahl gibt es 23bit

dH wenn deine Zahl 1.irgendwas ist, sind 23bit tatsächlich 
Nachkommapäzision, wenn du 100.irgendwas hast sind es nur noch 16bit.
bei 16.7Mio hast du gar keine Nachkommapräzision mehr.

Bei fixpoint, hast du zwar immer eine feste nachkommapräzision, 
allerdings wirst du die Variablen nicht mit 2^16 skalieren wollen, da 
dann multiplikationen schon kritisch werden, was überläufe angeht, da ja 
eine 1 schon 17bit braucht und man 2 solche zahlen nicht mehr in 32bit 
multiplizieren kann.

Bei fixpoint muss man halt bei jeder Rechenoperation wissen, was sind 
die maximalen/minimalen Werte die eingehen können. Nur so kann man Über- 
und Unterläufe verhindern.

Unterläufe treten auf, wenn man zB zwei fixpoints multipliziert und dann 
auf die Ursprüngliche skalierung zurückschiftet.
Wenn di Zahlen zu klein waren ist das ergebnis 0.
OP #1314898
Lesenswert?

Das mit den floats ist mir klar. Das gute ist, dass ich (in den meißten 
Fällen) nur bei kleinen Winkeln hohe Präzision brauche, bei großen 
Winkeln brauche ich nur wenige Nachkommastellen. Wenn mi die 23bit der 
floats mal nicht ausreichen, werde ich auf fixpoint zurückgreifen.

Gruß, Yaro
Gast #1314934
Lesenswert?

moin moin,

>>kleinen Winkeln hohe Präzision brauche

kann man so nicht sagen. Mein dicker Bartsch (Matheformeln) sagt dazu:
Näherungsformeln für kleine Winkel
sin a ~ a ~ tan a
sin n a ~ n sin a

Die Berechnung zu den Füßen ist vergleichbar mit der 
Fräsradienkorrektur.

Zum Platzbedarf: Der C8051F365 ist 5x5mm, braucht 3,3V.

Gruß
Pieter
OP #1315023
Lesenswert?

Große Genauigkeit bei kleinen Winkeln brauche ich, weil:
Kleine Winkel habe ich (im Fall der gehens um einen Radius) dann, wenn 
der Radius groß ist. Dann nämlich wirkt sich die änderung des Winkels 
sehr stark auf den Bogen aus, der sich gegenüber dem Winkel öffnet, den 
ich dazu benutze, meine Schritte zu setzten.
Bei kleinem Radius (und dabei dann großem Schrittwinkel) wirken sich 
kleine Ungenauigkeiten weit weniger aus.

Gruß, Yaro
Gast #1315100
Lesenswert?

nur mal so als gedankenansatz :

 - arbeite komplett mit fixed-point
 - lege dir eine viertel sinusschwingung bei maximaler auflösung (32bit) 
in ein 2mbyte daten-flash (das macht bei 4bytes pro wert -> 500k-werte 
..  bei einer viertel schwingung (90°) -> 0,000171° auflösung)
 - bilde sinus-cosinus-fkt aus dieser viertel schwinung
 - bilde arccos/arcsin per wägeverfahren aus der sinus/cosinusfkt

(selbst wenn ich mich mit dem wägeverfahren nun in die nesseln setze, 
aber ist brute-force und sollte auf jedenfall in akzeptabler zeit zum 
ergebnis führen)

ich denke du wirst wenn du das konsequent anwendest mit 32-bit auflösung 
am besten gehen bzw fahren :-)
vor allem hast du dann das genauigkeits-problem gelöst und bist zudem 
noch ne ganze ecke schneller als floating point.
Gast #1315116
Lesenswert?

Zur Praezision von float und Integern. Also single precision float hat 
eine mantisse von 23 bit, und einen exponent von 8 bit, plus ein sign. 
Das naechst groessere ist double precision, mit etwas mehr von beidem. 
Der Vorteil von integern ist, dass man deren Groesse selbst anpassen 
kann.
Einen 40, 48 oder 56 bit integer mit seinen Additions- und 
Multiplikations- grundfunktionen sind schnell und einfach geschrieben. 
Falls Single nicht hinkommt, sollte man sich den Schritt zu 64bit gut 
ueberlegen.
Gast #1315397
Lesenswert?

Wenn man die Winkelfunktionen nur bei kleinen Werten braucht, dann ist 
die Potenzreihen Entwicklung gut:
sin x = x - 1/3 x^3 + 1/5 x^5 ...
Wobei man bei kleinen Werten halt schon relativ früh (z.B. schon nach 
x^3) aufhören kann.
Der Arctan ist allerdings nicht ganz so gutmütig und braicht oft mehr 
glieder.
#1315602
Lesenswert?

Jetzt mal ein kleiner Mathe Grundkurs Mathematik. Man verwendet für die 
Berechnung von Wickelfunktionen und Co die sog. Taylorreihe.
http://de.wikipedia.org/wiki/Taylorreihe
Diese reihe ermöglicht eine "APROXIMATION" für eine Funktion f(x).

Also das ist das was der Ulrich für den sin(x) aufgeschrieben hat.

Noch ne Kleinigkeit es ist blödsinn wenn man einem "Coprozessor" nur 
dazu benutzt um die Winkelfunktionen zu berechnen. Sinnvoller wäre 
gewisse Algorythmen direkt auf den zweiten Controller auszulagern zB die 
Berechnung von 4 Füssen von den insgesamt 8 oder so ähnlich. Denn dan 
würde die Latenzzeit wegen der Kommunikationsschnittstelle nicht mehr so 
ins Gewicht fallen.

MFG Patrick
Gast #1315656
Lesenswert?

> Man verwendet für die Berechnung von Wickelfunktionen und Co die sog. 
Taylorreihe.

Wer ist man?

Der Mathe-Professor?
Vielleicht.

Ein Micro(computer/controller/coprozessor) ?

Sicher nicht, konvergiert viel zu langsam, nicht effizient genug.
Gast #1315816
Lesenswert?

In Softwarebibliotheken werden zur Berechnung von Winkelfunktionen meist
Potenzreihen verwendet, deren Koeffizienten aber von den Taylor-Reihen
der zu approximierenden Funktionen geringfügig abweichen (mit steigendem
Index prozentual immer mehr). Die Koeffizienten sind daraufhin
optimiert, dass der maximale Fehler im genutzten Wertebereich minimal
wird. Taylor-Reihen, die nach n Gliedern abgeschnitten werden, schneiden
hierbei deutlich schlechter ab.

So beträgt bspw. der maximale Fehler des Sinus aus der AVR-Libc nur etwa
4% des Fehlers der Taylor-Reihe, die auf die gleiche Anzahl von Gliedern
(6) begrenzt wird.
Gast #1315953
Lesenswert?

Es gibt für die Winkelfunktionen die beiden Möglichkeiten Cordic oder 
Taylorreihe. Welche Methode man nimmt hängt davon ab, was man braucht 
(Sin und Cos, oder nur Sin), und was die Hardware gut kann.

Die AVRs haben einen HW Muplipier, aber keine Hardware füs Shiften. Das 
spricht etwas für die Taylorreihen.

Bei den Taylorreihen wird normalerweise erst einmal dafür gesorgt, das 
das Argument klein ist, um einen gute Konvergenz zu erreichen. Beim 
Sinus / Cosinus wird man wohl wenigstens dafür sorgen, dass man unter 45 
Grad (ca. 0.79 im Bogenmaß) bleibt. Man kann eventuell auch noch weiter 
runter gehen durch Ausnutzen von anderen Identitäten.

Die Reihen für Sinus und Cosinus konvergieren dann schon nicht so 
schlecht.
Gerade wenn man nur kleine Winkel braucht sind die Taylorreihen die 
Methode der Wahl. Einige Reihen gehen dabei gut (exp, sin, cos), andere 
weniger gut (Arctan, Wurzel, Logarithmus).

Wenn man geschickt rechnet, sind auch 5 oder mehr Glieder im Polynom 
kein großes Problem.

Hab gerade gesehn: oben ist eine Fehler drin: die Vorfaktoren sind
-1/3! , 1/5! usw.  die gehen also recht schnell gegen Null.
OP #1317260
Lesenswert?

Das mit der Taylor-Reihe ist ja eine richtig tolle Erfindung!
Bei kleinen Winkeln sollte das mit einem AVR relativ schnell gemacht 
sein. Schwierig wird es bei größeren Winkeln.
Problem ist aber auch hier: auf Grund der Brüche (z.B. 1/3*x³) muss man 
einen relativ roßen skallierungsfaktor nehmen, um genug genauigkeit 
hinzubekommen. Großer Skallierungsfaktor bedeutet große Variablen, was 
widerum einen großen Rechenaufwand bedeutet.

Ich bin gerade dabei, das Programm zu schreiben, welches diese 
sinusfunktionen braucht, ich werde mal testen, welche Genauigkeit ich 
brauche, und welches Verfahren ich dann nehme. Werde bei sehr kleinen 
Winkeln wahrscheinlich Taylor nehmen (mit fixpoint) und bei den anderen 
wahrscheinlich die math-funktionen mit float.

Gruß, Yaro
Persönliche Seite #1317290
Lesenswert?

Patrick Weinberger schrieb:
> Mal eine andere Frage ?
> Können deine aktoren eine solche genauigkeit überhaupst wiedergeben ?
Das habe ich mich in dem Thread das erste mal gefragt, als das Wort 
Hexapod fiel.

Ist die Hardware schon fertig und merkst du, dass die ungenauen 
Rechnungen den Roboter schlecht machen? Das kann ich nämlich nicht 
glauben.
Gast #1317418
Lesenswert?

Moin

hat sich mal schon jeman die mühe gemacht eine Fehler / Toleranz 
berechnung / bewertung zu machen? ggf ist das ganze mit der 7ten 
nachkommastelle gar nicht so wichtig, wenn die hinterher gar nicht mehr 
dargestellt werden können (8 bit ausgangswerte). bzw aufgrund von 
mechanik, elektronik sowieso mehr fehler reinkommen, als einem lieb ist.


nur mal so zur info, der unterschied zwischen 8 16 und 32 bit

32 bit soll angeblich 48 mal schneller sein bei einer multiplikation als 
ein 8 bitter ( nur von der anzahl der befehle )
http://www.elektroniknet.de/home/bauelemente/fachwissen/uebersicht/aktive-bauelemente/mikrocontroller-prozessoren-dsps/32-bit-mcu-soll-8-und-16-bit-markt-angreifen/druckversion/

und viel spass noch
Gast #1317468
Lesenswert?

Hallo,

ich habe für Winkelfunktionen auf dem AVR die 'Cephes Lib' benutzt. Die 
darin verwendeten Reihenentwicklungen sind keine Taylorreihen, sondern 
es werden zunächst die Argumente transformiert, bevor dann eine Reihe 
mit wenigen Gliedern zum Einsatz kommt.
Als meine Assemblerroutinen fertig waren, habe ich sie gegen den PC mit 
Zufallswerten geprüft und die Ergebnisse waren fast immer auf 15 
Dezimalen identisch.

Meine Anwendung (Teleskopsteuerung) benutzt das 64bit Floating Point 
Format, daher sind die Routinen wohl unnötig genau und vor allem zu 
langsam für den Hexapod.

Hier sind meine Floating Point Routinen:
http://www.martin-cibulski.de/atm/mount_controller_4/mc_4_asm_main/index_de.htm

Hier findet man die Library für verschiedene Auflösungen:
http://www.moshier.net/#Cephes

Gruß,
Martin

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