Forum: Mikrocontroller und Digitale Elektronik ADC/Sensorwert - Mittelwert


von kathleen (Gast)


Lesenswert?

Hallo Leute,

schön langsam bekomme ich einen Knopf im Gehirn :-/ hab bis jetzt ALLE 
Beiträge zu "Mittelwert-Berechnung" durch - komme aber trotzdem nicht 
auf mein geplantes Ergebnis. vlt kann mir hier ja wer weiterhelfen.

Rand-Infos:
PIC18F2550; einlesen von Sensor-Daten mittels ADC und Umrechnung dann in 
Pascal-Werte; diese Sensor-Daten werden kontinuierlich eingelesen - über 
10 Messungen soll dann ein Mittelwert berechnet werden u falls dieser 
dann in (voreingestellten) Grenzen "ausfährt" soll ein Alarm ausgegeben 
werden.
Ausgabe erfolgt auf einem LCD-Display (über RS232)

Ausschnitte von meinem Code:
1
set_adc_channel(1);
2
   delay_us(50);
3
  sensor_data = read_adc();
4
        //Umrechnung von ADC auf Pascal
5
  pa_value = ((float)sensor_data-429)*62/389; 
6
        
7
  act_pressure_values[1] = sensor_data;      //(int16)pa_value;
8
  //Ausgabe auf LCD      
9
  printf("\f   Sensor1   \r");
10
  printf("   %lu Pa  ",act_pressure_values[1]);  //0x94 CR line 1  delay_ms(100);

was ich nun zur Mittelwertberechnung gefunden habe, ist folgendes:
1
   SummeMessungen+=Ergebnis;
2
   AnzahlMessungen++;
