Sunday 31 August 2014

Home made Pyranometer or Irradiance/Insolation Meter

Home made Pyranometer or Irradiance/Insolation Meter


The idea behind making a Pyranometer is to add another measurement to my weather station. It is basically a light meter but it can also tell me what the cloud cover was on any given day. I'm hoping to combine this data with temperature and rainfall readings to see if I can find correlations between plant growth and fruit yields. Just something to do really!

Today was the first day my prototype was put into action, see previous post, and I recorded, automatically, a reading of how much power from the sun was reaching the earth every minute. Technically if using a PV Solar Panel I should have put it into short circuit but I haven't done this since I have no way of calibrating my device. By loading the panel to the maximum power point, which is close to the short circuit point, I at least have the manufacturers Standard Test Condition ratings to calibrate my readings with.

To cut a long story short the results were graphed from 8:30am to just past 6:30pm and are below. What the readings can tell me is what the cloud cover was and whether the clouds were thick and low or high cirrus clouds. Today was a good day for the trial run...


Click image for larger version
  The Y axis is Watts per Metre Squared and the X access is minutes since 8:30am.

The dip just after the 100 minute mark is when the telegraph pole cast a shadow onto the solar panel and 10 minutes later the jagged points rising were the shadows of the power lines. The rest are clouds.

