Community
OpenEnergyMonitor

OpenEnergyMonitor Community

EmonLib (Current only) IRMS value not right - Can anybody help me see what I am doing wrong

Can anybody help me understand what I am doing wrong to get these inaccurate numbers.
Please (Any help gratefully received!!)

Problem: Using the basic Current_Only sketch and example hardware on a breadboard, my reading for IRMS is 3.94 for a 1500watt blow heater (US voltage of 120) so I tweaked the calibration number and burden resister values as shown below. But I am still not getting accurate IRMS numbers.

Details:

  1. I have the ‘out of the box’ Current Only Sketch.
  2. Changed double Irms = emon1.calcIrms(1480); to double Irms = emon1.calcIrms(1676);
  3. Changed Serial.print(Irms240.0) to be Serial.print(Irms123.0); // Apparent power
  4. Changed emon1.current(1, 111.1); to emon1.current(1, 350); gives better but still not accurate results (see below table)

My CT is a YHDC SCT013 100 Amp / 50mA device
My Arduino is an Adafruit M4 Airlift Lite
My Burden resister is 27 Ohm
Calculations to get to 27 Ohm:
• The voltage from M4 3.3v output on the M4 Airlift measures at 3.89 with my multimeter
• Primary peak-current = RMS current × √2 = 100 A × 1.414 = 141.4A
• Secondary Peak Current = Pri Peak Current / Num Turns : 141.4 / 2000 = 0.070711
• Burden resistance = (AREF / 2 ) / Secondary Peak Current so for me = (3.89/2) / 0.070711 which = 27.29
• My Voltage divider is 22k resisters (Voltage measured at divide = 1.99)

Table of tests (Attached file is prob easier to read)Power_testResults.csv (1.8 KB)

Serial Monitor Output (average of about 20 readings for each ‘test’)

    	 				Apparent   IRMS	Calibration
					     Power			Number (in sketch)
1500 Watt Heater		485.72	   3.94		111.1
90  Watt Heating pad     39.16	   0.31		111.1
50 Wat Heating Pad	     19.8	   0.16		111.1
No load				      8.77	   0.07		111.1
1500 Watt Heater	   1827	      14.85	    375
90  Watt Heating pad	132		   1.07		375
50 Wat Heating Pad	     68.3	   0.55		375
No load				     28.44	   0.23		375
1500 Watt Heater	   1515	      12.32	    360
90  Watt Heating pad	127		   1.03		360
50 Wat Heating Pad	     61.6	   0.501	360
No load				     26.97	   0.21		360
1500 Watt Heater	   1473	      11.98	    350
90  Watt Heating pad	123.3	   1		350
50 Wat Heating Pad	     59.34	   0.48		350
No load				     26.64	   0.21		350
1500 Watt Heater	   1269	      10.31	    300
90  Watt Heating pad	105		   0.85		300
50 Wat Heating Pad	     54	       0.44		300
No load				     23.58	   0.19		300

Note: The values of each device are only what is printed on thee device, so not proven as accurate.

EmonLib (I assume you’re using emonLib and not emonLibCM) wasn’t designed for the processor - and probably more importantly the ADCs that it has - that you’re using, so the first step will be to confirm the ADC reference voltage and the count at that voltage - assuming it is single-ended.

That looks as if it might be 3.89 V and 12 bits, if that’s the case, then look near the top of the emonlib.h file, and make sure that #define ADC_BITS 12 is live (it’s probably easiest to comment out the if - else condition) to set it for a 12-bit ADC, and then in emonLib.cpp about ¾ down change
int SupplyVoltage=3300; to int SupplyVoltage=3890;
and likewise remove the if ... else around it.

Everything should then come a lot closer. The calibration constant is the current that would give 1 V at the ADC input - given your components, I make that 74.07

[Edit]
You need to confirm the analogue voltage input range from the data sheet for your Arduino clone, because having now got the processor’s data sheet, I see the bandgap reference is nominally 1.1 V.

I think I’d prefer to believe the output rather than your meter - it’s an awful long way out for a regulated supply - assuming you’ve measured the right place.

Robert - Thank you so much for the speedy response!