3
4
      if(AnzahlMessungen == 10){
5
      Ergebnis = SummeMessungen/AnzahlMessungen;
6
7
      if(Ergebnis >=limits)
8
      printf("\f***ALARM***);
9
10
      SummeMessungen = 0;
11
      AnzahlMessungen = 0;
wo ich nun schon seit Tagen hänge - u auch durch probieren auf keinen 
gemeinsamen Nenner komme, ist die "Variablen-Zuweisung". :-/
vlt kann mir da kurz jemand weiterhelfen, damit ich ENDLICH meine 
Diplomarbeit abschließen kann.

DANKE schon mal im vorhinein (u sorry, dass schon wieder eine Frage 
bezüglich "Mittelwert" aufgetaucht ist)

: Bearbeitet durch Moderator
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich weiss nicht, wieviel Rechenleistung du zur Verfügung hast, aber 
meist ist es sinnvoll, den Mittelwert zu machen, bevor du die Umrechnung 
in deine Ergebnisse machst, also bildest du den Mittelwert aus den rohen 
ADC Werten.

Du machst dir z.B. einen Fifo mit 10 Plätzen auf, in dem du den ältesten 
Wert rauswirfst und den neusten einfügst. Alle Werte im Fifo addieren 
und durch 10 teilen, dann auf die Umrechnung schicken. 'sensor_data' 
wird so zu einem Array von 10, plus einem Pointer auf den neusten Wert.
Alleridngs wundert mich schon, wie du es so bis zur Diplomarbeit 
geschafft hast.

von Pandur S. (jetztnicht)


Lesenswert?

Ich wuerd diese Fifo Mittelwert Geschichte durch den exponentiellen 
Mittelwert ersetzen, der benotigt viel weniger Resourcen, (eine 
Speicherstelle & Schieben-Summieren) und man hat immer einen aktuell 
gemittelten Wert am Ausgang. Der grad gemessene Wert verliert 
exponentiell an Bedeutung.

Siehe http://www.ibrtses.com/embedded/exponential.html

Und. Ja. Den ADC Wert mitteln, die Skalierungen kommen allenfalls fuer 
das Userinterface, waehrend man sinnvollerweise mit dem ADC Wert 
weiterrechnet. Im fuer den Prozess sinnvollen Takt.

Floating point wuerde ich vermeiden. Ich rechne jeweils mit Integer 32 
bit.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

kathleen schrieb:
> Diplomarbeit
> pa_value = ((float)sensor_data-429)*62/389;
Aber holla, dafür würde ich Punkte abziehen (und das delay_us sehr 
kritisch hinterfragen!!!). Denn auf einem uC rechnet man so lang wie 
möglich in Integer. Und bestenfalls zur Ausgabe kommt dann ein Float ins 
Spiel...

kathleen schrieb:
> Ausschnitte von meinem Code
Ein paar Zeilen über dem Eingabefenster steht da was:
1
Wichtige Regeln - erst lesen, dann posten!
2
3
Formatierung
4
    [c]C-Code[/c]

kathleen schrieb:
> über 10 Messungen soll dann ein Mittelwert berechnet werden
Also musst du die letzten zehn Messungen speichern. Das machst du in 
einem Ringpuffer, in dem immer der älteste Wert überschrieben wird. Und 
danach wird die Summe dieses Puffers gebildet und durch 10 geteilt:
1
   int  ring[10];
2
   char index = 0;
3
   :
4
   :
5
6
   set_adc_channel(1);
7
   delay_us(50);
8
   // neuen Wert in den Puffer eintragen
9
   ring[index] = read_adc();
10
   // Index weiterzählen
11
   if (index==9) index=0;
12
   else          index++;
13
14
   :
15
   :
16
   // Mittelwert berechnen
17
   // Summe bilden
18
   for (int i=0, sum=0; i<10; i++)  sum += ring[i];
19
   // Mittelwert skalieren
20
   mittelwert = sum/10;

Aber auch ich würde den erwähnten PT1-Mittelwert verwenden:
http://www.lothar-miller.de/s9y/archives/25-Filter-in-C.html
Beitrag "PT1-Filter in C"

BTW: 10 ist eine blöde Größe für einen uC. Denn der arbeitet viel lieber 
mit binären Zahlen. 8 wäre eine schöne Zahl, oder 16...

: Bearbeitet durch Moderator
von kathleen (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Alleridngs wundert mich schon, wie du es so bis zur Diplomarbeit
> geschafft hast.

---> ? was soll diese Bemerkung? ich glaube, OHNE Hintergrundwissen zu 
meiner Person kannst du dir dies sparen!
(ich komme aus einem GANZ anderen Metier - habe Koch gelernt - u bin nun 
innerhalb von 2 Jahren auf einen technischen Beruf umgesattelt - u 
innerhalb von 2 Jahren dann noch den gesamten Bereich von 
Mikrokontroller, Elektrotechnik usw. NACHzulernen u nebenbei beruflich 
in Schichtarbeit tätig zu sein ist SICHER nicht einfach! da kann man vor 
mir schon den hut ziehen, dass ich es überhaupt so weit geschafft habe!)

Lothar Miller schrieb:
>> Diplomarbeit
>> pa_value = ((float)sensor_data-429)*62/389;
> Aber holla, dafür würde ich Punkte abziehen (und das delay_us sehr
> kritisch hinterfragen!!!). Denn auf einem uC rechnet man so lang wie
> möglich in Integer. Und bestenfalls zur Ausgabe kommt dann ein Float ins
> Spiel...

---> dasselbige gilt für dich!

ich dachte hier wird einem NETT geholfen, aber nicht kritisch 
hinterfragt, warum wieso weshalb es diese Person soweit geschafft hat!?

ansonst - DANKE für eure Antworten - werde mich weiter damit 
beschäftigen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

kathleen schrieb:
> DANKE für eure Antworten - werde mich weiter damit beschäftigen.
Keine Ursache.

> ich dachte hier wird einem NETT geholfen, aber nicht kritisch
> hinterfragt
Jede Angabe muss kritisch hinterfragt werden. Oft kommt einer und sagt: 
ich WILL es genau so oder so machen. Mit einer kleinen Rückfrage stellt 
sich raus, dass derjenige es eben nicht besser weiß und es deshalb 
genauso eigenartig und umständlich machen WILL. Und es könnte sein, dass 
deine Forderung "über 10 Messungen soll dann ein Mittelwert berechnet 
werden" eben diesen Hintergrund hat.

> da kann man vor mir schon den hut ziehen, dass ich es überhaupt so weit
> geschafft habe!
Im Ernst: das interessiert eigentlich Keinen (oder nur dann, wenn du es 
gewinnbringend verkaufen kannst: "Durchaltevermögen, Zielstrebigkeit, 
Belastbarkeit, blabla").
Das mit dem Punkteabzug habe ich wirklich so gemeint. Es ist bei der 
Diplomarbeit nämlich schnurzpiepegal, was man vorher gemacht hat. DU 
wollstest doch E-Techniker werden. Dann musst DU dich mit der 
E-Technik-Latte messen lassen. Und die liegt nun mal ein wenig höher...

Und noch ein Wort zur Praxis, die du nach deiner Diplomarbeit in gut 
einem viertel Jahr auch betreten willst:
Ich verwende kein delay und keine floats in einem uC-Programm 
(höchstens es geht nicht anders!). Und als Filter verwende ich möglichst 
speichersparende Strukturen. Etwa so wie das angeführte PT1-Glied. Vor 
Allem achte ich aber darauf, dass ich das Programm so schreibe, dass der 
uC in seiner dualen Welt arbeiten kann...

> werde mich weiter damit beschäftigen.
Tu das.

: Bearbeitet durch Moderator
von Pandur S. (jetztnicht)


Lesenswert?

>> da kann man vor mir schon den hut ziehen, dass ich es überhaupt so weit
> geschafft habe!

Ja. Machen wir. Wir ziehen den Hut. Meine Gratulation. Ich hab vorher 
uebrigens auch was anderes gemacht.

Nun geht's aber weiter.

von public (Gast)


Lesenswert?

Servus,

ich kann dir auch den Ringspeicher empfehlen (siehe Kommentar von Lothar 
Miller), du musst aber auf ein paar Dinge achten.

1. sinnvolle Initialisierung des Ringspeichers (alle Werte auf Null?)
2. Ringspeichergröße -> µC immer 8, 16, 32, 64,... was halt sinnvoll ist
3. während des schreibens auf den Ringspeicher mögliche Interrupts 
sperren

der folgende Schritt ist kein muss
4. lieber einen kleinen feinen Funktionsautomaten (FSM) verwenden, der 
dann timer getriggert die aufgaben erledigt :)

Beispiel:
1
static int ringcounter = 0;
2
// state musst dir selber basteln am besten mit typedef enum im entsprechenden *.h-File
3
4
5
switch (state)
6
{
7
first_state:
8
  ring[ringcounter] = adc_read_value();
9
  state = second_state;
10
  timer_start_us(50);
11
  break;
12
13
second_state:
14
  ...
15
16
third_state:
17
  ...
18
19
last_state:
20
  ...
21
  if (ringcounter >= 16)
22
  {
23
    ringcounter = 0;
24
  }
25
}

wobei die Schritte "neuen Status zuweisen" und "timer starten" bei jedem 
Schritt ausgeführt werden müssen, aja das ganze natürlich in eine 
Funktion packen.

Am besten du malst es dir mal auf!

beste grüße
public

von Lehrer Specht (Gast)


Lesenswert?

kathleen schrieb:
> da kann man vor
> mir schon den hut ziehen, dass ich es überhaupt so weit geschafft habe!)

Hut schreibt man u.a. groß, da es sich um ein Substantiv handelt. Ebenso 
Wörter am Satzanfang...

SCNR :)

Zum Thema: Verwende einen Tiefpass. Hat sich in der Praxis bewährt.

von Ralf D. (rad)


Lesenswert?

Die Methoden

a) gleitender Mittelwert (= FIR-Filter),
b) exponentieller Mittelwert (= IIR-Filter) und
c) Durchschnitt von n Werten (= ich weiß nicht was)

sind doch unterschiedliche Tiefpassfilter mit recht unterschiedlichem 
Verhalten (Frequenzgang, Phasengang bzw. Impuls/Sprungantwort) die je 
nach Anforderung an die Filtereigenschaften der Applikation zu wählen 
sind. Bei den Überlegungen haben m.M.n. Aspekte der "leichten" oder 
"eleganten" Implementierbarkeit nix mitzureden.

Wie dann der ausgewählte Filter (am günstigsten) implementiert wird ist 
nachrangig.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

public schrieb:
> der folgende Schritt ist kein muss
> 4. lieber einen kleinen feinen Funktionsautomaten (FSM) verwenden
So ein Zustandsautomat könnte aber eine ganz hübsche Herausforderung 
sein, insbesondere, wenn man diesen Programmierstil nicht kennt...

Ich würde auf jeden Fall nach jedem Einlesen des ADC den Wert neu 
berechnen, weil sonst ja unnötige Latenz bis zum Ergebnis auftriit. Also 
keinesfalls "10 Werte einlesen, dann den Mittelwert berechnen, dann 
wieder 10 Werte einlesen, dann den Mittelwert berechnen, usf..."

> 3. während des schreibens auf den Ringspeicher .. Interrupts sperren
Warum?
Die Interrupts müssen nur gesperrt werden, wenn in einem Interrupt 
ebenfalls auf den Ringspeicher zugegriffen wird. Dann gibt es nämlich 
das allseits bekannte Semaphorenproblem...

