Page 1 of 1

Recurring averages

Posted: Wed Aug 22, 2012 1:13 pm
by jsclownfish
Awhile ago I was trying to have the RA calculate a weekly average of different variables in the tank. I never really got it to work and I'm guessing it's because I need to store the datapoint each day in a memory location and then display the average. My first attempt to code the functions was pulled from another smoothing function and looked like this...

Code: Select all

void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
I looked into the libraries used to store data used in generating the graphs on the display, but I'm not sure I understand how it saves the recurring data and knows to write over it when the last datapoint is added at the end. :? I'm hoping to see general trends in the data over time by having these points calculated and displayed on the monitor.

Any idea?
Thanks,
Jon

Re: Recurring averages

Posted: Wed Aug 22, 2012 1:58 pm
by rimai
How do you want to calculate average?
How many samples per week do you want to use?

Re: Recurring averages

Posted: Wed Aug 22, 2012 2:49 pm
by jsclownfish
The idea of the daily average was to take a reading at the top of the hour and therefore average every 24 readings. These would be a recurring average of the last 24 hours. The weekly average asks for a time (hour) to take a reading each day and average 7 readings. That too would be a recurring average of the last week. For the weekly average I wanted to be able to follow two time points, say 7am and 7pm for the highs and lows of pH.

-Jon

Re: Recurring averages

Posted: Wed Aug 22, 2012 3:20 pm
by rimai
Try this:

Code: Select all

#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

int daily[7];
int weekly_AM[7];
int weekly_PM[7];

void setup()
{
  ReefAngel.Init();  
  for (int a=0;a<7;a++)
  {
    daily[a]=0;
    weekly_AM[a]=0;
    weekly_PM[a]=0;    
  }
}

void loop()
{
  if (now()%3600) daily[hour()]=ReefAngel.Params.PH;
  if (now()%3600 && hour()==7) weekly_AM[hour()]=ReefAngel.Params.PH;
  if (now()%3600 && hour()==19) weekly_PM[hour()]=ReefAngel.Params.PH;
  ReefAngel.ShowInterface();
}

Re: Recurring averages

Posted: Sat Aug 25, 2012 6:57 am
by binder
Yep, like roberto is doing, the "readings" variable needs to be a global variable instead of private for each function. The reason is if it is declared in each function it is initialized in that function only and it is created each time the function is called. If you declare it globally (outside of all the functions at the top), then all functions have access to the variable and the values stay around for the life of the controller (until the controller is reset).

If you want to keep the values across controller reboots, you will need to save the values in the memory at the same time you update them in the array. Then, when the controller starts up, instead of initializing them to 0 like roberto is doing, you would need to read them from memory.
I took what roberto did and adapted it to use the internal memory and save it across controller restarts.
Here's my adapted code:

Code: Select all

#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

#define DAILY_START 100  // start point for daily
#define AM_START	DAILY_START + 14  // start point for weekly am
#define PM_START	DAILY_START + 28  // start point for weekly pm

int daily[7];
int weekly_AM[7];
int weekly_PM[7];

void set_average(byte avg_array, int loc)
{
  // avg_array:  0 = daily, 1 = weekly_am, 2 = weekly_pm
  int mem_location;
  switch ( avg_array ) 
  {
	default:
	case 0:  // daily average
	{
		daily[loc] = ReefAngel.Paramas.PH;
		mem_location = DAILY_START + (loc * 2);
		break;
	}
	case 1:  // weekly am average
	{
		weekly_AM[loc] = ReefAngel.Paramas.PH;
		mem_location = AM_START + (loc * 2);
		break;
	}
	case 2:  // weekly pm average
	{
		weekly_PM[loc] = ReefAngel.Paramas.PH;
		mem_location = PM_START + (loc * 2);
		break;
	}
  }
  InternalMemory.write_int(mem_location, ReefAngel.Params.PH);
}

