Forum: Mikrocontroller und Digitale Elektronik Mittelwert über 11 Messwerte


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Daniel (Gast)


Lesenswert?

Hallo alle zusammen,

in meinem Programm bekomme ich eine Periodenzeit mit Hilfe des 16-Bit 
Timers. Ich möchte die gemessene Zeit über 11 Messungen addieren und 
davon dann den Mittelwert bilden. Wie baue ich das im Programm ein?

Vielen Dank
1
//#define F_CPU  16000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include "lcd.h"
5
#include <avr/interrupt.h>
6
7
8
/*unsigned int read_ad(void)
9
{
10
  // Funktion zum Auslesen des A/D-Wandlers
11
    ADCSRA |= (1<<ADSC);  // Wandler starten
12
  while(!(ADCSRA & (1<<ADIF)));  //warten auf Wandler
13
  return ADCW;
14
}
15
*/
16
17
volatile uint16_t messung = 0;
18
volatile uint32_t periodenzeit;
19
volatile uint16_t start;
20
volatile uint16_t ende;
21
int i;
22
23
24
25
ISR(ADC_vect)        // Interrupt zum Auslesen des Wandlers
26
{
27
  messung = ADCW;
28
29
30
31
}
32
33
34
int main (void)
35
{
36
  DDRB = 0b01001000;
37
  
38
39
  ADMUX  = (0<<REFS1)|(1<<REFS0)|(1<<MUX0);  // Ref=AVCC, PA1
40
  ADCSRA = (1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);  // Wandler an
41
                    // Teiler 128 -> 125kHz Takt,
42
  
43
                      
44
45
 sei();                // Interruptverarbeitung AN
46
 
47
  
48
  lcd_init();
49
  //lcd_string("TESTPROGRAMM ADC");
50
  lcd_setpos(1,0);
51
  lcd_string("Wert: ");
52
53
54
55
  
56
  while(1)                // Hauptschleife
57
  {
58
59
  
60
61
  if (messung >= 200)      // ADC-Wert bei 200 Timer Starten
62
                
63
  {
64
      
65
66
      
67
      
68
        TCCR1B = (1<<CS12)|(1<<CS10);        // Timer-Konfiguration mit 1024 Vorteiler
69
      
70
        start=TCNT1;
71
72
  }
73
74
  else 
75
76
  {
77
          TCCR1B = (0<<CS12)|(0<<CS10);
78
          ende=TCNT1;
79
80
          periodenzeit=ende;
81
          TCNT1 = 0b00000000;
82
83
          
84
85
86
  }
87
    
88
89
90
91
92
    if((periodenzeit*0.064)>=585)    // pro Timer-Schritt = 0.000064 us
93
    {                  // Vergleich in Mikrosekunden
94
      
95
    
96
      PORTB = (1<<PB6);
97
      
98
    
99
        
100
       
101
    
102
    }
103
    else 
104
    {
105
      PORTB = (1<<PB3);
106
      
107
      
108
        
109
    } 
110
111
112
  
113
114
  lcd_setpos(1,5);
115
  lcd_int(messung);
116
  lcd_char(' ');
117
  lcd_setpos(1,10);
118
  lcd_int(0.064);
119
  
120
  //lcd_string("Wert: ");
121
  
122
  
123
  lcd_setpos(0,0);
124
  lcd_string("Zeit: ");
125
  lcd_setpos(0,5);
126
  lcd_int((TCNT1*0.064));
127
  lcd_setpos(0,10);
128
  lcd_int(periodenzeit);
129
  
130
131
  
132
  };
133
  return 0;
134
}

von Jim M. (turboj)


Lesenswert?

Gegenfrage: Du weisst wie man in C ein Array programmiert?

Wenn "Nein": Buch über die Programmiersprace C besorgen und 
durcharbeiten.

Wenn "Ja": Array benutzen.

von Stephan (Gast)


Lesenswert?

Warum ausgerechnet 11 Werte ?
1,2,4,8,16 usw. macht die DIV einfacher...schieben.

von Pieter (Gast)


Lesenswert?

>>Warum ausgerechnet 11 Werte ?

warum sagt der TO nicht.
Auch nicht welche Werte zu mitteln sind.
Alles unklar.

von Theor (Gast)


Lesenswert?

@ Daniel
Ich würde Dir folgendes raten:

1. Überlege wie man einen Mittelwert auf dem Papier berechnet. Schau in 
einem Mathematik-Buch nach, falls Du Dich nicht mehr genau erinnerst, 
wie das geht.

2. Denke Dir ein paar zufällige Zahlen aus und rechne das einfach mal 
von Hand bzw. mit dem Taschenrechner.

3. Nimm auch ein paar Zahlen, bei denen Du am Ergebnis sofort siehst, 
dass die Rechnung richtig verlaufen sein muss! Etwa nur gleiche Zahlen. 
Oder Zahlen die, der Grösse nach geordnet, immer die gleiche Differenz 
zu dem Vorgänger und Nachfolger haben.

