Hallo, bin seit Stunden bei einer Fehlersuche und komme leider nicht weiter. Als Anlage 2 Zeilen Code in C. Habe die varriablen zum Testen durch Konstanten ersetzt. Frage: Warum ist hier e immer positiv ?? Gruß
:
Verschoben durch Admin
Weil 32767*2000000 schon überläuft. Das Ergebnis benötigt 38bit. "Long" hat aber nur 32bit. wenn dein C das 64bit "long long" kennt, hast du gewonnen.
:
Bearbeitet durch User
Bitte nächstes mal als Text und nicht als Bild posten. 32767 * 2000000 = 65534000000 -> viel zu groß für long auf allen gängigen Plattformen. Das Überlauffverhalten für vorzeichenbehaftete Werte ist nicht definiert. Damit darf also ein beliebiges Ergebnis rauskommen.
Dirk F schrieb: > Habe die varriablen zum Testen durch Konstanten ersetzt. Wenn man jetzt wüßte, was an der Ganzzahlrechnung wirklich variable Größen sind, könnte man auch über sinnvolle alternative Formulierungen nachdenken, um explosionsartige Anforderungen an die Zahl der gültigen Bits in der Rechnung zu vermeiden.
(2^15 -1)/(2^16 -1) ist 1/2 mit einer Abweichung von 7ppm oder einer Unsicherheit auf dem 16ten Bit. Der DAC ist ja bestimmt fehlerfrei, oder?
Hallo, das ging ja schnell mit den Antworten. Die Platform ist PIC32 mit dem XC32 compiler. Ich denke, INT ist da 32 Bit und long 64 Bit ? Das Problem: Der 24 Bit wert vom DAC (Skaliert auf 0...2000000) soll mit Sollwertvorgabe vom 16 Bit DAC (Bereich 0....65535) verglichen werden. Also muss ich ja erst eine der beiden Werte auf den anderen Bereich skalieren. Hier der aktuelle code in Textform:
1 | e = (long) 900000 - (((long) 32767 * (long) 2000000 )/ (long) 65535 ) ; // ( ( voltage <<16) /2000000) - 32000; //data ; // Regeldifferenz = Istwert - Sollwert |
2 | if ((e > 1) && (PI_corr > -650)) PI_corr -- ; // um 1 Digit vom 16-Bit DAC korregieren |
3 | if ((e < -1) && (PI_corr < 650)) PI_corr ++ ; // wird ausgef max 1 % in 6,5 s ausregeln |
-- Und das nächste Mal liest Du auch noch den Text, der über dem Eingabefeld steht, und verwendest die [ c ] [ /c ] -Tags, dann kann man den Kram .. naja .. besser lesen. -rufus
:
Bearbeitet durch User
HI, habe den Fehler gefunden. long ist 32 Bit, long long ist 64 Bit... Danke an alle !!!! uper forum hier.
Dirk F schrieb: > Der 24 Bit wert vom DAC (Skaliert auf 0...2000000) Blöde Idee. Die Sache wird aber einfacher, wenn du 65536 auf 2000030 oder 2000031 skalierst. Und der Genauigkeitsfehler verschwindet im Digitalisierungsrauschen vom 16-Bit ADC. > Hier der aktuelle code in Textform: Du darfst das gerne mit "pre" taggen. > > e = (long) 900000 - (((long) 32767 * (long) 2000000 )/ (long) > 65535 ) ; // ( ( voltage <<16) /2000000) - 32000; //data ; // Und was davon ist jetzt wirklich konstant?
Rolf Magnus schrieb: > 32767 * 2000000 = 65534000000 -> viel zu groß für long auf allen > gängigen Plattformen. Ohne den üblichen Streit starten zu wollen möchte ich doch anmerken, dass 64-Bit Linux durchaus als gängige Plattform betrachtet werden darf. Und da ist "long" 64 Bits breit (LP64 Modell). Dass Microsoft sich das nicht getraut hat (LLP64 Modell) liegt wohl an der Historie von deren APIs und den darin enthaltenen Typdefinitionen.
:
Bearbeitet durch User
>>>Digitalisierungsrauschen vom 16-Bit ADC. Verwende einen 24 Bit ADC . Habe eine rauschfreie Auflösung 0.5 PPM erreicht. >>>Und was davon ist jetzt wirklich konstant? Hier der code, der funktioniert: e = (long) voltage - (((long long) data_roh * (long long ) 2000000 )/ (long long ) 65535 ) ;
Eine sehr gute Näherung für 2000000/65535 ist 26215/859 (der relative Fehler beträgt nur 1.5E-8). Damit kannst du das Ganze auch ohne 64-Bit-Arithmetik rechnen. Die Division kannst du ebenfalls einsparen, wenn du sowohl den Ausdruck für e als auch die Fehlergrenzen (±2) jeweils mit 859 multiplizierst. Dann sieht der Code folgendermaßen aus:
1 | e = voltage * 859 - data_roh * 26215; |
2 | if ((e >= 2 * 859) && (PI_corr > -650)) PI_corr -- ; |
3 | if ((e <= -2 * 859) && (PI_corr < 650)) PI_corr ++ ; |
Bei dieser Methode entfällt zudem der Rundungsfehler durch die ganzzahlige Division.
Da mir solche Divisionen durch 65535 (oder durch 255, ...) überhaupt nicht gefallen, verschiebe ich den 'Rundungsfehler' lieber an das untere Ende des Messwertes. z.B.: Messwert ist 1023 -> Messwert + 1 -> 1024 -> und jetzt, falls es hier nötig ist, schon was anzupassen: durch 4, statt 1023 / 4 -> jetzt noch minus eins und somit hat der Compiler die Möglichkeit, die Division durch Bitschieben zu ersetzen. In dem vorliegenden Fall könnte man dann mit 15625 / 512 rechnen. (Falls die Genauigkeit 7.9e-5 reicht, auch mit 7812 / 256)
>>>Damit kannst du das Ganze auch ohne 64-Bit-Arithmetik rechnen. Diese Berechnung wird jede 250 ms ausgeführt. Aus Prozessorsicht eine Ewigkeit. Ich denke, eine 64-Bit Berechnung wird die Gesamt Performance vom System nicht sehr stark beeinträchtigen. >>>Eine sehr gute Näherung für 2000000/65535 ist 26215/859 Danke für den guten Hinweis. Aber ein Argument spricht dagegen: Um die Wartung des Programms zu verbessern, ist die Lesbarkeit/Nachvollziehbarkeit nach z.B. 1 Jahr mit der ersten Methode besser. Danke für eure Hilfe! Gruß
DirkF schrieb: > Danke für den guten Hinweis. Aber ein Argument spricht dagegen: Um die > Wartung des Programms zu verbessern, ist die > Lesbarkeit/Nachvollziehbarkeit nach z.B. 1 Jahr mit der ersten Methode > besser. Man kann alles übertreiben. Irgendwie sollte es doch möglich sein, zwei Programmzeilen auch nach einem Jahr noch zu überblicken. Und zur Not gibt es die Möglichkeit, in solchen Fällen durch einen Kommentar Licht ins Dunkle zu bringen und so den Sinn solcher Formulierung zu erhellen.
Ich würde empfehlen in zukunft die <stdint.h> zu includieren und dann mit diesen Datentypen zu arbeiten. Dann gibt's kein "Ich dachte long sein 64bit" mehr, einfach int64_t.
DirkF schrieb: > Diese Berechnung wird jede 250 ms ausgeführt. >>>>Eine sehr gute Näherung für 2000000/65535 ist 26215/859 > > Danke für den guten Hinweis. Aber ein Argument spricht dagegen: Um die > Wartung des Programms zu verbessern, ist die > Lesbarkeit/Nachvollziehbarkeit nach z.B. 1 Jahr mit der ersten Methode > besser. Ok, da stimme ich dir zu. Wenn weder Rechenzeit noch der Programm- speicherverbrauch kritisch sind, ist es besser, die übersichtlichere Lösung zu wählen. Wolfgang schrieb: > Man kann alles übertreiben. > > Irgendwie sollte es doch möglich sein, zwei Programmzeilen auch nach > einem Jahr noch zu überblicken. Den obigen Näherungswert habe ich über die Kettenbruchentwicklung von 2000000/65535 bestimmt. Wird nun aus irgendeinem Grund die Skalierung der Werte geändert, so dass der Wertebereich von voltage nicht mehr nur bis 2000000, sondern bspw. bis 3000000 reicht, müsste die Näherung neu berechnet werden. Im anderen Fall genügt es, im Programm einfach den Wert 2000000 durch 3000000 zu ersetzen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.