come fare la media di una serie di valori rilevati in sequenza ?

Ciao a tutti, ho una domanda: vorrei eliminare il "rumore" dalla lettura di sensori analogici.
Una cosa che si fa in genere, a quanto ne so, è fare una media di una serie di valori misurati in successione.
Questo però come si fa con Arduino?

Cioé, dal poco he ho capito Arduino funziona per cicli, ed esegue infinite volte la serie di operazioni che inseriamo tra un delay e l'altro.
Come faccio a dirgli di andarsi a riprendere i valori rilevati, per esempio nei 5 cicli precedenti per farne una media da considerare il valore ripulito dalle microfrequenze di disturbo?

Grazie

li metti in un array globale(così non viene distrutto ogni loop)..

C'è qualche esempio in rete per caso?

http://programmazione.html.it/guide/lezione/1099/cosa-sono-gli-array/

è una delle cose più basiche da fare, anche senza guide non dovrebbe essere un problema

Il codice che ti serve dovrebbe fare le seguenti cose:

#define PIN 5 //un pin analogico

int valori[5]; //Array in cui ci salvi i valori letti
int T_campionamento;
int somma;
float media;

void setup(){
}

void loop(){
  //così ti salvi 5 valori
  for(int i=0; i<5; i++){
    valori[i] = analogRead(PIN);
    delay(T_campionamento); //se vuoi fare una lettura ogni tot millisecondi
                            //non è necessario
  } 
  somma = 0; // devi essere sicuro che il primo valore sia zero, altrimenti poi sballa tutto
  
  // finito di acquisire, fai la somma di tutti i campioni
  for(int i=0; i<5; i++)
    somma = somma + valori[i];

  //ottenuta la somma puoi fare la media
  media = somma / 5;
  
  //il loop finisce e di seguito ricomincia
  //per questo è mecessario azzerare di volta in volta la variabile somma
}

non è sicuramente il modo migliore e più compatto per fare il calcolo, ma sicuramente è il metodo più intuitivo e naturale, in base a ciò che hai chiesto. Comincia con questo poi una volta capito il ragionamento che c'è dietro si va avanti

