ADC Noise

Posted on
  • I have a thermistor connected to one of the ADC's but I am having quite a bit of trouble with noise.

    As a test I have setup the circuit with another resistor in replacement of the thermistor bead but I cannot seem to get the readings to a stable state. I have in addition tried using a 100nF capacitor across the input which helps to some degree but not enough.

    Ideally I would like to stabilise the temp to at least one decimal place.
    I would assume some sort of software filter, any suggestions?

  • Wow, that's a pretty serious noise issue. What's the other side of the thermistor connected to? GND and 3.3v would be best as that is what the microcontroller is also using. When I was doing the stuff for http://www.espruino.com/Thermistors it was pretty stable.

    As far as software filters, the simplest is:

    var amt  =0.1;
    var average = first_temperature_we_have;
    function step() {
      average = average * (1-amt) + new_temperature * amt;
      filtered_temperature = average;
    }
    

    But you can also do a median filter, which is the kind that's used for noise reduction in digital cameras, TVs and stuff like that:

    var history = new Uint16Array(50); // or whatever level of filtering
    var sortedHistory = new Uint16Array(history.length);
    var historyPtr = 0;
    
    function step() {
      history[historyPtr] = new_temperature*256;
      historyPtr = (historyPtr+1) % history.length; // choose a new history item
      sortedHistory.set(history); // set history values to the new ones
      sortedHistory.sort(function(a,b) { return a-b; });
      filtered_temperature = sortedHistory[sortedHistory.length/2]/256;
    }
    

    Hope that helps! While doing this I found a bug in Float32Array.set, so you won't be able to use that until 1v65 I'm afraid. However if you need floats you can always use the normal Array - it'll just take up a bit more memory.

  • Thanks Gordon that's a huge help.

    I did manage to get to a reasonable point by logging temperatures to an array. That was until the array got too large and crashed the Espruino! So now when I get to the max array size I 'unshift' the first value off the array.

    Mode appears to work better than median. I will investigate further using your post above.

    The noise may be down to the thermistor I am using. I'm using a 10K thermistor with a 10K resistor as the divider all on a small board next to the Espruino.

    To test the readings I was using a 10K resistor in place of the thermistor so in theory I should be reading bang on 25°C but it was fluctuating around too much.

    The response doesn't need to be super fast so I think some sort of array and average should work okay.

  • Well this is slightly embarrassing!
    It helps if I put the 100nF capacitor in the right place in the circuit!! Doh! What an idiot!!

  • :) Ahh, well that's good to hear anyway!

    Were you running out of memory using Uint16Array from the example? That's quite a big array!

  • You can use a moving average with an interval of 8 or 16 samples .
    I used the following code to get stable readings from a 10-bit encoder.
    Using the dithered noise resolution is in fact improved to 1 1bits.

    setInterval(function() {
            enc_deg = sma16(degree(C1).toFixed(1)); // console.log("Encoder Angle[°] = "+enc_deg.toFixed(1)); 
        }, 100 );
    function degree( pin ) {
      var ratio  = 4.0;                  
      var offset = 0.5;       
      var factor = 0.73333333333; 
      var phys   = analogRead(pin) * 3.3;  // *E.getAnalogVRef(); 
      var meas   = 360.0 * ( phys / factor - offset ) / ratio ;    
      console.log("Input[V] = "+phys.toFixed(3)+"  Angle[°] = "+meas.toFixed(1));
      return meas;
    }
    
    
    // ------------------------------------
    // simple parametric moving averager
    // ------------------------------------
    function sma(period) {
        var nums = [];
        return function(num) {                 
            nums.push(num);
            if (nums.length > period) nums.splice(0,1); 
            var sum = 0; var n = period;
            function sum_num (n) { sum+=Number(n); };
            nums.forEach(sum_num);
            if (nums.length < period) n = nums.length;
            return(sum/n);
        }
    }
    
    var sma16 = sma(16);
    

    Input[V] = 0.494 Angle[°] = 15.6 Next reading = 15.6, SMA = 15.6
    Input[V] = 0.496 Angle[°] = 15.9 Next reading = 15.9, SMA = 15.7
    Input[V] = 0.495 Angle[°] = 15.8 Next reading = 15.8, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.8 Next reading = 15.8, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.7 Next reading = 15.7, SMA = 15.7
    Input[V] = 0.498 Angle[°] = 16.1 Next reading = 16.1, SMA = 15.8
    Input[V] = 0.497 Angle[°] = 16.0 Next reading = 16.0, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.7 Next reading = 15.7, SMA = 15.8
    Input[V] = 0.496 Angle[°] = 15.9 Next reading = 15.9, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.7 Next reading = 15.7, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.7 Next reading = 15.7, SMA = 15.8
    Input[V] = 0.494 Angle[°] = 15.6 Next reading = 15.6, SMA = 15.8
    Input[V] = 0.494 Angle[°] = 15.6 Next reading = 15.6, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.8 Next reading = 15.8, SMA = 15.8
    Input[V] = 0.495 Angle[°] = 15.7

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

ADC Noise

Posted by Avatar for StuntMonkeh @StuntMonkeh

Actions