cancel
Showing results for 
Search instead for 
Did you mean: 

ADC noise on stm32f401

andrewg
Associate III

I've been messing around with a LMT86 temperature sensor

This sensor is deemed high output impedance as the documented loads it drives is 50uA.

ADC noise on STM32 isn't 'new'. Just that for a first time I'm observing such volatility up close. The problem is mere millivolts differences means a different temperature reading from the sensor, and accordingly there is already a sort of 'amplification' from the sensor itself.

Threads found from a Google search are like such.

https://embdev.net/topic/stm32f0-adc-input-noise-investigations

https://itectec.com/electrical/electronic-stm32-adc-noise-2/

https://www.eevblog.com/forum/microcontrollers/stm32-adc-noise/

https://stackoverflow.com/questions/55499111/pid-temperature-control-python-eliminating-noise-values-stm32

It is explored in a thread discussing the temperature sensor here:

https://forum.allaboutcircuits.com/threads/lmt86-2-2v-temperature-sensor.181850/

Among the discussions is that given this is a high impedance source, an Op-Amp is needed to buffer inputs to the ADC.

So next I strapped up an LMV358 Op-Amp as a buffer and here are the observations. This is with the Op-Amp

common parameters for charts below: adc clock 84 mhz / 4 ~ 21 mhz, 84 clocks sample time

2000 samples, 10 samples/s, measuring room temperature about 30.5-31 deg C

0693W00000Dnmj4QAB.pngcount   2000.000000

mean      30.882000

std        6.782125

min     -213.360000

median  30.960000

max       57.800000

No, temperature did not accidentally drop to near absolute zero. It is room temperature all the while during measurement, a multimeter did not change a single millivolt while variances are recorded by the ADC.

Next, I set up a filter to remove all values outside +/- 2 deg C from the median, 555 outlier values removed.

0693W00000DnmjsQAB.pngcount   1445.000000

mean      30.973156

std        0.733296

min       29.030000

median  30.890000

max       32.950000

Next remove that Op Amp and connect the sensor LMT86 directly to the ADC (on stm32f401)

2000 samples, 10 samples/s, measuring room temperature about 30.5-31 deg C

0693W00000DnmlPQAR.pngcount   2000.000000

mean      30.930100

std        4.062343

min        3.670000

median 30.810000

max       59.260000

Next, I set up a filter to remove all values outside +/- 2 deg C from the median, 500 outlier values removed.

 0693W00000DnmmwQAB.pngcount   1500.000000

mean      30.817787

std        0.698166

min       28.810000

median  30.810000

max       32.800000

It is a dilemma kind of. The Op-Amp probably reduce the impedance (significantly?), but that the errors/variance are about the same !

What is more concerning is the large outlier values as those are observed in the unfiltered input. This didn't seem to go away when the OpAmp is placed as a buffer between the sensor to stm32f401.

1 ACCEPTED SOLUTION

Accepted Solutions
andrewg
Associate III

Here is an update, I patched a LMT86 directly on the breadboard - no long wires / no cords / no op amps etc.

2000 samples, LMT86 direct to STM32F401 ADC PA0

0693W00000FA8l0QAD.png 

LMT86 direct to STM32F401 ADC PA0 discarding 122 values outside 0.5 deg C range from median, this is barely around 5% of 2000 samples.

0693W00000FA8jbQAD.pngcount   1878.000000

mean      31.195000

std        0.162021

min       30.740000

25%       31.110000

median   31.180000

75%       31.330000

max       31.620000

This result is astonishing, standard deviation is 0.162 deg C. 95% confidence interval is 1.959 sigma ~ 0.31736.

Now LMT86 measured on stm32f401 ADC pa0 is +/- 0.31736 deg C accurate at 95% confidence interval.

Then taking the full 0.5 deg C interval, that is 3.08 sigma, that is > 99.8% (accurate) confidence interval

https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function

LMT86 is an accurate device, and it meets the specs published by TI, when a near noiseless measurement on stm32f401 ADC is possible.

The histogram is showing bars for temperatures well within 0.1 of a degree C. And I'm using only 12 bins for 2000 samples.

Working this back to the specs for LMT86, it is -10.9 mV average gain per deg C.

This translates to a +/-3.46 mV accuracy measured on STM32F401 ADC at 95% confidence interval.

And at 0.5 deg C at 3.08 sigma (> 99.8% confidence interval) it is +/- 5.45 mV at pretty much > 99.8% confidence interval measured on stm32f401 ADC.

Measurements are still stochastic, as I can observe varying numbers with each sample. But the samples and mean conforms well to a bell curve (normal distribution), after dropping the *outliers*.

