Author Topic: ADC Filtering Algorithm  (Read 21608 times)

garysdickinson

  • Hero Member
  • Posts: 502
  • Old PLC Coder
    • View Profile
ADC Filtering Algorithm
« on: September 29, 2015, 02:00:16 PM »
As many have noted the FMD/Fx ADC readings dance around a bit from sample to sample.  I have not been alone in observing this behavior.

The PLC's have some options for enabling a moving average filter within the ADC firmware.  And this helps with the noise.

I have been using a simple digital filter that acts as a low pass filter to reject the random noise and at the same time increase the resolution of the ADC channel from 12 to 13 bits (0..8191).

This is the simplest version of the code:

DM32[1] = ((DM32[1] * 31)  + ADC(1) + ADC(1)) / 32
[/font][/color]

How do I use it?  I invoke this code 10 times every second usually timed to the Clk:0.1Sec signal.  My actual application only needs to look at the computed ADC value once every second or two.  I'm not working with stuff that changes all that rapidly.

How does it work? This is a simple single pole IIR (Infinite Impulse Response) low pass filter.  Each time the code is called the output, calculated output value, DM32[1] is updated. The new output value is 31/32 of the previous value with the "new" ADC value contributing only 1/32 of the "new" output value.  This is a digital implementation of an analog filter that might consist of a series resistor and a capacitor to ground.  Google "IIR low pass filter" for the real science.

Why do I add the ADC(1) value into the equation twice? I wanted to double the resolution of the ADC from 12 bits to 13 bits as a byproduct of over ADC over sampling. I found that if I use two separate ADC samples that this works much better.  There is actually a requirement for a bit of noise from the ADC conversion to make the oversampling work. Google ADC oversampling for the technical details.

Ok what is the down side of this trick?  Response time.  If the input makes a big change in value, the output, DM32[1] will take a few seconds to respond to the change.  The two constants 31 and 32 in combination with the sampling rate (0.1 Hz) determine the time constant for this filter.  If the filter is too sluggish for your requirements, increase the sampling rate or change the filter constants to 15/16 or 7/8.

I have been working, with systems that the analog values cannot change very rapidly.  One of my clients monitors the levels in 100,000 liter fuel tanks using a pressure gauge.  It takes over 2 hours to fill the tank and about a week to empty into transit buses.  So from one second to the next the level in the tank cannot change so the filter delay is insignificant in this application.

So I am happy to trade off some response time to get stable ADC readings and double the resolution of the ADC from 12 to 13 bits.


Best regards,

Gary D*ickinson


« Last Edit: September 29, 2015, 05:48:57 PM by garysdickinson »

rjd1234

  • Newbie
  • Posts: 6
    • View Profile
Re:ADC Filtering Algorithm
« Reply #1 on: October 11, 2015, 12:36:28 AM »
Gary,

Thank you for posting this!  I'm still learning better process control technique, so I appreciate these sorts of posts.

Can I ask why you have ADC(1) twice?

Would either of these work?

   DM32[1] = ((DM32[1] * 31)  + ADC(1)) / 32

   or

   DM32[1] = ((DM32[1] * 31)  + ADC(1) + ADC(1)) / 33

Maybe I'm misunderstanding something fundamental.

garysdickinson

  • Hero Member
  • Posts: 502
  • Old PLC Coder
    • View Profile
Re:ADC Filtering Algorithm
« Reply #2 on: October 11, 2015, 07:56:13 AM »
The reason for

ADC(1) + ADC(1)  has to do with the fact that the over sampling algorithm requires that the there be random noise in the ADC conversion.  I have found that back to back conversions result in a bit of randomness.

The alternative would be to use ADC(1) * 2 but this results in no noise and the algorithm does not produces as nice a filtered result.

Your first sample:

 DM32[1] = ((DM32[1] * 31)  + ADC(1)) / 32

gets the filter behavior but the results will be in the range of  0..4095 and you didn't double the sampling resolution.