4. Versuche die wesentlich wichtigen Schritte, bei dieser Berechnung 
aufzuschreiben. Vielleicht ein einer Liste von nacheinander 
abzuarbeitenden Punkten.

5. Überlege Dir, wie Du das Papierverfahren in der Programmiersprache 
ausdrückst. Dabei sind folgende Fragen von entscheidender Bedeutung: A) 
Wie und wo werden die Werte abgespeichert. B) Gibt es bestimmte 
Gegebenheiten, die vor dem Beginn der Berechnung vorhanden sein müssen? 
C) Lassen sich, bestimmte Schritte als Wiederholungen formulieren? D) 
Wovon hängt die Anzahl dieser Wiederholungen ab?

von Joachim B. (jar)


Lesenswert?

Stephan schrieb:
> Warum ausgerechnet 11 Werte ?
> 1,2,4,8,16 usw. macht die DIV einfacher...schieben.

genau
1
#define READS 5 // vielfache von 2^X READS 5 nimmt den Mittelwert aus 32 Messwerten
2
uint16_t lese_analog(uint8_t _port)
3
{ uint16_t _adc=0;
4
  for(i=0; i<(1<<READS); i++)
5
    _adc += analogRead(_port);    // read the input pin
6
  _adc >>= READS;  
7
#ifndef SCHNAUZE  
8
  DEBUG_PRINT(F("_adc: ")); DEBUG_PRINTLN(_adc);  
9
//  Serial.println();
10
  delay(500);
11
#endif
12
  return _adc;
13
}

noch besser wirds wenn man obere und untere Extremwerte nicht nimmt, ein 
Array + Sortalgorythmus und erste und letzte ausserhalb der Toleranz 
verwerfen

: Bearbeitet durch User
von fop (Gast)


Lesenswert?

Also ein Array bräuchte ich nicht. Die einzelnen Werte will ja nachher 
keiner mehr wissen. Einfach die Summe in einer Variablen speichern. 
Dabei ein wenig aufpassen, dass die Variable genug Platz für die 
größtmögliche Zahl bietet.
Und natürlich darauf achten, dass es auch 11 Werte sind, die da 
aufaddiert werden.
Damit reduziert sich das Problem auf ein Teilen durch 11.

Wenn Du dann weißt wie, kannst Du Dich an einem Median-Wert der 11 
Messungen versuchen. Der bügelt Ausreisser durch Messfehler besser aus.
Und ab da kommen dann doch wieder die Arrays ins Spiel.

von Joachim B. (jar)


Lesenswert?

fop schrieb:
> Also ein Array bräuchte ich nicht

bist du der TO unter Doppelnamen?
Der TO stellt eine Frage und du antwortest brauche ich nicht?

fop schrieb:
> Die einzelnen Werte will ja nachher
> keiner mehr wissen

stimmt auch kann man wenn ausserhalb der Toleranz auch gleich vor dem 
Aufaddieren verwerfen, nur darf man dann nicht mehr durch die Anzahl der 
Durchläufe teilen!

fop schrieb:
> nd natürlich darauf achten, dass es auch 11 Werte sind, die da
> aufaddiert werden.
> Damit reduziert sich das Problem auf ein Teilen durch 11.

was unheimlich viel Zeit braucht u.U. übermäßig viel mehr als man hat 
gegenüber einem einfachen RECHTS Shift!

aber jeder wie er mag.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Lesenswert?

Joachim B. schrieb:
> was unheimlich viel Zeit braucht
> ....
> aber jeder wie er mag.

Wenn ich nicht auf jeden Takt schauen muss, ist dieses mein Arbeitsesel 
für solcherart Probleme.

Ist natürlich im Arduino Style, aber der Kern sollte sich auf C 
übertragen lassen.

1
    
2
    template<typename DatenType> 
3
    class GleitenderMittelwert   // eher ein Tiefpassfilter
4
    {
5
      private:
6
        const double factor;
7
        double mittelwert;
8
        
9
      public:
10
         GleitenderMittelwert(const double factor):factor(factor),mittelwert(0){}
11
         
12
         void setInitial(double value)
13
         {
14
             mittelwert = value;
15
         }
16
    
17
         operator DatenType() const
18
         {
19
            return mittelwert;
20
         }  
21
         
22
         DatenType doValue(DatenType value) // neuen Wert verarbeiten
23
         {
24
             mittelwert *= 1.0 - factor;
25
             mittelwert += factor * value;
26
             return  mittelwert;
27
         }
28
         
29
         DatenType operator= (DatenType value)
30
         {
31
             return doValue(value);       
32
         }
33
         
34
         DatenType operator() (DatenType value)
35
         {
36
             return doValue(value);       
37
         }
38
         
39
         DatenType operator() () const
40
         {
41
             return mittelwert;       
42
         }
43
    };

PS:
Hier sollte dann der Faktor 1.0/11.0 betragen.

: Bearbeitet durch User
von Andi (Gast)


Lesenswert?

