Zero crossing spikes while measuring power with CT - Page 1
Forum section: electronics / projects

author: chaseadam
author_rank: Contributor
timestamp: July 13, 2018, 07:59:15 am
content: Looking for some possible causes for the zero crossing spikes. I am using an MCP3903 with a CT (with built in burden resistor). The CT and MCP3903 are separated by 1k resistors and have 100nF capacitor to the analog ground to reduce the high frequency noise. This results in *almost* the expected sine wave (measuring small resistive light bulb load), but I regularly receive spikes at what appears to be the zero crossing. I double checked and confirmed I am receiving extreme negatives and positives (so it is not the math to handle the negative translation).I am reading in continuous mode from a single channel in differential mode using a bus pirate and processing the output with pythonPlots attachedCode:import matplotlib.pyplot as plttext = input("hex data")values = []hex = Falsefor sample in text.split(" "):if not hex:hex = sample.split("x")msb = Falseelse:hex = hex + sample.split("x")msb = Truedec = int(hex, 16)#volts = dec/32768/3*2.372# negative value calculationif dec > 32767: #0x7FFFprint(hex)dec -= 65536 #0xFFFF + 1(dec)values.append(dec)hex = Falseprint(values)plt.plot(values)plt.ylabel('adc raw value')plt.show()Sample data:Code:0x01 0x80 0x01 0xA1 0x01 0xA5 0x01 0x84 0x01 0x09 0x00 0x89 0x7F 0xD8 0xFF 0x5B 0xFE 0xBA 0xFE 0x58 0xFE 0x18 0xFE 0x0D 0xFE 0x11 0xFE 0x6A 0xFE 0xE2 0xFF 0x6B 0x80 0x17 0x00 0x99 0x01 0x2C 0x01 0x7E 0x01 0xA0 0x01 0xA5 0x01 0x87 0x01 0x12 0x00 0x91 0x7F 0xDA 0xFF 0x5E 0xFE 0xBA 0xFE 0x5A 0xFE 0x14 0xFE 0x0A 0xFE 0x0D 0xFE 0x63 0xFE 0xDF 0xFF 0x92 0x80 0x10 0x00 0x92 0x01 0x24 0x01 0x82 0x01 0xA4 0x01 0xA6 0x01 0x76 0x01 0x16 0x00 0x92 0x7F 0xDC 0xFF 0x66 0xFE 0xC1 0xFE 0x5B 0xFE 0x13 0xFE 0x0B 0xFE 0x0E 0xFE 0x60 0xFE 0xDE 0xFF 0x8C 0x80 0x0B 0x00 0x8C 0x01 0x20 0x01 0x7A 0x01 0xA3 0x01 0xA6 0x01 0x80 0x01 0x1D 0x00 0x95 0x7F 0xE2 0xFF 0x68 0xFE 0xC5 0xFE 0x5F 0xFE 0x15 0xFE 0x0A 0xFE 0x10 0xFE 0x5A 0xFE 0xD2 0xFF 0x83 0x80 0x09 0x00 0xB2 0x01 0x23 0x01 0x77 0x01 0x9E 0x01 0xA4 0x01 0x7E 0x01 0x23 0x00 0x70 0x7F 0xE7 0xFF 0x6C 0xFE 0xCE 0xFE 0x62 0xFE 0x18 0xFE 0x07 0xFE 0x14 0xFE 0x55 0xFE 0xCE 0xFF 0x81 0x80 0x02 0x00 0xAB 0x01 0x21 0x01 0x71 0x01 0xA0 0x01 0xA5 0x01 0x7F 0x01 0x24 0x00 0x76 0x7F 0xF0 0xFF 0x72 0xFE 0xD1 0xFE 0x67 0xFE 0x15 0xFE 0x0B 0xFE 0x11 0xFE 0x58 0xFE 0xCA 0xFF 0x81 0x80 0x02 0x00 0xA5 0x01 0x16 0x01 0x85 0x01 0xA2 0x01 0x9C 0x01 0x82 0x01 0x2B 0x00 0x7E 0x7F 0xF3 0xFF 0x4B 0xFE 0xD4 0xFE 0x6C 0xFE 0x15 0xFE 0x0B 0xFE 0x13 0xFE 0x4C 0xFE 0xC6 0xFF 0x7E 0xFF 0xFA 0x00 0xA4 0x01 0x12 0x01 0x88 0x01 0xA3 0x01 0xA3 0x01 0x87 0x01 0x30 0x00 0x80 0x7F 0xF7 0xFF 0x52 0xFE 0xD8 0xFE 0x6A 0xFE 0x18 0xFE 0x0E 0xFE 0x16 0xFE 0x4B 0xFE 0xED 0xFF 0x74 0xFF 0xF7 0x00 0x9D 0x01 0x0B 0x01 0x82 0x01 0xA1 0x01 0xA9 0x01 0x86 0x01 0x35 0x00 0x81 0x7F 0xFF 0xFF 0x5C 0xFE 0xDD 0xFE 0x57 0xFE 0x18 0xFE 0x0E 0xFE 0x0F 0xFE 0x47 0xFE 0xE3 0xFF 0x67 0xFF 0xEF 0x00 0x9A 0x01 0x09 0x01 0x7F 0x01 0x9F 0x01 0xAA 0x01 0x8D 0x01 0x39 0x00 0x8C 0x00 0x04 0xFF 0x60 0xFE 0xDE 0xFE 0x56 0xFE 0x18 0xFE 0x0B 0xFE 0x07 0xFE 0x43 0xFE 0xE2 0xFF 0x68 0x80 0x17 0x00 0x8B 0x01 0x02 0x01 0x7E 0x01 0x9B 0x01 0xA4 0x01 0x8C 0x01 0x15 0x00 0x8F 0x00 0x0B 0xFF 0x61 0xFE 0xE3 0xFE 0x5A 0xFE 0x1B 0xFE 0x0B 0xFE 0x0D 0xFE 0x43 0xFE 0xD9 0xFF 0x61 0x80 0x14 0x00 0x8A 0x00 0xFF 0x01 0x7A 0x01 0x9C 0x01 0xA5 0x01 0x93 0x01 0x1D 0x00 0x8F 0x00 0x0C 0xFF 0x67 0xFE 0xE9 0xFE 0x63 0xFE 0x1D 0xFE 0x0B 0xFE 0x0A 0xFE 0x43 0xFE 0xD0 0xFF 0x5A 0x80 0x0C 0x00 0x89 0x01 0x25 0x01 0x79 0x01 0x9D 0x01 0xA4 0x01 0x91 0x01 0x25 0x00 0x9E 0x7F 0xDF 0xFF 0x6C 0xFE 0xF0 0xFE 0x62 0xFE 0x19 0xFE 0x0A 0xFE 0x0A 0xFE 0x3F 0xFE 0xD2 0xFF 0x58 0x80 0x0A 0x00 0x81 0x01 0x1D 0x01 0x77 0x01 0x9E 0x01 0xA8 0x01 0x95 0x01 0x23 0x00 0xA0 0x7F 0xF0 0xFF 0x74 0xFE 0xF2 0xFE 0x64 0xFE 0x1C 0xFE 0x0C 0xFE 0x0F 0xFE 0x56 0xFE 0xCB 0xFF 0x54 0xFF 0xFD 0x00 0x7B 0x01 0x16 0x01 0x6F 0x01 0x9D 0x01 0xA7 0x01 0x99 0x01 0x2B 0x00 0xAA 0x7F 0xF2 0xFF 0x77 0xFE 0xD8 0xFE 0x68 0xFE 0x1E 0xFE 0x10 0xFE 0x0C 0xFE 0x4C 0xFE 0xC4 0xFF 0x4B 0xFF 0xFB 0x00 0x74 0x01 0x19 0x01 0x6F 0x01 0xA0 0x01 0xA8 0x01 0x95 0x01 0x2E 0x00 0xAA 0x7F 0xF5 0xFF 0x7D 0xFE 0xDE 0xFE 0x6E 0xFE 0x22 0xFE 0x08 0xFE 0x0B 0xFE 0x4B 0xFE 0xC0Plotted values:[384, 417, 421, 388, 265, 137, 32728, -165, -326, -424, -488, -499, -495, -406, -286, -149, -32745, 153, 300, 382, 416, 421, 391, 274, 145, 32730, -162, -326, -422, -492, -502, -499, -413, -289, -110, -32752, 146, 292, 386, 420, 422, 374, 278, 146, 32732, -154, -319, -421, -493, -501, -498, -416, -290, -116, -32757, 140, 288, 378, 419, 422, 384, 285, 149,32738, -152, -315, -417, -491, -502, -496, -422, -302, -125,-32759, 178, 291, 375, 414, 420, 382, 291, 112,32743, -148, -306, -414, -488, -505, -492, -427, -306, -127, -32766, 171, 289, 369, 416, 421, 383, 292, 118, 32752, -142, -303, -409, -491, -501, -495, -424, -310, -127, -32766, 165, 278, 389, 418, 412, 386, 299, 126, 32755, -181, -300, -404, -491, -501, -493, -436, -314, -130, -6, 164, 274, 392, 419, 419, 391, 304, 128, 32759, -174, -296, -406, -488, -498, -490, -437, -275, -140, -9, 157, 267, 386, 417, 425, 390, 309, 129, 32767, -164, -291, -425, -488, -498, -497, -441, -285, -153, -17, 154, 265, 383, 415, 426, 397, 313, 140, 4, -160, -290, -426, -488, -501, -505, -445, -286, -152, -32745, 139, 258, 382, 411, 420, 396, 277, 143, 11, -159, -285, -422, -485, -501, -499, -445, -295, -159, -32748, 138, 255, 378, 412, 421, 403, 285, 143, 12, -153, -279, -413, -483, -501, -502, -445, -304, -166, -32756, 137, 293, 377, 413, 420, 401, 293, 158, 32735, -148, -272, -414, -487, -502, -502, -449, -302, -168, -32758, 129, 285, 375, 414, 424, 405, 291, 160, 32752, -140, -270, -412, -484, -500, -497, -426, -309, -172, -3, 123, 278, 367, 413, 423, 409, 299, 170, 32754, -137, -296, -408, -482, -496, -500, -436, -316, -181, -5, 116, 281, 367, 416, 424, 405, 302, 170, 32757, -131, -290, -402, -478, -504, -501, -437, -320]