Your sencond example:

  DM32[1] = ((DM32[1] * 31)  + ADC(1) + ADC(1)) / 33

Changes the the filter constants to 31 and 33 and will probably work.  The filter time constant will be slightly longer than my example.

« Last Edit: October 11, 2015, 08:01:57 AM by garysdickinson »

garysdickinson

  • Hero Member
  • Posts: 502
  • Old PLC Coder
    • View Profile
Re:ADC Filtering Algorithm
« Reply #3 on: January 23, 2017, 09:16:11 PM »
Just an update on ADC filtering and how to get 14 bits out of the PLC's 12-bit ADC.

I have updated my ADC code to allow me to interpolate to 14 bits of resolution. The custom function is triggered from ladder logic on the Clk:0.1s signal. The custom function takes 750 us to execute on a Nano-10 PLC.

This is the code that I am using:


' Sample ADC - test code to demonstrate how to increase the resolution from 12 to 14 bits
'
' Why is this possible? The PLC's ADC has a fair amount of random noise in its output from
' one sample to the next. This noise provides an opportunity to to increase the resolution
' of the ADC by oversampling and decimation. For those of you that want to read up on this
' I refer you to a application note by Atmel, titled "AVR121: Enhancing ADC resolution by
' oversampling".  The following is a link to the applicaiton note:
'
'   www.atmel.com/images/doc8003.pdf
'

' Oversample by a factor of 16 to allow interpolation of 2 additional bits of resolution.
'
A =        ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)
A = A +   ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)+ADC(1)

' Now filter the oversampled ADC using an IIR (Infinite Impulse Response) low pass filter to smooth
' out remaining noise. If we decimated the 16x sample down to 1x the resulting 12 bit ADC value
' would have about */- 1 bit of noise. This is a significant improvement over the original raw
' ADC data. However, I'd like to get 14 bit data and additional filtering is required.
'
' The IIR low pass filter is a classic digital filter algorithm that mimics the response of
' a single pole analog R/C filter. This type of filter can be described as an
' "exponentially weighted moving average".
'
' The filter is pretty simple in operation. With filter constants of 15/16 the next filter value is
' based on 15/16 of the old value plus 1/16 of the new ADC value.
'
' The filter constants in conjunction with the sample rate determines the time constant of the digital
' filter. When using the 15/16 filter constants it will take 16 samples for the filter
' to get to 63.2% of the final value. If the sample rate is 0.1 seconds, then this filter will
' require 1.6 seconds per time constant. To get the output to reach 98.2% of the final value will
' require 5 time constants or 8 seconds.
'
' Other filter constants can be used. I have used 3/4, 7/8, 15/16, and 31/32. All of these work and
' will not overflow the 32-bit integer math.
'
' Please note that ADC1Filter is defined using the #Define mechanism as DM32[1]. ADC1Filter must be a
' 32-bit integer and since this value must not be disturbed by any other custom function, I prefer
' use DM32[] rather than the other integer values, A..Z.
'
ADC1Filter = ((ADC1Filter * 15) + A) / 16

' Decimate and round to nearest integer
'
' At this point the ADC1Filter holds the filtered ADC value multiplied by 16. Now we must decimate (divide)
' the filtered value by 4 and this will result in the ADC value being interpolated to 14 bit resolution.
' A 14 bit ADC will have an output in the range of 0..16383.
'
C = (ADC1Filter+2)/4   ' decimate to 14 bits and round to nearest integer

[/font]

Not a lot of code and the return on investment is reasonable: 14 bits of resolution and little or no noise. The only downside is response time of the low pass filter.

Gary D*ckinson
« Last Edit: January 23, 2017, 09:44:19 PM by garysdickinson »

support

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3174
    • View Profile
    • Internet Programmable PLCs
Re:ADC Filtering Algorithm
« Reply #4 on: January 24, 2017, 09:39:30 PM »
AWESOME!

Thanks for the contribution, Gary. We appreciate it!
Email: support@triplc.com
Tel: 1-877-TRI-PLCS