RobTillaart / ACS712

Arduino library for ACS Current Sensor - 5A, 20A, 30A
MIT License
129 stars 35 forks source link

Complex AC RMS Current Reading Issues #18

Closed imk2021 closed 2 years ago

imk2021 commented 2 years ago

Hello Rob I am having issues with the ACS712 library ver 0.2.7/6 when reading complex AC waveform and i am wondering if you want my full project details and waveform photos to investigate. Basically the load on the AC line that the ACS712 is monitoring has two loads: Load One is an old 100w incandescent lamp controlled via a simple switch. Load Two is an old 200w incandescent lamp controlled the RBDdimmer function.

Switching on load One gives a clean sine ACS712 output and your library produces very good results. Switching on load Two gives a switched sine ACS712 output and your library produces good but variable results depend on the dimmer.setPower( n ); power level.

Switching on load One and load Two produces a complex ACS712 waveform (Sine plus Dimmer Spike) and I am afraid your ACS712 library produces very inconsistent results. compared to the in series BRYMEN BM257 RMS meter I am using.

I have had a look on Github for your email to send you full info, scope screen shots and my code and project wire info but i can't seem to find it so i am wondering how to proceed.

All best Ian Knight PS Ignore the jitter in the image, this is my poor camera

IMG_5803

RobTillaart commented 2 years ago

That is often a issue with libraries (including non-Arduino), they do not cover all possible needs. One can use the libs as starting point, or go to an RTOS solution that allows proper scheduling of all tasks. The learning curve for RTOS is much steeper than for a plain single thread Arduino code.

imk2021 commented 2 years ago

Afternoon Rob,

So i thought i would put together a test app to gather some data for a dimmer not controlled by the Arduino and therefore just unmolested ACS712 data. This little app main loop is basically just a 10 state, state counter that tick every 100mS. Each 100mS tick it reads your ACS712 mA_AC(50) and computes the mean for 10 samples, a 1 second mean.

The dimmer used is a typical domestic light dimmer that you would find on the lounge wall of many homes. The test load is 200W at ~240 volts, the dimmer range seems limited to the lowest value in the data set below. Also see scope image captures of the ACS712 output at each of the four measurements i was able to take, plus the app.

Hope this all helps and a looking forward to your ACS library update when ready. Let me know other testing you need, all best Ian Code and images below

Dimmer at minimum BRYMEN 0.489A                     LCD MeanmA ~1020

Dimmer at                    BRYMEN 0.6A LCD MeanmA    ~1016

Dimmer at                    BRYMEN 0.7A LCD MeanmA    ~907

Dimmer at maximum BRYMEN 0.815A                     LCD MeanmA ~793  (Think this is very good result given the noise)

// //    FILE: OVEN_CONTROLLER_PRODUCTION_V4.ino //    AUTHOR: Ian Knight //    PURPOSE: Testing Data //    DATE: 2022-21-Aug.

include

include"ACS712.h"// Current sensor

defineACS_Pin A0

defineACS712_CURRENT_SENSOR_ANALOG_PIN               A0

defineADJUSTABLE_MAX_CURRENT_ANALOG_PIN              A1

defineMEAN_ACS712_SAMPLES 10

defineSTATE_COUNTER_TICK_RATE 100// in mS

defineHYSTERESIS_CURRENT_IN_MA 100

defineOUTPUT_TEST_PIN 8

ACS712ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN, 5.0, 1023, 100); constintrs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4; LiquidCrystallcd(rs, en, d4, d5, d6, d7); longMaxmA; // Adjusted maximum current longMeanmA;// AC721 Mean Current unsignedlongPreviousMillis = 0; //  ----------------------------- Prototypes

voidDisplayToLCDTotalCurrent( void); voidDisplayToLCDMaxCurrent( void); // ------------------------------------------------ setup()

