Ich muss auf einem Controller (leider) einen Sinus berechnen und habe
für die MATH Bibliothek nicht genügend Speicher übrig, deswegen habe ich
altes Schulwissen ausgekramt und händisch gecoded, aber zufrieden bin
ich damit nicht (allerdings reichen 4 Stellen Genauigkeit aus).
Folgender Code belegt auf einem STM32F030F4P6 ca. 4500 Bytes:
1
#define M_PI 3.14159265359
2
3
floattiny_pow(intn,floatvalue)
4
{
5
floattmp;
6
7
tmp=value;
8
for(inti=0;i<n-1;i++)
9
{
10
tmp=tmp*value;
11
}
12
returntmp;
13
}
14
15
floattiny_sin(floatvalue)
16
{
17
18
floatdegree;
19
floatp3;
20
floatp5;
21
floatp7;
22
floatsinx;
23
24
intmflag=0;
25
26
while(value>360)value-=360;
27
if(value>180)
28
{
29
mflag=-1;
30
value-=180;
31
}
32
33
if(value>90)value=180-value;
34
35
degree=(value*M_PI)/180;
36
37
p3=tiny_pow(3,degree);
38
p5=tiny_pow(5,degree);
39
p7=tiny_pow(7,degree);
40
41
sinx=(degree-(p3/6)+(p5/120)-(p7/5040));
42
43
if(mflag)sinx=sinx*(-1);
44
returnsinx;
45
}
Hat hier jemand vllt. etwas in Petto, das kürzeren Code produziert ?
Gruß, Ralph
Welche Wertebereich brauchst du? Wie fein muss die Unterteilung sein?
Du kannst eine Look-Up-Table bauen. Du brauchst nur den Wertebereich 0°
bis 90° abspeichern. Bei 1° Winkelgenauigkeit reichen dann eben 90
Werte.
Und den Sinus benoetigst du wozu ? Allenfalls ist man mit einer Tabelle
sowieso besser bedient. Falls es immer wieder dieselben Werte sind. Ich
wuerd mir aber eher 2^N Werte abspeichern. Also 64, 128, 256, das machts
dann einfacher mit Wrap-aroud
Ich verwendete auch meist die Taylor-Reihenentwicklung.
Wenn man ein paar Stützstellen speichert (z.B. 16 oder 32) kann man den
Summensatz sin(a+-b) = sin(a)*cos(b)+-cos(a)*sin(b) sehr gut verwenden
um schnell den Sinus zu berechnen.
a sind dann einfach die Stützstellen und b die Abweichung zum
gewünschten Wert. sin(a) und cos(a) sind in der Stützstellentabelle (da
braucht man auch nur die Werte von 0 bis PI/2, danach spiegeln bzw.
invertieren), sin(b) und cos(b) kann man mit Taylor-Reihenentwicklung
machen, braucht aber viel weniger Potenzen für ein gutes Ergebnis, da b
immer nur sehr klein ist.
Auf einem DSP schaffe ich so eine Sinusberechnung im Schnitt
(Interleaved) in 11 Zyklen bei 16 Bit Genauigkeit bei einer geringen
Codegröße.
Wenn die Performance egal ist und nur die Codegröße zählt, dann dürfte
obige Version sehr gut sein.
Moin,
Wenns denn unbedingt eine Potenzreihe sein muss (ich bin auch ein
grosser Fan der Lookup-Table), dann kann man die noch etwas umformen.
Aus dem Polynom einmal mit Gewalt x ausklammern, danach noch aus den
verbliebenen Teilen mit Gewalt (1/bla*x²) ausklammern.
Das gibt dann z.b. sowas:
sin(x)~x*(1-1/6*x²*(1-1/20*x²*(1-1/42*x²)))
Einmal x² berechnen, dann das ganze von hinten her ausrechnen.
Damit braucht man statt der ganzen Potenzen von x nur noch das Quadrat.
Insgesamt wird man auch weniger Probleme mit Rechenungenauigkeiten
haben, weil die Faktoren nicht so gross/klein werden, wie mit den echten
Potenzen im Zaehler und echten Fakultaeten im Nenner.
Ob der Code dann kuerzer wird? Keine Ahnung. Aber wahrscheinlich
schneller.
Gruss
WK
Hmm, ich habs mal in AVR Studio kopiert - 3742 Bytes mit einem minimalen
main().
Wenn man alles auf 'long' statt 'float' umstellt und dann mit z.B.
'1825000' für 182,5 Grad arbeitet, sind nur noch 2780 oder so Bytes fürs
Programm.
... ich hatte zuerst eine Lookup-Tabelle mit 0,5° Schritten gehabt,
allerdings nur bis 45° (und die Werte sogar als Integer-Werte * 100000
gespeichert gehabt = > 90 Werte * 32 Bit = 720 Byte).
Von 45 Grad dann auf den Vollkreis umrechnen und das Interpolieren
dazwischen war dann in der Codegröße insgesamt größer als das, was ich
jetzt habe.
Geschwindigkeit spielt nicht die Rolle.
Ich brauche dieses, weil ich nach Vorgaben eines unserer Wissenschaftler
eine von ihm vorgegebenen Meßwert verrechnen muß, in dem Sinus, Wurzel
und natürlicher Logarithmus vorkommt.
Wenn es nicht hinhaut, muß ich wohl (was mich ärgern würde) auf einen
größeren Controller umsteigen.
Matthias S. schrieb:> Hmm, ich habs mal in AVR Studio kopiert - 3742 Bytes mit einem minimalen> main().> Wenn man alles auf 'long' statt 'float' umstellt und dann mit z.B.> '1825000' für 182,5 Grad arbeitet, sind nur noch 2780 oder so Bytes fürs> Programm.
Im AVR wäre das so nicht ein Problem, weil ein 8 Bit breit, bei einem
ARM dieses jedoch 32 Bit breit.
Es wäre mal einen Vergleich wert, wie groß der Code auf einem AVR und
wie groß der Code auf einem ARM wird.
Den ARM (mit seiner höheren Taktfrequenz) brauch ich, weil an diesem die
I/O Pins deutlich höhere Frequenzen möglich als auf einem AVR sind.
Sepp schrieb:> ch ja, ich würde die Zwischenergebnisse nutzen. Spart bei den meisten> Compilern Code Größe und Performance.
Tut es leider nicht, scheinbar ist der arm-none-eabi-gcc so gut in der
Optimierung, dass es keinen Unterschied macht...
auch etwas in der Art:
p3= degree degree degree;
anstelle von tiny_pow bringt nichts (abgesehen davon , dass ich das
tiny_pow an anderer Stelle auch noch benötige).
Hmmm, mach ich mal weiter in der Hoffnung, dass nicht mehr zu viel an
Code hinzukommt und es noch "reinpasst"...
Ralph S. schrieb:> Im AVR wäre das so nicht ein Problem, weil ein 8 Bit breit, bei einem> ARM dieses jedoch 32 Bit breit.
Genau das ist deinen Chance, hatte nur keine Zeit mehr, zu editieren.
Der ARM ist nativ 32 bit breit und würde damit bei int32 Typen besser
abschneiden als der olle AVR.
Ich probier das nochmal für den VL Discovery auf CooCox...
Der Haken ist der Wertebereich. MAX_LONG liegt bei 0x7fffffff und würde
bei 4 Digits nach dem Komma maximal bis 214748,3647 Grad gehen.
Ralph S. schrieb:> und habe> für die MATH Bibliothek nicht genügend Speicher übrig
Ich weiss nicht, was dein Compiler kann, aber in vergleichbaren Fällen
habe ich die Meldungen des Linkers ausgewertet, welche Routinen er nicht
findet, und die einzeln solange eingebunden, bis der Linker zufrieden
ist. Das Progamm kann dann Sinus berehcnen, aber sonst nichts. Man
braucht dazu ja nicht eine ganze Math-Bibliothek. Ist natürlich Arbeit,
Selberschreiben aber auch.
Das beruhte auf dem klassischen Workflow mit Compiler, Linker,
Librarian. Moderne IDEs haben da viel weniger Möglichkeiten, das ist
eben der Fortschritt, beruhend auf dem Dogma dass man immer und überall
mehr als genug Speicher hat.
Georg
Moin,
Ralph S. schrieb:> Ich brauche dieses, weil ich nach Vorgaben eines unserer Wissenschaftler> eine von ihm vorgegebenen Meßwert verrechnen muß, in dem Sinus, Wurzel> und natürlicher Logarithmus vorkommt.
Haste schonmal geguckt, ob du nicht die gesamte Rechnerei mittels einer
Taylor- oder Sonstigen-Reihenentwicklung erschlagen kannst? Das koennte
dann etwas Platz schaffen, weil du "nur noch" eine Reihenberechnung hast
und keine weiteren Rechnungen mehr.
Gruss
WK
Matthias S. schrieb:> Ich probier das nochmal für den VL Discovery auf CooCox...
So, ganz kurz habe ich das mal auf einem STM32F030 Build probiert,
allerdings habe ich kein Board hier.
Das Originalprogramm war bei mir bei 7800 Bytes... keine Ahnung, woher
der Unterschied zu deinem kommt.
Alle 'float' auf 'long' und mit langen Integern gefüttert (also z.B.
1800000 statt 180,0000) als Festkomma Arithmetik.
https://www.mikrocontroller.net/articles/Festkommaarithmetik
Das Programm ist nur noch 540 Bytes lang.
Ralph S. schrieb:> Ich brauche dieses, weil ich nach Vorgaben eines unserer Wissenschaftler> eine von ihm vorgegebenen Meßwert verrechnen muß, in dem Sinus, Wurzel> und natürlicher Logarithmus vorkommt.
Muss denn diese "große" Umrechnung am µC passieren? Evtl wäre es
zielführender nur das am µC zu berechnen, was für den nächsten
Prozessschritt benötigt wird und den Rest der Datenauswertung am PC zu
machen.
Auf einem M4:
sint 0x08000041 0x32 Code Gb sint.o [1]
sintk 0x20000000 0x10 Data Gb sint.o [1]
Auf einem M3:
sint 0x080002e5 0x3a Code Gb sint.o [1]
sintk 0x20000000 0x10 Data Gb sint.o [1]
dazu aus der Runtimelib:
FltAdd.o 132
FltMul.o 216
FltSub.o 214
Ralph S. schrieb:> Hat hier jemand vllt. etwas in Petto, das kürzeren Code produziert ?
Alleine wenn du den code auf integer umstellst (bekommst du ein Ergebnis
zwischen 0 und 32767) wird es schon mal viel kleiner und schneller.
CORDIC ist aber die beste Lösung für exakte Ergebnisse.
Eine Tabelle z.b. für 0, 10, 20, 30, 40...90 Grad und dazwischen linear
interpolieren (wieder im Interger-Zahlenbereich) wird aber auch gern
verwendet.
Georg schrieb:> Moderne IDEs haben da viel weniger Möglichkeiten, das ist> eben der Fortschritt, beruhend auf dem Dogma dass man immer und überall> mehr als genug Speicher hat
Das braucht man zum Glück bei modernen Compilern auch alles nicht, denn
der GCC/gnu ld z.B. kann automatisch alle Funktionen/Variablen aus den
Libraries entfernen und nur exakt die einbinden, die man benötigt. All
die manuelle Fummelei ist somit vollkommen unnötig.
Das schaltet man ein indem man -ffunction-sections -fdata-sections an
den Compiler, und -Wl,--gc-sections an den Linker übergibt. -flto an
Compiler und Linker übergeben optimiert noch mehr.
Dr. Sommer schrieb:> Das braucht man zum Glück bei modernen Compilern auch alles nicht, denn> der GCC/gnu ld z.B. kann automatisch alle Funktionen/Variablen aus den> Libraries entfernen und nur exakt die einbinden, die man benötigt
So stelle ich mir das ja auch vor. Es soll aber auch
Entwicklungsumgebungen geben, die der Einfachkeit halber die gesamte
Runtime einbinden und bei denen daher ein "Hello world" schon MByte
gross ist. Bei Embedded ist das eigentlich untragbar, daher wundert es
mich wenn eine Sinusberechnung den Speicherplatz sprengt.
Georg
Heinz K. schrieb:> Ralph S. schrieb:
icher Logarithmus vorkommt.
>> Muss denn diese "große" Umrechnung am µC passieren? Evtl wäre es> zielführender nur das am µC zu berechnen, was für den nächsten> Prozessschritt benötigt wird und den Rest der Datenauswertung am PC zu> machen.
Es gibt keinen PC der das später auswertet, das wird ein
"Handschätzeisen" mit Display, der unterm Strich genau 3 Zahlen anzeigen
wird.
... ich probiere mal CORDIC aus ... auch wenn ich im Rest des Programms
so viel abgespeckt habe, dass wohl alles reinpasst was rein soll !
:-) mußte schon lange nicht mehr so mit Speicher geizen wie jetzt !
Moin,
Ralph S. schrieb:> Es gibt keinen PC der das später auswertet, das wird ein> "Handschätzeisen" mit Display, der unterm Strich genau 3 Zahlen anzeigen> wird.
Also das taet' imho schon danach schreien, die gesamte Funktion, incl.
aller sinuesse, wurzeln und logarithmen in eine einzige
Reihenentwicklung zu quetschen und die dann ggf. auch noch auf
Integer-Arithmetik zu bringen. Ok, wenn sich das drueber nachdenken und
die (Kopf)Rechnerei lohnt. Ansonsten wirds billiger sein, eine dickere
CPU zu nehmen.
Gruss
WK
Dergute W. schrieb:> Moin,>> Ralph S. schrieb:>> Es gibt keinen PC der das später auswertet, das wird ein>> "Handschätzeisen" mit Display, der unterm Strich genau 3 Zahlen anzeigen>> wird.>> Also das taet' imho schon danach schreien, die gesamte Funktion, incl.> aller sinuesse, wurzeln und logarithmen in eine einzige> Reihenentwicklung zu quetschen und die dann ggf. auch noch auf> Integer-Arithmetik zu bringen. Ok, wenn sich das drueber nachdenken und> die (Kopf)Rechnerei lohnt. Ansonsten wirds billiger sein, eine dickere> CPU zu nehmen.>> Gruss> WK
Deine Rechtschreibung ist zum Heulen.
Stuss
LJ
Reinhard M. schrieb:> Axel S. schrieb:>> Der Klassiker für trigonometrische Funktionen:>> Auf jeden Fall.> Zum Testen:>> cordic-32bit.c
Hab ich jetzt auf dem STM32 ausprobiert und die Genauigkeit ist absolut
super und auch deutlich schneller... aber leider auch um ca. 700 Byte
größer.
Werde ich mir dennoch merken, wenn ich etwas in dieser Art nochmal
benötige.
MaWin schrieb:> Alleine wenn du den code auf integer umstellst (bekommst du ein Ergebnis> zwischen 0 und 32767) wird es schon mal viel kleiner und schneller.
Das wird jetzt der nächste "Versuch" werden.
Vielen Dank an alle
Wenn im Programm noch an anderen Stellen mit floats gerechnet wird,
werden die Objekte FltAdd.o, FltMul.o und FltSub.o ohnehin geladen.
Da nuetzt das ganze Herumgepopel mit Integern nichts.
Die Taylorreihenentwicklung aus meinem Beispiel, hat bei
PI/2 einen Fehler von 1.2e-007. Das sollte fuer ein 3-stelliges
Rechenergebnis wohl sicher reichen.
Dergute W. schrieb:> Moin,>> Sabun schrieb:>> Stuss>> Ginge es eventuell etwas qualifizierter?>> Gruss> WK
Da du dir diese Frage selbst stellst, musst du sie auch selbst
beantworten.
Stuss
LJ
./. schrieb:> Wenn im Programm noch an anderen Stellen mit floats gerechnet wird,> werden die Objekte FltAdd.o, FltMul.o und FltSub.o ohnehin geladen.> Da nuetzt das ganze Herumgepopel mit Integern nichts.> Die Taylorreihenentwicklung aus meinem Beispiel, hat bei> PI/2 einen Fehler von 1.2e-007. Das sollte fuer ein 3-stelliges> Rechenergebnis wohl sicher reichen.
Es wird mit floats gerechnet ... und du hast Recht, das Integergeschubse
hat nicht so viel gebracht.
Aber wie es ausschaut, reicht mir nun der Speicherplatz.
:-) Smile, ich sagte nicht, dass ein Ergebnis 3-stellig ist, sondern
dass es ein Ergebnis wird, das aus 3 Zahlen besteht. Die Anzeige wird
zum Schluß sogar nur 2 Stellen hinter dem Komma haben.
Ich muß nur sehr aufpassen, mir meinen Fehler nicht fort zu schleifen.
Wenn der Mensch für den das ist "zufrieden" ist, kann das schon sein,
dass das in der Größenordnung 1000 Stück gebaut wird (und dann kann es
auch schon sein, dass da auf die MCU geachtet wird).
Aber ich bin guten Mutes dass mir der kleine ARM reicht...
Aber hier merkt man wieder: am falschen Ende gegeizt. Mit bspw. einem
F103 (selbst in der 64 KByte Version)... wäre ich wahrscheinlich schon
fertig.
Nochmals Dank an alle, die sich hier eingebracht haben ... und gelernt
hab ich auch wieder was ( schmunzeln muß und am WE werde ich mir den
CORDIC Algorithmus mal genauer ansehen wie der funktioniert - hoff ich
dass ich da dahinter komme).
Ralph
Ralph S. schrieb:> STM32F030F4P6
Du weißt daß dieser µC 32KB Flash hat? Das Datenblatt sagt zwar nur
16KB, in echt sind aber 32KB drauf, genauso der 32Bit-Timer. Der
STM32F030F4P6 und der STM32F031F6P6 verwenden die selben Dies.
Das einzige was anders ist ist der Wert, der ins Flash size Register
programmiert wurde. Wenn Du das ignorierst kannst Du den vollen Flash
verwenden.
Der ST Link prüft das Flash Size Register, den kannst Du also nicht zum
programmieren verwenden. Wie es mit einem auf Jlink umgestellten ST Link
aussieht hab ich noch nicht programmiert. Aber mit dem seriellen
Bootloader funktioniert es.
Also musst Du Dir wegen Deinem Sinus vermutlich keine Gedanken bzgl. der
Codegröße machen und kannst beim STM32F030F4P6 bleiben.
Möchte nochmal was einwerfen weil das häufig nicht so bekannt ist:
Unbedingt alle float - Konstanten auch mit f kennzeichnen! Wenn man 3.14
als Konstante verwendet wird in double gerechnet bei 3.14f in float.
Kurzes Beispiel für stm32f030 und Crossworks:
1
intmain(void)
2
{
3
floatf=sinf(1.24f);
4
f=f*2.13f;
5
return(int)f;
6
}
benötigt 1.9k
1
intmain(void)
2
{
3
floatf=sinf(1.24f);
4
f=f*2.13;// double Berechnung!
5
return(int)f;
6
}
benötigt 2.5kb
Am besten mal im map-File nachsehen ob da irgendwas mit float64 zu
finden ist.
Ralph S. schrieb:> Ich muss auf einem Controller (leider) einen Sinus berechnen und habe> für die MATH Bibliothek nicht genügend Speicher übrig
Jaja, so viele Beiträge und immer noch keine Lösung..
Also, Sinus nach Pedersen: "High speed, low accuracy algorithms for
computing cos x, sin x" (Danmarks tekniske Hojskole, Mai 1978, via
Lampe-Jorke-Wengel):
y:= x * (K*x^2 + L + M / (x^2 + N));
mit
K = 0.15625
L = -11.45242628
M = 480.1488517
N = 38.55864669
Der reicht für 6 Stellen bei single. Aber bitte auf den 1. Quadranten
herunterbrechen.
W.S.
W.S. schrieb:> Also, Sinus nach Pedersen:
es kusieren ja einige ähnliche Algorithmen im Netz, das kannte ich noch
nicht. Um meine Beispiele von oben zu vervollständigen hab ich das mal
probiert:
das benötigt dann 1,6kb. Genau 288Byte weniger als mit der libm. Die
Genauigkeit ist beachtlich, etwa 1 Zehnerpotenz schlechter als bei
sinf().
Größte Abweichung beim Probieren mit ganzen Gradzahlen lag bei 0,001%.
Georg schrieb:> Ich weiss nicht, was dein Compiler kann, aber in vergleichbaren Fällen> habe ich die Meldungen des Linkers ausgewertet, welche Routinen er nicht> findet, und die einzeln solange eingebunden, bis der Linker zufrieden> ist.
Herzlichen Glückwunsch!
Du hast gerade vollkommen unnötig die Arbeitsweise eines Linkers
nachgefrickelt.
Der links aus einer Lib nämlich nur die Objecte, die nebötogt werden.
Unfd falls das bei einer bestimmten Lib nicht der Fall ist dann heißt
dass, dass deren Autoren planlos waren. In dem Fall wird man von der
Verwendung der entsprechenden Lib ohnehin absehen.
> Das Progamm kann dann Sinus berehcnen, aber sonst nichts. Man> braucht dazu ja nicht eine ganze Math-Bibliothek. Ist natürlich Arbeit,> Selberschreiben aber auch.
Unsinn, wenn gegen eine Lib gelinkt wird, und z.B. nur sin gebraucht
wird, warum sollte ein Linker dann gegen log oder bessel linken?
So, den Post von W.S. hab ich jetzt ausprobiert und benötig von allen
bisherigen Versuchen den wenigsten Speicherplatz und ist von der von mir
benötigten Genauigkeit absolut ausreichend, Speicherplatz für alles
andere habe ich nun auch genug.
Herzlichen Dank dafür, (auch für an anderer Stelle den, sagen wir etwas
derberen aber NOTWENIGEN "Schubser" Dinge lieber selbst zu machen).
Mich würde sehr interessieren, wer sich hinter W.S. verbirgt (aber das
wird wohl sein Geheimnis bleiben).
Johann L. schrieb:> Du hast gerade vollkommen unnötig die Arbeitsweise eines Linkers> nachgefrickelt.
Totales Nichtverständnis. Der Linker linkt im Scan-Modus die Module, die
für das geschriebene Programm benötigt werden, das ist trivial, auch
wenn es Linker gibt die das nicht können. D.h. er linkt z.B. ein
Trigonometriemodul, wenn Sinus oder Tangens usw. benötigt werden.
Um aber noch weiter Speicherplatz zu sparen kann man eben manuell
steuern, dass nur z.B. die Sinusroutine geladen wird, Tangens aber nicht
- das ist feinere Granularität als die Library üblicherweise hat. Recht
effektiv ist auch, bei den Grundrechenarten auf die Division zu
verzichten, wenn man sie nicht braucht. Also Linken nach Bedarf nicht
auf Modul-Ebene, sondern auf der Ebene einzelner Unterprogramme.
Es ist aber wohl von einem heutigen Programmierer entschieden zu viel
verlangt, das zu verstehen. Alles macht die IDE, und was sie nicht macht
geht halt nicht.
>> Der links aus einer Lib nämlich nur die Objecte, die nebötogt werden.
Du hast sicher noch nie etwas von Borland gehört. Es gibt aber auch
andere, die einfach die ganze Runtime linken.
Georg
Wenn das Inkrement β des Winkels konstant ist und du bei α = 0 anfängst,
braucht du nur einmal den Sinus und den Cosinus des Inkrements wirklich
zu berechnen, für alle anderen Werte verwendet man Additionstheoreme und
braucht nur noch wenige Multiplikationen pro Wert:
sin(α+β) = sin(α) * cos(β) + cos(α) * sin(β)
cos(α+β) = cos(α) * cos(β) - sin(α) * sin(β]
Für den Anfangswert α=0 wissen wir, dass sin(0)= und cos(0)=1 ist:
sin(0+β) = 0 * cos(β) + 1 * sin(β)
cos(0+β) = 1 * cos(β) - 0 * sin(β]
Die benötigten Sinuswerte für das Inkrement β muss man entweder einmal
berechnen, oder evtl, falls nur wenige Werte in Frage kommen, einer
Tabelle entnehmen.
Wenn man die Werte berechnen muss, kann es schneller sein, wenn man den
bereits berechneten Sinus(β) verwendet und berücksichtigt,
dass cos(β) = Wurzel(1-sin^2(β)) ist.
Wesentlich hierbei ist, dass u=sin(β) und v=cos(β) konstante Werte sind,
und dass man von nun an nie wieder die langsame Reihenentwicklung von
sin oder cos benötigt, sondern nur die beiden obigen Formeln in eine
Schleife stecken muss:
sin(α+β) = sin(α) * v + cos(α) * u
cos(α+β) = cos(α) * v - sin(α) * u
Beim nächsten Schleifendurchlauf nehmen die soeben berechneten sin und
cos Werte den Platz der Anfangswerte sin(α) und cos(α) ein.
Man braucht also nur noch 4 Multiplikationen und zwei Additionen pro
sin-cos-Wertepaar.
Hp M. schrieb:> Wenn das Inkrement β des Winkels konstant ist und du bei α = 0 anfängst,> braucht du nur einmal den Sinus und den Cosinus des Inkrements wirklich> zu berechnen, für alle anderen Werte verwendet man Additionstheoreme und> braucht nur noch wenige Multiplikationen pro Wert:>> sin(α+β) = sin(α) * cos(β) + cos(α) * sin(β)> cos(α+β) = cos(α) * cos(β) - sin(α) * sin(β]
Im Prinzip ja. In der Praxis überlegst du jetzt mal kurz, welchen Fehler
du anhäufst, wenn du von 0 .. 90° in Schritten von 0.1° durch den z.B.
Sinus läufst.
Georg schrieb:> Du hast sicher noch nie etwas von Borland gehört. Es gibt aber auch> andere, die einfach die ganze Runtime linken.
Gibs es jetzt endlich Turbo-C für AVR?
Als Linker empfehle ich immer solche, die nach 1995 ausgeliefert wurden.
Georg schrieb:> Totales Nichtverständnis. Der Linker linkt im Scan-Modus die Module, die> für das geschriebene Programm benötigt werden, das ist trivial, auch> wenn es Linker gibt die das nicht können. D.h. er linkt z.B. ein> Trigonometriemodul, wenn Sinus oder Tangens usw. benötigt werden.>> Um aber noch weiter Speicherplatz zu sparen kann man eben manuell> steuern, dass nur z.B. die Sinusroutine geladen wird, Tangens aber nicht
Ja das ist nun mal eventuell bei der PC Programmierung so aber nicht bei
der cortex-Programmierung. Alles Libs die ich kenne sind mit
-ffunction-sections -fdata-sections gebaut. d.h. jede Funktion! der Lib
bekommt ihre eigene Section. Ebenso die verwendeten Daten. Was am Ende
nicht gebraucht wird fliegt raus. Und wenn ich nur sinf benutze ist auch
nur sinf drin. Und die Funktionen die sinf selbst benötigt u.U.
Auf alle Fälle kann man wohl sagen, die sinf aus der libm ist in der
Regel klein genug. Wenn man den Teil noch dazubaut um die o.g. Funktion
kompatibel zu sinf() zu machen kommen ja auch noch ein paar Byte dazu.
Ralph S. schrieb:> Mich würde sehr interessieren, wer sich hinter W.S. verbirgt (aber das> wird wohl sein Geheimnis bleiben).
Sicherlich jemand der noch jedes Bit vom U880 einzeln kennt und die
Assembler-hex-Codes per Hand in 1k Ram gekloppt hat. Tastatur
selbstgebaut und betrachtet am Junost.
ala: C3 xx xx
...
Jedenfalls lässt das die Literaturangabe vermuten.
temp schrieb:> Assembler-hex-Codes per Hand in 1k Ram gekloppt hat. Tastatur> selbstgebaut
Also ich komme aus BaWü und hab die Assembler-Hex Codes vom 8085 von
Hand reingekloppt ... und die Tastatur war auch selbstgebaut...
Egal wer das ist: heftig aber gut !
Reinhard M. schrieb:> cordic-32bit.c
-> Sinusberechnung
F030 Atollic GCC:
-Os 118 Bytes
-O0 ~180 Bytes
Krass. Danke für die Erinnerung.
Hat grad gut reingepasst: Die Tage habe ich auch auf einem STM32F030 für
ein eichfähiges System eine interne Berechnung in int64_t statt in
double durchgeführt. Plötzlich reichen auch 16k statt 32k Flash.
Und int64_t war schon der Ansatz für Faule. ;)
Marcus H. schrieb:> Reinhard M. schrieb:>> cordic-32bit.c>> -> Sinusberechnung> F030 Atollic GCC:> -Os 118 Bytes> -O0 ~180 Bytes
Sorry, aber nicht mit der cordic-32bit.c von oben. Da stehen 32 32bit
Werte in der Tabelle. Macht 128 Byte. Da würde ich jetzt ins Grübeln
kommen...
temp, danke, mein Fehler. Hab nur text gelesen und die dec übersehen:
Der gcc hatte folgende Info ausgeworfen:
Print size Information
OHNE CORDIC
text data bss dec hex filename
1056 28 164 1248 4e0 cordic_test.elf
MIT CORDIC
text data bss dec hex filename
1164 156 164 1484 5cc cordic_test.elf
Ich korrigiere auf 118 Byte Code + 128 Byte Tabelle = 236 Bytes Flash.
Legt man die Tabelle per const ins Flash, dann sieht es so aus:
text data bss dec hex filename
1292 28 164 1484 5cc cordic_test.elf
Je nach Speichermodell kann man sich jetzt noch raussuchen, was
geschwindigkeitsoptimal ist (F4+ART wohl const, beim M0+1WS müsste man
mal messen). Aber das sind Kleinigkeiten im niedrigen Prozentbereich.
Sepp schrieb:> Wenn man ein paar Stützstellen speichert (z.B. 16 oder 32) kann man den> Summensatz sin(a+-b) = sin(a)*cos(b)+-cos(a)*sin(b) sehr gut verwenden> um schnell den Sinus zu berechnen
Oh Oh Oh ....
Axel S. schrieb:> Im Prinzip ja. In der Praxis überlegst du jetzt mal kurz, welchen Fehler> du anhäufst, wenn du von 0 .. 90° in Schritten von 0.1° durch den z.B.> Sinus läufst.
Das wollte Ich auch gesagt haben. 4x trigonometrisch rechnen in einem
einzigen Schritt ist eigentlich niemals irgendwo effizient zu lösen.
Dergute W. schrieb:> sin(x) = x*(1-1/6*x²*(1-1/20*x²*(1-1/42*x²)))
Das schaut schon ansprechender aus.