This post covers the design of a low-cost solar irradiance sensor. This type of sensor is called a ‘pyranometer‘, (from the Greek “pyr” (fire) and “ano” (sky/heaven)) and there are a wide range of units available, typically very expensive, but accurate! I wanted to design a lower cost unit which can be easily interfaced with a microcontroller. I wanted to measure in-plane solar irradiance, so that I could compare the output from solar panels with the light level.
There are quite a few ways of doing this, with the three main techniques being: (1) use a solar cell that is accurately calibrated (a solar cell is also a photo diode) and measure the output current, (2) use a thermopile, where two dissimilar metals are used with a hot and cold side to measure a very small generated voltage from the difference in heat from the solar radiation and (3) use a photo-resistor, which has a resistance that varies with light level. Most highly accurate pyranometers use the thermopile, which have the widest spectral response , but this requires specialist glass covering and highly accurate voltage measurement. So some form of photo diode will probably be the final design.
First lets have a look at what is already available. These are the main suppliers of laboratory-grade pyranomteres. These are the ones you want if you need high accuracy and have the budget:
- Kipp & Zonen: https://www.kippzonen.com/ProductGroup/3/Pyranometers
- Skye Instruments: https://www.skyeinstruments.com/pyranometers-solar-farms/
- Cambell Scientific: https://www.campbellsci.eu/cmp11
- Delta-T: https://delta-t.co.uk/product/spn1/
- OnSet S-LIB-M003: https://www.onsetcomp.com/products/sensors/s-lib-m003/
The next few here are either designed for hand-held measurements of solar irradiance, for example when checking PV output during installation checks, or they are slightly lower cost sensors:
- RS Pro Solar Power Meter: https://uk.rs-online.com/web/p/solar-power-meters/1232218/
- Solar Survey 100 from Seaward: https://www.seaward.com/gb/products/solar/irradiance-meters/396a910-solar-survey-100/
- Solar Power Meter TM-206: https://www.test-meter.co.uk/solar-power-meter-tm-206
- Megger PVM201: https://www.test-meter.co.uk/megger-pvm210-irradiance-meter
Here are some plans for DIY pyranometers. Lots of great information here, but there are loads of ideas and plans out there:
- Designing a Low-Cost Autonomous Pyranometer – Peter van der Burgt – This is probably the best review of the ideas here!
- Measuring Sunlight at Earth’s Surface: Build Your Own Pyranometer – David Brookes
- Build-it-solar use & review the above design here
- ERASMUS: Build your own pyranometer – using temperature difference to calculate irradiance
- Solarduino – nice review of concepts and design of solar cell irradiance sensor
- A New and Inexpensive Pyranometer for the Visible Spectral Range
To get going I ordered a wide range of different light level sensors. Not all of these were suitable, which I try to highlight here.
This is a ‘metal can’ ambient light sensor from Osram. This is around £10 (!) per unit. It has a large sensor area.
This is a Light Dependant Resistor with buffer amplifier. This type of sensor is not really suitable for accurate irradiance sensing. It has a nice ‘Grove’ connector for quick wiring to prototypes.
This is another ‘metal can’ ambient light sensor from Osram. This is around £6.50 in single quantities, so pretty expensive! I used this in my prototype and it worked really well. But maybe too expensive for deployment. This is a silicon based photodiode, so would have a similar response to a silicon solar photovoltaic panel.
This uses a light-to-digital converter, the TSL2561. This has dual photo diode to cover infra-red and visible light spectrum.
This is a similar break out board to the unit above, but supplied by Adafruit. This is a discontinued product.
This is designed for use in mobile electronics to adjust screen brightness. It has an I2C connection so easy to interface with a micro-controller. But this is designed for human eye light level sensing, so outputs lux rather than irradiance
This is a module using a low-cost photo-diode and an amplifier and a comparator. This means we can set a light level and have a digital trigger. Great for sensing light changes and setting an alarm, but not too useful here. The diode is unspecified so unsure about accuracy and calibration here, so probably not suitable.
This is a much lower cost unfiltered photo diode from Osram (code: Q62702-P0955), at around £1.50 per unit. This seems to be a suitable unit with a decent spectral response.
This uses the SI1145 from SiLabs with a calibrated light sensing algorithm that can calculate UV Index. This is great for UV monitoring (for sunlight exposure, for example) but is not really suitable here.
The paper here by Martínez et al gives a good comparison of the sensors that they short listed, which is probably what I should have read in the first place!
I decided to use a photo-diode for my unit. This needs correct biasing in order to give a good linear output.
I found some information here:
- What Photodiode Bias Should You Use for Optical Detectors?
- DESIGNING PHOTODIODE AMPLIFIER CIRCUITS WITH OPA128
- Optimizing Precision Photodiode Sensor Circuit Design
The main take-away is that the photo diode outputs a current which varies with light level. This can then be biased to ensure a linear voltage output. The third link gives a good review of a simple op-amp circuit to give an output voltage proportional to the photodiode current. This is shown here:
They highlight the main requirements which are: very low input current op-amp (such as JFET or CMOS) and a rail-to-rail op-amp with very low offset voltage. I had both the TLC2252 and the LMC662 types in stock and tried both of them and they both had similar outputs and both worked well, as far as I could see on my ‘scope. The main issue with both of these op-amps is that they need 4.4V or more. I will look at single side CMOS or JFET op amps that will work with 3.3V, so the unit can then be run at 3.3V or 5V which makes it more compatible. I searched and found that the TSV911 is a low cost, single supply op-amp working at 2.5-5.5V and with low bias current and low offset voltage, so this should work!
I made up a prototype circuit, first on breadboard and then (when working) I put it onto strip board. This is not great for noise, but seems to work well for now! I will design the PCB further down the line, when I know this is reading accurately.
After review the above samples and various links, I settled on using a photo-diode with a simple transimpedance amplifier. The sensor choice came down to two sensors, which actually both gave decent results. These were the BPX65 and the SFH203 both manufactured by Osram. The spectral response of these two sensors is given below, along with a typical silicon solar PV spectral response.
It can be seen that the BPX65 has a response that is more similar to the silicon PV cell, but both have a relatively good and similar spectral response. The main issue here is that the BPX65 costs in the region of £6.50 each and the SFH203 is around £1.50… I might design this to work with either and then people can choose the sensor for their final application.
In order to correct the unit for any temperature related effects, I need to also measure the temperature of the sensor. I decided to use the DS18B20 1-wire temperature sensor. This provides an accurate temperature, but is quite a big case, so may have a thermal lag. It is also measuring the air temperature, rather than direct on the sensor. But within a couple of degrees I think this might work?
When I started to put the unit together a bit more, then I realised that it might be better to have an I2C sensor on the PCB, rather than a 1-wire unit. I’m already implementing I2C, so why not use this for the temperature sensor. I found the LM75B from NXP. This is a low cost I2C temperature sensor, designed for device temperature monitoring. It’s not amazingly accurate for a direct value, but good for relative change. As long as we can calibrate for this then it should be OK? The PCB design will have one of these IC’s onboard, connected to the I2C bus.
The sensors given here are very sensitive and are likely to be overloaded with too much irradiance. We want the sensor to work in a ‘linear’ region where the output is proportional to the irradiance. Most commercial sensors have diffusers in order to reduce the light reaching the sensor. I read that this is usually made form a standard thickness PTFE, so I ordered some samples on different thickness PTFE (0.25, 0.5 and 1mm). I built a small enclosure to house the prototype sensor and found that the 1mm PTFE reduced the output quite well, although it still reached saturation (in my case, hit the maximum of the op-amp output) with a very bright light close to the sensor (in the region of > 2000W/m2). I want a sensor that can read 0-2000W/m2 range (typical outdoor irradiance values). I will mess around with the PTFE thickness when moving forwards with the prototype.
One note here: Do NOT cut PTFE on your laser cutter. It will release fluorine gas which is highly poisonous. I cut my sample down to size with a knife and drill. I will look to CNC these if I need to make lots.
Validation and Calibration
In order to initially test my prototype, I used another (uncalibrated!) irradiance sensor that I own. I looked at the output values from my sensor and that with the irradiance sensor. This allowed my to create a ‘map’ of sensor values proportional to the irradiance. I then added this to the basic Arduino code to start to give me irradiance readings out. I wanted to test repeatability and also any temperature changes.
*** to do: add this data!!! ***
I designed a PCB layout for this sensor using KiCAD (an open source PCB design package). I started off trying to make a full unit with display and buttons etc. I then decided to strip this back and just make a sensor unit that can communicate via a serial communication. I initially decided to use the ATTiny85 IC, as this is one I am familiar with and have lots of samples lying around! I wanted the sensor to be configurable and either report data back as a stream or as a single value when requested. I also needed to be able to easily calibrate the sensor with simple serial commands. Also I wanted the unit to have a configurable address, so there can be more than one sensor on a serial bus.
Running I2C on the ATTiny85 requires a few additional bits of information, as given in the following links:
The main point is that the ATTiny85 does not have a built in I2C controller – you need to configure the Universal Serial Interface. It seems like the most used library for this is the Adafruit version of TinyWire, which is TinyWireM. I added this to my code and it worked first time! You do need to ensure your SDA and clock signals go to the correct pins, as per the schematic for this project.
I also need to service serial requests from the monitoring device. This needs to implement a software serial port. Here are some posts on getting started with software serial on the ATTiny85:
I’m using the internal 8MHz oscillator, so timing for high speed serial will not be great. I am limiting the baud rate here to 9600 only, to stop any communication timing issues. Using the Arduino SoftwareSerial library seems to just work. I wired this up and tried it out. There is not much memory on the ATTiny85, so I need to be careful with serial strings and ensure I am efficient with code! I added SoftwareSerial and connected to a USB-Serial converter at 9600 baud and I could see data sent from the ATTiny85 out via the serial port. This is a good step!
I needed to sleep most of the time to save a bit of power. But I want to wake up either on a watch dog timer (for regular reading of the sensor) or if any data comes in on the serial port. I had done code to enable the watch dog timer before, so that was quite easy (see code example), but I also needed to have an interrupt pin on the Rx pin of the SoftwareSerial. This means data into the unit will wake it up, as it will trigger the external interrupt. I needed to set up an interrupt on pin D3 and have an interrupt service routine that services that interrupt.
I mainly used the information here (https://www.gadgetronicx.com/attiny85-external-pin-change-interrupt/) relating to interrupts on the ATTiny85. This explains that INT0 (pin PB2/D2) can be used as an external interrupt. But pins PB0, PB1, PB2, PB3, PB4 and PB5 can all be configured to be a pin-change interrupt, which can be triggered by change in state of an external source. We need to ensure the Global Interrupt Enable is set within SREG. We also need to set the General Interrupt Mask Register is correctly configured, to enable PCIE (pin change). We need to set the PCMSK : Pin Change Mask Register so it knows that we want a pin-change interrupt on pin PB3. Everything shares the same ISR, so we will need to check why the unit was triggered (either watch dog timer or interrupt) and service the request correctly.
Maybe this already happens with SoftwareSerial which uses pin change interrupts? Yes – it does. Basically the SoftwareSerial will interrupt when data is received. This means it already wakes up and we don’t need to do anything, just put it to sleep again after processing a serial command.
I managed to get nearly everything working on the ATTin85, but the 8kB code limit stopped me implementing some of the more useful features (such as calibration curves and different baud rates). So I upgraded the design to use the ATMega328 (the same as used in the Arduino Nano/Uno). This gives me a whopping 32kB to play with! I kept the ATTiny85 design within the github repository, but have added new firmware and PCB design for the ATMega328 unit. I needed to change the circuit board from a circular one to a square one, but its the same diameter (45mm). I managed to cram the additional components on, including the crystal oscillator required.
The firmware will be very similar to the ATTiny85 version, but I have more space to do things, such as implement floats for data conversion, have more commands for adjusting the unit, run at different and much higher baud rates (up to 57600 for an 8MHz crystal and operating at 3.3V), and also implement much more accurate calibration curves to convert the sensor reading into the irradiance output. The firmware will be updated when I have some PCB samples to play with!
For long distance cables this should really be changed to an RS485 serial communication. This is a relatively simple add on with a MAX485, but this needs thought about the power supply voltage. To start with I’ll just get a serial unit designed.
All the PCB design and Arduino code is held in the github repository here: