Electric Imp and Non-invasive AC current sensor

What is the current sensor hooked to?

One other question is timing. The code seems to be self-timed and so is likely to be running at a totally different speed on the arduino and imp. Are you trying to measure a single cycle?

@mlseim
i use this sensor: YHDS SCT-013-000. Works fine with the arduino uno.

@Hugo
i tried it without luck. i get with the same perfboard absolut different values on the arduino and the imp.

@Hugo
The code does about 75 reads per cycle (at 60Hz). The request is for 1480 samples so it measures about 20 cycles.

…and how many does it do on an arduino?

The code looks comparable to the arduino version, but it’s rather hard to debug remotely. With no load do you get a near-zero value like you should?

… approximately 106 samples of current in each cycle of mains at 50 Hz. 1480 samples therefore works out at 14 cycles of mains:
http://openenergymonitor.org/emon/node/846

I think the problem is in this statement:
I_RATIO = 90.90 * ((hardware.voltage() / 1000) /65535.0);

The Arduino code looks like this:
`
SUPPLYVOLTAGE = readVcc();
I_RATIO = 90.90 *((SUPPLYVOLTAGE/1000.0) / 1023.0);

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
long EnergyMonitor::readVcc() {
long result;
#if defined(AVR_ATmega168) || defined(AVR_ATmega328)
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(AVR_ATmega32U4) || defined(AVR_ATmega1280) || defined(AVR_ATmega2560)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1125300L / result; //1100mV*1023 ADC steps
return result;
}
`
I can’t figure out what readVcc() does but it returns about 2270 without load and changes with load.
Hugo, can you comment on readVcc() and suggest an Imp solution for it?
Thanks.

osherl: the arduino hasn’t such a nice hardware.voltage() function like the imp and so you can’t do accurate ADC readings without knowing the exact supply voltage. Some Guy found a way how to work out what the supply voltage must be and the result is the code above.

@Chrischi
readVcc() returns around 2270, I would expect around 5 or 5000. It must be doing something else… Hugo will tell us :slight_smile:

@osherl
in my case it reads exactly what it should… 5028 or 5051 and that means 50xx/1000 = 5V

i am sure that function has nothing to do with the eimp problem.

@Chrischi
I think I finally got it!!! Move all the local variable definitions out of the function to global level. Looks like one of the variables in the for loop does not retain it’s value after it leaves the loop…
Anyway, the readings are more accurate than on the Arduino… Please try and let us know.

@bonded104 that’s a bit strange. Have you got the “before” and “after” code we can look at? I didn’t see any scoping issues in the code segment posted above. If something fell out of scope you should see an error…

@bonded104
i will try, because i really don’t know whats wrong. I did before some debuging without the function and it hasn’t changed anything. Would love to see your code.

just fyi:

this is what the arduino shows (4 windings of a 40W light bulb, energymeter 38,7):
Irms*230 Irms
153.85 0.67
152.79 0.66
151.47 0.66
151.66 0.66
153.41 0.67
153.25 0.67
151.04 0.66

and with the imp i get the same value (with AND without load), not nearly what it should like above.

edit:
i looked a bit at the basic configuration and it shows that pin 1 which i’am actually using is giving absolut wrong values.

local voltage = hardware.voltage()/65536.0;
server.log(hardware.pin1.read()*voltage);
server.log(hardware.pin5.read()*voltage);
server.log(hardware.pin9.read()*voltage);

gives the following:
0.322121
1.65021
1.65101

i measured pin1 with a voltmeter and it shows 1.6V.
i think pin1 is damaged!? any test to proof this?

now i will try the code with the other pins…

after changing the pin1 to another it works!!! Tested it on all other pins, only pin1 doesn’t work.

Here is my working Code:

`
// Energy Monitor for April Board

hardware.pin5.configure(ANALOG_IN);
hardware.pin7.configure(ANALOG_IN); //future use ;3-Phases
hardware.pin8.configure(ANALOG_IN); //future use ;3-Phases
Irms <- 0.0;

function current()
{
local voltage = hardware.voltage();
local calibration = 82.95; // change to your sensor specs
local samples = 1480;
local ratio = 0.0;
local sample = 32767.5; // 65535/2 to see nice values at first run
local lastSample = 0.0;
local filtered = 0.0;
local lastFiltered = 0.0;
local sq = 0.0;
local sum = 0.0;

for (local n = 0; n < samples; n++)
{
local lastSample = sample;
sample = hardware.pin8.read();
lastFiltered = filtered;
filtered = 0.996*(lastFiltered+(sample-lastSample));
sq = filtered * filtered;
sum += sq;
}

ratio = calibration*(voltage/65535.0);
Irms = ratio * math.sqrt(sum / samples); 

sum = 0.0;

return Irms;
}
`

