nD-enerserve Forums
Current drift values - Printable Version

+- nD-enerserve Forums (https://forum.enerserve.eu)
+-- Forum: SmartPi (https://forum.enerserve.eu/forumdisplay.php?fid=1)
+--- Forum: SmartPi - English (https://forum.enerserve.eu/forumdisplay.php?fid=2)
+--- Thread: Current drift values (/showthread.php?tid=1345)

Pages: 1 2


Current drift values - markobursic - 20.06.2019

Hi, I don't fully understand the current measurement and why do I have offsets on each input.
1st: outcome = outcome - 7300why is this number subtracted? Is this line causing a zero drift on all current measurements?

2nd: 
switch c.PowerFrequency {



case 60:



rmsFactor = 3493258.0 // 60Hz



case 50:



rmsFactor = 4191910.0 // 50Hz





In the datasheet it says clearly: 

With the specified full-scale analog input signal of 0.5 V, the ADC produces an output code that is approximately ±5,928,256. The equivalent rms value of a full-scale sinusoidal signal is 4,191,910(0x3FF6A6), independent of the line frequency. If the integrator is enabled, that is when bit 0 (INTEN) in CONFIG[15:0] register is set to 1, the equivalent rms value of a full-scale sinusoidal signal at 50Hz is 4,191,910(0x3FF6A6) and at 60Hz is 3,493,258(0x354D8A). 

So, only when integrator is enabled you should change rmsFactor with respect of line frequency. The integrator should be enabled only when using Rogowski coil, but your product comes with current transformers, so integrator bypassed should be the default setting.

Source: https://github.com/nDenerserve/SmartPi/blob/master/src/smartpi/ade7878.go



func ReadCurrent(d *i2c.Device, c *Config, phase Phase) (current float64) {
command := make([]byte, 2)
switch phase {
case PhaseA:
command = ADE7878REG["AIRMS"] // 0x43C0 (AIRMS; Current rms an A)
case PhaseB:
command = ADE7878REG["BIRMS"] // 0x43C2 (AIRMS; Current rms an B)
case PhaseC:
command = ADE7878REG["CIRMS"] // 0x43C4 (AIRMS; Current rms an C)
case PhaseN:
command = ADE7878REG["NIRMS"] // 0x43C6 (AIRMS; Current rms an N)
default:
panic(fmt.Errorf("Invalid phase %q", phase))
}


var rmsFactor float64
switch c.PowerFrequency {
case 60:
rmsFactor = 3493258.0 // 60Hz
case 50:
rmsFactor = 4191910.0 // 50Hz
default:
panic(fmt.Errorf("Invalid frequency %g", c.PowerFrequency))
}

if c.MeasureCurrent[phase] {
outcome := float64(DeviceFetchInt(d, 4, command))
cr := CTTypes[c.CTType[phase]].CurrentResistor

var ccf float64
if c.CTType[phase] == "YHDC_SCT013" {
ccf = CTTypes[c.CTType[phase]].CurrentClampFactor
} else {
ccf = 1.0 / (float64(c.CTTypePrimaryCurrent[phase]) / 100.0)
}
// fmt.Println("CalibrationfactorI: ", phase, "  ", c.CalibrationfactorI[phase])
oc := CTTypes[c.CTType[phase]].OffsetCurrent
outcome = outcome - 7300
current = ((((outcome * 0.3535) / rmsFactor) / cr) / ccf) * 100.0 * oc * c.CalibrationfactorI[phase]
} else {
 current = 0.0
}
   return current
}



RE: Current drift values - markobursic - 29.06.2019

(20.06.2019, 13:10)markobursic Wrote: // outcome = outcome - 7300

Commenting this line in the ade7878.go definetelly removes the offset of -0.07 A.


RE: Current drift values - frank - 05.07.2019

I tried the same, but instead of -0.07A offset I get about +0.11A offset now.


RE: Current drift values - markobursic - 06.07.2019

(05.07.2019, 08:44)frank Wrote: I tried the same, but instead of -0.07A offset I get about +0.11A offset now.
I forgot to tell that I had also changed the transformation ratio of the current transformer 10x, to reduce the measurment range to 10A. My output was something similar to yours, 0.01A which multiplied by 10 would give 0.1A.


The application lacks of offset calibration routine. It would need to calculate offset coeficients AIRMOS, BIRMOS, CIRMOS, NIRMOS.

From ADE7878 manual:
Conduct offset calibration at low current; avoid using currents equal to zero for this purpose. (14) 

It is almost impossible to properly calibrate this instrument without having a reference current source. In my opinion a "non properly" method should give also good results:
1- Set all  xIRMOS registers to 0
2 - Without current present, make measutings of all AIRMS, BIRMS, CIRMS, NIRMS registers and compute mean value
3 - Calcultae xIRMOS registers and store values on disk
4 - Each starup set xIRMOS registers.

The implemented method of subtracting offset from xIRMS is not correct. 
( sin(omegat) + offset )^2  = sin^2(omegat) + 2*sin(omegat)*offset + offset^2
The mean value of sin(omegat) is zero so the result in xIRMS register is sqrt( mean( sin^2(omegat) + offset^2) )
Therefore the corrrect way to eliminate the offset is to subtract by use of xIRMOS register.

EDIT:
This is what I have tried:
current = ((((outcome * 0.3535) / rmsFactor) / cr) / ccf) * 100.0 * oc * c.CalibrationfactorI[phase]

(outcome * 0.3535) * cr * 100.0 * oc * c.CalibrationfactorI[phase] / ( rmsFactor * ccf)
outcome * 0.3535 * 7.07107 * 1.049084906 * 1.0 / (4191910.0 * 0.05)
outcome * 2.62231701701623997 / 209595.5
outcome * 1.2511323081918457075652864684595e-5‬

(outcome-7300) * 1.2511323081918457075652864684595e-5‬ = -0.07111431638511632
outcome = -0.07111431638511632/1.2511323081918457075652864684595e-5 + 7300;
outcome = 1616

Irms = sqrt(Irms0^2 + 128* IRMSOS)
Irms^2 = Irms0^2 + 128* IRMSOS
IRMSOS * 128 = Irms^2 - Irms0^2
IRMSOS = 1616^2 / 128 = 20402
IRMOS = 4F B2 (hex)

In fuction InitADE7878 I have uncommented the existing write AIRMOS register line and put my coefficients 4FB2, also commented the line outcome=outcome-7300.

err = WriteRegister(d, "AIRMSOS", 0x00, 0x00, 0x4F, 0xB2)
if err != nil {
panic(err)
}

The result is : I1=0.12A, I2=0.12A, I3=0.12A

EDIT2:

I did changed coefficients to see if it has any influence on result:
err = WriteRegister(d, "AIRMSOS", 0x00, 0x0F, 0xFF, 0xFF)
if err != nil {
panic(err)
}
The result is : I1=0.31A, I2=0.12A, I3=0.11A

The error is increased from 0.12A to 0.31A. So I need to give an negative value:

the AIRMSOS, BIRMSOS, CIRMSOS, and
NIRMSOS (ADE7868/ADE7878 only) 24-bit signed registers
are accessed as 32-bit registers with four MSBs padded with 0s
and sign extended to 28 bits.

But before that I have to find out the correct calculation of xIRMSOS, the one used is not.

To be continued....


RE: Current drift values - frank - 06.07.2019

Thank you, very interesting!

If I understand it correctly, 0x0F 0xFF 0xFF 0xFF should be the corresponding binary representation of xIRMSOS = -1?


RE: Current drift values - frank - 06.07.2019

(06.07.2019, 08:19)markobursic Wrote: current = ((((outcome * 0.3535) / rmsFactor) / cr) / ccf) * 100.0 * oc * c.CalibrationfactorI[phase]

(outcome * 0.3535) * cr * 100.0 * oc * c.CalibrationfactorI[phase] / ( rmsFactor * ccf)

I think you made a mistake there. This should be correct:

current = (outcome * 0.3535 * 100.0 * oc * c.CalibrationfactorI[phase]) / (rmsFactor * cr* ccf)
current = outcome * 2.502e-5


RE: Current drift values - markobursic - 06.07.2019

EDIT 3:

current = ((((outcome * 0.3535) / rmsFactor) / cr) / ccf) * 100.0 * oc * c.CalibrationfactorI[phase]

(outcome * 0.3535) * 100.0 * oc * c.CalibrationfactorI[phase] / ( rmsFactor * cr * ccf)
outcome * 0.3535 * 100.0 * 1.049084906 * 1.0 / (4191910.0 * 7.07107 * 0.05)
outcome * 37.0851514271‬/1482064.452185
outcome * 2.5022630677380833181662834904425e-5

outcome * 2.5022630677380833181662834904425e-5‬ = 0.12
outcome = 0.12/2.5022630677380833181662834904425e-5‬ ;
outcome = 4502

Irms = sqrt(Irms0^2 + 128* IRMSOS)
Irms^2 = Irms0^2 + 128* IRMSOS
IRMSOS * 128 = Irms^2 - Irms0^2
IRMSOS = 4502^2 / 128 = 158344
IRMOS = 02 6A 88 (hex)
negate -158344 = ‭FFFD9578‬
pad 4 MSB bits with 0 = ‭0F FD 95 78‬

err = WriteRegister(d, "AIRMSOS", 0x0F, 0xFD, 0x95, 0x78)
if err != nil {
panic(err)
}
err = WriteRegister(d, "BIRMSOS", 0x0F, 0xFD, 0x95, 0x78)
if err != nil {
panic(err)
}

err = WriteRegister(d, "CIRMSOS", 0x0F, 0xFD, 0x95, 0x78)
if err != nil {
panic(err)
}
err = WriteRegister(d, "NIRMSOS", 0x0F, 0xFD, 0x95, 0x78)
if err != nil {
panic(err)
}

RESULTS:
date, I1, I2, I3
019-07-06 16:52:36.456,0.016665072031135632,0.024572223325187978,0.0161896420482654
2019-07-06 16:52:37.467,0,0,0.018817018269390386
2019-07-06 16:52:38.479,0,0,0.023871589666221316
2019-07-06 16:52:39.491,0.026473943256668925,0,0
2019-07-06 16:52:40.498,0,0.02292072970048084,0
2019-07-06 16:52:41.505,0.00955864491875948,0.027449825853086772,0
2019-07-06 16:52:42.515,0,0,0
2019-07-06 16:52:43.527,0.00663099712950592,0,0
2019-07-06 16:52:44.538,0,0.022945752331158226,0
2019-07-06 16:52:45.546,0,0,0
2019-07-06 16:52:46.556,0.008182400231503533,0.02094394187696776,0.01443805790084874
2019-07-06 16:52:47.573,0.02267050339370703,0,0
2019-07-06 16:52:48.587,0,0.012761541645464225,0
2019-07-06 16:52:49.601,0,0.01699036622994159,0.020218285587323716
2019-07-06 16:52:50.609,0.0246723138478975,0.029501681568632,0
2019-07-06 16:52:51.618,0,0.013136881105624935,0.024271951757059408
2019-07-06 16:52:52.630,0,0.022945752331158226,0
2019-07-06 16:52:53.641,0.02139434922916061,0.0268993279781844,0.03092797151724271
2019-07-06 16:52:54.654,0.010359369100435665,0,0
2019-07-06 16:52:55.666,0,0.014588193684913027,0.01268647375343208
2019-07-06 16:52:56.681,0.011510410111595181,0,0
2019-07-06 16:52:57.691,0,0.03378055141446412,0
2019-07-06 16:52:58.703,0,0.025798332228379635,0.019993081911227284
2019-07-06 16:52:59.715,0,0,0.023946657558253457
2019-07-06 16:53:00.722,0,0,0.023571318098092743
2019-07-06 16:53:01.730,0,0.035982542914073636,0
2019-07-06 16:53:02.742,0.02682426008615225,0.0023271046529964173,0.01203588535582018
2019-07-06 16:53:03.754,0,0.010309323839080902,0
2019-07-06 16:53:04.766,0.01664004940045825,0.03453123033478555,0.01861683722397134
2019-07-06 16:53:05.774,0.02855082160289153,0,0
2019-07-06 16:53:06.786,0,0.023646385990124887,0
2019-07-06 16:53:07.800,0.007081404481698776,0.01503860103710588,0
2019-07-06 16:53:08.817,0,0.002076878346222609,0.022195073410836794
2019-07-06 16:53:09.829,0.0061055218852809215,0,0.024321997018414167
2019-07-06 16:53:10.837,0,0.02174466605864394,0

Still slightly positive offset, but that's the way to solve the drift, IMO.


RE: Current drift values - frank - 06.07.2019

I get quite nice results with
Code:
err = WriteRegister(d, "AIRMSOS", 0x0F, 0xFD, 0x40, 0xE0)
which is equivalent to AIRMSOS = - 180000


My calculation:

mean current reading without current transformer and with outcome=outcome-7300 commented: 0.12A

outcome = current / 2.5e-5 = 0.12 / 2.5e-5 = 4800

AIRMSOS = - 4800² / 128 = - 180000



(06.07.2019, 15:55)markobursic Wrote: outcome * 2.5022630677380833181662834904425e-5‬ = 0.12
outcome = 0.12/2.5022630677380833181662834904425e-5‬ ;
outcome = 4502
outcome = 4796 IMHO  Wink
Well, we got very similar results. Thank you very much for your efforts!


RE: Current drift values - markobursic - 07.07.2019

You are correct. I am struggling with Windws calc which I have found it almost useless. But the principle is the same, in automatic calibration you would get xIRMS value directly (outcome). A pseudo algorithm would be:
1. set all xIRMSOS registers to 0
2. get N values of xIRMS registers (outcome)
3. calculate the mean value of xIRMS
4. calculate:
temp_xIRMSOS = meanIRMS^2/128
if meanIRMS<0 then
xIRMSOS = temp_xIRMSOS
else
xIRMSOS = -1.0* temp_xIRMSOS
pad 4 MSB bits with zeroes
5. store xIRMSOS values, set them every startup


There is another issue I have found. Not always at startup the xIRMSOS values are accepted from ADE7878.


RE: Current drift values - markobursic - 07.07.2019

(06.07.2019, 16:02)frank Wrote: I get quite nice results with
Code:
err = WriteRegister(d, "AIRMSOS", 0x0F, 0xFD, 0x40, 0xE0)
which is equivalent to AIRMSOS = - 180000

I have updated to your coefficients, now all three currents show 0A. Looks like the drift has almost the same value for all SmarPi devices.