int read_average(byte avg_array, int loc)
{
  int mem_location;
  switch ( avg_array ) 
  {
	default:
	case 0:  // daily average
	{
		mem_location = DAILY_START + (loc * 2);
		break;
	}
	case 1:  // weekly am average
	{
		mem_location = AM_START + (loc * 2);
		break;
	}
	case 2:  // weekly pm average
	{
		mem_location = PM_START + (loc * 2);
		break;
	}
  }
  return InternalMemory.read_int(mem_location);
}

void setup()
{
  ReefAngel.Init();  
  for (int a=0;a<7;a++)
  {
    daily[a]=read_average(0, a);
    weekly_AM[a]=read_average(1, a);
    weekly_PM[a]=read_average(2, a);
  }
}

void loop()
{
  if (now()%3600) set_average(0, hour());
  if (now()%3600 && hour()==7) set_average(1, hour());
  if (now()%3600 && hour()==19) set_average(2, hour());
  ReefAngel.ShowInterface();
}
Now with this, it saves the values as it updates them. It restores the values when the controller reboots. You are able to use those values in your display or get them from wifi memory. You can change the memory locations if you want, but I have them set to where they won't (or shouldn't) interfere with the existing memory locations.
The ONLY time this code won't work properly is on the very first use because the memory locations will have uninitialized data in it (most likely FF). So the data will be off at first. I would suggest you clearing out the memory prior to uploading the code so it will work as planned. Otherwise you will get erroneous data from memory for the first time through will all of them. To clear out the locations, I would use either the wifi apps or use the set_average call for each array and put the value to be 0.

Re: Recurring averages

Posted: Sat Aug 25, 2012 9:34 am
by jsclownfish
That makes sense. I'll try these changes today.

Thanks for the code and the lesson. I really appreciate it!

-Jon

Re: Recurring averages

Posted: Sun Aug 26, 2012 6:32 am
by binder
jsclownfish wrote:That makes sense. I'll try these changes today.

Thanks for the code and the lesson. I really appreciate it!

-Jon
No problem at all. Glad it helps. :)

Re: Recurring averages

Posted: Mon Aug 27, 2012 1:29 pm
by jsclownfish
I made this bit of code to follow it along and make sure the function was working OK. This just checks the reading each hour and generates a 24 hr. average temp. It seems to work fine, except I added a step to just take a point at the top of each hour. I was worried about the reading rewriting over and over again across an hour. Is there a limit to how often you can write over a memory space?

Code: Select all

#include <Salinity.h>
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

#define DAILY_START 100  // start point for daily
#define AM_START   DAILY_START + 48  // start point for weekly am
#define PM_START   DAILY_START + 62  // start point for weekly pm

int daily[24];
int weekly_AM[7];
int weekly_PM[7];
int average;
int total;
byte mod;

void set_average(byte avg_array, int loc)
{
  // avg_array:  0 = daily, 1 = weekly_am, 2 = weekly_pm
  int mem_location;
  switch ( avg_array ) 
  {
   default:
   case 0:  // daily average
   {
      daily[loc] = ReefAngel.Params.Temp[T1_PROBE];
      mem_location = DAILY_START + (loc * 2);
      break;
   }
   case 1:  // weekly am average
   {
      weekly_AM[loc] = ReefAngel.Params.Temp[T1_PROBE];
      mem_location = AM_START + (loc * 2);
      break;
   }
   case 2:  // weekly pm average
   {
      weekly_PM[loc] = ReefAngel.Params.Temp[T1_PROBE];
      mem_location = PM_START + (loc * 2);
      break;
   }
  }
  InternalMemory.write_int(mem_location, ReefAngel.Params.Temp[T1_PROBE]);
}

