Hallo! Vielleicht kann mir jemand von Euch helfen. Ich möchte einige Spannungswerte in mV über die UART ausgeben. Die Werte (Datentyp unsigned int) liegen zwischen 0mV und 35000mV. Damit die Werte nicht zu sehr schwanken würde ich gern in 100mV Schritten runden. Bsp.: Gemessener Wert: Ausgegebener Wert: 24113mV 24100mV 24159mV 24200mV Bin mittlerweile schon ziemlich am verzweifeln. Habt Ihr vielleicht eine Idee??? Gruß Daniel
Woran verzweifelst Du konkret? Anhand der Erwähnung von unsigned int gehe ich mal davon aus, dass es sich um C handelt, wobei eine explizite Erwähnung der Programmiersprache eigentlich zu den Selbstverständlichkeiten gehört. Und eine Rundung ist in C eigentlich kein Problem, allerdings müsstest Du dazu schon mal ein paar Randbedingungen rausrücken...
gerundet = ((wert + 50)/100)*100; fertig! Edit: wenn die Werte nicht so sehr schwanken sollen, dann wäre vielleicht auch ein Filter angebracht. Denn ist der Messwert um 24100 herum, so schwankt es wieder hin und her.
Ja genau es handelt sich un C, hatte ich vergessen zu erwähnen. Das Problem ist, dass ich keinen float-Wert auf "x" Kommastellen runden möchte, sondern wie in dem Beispiel angegeben einen unsigned int in 100er Schritten. Der Wert der sich also in der Variablen befindet beträgt wie im Beispiel 24113. Nun würde ich diesen Wert gerne so runden, dass anschließen 24100 in der Variablen steht. Fehlt sonst noch etwas?
Da Kn wrote: > Das Problem ist, dass ich keinen float-Wert auf "x" Kommastellen runden > möchte, sondern wie in dem Beispiel angegeben einen unsigned int in > 100er Schritten. Schön, die Lösung hat Karl ja mittlerweile geliefert...
sorry, wenn der wert um 24150 herum liegt....
Karl Zeilhofer wrote: > gerundet = ((wert + 50)/100)*100; > > fertig! > > Edit: wenn die Werte nicht so sehr schwanken sollen, dann wäre > vielleicht auch ein Filter angebracht. Denn ist der Messwert um 24100 > herum, so schwankt es wieder hin und her. Stimmt das klappt. Das Problem ist, dass ich wahrscheinlich keine Zeit für eine weitere Multiplikation und Division habe.
Karl Zeilhofer wrote: > Edit: wenn die Werte nicht so sehr schwanken sollen, dann wäre > vielleicht auch ein Filter angebracht. Denn ist der Messwert um 24100 > herum, so schwankt es wieder hin und her. Richtig, eine Rundung glättet nur unzureichend. Glätten kann man mit einer (vernünftigen) Mittelwertbildung.
Auf welcher Hardware arbeitest du?
Da Kn wrote: > Stimmt das klappt. Das Problem ist, dass ich wahrscheinlich keine Zeit > für eine weitere Multiplikation und Division habe. Dann runde halt nich im Dezimalen, sondern im Binären mit Shift. Sieht zwar nicht so schön aus, erfüllt aber den Zweck...
Da Kn wrote: > Stimmt das klappt. Das Problem ist, dass ich wahrscheinlich keine Zeit > für eine weitere Multiplikation und Division habe. Ach, guck mal da. Genau das sind die Randbedingungen, die Du oben verschwiegen hast. Dazu gehört neben der Programmiersprache auch, was für Ressourcen Dir zur Verfügung stehen. So langsam kommt es also raus... Der nächste Punkt (nachdem Du Deine Hardware mal beschrieben hast) wäre jetzt die Frage, was mit den gerundeten Werten überhaupt geschehen soll. Eine Multiplikation (Division) mit (durch) eine(r) Konstante benötigt auf den meisten Systemen übrigens gar nicht so viel Zeit. Wenn es nicht grad um Mikrosekunden geht, ist das relativ unkritisch. Aber wie schon gesagt: Das hängt von den verdammten Randbedingungen ab, die bislang nur Du selbst kennst!
Also bei dem Controller handelt es sich um einen MSP430F2272, der mit einer Taktfrequenz von 16Mhz läuft. Es sollen 3 Werte in 100er Schritten gerundet werden. Ich habe jetzt gerade nocheinma nachgemessen. Für die Rundung eines Wertes über das Verfahren was Karl vorgeschlagen hatte benötige ich für einen Wert eine Zeit von ca 30us. Ich könnte mich mit einer Zeit von maximal 10us anfreunden.
Gast
#1099025
in welcher form wird es über die UART übertragen? Wenn es in Textform ist könnte man es auch dort Manuell runden.
Nee nee das mit der UART geht nicht. Ich muss die Werte vorher im Controller gerundet haben.
Gast
#1099033
Addiere 50 auf deinen Messwert. Wenn Messwert größergleich 100 ist, setze die beiden letzten stellen 0. Sonst setze Messwert 0. Randbedingung: Nur Positive Messwerte.
Tim T. wrote:
> Randbedingung: Nur Positive Messwerte.
Weitere Randbedingung: funktioniert nur, wenn der Messwert kleiner 100
ist. Man kann mit dieser Methode also Messwerte kleiner 100 zu 0 oder
100 runden.
Man bräuchte schon noch zusätzlich ein Modulo, und das braucht dann
wieder signifikant Zeit.
> Addiere 50 auf deinen Messwert. > Wenn Messwert größergleich 100 ist, > setze die beiden letzten stellen 0. > Sonst > setze Messwert 0. > > > Randbedingung: Nur Positive Messwerte. Soweit logisch:
1 | |
2 | |
3 | |
4 | |
5 | |
Aber wie setze ich in C die letzten zwei Stellen auf 0?
Da Kn wrote: > Soweit logisch: Nö, denn die Methode rundet bei den meisten Werten (alle größer 100) nicht, sondern streicht nur die letzten beiden Stellen. > Aber wie setze ich in C die letzten zwei Stellen auf 0? Indem du den Modulo 100 abziehst. Für ein korrektes Funktionieren dieser Methode bräuchte man also zweimal den Modulo-Operator. Dürfte (wenn überhaupt) nur unwesentlich schneller sein, wie einmal * und einmal /.
Korrektur, man kommt natürlich auch mit nur einmal Modulo aus:
1 | |
2 | |
3 | |
4 | |
Du kannst zum wert 50 addieren, in einen String printen (sprintf()), und dort die entsprechenden Zeichen auf '0' setzen. Diesen String sendest du dann per UART.
Das mit dem Modulo klappt bringt aber nicht wirklich eine Zeitersparnis. Als String printen ist keine Lösung für mich, muss es mit dem unsigned int Wert machen.
Karl Zeilhofer wrote: > Da Kn wrote: >> Stimmt das klappt. Das Problem ist, dass ich wahrscheinlich keine Zeit >> für eine weitere Multiplikation und Division habe. > > Dann runde halt nich im Dezimalen, sondern im Binären mit Shift. Sieht > zwar nicht so schön aus, erfüllt aber den Zweck...
Addiere jeweils 2^n Werte auf und schiebe die Summe n Bits nach rechts. Dann hast du eine Mittelwertbildung, ohne einen Divisionsbefehl ausführen zu müssen. Wenn der Wertebereich nicht zu groß ist, kann man auch eine Lookup-Tabelle verwenden.
Gast
#1099083
Wie werden denn die Daten im UART-Empfänger weiterverarbeitet?
Gast
#1099086
1.) In zeitkritischen Anwendungen würde ich auf'm MSP430 nie Multiplikationen oder gar Divisionen berechnen lassen. Wer µC programmiert, sollte sich mit dem Binärsystem anfreunden und z.B. Multiplikationen mit 2, 4, 8, 16, usw. per Shiftoperation durchführen (Division analog). Bei 16MHz hast Du in 10µs genau 160 Taktzyklen Zeit die Berechnung durchzuführen. Das ist nicht wenig aber für Mul und Div zu wenig! Wie wär's, wenn Du nicht auf 100'er sondern z.B auf 128'er Runden würdest?
1 | |
2 | |
Das dürfte bei 16MHz in etwas mehr als 1µs erledigt sein! Allerdings wird Dein Compiler da noch was Optimieren wollen, was man aber auch "von Hand" hinbekommt, wenn man nämlich das Runden durch Ausmaskieren den unteren Bits bewerkstelligt:
1 | |
Das wären dann 4TZ @ 16MHz = 250ns... schneller geht's kaum! 2.) Wie schon erwähnt wurde, bekämpft man "zappelnde" Werte nicht mit Runden, sondern mit Mittelwertbildung! Auch hier ist das Binärsystem Dein Freund, wenn Du 2, 4, 8, usw. Werte zum Mitteln nimmst, weil dann die Division per Shift wieder einfach und schnell wird!
Karl Zeilhofer wrote: > Dann runde halt nich im Dezimalen, sondern im Binären mit Shift. Sieht > zwar nicht so schön aus, erfüllt aber den Zweck... Dann erkläre doch mal, wie man das macht, im Binären mit Shift auf 100 zu runden?
Stefan Ernst wrote: > Karl Zeilhofer wrote: >> Dann runde halt nich im Dezimalen, sondern im Binären mit Shift. Sieht >> zwar nicht so schön aus, erfüllt aber den Zweck... > > Dann erkläre doch mal, wie man das macht, im Binären mit Shift auf *100* > zu runden? Stefan (Gast) hats bereit genau nach meiner Vorstellung vorgeführt.
Karl Zeilhofer wrote:
> Stefan (Gast) hats bereit genau nach meiner Vorstellung vorgeführt.
Und wo bitte wird da auf 100 gerundet?
Da wird auf 128 gerundet, so dass er als Ergebnis wieder "krumme" Werte
hat.
Gast
#1099097
>Und wo bitte wird da auf 100 gerundet? >Da wird auf 128 gerundet, so dass er als Ergebnis wieder "krumme" Werte >hat. Das war ja auch ein Vorschlag...! Wenn ich für eine Rundung 30µs brauche aber nur 10µs zur Verfügung habe, muss man halt Kompromisse eingehen! ;-)
Wenn man es eh an den PC sendet kann der doch auch das runden übernehmen...
Ja mir war auch klar das es mit schieben viel schneller geht. Normalerweise würde ich es auch imer so machen. Der Problemfall hier ist aber das ich in 100er Schritten runden muss. Naja ich werde mal sehen ob ich das ganze noch etwas schneller hinbekomme.
Gast
#1099106
>Und wo bitte wird da auf 100 gerundet? >Da wird auf 128 gerundet, so dass er als Ergebnis wieder "krumme" Werte >hat. nur weil es im Decimalsystem nicht schön aussieht ist es doch im Binärsystem gut gerunden. Man muss halt etwas universeller Denken. (Es gibt genau 10 Arten von Menschen. Die, die binär verstehen, und die, die es nicht verstehen.)
Peter wrote: >>Und wo bitte wird da auf 100 gerundet? >>Da wird auf 128 gerundet, so dass er als Ergebnis wieder "krumme" Werte >>hat. > nur weil es im Decimalsystem nicht schön aussieht ist es doch im > Binärsystem gut gerunden. Man muss halt etwas universeller Denken. Und welchen Zweck erfüllt dann der im Binärsystem gerundete Wert? Gar keinen, denn eine korrekte Wertberuhigung (wie schon mehrfach erwähnt) macht man per Mittelwertbildung. Der einzige Grund für eine Rundung sind halt "schönere" Werte.
Gast
#1099146
Da Kn wrote: > Als String printen ist keine Lösung für mich, muss es mit dem unsigned > int Wert machen. Warum?
Gast
#1099660
@Threadersteller: Wie Schiebst du die Werte letztendlich über die UART? Irgendwas mit ITOA oder als Struct?
@ Tim T.: Du hättest das mit dem Quark ruhig drin lassen können, stimmte ja. Mein Blick auf den Code dort oben war doch etwas zu kurz.
Gast
#1099781
Jein, in der Sache ansich richtig, nur mein Ton gefiel mir selber nicht^^ Abgesehen davon war ich in der Annahme, da ich nicht genau gelesen habe, das der OP die Messwerte als ASCII überträgt, da ist ein Nullen natürlich einfach... Da dem aber wohl nicht so ist, fiele mir auch nichts ein ausser:
1 | |
2 | |
3 | |
4 | |
ein, wobei ich aber denke das der Modulo länger als eine Multiplikation und Division zusammen braucht. Ein anderer Ansatz wäre den Messwert erst zu Senden wenn er mehr als 100mV vom alten verschieden wäre:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Rundet zwar nicht direkt, sorgt aber dafür das das Zappeln aufhört. Alles in allem aber auch nicht ganz meine Lösungsart, da ich in diesem Falle eher die Auflösung des ADC runterschrauben würde...
Wie wärs damit:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
Obs letztlich kleiner/schneller ist, als Code mit Division weiß ich nicht... Das Prinzip läßt sich noch verfeinern.
ja, V und R. Bessere Variablen namen hätten es aber auch nicht sein können :P
Variablennamen schreibt man zusammen.
Ist richtig.
Version 2:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
Me ss wert mit mit doppel s geschrieben.... ;)
Nein.
Da Kn wrote: > Damit > die Werte nicht zu sehr schwanken würde ich gern in 100mV Schritten > runden. > > Bsp.: > > Gemessener Wert: Ausgegebener Wert: > 24113mV 24100mV > 24159mV 24200mV Was meinst du mit "schwanken" deine ausgegebenen Werte haben ein größeres Delta als deine gemessenen Werte. Was du willst ist quantisieren. Also Genauigkeit für die Ausgabe verschwenden. Wenn du das Schwanken eindämmen willst, nimm die schon erwähnte Methode des Mittelwertes, dies geht sehr effektiv mit:
1 | |
Das mit deinen 100 ist natürlich ne ganz spezielle Anforderung. Wie auch schon erwähnt wurde kann man sowas mit 2^n Werten am effektivsten umsetzen. ansonsten kommt in etwa sowas raus:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
GRUß ;-)
Gast
#1099873
Hey Daniel, seit wann verwendet ihr denn an der FH MSP? ;-) Achja, wenn du die Werte in ASCII über die UART schickt, dann habt ihr dort ja auch schon Module und Divison drin, vielleicht kann man dort optimieren? Gruß ein Ex-Mitstudent
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.