Ralf D. schrieb:
> Bei den Überlegungen haben m.M.n. Aspekte der "leichten" oder
> "eleganten" Implementierbarkeit nix mitzureden.
Doch, durchaus. Solange nämlich nicht bekannt ist, warum denn UNBEDINGT 
GENAU der gleitende Mittelwert genommen werden MUSS, solange frage ich 
da auf jeden Fall nach. Denn eines ist klar: ein Grundschüler wird zur 
Multiplikation eine forgesetzte Addition nehmen, weil er es nicht besser 
KANN. Wenn man ihm dann aber zeigt, dass man 6*7 auch einfacher rechnen 
kann als 6+6+6+6+6+6+6, dann kann er dieses "neue" Verfahren anwenden.
Und in der elektrotechnischen "Grundschule" lernt man nun mal 
zuallererst den gleitenden Mittelwert.

Ralf D. schrieb:
> Die Methoden
> a) gleitender Mittelwert (= FIR-Filter),
> b) exponentieller Mittelwert (= IIR-Filter) und
> c) Durchschnitt von n Werten (= ich weiß nicht was)
d) die Werte sortieren und den "mittleren" Wert verwenden (Medianfilter)
Das ist ein tolles Verfahren bei verrauschten Signalen. siehe dort etwa 
in der Mitte:
http://de.wikipedia.org/wiki/Rangordnungsfilter


@Kathleen: du hättest doch einfach sagen können, dass du das Diplom in 
Österreich an einer HTL machst, dann wären die Kommentare evtl. ein 
wenig weniger bissig ausgefallen. So mussten wir annehmen, du hättest an 
einer (deutschen) Hochschule schon 4 Jahre Studium hinter dir...

: Bearbeitet durch Moderator
von Pandur S. (jetztnicht)


Lesenswert?

Ralf D. schrieb:
> Bei den Überlegungen haben m.M.n. Aspekte der "leichten" oder
> "eleganten" Implementierbarkeit nix mitzureden.

Nix da. Auf alle Faelle, darum geht es genau. Nun lassen wir mal die 
Faelle aussen vor wo Leute den Zwang verspueren einen Raspi einseten 
muessen, wo auch ein Mega 8 reicht.

Als Physiker lernt man mit Ungenauigkeiten zu leben. Eigentlich sind sie 
das Leben. Also, wenn die Anwendung, resp die Idee davon, per Mathe eine 
Division durch 1000 moechte, schau ich erst ob zB 2% Fehler drinliegt. 
Dann teile ich durch 1024. In sehr vielen Anwendungen ist das naemlich 
egal.
Das erscheint in den Spezifikationen unter "Absolute Genauigkeit 2%", 
mit trotzdem "Stabilitaet 0.01%". Die Meisten Anwendungen verlangen hohe 
Reproduzierbarkeit, und nicht absolute Werte.