voidsetup() { // set up the LCD's number of columns and rows: Serial.begin(9600); lcd.begin(16, 2);  // Init LCD pinMode( OUTPUT_TEST_PIN , OUTPUT); ACS.autoMidPoint();// Init ACS712 } // -------------------------------------------------- loop()

voidloop() { staticint StateCounterState; if( ( unsignedlong)( millis() - PreviousMillis ) >= STATE_COUNTER_TICK_RATE )  {  PreviousMillis = millis();// update time switch( StateCounterState )   { case0:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case1:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case2:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case3:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print("                ");// Clear Line 0 digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case4:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print( "Max mA's: "); lcd.print( 1000); digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case5:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case6:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case7:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current break; case8:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current lcd.setCursor(0, 1); lcd.print("                ");// Clear Line 1 break; case9:    MeanmA += ACS.mA_AC( 50.0);// Read the ACS712 for AC current    MeanmA /= MEAN_ACS712_SAMPLES; lcd.setCursor(0, 1); lcd.print( "Cur mA's: "); lcd.print( MeanmA );    MeanmA = 0; break;   }// End state counter state if( ++StateCounterState > 9)   StateCounterState = 0;// Back to state Zero  }// end if millis State Tick Rate }// End loop() // ------------------------------------------ DisplayToLCDTotalCurrent( ) ---------------------------------- voidDisplayToLCDTotalCurrent( void) { lcd.setCursor(0, 1); lcd.print("                ");// Clear Line lcd.setCursor(0, 1); lcd.print( "Curt I="); lcd.print( MeanmA );  // print ACS712 AC mean current } // ------------------------------------------- DisplayToLCDMaxCurrent()

voidDisplayToLCDMaxCurrent( void) { lcd.setCursor(0, 0);// Col, row lcd.print("                ");// Clear Line lcd.setCursor(0, 0); lcd.print( "Max  I="); lcd.print( MaxmA );  // print the System Maximum mA } // *** END OF FILE


RobTillaart commented 2 years ago

Hi Ian, Thanks for the test, I appreciate the time and efforts. What I notice is that in this last numbers it seems that BRYMEN + LCD ~ 1600 mA When Brymen goes up lcd goes down? Or do I just image seeing a pattern?

imk2021 commented 2 years ago

Hello Rob,

Yes the pattern is a bit odd but these are the values I read: At minimum dimmer  the mean mA_AC(50) is highest and the nearer the full sine the lower. To the point where dimmer is 100% and sine mostly complete mean mA_AC(50) returns a value close to the BRYMEN. Note i think when the email was sent it reordered the images but they have a title/name of the BRYMEN current. Also in the images the HANTEK RMS volts goes in the right direction (Up as current goes up) Again happy to help and i think we are making good progress, i have this rig as permanent setup now so more testing is easy :-) You can also ignore the scope ch2 (green pules) as it is just measuring time it takes for LCD write as want to make sure mA_AC(50) was read at consistent timing. Ian PS Just a thought, in mA_AC() you comment UNO ~160 samples which is about as fast ADC can go in UNO/NANO What about a little Nano testing app where just 200 or so raw sample data (ADC output) is written into an array then dump to serial. Do this dump for each of the previous dimmer settings  then do the math on them in a Visual Studio Consul cpp app which would be easier to debug than embedded.

Dimmer at minimum BRYMEN 0.489A                     LCD MeanmA ~1020

Dimmer at                    BRYMEN 0.6A LCD MeanmA    ~1016

Dimmer at                    BRYMEN 0.7A LCD MeanmA    ~907

Dimmer at maximum BRYMEN 0.815A                     LCD MeanmA ~793  (Think this is very good result given the noise)

RobTillaart commented 2 years ago

Found a bug in mA_AC - https://github.com/RobTillaart/ACS712/issues/21

RobTillaart commented 2 years ago

https://create.arduino.cc/projecthub/daniel232/three-phase-rms-ammeter-with-current-transformers-7a7866

Related article

imk2021 commented 2 years ago

Hello Rob and many thanks for the interesting post

In the project code (and only had quick look) they take many sample over a period

const unsigned long sampleTime = 60000UL;   // sample over 60ms, 3 cycles for 50Hz const unsigned long numSamples = 120UL;

That is why i mentioned in previous post functions to capture n sample or n cycles. The other thing i think will help  is to filter noise spike by validating min/max samples. This i think you can do by looking at sample either side of min max to see if measurement is out of range. Or as i did for noisy accelerometer data is to have a rolling mean of a few samples.

I still think the ACS712 is a viable solution for most Arduino user, just matter of getting the algorithm right. As I said this test rig is permanent so happy to do testing for you Ian

RobTillaart commented 2 years ago

@imk2021 The example in the link uses 3 full cycles to be able to measure the 3 phases independently for one full cycle. It doesn't use averaging the values of multiple cycles in the measurement. It uses an additional RunningAverage object to average the measurements outside the cal to rmsValue(phasePin_1, numSamples);

const unsigned long sampleTime = 60000UL;   // sample over 60ms, 3 cycles for 50Hz
const unsigned long numSamples = 120UL;     // samples number to divide sampleTime exactly, low enough for the ADC

So 120 samples per full cycle (mA_AC() makes about 150 same order of magnitude)


In the develop branch I added a parameter cycles to the three measurement functions - mA_AC(), mA_AC_sampling() and ma_DC(). The default for cycles = 1.

Please test mA_AC() and mA_AC_sampling() if they meet your expectations.

Can you time in one sketch how long it takes to do 1000 cycles - 300 Watt if possible.

1000 calls should take ~ 20 seconds.

I am far from convinced that this parameter is the right step forward. I am a strong believer in scenario (2) as that allows the user to be more flexible in taking the average, median, low pass filtering etc. Whatever suits his project.

RobTillaart commented 2 years ago

@imk2021 After analyzing the code again step by step I finally found a serious bug. It is in the math in the mA_AC_sampling().

There is a mix of int and uint16_t math in the line current = analogRead() - _midPoint; It was evaluated as unsigned while it should signed.

This caused -2 being 65533 and squaring that gave a way too big sum and therefor RMS.

Don't know if it is now 100% but I expect the results of mA_AC_sampling() now to be much better.

Also added 3 extra AC examples to the library.

imk2021 commented 2 years ago

Rob

I am not sure what to do re your.

After analyzing the code again step by step I finally found a serious bug. It is in the math in the mA_AC_sampling(). Because there is a mix of int and uint16_t math the line |current = analogRead() - _midPoint;| was apparently evaluated as unsigned while it should be signed. This caused -2 being 65533 and squaring that gave a way too big sum and therefor RMS.

Don't know if it is now 100% but I expect the results of mA_AC_sampling() now be better.

Also added 3 extra AC examples to the library.

Have you updated your library as I already have 0.2.7 installed and that's what i tested with. Can't find 0.2.8 so note sure what changes you have made.

Ian

RobTillaart commented 2 years ago

https://github.com/RobTillaart/ACS712/archive/refs/heads/develop.zip

imk2021 commented 2 years ago

Morning  Rob

Just collected test result for 0.2.8 development library, they look much better. The dimmed results still seem a bit off, but better :-) I am going to tweak my little test app to call    MeanmA += ACS.mA_AC( 50.0 ); Several times in each state, my guess is 3 for first test so 30 sample calls rather than 10 per second. To just see what happens, expect some result later today.

Ian

Not Dimmed 100w  Brymen=0.423  MeanmA=375        Image=NotDimmed100w 200w  Brymen=0.824  MeanmA=766        Image=NotDimmed200w 300w  Brymen=1.247   MeanmA=1175    Image=NotDimmed300w 1000w Brymen=4.527   MeanmA=4376    Image=NotDimmed1000w

200w Dimmed Brymen=0.509   MeanmA=540 Image=200w-LightDimmerBRYMEN-509ma Brymen=0.607   MeanmA=624 Image=200w-LightDimmerBRYMEN-607ma Brymen=0.703   MeanmA=645 Image=200w-LightDimmerBRYMEN-703ma Brymen=0.827   MeanmA=744 Image=200w-LightDimmerBRYMEN-827ma

RobTillaart commented 2 years ago

Thanks!

Put the numbers in a spreadsheet to explore them

Brymen AC Brym / AC Average
423 375 1,1280  
824 766 1,0757  
1247 1175 1,0613  
4527 4376 1,0345  
      1,0749
509 540 0,9426  
607 624 0,9728  
703 645 1,0899  
827 744 1,1116  
      1,0292

Observations 1st set

There seems almost a constant factor that drops as current increases. The device is a 20 A sensor and the first 3 measurements are all in the bottom 6% of its range. The 4th measurement is at 20% of its range, and is best.

From the datasheet

image

The sensitivity can be calibrated between 96 - 104, bringing it closer to real values. (try 96) Noise = 11 mV which is roughly 0.1A and I expect that after calibrating the deviations are all under this 0.1Amp.

Observations 2nd set

Opposite behavior of the factor, it increases as current drops. The device is a 20 A sensor and all measurements are in the bottom 4% of its range. As the dimmer causes the form factor to be incorrect it is expected to deviate. mA_AC_sampling() is expected (by me) to do a better job.

Trend line analysis

The 1st set of 4 gives a formula f(x) = 0.9750 x - 38.4676 with R2 = 1 (very good) The 2nd set of 4 gives a formula f(x) = 0.6061 x + 237.3085 with R2 = 0.9642 (good)

imk2021 commented 2 years ago

Hello Rob,

Just thought i would give mA_AC_samples() a quick test before dinner.

Not Dimmed 100w Brymen 431mA, mean of 40 mA_AC_samples() call 421mA

Dimmed 200w Brymen 510mA, mean of 40 mA_AC_samples() call 501mA

Both results i think are very good!

However sometimes No load Brymen 3mA, mean of 40 mA_AC_samples() call after NANO reset is 27mA but this slowly increases at rate of ~0.5mA per second Thus after a few seconds mean mA_AC_samples() reads 100mA or so. This does not always happen, sometimes after NANO reset the output will stabilize at about 40 mA.

Code below:

// //    FILE: OVEN_CONTROLLER_PRODUCTION_V5.ino //    AUTHOR: Ian Knight //    PURPOSE: Testing Data //    DATE: 2022-26-Aug.

include

include"ACS712.h"// Current sensor

defineACS_Pin A0

defineACS712_CURRENT_SENSOR_ANALOG_PIN               A0

defineADJUSTABLE_MAX_CURRENT_ANALOG_PIN              A1

defineMEAN_ACS712_SAMPLES_SETS 10

defineSTATE_COUNTER_TICK_RATE 100// in mS

defineHYSTERESIS_CURRENT_IN_MA 100

defineOUTPUT_TEST_PIN 8

ACS712ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN, 5.0, 1023, 100); constintrs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4; LiquidCrystallcd(rs, en, d4, d5, d6, d7); longMaxmA = 0; // Adjusted maximum current // long MeanmA; // AC721 Mean Current floatMeanmA;// AC721 Mean Current New for multi cycle samples unsignedlongPreviousMillis = 0; //  ----------------------------- Prototypes

voidDisplayToLCDTotalCurrent( void); voidDisplayToLCDMaxCurrent( void); // ------------------------------------------------ setup()

voidsetup() { // set up the LCD's number of columns and rows: Serial.begin(9600); lcd.begin(16, 2);  // Init LCD pinMode( OUTPUT_TEST_PIN , OUTPUT); ACS.autoMidPoint();// Init ACS712 } // -------------------------------------------------- loop()

voidloop() { staticint StateCounterState; if( ( unsignedlong)( millis() - PreviousMillis ) >= STATE_COUNTER_TICK_RATE )  {  PreviousMillis = millis();// update time switch( StateCounterState )   { case0: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current digitalWrite( OUTPUT_TEST_PIN , HIGH );    MeanmA += ACS.mA_AC_sampling( 50.0, 4);// Takes as expected 80mS digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case1: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case2: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case3: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); //digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print("                ");// Clear Line 0.. This takes 9.8 mS //digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case4: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); //digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print( "Max mA's: "); lcd.print( MaxmA );// This takes 7 mS //digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case5: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case6: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case7: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case8: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); lcd.setCursor(0, 1); lcd.print("                ");// Clear Line 1 break; case9: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4);    MeanmA /= MEAN_ACS712_SAMPLES_SETS; lcd.setCursor(0, 1); lcd.print( "Cur mA's: "); lcd.print( MeanmA );    MeanmA = 0; break;   }// End state counter state if( ++StateCounterState > 9)   StateCounterState = 0;// Back to state Zero  }// end if millis State Tick Rate }// End loop()

ifdefOLD

// ------------------------------------------ DisplayToLCDTotalCurrent( ) ---------------------------------- voidDisplayToLCDTotalCurrent( void) { lcd.setCursor(0, 1); lcd.print("                ");// Clear Line lcd.setCursor(0, 1); lcd.print( "Curt I="); lcd.print( MeanmA );  // print ACS712 AC mean current } // ------------------------------------------- DisplayToLCDMaxCurrent()

voidDisplayToLCDMaxCurrent( void) { lcd.setCursor(0, 0);// Col, row lcd.print("                ");// Clear Line lcd.setCursor(0, 0); lcd.print( "Max  I="); //lcd.print( MaxmA );   // print the System Maximum mA lcd.print( 0);  // print the System Maximum mA }

endif

// *** END OF FILE


RobTillaart commented 2 years ago

Those are the numbers we were waiting for.

Dimmed 200w Brymen 510mA, mean of 40 mA_AC_samples() call 501mA

you might subtract 2% to the mVperAmp parameter (make it 98 )

ACS712ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN, 5.0, 1023, 98);

Analysis

ACS.mA_AC_sampling() uses all samples it takes for doing the math. Therefor it will add up all the noise and interpret it as a current.

An improvement could be to ignore values in the noise range? I'll have a look how to add noiseFiltering. Result will be that the mA calculated is slightly lower again. Might need to adjust the mVperAmp parameter even a bit more.

to be continued

RobTillaart commented 2 years ago

I have added noise filtering in the develop branch.

Please finish the tests without noise filtering so we get an idea of how it performs at higher loads.

imk2021 commented 2 years ago

Hello Rob, So I'll continue to do all the tests tomorrow and leave 0.2.8 library as currently installed; Pre noise filter. Now I think it is about time I added into setup  setmVperAmp(float mVperAmpere) to see how much we are off by. Questions: Should I add setmVperAmp(float mVperAmpere) before or after autoMidPoint() What you think best load  to use to get best value for setmVperAmp() 100w or 1000w

Have good evening Ian

RobTillaart commented 2 years ago

MidPoint is determined without mV so it should not make a big difference. But yes, specific noise can create a small bias.

It is good to keep measuring the 5V power supply too. You want to know if it drops during measurements as that would shift the midpoint

RobTillaart commented 2 years ago

BTW in the next 0.3.0 release midpoint will be a float to be more accurate. In coming weeks / months I want to investigate external ADC eg 16 bit as an option. Could improve resolution in the lower ranges

imk2021 commented 2 years ago

Hello Rob, please find below test set three.

As you can see I have added 500w test for completeness. Also we have an issues where when i turn the load off, MeanmA sometimes (very intermittent) does not return to zero or close to it, see note

All best Ian

Test Set Three mA_AC_sampling() 40 calls per sec. OVEN_CONTROLLER_PRODUCTION_V5 Pre noise reduction version 0.2.8 ACS.setmVperAmp( 99 ); // To set the calibration for ACS712 deviation

Note: Sometimes after switching a test off, MeanmA does not return to near zero (50mA or so).       So I have to press the reset button of the Nano to reinitialize the app, this resolves the issues. Originally in the code (state case 9) was MeanmA = 0; so I changed this to MeanmA = 0.0; and it seemed to have fixed it. However, it happened again during this test set, my app is attached but i can't see an error in it.

Not Dimmed 100w  Brymen=0.430  MeanmA=414.2 200w  Brymen=0.833  MeanmA=797.5 300w  Brymen=1.247  MeanmA=1220.3 500w  Brymen=2.074  MeanmA=1977.8 1000w Brymen=4.6    MeanmA=4456.5

200w Dimmed Brymen=0.505   MeanmA=815.5 after reset 515.6 Brymen=0.603   MeanmA=591.5 Brymen=0.702   MeanmA=687.5 Brymen=0.830   MeanmA=812.3

500w Dimmed Brymen=1.277   MeanmA=1302.9 Brymen=1.404   MeanmA=1416.3 Brymen=1.506   MeanmA=1507.8 Brymen=1.611   MeanmA=1606.9 Brymen=1.701   MeanmA=1690.8 Brymen=1.800   MeanmA=1778.1 Brymen=1.905   MeanmA=1888.9 Brymen=2.007   MeanmA=1982.4 Brymen=2.059   MeanmA=2025.8

// //    FILE: OVEN_CONTROLLER_PRODUCTION_V5.ino //    AUTHOR: Ian Knight //    PURPOSE: Testing Data //    DATE: 2022-26-Aug.

include

include"ACS712.h"// Current sensor

//#define ACS_Pin A0

defineACS712_CURRENT_SENSOR_ANALOG_PIN               A0

defineADJUSTABLE_MAX_CURRENT_ANALOG_PIN              A1

defineMEAN_ACS712_SAMPLES_SETS 10

defineSTATE_COUNTER_TICK_RATE 100// in mS

defineHYSTERESIS_CURRENT_IN_MA 100

defineOUTPUT_TEST_PIN 8

ACS712ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN, 5.0, 1023, 100); constintrs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4; LiquidCrystallcd(rs, en, d4, d5, d6, d7); longMaxmA = 0; // Adjusted maximum current // long MeanmA; // AC721 Mean Current floatMeanmA = 0.0;// AC721 Mean Current New for multi cycle samples unsignedlongPreviousMillis = 0; //  ----------------------------- Prototypes

voidDisplayToLCDTotalCurrent( void); voidDisplayToLCDMaxCurrent( void); // ------------------------------------------------ setup()

voidsetup() { // set up the LCD's number of columns and rows: Serial.begin(9600); lcd.begin(16, 2);  // Init LCD pinMode( OUTPUT_TEST_PIN , OUTPUT); ACS.setmVperAmp( 99);// To set the calibration for ACS712 deviation ACS.autoMidPoint();// Init ACS712 } // -------------------------------------------------- loop()

voidloop() { staticint StateCounterState; if( ( unsignedlong)( millis() - PreviousMillis ) >= STATE_COUNTER_TICK_RATE )  {  PreviousMillis = millis();// update time switch( StateCounterState )   { case0: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current digitalWrite( OUTPUT_TEST_PIN , HIGH );    MeanmA += ACS.mA_AC_sampling( 50.0, 4);// Takes as expected 80mS digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case1: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case2: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case3: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); //digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print("                ");// Clear Line 0.. This takes 9.8 mS //digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case4: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); //digitalWrite( OUTPUT_TEST_PIN , HIGH ); lcd.setCursor(0, 0); lcd.print( "Max mA's: "); lcd.print( MaxmA );// This takes 7 mS //digitalWrite( OUTPUT_TEST_PIN , LOW ); break; case5: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case6: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case7: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); break; case8: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4); lcd.setCursor(0, 1); lcd.print("                ");// Clear Line 1 break; case9: //..   MeanmA += ACS.mA_AC( 50.0 ); // Read the ACS712 for AC current    MeanmA += ACS.mA_AC_sampling( 50.0, 4);    MeanmA /= MEAN_ACS712_SAMPLES_SETS; lcd.setCursor(0, 1); lcd.print( "Cur mA's: "); lcd.print( MeanmA );    MeanmA = 0.0; break;   }// End state counter state if( ++StateCounterState > 9)   StateCounterState = 0;// Back to state Zero  }// end if millis State Tick Rate }// End loop()

ifdefOLD

// ------------------------------------------ DisplayToLCDTotalCurrent( ) ---------------------------------- voidDisplayToLCDTotalCurrent( void) { lcd.setCursor(0, 1); lcd.print("                ");// Clear Line lcd.setCursor(0, 1); lcd.print( "Curt I="); lcd.print( MeanmA );  // print ACS712 AC mean current } // ------------------------------------------- DisplayToLCDMaxCurrent()

voidDisplayToLCDMaxCurrent( void) { lcd.setCursor(0, 0);// Col, row lcd.print("                ");// Clear Line lcd.setCursor(0, 0); lcd.print( "Max  I="); //lcd.print( MaxmA );   // print the System Maximum mA lcd.print( 0);  // print the System Maximum mA }

endif

// *** END OF FILE


imk2021 commented 2 years ago

Rob,

The situation where post test power off leave MeanmA displaying a non zero or near value.

I have repeated this cycle a couple of dozen times and can now reproduce it as follows: Power up the test with any load current going thru the ACS712 and MeanmA is about 25mA I can repeat this power on/off/on and or press the reset button and MeanmA is always a nominal  25mA hence the code boots reliably.

However when turning off a say 100w load MeanmA sometimes does not return to about 25mA or so. This I can reproduce simple and repeatable as follows:

Power up the system and apply a 100w load. Switch off the load. Unplug the ACS712 out pin from analog in A0, lets the analog in A0 float and MeanmA displays a very large number. Plug the ACS712 out pin back into analog in A0 and the MeanmA does NOT return to the nominal  25mA

So it seems that once a large value has be seen at analog A0 the software losses some  reference point/value. Hence what i think is happening is when a load is switched off a spike hits A0 and causes the loss/corruption/overright of some midpoint or something like that.

Hope this helps Ian

RobTillaart commented 2 years ago

Quick look at your code


Power up the test with any load current going thru the ACS712 and MeanmA is about 25mA

I expect it is adding up noise.

Did you test the Noise filtering version already?


Plug the ACS712 out pin back into analog in A0 and the MeanmA does NOT return to the nominal 25mA

Can't explain this scenario, what voltage does the BRYMEN measure on the out pin (frequency?)

Hence what i think is happening is when a load is switched off a spike hits A0

Yes, that is 99% sure what happens when switching on/off. This is also what happens with the dimmer, see your scope images (above) When you do the averaging yourself you can "act upon outliers" after every single measurement.

if (newMeasurement differs less than X % from previous) it is OK
else reuse old Value.

Are you familiar with my runningMedian class, It might be just the trick you need.


Unplug the ACS712 out pin from analog in A0, lets the analog in A0 float and MeanmA displays a very large number.

Yes as it "measures" unknown values and interpret them as good one. Floating lines should be prevented in measurements at all costs. They can disrupt any control process and cause serious damage. You can prevent this by adding a voltage divider of two 1M (or more) resistors to keep the A0 around midpoint.If the ACS changes the 1M are neglectable, if the ACS is disconnected, the two resistors take over.

    5V ------[ 1M ] ------A0------[ 1M ]------GND
                           |
                           |
                          OUT

Another trick is to use only one 1M pull down resistor. That would give automatic extreme values that

The first one is the most safe as the error state is explicit definitely different from "normal" values.


Minimized your test code to a simple loop, to make it more understandable.

//
//    FILE: OVEN_CONTROLLER_PRODUCTION_V5.ino
//    AUTHOR: Ian Knight
//    PURPOSE: Testing Data
//    DATE: 2022-26-Aug.

#include <LiquidCrystal.h>
#include "ACS712.h"// Current sensor

//#define ACS_Pin A0
#define ACS712_CURRENT_SENSOR_ANALOG_PIN               A0
#define ADJUSTABLE_MAX_CURRENT_ANALOG_PIN              A1
#define MEAN_ACS712_SAMPLES_SETS                      10
#define STATE_COUNTER_TICK_RATE                       100// in mS
#define HYSTERESIS_CURRENT_IN_MA                      100
#define OUTPUT_TEST_PIN                               8

ACS712 ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN, 5.0, 1023, 100);

const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

long MaxmA = 0;       // Adjusted maximum current
float MeanmA = 0.0;   // AC721 Mean Current New for multi cycle samples
unsigned long PreviousMillis = 0;

void setup()
{
  // set up the LCD's number of columns and rows:
  Serial.begin(9600);

  lcd.begin(16, 2);         // Init LCD

  pinMode( OUTPUT_TEST_PIN , OUTPUT);
  digitalWrite( OUTPUT_TEST_PIN , LOW );

  ACS.setmVperAmp(99);      // To set the calibration for ACS712 deviation
  ACS.autoMidPoint();       // Init ACS712
}

void loop()
{
  MeanmA = 0.0;

  for (int i = 0; i < MEAN_ACS712_SAMPLES_SETS; i++)
  {
    while (millis() - PreviousMillis < STATE_COUNTER_TICK_RATE);
    PreviousMillis = millis();

    digitalWrite( OUTPUT_TEST_PIN , HIGH );
    //..   MeanmA += ACS.mA_AC( 50.0 );
    MeanmA += ACS.mA_AC_sampling( 50.0, 4);
    digitalWrite( OUTPUT_TEST_PIN , LOW );
  }
  //  calculate the average
  MeanmA /= MEAN_ACS712_SAMPLES_SETS;

  lcd.setCursor(0, 1); lcd.print("                "); // Clear Line 1
  lcd.setCursor(0, 1); lcd.print( "Cur mA's: "); lcd.print( MeanmA );
}    // End loop()

// **** END OF FILE ****
imk2021 commented 2 years ago

Hello Rob,

I think these development versions of ACS712 library have confused my system:

As IDE 1.8.19 says  0.2.7 is installed But IDE 2 RC 9.2 says 0.2.8 is installed, however when i try to uninstall 0.2.8 from IDE 2 RC 9.2 it reports 0.2.8 is not installed

Hence I am not sure when I build in IDE 2 RC 9.2 which ACS712 library i am building with. However I can't see in the arduino library folder tree 0.2.7 or 0.2.8 so I think they are not there but the IDE's still think they are :-) Ain't Computers Wonderful!

Now i have done a file search and can see your ACS712-develop library has a sub folder under arduino and had I a look at the .h and .cpp and they look the same as the unzipped version off 0.2.8 you say you have have added a noise filter to. I

So i think before we test further this library version confusion needs to be sorted and I don't know how the arduino library structure is managed.

Also OVEN_CONTROLLER_PRODUCTION_V5.ino that i am currently testing with drifts. Inasmuch as MeanmA from a cold start or reset will drift from an initial 50mA to 180mA after an hours or so with zero current flow thru the ACS712.

Have a good evening Ian

RobTillaart commented 2 years ago

Think your project setup is affected by noise. You could check with a scope.

the arduino website has an excellent tutorial on libraries. They should be in your personal Arduino folder under libraries. Check preferences in the IDE.

All my libs have a version string, see the .h file Add Serial.println(ACS712_LIB_VERSION); It is most of the examples. That should help guard versions.

It is now 6:15 and later today I will merge 0.2.8 and release it as last results are good. (Not perfect).

Thereafter i want to start with a 0.3.0 soon which will change return types. Mainly from int to float to improve precision. Add some analysis functions, most of that is already written, so can be online almost directly after 0.2.8 is released.

Noise suppression is a topic / issue on its own. That will be investigated for 0.3.x

RobTillaart commented 2 years ago

@imk2021 Can you open a separate issue on the noise level at ZERO amps?

RobTillaart commented 2 years ago
imk2021 commented 2 years ago

Morning Rob, Later when 0.2.8 is released i'll retest all so we have a fresh starting point. Ian

RobTillaart commented 2 years ago

Good morning!

0.2.8 is released, but possibly not available yet in the library manager.

In the develop branch you can now find the preview of the 0.3.0 version (had some build issues).

imk2021 commented 2 years ago

Rob,

ACS712 is wired to Nano thus.

ACS712 0V to Nano 0V ACS712 5V to Nano 5V ACS712 Out to Nano A0, no other circuitry I just plug in a flying lead if I want to BREMEN or Scope it All just jumper-ed on breadboard

Ian

imk2021 commented 2 years ago

Hello Rob, please find the attached test results:

This data is from a 1kW fan heater so may have slight motor inductive influence

measure with BRYMEN                                    4.594A measure with mA_AC();                                   4.437A measure with RMS_by_sampling();

22:22:42.444 -> 20000 22:22:42.444 -> 0.04888 22:22:42.444 -> 2254.11108 22:22:42.475 -> 20000 22:22:42.475 -> 0.04888 22:22:42.475 -> 2237.93579 22:22:42.514 -> 20000 22:22:42.514 -> 0.04888 22:22:42.514 -> 2237.94189 22:22:42.550 -> 20000 22:22:42.550 -> 0.04888 22:22:42.550 -> 2245.92211 22:22:42.583 -> 20000 22:22:42.583 -> 0.04888 22:22:42.583 -> 2262.14453 22:22:42.623 -> 20000 22:22:42.623 -> 0.04888 22:22:42.623 -> 2254.09643 22:22:42.659 -> 20000 22:22:42.659 -> 0.04888 22:22:42.659 -> 2245.93359 22:22:42.691 -> 20000 22:22:42.691 -> 0.04888 22:22:42.691 -> 2221.63159 22:22:42.731 -> 20000 22:22:42.731 -> 0.04888 22:22:42.731 -> 2230.03393 22:22:42.767 -> 20000 22:22:42.767 -> 0.04888 22:22:42.767 -> 2254.08618 22:22:42.800 -> 20000 22:22:42.800 -> 0.04888 22:22:42.800 -> 2254.08105

I will be at home tomorrow doing the domestic stuff so can test if you require. Hope that helps have a good evening Ian.

RobTillaart commented 2 years ago

No direct tests in mind. As this issue is closed, we might better communicate in issue #23 ?

2254.08105 that looks like exactly a factor 2 from the Brymen...

imk2021 commented 2 years ago

Hello Rob,

I just thought of an alternative way to using real hardware/embedded micro  etc to test your mA_AC() function to deal with complex waveform.

Basically use VS2022 community (free) and write a couple of simple console apps; one to generate a sine wave into an array and or file. The second is a modified  version of mA_AC() that replaces analogRead() with read from the array or file record analogReadRecord( n ). Now you can prove your math really easy without having to upload etc plus you have a really nice full function debugger in VS2022. Once this basic mechanize is working you can tweak the sine generator app to create  sine files of different magnitudes. You can now hack these sine files where you set to zero some records so you create a modified sine similar to a dimmed sine. And or tweak record to have big noise spikes in them. You can then view the sine files in Excel to check the shape of the etc. Then just cross compile the VS2022 cpp back into Auduino cpp and test.

I have used this method in the past when using accelerometers to do tricky math motion analyses. It works and is much quicker than coding into a tricky to debug micro-controllers.

Ian

imk2021 commented 2 years ago

Hello Rob,

Please ignore subject title Professor Jack Stilgoe, this was a copy paste error as i was reading his work on autonomous car.

Ian

imk2021 commented 2 years ago

Hello Rob,

I think you will like these results, however i had to hit NANO reset to clear drift during 500w Dimmed testing, I will look into this later

Ian

Test Set Four 28-Aug-2022 1300 mA_AC_sampling() 40 calls per sec. OVEN_CONTROLLER_PRODUCTION_V5 released library version 0.2.8

ACS712 Calibration load 1000w Brymen 4476mA

ACS712  ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 101 );        MeanmA=4310 ACS712  ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 100 );        MeanmA=4365 ACS712  ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 99 );        MeanmA=4412 ACS712  ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 98 );        MeanmA=4443 ACS712  ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 97 );        MeanmA=4480