Joachim B. schrieb:
> fop schrieb:
>> Also ein Array bräuchte ich nicht
>
> bist du der TO unter Doppelnamen?
> Der TO stellt eine Frage und du antwortest brauche ich nicht?

Wenn ich fop wäre würde ich dir antworten, dass das "bräuchte" eben im 
Konjunktiv steht, um anzudeuten, dass er es ohne Array machen würde, 
wenn er es machen würde oder der TO wäre.

Und nein ich bin nicht fop unter anderem Namen.

von npn (Gast)


Lesenswert?

Andi schrieb:
> Und nein ich bin nicht fop unter anderem Namen.
Daniel unter anderem Namen?

von Wolfgang (Gast)


Lesenswert?

Arduino F. schrieb:
> class GleitenderMittelwert   // eher ein Tiefpassfilter

Wenn es allerdings wirklich ein gleitender Mittelwert werden soll, käme 
man um ein Array, am einfachsten verwaltet als Ringpuffer, nicht 
drumrum.

von georg (Gast)


Lesenswert?

Wolfgang schrieb:
> äme
> man um ein Array, am einfachsten verwaltet als Ringpuffer, nicht
> drumrum.

Natürlich nicht. Wieso überhaupt diese panische Angst vor einem Array? 
Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte 
haben.

Georg

von Joachim B. (jar)


Lesenswert?

georg schrieb:
> Natürlich nicht. Wieso überhaupt diese panische Angst vor einem Array?
> Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte
> haben.

sogar für 64/32 Messwerte wo man nur 32/16 sammelt die innerhalb der 
Toleranz für einen Mittelwert liegen um wieder statt teilen shiften 
kann..

von Arduino Fanboy D. (ufuf)


Lesenswert?

georg schrieb:
> Selbst der popeligste Arduino wird doch noch Platz für 11 Messwerte

Ab wann wird es denn knapp?
Ab 1000 Integers?



georg schrieb:
> Wieso überhaupt diese panische Angst vor einem Array?
Wie immer:
Man wähle ein, der Aufgabe angemessenes, Verfahren.

Was soll das mit Angst zu tun haben?

von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> Ab wann wird es denn knapp?
> Ab 1000 Integers?

bein UNO oder nano 328p ja, der mega2560 kommt etwas weiter, der mighty 
mini 1284p hat SRAM über alles was man brauchen wird, den habe ich noch 
nie überlastet, den nano schon öfter da kratzen meine 
Programmiermöglichkeiten an dessen Grenzen.

von Wolfgang (Gast)


Lesenswert?

Arduino F. schrieb:
> Ab wann wird es denn knapp?
> Ab 1000 Integers?

Da wird es dann Zeit, auf einen anderen Arduino mit besserer 
RAM-Ausstattung zurückzugreifen, z.B. einen Arduino Due.
Ob solch eine hohe Zeitauflösung bei einem gleitenden Mittelwert 
sinnvoll erscheint, ist ein anderes Thema. Wenn die Daten derart 
verrauscht sind, das so ein Filter erforderlich ist, kann man meist auch 
erstmal einen kürzeres FIR davor schalten und für den gleitenden 
Mittelwert mit niedrigerer Abtastrate weiterrechnen.

von Purzel H. (hacky)


Lesenswert?

Aber sicher nicht fuer einen duemmlichen Mittelwert. Ich wuerde zu einem 
exponentiellen Mittelwert greifen, der genau nur eine einzelne 
Speicherstelle benoetigt. Dazu siehe :
https://www.ibrtses.com/embedded/exponential.html
Da ist die Mittelungskonstante, dh Zeitkonstante, auch nur genau ein 
Wert.

von Carsten R. (kaffeetante)


Lesenswert?

Eine der für mich wichtigsten Lektionen an der Uni war die 
Unterscheidung zwischen:

"Building the right thing vs. building the thing right"

Es gibt viele schöne Lösungen für verschiedene Probleme.
Aktuell ist noch völlig unklar was er wirklich braucht/will.

Beispielsweise ist völlig unklar ob er einen Mittelwert alle 11 Zyklen 
will (Summe bilden + Division, dann erneut von vorn beginnen) oder ob es 
ein gleitender Mittelwert mit 11 Zyklen rückblickend werden soll (in 
jedem Zyklus immer die aktuell letzten 11 Zyklen auswerten).

von Joachim B. (jar)


Lesenswert?

Carsten R. schrieb:
> oder ob es
> ein gleitender Mittelwert mit 11 Zyklen rückblickend werden soll (in
> jedem Zyklus immer die aktuell letzten 11 Zyklen auswerten).

sowas hatte ich mal bei einer DFC77 Auswertung gemacht für die 1/0 
Erkennung
je nach Länge vom Kabel waren die Impulse verschliffen und durch 
Erwärmung verschob sich das auch noch.

Also die 1/0 Schwelle(100ms/200ms) sowie die Sekundenpause 800ms/1900ms 
immer über die Zeit nachjustiert, klappte ganz gut.
(war auch nötig um im Interrupt keine µs Störer zur Auswertung zu 
bringen)

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.