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?
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;
}
é esattamente come farei io, più veloce e con molte meno variabili
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!
@leo72: si, è il metodo più semplice e che consuma meno risorse
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
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
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) - WikipediaVarianza - WikipediaModa (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) - WikipediaVarianza - WikipediaModa (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
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.
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!