Arduino - ta medelvärde från beräkning, inte sensordata

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av Corpze »

Hej, skriver en lite kod till en molnsensor, den jämför marktemp med molntemp, om diffen är mindre än 21 grader C finns det moln, är diffen större så är det mycket lite eller inga moln.

Koden skickas till en drivrutin (ASCOM) för att styra ett observatorietak med strängen "IsSafe" när det inte är några moln, finns det moln så skall taket stängas, men inte om jag får ETT enstaka värde under 21 grader, utan ett medel för ca 5 minuter.

Jag vill således ta in data kontinuerligt från sensorn (MLX90614), alltså inte ta medelvärde från sensorn då värdet skall dras från marksensorn (DB18B20) utan medelvärdet från beräkningen

Kod: Markera allt

delta_celsius = abs(ds18b20_celsius - MLX90614_celsius)
Förstår ni vad jag menar?

Datan skall trilla in hela tiden, men resultatet från beräkningen (delta_celsius) vill jag ha medelvärdet från.

Kommer printas

Kod: Markera allt

Serial.print("Ascom Safety monitor status:    ");
  if ((delta_celsius >21) && (range>1))
     {
  Serial.println("IsSafe");
(Bortse från range>1 då detta är en regnsensor som funkar bra i koden)

Med vänlig hälsning, Daniel
Användarvisningsbild
orvar-e
EF Sponsor
Inlägg: 5973
Blev medlem: 9 mars 2007, 09:01:32
Ort: Borlänge

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av orvar-e »

Kod: Markera allt

  for (int i = 1; i < 51; i++) {      // Take 50 samples of the flame value
    avgFlame = analogRead(flameInput)+avgFlame; 
  }

  flameValue = avgFlame / 50;         // Divide the result by 50
Exempel som jag saxat från Enstens pelletsbrännare
Istället för att ha en analog ingång som mätpunkt borde det väl gå att ta en variabel som du kallar vad du vill. Bara det är en float.
Jag kan inte testa just nu.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av sodjan »

> Jag vill således ta in data kontinuerligt från sensorn...

Vad betyder "kontinuerligt"? 100 gånger per sekund?

Istället för att ta medelvädet av delta_celsius så kan du ju
även räkna hur många gånger delta_celsius > 21 resp < 21.

Du kan ha två räknare, t.ex over21 och under21 som du bara
räknar upp. När den ena räknas upp så nollas den andra. När
någon av dom når en viss gräns så är värdet "sant" och du kan
göra vad som krävs. Enklare än att räkna medelvärde, enbart
integers. Inga divisioner eller floats...

Hur många väden det ska krävas beror på hur ofta du läser
sensorerna och hur mycket du vill "filtrera".
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av lillahuset »

Man kan också subtrahera summan dividerat med antal sample och addera nya samplet. Det här blir inte riktigt rätt har jag fått lära mig men tillräckligt rätt i min värld.

Typ:

Kod: Markera allt

sum -= (sum / NSAMPLES);
sum += sample;
average = sum / NSAMPLES;
Fördelen är att man får ett nytt medelvärde för varje sample. Sedan kan man kanske vilja initiera summan till sample * NSAMPLES för att slippa ett tråkigt insvängningsförlopp. Med risk att man har ett idiotiskt sample som ger ett annat tråkigt insvängningsförlopp. Välj själv.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av sodjan »

Ett problem med medelvärden är att, om det aktuella medelvärdet
redan ligger nära "tröskeln", så kan ett enda värde som ligger
mycket fel få medelvärdet att felaktigt passera gränsen. Med min
metod så måste det vara en kontinuerlig sekvens av värden på
enda sidan för att det ska tolkas som ett "sant" värde.

Sen så får det ju inte komma felaktiga värden oftare än vad man
har satt gränsvärdet för antalet lika värden, då kommer man
aldrig att få att "sant" värde...
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av lillahuset »

Medelvärden är alltid trista, på ett eller annat sätt.

Ofta kan det vara bättre att ha något kriterium för hur mycket senaste sample får avvika från aktuellt "medelvärde" för att få vara med.
Men, ju smartare man försöker vara desto större är risken att det skiter sig.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av sodjan »

Sant... :-)
Dessutom vet vi för lite om hur värderna varierar
för att säga mer än vad som har gjorts nu...
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av Corpze »

Jag har testat lite mer, skrev en float till att börja med;

Kod: Markera allt

float avg_delta_celsius= (avg_delta_celsius*14.0+delta_celsius)/15.0;
Den fungerade inte, kanske för att

Kod: Markera allt

delta_celsius
redan är en float?
lillahuset skrev:Man kan också subtrahera summan dividerat med antal sample och addera nya samplet. Det här blir inte riktigt rätt har jag fått lära mig men tillräckligt rätt i min värld.

Typ:

Kod: Markera allt

sum -= (sum / NSAMPLES);
sum += sample;
average = sum / NSAMPLES;
Fördelen är att man får ett nytt medelvärde för varje sample. Sedan kan man kanske vilja initiera summan till sample * NSAMPLES för att slippa ett tråkigt insvängningsförlopp. Med risk att man har ett idiotiskt sample som ger ett annat tråkigt insvängningsförlopp. Välj själv.
Det låter riktigt intressant, skulle det bli något såhär (med risk för nybörjarmisstag)

Kod: Markera allt

sum-=(sum/99delta_celsius);
sum+= delta_celsius;
average = sum / 100
Sensorn läses av en gång i sekunden, kontinuerligt är alltså under tiden den samlar på sig data för att ta ett medlevärde.

Med vänlig hälsning
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av sodjan »

> Den fungerade inte, kanske för att...

Vad betyder "fungerade inte" ?
Hur vet du att det inte fungerade?
Du borde ju få något felmeddelande eller liknande !?

> Sensorn läses av en gång i sekunden...

Är det inte två sensorer?

Använd inte float om du absolut inte måste och alla
andra lösningar är testade. Jag har lite svårt att se
att float skulle vara helt nödvändigt för detta.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av Corpze »

Det fungerade inte för att den helt enkelt inte printade ut IsSafe efter att 15 värden tagits in.

Det stämmer bra att det är två sensorer, en IR temp (MLX90614) och en vanlig probe (DB18B20), båda dessa läses av en gång i sekunden. men det är diffen mellan dessa två som jag vill ha ett medelvärde av, vet inte riktigt hur dock.

Här är hela koden (utan medelvärdet) och den är fullt fungerande.

Kod: Markera allt


/**
* This sketch reads three sensors:
*  DS18B20 - Connected to D10
*  MLX90614 - Connected to SCL-A5, SDA-A4
*  Rain sensor conected to A0

* It calculates the temperatures (DS18B20 and MLX90614)
* DS18B20: http://playground.arduino.cc/Learning/OneWire
* MLX90614: http://bildr.org/2011/02/mlx90614-arduino/
*/



//get it here: http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <OneWire.h>

//get it here: http://jump.to/fleury
#include <i2cmaster.h>

#include <SPI.h>

// lowest and highest rain sensor readings:
const int sensorMin = 0;     // sensor minimum
const int sensorMax = 1024;  // sensor maximum

OneWire  ds(10);  // DS18B20 on Arduino pin 10
byte ds18b20_addr[8];

void setup(void) 
{
  Serial.begin(9600);
  
  
  init_DS18B20();
  init_MLX90614();
}

void init_DS18B20()
{
  Serial.println("Initializing DS18B20 sensor...");
  while( !ds.search(ds18b20_addr)) 
  {
    ds.reset_search();
    delay(250);
  }
}


void init_MLX90614()
{
  Serial.println("Initializing MLX90614 sensor...");
  i2c_init(); //Initialise the i2c bus
  //	PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups if you use 5V sensors and don't have external pullups in the circuit
}