Float fuer eine Benutzerausgabe alle 300ms, aber nicht haeufiger, ist 
tragbar, sonst aber nicht. Sonst wird konsequent mit Integern 
gearbeitet.
Falls nun eine Skalierung doch etwas praeziser sein soll...
zB ein Faktor 1.05 oder in der Naehe sein muss, an liebsten 
Benutzer-Einstellbar, verwende ich zb * 68812 / 65536, wobei die erste 
Zahl als Variable auftaucht. Die zweite Zahl bedeutet die hinteren zwei 
byte entfernen. Das ist nicht etwa Mehrarbeit, sondern geht gratis mit.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Jetzt Nicht schrieb:
> zB ein Faktor 1.05 oder in der Naehe sein muss, an liebsten
> Benutzer-Einstellbar, verwende ich zb * 68812 / 65536, wobei die erste
> Zahl als Variable auftaucht.
Genau dieses simple Verfahren ist den meisten schleierhaft.
Wie kann ich einen Integer ohne Division durch 3 teilen?
Klar: mit *0.33333
Und wie geht das jetzt ohne Float?
Ganz einfach: mit *21845/65536
Ja, ruft gleich einer: da ist doch eine Division drin!
Aber das Lustige ist jetzt: es ist eine Division durch die Zweierpotenz 
2^16 und das bedeutet, dass der Compiler diese beiden unteren Bytes 
einfach "vergessen darf". Fertig ist die Division...

(bei signed-Divisionen muss man beim Abschneiden ein wenig aufpassen 
oder mit dem +-1 Fehler leben, aber das ist ein fortgeschrittenes 
Thema...)

: Bearbeitet durch Moderator
von public (Gast)


Lesenswert?

Hey es geht doch um eine Diplomarbeit, und die liegt auch noch kurz vor 
Fertigstellung. Bei mir hat in entsprechender Phase die Verschönigung 
eingesetzt, Code kürzer/kleiner/schneller/effizienter...

Ein Automat macht es sehr übersichtlich, aber natürlich nicht einfacher.

Interrupts natürlich nur sperren wenn denn dann noch etwas anderes mit 
dem entsprechenden Buffer passiert, davon bin ich mal ausgegangen 
(wollte hier nur einen Hinweis) ;)

Ich würde den Mittelwert nicht die ganze Zeit berechnen, sondern nur 
wenn der Wert interessant wird. Wenn das natürlich die gesamte Zeit ist 
ein sofortiges Update evtl. wichtig.

beste grüße
public

von kathleen (Gast)


Lesenswert?

Lehrer Specht schrieb:
> Hut schreibt man u.a. groß, da es sich um ein Substantiv handelt. Ebenso
> Wörter am Satzanfang...

Bitte entschuldige, dass mir hier die Shift-Taste nicht genommen wurde.

Lothar Miller schrieb:
> @Kathleen: du hättest doch einfach sagen können, dass du das Diplom in
> Österreich an einer HTL machst, dann wären die Kommentare evtl. ein
> wenig weniger bissig ausgefallen. So mussten wir annehmen, du hättest an
> einer (deutschen) Hochschule schon 4 Jahre Studium hinter dir...

-> JA, es betrifft hier die Abendschule an einer Höheren technischen 
Lehranstalt in Österreich.
Falls ich wirklich schon 4 Jahre Studium hinter mir hätte, dann hätte 
ich bestimmt keine Fragen (zumind. nicht solch "primitive" Fragen, wie 
diese hier) in ein Forum gestellt.

aber nun möchte ich hiermit diesen Beitrag schließen (oder von einem 
Admin schließen lassen) - da es nun immer weiter in die Materie 
hineingeht.

Vielen Dank nochmal an alle.

von public (Gast)


Lesenswert?

kathleen schrieb:
> aber nun möchte ich hiermit diesen Beitrag schließen (oder von einem
> Admin schließen lassen) - da es nun immer weiter in die Materie
> hineingeht.

Heyho Frustrationsgrenze runterschrauben und helfen lassen, auch wenn es 
nicht immer "freundlich" zugeht.

> Vielen Dank nochmal an alle.

Bitte, gerne wieder ;)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

kathleen schrieb:
> aber nun möchte ich hiermit diesen Beitrag schließen
Beiträge werden hier idR. nicht geschlossen. Du kannst deinen Beitrag im 
Juni nochmal rauskramen und schreiben, wie die Lösung zum Schluss 
ausgesehen hat. Das rundet so eine Sache dann immmer hübsch ab, aber 
leider tun das nur wenige...

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
Noch kein Account? Hier anmelden.