Hallo zusammen,
Ich möchte den Mittelwert einer (10Bit) ADC Messung über eine Zeit-x
(10sek) erfassen/auswerten.
Ich möchte jedoch, dass immer der letzte Wert rausfällt und der aktuelle
übernommen wird.
Also nich immer neu bei 0 anfangen.
Wie programmiert man so etwas am geschicktesten.
100 Variablen anlegen und damit rumrechnen kommt mir nicht ideal vor.
Ich könnte natürlich 1x den Mittelwert abziehen und den neuen Wert
addieren, aber ein echter Mittelwert wird das nicht...
Danke für eure Hilfe
Philipp L. schrieb:> Hallo zusammen,>> Ich möchte den Mittelwert einer (10Bit) ADC Messung über eine Zeit-x> (10sek) erfassen/auswerten.> Ich möchte jedoch, dass immer der letzte Wert rausfällt und der aktuelle> übernommen wird.> Also nich immer neu bei 0 anfangen.
Nennt sich moving average filter.
> Wie programmiert man so etwas am geschicktesten.
Mit einem Array mit 100 Elementen und einem Akku. Im Akku steht die
Summe aller Elemente drin. Wenn nun ein neuer Wert reinkommt, wird der
älteste Eintrag vom Akku entfernt, mit dem neuen Wert im Array
überschrieben und der neue Wert zum Akku hinzuaddiert. Mit diesem Trick
spart man sich bei jedem Durchlauf das Aufsummieren der 100 Werte. Der
Mittelwert ist dann Akku/100, diese Division kann man nicht einsparen.
> 100 Variablen anlegen und damit rumrechnen kommt mir nicht ideal vor.
Die 100 Variablen stecken im Array.
Stichwort ist Ring-buffer. Die Idee ist ein Array mit 100 Stellen
anlegen und einen separaten Zeiger nehmen der immer auf eine Zelle
zeigt.
Bei jedem neuen Wert schreibst du den an die Zeiger-Position und
incrementierst den Zeiger. Wenn du bei hundert bist, springst du wieder
zur ersten Position des Arrays.
Die Reihenfolge der Werte im Speicher stimmt damit natürlich nicht, aber
bei vielen Berechnungen wie Mittelwert ist das ja irrelevant da nur der
Wert und nicht der Index zählt.
Mittels der momentanen Zeiger-Position kann man, wenn nötig eine
Schleife auf dem Array auch in der richtigen Reihenfolge laufen lassen.
Btw. wenn du Speicher sparen musst, versuche den kleinstmöglichen
Datentyp für dein Array zu nehmen.
Nimm ein Array, anders wird es nicht funktionieren, da du dir immer die
Messwerte einzeln speichern musst. Wenn dir der Fehler relativ egal ist
könntest du auch für jeden neuen Messwert den du addierst einmal den
Mittelwert der letzten 100 Messungen abziehen. Dann kämst du mit 3
Variablen aus.
Philipp L. schrieb:> Wie programmiert man so etwas am geschicktesten.> 100 Variablen anlegen und damit rumrechnen kommt mir nicht ideal vor.
Immer wenn du einen neuen Wert erhältst, ziehst du den ältesten von der
Summe ab und addierst den neuen drauf. Dazu mußt du dir die alten Werte
in einem Array merken. Bei 100 Werten ist das natürlich entsprechend
groß. Aber solange der Speicher das hergibt auch kein Problem. Dem
Controller ist das egal. Und Geld gibt es für gesparten Speicher auch
nicht zurück.
Philipp L. schrieb:> Wie programmiert man so etwas am geschicktesten.
Suche nach Implementierungen von "gleitender Mittelwert". Es gibt
unzählige davon.
Im Prinzip benötigt man einen Ringpuffer und eine Summenvariable.
Besonders effizient wird es, wenn man die Größe des Ringpuffers auf eine
Zweierpotenz festlegt, denn dann braucht man zur Ermittlung des
Mittelwerts nicht dividieren, sondern nur schieben. Auch die Verwaltung
des Ringpuffers selber kann dann effizienter geschehen.
Dussel schrieb:> Das ist etwas unglücklich ausgedrückt.> Ich meinte das iterativ, also> Neuer_Mittelwert=(Alter_Mittelwert*99+Neuer_Mittelwert)/100
Damit hat man natürlich Abweichungen, aber es ist die
speicherschonendste Variante.
Die Idee mit dem "Akku" ist richtig gut!
Das mit dem Akku ist auch eine gute Idee. das ist genauer. Es kommt auch
drauf an, was wichtig ist, Speicher, Laufzeit oder Genauigkeit.
Falk B. schrieb:> Der Mittelwert ist dann Akku/100, diese Division> kann man nicht einsparen.
Da es um "ca. 100 Werte" geht, geht vielleicht auch 128.
um die 100 Variablen wirst Du nicht rumkommen.
in Integer Arithmetik ist es einfach. Mit float geht das nicht so.
static uint16_t buf[100];
static uint32_t ergebnis=0;
static int Cnt=0;
uint32_t getAverage(uint16_t wert)
{
if(Cnt >= 100) Cnt=0;
ergebnis -= buf[Cnt];
ergebnis += wert;
buf[Cnt] = wert;
Cnt++;
return ergebnis;
}
die ersten 100 Messungen kommt nichts vernüftiges heraus, da die
Vorgeschichte nicht bekannt ist. buf[100] muss auch mit Nullen
initialisiert sein, falls der Compiler das nicht auomatisch tut.
Martin B. schrieb:> die ersten 100 Messungen kommt nichts vernüftiges heraus, da die> Vorgeschichte nicht bekannt ist.
Stimmt nicht. Es kommt die Sprungantwort des Filters raus, so wie auch
bei einem analogen RC-Filter, das auf Spannung 0V geladen ist.
Okay, den Code muss ich mir in Ruhe ansehen.
Habe mit Arrays noch nichts gemacht und bin noch C-Anfänger...
Aber vielen Dank schon mal!
Die Genauigkeit ist nicht soo wichtig (grobe Überstromabschaltung).
Die ersten 100 Werte sind mir egal.
Es soll aber eine kleine Unterfunktion auf dem Controller sein und nicht
übermäßig viele Takte verbraten.
Philipp L. schrieb:> Es soll aber eine kleine Unterfunktion auf dem Controller sein und nicht> übermäßig viele Takte verbraten.
Dann nimm keine 100 Werte, sondern eine 2er-Potenz. Also 64 oder 128.
Dann kann die Division durch die Anzahl Werte als effektives shift
gemacht werden.
(macht der Compiler wahrscheinlich dann automatisch)
Das wurde oben auch schon mehrfach angeregt.
Ja, die 100 Werte sind nicht fix.
die Division als Schiebefunktion ist gut.
Habe ich es richtig verstanden, dass der Ringbuffer nicht ständig
geändert und dann als ganzes summiert wird.
Sondern man verwendet eine Summenvariable und verwendet den Pointer nur
um den ältesten Wert rauszuholen, von der Summe zu sub. und dann den
aktuellen Wert zu Add. ?
Klingt für mich gut und effektiv.
Über die Initialisierung muss man sich auch noch Gedanken machen:
Wenn es keine Rolle spielt, dass die ersten 100 Mittelwerte nur langsam
an den tatsächlichen heran schleichen, benötigt man keine
Initialisierung.
Sonst kann man entweder das Array komplett mit dem ersten Messwert
initialisieren. Oder auch mehrere Messwerte zur Initialisierung heran
ziehen.
Außerdem ist es noch eine gute Idee, z.B. die 5 maximalen und die 5
minimalen Werte raus fallen zu lassen. So vermeidet man, dass Ausreißer
den Mittelwert verfälschen.
Da hier aber der Mittelwert aus 100 Messwerten gewonnen wird, fallen
Ausreißer ohnehin nicht sehr ins Gewicht.
Mark U. schrieb:> Wenn es keine Rolle spielt, dass die ersten 100 Mittelwerte nur langsam> an den tatsächlichen heran schleichen, benötigt man keine> Initialisierung
Man braucht immer eine Initialisierung!
> Außerdem ist es noch eine gute Idee, z.B. die 5 maximalen und die 5> minimalen Werte raus fallen zu lassen. So vermeidet man, dass Ausreißer> den Mittelwert verfälschen.
Immer soviel wegwerfen, bis das Weltbild stimmt? Das ist keine gute Idee
sondern der Versuch, an den Daten herumzufuschen.
Udo S. schrieb:> Dann nimm keine 100 Werte, sondern eine 2er-Potenz. Also 64 oder 128.
Was soll der Unfug? Wenn ich 100 Werte mitteln möchte/muß, dann nehme
ich 100 Werte. Soll wieder der µC entlastet werden, um sich noch mehr zu
langweilen?
Dussel schrieb:> Das ist etwas unglücklich ausgedrückt.> Ich meinte das iterativ, also> Neuer_Mittelwert=(Alter_Mittelwert*99+Neuer_Mittelwert)/100
Du hast nicht verstanden, was der TO möchte.
Bei ihm soll der Mittelwert der letzten 100 Werte berechnet werden, also
braucht er ein FIR-Filter.
Deine Gleichung beschreibt ein IIR-Filter
https://de.wikipedia.org/wiki/Filter_mit_unendlicher_Impulsantwort
Dussel schrieb:> Mit einem Array kann man es natürlich machen.> Es müsste aber auch gehen mit (Mittelwert*99+Neuer_Wert)/100.
Ja in etwa so. Nennt sich dann "IIR Filter".
Etwas anschaulicher macht man es dann so:
Filterfaktor = 0.xxxx
GefilterterWert = GefilterterWert - (GefilterterWert * Filterfaktor) +
(Messwert * Filterfaktor)
Habe mir die beiden Codes grad in der Mittagpause angesehen.
Klingt sehr logisch, wird heute Abend gleich probiert.
Danke für die schnelle Hilfe, das Forum hier ist super !!
Was ich auch noch nicht spontan überblicke, sind die notwendigen Takte
bei der Divison.
return accu/100;
oder
return accu<<7; -> geht das oder muss ich erst accu = accu<<7
schreiben?
Dann natürlich mit filter[128].
Wolfgang schrieb:> Dussel schrieb:>> Das ist etwas unglücklich ausgedrückt.>> Ich meinte das iterativ, also>> Neuer_Mittelwert=(Alter_Mittelwert*99+Neuer_Mittelwert)/100>> Du hast nicht verstanden, was der TO möchte.Johnny B. schrieb:> Dussel schrieb:>> Mit einem Array kann man es natürlich machen.>> Es müsste aber auch gehen mit (Mittelwert*99+Neuer_Wert)/100.>> Ja in etwa so. Nennt sich dann "IIR Filter".
Verstanden habe ich es natürlich, aber ich hatte einen Denkfehler. Mein
Ansatz beschreibt keinen arithmetischen Mittelwert.
Philipp L. schrieb:> return accu<<7; -> geht das oder muss ich erst accu = accu<<7> schreiben?> Dann natürlich mit filter[128].
Und natürlich 'accu >> 7'. Du willst ja dividieren, nicht
multiplizieren.
Bei einer Groben Überstromabschaltung reicht sicher ein Muittelwert über
3 oder 4 Werte. Dann Abschaltung wenn Wert >= Wert_max ist. Da reicht ja
noch ein Komparator aus.
> Bei einer Groben Überstromabschaltung reicht sicher ein Muittelwert über> 3 oder 4 Werte. Dann Abschaltung wenn Wert >= Wert_max ist. Da reicht ja> noch ein Komparator aus.
Da bin ich anderer Meinung, da der Strom wie geschrieben über min. 10sek
gemittelt werden soll (eher länger).
Denn es geht um die Erwärmung eines step-down an der Spule.
Dieser kann laut Datenblatt 3A, wird bei dieser Dauerbelastung aber sehr
heiß!
Daher teste ich, mit welcher Dauerbelastung der nicht übermäßig warm
wird.
Dieser wird dann der Grenzwert der Mittelwerterfassung.
So kann ich die vollen 3A kurzzeitig ausnutzen (Servo`s, usw..), habe
aber trotzdem die Sicherheit das der nicht überhitzt.
> Und natürlich 'accu >> 7'. Du willst ja dividieren, nicht> multiplizieren.
Ups..
Die eigentliche Frage war, wie viele Takte benötigt ein
x/128 und im Vergleich dazu ein x>>7
Das Ergebnis sollte doch gleich sein?
> void Filtern(float &FiltVal, int NewVal, int FF){> FiltVal= ((FiltVal * FF) + NewVal) / (FF+1);}
Das ist aber kein exakter Mittelwert wie beim Array, sondern eher wie:
>Neuer_Mittelwert=(Alter_Mittelwert*99+Neuer_Mittelwert)/100
Philipp L. schrieb:> Die eigentliche Frage war, wie viele Takte benötigt ein> x/128 und im Vergleich dazu ein x>>7
Schreibe immer: x/128. Der Compiler wird es richten.
Diese Takte kannst Du Dir einfach sparen, indem Du den Überstrom als
#define MAX_STROM (GRENZWERT * 128)
vorgibts. Das geht auch für (GRENZWERT * 100) genau so schnell ;-)
m.n. schrieb:> Immer soviel wegwerfen, bis das Weltbild stimmt? Das ist keine gute Idee> sondern der Versuch, an den Daten herumzufuschen.
"weltbild" geht schon in die richtige richtung.
der to sollte erst mal klären welche physikalische grösse (weltbild) er
abbilden will und zeitliche änderungsrate? gültiger wertebereich?
störgrössen art? ... sollen evtl. gefiltern werden und erst dann,
entscheidet man wie das geschehen soll moving average ist oft kontra
indiziert und eher ein exp. filer macht den job besser, like
//linear recursive exponential filter, weight e.g. 0.3=30%
//y(t)=(1-w)*y(t-1)+w*x(t)
oldValue = (1 - weight) * oldValue + weight * newValue;
ohne messtechnik und statistik grundkentnisse wird das wieder nur das
übliche raten von schwachmaten.
mt
Name H. schrieb:> Eine effiziente implementierung :> https://www.ibrtses.com/embedded/exponential.html
das ist ein "linear recursive exponential filter" und wie schon
geschrieben kann die richtige wahl sein muss aber nicht!
die filterwahl (und nichts anderes ist mittelwertbildung) hängt von der
konkreten fragestellung ab, was will ich erreichen unter welchen
bedingungen?!
... moving average der lottezahlen der letzten 4 wochen macht das sinn?
mt
Udo S. schrieb:> Dann nimm keine 100 Werte, sondern eine 2er-Potenz. Also 64 oder 128.
Da er 10-Bit addiert wären 64 Werte besser, weil dann ein 16-Bit Wert
für die Summe reicht.
Martin B. schrieb:> static uint16_t buf[100];> ....>> buf[100] muss auch mit Nullen> initialisiert sein, falls der Compiler das nicht auomatisch tut.
static und globale Variablen werden immer mit 0 initialisiert, sofern
nichts anderes angegeben wird.
Philipp L. schrieb:> return accu<<7; -> geht das oder muss ich erst accu = accu<<7
Wie schon an anderer Stelle geschrieben, mußt du natürlich nach rechts
schieben.
Du kannst aber auch
1
returnaccu/128;
schreiben.
Die Optimierung des Compilers sorgt dafür, daß in beiden Fällen dasselbe
rauskommt.
Bernd K. schrieb:> Sag das mal dem Keil C51 Compiler :-(
Das war schon klar, daß sowas kommt.
Allerdings darf man, wenn da nichts anderes steht, in diesem Forum davon
ausgehen, daß es sich um einen AVR handelt, dessen C-Code mit GCC bei
-Os kompiliert wird.
> störgrössen art? ... sollen evtl. gefiltern werden
Nein, es müssen alle Werte mit in das Ergebnis einfließen.
Denn es handelt sich bei einem "Ausreißer" EVTL. nicht um eine Störung
sondern den Anlaufstrom eines z.B. Motors.
HINWEIS:
Es werden vermutlich alle hier genannten Methoden für meinen
Anwendungsfall ausreichend sein.
Denn ich möchte ja nur wissen, ob der Stepdown-Regler länger als Zeitx
(min. aber 10sek) mit mehr als dem definierten Grenzwert belastet wird.
Der Grenzwert ist ja auch nur empirisch ermittelt worden und liegt unter
dem im Datenblatt angegebenen Wert.
Es geht mir darum, dass das Teil nicht zuuu warm wird.
Also alles halb so wild, trotzdem sind die verschiedenen Modelle
interessant gewesen.
Ich werde jedoch das Array verwenden, da es mir am besten gefällt und
genau meine ursprüngliche Vorstellung wiedergibt.
Danke euch allen!!
Philipp L. schrieb:> Denn ich möchte ja nur wissen, ob der Stepdown-Regler länger als Zeitx> (min. aber 10sek) mit mehr als dem definierten Grenzwert belastet wird.> Der Grenzwert ist ja auch nur empirisch ermittelt worden und liegt unter> dem im Datenblatt angegebenen Wert.> Es geht mir darum, dass das Teil nicht zuuu warm wird.
Erwärmung hängt (normalerweise) von der Verlustleistung ab ( Delta T =
Wärmewiderstand × Verlustleistung). Diese hängt vom Quadrat des Stromes
ab (z.B.: I^2 x R DS on x duty_cycle des Schalt Mosfets im Stepdown
Regler)
Mit dem Durschnitt der I^2 könnte man dieses Verhalten wohl besser
abbilden(absichern). Das sollte dann auch besser dem Verhalten einer
Feinsicherung entsprechen.
Philipp L. schrieb:> Da bin ich anderer Meinung, da der Strom wie geschrieben über min. 10sek> gemittelt werden soll (eher länger).> Denn es geht um die Erwärmung eines step-down an der Spule.> Dieser kann laut Datenblatt 3A, wird bei dieser Dauerbelastung aber sehr> heiß!>> Daher teste ich, mit welcher Dauerbelastung der nicht übermäßig warm> wird.> Dieser wird dann der Grenzwert der Mittelwerterfassung.>> So kann ich die vollen 3A kurzzeitig ausnutzen (Servo`s, usw..), habe> aber trotzdem die Sicherheit das der nicht überhitzt.
Das ist doch BLÖDSINN. Bei pulsweiser Belastung wirst Du da im
schlimmsten Fall nichts erfassen, weil Du möglicher weise während der
Laspause misst, und die Kiste wird kochen. Die Überhitzung hat auch was
mit der Umgebungsluft zu tun. Da hift die Srrommessung nicht. Vertane
Zeit sage ich mal. Beschäftige Dich mit der Temp.-Messung.
Stephan schrieb:> Was wird passieren ?
Es gibt keine Lösung des Problems.
Warum? Es darf sie nicht geben.
Was der TO auch immer machen wird, es wird alles falsch sein ;-)
Philipp L. schrieb:> Ich werde jedoch das Array verwenden,
Fange einfach an!
Veit D. schrieb:> das geht auch ohne Array. Ein schlauer Mensch hat das zur Verfügung> gestellt. Nennt sich gleitender Mittelwert.
Wie oben bereits festgestellt, ist diese Behauptung falsch. Die
Berechnung ohne Array, die Du hier anfügst, wurde oben bereits (in
abgewandelter Form) erwähnt. Das ist ein IIR-Filter (Infinite Impulse
Response) und kein gleitender Mittelwert, denn ein IIR-Filter hat ein
"unendliches Gedächtnis".
Um einen "gleitenden Mittelwert" zu erhalten, kommst Du um das Array
nicht herum. Hier wird immer nur ein endliches Zeitfenster betrachtet.
Was vor ein paar Tagen war, spielt hier keine Rolle. Das nennt sich
deshalb auch FIR-Filter (Finite Impulse Response).
Siehe auch: https://de.wikipedia.org/wiki/Gleitender_Mittelwert
> Das ist doch BLÖDSINN.
Ach wie schön...
Mal wieder jemand der sich bei einer anderen Meinung gleich angegriffen
fühlt :-) :-) :-)
>Bei pulsweiser Belastung wirst Du da im schlimmsten Fall nichts erfassen,>weil Du möglicher weise während der Laspause misst,>und die Kiste wird kochen.
woher soll denn die pulsweise Belastung in meinem sekundären Teil
kommen?
Die Spannung hinterm stepdown ist kondensatorgepuffert.
Ausnahme:
Bei Servo`s die kurz von POS-A zu POS-B fahren, kann es evtl. zu
Messfehlern kommen.
Aber diese kurzzeitbelastung ist bei der Erwärmung des Reglers zu
vernachlässigen.
Nochmals:
Dies ist eine on-Top Maßnahme, ich bewege mich immer innerhalb der
Grenzen des Datenblattes...
> Die Überhitzung hat auch was mit der Umgebungsluft zu tun.> Da hift die Srommessung nicht.
keine Sorge, wird nicht in der Wüste eingesetzt..
> Vertane Zeit sage ich mal. Beschäftige Dich mit der Temp.-Messung.
Natürlich die beste Variante, aber zuviel des guten.
extra einen Tempsensor auf die Spule, usw... Nee...
> ps. Ich schäume Deinen Step Down ein und Du misst dafür fleißig den> Strom. Was wird passieren ?
Jeder Kommentar ist hier einer zuviel :-)
Es wäre schön, wenn wir den Thread diesmal nicht mit gegenseitigen
"Angriffen" kaputt machen...
Ich habe jedenfalls genug Informationen für die umsetzung bekommen.
Danke und bis zum nächsten mal.
Veit D. schrieb:> Ein schlauer Mensch hat das zur Verfügung> gestellt. Nennt sich gleitender Mittelwert.
Die Rechnung hat nur den kleinen Schönheitsfehler, dass sich der
"schlaue" Mensch vertan hat und damit kein gleitender Mittelwert
berechnet wird.
Hier kannst du nachlesen, wie der richtig berechnet wird:
https://de.wikipedia.org/wiki/Gleitender_Mittelwert
Wolfgang schrieb:> Die Rechnung hat nur den kleinen Schönheitsfehler, dass sich der> "schlaue" Mensch vertan hat und damit kein gleitender Mittelwert> berechnet wird.>> Hier kannst du nachlesen, wie der richtig berechnet wird:> https://de.wikipedia.org/wiki/Gleitender_Mittelwert
In dem von dir verlinkten Wikipedia-Artrikel wird unterschieden zwischen
1. dem einfachen (gleichgewichteten) gleitenden Mittelwert und
2. dem exponentiell geglätteten (exponentiell gewichteten gleitenden)
Mittelwert.
(1) zählt zu den FIR-Filtern, benötigt ein Array als Puffer für die
letzten n Messwerte und wird von Philipp gerade implementiert.
(2) zählt zu den IIR-Filtern, kann unabhängig vom Filterfaktor mit nur
wenigen Einzelvariablen implementiert werden, verhält sich wie ein
analoger Tiefpass 1. Ordnung und wird durch der von Veit geposteten Code
des "schlauen Menschen" umgesetzt.
Für Philipps Problemstellung liefern IMHO beide Verfahren brauchbare,
wenn auch unterschiedliche Ergebnisse.
Philipp L. schrieb:> Die eigentliche Frage war, wie viele Takte benötigt ein> x/128 und im Vergleich dazu ein x>>7> Das Ergebnis sollte doch gleich sein?
Für die Zukunft: einfach den Compiler Explorer fragen was dabei
compiliert wird (AVR-spezifisch: http://avr-gcc.senthilthecoder.com,
allgemeiner: https://godbolt.org/)
Gibt man dem AVR compiler explorer folgenden Quellcode
1
intshift(intin){
2
return(in>>7);
3
}
4
5
intdiv(intin){
6
return(in/128);
7
}
mit Compiler-Optionen -Os -mmcu=atmega328p -std=gnu99 und gcc 4.9.2, so
wird daraus folgendes:
shift:
1
lsl r24
2
mov r24,r25
3
rol r24
4
sbc r25,r25
5
ret
div:
1
sbrs r25,7
2
rjmp .L3
3
subi r24,-127
4
sbci r25,-1
5
.L3:
6
lsl r24
7
mov r24,r25
8
rol r24
9
sbc r25,r25
10
ret
Resultat: definitiv nicht das selbe (was ich nicht erwartet hätte...)
-O2 ist auch nicht gleich.
*Viel schlimmer*: avr-gcc 4.5.1/4.6.4 fügen mit "-Os" ein
Philipp M. schrieb:> Philipp L. schrieb:>> Die eigentliche Frage war, wie viele Takte benötigt ein>> x/128 und im Vergleich dazu ein x>>7>> Das Ergebnis sollte doch gleich sein?>> Für die Zukunft: einfach den Compiler Explorer fragen was dabei> compiliert wird (AVR-spezifisch: http://avr-gcc.senthilthecoder.com,> allgemeiner: https://godbolt.org/)
Mit unsigned int wäre das nicht passiert. x>>7 ist für x < 0
implementation-defined Rotz.
Jemand schrieb:> it unsigned int wäre das nicht passiert. x>>7 ist für x < 0> implementation-defined Rotz.
Kann man trotzdem näherungsweise machen für negative Zahlen.
x>>7 und x/128 ist nur für positive Zahlen dasselbe. War schon immer so.
für negative Zahlen unterscheidet sich das Ergebnis um 1. Aber auch
nicht mehr.
Jemand schrieb:> Mit unsigned int wäre das nicht passiert. x>>7 ist für x < 0> implementation-defined Rotz.
Damit hast du Recht, mit uint16_t sind beide Operationen gleich. Das
doofe ist nur - die "richtige" Operation (Division) ist langsam, während
die implementation-defined Operation das korrekte Verhalten liefert.
Yalu X. schrieb:> 2. dem exponentiell geglätteten (exponentiell gewichteten gleitenden)> Mittelwert.
Egal ob man diesem Konstrukt die Bezeichnung Mittelwert zuschreibt - das
Ergebnis dieser Operation setzt sich nicht aus einer festen Anzahl von
Messwerten zusammen und entspricht damit nicht dem Ziel des TOs.
So schwer ist das doch nicht.
Martin B. schrieb:> für negative Zahlen unterscheidet sich das Ergebnis um 1. Aber auch> nicht mehr.
Meinst du Negation vs. bitweises Invertieren? Da stimmt das. "x>>"
funktioniert auch für negative Zahlen, wenn man Vorzeichenerweiterung
macht, d.h. beim rechts schieben nicht links Nullen einfügen sondern das
MSB kopieren.
Wolfgang schrieb:> Egal ob man diesem Konstrukt die Bezeichnung Mittelwert zuschreibt - das> Ergebnis dieser Operation setzt sich nicht aus einer festen Anzahl von> Messwerten zusammen und entspricht damit nicht dem Ziel des TOs.>> So schwer ist das doch nicht.
Ein IIR erster Ordnung entspricht aber eher dem zugrundeliegendem
physikalischen Modell, das der TO zu erfassen versucht - eine
Überstromspitze hinterlässt ihren thermischen Eindruck auch nach 10
Sekunden noch, und so ist ein IIR zwar nicht das erklärte Ziel des TOs,
aber vielleicht das was er tatsächlich braucht, ohne dass er das weiß.
Das zu erkennen und zu vermitteln ist schwer.
Philipp M. schrieb:> Martin B. schrieb:>> für negative Zahlen unterscheidet sich das Ergebnis um 1. Aber auch>> nicht mehr.>> Meinst du Negation vs. bitweises Invertieren? Da stimmt das. "x>>"> funktioniert auch für negative Zahlen, wenn man Vorzeichenerweiterung> macht, d.h. beim rechts schieben nicht links Nullen einfügen sondern das> MSB kopieren.
Um beim Beispiel shiften eines int um 7 zu bleiben:
-1 ... -128 liefern beim shiften eine -1
-1... -127 liefern beim dividieren eine 0, bei -128 eine -1
um das zu korrigieren muss bei einer Division einer negativen Zahl durch
128 erst 127 aufaddieren und dann um 7 shiften. Dann stimmt es wieder
genau.
Philipp M. schrieb:> Für die Zukunft:
... erst einmal darüber nachdenken, welcher Datentyp denn notwendig ist.
Im vorliegenden Fall muß es uint32_t sein.
Da der Mittelwert mit einem Grenzwert verglichen werden soll, geht es -
wie oben schon angedeutet - viel schneller, jegliche Division zu
unterlassen und direkt die Summe der Einzelwerte zum Vergleich nutzen.
Allerdings bezweifele ich, daß die Ausführungsgeschwindigkeit irgendeine
Rolle spielt. Ein delay(100) braucht mehr Zeit. Oder optimiert Ihr das
auch immer?
Philipp M. schrieb:> Wolfgang schrieb:>> Egal ob man diesem Konstrukt die Bezeichnung Mittelwert zuschreibt - das>> Ergebnis dieser Operation setzt sich nicht aus einer festen Anzahl von>> Messwerten zusammen und entspricht damit nicht dem Ziel des TOs.>>>> So schwer ist das doch nicht.>> Ein IIR erster Ordnung entspricht aber eher dem zugrundeliegendem> physikalischen Modell, das der TO zu erfassen versucht - eine> Überstromspitze hinterlässt ihren thermischen Eindruck auch nach 10> Sekunden noch, und so ist ein IIR zwar nicht das erklärte Ziel des TOs,> aber vielleicht das was er tatsächlich braucht, ohne dass er das weiß.>> Das zu erkennen und zu vermitteln ist schwer.
Das sehe ich genauso.
Mathematisch betrachtet ist es richtig was Wolfgang schreibt, in der
Praxis für die genannte Anwendung jedoch völlig irrelevant, zumal ein
ADC eh nicht 100% genau misst. Daher liefert für diese Anwendung ein IIR
Filter das gewünschte Resultat und ist zudem sehr einfach realisiert
(minimiert Programmierfehler) und benötigt nur sehr wenig Speicher.