ESP8266-12E running in to overflow when trying to calculate RMS


I’m trying to build my first Arduino project, and have learned a ton from this site and it’s forum. However I seem to be stuck, so hoping someone could have a look at what I’m doing wrong. Pardon any wrong terminology here…

I’ve got a NodeMCU ESP8266-12E, and an ads1115 16-bit (differential mode) hooked up with my SCT-013-000 (22Ohm burden resistor). So far so good, I’ve got various test-sketches to see that I’m actually reading data and it seems pretty reasonable.

ads1115 running on 3.3V from the esp8266-12E, and its set up with gain=1 meaning it’s measuring +/-4.096V and the resulting count should be -32768->32765

Quite a few of my samples are -31869, and I’m suspecting the minijack-barrel on my breadboard which is poorly fastened. Still my main issue is the sum in my sketch is returning as “ovf” which I’ve found out is overflow when its passing 2^32. I dont see how I can avoid this if I want any reasonable amount of samples, and its stored as the sum of the squared samples. (Is the ovf just happening in the serial output?)

Here is my current sketch which is likely a poor mix of code, but it’s a result of combining some code from the emonlib library, and some previously ported code from that library which I’ve found. I’ve added various points of serial output to troubleshoot now.

Which outputs something like this, and the resulting calcuation ending at 209A which obviously is far off:

Anyone care to point me in the right direction or want to tell me what I’m doing wrong here? Thanks! :slight_smile:

Please look at the top paragraph in the FAQ. I have increased your trust level, so you can upload your code here. I do not look at external sites.

You will probably need to move to larger variables to store the sums of squares. You can gain 1 bit by using unsigned (a square can never be negative), so the choice of integers is unsigned long or uint64_t. You should use the smallest that will hold the biggest number that you expect, because working with big numbers (32-bit or 64-bit) is slow.
If you don’t mind losing precision (which may not in fact have any serious disadvantage to you), you could use floating point variables for the sums - you’ll need to check for the ESP, but for the emonTx, ‘float’ and ‘double’ are the same.

Sorry about that. Sketch has been attached now.

Energy_Monitor.ino (1.8 KB)

I didn’t even consider having sum as float, as I’m not familiar with the differences. Found this answer regarding the question and my hardware over on another site:

The integer version does not support floating point operations nor does it allow non-integer numbers.

In the integer version 3/2 is 1 rather than 1.5.

The following file is the serial output going through calcirms(172) twice. Dont know if its of use to anyone.
sample (34.6 KB)

The answer you found is not complete, by any means. An integer variable can only contain whole numbers (1, 2, 3, 495, 8749, etc), a floating point variable can hold a decimal fraction (e.g 1.25, 39.702, 48119.6, etc)
When you convert a float to an integer, it must be smaller than the largest integer you can store. For an int, it must be in the range -32768 to +32767, and the decimal part is lost, so 1.25 is converted as 1, 39.702 is converted as 39.
When you go the other way, convert an integer to a float, that problem does not exist, but you have another one instead. If your integer is bigger than the precision of the float, then the least significant digits will become zero. So a big integer, 19875538407 will become (say - this is not a real example) 19875538000.

You have the wrong value for “supply voltage”. You should have the real voltage value there, probably 5.0 (or maybe 3.3), not the ADC maximum value. Your c.t and its burden resistor converted amps to volts, the ADC converted that to a number, now you’re converting numbers back to amps, and you need to know the relationship, which is the ratio Supply Voltage : counts!

Sorry, but that does not mean anything. I see you have double for the sums, when you put the correct value for supply voltage, does you sketch give you sensible results?

Thanks for the intro to float/integer. A float is not limited to 16 bit, correct? But is likely heavier for the processor to work with?

This is the result of reading (might be mis-reading) this archived thread from this forum. As far as I understand the calculations comes down to the ratio between supply-voltage and ADC_COUNT. I could either use 4096 & 32767 OR 3300 (which I’m running the ADC on) & 26 399 (which is (3300/4096)*2^15 -1)

This is a quote of you from the mentioned thread:

You can use 3300 and 26399 for SUPPLYVOLTAGE and ADC_COUNTS, or you can use 4096 and 32767.

The ads will use counts all the way up to the gain setting of 4.096V, but I can’t have more than 3.3V due to the input voltage.

Yeah I pretty much figured it wouldnt make sense to anyone but me (and doesn’t make much sense to me either). It was basically a part of my troubleshooting. In conclusion the two “series” of 172 samples through the calcirms function yielded 180A and 209A which is obviously wrong. I dont have a meter to calibrate it against unfortunately, but I could measure only certain circuits where the current should be fairly easy to measure.

Having looked again at your post, 4096 is correct as that is the voltage for 32767 counts. (32767 - 32768 makes no difference in practice.)

So what current do you think you had when it showed ~ 200 A? ICAL should be correct as it is the current that gives you 1 V across the burden resistor, and that is 90.9 A.

It might help to measure more than 172 samples. You only have 860 samples per second maximum, that’s about 17 samples per cycle of mains, so I would expect some variation between readings simply because you never read a complete cycle, it’s always a bit more, but you don’t know where that extra bit is in relation to the waveform - it could be near maximum or it could be across zero. Averaging over a longer period will smooth out those variations.