I made the change to the ADC_BITS (I just commented out the if statement leaving the one define
I made the change to the Supply voltage in the .cpp file to =3890And made the change to the calibration constant to 74.07

Then did the one test with the 1500watt blower

The returned IRMS was 3.6

So I am going to assume I messed something up I will take a closer look tomorrow (right now I am so tiered I cant see straight!)

One thing is confusing me (And this is probably a dumb question!)
is : “The calibration constant is the current that would give 1 V at the ADC input”

I will look at the data I put in the post that you had to go on, then try and reverse into your 74.07 to see if I can work out what I should be measuring against (Sorry to be dumb!)

Thanks!! more on this tomorrow!

I really need to know details of the analogue inputs of your Arduino board. I’m deeply suspicious of your 3.89 V, and as I found after I’d replied earlier, the ADC resolution is under software control, so I need to know if Adafruit has changed that from the processor’s default.

My problem is we don’t use the board that you have, and I haven’t been able to find any useful information about it: the only “Technical details” on the Adafruit website appeared to be the size of the mounting holes - that’s so amazingly stupid it’s beyond belief. I’d have expected better of Adafruit.

The explanation of the calibration constant is really, there are three parts to converting the current into a meaningful number: the conversion of the current you’re measuring into a voltage at the ADC input, the conversion of that voltage into a pure number by the ADC, and finally scaling that number to become a meaningful current.

The middle part is baked into emonLib, but because you’re using a different ADC with different properties, it’s that which we need to change. The first part is defined by the choice of c.t. and burden, and the last part is what the calibration constant does.

Starting at the ADC input and working backwards, you have a 1 V signal. A current flows in the burden to generate this 1 V - that current is 1 V ÷ 27 Ω = 37.037 mA. A current needs to flow in the cable you’re measuring (actually the primary winding of the transformer) to give that 37 mA. The c.t. ratio is 100 A : 50 mA, so the primary current is 37.037 mA × 100 A ÷ 50 mA = 74.074 A. (The explanation in ‘Learn’ needs rewriting - you only need the peak-peak values to calculate the burden value, when you have that, you can use rms for scaling and all subsequent calculations.)

If you can’t turn up any useful information regarding the ADC, I might need you to do some experiments to measure it. What I need to know is the voltage that produces a count of zero out of the ADC, and the voltage that produces the maximum count out of the ADC, and what that number is.

Given the counts per volt, all you then need to do is multiply the number of counts that comes out of the averaging process in emonLib, which is sqrt(sumI / Number_of_Samples); about ¾ down the file, by a number that changes it to 74.074 A, which from the line above is ICAL (the 74.074 you tell it) times the volts per count.

Robert,

You were right to be deeply suspicious of the 3.89v reading (It seems my Multimeter sucks!!)
I took a handful of devices and measured the voltage of their 3.3 v and 5v outputs the below table shows the results

The summary is :

  1. When measuring 3.3 V my meter is off by 0.59 V
  2. When measuring 5.0 V my meter is off by 0.93 V
    (I grouped all the 3.3v devices and averaged, and all the 5.0 volt devices and averaged)

Does this help you understand what is going on ? (Other than my measurements being wrong)

Comparison Board / Device / Voltage Multimeter Reading Off by
Adafruit M4 Express Airlift Lite 3.3v Output 3.88 0.58
Adafruit Huzzah Feather ESP32 3.3V 3.9 0.6
Adafruit Feather 32u4 3.3V 3.94 0.64
Raspberry Pi 4 3.3V 3.87 0.57
Raspberry Pi Zero 3.3 V 3.95 0.65
Generic 3.3v mini regulator 3.84 0.54
Adafruit M4 Express Airlift Lite 5v Output 5.96 0.96
Raspberry Pi Zero 5 V 6 1
Raspberry Pi 4 5V 5.84 0.84

Multimeter_VoltageComparison.csv (578 Bytes)

That meter just added confusion. If you’d given me a number 2% out, I wouldn’t have questioned it. 4.095 ± a few percent and I wouldn’t have questioned that either (it’s used as a reference for obvious reasons). But your number for what stood a good chance of being 3.3 V was just too far out - something like 18%? It’s even 5% out if the reference was 4.095 V, which is high for a d.c. voltage error. Most meters have their best accuracy on the d.c. voltage range, of around 1 - 2% - even a £7 ($9) one from Amazon claims better than 1% (though I’m a bit suspicious of that too - it misses out the “+ n digits” bit).

I still need to know how Adafruit have set up the ADC on your Arduino board. That’s going to be the key to sorting out the calibration.

(I ought to update the page in ‘Learn’ about multimeters.)

Robert - sorry for delay…

I deffo appreciate your time and insight on this :smiley:

On the Multimeter topic : I bought a Klein Tools MM400 today.
It is yielding results within less than a 1% deviation (example 3.03 V instead of 3.89v the old meter measured)

The next test was to determine what the ADC produced when 1volt was measured at the Input pin
I used a pair of resisters to yield a measured voltage at the pin of 1.027V - Is this close enough to 1V or should I see if I can get closer to the 1.0 you mentioned?

With 1V at Pin A1, I measured the ADC value once every 50millis

  1. On The Adafruit M4 Express the averaged ADC output was 325.6774 (Actual voltage at pin was 1.0.28)
    1.a When the pin was tied to ground, the ADC produced 2
  2. I ran the same code, same circuit on a Adafruit Feather ESP32 the averaged ADC output was 1185.96 (Actual voltage at pin was 1.0.28)
    2.a. When the pin was tied to ground, the ADC produced 0

See attached file for test results
1Volt - ADC :ADC_Value_With_Voltage_At_1v.csv (2.5 KB)

Multimeter test results :3point3Volt_Multimetertest_WithNewKlein.csv (756 Bytes)

That doesn’t look too bad at all. The numbers it produces are close enough to let me make a good guess at what’s going on.

Let’s assume the ADC input goes from 0 V to 3.3 V: those numbers tell me that the Adafruit M4 Express has a 10-bit ADC with a max count of 1023 (the same as our emonTx and Arduino Uno), and the Adafruit Feather ESP32 is going to be a 12-bit ADC counting up to 4095. (Even though your numbers aren’t totally consistent with those: if I take the first, 324 counts represents 1.028 V, so 1023 will be 3.246 V - close enough to 3.3 V (not 3.03 as you measured), and for the second: 1186 counts from 1.028 V gives 3.55 V - not so close but I still think it will have a 3.3 V input range.

So, which are you going to use: If you use the Adafruit M4 Express, you should be able to use emonLib as it came with no changes. If you use the Adafruit Feather ESP32, then you need to keep the change to use the 12-bit version wit a max count of 4095, but you must change the voltage reference back to as it was at 3300.

Here’s the source code: https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/wiring_analog.c#L134

1 Like

I still think I wouldn’t buy anything from there if they can’t put the spec. on the shop page of the website, or even a link to it.

It looks as if @GerardM has got a lot of programming to do if he wants to convert emonLib to run with that.

Am going to use the M4 Express (Edit: I am going to try and use the M4 express )
I just changed the .cpp .h files back to standard

With a better multimeter reading and the info on the ADC at 1v what are your thoughts on the calibration value?

Thanks

I would interpret that as “no change to normal”. Their’s is not the first SAMD Arduino and the SAMD Arduino analog reference voltages are well documented at the usual place: https://www.arduino.cc/reference/en/language/functions/analog-io/analogreference/

If you use the Adafruit M4 Express, and emonLib is back as it was, then you can use the maths a few post back: 1 V at the ADC input will be the result of 37 mA, and you get that from a primary current of 74 A. So the calibration constant should be 74.074. Bear in mind that component tolerances - the actual c.t. ratio, value of your burden and the ADC reference voltage - may mean that’s wrong by a few percent.

Robert I must be doing something wrong :frowning:Thank you for your patience for even reading this far!

I deleted the library folder (EmonLib-master)
Unzipped it again
Shutdown the Arduino IDE
Went to the examples folder and opened Current_Only example
Changed the voltage from 240 to 120 and the calibration to 74
Turned on my 1500 Watt blow heater
And the numbers in the Serial Monitor are
310 (for pwr) and 2.5 for IRMS
(example : 18:48:59.186 -> 310.14 2.52)

My burden is 23 Ohms (I changed it based on the new multimeter readings)

If your patience hasnt worn thin with my mistakes - where would you suggest I focus my attention?

// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include "EmonLib.h"                   // Include Emon Library
EnergyMonitor emon1;                   // Create an instance

void setup()
{  
  Serial.begin(9600);
  
  emon1.current(1, 74.1);             // Current: input pin, calibration.
}

void loop()
{
  double Irms = emon1.calcIrms(1480);  // Calculate Irms only
  
  Serial.print(Irms*123.0);	       // Apparent power
  Serial.print(" ");
  Serial.println(Irms);		       // Irms
}

The first step is to recalculate the calibration based on the new burden value.

The second is to check that you have your analogue circuit correct. I presume you have a “breadboard” prototype connected to your Arduino board.
Is the circuit that of the figure on this page in ‘Learn’ (bearing in mind that assumes a 5 V Arduino): Learn→Electricity Monitoring→CT Sensors→3. Interfacing with an Arduino→CT Sensors - Interfacing with an Arduino
Is the mid-point voltage (i.e. the d.c. voltage on the c.t. when there’s no a.c. current flowing) exactly (to within about 2-3%) half the ADC reference voltage?

Third will be to change the number of samples you average over (“1480” in the call to calcIrms( ). That’s wrong anyway, even for the Atmel328P (because we’ve speeded up emonLib), but it’s probably even more wrong for your processor. And I’ve no idea what it should be - you’ll have to find out by timing the sketch. Here’s how:

Put this just before and just after the call to calcIrms( ):

unsigned long first, now = millis();
double Irms = emon1.calcIrms(1480); // Calculate Irms only
first = millis() - now;

then repeat that with the number of samples changed and do the sum so that you get the difference for the changed number of samples (so you cancel out the overhead of processing the batch of samples):

now = millis();
Irms = emon1.calcIrms(2480); // Calculate Irms only
Serial.print("1000 samples = ");Serial.println(millis() - now - first);

And if I haven’t made a silly mistake, you’ll get the time for 1000 samples. If it’s only a few milliseconds, change the “2480” to something a lot bigger. You’re aiming to find how many samples you get in 3 or 6 cycles of mains - 50 or 100 ms for you, but as time comes as integer milliseconds, aim to get at least 500 ms worth of samples.

I am all over this!!
:slight_smile:

When my wife goes to sleep I will sneak back to my office … :slight_smile:

Erm… There was a silly mistake in my last post - corrected now. Running that on an emonTxV2, I get anything between 172 and 186 ms per 1000 samples.

Steps 2 and 3 I was ok with, I failed on step 1 - sorry!

The first step is to recalculate the calibration based on the new burden value.
I used the formula [ Burden Resistor (ohms) = (AREF * CT TURNS) / (2√2 * max primary current) ] : This came to 23.3 Ohms. I made up a Burden of 23.0 , based on a couple of resistors

I failed at the calibration step :frowning: (not understanding) (The last para from the post earlier up thread says)
“Given the counts per volt, all you then need to do is multiply the number of counts that comes out of the averaging process in emonLib, which is sqrt(sumI / Number_of_Samples); about ¾ down the file, by a number that changes it to 74.074 A, which from the line above is ICAL (the 74.074 you tell it) times the volts per count.”

(I may be way off base, but I think you are saying grab the IRMS number (line 202) , multiply it by X so that the result = the number I passed into ICAL)

I can see that

  1. Number_of_Samples = the number I provide on the line – double Irms = emon1.calcIrms(1480); ( I know we will change this number based on step 3 below)
  2. ICAL = the number I provide on the line – emon1.current(1, 74.1); (Just using the 74.1 number for now)
  3. I am not properly understanding ‘multiply the number of counts that comes out of the averaging process……’’ relating to the codeblock ‘calcIrms’ line 175
  4. And I am sorry, I am not making the connection ‘Counts per volt’ / ‘volts per count’

Second step : Confirm voltage at ‘mid point’ is half AREF
• I measured across the top of CT (on diagram) to ground rail I measure 1.646 (Pretty much bang on half of 3.303)
o (Positive rail and ground = 3.303) When I measure Grnd to AREF pin on Ardiuio I get 3.303
• I measured across burden and get 0.122V AC when the 1500 watt is blowing and 0.0 AC when no blower running

Third: Check / Change num samples
• in 3 or 6 cycles of mains - 50 or 100 ms for you, but as time comes as integer milliseconds, aim to get at least 500 ms worth of samples.

• I inserted your code
• With the number of samples set at 2480 : Num ms = between 41 and 43
• With the number of samples set at 4750 : Num ms = between 99 and 101
• With the number of samples set at 8000 : Num ms = between 199 and 201
• With the number of samples set at 17800 : Num ms = between 500 and 501

Example Serial monitor output
12:37:04.795 -> 17800 << This many samples took this many Ms > 500
12:37:04.795 -> 7.26 0.06
12:37:05.404 -> 17800 << This many samples took this many Ms > 501
12:37:05.404 -> 7.29 0.06

Code I used
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include “EmonLib.h” // Include Emon Library
EnergyMonitor emon1; // Create an instance

int NumSamplesAdjusted=17800;

void setup()
{
Serial.begin(9600);

emon1.current(1, 74.1); // Current: input pin, calibration.
}

void loop()
{
unsigned long first, now = millis();
double Irms = emon1.calcIrms(1480); // Calculate Irms only
first = millis() - now;

now = millis();
Irms = emon1.calcIrms(NumSamplesAdjusted); // Calculate Irms only
Serial.print(NumSamplesAdjusted); Serial.print(" << This many samples took this many Ms > ");Serial.println(millis() - now - first);

Serial.print(Irms*123.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms

}

Not to worry, that description/procedure you’re looking at, whilst accurate, is in practice unnecessarily complicated. I’ve given you the (practical) way to do it above. Here it is again, with the numbers changed:

Starting at the ADC input and working backwards, say you have a 1 V signal. A current flows in the burden to generate this 1 V - that current is 1 V ÷ 23 Ω = 43.48 mA. A current needs to flow in the cable you’re measuring (actually the primary winding of the transformer) to give that 43 mA. The c.t. ratio is 100 A : 50 mA, so the primary current is 43.48 mA × 100 A ÷ 50 mA = 86.86 A.
So the calibration constant is 86.96.
You only needed to go into the details if you had used the other processor, I can go through it again if you’re desperate. :wink:

OK, that’s good. It was worth the check, because if that was a long way out, it would give a non-linear response that would have us both fooled for a long time.

Is that when you put 2480 into NumSamplesAdjusted?

If so, I suggest (depending on how long a period you want to average over, setting the number of samples to 8900 (250 ms, or 15 cycles) or 10680 (300 ms or 18 cycles) - you can see the sum I’m doing. I’ve not checked the maths in emonLib closely - if you sample for too long and have too many samples, there’s a danger that the numbers will overflow.

Try your blower and see what you get.

I am such a DOLT! Yep the Calibration makes sense now :slight_smile:

Your question : Is that when you put 2480 into NumSamplesAdjusted ?
Yep: I set that variable to be 2480 then 4750, (a few more) then 17800 to get the returned time to be about 500ms

I just now put the Calibration value to 86.96, and the NumSamples to be 8900
(Full code is below)
I tested without anything running on through the CT, and got a 90% consistent 0.07 (occasionally 0.06)
I then turned the blower on…drum roll…wait for it…
and got a consistent 2.64 value for IRMS

Now that cant be right can it… cause 123V * 2.64 A = 324 Watts :frowning:

I would be happy if the blow heater was only running at 2.64 amps as that would lower my power bills…but… I fear thats not the case :wink:

Full code below :
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include “EmonLib.h” // Include Emon Library
EnergyMonitor emon1; // Create an instance

//int NumSamplesAdjusted=2840;
//int NumSamplesAdjusted=4750;
//int NumSamplesAdjusted=17800;
int NumSamplesAdjusted=8900;

void setup()
{
Serial.begin(9600);

emon1.current(1, 86.96); // Current: input pin, calibration.
}

void loop()
{
//orig double Irms = emon1.calcIrms(1480); // Calculate Irms only
unsigned long first, now = millis();
//double Irms = emon1.calcIrms(1480); // Calculate Irms only
//first = millis() - now;

//now = millis();
double Irms = emon1.calcIrms(NumSamplesAdjusted); // Calculate Irms only
//Serial.print(NumSamplesAdjusted); Serial.print(" << This many samples took this many Ms > ");Serial.println(millis() - now - first);

Serial.print(Irms*123.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms

}

Am starting to wonder if there is something wrong with my CT… I bought two of them (the same modle at the same time) I tried the other one and I get the same results. But I wonder if I have a pair of ‘clone’ CT’s that are not manufactured to the same standard ? They say YHDC on them and the part num looks correct (SCT013 100A 50mA)