The panel is on a 66 degree roof (I couldn't find a horizontal place to mount the panel near a power point) and is a few degrees off of south. The results are reasonably accurate, perfect for what I need. You can clearly see that first thing there were very few clouds, as is the case around 4pm and from 5pm onwards. The highest peaks are full sun. Today was one that you would class as not a bad summers day, a few too many clouds perhaps but a standard late summers day.

Had there been no clouds the graph would have looked similar to this image I nicked from http://www.mpoweruk.com/solar_power.htm


Anyone interested in the C++ program I knocked up it is here (not brilliant but functional and the formatting has gone wrong when I pasted it here):



// The Raspberry Pi is connected to an MCP3004 Analogue
// to Digital Converter. That is connected to a Solar
// Panel with a load to produce max power. The Voltage
// is divided down to max of 3.3 and then read.
// Calculations are made to work out power being generated
// and Insolation (irradiance) falling onto the panel
// It is calibrated by the manufacturers STC values on
// the panel, ie, 5 Watts at 17.9 volts, .280A when
// Irradiance is 1000 W/m2

/////////////
// OUTPUTS //
/////////////
//
// date time,interval in minutes,power in watts from test panel
// ,watts per sq metre,watts generated with 16 standard panels
// ,calculated insolation,voltage of test panel,current in test panel,status (0=ok,1=no reading)
//
// yyyy-mm-dd hh:mm:ss,int,float,float,float,float,float,float,int

// Used to access GPIO
#include <wiringPi.h>
// Used to read ADC
#include <mcp3004.h>
// Used by setprecision
#include <iomanip>
// Used for reading the time
#include <ctime>
// Used for making strings
#include <string>
// Used by number to string conversion
#include <sstream>
// Used by file writing
#include <fstream>
// Used by mkdir()
#include <sys/stat.h>
// Used by shutdown
#include <stdlib.h>

// Used by WiringPi to access ADC MCP3004
#define BASE 100
#define SPI_CHAN 0
using namespace std;

// Test last write time
int check_clock_update()
{
long int solartime = 0;
ifstream in("solartime.txt", ios::in);
if(!in)
{
// no file
return(1);
}
in >> solartime;
in.close();
time_t t = time(NULL);
// Give the time 5 minutes because Pi may take some while to shutedown and record time
// This may be lowered to what ever time it takes Pi to shutdown properly
// If Pi power is cut then fake clock time will be upto 1 hr behind
if (t > (solartime+300)) return(solartime); else return(0);
};

// save last write time
void record_time(long int t)
        {
        ofstream out("solartime.txt", ios::out);
        if(out)
{
  out << t;
out.flush();
out.close();
}
        };

// convert any number to string
template <typename T>
  string NumberToString ( T Number )
  {
     ostringstream ss;
     ss << Number;
     return ss.str();
  };

// Make time string YYYY-MM-DD HH:MM:SS for recording the date time of reading
string time_str()
{
time_t t = time(0);   // get time now
struct tm * now = localtime( & t );
string s;
string year = NumberToString(now->tm_year + 1900);
string month = NumberToString(now->tm_mon + 1);
if (now->tm_mon+1 < 10) month = "0" + month;
string day = NumberToString(now->tm_mday);
if (now->tm_mday < 10) day = "0" + day;
string hour = NumberToString(now->tm_hour);
if (now->tm_hour < 10) hour = "0" + hour;
string min = NumberToString(now->tm_min);
if (now->tm_min < 10) min = "0" + min;
string sec = NumberToString(now->tm_sec);
if (now->tm_sec < 10) sec = "0" + sec;
s = year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec;
return(s);
};

// For 1st folder name
string time_year_str()
        {
        time_t t = time(0);   // get time now
        struct tm * now = localtime( & t );
        string year;
        year = NumberToString(now->tm_year + 1900);
return(year);
};

// For 2nd folder name
string time_year_month_str()
{
// Get time
        time_t t = time(0);   // get time now
        struct tm * now = localtime( & t );
// Build up string YYYY-MM
        string s;
        string year = NumberToString(now->tm_year + 1900);
        string month = NumberToString(now->tm_mon + 1);
        if (now->tm_mon+1 < 10) month = "0" + month;
s = year + "-" + month;
return(s);
};

// For filename
string time_year_month_day_str()
        {
// Get time
        time_t t = time(0);   // get time now
        struct tm * now = localtime( & t );
// Build up string in a formatted way
// YYYY-MM-DD
        string s;
        string year = NumberToString(now->tm_year + 1900);
        string month = NumberToString(now->tm_mon + 1);
        if (now->tm_mon+1 < 10) month = "0" + month;
        string day = NumberToString(now->tm_mday);
        if (now->tm_mday < 10) day = "0" + day;
        s = year + "-" + month + "-" + day;
        return(s);
};


int main()
{
// General Variables
    float x, chan, irradiance, panels ;
float voltage, current, power, metre, resistor;
long int time_target = 0;
int read = 0, status, interval, fail_count = 0, start = 0;
int writes = 0;
// Interval between samples
interval = 60;
string ts;
// Don't start unless the time is greater than our last reading
// plus 5 minutes. Since the Pi doesn't have RTC we may have to wait
// for the clock to be updated.The Pi fake clock gets written on shutdown
// so we may power up with the last known good time.
// If no file continue, it may be the first run
// If last write time is before now, wait
// if last time time is after now continue
long int check_time = 0;
while (check_time == 0)
{
check_time = check_clock_update();
}
// Handy little library to access various chips via Raspberry Pi
    wiringPiSetup() ;
// This is the ADC chip on the LinkSprite.com Shield.
    mcp3004Setup (BASE, SPI_CHAN) ; // 3004 and 3008 are the same 4/8 channels
chan = 0;
// Just keep repeating until power fail or cntl-c etc
while(1)
{
time_t t = time(NULL);
// Do we take a reading?
if (time_target <= t) read = 1;
if (read)
{
// read ADC on  linksprite.com rpi shield
x = analogRead (BASE + chan);
// If we got a value then do calculations
if (x > 0)
{
// We have loaded the solar panel with 8 Watt resistor
resistor = 63.93;
// Voltage from panel is divided using resistors to produce
// Max 3.3v - this is 6.79 times smaller than the real voltage
// combine this with the ADC output to find correct voltage
// that the panel is generating
voltage = (3.3/1023)*(x*6.79);
// When we know Voltage we use Ohms Law to find current
current = voltage / resistor;
// Now we can work out power of our little panel
power = voltage * current;
// Scale it up dimension wise to 1 sq metre
// Our panel is 27.135 times smaller than 1 sq metre
metre = 27.135*power;
// 16 panels of roughly 1.5 sq metres each
panels = (24 * metre);
// Our little panel is 5.012 Watts when irradiance = 1000 Watts
// So we scale up
irradiance = 199.52*power;
// What's the time of our reading?
ts = time_str();
// Good status
status = 0;
start = 1;
fail_count = 0;
}
// If we didn't get a value then zero everything, set status and time
else
{
// Don't know if we ever get here but if we do
// We still want to record the fact it failed
voltage = 0;
current = 0;
power = 0;
metre = 0;
ts = time_str();
panels = 0;
irradiance = 0;
// Bad status
status = 1;
fail_count++;
}
}
// If we attempted a reading save it providing we have had
// at least one good reading. Only start recording once we
// know there is enough data. Saves SD Card Writes.
if (read && start == 1)
{
// Create pathname in same format as our other weather station
string top = "/home/pi/SolarPanelPower/irradiance";
// If directory isn't there make it otherwise silently fail
mkdir(top.c_str(), 0777);
string pathname, path;
pathname =  time_year_str();
pathname = top + "/" + pathname;
// write 2nd directory of year
mkdir(pathname.c_str(), 0777);
path = time_year_month_str();
path = pathname + "/" + path;
// 3rd directory is year + month
mkdir(path.c_str(), 0777);
// Filename is year-month-day.txt
string filename = path + "/" + time_year_month_day_str() + ".txt";
    ofstream ofile(filename.c_str(), ios::app);
// Interval between readings in seconds needs converting to minutes
// to match weather station
int temp = interval / 60;
    if ( ofile )
    {
// write to file
        ofile << ts << setprecision(2) << fixed << "," << temp << "," << power << "," << metre << "," << panels << "," << irradiance << "," << voltage << "," << current << "," << status << endl;;
        ofile.flush();
ofile.close();
    }
// We have finished this reading
read = 0;
// increase write count
writes++;
// Reset counter interval
               time_target = t + interval;
// write last sample time every 10 samples
if (writes == 10)
{
record_time(t);
writes = 0;
}
// Sleep for 90% of interval time to save CPU
// CPU on Raspberry PI is flat out with this program which uses
// a lot of power. Well over 90% of time is spent running around
// in a loop checking the time to see if the interval time has
// been reached. Not necessary so do nothing for most of the time.
// We could do nothing for 99% but play it safe!
sleep((int)interval*0.9);
// If we fail to get 10 readings in a row shutdown - fault or too dark
// for a reading. Save SD Card Writes.
if (fail_count >= 10 && start == 1)
{
record_time(t);
// wait for any flushing to finish - maybe not needed
sleep(60);
system("sudo shutdown -h now");
}
}
}

// All done, return to OS
return 0;
}




Thursday 21 August 2014

Monitoring the Health of Plants

Monitoring the Health of Plants

The purchasing of a Raspberry Pi computer for making and designing electronic circuits has opened up a few useful and interesting possibilities. I was initially looking for a way to add to my weather station data that I collect. I am lacking the ability to monitor the amount of light and with it the ability to record cloud cover. Hooking the Raspberry Pi up to a solar panel and reading the power from the sun deals with this issue but whilst working out the details of reading the Sun's energy from the solar panel I was reading up about Infra-red light and stumbled upon Normalized Difference Vegetation Index or NDVI for short. 

NDVI uses Infra-red and visible light to look at how much photosynthesis is taking place within a plant. This involves taking a photo with an Infra-red camera and combining that with the visual light image of the same subject. 

I haven't read anything about needing to know how much Infra-red is coming in from the sun at the time the picture is taken but I feel there may be some mileage in doing so. To this end the first job was to read the Sun's power from a solar panel on a regular basis, every 10 minutes, and store the data so that it can be combined with my weather data. Knowing how much power is coming from the Sun also has the advantage of being able to record how cloudy the day has been as well as how high the clouds are and how dark they are. It can also tell you how clear a day it is.

To work out how much power a solar panel is producing you need to monitor the voltage and current but if the solar panel isn't being used to power anything you can combine these by giving the solar panel a fixed load. If you know the load, the resistance, then all you need to measure is the voltage. Knowing the Voltage and resistance you can work out the current and from there you can work out the power, in Watts, that is being produced. A little bit of mathematics is needed along with a small amount of computer programming and some wiring up. First we need to know the details of the solar panel. The one I have is for keeping a car battery charged and is only a 5 Watt panel.

Solar Panel Irradiance Meter
I'm going into as much detail as I can with regards to reading the Sun's power because I couldn't find much information about it around the web and there is nothing worse than thinking you have found what you want only to find an important piece of information is missing in order to build one yourself.

Solar panels are rated and the cells have been tested with "Standard Test Conditions" which is handy because we know exactly what power it will produce at a certain light level.

The specs of my panel are:
Pmax: 5W
Vpm: 17.9V
Ipm: 0.28A
Voc: 22.41V
Isc: 0.3A
Standard Test Conditions: 1000W/m2 AM1.5 @ 25 Degrees Celsius

What this tells us is that the panel will produce 5W of power when the Sun's irradiance is 1000W per meter squared. In those conditions the panel will output 17.9V and be able to produce 0.28A of current.

Multiplying Voltage by Current gives us the Power: P = V x I,  17.9 x 0.28 = 5 Watts

The panel could produce more power than this if the Sun's irradiance was more than 1000 but the 5W power point allows us to calibrate and scale our readings to this figure. The Voc, The open circuit voltage is the highest voltage that the board can produce with full sun and no load. Isc is the short circuit current or the maximum current that will be produced under perfect conditions.

To get a computer to read voltages we need to use an Analog to Digital converter. The Laika Explorers Kit, or Inventors kit has an ADC on it and the maximum voltage it can read is 3.3V.

We need to scale the voltage that can come out of the panel in normal conditions (17.9V) down to 3.0V using resistors. Not only that but the resistors we choose need to act as a load for the panel. When we load up the panel it shouldn't be able to reach the maximum voltage of 22.41V.

R = V / I will give us the resistance we need to load the panel with.

R = 17.9V / 0.28A
R = 63.9 Ohms

We now need to split this resistance into 2 so when the panel outputs 17.9V the Analog to Digital converter only sees 3V.

17.9V / 3V = 5.96 - this is our scaling factor. One resistor must be 5.96 times bigger than the other.

We now divide our load resistance by 5.96

63.9 Ohms / 5.96 = 10.7 Ohms (one resistor is 10.7 Ohms) the other is 63.9 Ohms minus 10.7 Ohms which is: 53.2 Ohms

I'll use 2 potentiometers, variable resistors, and trim them to exactly the right values using a multimeter. We feed the voltage across the smaller resistor into the Analog to Digital converter. The reason the drawing above shows different resistors is because I used the maximum voltage of 22.41V for the calculations rather than the normal voltage. I did this to make sure that the maximum voltage was never reached under load. I still need to do more tests to make sure that the Analog to Digital converter doesn't see more than 3.3V which converts into a maximum of 19.17V overall. We don't want to blow up the ADC. The Sun's irradiance power could possibly reach 1367 Watts and we have presumed that the actual figure won't go above 80% of this figure because the atmosphere will block at least 20%. If the Sun's power reaching our solar panel does go above 1100 Watts then we'll need to increase our resistors accordingly to protect the ADC.

The Analog to Digital Converter is a 10 Bit converter. This means that the digital output will be from 0 to 1023, with 0 representing 0 Volts and 1023 representing 3.3 Volts.

If we see the number of 600 from the ADC then we known that 3.3v / 1023 x 600 is the voltage (1.84 Volts). We would then multiply this by our scaling factor above, 5.96, which would give us a voltage of 11.54 Volts. We know the load resistance, 63.9 Ohms so we can work out the current as V / R which is :  180mA. From there we multiple V x I = 2.08 Watts.

Our panel is able to produce 5 Watts when the sun's irradiance is 1000 Watts which gives us a scaling figure of 200. Multiply what our panel is producing by 200, 2.08 x 200 and we get a reading of 416 Watts per square meter. That is how much power is in the sun light reaching our panel.

These readings are only correct when our panel is perpendicular to the sun. If we leave it in one position then it will hardly ever be at right angles to the Sun.

At this point we are in the position of being able to leave our panel in a fixed position and work out how much electricity we could produce from the sun, and it would be an accurate representation of what we could expect to produce should we want to install Solar panels on our house roof. Just mount our small panel at the angle of our roof.

For working out how much sunlight irradiance there is we need to compensate for the angle of the panel compared to the angle of the Sun.

If our panel was 45 degrees different from perpendicular to the sun ( or any other angle) then we can use the mathematical Sine function.

The SIN(45) (sin of 45 degrees) = 0.707 - this tells us that our panel reading is only 70.7% of the actual value.

1/sin(45) x 416 = 588 Watts which is the real power in the sun considering we are at 45 degrees to the Sun.

Obviously our panel is not only out in one direction (the tilt) but will be out in the east west angle as well so this angle would also need to be calculated. To work out these calculations we need to know the position of the sun in the sky when we take our readings. To do this we need some serious astronomical calculations, which are available, and which I have a program for working out the position of the sun at any given time. This is where hooking a solar panel to an analog to digital converter and then inputting that into a tiny computer such as the Raspberry Pi allows us to make a really good irradiance / insolation meter.

Our meter, if monitoring the suns power every minute or 10 minutes, can see clouds passing. A high value but not maximum tells us that there are either high cirrus clouds or the day is hazy, low readings tell us that it is over cast.

To get more correct readings we should temperature compensate our readings because a solar panel will lose about 0.4 or 0.5% of it's power for every degree Celsius the panel is above 25 degrees C. This is easy to do by hooking up a small temperature sensor to the Raspberry Pi and sticking it to the back of the solar panel.

Infrared Photography and NDVI
Plants use Red and Blue light to carry out photosynthesis. The structure of plant cells will reflect near infrared light. Scientists have been using this to photograph the earth from satellites for years to work out how well the vegetation is doing on earth. More recently farmers have been using this data to work out how well their crops are doing. Using the power of modern technology and the fact it is cheap and within the hands of the ordinary man we can also use this technology to monitor the health of our own plants.

It should be possible to see areas within your own crop that isn't growing particularly well before it causes a problem and then to rectify the problem which could be lack of water or lack of nutrients.

I have purchased an infrared camera and am in the process of learning how to process the camera image to produce an NDVI image. Basically this simply means doing some maths on the pictures.

The NDVI process is: Subtract the visible light image from the infrared image then divide that by the infrared image plus the visible light image. What is produced is an image which is a ratio of visible and infrared.

From that point you could attach the camera to a balloon and photo your own plot from above.

There is a Public Lab open community project to do just this at http://publiclab.org/wiki/near-infrared-camera

I am hoping to find a correlation between the sun's power as recorded above with infrared pictures obtained.

Accurate data
I am hoping by recording all the environmental conditions including the sun's power, and future soil temperature, that I should be able to document how many hows of sunshine and how many hours above a certain temperature a crop needs to germinate and go on to produce ripe fruit.

Future plans
In theory it might be possible to detect plant diseases and different bacteria using infrared or by using a camera to do spectral analysis on reflected UV. Technology has opened up a whole new avenue of experimentation with plants and the environment for me and allows me to combine my programming and electronic background with growing food.

I have all the technology, it's now just a matter of hooking it up, programming and experimenting and looking at the results and seeing whether they can be useful....more to follow :)