ma vi servono i valori letti?
se vi serve solo la media: (é solo codice concettuale non eseguibile; mancano le dichiarazioni delle variabioli e i valori d' inizio).

somma = somma + analogRead(PIN);
nr ++;
if (nr >= 5)
  {
  media = somma/nr
  nr = 0;
  somma = 0;
  }

Ciao Uwe

é esattamente come farei io, più veloce e con molte meno variabili :smiley:

Però mi rendo conto che per chi è alle prime armi il loop anzichè essere una risorsa da sfruttare è un intralcio che complica i ragionamenti...da qui l'esempio che ho fatto!

Metodo "rozzo":

lettura = AnalogRead(PIN);
do {
    lettura = (lettura + AnalogRead(PIN)) / 2;
} while (condizione_di_uscita);

In questo modo la media è in tempo reale... o no?

@leo72: si, è il metodo più semplice e che consuma meno risorse :slight_smile:

anche il metodo di uwefed è valido, però bisogna fare attenzione agli overflow e al fatto che appena calcolata una media ci vogliono un pò di letture per riottenere una media valida

un altro metodo è avere un array ciclico, al setup lo riempi di valori, poi ogni lettura va a sovrascrivere quella più vecchia, fa la somma di tutto l'array e divide per la grandezza dell'array.
In questo modo, semplicemente dimensionano l'array (se il codice è scritto bene) si può cambiare la "resistenza al rumore" della media aritmetica (esattamente come nel codice di uwefed cambiando i 5 con altri numeri).
in oltre, dato che si sa la posizione dell'ultimo elemento inserito e che sono stati inseriti in modo "ciclico", si può effettuare anche una media pesata dando più o meno peso ai valori più recenti
ah e a ogni lettura si ha una media valida :slight_smile:

Tipo qualche cosa del genere?

int Array_Max = 5;                                       // Capienza array
int T_campionamento = 500;                         // Come già suggerito, indica il tempo necessario tra una rilevazione e l'altra
float Array_valori[Array_Max] ;                      // Array contenente i valori
int Array_Index = 0;                                     // Variabile globale che ricorda la posizione dell'ultimo dato inserito

float Media_valori = 0;                                  // La variabile che conterrà la media "real time"

void setup(){
  for(int i=0; i<Array_Max; i++) {           //Riempi l'array al primo utilizzo
     Array_valori[i] = Acqusisci_dato;
     delay(T_campionamento);               //Come già suggerito, sempre se necessario
  }
}

void loop(){
 if ( Array_Index >= Array_Max ) {   //Verifica l'attuale posizione dell'array in modo da sovrascrivere il valore più vecchio;
   Array_Index = 0;                       //Se l'array è saturo (Array_Index = Array_Max), riparte da zero;
 }
 else {
 Array_Index++;
 }
 delay(T_campionamento);  //Come già suggerito, sempre se necessario
 Array_valori[Array_Index] = Acqusisci_dato;  //Acquisisce il dato dal sensore e lo salva nell'array sovrascrivendo il dato più vecchio
 
 Media_valori = 0;                              // Inizializza a 0 la media
 for(int i=0; i<Array_Max; i++) {           //Riempi l'array al primo utilizzo
     Media_valori = (Media_valori + Array_valori )/2
  }

 Serial.println(Media_Valori);              // Stampa il valore medio
}

Ovviamente non è codice verificato, e sicuramente la mia conoscenza sulla programmazione non è massima, per cui, appurata la praticità del codice, è sempre da ottimizzare

più o meno giusto...

if ( Array_Index >= Array_Max ) {   //Verifica l'attuale posizione dell'array in modo da sovrascrivere il valore più vecchio;
   Array_Index = 0;                       //Se l'array è saturo (Array_Index = Array_Max), riparte da zero;
 }
 else 
 Array_Index++;
 }

va messo DOPO aver messo il dato nell'array, io lo scriverei così:

