Home › Forums › Environmental Sensors › Programming and troubleshooting Apogee SP-710 sensor
Tagged: albedometer, apogee, modular sensors, pyranometer, SP-710
- This topic has 2 replies, 1 voice, and was last updated 2024-03-25 at 12:53 PM by Braedon.
-
AuthorPosts
-
-
2024-01-25 at 6:03 PM #18306
I have installed some stations that use the Apogee thermopile pyranometers and pyrgeometers to measure incoming and outgoing shortwave and longwave radiation. These sensors don’t have their own source code in the modular sensors library, so I took the liberty of creating my own based on the Apogee SQ-212 files that already exist. The data I’m getting back for the longwave radiation (from the SL-510 and SL-610 sensors) seems to be in a reasonable range but my shortwave readings are not. The shortwave measurements are taken by the SP-710, which is an analog albedometer that combines the SP-510 and the SP-610: https://www.apogeeinstruments.com/sp-710-ss-albedometer-sensor-package/
I don’t notice anything wrong with my wiring, so my guess is that there is something wrong with the code I created. If I could get some help checking if the source code and header files I made for the Apogee pyranometers and pyrgeometers is sound that would be great. I’ll just add the upward looking pyranometer header and cpp files first because I don’t want to clutter this thread, and the SP-610 files are based on the SP-510 files.
C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355/*** @file ApogeeSP510.h* @copyright 2017-2022 Stroud Water Research Center* Part of the EnviroDIY ModularSensors library for Arduino* @author Written By: Anthony Aufdenkampe <aaufdenkampe@limno.com>* Edited by Sara Geleskie Damiano <sdamiano@stroudcenter.org>* Adapted from CampbellOBS3.h by Sara Geleskie Damiano* <sdamiano@stroudcenter.org>** @brief Contains the ApogeeSP510 sensor subclass and the variable subclasses* ApogeeSP510_ISWR and ApogeeSP510_Voltage.** These are used for the Apogee SP-510 incoming shortwave radiation sensor.** This depends on the soligen2010 fork of the Adafruit ADS1015 library.*//* clang-format off *//*** @defgroup sensor_sp510 Apogee SP-510* Classes for the Apogee SP-510 thermopile radiation sensor.** @ingroup analog_group** @tableofcontents* @m_footernavigation** @section sensor_sq212_intro Introduction* The [Apogee SQ-212 quantum light* sensor](https://www.apogeeinstruments.com/sq-212-amplified-0-2-5-volt-sun-calibration-quantum-sensor/)* measures [photosynthetically active radiation* (PAR)](https://en.wikipedia.org/wiki/Photosynthetically_active_radiation) -* typically defined as total radiation across a range of 400 to 700 nm. PAR is* often expressed as photosynthetic photon flux density (PPFD): photon flux in* units of micromoles per square meter per second (μmol m-2 s-1, equal to* microEinsteins per square meter per second) summed from 400 to 700 nm. The* raw output from the sensor is a simple analog signal which must be converted* to a digital signal and then multiplied by a calibration factor to get the* final PAR value. The PAR sensor requires a 5-24 V DC power source with a* nominal current draw of 300 μA. The power supply to the sensor can be* stopped between measurements.** To convert the sensor's analog signal to a high resolution digital signal,* the sensor must be attached to an analog-to-digital converter. See the* [ADS1115](@ref analog_group) for details on the conversion.** The calibration factor this library uses to convert from raw voltage to PAR* is that specified by Apogee for the SQ-212: 1 µmol mˉ² sˉ¹ per mV (reciprocal* of sensitivity). If needed, this calibration factor can be modified by* compiling with the build flag <code></code><code>-D SQ212_CALIBRATION_FACTOR=x</code><code></code> where x is* the calibration factor. This allows you to adjust the calibration or change* to another Apogee sensor (e.g. SQ-215 or SQ225) as needed.** @section sensor_sq212_datasheet Sensor Datasheet* [Datasheet](https://github.com/EnviroDIY/ModularSensors/wiki/Sensor-Datasheets/Apogee* SQ-212-215 Manual.pdf)** @section sensor_sq212_flags Build flags* - <code></code><code>-D MS_USE_ADS1015</code><code>* - switches from the 16-bit ADS1115 to the 12 bit ADS1015* - <code></code><code>-D SQ212_CALIBRATION_FACTOR=x</code><code>* - Changes the calibration factor from 1 to x** @section sensor_sq212_ctor Sensor Constructor* {{ @ref ApogeeSQ212::ApogeeSQ212 }}** ___* @section sensor_sq212_examples Example Code* The SQ-212 is used in the @menulink{apogee_sq212} example.** @menusnip{apogee_sq212}*//* clang-format on */// Header Guards#ifndef SRC_SENSORS_APOGEESP510_H_#define SRC_SENSORS_APOGEESP510_H_// Debugging Statement// #define MS_APOGEESP510_DEBUG#ifdef MS_APOGEESP510_DEBUG#define MS_DEBUGGING_STD "ApogeeSP510"#endif// Included Dependencies#include "ModSensorDebugger.h"#undef MS_DEBUGGING_STD#include "VariableBase.h"#include "SensorBase.h"/** @ingroup sensor_sp510 *//**@{*/// Sensor Specific Defines/// @brief Sensor::_numReturnedValues; the SP510 can report 2 values, raw/// voltage and calculated incoming shortwave radiation.#define SP510_NUM_VARIABLES 2/// @brief Sensor::_incCalcValues; PAR is calculated from the raw voltage.#define SP510_INC_CALC_VARIABLES 1/*** @anchor sensor_sp510_timing* @name Sensor Timing* The sensor timing for an Apogee SP-510*//**@{*//*** @brief Sensor::_warmUpTime_ms; the warm up time is unknown; using the 2ms for* the TI ADS1x15 to warm up** @todo Measure warm-up time of the SQ-212*/#define SP510_WARM_UP_TIME_MS 2/*** @brief Sensor::_stabilizationTime_ms; the ADS1115 is stable after 2ms.** The stabilization time of the SQ-212 itself is not known!** @todo Measure stabilization time of the SQ-212*/#define SP510_STABILIZATION_TIME_MS 2/// @brief Sensor::_measurementTime_ms; ADS1115 takes almost 2ms to complete a/// measurement (860/sec).#define SP510_MEASUREMENT_TIME_MS 2/**@}*//*** @anchor sensor_sp510_iswr* @name ISWR* The ISWR variable from an Apogee SP-510* - Range is 0 to 2000 W m-2* - Accuracy is ± 0.5%* - Resolution:* - 16-bit ADC (ADS1115): 0.3125 µmol m-2 s-1 (ADS1115)* - 12-bit ADC (ADS1015, using build flag <code></code><code>MS_USE_ADS1015</code><code></code>): 5 µmol m-2* s-1 (ADS1015)* - Reported as microeinsteins per square meter per second (µE m-2 s-1 or µmol* m-2 s-1)** {{ @ref ApogeeSP510_ISWR }}*//**@{*//// Variable number; ISWR is stored in sensorValues[0].#define SP510_ISWR_VAR_NUM 0/// @brief Variable name in [ODM2 controlled/// vocabulary](http://vocabulary.odm2.org/variablename/);/// "radiationIncomingPAR"#define SP510_ISWR_VAR_NAME "radiationIncomingShortwave"/// @brief Variable unit name in/// [ODM2 controlled vocabulary](http://vocabulary.odm2.org/units/);/// "wattsPerMeterSquared" (W m-2)#define SP510_ISWR_UNIT_NAME "wattsPerMeterSquared"/// @brief Default variable short code; "incomingShortwaveRadiation"#define SP510_ISWR_DEFAULT_CODE "incomingShortwaveRadiation"#ifdef MS_USE_ADS1015/// @brief Decimals places in string representation; PAR should have 0 when/// using an ADS1015.#define SP510_PAR_RESOLUTION 0#else/// @brief Decimals places in string representation; PAR should have 4 when/// using an ADS1115.#define SP510_ISWR_RESOLUTION 4#endif/**@}*//*** @anchor sensor_sp510_voltage* @name Voltage* The voltage variable from an Apogee SQ-212* - Range is 0 to 3.6V [when ADC is powered at 3.3V]* - Accuracy is ± 0.5%* - 16-bit ADC (ADS1115): < 0.25% (gain error), <0.25 LSB (offset error)* - 12-bit ADC (ADS1015, using build flag <code></code><code>MS_USE_ADS1015</code><code></code>): < 0.15%* (gain error), <3 LSB (offset error)* - Resolution [assuming the ADC is powered at 3.3V with inbuilt gain set to 1* (0-4.096V)]:* - 16-bit ADC (ADS1115): 0.125 mV (ADS1115)* - 12-bit ADC (ADS1015, using build flag <code></code><code>MS_USE_ADS1015</code><code></code>): 2 mV* (ADS1015)** {{ @ref ApogeeSP510_Voltage }}*//**@{*//// Variable number; voltage is stored in sensorValues[1].#define SP510_VOLTAGE_VAR_NUM 1/// @brief Variable name in [ODM2 controlled/// vocabulary](http://vocabulary.odm2.org/variablename/); "voltage"#define SP510_VOLTAGE_VAR_NAME "voltage"/// @brief Variable unit name in/// [ODM2 controlled vocabulary](http://vocabulary.odm2.org/units/); "volt" (V)#define SP510_VOLTAGE_UNIT_NAME "volt"/// @brief Default variable short code; "SP510Voltage"#define SP510_VOLTAGE_DEFAULT_CODE "SP510Voltage"#ifdef MS_USE_ADS1015/// @brief Decimals places in string representation; voltage should have 1 when/// used with an ADS1015.#define SP510_VOLTAGE_RESOLUTION 1#else/// @brief Decimals places in string representation; voltage should have 4 when/// used with an ADS1115.#define SP510_VOLTAGE_RESOLUTION 4#endif/**@}*//*** @brief The calibration factor between output in volts and PAR* (microeinsteinPerSquareMeterPerSecond) 1 µmol mˉ² sˉ¹ per mV (reciprocal of* sensitivity)*/#ifndef SP510_CALIBRATION_FACTOR#define SP510_CALIBRATION_FACTOR 26.03#endif/// The assumed address of the ADS1115, 1001 000 (ADDR = GND)#define ADS1115_ADDRESS 0x48/*** @brief The Sensor sub-class for the [Apogee SP-510](@ref sensor_sp510) sensor** @ingroup sensor_sp510*/class ApogeeSP510 : public Sensor {public:/*** @brief Construct a new Apogee SQ-212 object - need the power pin and the* data channel on the ADS1x15.** @note ModularSensors only supports connecting the ADS1x15 to the primary* hardware I2C instance defined in the Arduino core. Connecting the ADS to* a secondary hardware or software I2C instance is *not* supported!** @param powerPin The pin on the mcu controlling power to the Apogee* SQ-212. Use -1 if it is continuously powered.* - The SQ-212 requires 3.3 to 24 V DC; current draw 10 µA* - The ADS1115 requires 2.0-5.5V but is assumed to be powered at 3.3V* @param i2cAddress The I2C address of the ADS 1x15, default is 0x48 (ADDR* = GND)* @param measurementsToAverage The number of measurements to take and* average before giving a "final" result from the sensor; optional with a* default value of 1.* @note The ADS is expected to be either continuously powered or have* its power controlled by the same pin as the SQ-212. This library does* not support any other configuration.*/ApogeeSP510(int8_t powerPin,uint8_t i2cAddress = ADS1115_ADDRESS,uint8_t measurementsToAverage = 1);/*** @brief Destroy the ApogeeSP510 object - no action needed*/~ApogeeSP510();/*** @brief Report the I1C address of the ADS and the channel that the SQ-212* is attached to.** @return **String** Text describing how the sensor is attached to the mcu.*/String getSensorLocation(void) override;/*** @copydoc Sensor::addSingleMeasurementResult()*/bool addSingleMeasurementResult(void) override;private:uint8_t _i2cAddress;};/* clang-format off *//*** @brief The Variable sub-class used for the* [incoming shortwave radiation (ISWR) output](@ref sensor_sp510_iswr)* from an [Apogee SQ-212](@ref sensor_sp510).** @ingroup sensor_sp510*//* clang-format on */class ApogeeSP510_ISWR : public Variable {public:/*** @brief Construct a new ApogeeSP510_ISWR object.** @param parentSense The parent ApogeeSP510 providing the result* values.* @param uuid A universally unique identifier (UUID or GUID) for the* variable; optional with the default value of an empty string.* @param varCode A short code to help identify the variable in files;* optional with a default value of "radiationIncomingPAR".*/explicit ApogeeSP510_ISWR(ApogeeSP510* parentSense, const char* uuid = "",const char* varCode = SP510_ISWR_DEFAULT_CODE): Variable(parentSense, (const uint8_t)SP510_ISWR_VAR_NUM,(uint8_t)SP510_ISWR_RESOLUTION, SP510_ISWR_VAR_NAME,SP510_ISWR_UNIT_NAME, varCode, uuid) {}/*** @brief Construct a new ApogeeSP510_ISWR object.** @note This must be tied with a parent ApogeeSP510 before it can be used.*/ApogeeSP510_ISWR(): Variable((const uint8_t)SP510_ISWR_VAR_NUM,(uint8_t)SP510_ISWR_RESOLUTION, SP510_ISWR_VAR_NAME,SP510_ISWR_UNIT_NAME, SP510_ISWR_DEFAULT_CODE) {}/*** @brief Destroy the ApogeeSP510_ISWR object - no action needed.*/~ApogeeSP510_ISWR() {}};/* clang-format off *//*** @brief The Variable sub-class used for the* [raw voltage output](@ref sensor_sp510_voltage) from an* [Apogee SQ-212](@ref sensor_sp510).** @ingroup sensor_sp510*//* clang-format on */class ApogeeSP510_Voltage : public Variable {public:/*** @brief Construct a new ApogeeSP510_Voltage object.** @param parentSense The parent ApogeeSP510 providing the result* values.* @param uuid A universally unique identifier (UUID or GUID) for the* variable; optional with the default value of an empty string.* @param varCode A short code to help identify the variable in files;* optional with a default value of "SP510Voltage".*/explicit ApogeeSP510_Voltage(ApogeeSP510* parentSense, const char* uuid = "",const char* varCode = SP510_VOLTAGE_DEFAULT_CODE): Variable(parentSense, (const uint8_t)SP510_VOLTAGE_VAR_NUM,(uint8_t)SP510_VOLTAGE_RESOLUTION, SP510_VOLTAGE_VAR_NAME,SP510_VOLTAGE_UNIT_NAME, varCode, uuid) {}/*** @brief Construct a new ApogeeSP510_Voltage object.** @note This must be tied with a parent ApogeeSP510 before it can be used.*/ApogeeSP510_Voltage(): Variable((const uint8_t)SP510_VOLTAGE_VAR_NUM,(uint8_t)SP510_VOLTAGE_RESOLUTION, SP510_VOLTAGE_VAR_NAME,SP510_VOLTAGE_UNIT_NAME, SP510_VOLTAGE_DEFAULT_CODE) {}/*** @brief Destroy the ApogeeSP510_Voltage object - no action needed.*/~ApogeeSP510_Voltage() {}};/**@}*/#endif // SRC_SENSORS_APOGEESP510_H_C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112/*** @file ApogeeSP510.cpp* @copyright 2017-2022 Stroud Water Research Center* Part of the EnviroDIY ModularSensors library for Arduino* @author Written By: Anthony Aufdenkampe <aaufdenkampe@limno.com>* Edited by Sara Geleskie Damiano <sdamiano@stroudcenter.org>* Adapted from CampbellOBS3.cpp by Sara Geleskie Damiano* <sdamiano@stroudcenter.org>** @brief Implements the ApogeeSP510 class.*/#include "ApogeeSP510.h"#include <Adafruit_ADS1015.h>// The constructor - need the power pinApogeeSP510::ApogeeSP510(int8_t powerPin,uint8_t i2cAddress, uint8_t measurementsToAverage): Sensor("ApogeeSP510", SP510_NUM_VARIABLES, SP510_WARM_UP_TIME_MS,SP510_STABILIZATION_TIME_MS, SP510_MEASUREMENT_TIME_MS, powerPin,-1, measurementsToAverage, SP510_INC_CALC_VARIABLES),_i2cAddress(i2cAddress) {}// DestructorApogeeSP510::~ApogeeSP510() {}String ApogeeSP510::getSensorLocation(void) {#ifndef MS_USE_ADS1015String sensorLocation = F("ADS1115_0x");#elseString sensorLocation = F("ADS1015_0x");#endifsensorLocation += String(_i2cAddress, HEX);sensorLocation += F("_Channels_2_3");return sensorLocation;}bool ApogeeSP510::addSingleMeasurementResult(void) {// Variables to store the results infloat adcVoltage = -9999;float calibResult = -9999;// Check a measurement was *successfully* started (status bit 6 set)// Only go on to get a result if it wasif (bitRead(_sensorStatus, 6)) {MS_DBG(getSensorNameAndLocation(), F("is reporting:"));// Create an Auxillary ADD object// We create and set up the ADC object here so that each sensor using// the ADC may set the gain appropriately without effecting others.#ifndef MS_USE_ADS1015Adafruit_ADS1115 ads(_i2cAddress); // Use this for the 16-bit version#elseAdafruit_ADS1015 ads(_i2cAddress); // Use this for the 12-bit version#endif// ADS Library default settings:// - TI1115 (16 bit)// - single-shot mode (powers down between conversions)// - 128 samples per second (8ms conversion time)// - 2/3 gain +/- 6.144V range (limited to VDD +0.3V max)// - TI1015 (12 bit)// - single-shot mode (powers down between conversions)// - 1600 samples per second (625µs conversion time)// - 2/3 gain +/- 6.144V range (limited to VDD +0.3V max)// Bump the gain up to 1x = +/- 4.096V range// Sensor return range is 0-2.5V, but the next gain option is 2x which// only allows up to 2.048Vads.setGain(GAIN_ONE);// Begin ADCads.begin();// Read Analog to Digital Converter (ADC)// Taking this reading includes the 8ms conversion delay.// We're allowing the ADS1115 library to do the bit-to-volts conversion// for usadcVoltage =ads.readADC_Differential_2_3_V(); // Getting the readingMS_DBG(F(" ads.readADC_Differential_2_3_V():"),adcVoltage);if (adcVoltage < 3.6 && adcVoltage > -0.3) {// Skip results out of range// Apogee SQ-212 Calibration Factor = 1.0 μmol m-2 s-1 per mVcalibResult = 1000 * adcVoltage * SP510_CALIBRATION_FACTOR;MS_DBG(F(" calibResult:"), calibResult);} else {// set invalid voltages back to -9999adcVoltage = -9999;}} else {MS_DBG(getSensorNameAndLocation(), F("is not currently measuring!"));}verifyAndAddMeasurementResult(SP510_ISWR_VAR_NUM, calibResult);verifyAndAddMeasurementResult(SP510_VOLTAGE_VAR_NUM, adcVoltage);// Unset the time stamp for the beginning of this measurement_millisMeasurementRequested = 0;// Unset the status bits for a measurement request (bits 5 & 6)_sensorStatus &= 0b10011111;if (adcVoltage < 3.6 && adcVoltage > -0.3) {return true;} else {return false;}} -
2024-02-15 at 2:06 PM #18320
@srgdamiano do you by chance see where I am going wrong?</p>
-
2024-03-25 at 12:53 PM #18392
@shicks this is something I am still struggling with, and I am having hard time figuring out. I’ve added some pictures with some of the data I’ve been collecting. It seems that the logger is picking up that there is some diurnal cycle happening, but the values seem to not match what I would expect, or they can be wildly all over the place. If I could get some help with this that would be great.
Attachments:
-
-
AuthorPosts
- You must be logged in to reply to this topic.