Therefore all test result below where at  ACS712 Calibration value of 97

Other Load Testing Below:

Not Dimmed 100w  Brymen=0.426  MeanmA=458.2 200w  Brymen=0.823  MeanmA=883.5 300w  Brymen=1.248  MeanmA=1281.9 500w  Brymen=2.048  MeanmA=2067.5 1000w Brymen=4.485  MeanmA=4471.8

200w Dimmed Brymen=0.48    MeanmA=477.5 Min Dim Brymen=0.6     MeanmA=591.9 Brymen=0.703   MeanmA=694.5 Brymen=0.816   MeanmA=800.5 Max Dim

500w Dimmed Brymen=1.188   MeanmA=1176.2 Min  Dim Brymen=1.301   MeanmA=1285.1 Brymen=1.400   MeanmA=1376.4 Brymen=1.501   MeanmA=1481.0 Brymen=1.603   MeanmA=1585.0 Brymen=1.704   MeanmA=1671.5 Brymen=1.806   MeanmA=1777.7 Brymen=1.906   MeanmA=1894.3 Brymen=2.000   MeanmA=1974.4 Brymen=2.028   MeanmA=2000.5 Max  Dim

RobTillaart commented 2 years ago

Those numbers look almost perfect. they are almost all within a 1% range which is pretty OK. you can tune the mVperAmpere parameter with decimals, e.g 96.28

```ACS712 ACS( ACS712_CURRENT_SENSOR_ANALOG_PIN , 5.0, 1023, 96.3 );````

RobTillaart commented 2 years ago

I just thought of an alternative way to using real hardware/embedded micro etc to test your mA_AC() function to deal with complex waveform.

I did test my concept-code in Excel in a similar way. filled data of a sinus with a defined noise. and a certain sampling rate and compared the different methods.

Using the real code as you propose was also done. In fact that code is lying around to make an ACS class with an external ADC. Thinking of an MCP49xx (SPI based ADC) which is much faster and would to preprocess while sampling.