Very small noise when measuring small current with ADS1115

I am now trying to use the ADS1115 at low currents (≈10μA) for my personal interest.
The mechanism is very simple: a 5V power supply (supplied by the Arduino) is passed through 400kΩ. This resistor is the highest in the circuit, so the current will be about 12μA according to Ohm's law.

This small current is passed through 1kΩ. Measure the voltage across 1kΩ with the single-ended A0 of the ADS1115.
The results are attached. The measured voltage has noise or ripple-like waveform, which irritates me.
The horizontal axis of the graph is the number of measurement attempts (100 measurements in the loop) and the vertical axis is the calculated voltage in mV. The blue line in the graph is the result of measurement at 2/3x gain, and the orange line is the result of measurement at 16x gain.
This noise is very small, but I would like to solve it.
If you have any good advice, I would appreciate it.

//#define CFACTOR 0.18750 // GAIN_TWOTHIRDS
#define CFACTOR 0.00781 // GAIN_SIXTEEN
int t = 0;
float V0 = 0;
float ads0 = 0;


void setup() {     
        
 Serial.begin(9600); 
 //ads.setGain(GAIN_TWOTHIRDS);
 ads.setGain(GAIN_SIXTEEN);
 ads.begin();
 
}
    
void loop(){

    if(t<=99){

    ads0 = float(ads.readADC_SingleEnded(0)); 
    V0 = ads0*CFACTOR;
    Serial.print(V0,5);
    t=t+1;

    }else{
 
    delay(5000);

I use a GitHub - denyssene/SimpleKalmanFilter: A basic implementation of Kalman Filter for single variable models..

an example of my use of the filter.

void fReadBattery( void * parameter )
{
  float adcValue = 0.0f;
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  float Vbatt = 0.0f;
  int printCount = 0;
  float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 1000; //delay for mS
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}

@Idahowalker
I really liked your solution. I was also thinking of using RC filters, but I will consider other models.

By the way, as an analog solution, I had installed a bypass capacitor right after 400kΩ to reduce the noise. However, there were some problems with this method.
One of the problems is that if you change the resistor you are measuring (1kΩ in the first image I posted) to a larger resistor (say 10kΩ), the noise becomes larger again. My understanding is not good enough, but I believe that the noise is caused either by the impedance value or the small current value.
With this in mind, is there any way to reduce the noise using analog methods?

Hi
Try using a Pi filter as shown below.
FiltroPI

RV - mineirin

@ruilviana Here are the results obtained, with ADS1115 set to 16x gain, 560pF film capacitors. Blue is with the filter, orange is without the filter. Just by looking, there does not seem to be much difference...

We need more information, because many parts of the circuit could introduce noise.
Exactly which Arduino are you using?
What else is the ADS connected to?

The serial output seems to be going to a PC or similar. Presumably along the same USB wire as the "5V" supply; and every reading has a serial print at 9600 bd?

The divider gives a voltage of 5000 times 1 / 401 mV = 12.5mV
so why is your display showing 22?

What do you get if you connect A0 to ground?

Can you provide a schematic (or block diagram) of the whole setup; and a photo?

Aslo your code is incomplete.

@johnerrington
I'm using an Arduino UNO.
The circuit is built on a breadboard, but the ADS is only connected to the Arduino.
The power supply to the Arduino and the serial output are both via USB.
Incidentally, when the power is supplied from Vin to the Arduino with a 9V battery, the noise is also present.
The serial print setting is set to 9600 bd both in the code and on the PC serial monitor.

You are talking about the first image I posted, right? This is my mistake, I used 2kΩ instead of 1kΩ for the voltage divider resistor, and the second result I posted uses 1kΩ.

I am attaching the results of my trial. Your point is very interesting and the result is noisy.

I'm attaching a picture of the circuit and all of the code.

I would appreciate it if you could help me with a solution.
Sincerely yours,


#include <Wire.h>
#include <Adafruit_ADS1X15.h>
//#define CFACTOR 0.18750 // GAIN_TWOTHIRDS 
//#define CFACTOR 0.12500 // GAIN_ONE: 
//#define CFACTOR 0.03125 // GAIN_FOUR: 
//#define CFACTOR 0.01563 // GAIN_EIGHT: 
#define CFACTOR 0.00781 // GAIN_SIXTEEN: 


int t=0; 
float V0=0;  
float ads0 = 0;

Adafruit_ADS1115 ads ;

void setup() { 
 
 Serial.begin(9600); 
 //ads.setGain(GAIN_TWOTHIRDS);
 //ads.setGain(GAIN_ONE);
 //ads.setGain(GAIN_FOUR);
 //ads.setGain(GAIN_EIGHT);
 ads.setGain(GAIN_SIXTEEN);
 ads.begin();
 
}
    
void loop(){
    
    if(t<=99){

    ads0 = float(ads.readADC_SingleEnded(0)); 
    V0 = ads0*CFACTOR;
    Serial.println(V0,5);
    t=t+1;

    }else{
    delay(5000);
    }
}

Why not add in some filtering like a moving average filter to smooth the data?

@Idahowalker
Indeed, digital filters, such as the one you introduced earlier, are a powerful option. Eventually, I may focus on choosing a better model.

Apart from that, I would be happy to discuss why noise is generated and how to handle it analogically, out of personal interest to better understand the behavior of Arduino and ADS1115.

Hi,
Can you try this;
The current you are trying to measure is sharing the same path as the 1115 module. also through a protoboard connection.


Also making your potential divider soldered to a board may also help with noise.

Tom... :smiley: :+1: :coffee: :australia:

As

Although I disgree with his suggestion.

You need to keep the analog and digital grounds seperate until you have a common "star point" which should be at the ADC ground.

You should have decoupling caps across the VDD & GND of the adc.

adc

Also try changing the serial data rate.

Its not a suggestion.
This is;


Trying to make a star connection with the available parts.

Tom.. :smiley: :+1: :coffee: :australia:

@TomGeorge @johnerrington
Thanks for the replies, both of you!
I'll try to experiment tomorrow because of the time difference.
I'm a complete noob when it comes to "Star point". If you could give me a more detailed explanation (or share a link), that would be great.

When dealing with a mix of analog and digital circuits, noise is introduced from digital to analog through the ground, right?
If the noise gets on, the analog signal becomes a wrong signal and not a correct signal.
I would appreciate it if you could tell me how and why the grounding is appropriate when using an Arduino.

In fact, I once did a test by connecting decoupling caps (10μF) just after R1 (i.e., just behind 400kΩ). This reduced the noise at A0.

This is of course an Adafruit or Sparkfun board you have.
Not one from ebay or Amazon, with most likely a rejected or fake chip.

The ADS1115 is an absolute (voltage A/D.
I see you want to measure low currents.
Shouldn't you look at something like the uCurrent Gold from EEVblog.
Leo..

I think what the OP really wants is to understand where the noise is coming from.

Hi,
As this not for a project, but personal interest and experimentation.

Even DMMs call it quits at mA, unless a DMM that usually is quite expensive.
As you have found you are battling noise.

If you look at EEVblog, you will see that he uses an instrumentation amplifier before you decide on ADC.
Instrumentation amps are designed for low noise, low drift, low signal applications.

I would encourage you to do some research on diff amps.

Here is an example;
https://wiki.seeedstudio.com/Grove-Differential_Amplifier_v1.2/

This is an interesting YouTube, from the "Guy with the Swiss Accent"

Also the HX117 module is basically a diff amp setup for Wheatstone bridge applications.

Tom... :smiley: :+1: :coffee: :australia:
PS. Keep experimenting, great way to learn :+1:
PPS. Have you looked at using the ADS1115 in differential mode to lower your common mode noise?

@Wawa
I bought the one made by Adafruit. #26 and after, the results of using it. The noise problem arises in the same way.

@SteveThackery @TomGeorge
You are right. The use of commercial products and amplifiers is very interesting (Tom, thanks for sharing the video! I'll check it out!) ), but what I'm interested in is,

so I'd appreciate it if you could stick with my trial and error a bit longer.

In addition to the results with the ”correct way” to connect the GND, I will also post the verification in the differential mode later. I'd appreciate it if you could take a look.

@TomGeorge @johnerrington
The measurement results are attached.
First is the wiring considering Analog GND and Digital GND.
The blue color is the "star connection" and the orange color is the same wiring as before.
Unfortunately, I don't think there is a noticeable difference. Incidentally, there was no significant difference when a capacitor was placed between VDD and GND of ADS.

Next is the result using the differential mode (A0-A1), compared with the difference between A0 and A1 in the single-end mode. The blue color is the single-end mode and the orange color is the differential mode. The blue color is single-end mode and the orange color is the differential mode.

By the way, I read a blog that showed an example of installing an OP-Amp voltage follower.

A BLOG

I tried it with the LM358N that I had at hand, but it didn't reduce the noise.

Regards,

Hi,
The vertical scale is uV?

You might need to Google

Resistor Noise

Resistors are noisy when current is passed through them.

Tom... :smiley: :+1: :coffee: :australia:

The vertical axis is mV.
What you are thinking of is the thermal noise, right?