void loop(){
delay(T_campionamento);
Array_valori[Array_Index] = Acqusisci_dato;
Array_Index++;
if ( Array_Index >= Array_Max ) {   //Verifica l'attuale posizione dell'array in modo da sovrascrivere il valore più vecchio;
   Array_Index = 0;                       //Se l'array è saturo (Array_Index = Array_Max), riparte da zero;
 }
//calcola la media ecc...

atteno al calcolo della media:
sommare tutti i valori e dividere per il loro numero è DIVERSO da fare media = (media+valore)/2!!! perchè nel primo modo ogni valore ha lo stesso peso(influisce allo stesso modo sugli altri valori), mentre nel secondo metodo l'ultimo valore inserito ha peso doppio rispetto a tutti gli altri numeri inseriti precedentemente.
qualche info che può essere utile: Media (statistica) - Wikipedia Varianza - Wikipedia Moda (statistica) - Wikipedia

atteno al calcolo della media:
sommare tutti i valori e dividere per il loro numero è DIVERSO da fare media = (media+valore)/2!!! perchè nel primo modo ogni valore ha lo stesso peso(influisce allo stesso modo sugli altri valori), mentre nel secondo metodo l'ultimo valore inserito ha peso doppio rispetto a tutti gli altri numeri inseriti precedentemente.
qualche info che può essere utile: Media (statistica) - Wikipedia Varianza - Wikipedia Moda (statistica) - Wikipedia

Uhm, già... così modificato allora dovrebbe seguire il tuo appunto:

Media_valori = 0;                              // Inizializza a 0 la media
 for(int i=0; i<Array_Max; i++) {           //Riempi l'array al primo utilizzo
     Media_valori = Media_valori + Array_valori[Array_Index]
  }
Media_valori = Media_valori / Array_Max

esatto, così hai un risultato graficamente più rotondeggiante anziché a picchi

Scusate se non ho risposto prima, è che oggi sono stato molto impegnato e probabilmente fino a metà settimana le cose non cambieranno.
Gli argomenti che proponete sembrano centrati, ma non posso nascondervi che molte cose mi sfuggono.
Appena ho un pomeriggio in settimana mi ci metto e cerco di capire il più possibile.
Comunque, sostanzialmente, quello che mi serve è pulire in tempo reale il rilevamento di una fotoresistenza dal rumore.

Sono molto, mi sono affacciato ad arduino per un progetto all'incirca domotico, ma ora sto facendo alcune prove preliminari.
Questo è lo stato dell'arte:

Sulla base della scatola c'è una fotoresistenza, sul coperchio un diaframma con un servo che lo apre e lo chiude, influenzando quindi i valori della rilevati dentro la scatola.
In un secondo momento voglio impostare in tempo reale una variabile relativa alla quantità di luce che voglio ottenere all'interno e il diaframma dovrà aprirsi o chiudersi finché il valore non sarà verificato, ma per ora di questo secondo passaggio non voglio occuparmi, pensando precedentemente al rilevamento.
Gli array mi pare facciano al caso mio, a quanto ho capito ogni tot cicli fanno una media di valori che poi viene azzerata e ricalcolata, ma varie cose mi sfuggono ancora, soprattutto nella sintassi degli script.
Attualmente l'aggeggio funziona con questo codice, che ho scritto guardando qua e la le cose che mi sembravano attinenti.

#include <Servo.h> 
 
Servo myservo;  // crea l'oggetto servo

const int analogInPin = A0;  // pin della fotoresistenza
int pos = 0;    // variabile che indica la posizione del servo
int sensorValue = 0;        // valore della foresistenza
int outputValue = 0;        // valore mappato

void setup() 
{ 
  Serial.begin (9600); //apre la comunicazione con lo schermo seriale
  myservo.attach(9);  // attacca l'oggetto servo al pin 9
} 
 
 
void loop() 

{
  
  Serial.println(">>>");   
  Serial.println("nuovo ciclo");  
  Serial.println(">>>");   
  delay(3000); // loop che da il tempo di cambiare le condizioni di luce tra un'apertura e l'altra e le separa per l'esportazione in excell
  
  int x = 1;   // variabile che modifica la posizione
   for (int pos = 0; pos > -1; pos = pos + x)   // il servo parte da 0°, e se è supreriore a uno inizia a incrementarsi ad ogni ciclo di x
   {
      myservo.write(pos);                // dico al servo quale posizione assumere
      if (pos >= 80) x = -1;             // quando raggiungo gli 80° inizia il decremento pe rrichiudere il diaframma
     

  sensorValue = analogRead(analogInPin);            // leggo i valori         

  outputValue = map(sensorValue, 0, 1023, 0, 100);    // mappo i valori (primo tentativo per eliminare un po' di disturbo, 
                                                      // ma poco preciso se i valori letti si trovano tra due valori mappati

  Serial.print("sensore = " );                       
  Serial.print(sensorValue);      
  Serial.print("\t valore mappato = ");   
  Serial.print(outputValue); 
  Serial.print("\t gradi apertura= ");      
  Serial.println(pos);   
 
  
  delay(500);      
     
     
     
   } 
}

Primo: sono riuscito a far funzionare la scatoletta in modo che si aprisse e si chiudesse da sola a seconda della luce richiesta in relazione a quella rilevata. 8)
Secondo: devo dire che facendo girare il primo script ho iniziato un po' a capire di cosa si parla, certe cose non sono affatto immediate per me e dopo quello anche gli altri mi sono meno ostici.
Ho un po' di domande ma ci traffico ancora un po' e poi le metto giù in modo il più possibile ragionato.
Comunque grazie a tutti del grande contributo che state dando alla mia ricerca.
A questo punto se trovo un relatore disposto diventa il nucleo della mia tesi.
:wink:

ma alla fine sta media come la devo fare? io devo farla di tot valori, letture di un sensore di temperatura analogico e quando questa media supera un certo valore allora accendi un led!