@Hugo
any idea to test pin1?

@Hugo
Here is my “after” code:
const NUMBER_OF_SAMPLES = 1500.0; // 20 cycles const ICAL = 100.0; // 100 A / 50 mA / 20 Ω = (100 / 0.050) / 20 = 100.0 sampleI <- 0.0; lastSampleI <- 0.0; filteredI <- 0.0; lastFilteredI <- 0.0; sqI <- 0.0; sumI <- 0.0; function calcIrms() { for (local n = 0; n < NUMBER_OF_SAMPLES; n++) { lastSampleI = sampleI; sampleI = hardware.pin2.read(); lastFilteredI = filteredI; filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI); // phase correction algorithm sqI = filteredI * filteredI; // root-mean-square method current (RMS) sumI += sqI; } local I_RATIO = ICAL * ((hardware.voltage()) / 65536.0); local Irms = I_RATIO * math.sqrt(sumI / NUMBER_OF_SAMPLES); sumI = 0; server.log(Irms +" "+ Irms * 120.0); // Irms and apparent power imp.wakeup(1, calcIrms); } hardware.pin2.configure(ANALOG_IN); imp.configure("Power", [], []); calcIrms();
and the “before” code:
function calcIrms() { const NUMBER_OF_SAMPLES = 1500.0; // 20 cycles const ICAL = 100.0; // 100 A / 50 mA / 20 Ω = (100 / 0.050) / 20 = 100.0 local sampleI = 0.0; local lastSampleI = 0.0; local filteredI = 0.0; local lastFilteredI = 0.0; local sqI = 0.0; local sumI = 0.0; for (local n = 0; n < NUMBER_OF_SAMPLES; n++) { lastSampleI = sampleI; sampleI = hardware.pin2.read(); lastFilteredI = filteredI; filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI); // phase correction algorithm sqI = filteredI * filteredI; // root-mean-square method current (RMS) sumI += sqI; } local I_RATIO = ICAL * ((hardware.voltage()) / 65536.0); local Irms = I_RATIO * math.sqrt(sumI / NUMBER_OF_SAMPLES); sumI = 0; server.log(Irms +" "+ Irms * 120.0); // Irms and apparent power imp.wakeup(1, calcIrms); } hardware.pin2.configure(ANALOG_IN); imp.configure("Power", [], []); calcIrms();

@Chrischi
I tried your code and it’s giving me wrong results on every pin. Again, moving out the variables to global level fixes the issue (on every pin). I plugged in a 1500W electric heater and my Irms * 120V is very close to 1500…

@Chrischi
In your code only the local sample = 32767.5;variable definition has to be on global level to see the change, especially with no load. Try it without load, see if you notice any difference.

@osherl
your code is giving me the same results as mine also on pin1. :-/

i reworked a little bit and i think this will do it for everyone:

`
// Energy Monitor

hardware.pin5.configure(ANALOG_IN); // change to your analog input pin
Irms <- 0.0;
sample <- 0.0;

function p1()
{
local voltage = hardware.voltage();
const calibration = 82.95; //
const samples = 1480;
local ratio = 0.0;

local filtered = 0.0;
local lastFiltered = 0.0;
local sq = 0.0;
local sum = 0.0;

for (local n = 0; n < samples; n++)
{
local lastSample = sample;
sample = hardware.pin5.read(); // change this according to your input pin
lastFiltered = filtered;
filtered = 0.996*(lastFiltered+(sample-lastSample));
sq = filtered * filtered;
sum += sq;
}

ratio = calibration*(voltage/65536.0);
Irms = ratio * math.sqrt(sum / samples); 

sum = 0.0;

return Irms;
}

function capture( )
{
local p1 = p1(); // measure phase1
server.log(p1*230 +" "+ p1); // change this if you are using another voltage
imp.wakeup(0.5, capture);
}

imp.configure(“Energy v0.01”, [], []); // Register with the server
capture();
// End of code.
`

@osherl
which is the minimum current you can measure?

@Chrischi
About 0.20… The code looks good! I enjoyed working with you on this issue.
@Hugo
I still don’t understand why “sample” variable behaves like that (results change if moved inside the function).