Still can't rule out radio interference etc as noise sources which probably cause the variations and especially the outliers.

The data analysis looks like such

each line of these is the Anderson–Darling statistics

https://en.wikipedia.org/wiki/Anderson%E2%80%93Darling_test

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.anderson.html

This analysis is done by rejecting values outside a tolerance starting with 2 deg C and reducing it.

The Anderson–Darling statistic reduces to the smallest and finally increase, showing a poorer fit as tolerance is narrowed.

Now the tightest fit to normal distribution is 0.5 deg C at 99.8% confidence interval

n = 2000, lmt86 direct - no cord
no filter
145.97371710597236 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
 
tol = 2 del 13
95.23121766618078 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
 
tol = 1.5 del 29
59.96725246650158 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
 
tol = 1 del 56
33.59035490934821 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
 
tol = 0.5 del 122
20.692436455313555 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]
count   1878.000000
mean      31.195000
std        0.162021
min       30.740000
25%       31.110000
median   31.180000
75%       31.330000
max       31.620000
 
tol = 0.3 del 197
22.802556095985665 [0.575 0.655 0.785 0.916 1.09 ] [15. 10.  5.  2.5 1. ]

This kind of also confirms the 'radio waves' interference hypothesis, that those outliers, and variances are due to interferences from radio waves.

But that'd need 1 more set of 'scope' charts, to verify it.

View solution in original post

16 REPLIES 16
TDK
Guru

Temperature changes very slowly. Implementing a low pass filter either in hardware or digitally will help.

> a multimeter did not change a single millivolt while variances are recorded by the ADC.

While true, this isn't an apples to apples comparison. A multimeter will provide a time-averaged voltage reading. The ADC is providing a near-instantaneous reading.

Measure a high frequency square wave and you'll see the multimeter will happily report a constant voltage value at mid-scale.

Chips which report temperature digitally (such as over I2C) are typically much more accurate as they control all aspects of the measurement and can do the closed loop calibration.

If you feel a post has answered your question, please click "Accept as Solution".
andrewg
Associate III

Thanks, Those extreme outlier values are a concern, as one single very large swing outlier can throw the averages out significantly as well. I'm kind of thinking of doing a 20 samples moving median filter and removing samples outside +/- 2 deg C range from the median.

A feeling is that it would work. There are various implications, as this is simply used to calibrate a thermistor. Subsequently, this sensor gets replaced by a 100k thermistor on a 3d printer hot end. The impedance from that 100k thermistor resistor divider could be just as bad or worse than that LMT86 sensor.

Here are the same charts in millivolts (that is derived from ADC value * 3.3 / 4096)

this is for LMT86 temperature sensor - LMV358 Op Amp - STM32F401 ADC pa0

0693W00000Dnnl6QAB.pngcount   2000.000000

mean    1765.447655

std       45.694276

min     1466.310000

median 1765.210000

max     2223.630000

removing 561 outliers outside 0.5 std from previous 0693W00000Dnnp9QAB.pngcount  1439.000000

mean    1765.045448

std        8.352023

min     1742.650000

median 1765.210000

max     1787.770000

This is for LMT86 temperature sensor - STM32F401 ADC pa0 direct

0693W00000DnntKQAR.pngcount   2000.000000

mean    1766.020125

std       44.989596

min     1449.390000

median 1766.820000

max     2061.690000

removing 519 outliers outside 0.5 std from prior 0693W00000DnnvGQAR.pngcount  1481.000000

mean    1766.806712

std        7.830439

min     1745.070000

median 1766.820000

max     1788.570000

So it seemed the range of the outliers can be pretty large, they seem to be about 0.7-1V. That accounts for the extreme temperature readings.

As LMT86 has a spec of -10.9 mV / C, that kind of translate to a 64 deg C range for the volatility as seen in the ADC readings.

The unfiltered graphs are also noticeably not a normal distribution.

I'd try some other things, place large caps at power supply, run off batteries etc to see if those makes a difference.

andrewg
Associate III

Some findings, adding a 220 uF capacitor at the 5v supply before the LDO (it is the usb from PC actually)

0693W00000DnqBLQAZ.pngcount 2000.000000

mean 30.809150

std 2.734337

min 5.710000

median 30.600000

max 54.450000

Next, I set up a filter to remove all values outside +/- 2 deg C from the median, 147 outlier values removed.

This is significantly less than previous

0693W00000DnqDRQAZ.pngcount 1853.000000

mean 30.639255

std 0.589653

min 28.660000

median 30.600000

max 32.580000

220 uF is a little extreme, but it did reduce the count of outliers outside +/- 2 deg C significantly

