Recurring averages

Do you have a question on how to do something.
Ask in here.
Post Reply
User avatar
jsclownfish
Posts: 375
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Recurring averages

Post 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
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Recurring averages

Post by rimai »

How do you want to calculate average?
How many samples per week do you want to use?
Roberto.
User avatar
jsclownfish
Posts: 375
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: Recurring averages

Post 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
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Recurring averages

Post 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();
}
Roberto.
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Recurring averages

Post 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.
User avatar
jsclownfish
Posts: 375
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: Recurring averages

Post by jsclownfish »

That makes sense. I'll try these changes today.

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

-Jon
binder
Posts: 2865
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Recurring averages

Post 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. :)
User avatar
jsclownfish
Posts: 375
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: Recurring averages

Post 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
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Recurring averages

Post by rimai »

I think it is 100000 write operations
Roberto.
Post Reply