Question regarding High Pass Filter

I have a question regarding filtering to remove a DC offset bias. Specifically, I wonder whether the approach of the open energy monitor project is overly complex assuming the front end hardware (i.e. the analog inputs) has been designed with easy DC offset bias removal in mind. You can read about the theory / details behind their approach over at Page not found | Archived Forum but the basic approach is to take a varying AC signal (from a AC-AC transformer, for example) and then to use a voltage divider + capacitor as a DC offset source to make the signal all-positive for the arduino to read.

My approach to the hardware side was slightly different. A small linear voltage regulator creates a reference voltage for the arduino (i.e. AREF = 1.25V). Two 1k resistors (with a 1% tolerance) are used for the offset bias voltage divider. That way, the DC bias offset should always be equal to 1/2 the reference voltage. Measurements of the voltage and current inputs without external inputs attached confirm that the numeric ADC values are 511-512, just as one would expect.

The OpenEnergyMonitor group came up with a nifty way on the software side to remove bias, regardless of how the DC-bias voltage divider was set up. I suppose this is a great / better approach if the DC offset is not known, or drifts, etc. The snippet of their code below shows their approach to removing offsets as part of their measurement loops.

lastSampleV=sampleV;                          //Used for digital high pass filter
    lastSampleI=sampleI;                          //Used for digital high pass filter
    
    lastFilteredV = filteredV;                    //Used for offset removal
    lastFilteredI = filteredI;                    //Used for offset removal   
    
    //-----------------------------------------------------------------------------
    // A) Read in raw voltage and current samples
    //-----------------------------------------------------------------------------
    sampleV = analogRead(inPinV);                 //Read in raw voltage signal
    sampleI = analogRead(inPinI);                 //Read in raw current signal

    //-----------------------------------------------------------------------------
    // B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
    //-----------------------------------------------------------------------------
    filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

In the interest of speed (and simpler code), I would like to just use simple subtraction for the filtering. i.e.

filteredV = analogRead(inPinV)-512;                 //Read in raw voltage signal and subtract DC offset
filteredI = analogRead(inPinI)-512;                 //Read in raw current signal and subtract DC offset

Is there something I should be considering when doing this (that lead the openenergymon group down their particular path)? Also, any idea where/why they are applying the 0.996 multiplier?

Any suggestions are welcome and thanks to Grumpy Mike for posting his thoughts on how to protect the inputs of an Arduino using a BAV99, a cap, and a resistor.

There are two reason for DC offset. Voltage present at the input, and internal ADC offset.
You could install high grade precision voltage regulator and resistors, but it would eliminate only one part of the problem (and increase a cost). Second part due design / technological non perfection of the ADC would still present. In other words, if voltage exactly 50.0000% of the reference, there is no warranty that analogRead return 512, it could be 508 or 520, according to table 28.9 data sheet ATMega328:

Offset error Vcc = 4.0v, VRef = 4.0v -3.5 3.5 LSB

HPF filter is fighting with both problem.
Regarding coefficient 0.996 I'd recommend to study "AVR465: Single-Phase Power/Energy Meter with Tamper Detection" - Atmel application note.

Thank you so much, that answered all of my questions. I did get my simpler approach to work with loads but under a no-load condition (i.e. just a current sensor on the AC line) there was all sorts of very interesting noise in the signal that blew up the results. In other words, use the approach promoted by Atmel and Openenergymonitor! Thanks again.

Hi!!
Seems that I discovered somebody with the same doubts as me...
I understand almost everything, not at all the concept of "internal ADC offset".
In other hand if DC bias do all this stuff of negative signal filter, why it is used the voltage divider??

I'm getting so confused with all this concepts :fearful:

Search for AVR120, probably it would solve your confusion.
I'm not sure myself, what does it mean: "negative signal filter"?
The technical issue is appears because voltage (and current) has to be measured - AC. Analog input can't accept negative half-wave. This is why voltage divider was introduced in design. Creating DC offset its helping internal ADC to measure correctly full cycle of the AC waveform - positive and negative, shifting negative voltage up, above 0. But to get right measurements results at the end, value of the artificial DC offset must be subtracted from the data received, so AC energy only would be calculated. And here the problem, the exact value of the offset is never known, because analog digital converter itself has some offset (AVR120) altogether with external voltage offset created by voltage divider (never precise for a bunch of reasons). HPF is just a smart trick to eliminate this inaccuracy of measurements.