Thanks for helping out :slight_smile:

I know it’s pretty low, it was also part of my plan with troubleshooting to see the actual values, and spamming 1000 samples in serial output is not helpful. I know the ADC supports 860samples/s, but from reading around it seems to struggle above 800. And there are vasious info on wether 860sps is actually the default (might be 330). Is there a simple way I can check how long it takes to gather and process the set number of samples? This would also be helpful in trying to approach whole waves in 50Hz.

I did a test now with removing most of the serial output, and increasing samples to 1200, at the same time I manually counted blinks on my meter to actually have a rough approximation of the current I’m measuring.

The meter blinks turned out to be pretty accurately 3kWh, and at my voltage of 218VAC atm that should mean 13,76A current. The output from the attached sketch showed the sum to still be “ovf” and the calculated current was 111A, 119A and 215A for the three measurements I took (1200 samples, 10s wait between). This could mean I’m off by a factor of 10, but I’m not sure its that easy.

I see sqI and sumI are declared as “double”, which as far as I can tell should mean 64-bit that should be more than enough to cover the output I should be seeing.

test_serial_output.ino (2.0 KB)

Yes, it’s quite easy. The millis( ) function returns the time in milliseconds - as an unsigned long. So you get the time before you call calcIrms( ), and again when it returns, and subtract the first from the second. Now do the same but with (say) 100 more samples. Then the difference between the second answer and the first answer gives you the time for 100 samples, and does not include the time to start and stop the loop and process the result.
More on using millis( ) and solving a common problem (which you need not worry about here, but it’s useful to know) Arduino Playground - TimingRollover

That does not mean what I think you think it means. At the risk of your head hurting (a lot), look at this: Double-precision floating-point format - Wikipedia
In a double, the number is stored in two parts - the significand which is a fraction with 52 bits of precision (about 1 part in 10^16) and an 11-bit exponent (-1024 – 1023) that multiplies the fraction by 2 to the power of the exponent. And the sign bit, of course. So a huge number range. It cannot overflow for you. So the “ovf” error is coming from somewhere else.

You are using the ADC in differential input mode - is the second input tied to GND or to the midpoint bias voltage? I think, from what you wrote before, it is measuring the midpoint.

Using your current, the peak value of current should be about 214 mV at the ADC input, so 1712 counts. If you print the value of filteredI, you should see values centred on zero and varying between -1712 and +1712. OffsetI should be close to zero, but it might have some ripple (look with no current flowing).

Can you confirm those numbers?

I’ve run your sketch in an emonTx - with the ADC input calculated, and the maths works for me with no overflow. So I think you need to look at the numbers being generated by ads1115.readADC_Differential_0_1( )

It starts at:

Total sum of samples before calibration and RMS calculation
Utregnet str�m:

and when the filter has settled:

Total sum of samples before calibration and RMS calculation
Utregnet str�m:

My change to generate the false ADC output:

//    sampleI = ads1115.readADC_Differential_0_1();
    sampleI = 1712 * sin(n*0.184);

Just wanted to post an update in case anyone is following. I’m still getting “ovf”, and am still unsure why. I have however learned a lot today, and feel like I’m getting closer for each iteration :slight_smile:

The millis() call worked wonders to let me know I was having about 8.9ms delay between samples which is no good. This means I was just getting about 2 samples per sine, and was a result of the defaults in the ADS1015 library for my ADC. Editing this (conversiondelay and samplerate) got me down to just under 2ms which is a lot better, but I’m gonna try to go lower later.

I ran a couple of series where I output each sample to serial, and tried to pinpoint the ovf (before changing the sampling rate). 4 out of 6 series did not get sum “ovf”, and the calculated current seems to be pretty good (its in the right range, have to check it more later). In the 2 series that gave “ovf” I had some samples returning “-31869” which somehow seems like the lowest it can go (as opposed to -32768 that I expected), when squared and added to sum this causes the sum to overflow.

I’m not sure why I’m getting these samples, but I suspect a bad connection somewhere even though I haven’t been able to find any. The jack-barrel sits pretty loose in my breadboard, so I’m considering cutting the cable from my CT and putting some dupont connectors on there instead. Could also be my soldering on the ADC. Maybe something I misunderstood about the differential measurements, but that should be consistent instead of the on/off I’m seeing here.

My last series testing sample rate all returned ovf and wrong currents instead of the 4/6 hit-rate I got earlier (I didnt print all samples to serial here). Definitely pointing towards poor connection somewhere.

I too believe it to be the midtpoint, but I’m not sure.

Yea that seems about right when I’m not hitting the -31869 values that is giving overflow. The attached xlsx file for anyone interested show the output of my 6 series, and the 3 different runs testing sampling rate.

EDIT: Forgot attachement
sample (114.3 KB)

EDIT: On the one hand I think I figured out that the error/loose connection was in my soldering, which is good to know. On the other I broke the PCB trying to re-solder, so now I have to wait for a new one :confused: