Using second ADC_1 to cancel noise in ADC_0 measurements

Status
Not open for further replies.

pictographer

Well-known member
I'm recording the level of light in one of my skylights using a Teensy 3.1 and a phototransistor with the aim of making a system to alert me if my photovoltaic power generation system declines in performance.

The readings are somewhat noisy and don't span the full range of the ADC. I was wondering if it would be possible to reduce the noise by using ADC_1 connected to nothing to cancel the noise generated within the Teensy itself from the readings of ADC_0 connected to the phototransistor.

The current noise level is probably "good enough" for what I'm trying to accomplish since the sunlight changes slowly so I can massively oversampling and applying a median filter, but I'm curious if the noise canceling idea makes any sense. I'd also like to get a more practical understanding of how to prioritize various approaches to reducing sensor noise.

The wires from the phototransistor to the Teensy are about a couple of meters long from an old two-wire phone cable. Not shielded. I don't know the gauge.

How would you prioritize the following ways of understanding/reducing noise?
  • Calculate the Fourier transform of the noise to see if there are obvious periodic elements like "mains' hum" and understand how aggressive a low-pass filter to use.
  • Add a small capacitor 0.1uF or 0.01uF between the ADC input and ground.
  • Add a simple low-pass filter made from a resistor and capacitor.
  • Try a shorter cable.
  • Try a shielded cable.
  • Try a cable with twisted pairs of wires.
  • Try different parameters for the ADC library.
  • Use a median filter in software.
  • Boost the signal to the ADC by wiring the phototransistor to the base of another transistor.
  • Try to find the datasheet for the phototransistor.
  • Try using ADC_1 to cancel noise in ADC_0 readings.
  • Try running the project from a battery rather than the USB port of a pocket router.
  • Other ideas?

Code:
// Photodiode from 19 to 18.

#include "ADC.h"


ADC *adc = new ADC(); // adc object


void setup() {
  Serial.begin(9600);
  pinMode(18, INPUT);
  // Pull down pin 18.
  //*portConfigRegister(18) = PORT_PCR_MUX(1) | PORT_PCR_PE;
  *portConfigRegister(18) |= PORT_PCR_PE; //pull enable
  *portConfigRegister(18) &= ~PORT_PCR_PS; //pull down
  pinMode(19, OUTPUT);
  digitalWriteFast(19, 1);


  analogReference(INTERNAL); // Untested.
  adc->setAveraging(1); // set number of averages
  adc->setResolution(16); // set bits of resolution


  adc->setConversionSpeed(ADC_VERY_LOW_SPEED );
  adc->setSamplingSpeed(ADC_VERY_LOW_SPEED);
  // with 16 averages, 12 bits resolution and ADC_HIGH_SPEED conversion and sampling
  // it takes about 32.5 us for a conversion


//  adc->enablePGA(64, ADC_0);
}


const long avg = 1; // 2048
const char* dstr = "****************************************************************";
unsigned long i = 0;
void loop() {
  Serial.print(i++);
  Serial.print('\t');
  long lux = adc->analogRead(18, ADC_0);
  for (long k = 0; k < avg - 1; ++k) {
    lux += adc->analogRead(18, ADC_0);
  }
  lux /= avg;
  Serial.print(lux);
  long dots = log(4 * lux);
  Serial.print('\t');
  Serial.print(analogRead(26));
  Serial.print('\t');
  Serial.println(dstr + (64 - dots));
  delay(10);
}

// Values range from 1 to about 250.
// Under 25, the values look like noise compared to the Enphase PV data.
// Clearly, depending on the phase of the samples, we see different peaks.
// The Enphase PV data has 12 samples per hour or one sample every five minutes.
// A median filter on a five minute window results in significantly smoother graphs than Enphase.
 
What does it look like with the Teensy with short wires to a like phototransistor? You'll not get the same light for 1:1 compare - but a sunny window monitored through the day giving more stable results would say there is something to correct. You could start with similar USB power or try the battery and find a way to get a baseline. Put it under a lamp of decent intensity where the light is controlled. Put similar long wires on that the next day. What does a second phototransistor read if in a black out bag (0?) on second ADC if wired the same to the same spot - or the power on LED of the router? A powered USB hub?
 
I'm recording the level of light in one of my skylights using a Teensy 3.1 and a phototransistor with the aim of making a system to alert me if my photovoltaic power generation system declines in performance.

The readings are somewhat noisy and don't span the full range of the ADC. I was wondering if it would be possible to reduce the noise by using ADC_1 connected to nothing to cancel the noise generated within the Teensy itself from the readings of ADC_0 connected to the phototransistor.

I do not quite understand what you mean by "reduce the noise".
- If you mean subtract noise sample by sample from ADC_0, this is clearly not possible. The noise of different ADC's is most uncorrelated noise.
- If you mean to use the ADC_1 as a reference for electronic noise that may be possible.

What yo can easily do is to put the phototransistor to both ADCs and simply average the two values then the noise s reduces by 3 dB (noise power reduced by factor 2)
If this is not sufficient, then you only can time average (10 samples average give you 10 dB noise suppression, or noise power reduced by factor of 10)

More important is to recognize that the Teensy ADC NEEDS a filter that limits the analog input bandwidth. Even if the signal fulfills NYQUIST, analog noise does usually not. That is, why there is typically some RC at the ADC input.
 
Please don't mix ADC library code with the core's adc functions! There's no guarantee that the settings that you want are actually being used! Moreover you're using analogRead and adc->analogRead. Use one library or the other, but don't mix!
The ADC library has a function to change the reference to internal (1.2 V, only in Teensy 3.x). If you want less noise this is something you should definitely use if you can get your signal down to that range.
You can also try to use the asynchronous clock with adc->setConversionSpeed(ADC_ADACK_2_4). With the default options the ADC clock runs at 3 MHz with the lowest speed that you selected, that ADACK setting lowers it even more to 2.4 MHz.
Use a differential pair instead of a normal single-ended one. That's basically what you were trying to accomplish with the other ADC. Use adc->analogReadDifferential(pin1, pin2). Probably you want the pins connected to the photovoltaic element, this should cancel the noise due to the long cables and other random noise.
Finally, oversampling will indeed help.
 
Oversampling is so effective (for your slow application) that I wouldn't spend time on any other options. Use median if the noise is non-Gaussian, otherwise a simple mean.
 
Thanks, everyone! You've given me quite a few threads to pull on. Some of it I understand. Some will require some study. Will be traveling for a bit.
 
Status
Not open for further replies.
Back
Top