int read_average(byte avg_array, int loc)
{
  int mem_location;
  switch ( avg_array ) 
  {
   default:
   case 0:  // daily average
   {
      mem_location = DAILY_START + (loc * 2);
      break;
   }
   case 1:  // weekly am average
   {
      mem_location = AM_START + (loc * 2);
      break;
   }
   case 2:  // weekly pm average
   {
      mem_location = PM_START + (loc * 2);
      break;
   }
  }
  return InternalMemory.read_int(mem_location);
}
void DrawCustomGraph()
{
}
void DrawCustomMain()
{
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,1,"0:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,11,"1:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,21,"2:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,31,"3:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,41,"4:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,51,"5:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,61,"6:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,71,"7:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,81,"8:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,91,"9:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,101,"10:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,3,111,"11:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,1,"12:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,11,"13:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,21,"14:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,31,"15:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,41,"16:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,51,"17:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,61,"18:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,71,"19:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,81,"20:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,91,"21:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,101,"22:");
ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,55,111,"23:");
ReefAngel.LCD.DrawSingleMonitor(daily[0], COLOR_BLACK, 20, 1, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[1], COLOR_BLACK, 20, 11, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[2], COLOR_BLACK, 20, 21, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[3], COLOR_BLACK, 20, 31, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[4], COLOR_BLACK, 20, 41, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[5], COLOR_BLACK, 20, 51, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[6], COLOR_BLACK, 20, 61, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[7], COLOR_BLACK, 20, 71, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[8], COLOR_BLACK, 20, 81, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[9], COLOR_BLACK, 20, 91, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[10], COLOR_BLACK, 20, 101, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[11], COLOR_BLACK, 20, 111, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[12], COLOR_BLACK, 80, 1, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[13], COLOR_BLACK, 80, 11, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[14], COLOR_BLACK, 80, 21, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[15], COLOR_BLACK, 80, 31, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[16], COLOR_BLACK, 80, 41, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[17], COLOR_BLACK, 80, 51, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[18], COLOR_BLACK, 80, 61, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[19], COLOR_BLACK, 80, 71, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[20], COLOR_BLACK, 80, 81, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[21], COLOR_BLACK, 80, 91, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[22], COLOR_BLACK, 80, 101, 10);
ReefAngel.LCD.DrawSingleMonitor(daily[23], COLOR_BLACK, 80, 111, 10);
//average calculation
  total=daily[0]+daily[1]+daily[2]+daily[3]+daily[4]+daily[5]+daily[6]+daily[7]+daily[8]+daily[9]+daily[10]+daily[11]+daily[12]+daily[13]+daily[14]+daily[15]+daily[16]+daily[17]+daily[18]+daily[19]+daily[20]+daily[21]+daily[22]+daily[23];
  average = total / 24;    // calculate the average:
mod=second() %2;  
  if (mod==0)
  {
    ReefAngel.LCD.Clear(255,5,121,132,132);
    ReefAngel.LCD.DrawSingleMonitor(average, COLOR_BLUE, 55, 121, 10);
  ReefAngel.LCD.DrawSingleMonitor(total, COLOR_BLUE, 95, 121, 10);
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLUE, 15, 121, 10);
  }
  else
  {
    ReefAngel.LCD.Clear(255,5,121,132,132);
    ReefAngel.LCD.DrawDate(5,121);
  }
}
void setup()
{
  ReefAngel.Init(); 
//  setTime (3,59,0,8,26,2012);
  for (int a=0;a<24;a++)
  {
    daily[a]=read_average(0, a);
  }
    for (int a=0;a<7;a++)
  {
    weekly_AM[a]=read_average(1, a);
    weekly_PM[a]=read_average(2, a);
  }
}

void loop()
{
    if (minute()==0 && second()<5)
{
    if (now()%3600) set_average(0, hour());
    if (now()%3600 && hour()==7) set_average(1, hour());
    if (now()%3600 && hour()==19) set_average(2, hour());
}
  ReefAngel.ShowInterface();
}

-Jon

Re: Recurring averages

Posted: Mon Aug 27, 2012 2:55 pm
by rimai
I think it is 100000 write operations