void loop(void) 
{
  float ds18b20_celsius = read_DS18B20();
  
  Serial.println();

  Serial.print("DS18B20  Temperature:\t");
  Serial.print(ds18b20_celsius);
  Serial.println("\tCelsius");

  float MLX90614_celsius = read_MLX90614();
  Serial.print("MLX90614 Temperature:\t");
  Serial.print(MLX90614_celsius);
  Serial.println("\tCelsius");  

  float delta_celsius = abs(ds18b20_celsius - MLX90614_celsius);
  Serial.print("DELTA Temperature:\t");
  Serial.print(delta_celsius);
  Serial.println("\tCelsius");
 
  
  //Rain sensor
  
  // read the sensor on analog A0:
	int sensorReading = analogRead(A0);
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
	int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  Serial.print("Rain sensor status:             ");
  // range value:
  switch (range) {
    
 case 0:    // Sensor getting wet
    Serial.println("Rain");
    break;
 case 1:    // Sensor getting wet
    Serial.println("Rain Warning");
    break;
 case 2:    // Sensor dry - To shut this up delete the " Serial.println("Not Raining"); " below.
    Serial.println("Not Raining");
    break;
  }
  delay(1);  // delay between reads

  //End rain sensor

  Serial.print("Ascom Safety monitor status:    ");
    if ((delta_celsius >21) && (range>1))
     {
  Serial.println("IsSafe");
     }
     else
     {
       Serial.println("IsNotSafe");
     } 


  delay(1000);
  
}



float read_DS18B20()
{
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];

  float celsius;

  if (OneWire::crc8(ds18b20_addr, 7) != ds18b20_addr[7]) 
  {
    Serial.println("CRC is not valid!");
    return -300.0f;
  }


  // the first ROM byte indicates which chip
  switch (ds18b20_addr[0]) 
  {
  case 0x10:
    type_s = 1;
    break;
  case 0x28:
    type_s = 0;
    break;
  case 0x22:
    type_s = 0;
    break;
  default:
    return -301.0f;
  } 

  ds.reset();
  ds.select(ds18b20_addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(ds18b20_addr);    
  ds.write(0xBE);         // Read Scratchpad

  //read 9 data bytes
  for ( i = 0; i < 9; i++) 
  {
    data[i] = ds.read();
  }

  // Convert the data to actual temperature
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) 
  {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } 
  else 
  {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;

  return celsius;
}


float read_MLX90614()
{
  int dev = 0x5A<<1;
  int data_low = 0;
  int data_high = 0;
  int pec = 0;

  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck(); //Read 1 byte and then send ack
  data_high = i2c_readAck(); //Read 1 byte and then send ack
  pec = i2c_readNak();
  i2c_stop();

  //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
  double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
  double tempData = 0x0000; // zero out the data
  int frac; // data past the decimal point

  // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
  tempData = (double)(((data_high & 0x007F) << 8) + data_low);
  tempData = (tempData * tempFactor)-0.01;

  float celcius = tempData - 273.15;
  return celcius;
}

Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av lillahuset »

Det låter riktigt intressant, skulle det bli något såhär (med risk för nybörjarmisstag)

Kod: Markera allt

sum-=(sum/99delta_celsius);
sum+= delta_celsius;
average = sum / 100
Tycker du det liknar det jag skrev? Mycket?

När du ska testa en ny algoritm, gör det inte i målsystemet om du kan undvika det. Testa i PCn. Det sparar massor av arbete och tid.

Sodjans påpekande om float är i linje med min åsikt, om man inte har en FPU.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av lillahuset »

Du kanske ska skriva ut delta_celsius? Som hjälp i felsökningen.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av Corpze »

delta_celsius skrivs ut i varje print, så den fungerar som den skall.

Ja det liknar väl det du skrev fast med mina värden? eller jag kanske är helt ute och cyklar?
Målsystem? FPU? Du får ursäkta, men förklara gärna hur du menar.

Vad jag förstår så används float när man skall ha många siffror i luften, och därmed rätt så tung att arbeta med?

Tack för all hjälp men tyvärr är nog detta alldeles för högt över mitt huvud.

/Daniel
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av lillahuset »

Det var det här jag syftade på:

Kod: Markera allt

sum-=(sum/99delta_celsius);
Målsystemet i ditt fall är din Arduino. Det system som ska köra resultatet av dina vedermödor.

En FPU, eller "floating point unit", räknar flyttal direkt i hårdvara.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Arduino - ta medelvärde från beräkning, inte sensordata

Inlägg av Corpze »

Aha, då förstår jag.

Kod: Markera allt

sum-=(sum/99delta_celsius);
99st resultat... eller blir det 99* kanske...

Får kika närmare senare, begravning nu :/
Skriv svar