author: Kleinstein
author_rank: Super Contributor
timestamp: July 13, 2018, 08:14:21 am
content: Are you shure there is a burden resistor inside ? Just for a test one could add an extra resistor outside - just in case.A common mistake is to forget about a DC return path at the input with differential inputs and an isolated source.

author: chaseadam
author_rank: Contributor
timestamp: July 13, 2018, 09:42:11 pm
content: Definitely sure it is a burden resistor in the CT, took one apart to verify.I mimic-ed the evaluation board with series resistors and 100nF capacitors to the analog ground. See attached example (it has a bunch of DNP and some jumpers in there, but it shows the resistors and capacitors which are populated. Would this address the return path issue?I believe the CT is isolated as it isn't referenced to anything.Possibly noise on the power to the analog side? Just seems to regular and in sync with the zero crossings

author: ogden
author_rank: Super Contributor
timestamp: July 13, 2018, 09:58:03 pm
content: I know nothing about python, but in C (language) what you do about 16 bit unsigned to signed conversion, is wrong.Just try unconditionally:dec -= 32768 Anyway you shall look at raw ADC data first to confirm hardware error.

author: Kleinstein
author_rank: Super Contributor
timestamp: July 13, 2018, 10:16:45 pm
content: As far as I understand the circuit, it would likely need at least one of the resistors R1,R2,R6,R8. I would prefer R1 and R2 and the jumper from pin 3 to 4. R1 and R2 would be effectively in parallel to the burden resistor. With the common mode voltage floating the behavior of the ADC is not well defined.

author: sokoloff
author_rank: Super Contributor
timestamp: July 13, 2018, 10:23:31 pm
content: Are you sure that there are no powerline carrier communications devices on the circuit? They communicate around the zero crossing.

author: djacobow
author_rank: Super Contributor
timestamp: July 13, 2018, 10:46:57 pm
content: This is not a hardware problem at all. It is a software problem in the code that generated the byte stream.Let me guess, this is coming from a 12b ADC and you are sign-extending to 16b? If so, you're doing it wrong.For example, if you lop-off the upper nibble and then set it to all ones depending on whether the 12th bit is a one, you can a pretty sine wave with no discontinuities.Code:#include <stdlib.h>#include <stdio.h>#include <stdint.h>uint8_t indata[] = {0x01, 0x80, 0x01, 0xA1, 0x01, 0xA5, 0x01, 0x84, 0x01, 0x09, 0x00,0x89, 0x7F, 0xD8, 0xFF, 0x5B, 0xFE, 0xBA, 0xFE, 0x58, 0xFE, 0x18,0xFE, 0x0D, 0xFE, 0x11, 0xFE, 0x6A, 0xFE, 0xE2, 0xFF, 0x6B, 0x80,0x17, 0x00, 0x99, 0x01, 0x2C, 0x01, 0x7E, 0x01, 0xA0, 0x01, 0xA5,0x01, 0x87, 0x01, 0x12, 0x00, 0x91, 0x7F, 0xDA, 0xFF, 0x5E, 0xFE,0xBA, 0xFE, 0x5A, 0xFE, 0x14, 0xFE, 0x0A, 0xFE, 0x0D, 0xFE, 0x63,0xFE, 0xDF, 0xFF, 0x92, 0x80, 0x10, 0x00, 0x92, 0x01, 0x24, 0x01,0x82, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0x76, 0x01, 0x16, 0x00, 0x92,0x7F, 0xDC, 0xFF, 0x66, 0xFE, 0xC1, 0xFE, 0x5B, 0xFE, 0x13, 0xFE,0x0B, 0xFE, 0x0E, 0xFE, 0x60, 0xFE, 0xDE, 0xFF, 0x8C, 0x80, 0x0B,0x00, 0x8C, 0x01, 0x20, 0x01, 0x7A, 0x01, 0xA3, 0x01, 0xA6, 0x01,0x80, 0x01, 0x1D, 0x00, 0x95, 0x7F, 0xE2, 0xFF, 0x68, 0xFE, 0xC5,0xFE, 0x5F, 0xFE, 0x15, 0xFE, 0x0A, 0xFE, 0x10, 0xFE, 0x5A, 0xFE,0xD2, 0xFF, 0x83, 0x80, 0x09, 0x00, 0xB2, 0x01, 0x23, 0x01, 0x77,0x01, 0x9E, 0x01, 0xA4, 0x01, 0x7E, 0x01, 0x23, 0x00, 0x70, 0x7F,0xE7, 0xFF, 0x6C, 0xFE, 0xCE, 0xFE, 0x62, 0xFE, 0x18, 0xFE, 0x07,0xFE, 0x14, 0xFE, 0x55, 0xFE, 0xCE, 0xFF, 0x81, 0x80, 0x02, 0x00,0xAB, 0x01, 0x21, 0x01, 0x71, 0x01, 0xA0, 0x01, 0xA5, 0x01, 0x7F,0x01, 0x24, 0x00, 0x76, 0x7F, 0xF0, 0xFF, 0x72, 0xFE, 0xD1, 0xFE,0x67, 0xFE, 0x15, 0xFE, 0x0B, 0xFE, 0x11, 0xFE, 0x58, 0xFE, 0xCA,0xFF, 0x81, 0x80, 0x02, 0x00, 0xA5, 0x01, 0x16, 0x01, 0x85, 0x01,0xA2, 0x01, 0x9C, 0x01, 0x82, 0x01, 0x2B, 0x00, 0x7E, 0x7F, 0xF3,0xFF, 0x4B, 0xFE, 0xD4, 0xFE, 0x6C, 0xFE, 0x15, 0xFE, 0x0B, 0xFE,0x13, 0xFE, 0x4C, 0xFE, 0xC6, 0xFF, 0x7E, 0xFF, 0xFA, 0x00, 0xA4,0x01, 0x12, 0x01, 0x88, 0x01, 0xA3, 0x01, 0xA3, 0x01, 0x87, 0x01,0x30, 0x00, 0x80, 0x7F, 0xF7, 0xFF, 0x52, 0xFE, 0xD8, 0xFE, 0x6A,0xFE, 0x18, 0xFE, 0x0E, 0xFE, 0x16, 0xFE, 0x4B, 0xFE, 0xED, 0xFF,0x74, 0xFF, 0xF7, 0x00, 0x9D, 0x01, 0x0B, 0x01, 0x82, 0x01, 0xA1,0x01, 0xA9, 0x01, 0x86, 0x01, 0x35, 0x00, 0x81, 0x7F, 0xFF, 0xFF,0x5C, 0xFE, 0xDD, 0xFE, 0x57, 0xFE, 0x18, 0xFE, 0x0E, 0xFE, 0x0F,0xFE, 0x47, 0xFE, 0xE3, 0xFF, 0x67, 0xFF, 0xEF, 0x00, 0x9A, 0x01,0x09, 0x01, 0x7F, 0x01, 0x9F, 0x01, 0xAA, 0x01, 0x8D, 0x01, 0x39,0x00, 0x8C, 0x00, 0x04, 0xFF, 0x60, 0xFE, 0xDE, 0xFE, 0x56, 0xFE,0x18, 0xFE, 0x0B, 0xFE, 0x07, 0xFE, 0x43, 0xFE, 0xE2, 0xFF, 0x68,0x80, 0x17, 0x00, 0x8B, 0x01, 0x02, 0x01, 0x7E, 0x01, 0x9B, 0x01,0xA4, 0x01, 0x8C, 0x01, 0x15, 0x00, 0x8F, 0x00, 0x0B, 0xFF, 0x61,0xFE, 0xE3, 0xFE, 0x5A, 0xFE, 0x1B, 0xFE, 0x0B, 0xFE, 0x0D, 0xFE,0x43, 0xFE, 0xD9, 0xFF, 0x61, 0x80, 0x14, 0x00, 0x8A, 0x00, 0xFF,0x01, 0x7A, 0x01, 0x9C, 0x01, 0xA5, 0x01, 0x93, 0x01, 0x1D, 0x00,0x8F, 0x00, 0x0C, 0xFF, 0x67, 0xFE, 0xE9, 0xFE, 0x63, 0xFE, 0x1D,0xFE, 0x0B, 0xFE, 0x0A, 0xFE, 0x43, 0xFE, 0xD0, 0xFF, 0x5A, 0x80,0x0C, 0x00, 0x89, 0x01, 0x25, 0x01, 0x79, 0x01, 0x9D, 0x01, 0xA4,0x01, 0x91, 0x01, 0x25, 0x00, 0x9E, 0x7F, 0xDF, 0xFF, 0x6C, 0xFE,0xF0, 0xFE, 0x62, 0xFE, 0x19, 0xFE, 0x0A, 0xFE, 0x0A, 0xFE, 0x3F,0xFE, 0xD2, 0xFF, 0x58, 0x80, 0x0A, 0x00, 0x81, 0x01, 0x1D, 0x01,0x77, 0x01, 0x9E, 0x01, 0xA8, 0x01, 0x95, 0x01, 0x23, 0x00, 0xA0,0x7F, 0xF0, 0xFF, 0x74, 0xFE, 0xF2, 0xFE, 0x64, 0xFE, 0x1C, 0xFE,0x0C, 0xFE, 0x0F, 0xFE, 0x56, 0xFE, 0xCB, 0xFF, 0x54, 0xFF, 0xFD,0x00, 0x7B, 0x01, 0x16, 0x01, 0x6F, 0x01, 0x9D, 0x01, 0xA7, 0x01,0x99, 0x01, 0x2B, 0x00, 0xAA, 0x7F, 0xF2, 0xFF, 0x77, 0xFE, 0xD8,0xFE, 0x68, 0xFE, 0x1E, 0xFE, 0x10, 0xFE, 0x0C, 0xFE, 0x4C, 0xFE,0xC4, 0xFF, 0x4B, 0xFF, 0xFB, 0x00, 0x74, 0x01, 0x19, 0x01, 0x6F,0x01, 0xA0, 0x01, 0xA8, 0x01, 0x95, 0x01, 0x2E, 0x00, 0xAA, 0x7F,0xF5, 0xFF, 0x7D, 0xFE, 0xDE, 0xFE, 0x6E, 0xFE, 0x22, 0xFE, 0x08,0xFE, 0x0B, 0xFE, 0x4B, 0xFE, 0xC0 };int main(int argc, char *argv[]) {size_t length = sizeof(indata) / sizeof(uint8_t);uint16_t uval = 0;for (size_t i=0;i<length; i+=1) {if (!(i %2)) {// Get the MSBuval = indata << 8;} else {// get the LSB ... now you have a whole 16buval |= indata;// copy the 16b value over and chop off the upper nibbleuint16_t auval = uval;auval &= 0x0fff;// if the 12th bit is set, then set the upper nibble to all 1'sif (auval & 0x0800) auval |= 0xf000;// this rigamarole is to clearly show that we are asking// printf to interpret the bits of auval as signed; they are not// being converted.int16_t *ival;ival = (int16_t *)&auval;if (false) {// to show the steps of the adjustmentprintf("orig %u 0x%x adjusted %u 0x%x signed %d\n",uval, uval, auval, auval, (int)*ival);} else {// to make a file we can load into excel and plotprintf("%d\n",(int)*ival);}}}return 0;};

author: chaseadam
author_rank: Contributor
timestamp: July 14, 2018, 02:08:23 am
content: Thanks for all the guidance! That sine wave definitely looks like I would expect.I had a feeling the error might be in the conversion, but based on my interpretation in datasheet, they spiked. The chip appears to be not setting the 16th sign bit correctly after the zero cross.For the MCP3903, I am in 16 bit mode (by default) so it appears the value should be 15-bit plus signFrom the data sheet:QuoteAttached is a table from the datasheet describing the the decimal values in24bit mode.I do have some power line communication, but could that couple to the current transformer and saturate my ADC?Aside:My decoding approach was modeled after:https://github.com/kerrydwong/MCP3903/blob/master/MCP3903.cpp#L78:Code:double MCP3903::readADC(byte channel){unsigned long r = readRegister(channel);if (r > 8388607l) r -= 16777216l;return (double) r / 8388608.0 /3.0;}

author: chaseadam
author_rank: Contributor
timestamp: July 14, 2018, 02:36:42 am
content: Upon reviewing the modes of the chip, there are two methods to reading ADC values. In the data above, I was using continuous mode and may be the issue.This tripped me up:In 6.9 Line Cycle Sampling Options there is:QuoteI thought that this applies to continuous mode, but it cannot apply because CS is high the whole time in continuous mode (if it were true, then all the values would be the same).There is a whole "Data Ready" (DR) aspect of the ADC which I was ignoring. The attached diagram clearly indicates that SCK stops until the next DR.It is not intuitive to me that this issue would cause a missing sign bit, but possible. Thoughts?

author: djacobow
author_rank: Super Contributor
timestamp: July 14, 2018, 02:53:28 am
content: I suspected a "digital" problem because the outlier values looked like small numbers (like you would expect at zero crossing) but with messed up sign extension.I don't know the MCP and don't have the time to look at the data sheet in detail (in on phone), but I'd also give some thought to the idea that the ADC is giving 15b + sign, which is obviously not the same as two's complement signed numbers, which is what C and Matlab are expecting.