Unfortunately, the range of that outliers did not reduce significantly. It seemed there is a possibility the ADC is picking up signals from sources other than the sensor alone. Though at the pin, only the sensor is connected (across a wire to the probe).

andrewg
Associate III

This is a data analysis post. I used the Anderson–Darling test to test for fit to normal distribution. After removing the outliers

https://en.wikipedia.org/wiki/Anderson%E2%80%93Darling_test

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.anderson.html

n = 2000, 220uf
no fil
338.0688373916323 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 5 del 80
37.65825596079503 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 3 del 106
16.639158835365834 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 2 del 147
6.330279064999559 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 1.5 del 184
5.565211685938493 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
count    1816.000000
mean       30.629251
std         0.540934
min        29.100000
median     30.600000
max        32.070000
 
tol = 1 del 311
9.129102640304609 [0.575 0.654 0.785 0.916 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 0.5 del 908
12.947477639850604 [0.574 0.654 0.784 0.915 1.088] [15.  10.   5.   2.5  1. ]
 
----
n = 2000, lmv358 op amp
no fil
286.11314396470016 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 5 del 246
49.1890842386847 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 3 del 404
21.53082374676842 [0.575 0.654 0.785 0.916 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 2 del 555
6.184812017836293 [0.574 0.654 0.785 0.915 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 1.5 del 643
2.5784588330257066 [0.574 0.654 0.785 0.915 1.089] [15.  10.   5.   2.5  1. ]
count    1357.000000
mean       30.939005
std         0.605743
min        29.480000
median     30.890000
max        32.430000
 
tol = 1 del 781
4.116979988109961 [0.574 0.654 0.784 0.915 1.088] [15.  10.   5.   2.5  1. ]
 
tol = 0.5 del 1203
11.753081703721705 [0.573 0.653 0.783 0.913 1.087] [15.  10.   5.   2.5  1. ]
---
n = 2000, lmt86 direct
no fil
192.2082880456942 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 5 del 254
64.04789448918518 [0.575 0.655 0.785 0.916 1.09 ] [15.  10.   5.   2.5  1. ]
 
tol = 3 del 380
28.67826080132636 [0.575 0.654 0.785 0.916 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 2 del 500
9.98471395356546 [0.574 0.654 0.785 0.916 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 1.5 del 588
3.7181488303444894 [0.574 0.654 0.785 0.915 1.089] [15.  10.   5.   2.5  1. ]
count    1412.000000
mean       30.791516
std         0.567874
min        29.330000
median     30.810000
max        32.290000
 
tol = 1 del 705
4.255539391071579 [0.574 0.654 0.785 0.915 1.089] [15.  10.   5.   2.5  1. ]
 
tol = 0.5 del 1203
9.760407662442503 [0.573 0.653 0.783 0.914 1.087] [15.  10.   5.   2.5  1. ]
 

This result is important. The Anderson-Darling statistics started high and reduce to the smallest after values outside +/- 1.5 deg C from the median are removed. Below that, the statistic increase again showing a poorer fit. So +/- 1.5 deg C is the best fit. This is based on 2000 samples and a static (room) temperature.

After removing outliers beyond 1.5 deg C,

with the 220 uF cap at 5v, standard deviation is 0.540934, 184 values removed

with the Op-Amp (no cap), standard deviation is 0.605743, 643 values removed

LMT86 direct (no cap, no Op-Amp) standard deviation is 0.567874 588, values removed

The graphs is like such:

0693W00000DnwlFQAR.png 

95% confidence interval is about 1.96, so that gives an accuracy of +/- 1.11 deg C at 95% confidence interval measured at the ADC !

If we simply take the +/- 1.5 deg C range, that is 2.64 sigma, this is pretty much 99% confidence interval

https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function

Then we go back to the specs for LMT86 , which provides -10.9 mV/C.

This means the stm32f401 ADC under test has an accuracy of about +/- 12 mV at 95% confidence interval and +/- 16 mV at 99% confidence interval 😉

But these results are very stochastic, it takes lots of measurements and requires a static value to achieve such accuracy.

The 220 uF capacitor obviously made a difference, as only about 10% (184 values) are outside 1.5 deg C. Without the capacitor, no Op Amp, (30%) 588 values are outside +/- 1.5 C. The capacitor made a difference if smaller sample sizes are needed for averaging purposes, this may be particularly important if the temperature is changing rather than static.

S.Ma
Principal

How about specify the adc noise on the supply voltage, the output impedencd of the external temp sensor, the adc clock frequency, the chosen sampling time, and which parameter of the stm32401 adc ip electrical spec seems challenged?

TDK
Guru

If adding capacitance BEFORE the LDO helps so much, it suggests rails are not as stable as they could be. I would expect capacitance on the 3.3V line to help even more.

Massaging bad data can help, but correcting the source of the problem will help more.

If you feel a post has answered your question, please click "Accept as Solution".
andrewg
Associate III

The stm32f401 is running at 84 MHz, ADC clock is 84 MHz / 4 = 21 MHz, sampling time is 84 ADC clocks, then add 12 cycles conversion time ~ 96 cycles. So that is about 208.33 k samples / s max. The actual sample rates are 10 samples per sec for these graphs.

LMT86 has a spec of 50 uA max, so it is kind of high impedance. But the last test with the added LMV358 Op-Amp shows little improvement for the variance at least.

IMHO, the outliers are hazards, it is a little crazy to get sample points near absolute zero when actual temperature is room temperature. That volatility isn't easy to deal with. I'd think a median filter can deal with it, but that these tactics are (very) expensive, especially on microcontrollers.

I'd try putting the 220 uF cap after the LDO at the 3.3v rail. That might be interesting for a comparison. The 3.3v rail powers, the stm32f401 + a ssd1306 LCD (I'm not sure how much noise that can produce) + the LMT86 temperature sensor + optionally that LMV358 Op Amp. Maybe it is too small an LDO :D

andrewg
Associate III

OK here is it 220 uF on 3.3v after LDO, LMT86 direct to STM32F401 ADC pa0, no Op Amp, 2000 samples, 10 samples per sec, 84 cycle sample time as is previous

0693W00000F9tavQAB.pngcount 2000.000000

mean 30.730650

std 7.015711

min -176.190000

median 30.810000

max 56.960000

The above data after removing 193 values > 1.5 deg C from the median:

LMT86 to STM32F401 ADC, 220 uF on 3.3v

removed 193 values > +/- 1.5 deg C from median

0693W00000F9tdpQAB.pngcount 1807.000000

mean 30.796469

std 0.492922

min 29.330000

median 30.810000

max 32.290000

The count of outliers outside 1.5 deg C from median is comparable to that if 220 uF is placed before LDO at the 5v rail. 'Wild' outliers still occurs, there is one at -176 deg C (that one has a reading about 2.124 V), temperature measured is room temperature, values closer to room temperature 30 deg C is about 1.776 V. (edit: there is a bug for this value kind of 2.2v should be about 0 deg C as that's the spec for LMT86, Newton's method isn't a most stable solution search algorithm. But that this is still pretty much an outlier. 2.124 - 1.776 = 0.348 v, so using 10.9mV/C as an estimate that makes for a 31.9 deg C difference)

Oh, but the standard deviation after removing the outliers is the smallest so far at 0.49, so 95% confidence interval is +/- 0.96 deg C. at 1.5 deg C based on the filter, that is > 99% confidence interval at > 3 sigma.

It'd take a while to figure out where else are the noise sources, I'd guess. One of those tests I intend to do is to run it on batteries, that would take some work. Currently, it is pushing the values over usb-serial connection to the pc.

The sketch is here, for stm32duino

https://forum.allaboutcircuits.com/threads/lmt86-2-2v-temperature-sensor.181850/

https://www.stm32duino.com/viewtopic.php?p=8382#p8382

Georgy Moshkin
Senior II

You need to check your design with a scope. Make sure that regulator input voltage is enough so it is actually regulating. Voltmeter may show steady values, but actual voltage may be mearlndered at 1vpp. ​Replace your sensor with a battery! If you do not have a scope, connect earphones to Op-Amp buffer output through capacitors and hear what's going on there. If there is strong hiss which disappears when MCU reset pin (capacitor) is shorted, then you did not filter buffer power enough.

I would do the following:

1) C-L-C filter on MCU VDD. Main purpose of this filter is to filter out noise leaking from MCU/LCD to regulator side (LDO-CLC-MCU)

2) op-amp buffer and sensor must be powered from regulator side, and not from MCU side (relative to CLC filter).

3) Investigate if any data transfer induces significant noise on power lines.

4) Analyze whole system with battery-only power. Replace temperature sensor with 1.5v battery too.

5) Compare noise levels on all power lines while shorting MCU reset and in normal operation.

6) After everything is polished, try additional methods, like putting MCU to low power mode while sampling.

7) Largest sampling time is not always the best option. Assume you have constant data pumping between serveral ICs. It may be beneficial to increase inter-chip communication speeds, but decrease sampling time, so there is enough margin to reduce or eliminate time overlap between sampling and data transfer activities.