Figure 1 : panStamp meter board
The hardwareThe meter board is "non-AC intrusive", meaning that all voltages handled on the board are low-level, so there is no danger for the user when in direct contact with the on-board circuits. This is achieved thanks to the external transformers (voltage and current), which free the user from having to connect regular AC wires to the meter board. This board with the associated Arduino sketch has an input for an external voltage transformer, which powers the board and provides the voltage information for the internal calculations, six inputs for current transformers (current clamps) and three pulse counting inputs. The hardware design still needs to be modified with some additions, including a way to store readings for a while after detecting a power outage. A seventh input for current transformer may be added to to the PCB design as well, and finally some additional filtering capacitors. Working KiCad files can be downloaded from SVN too. Reading from voltage and current transformers are used to calculate the following data:
On the other hand, pulse inputs are used to count pulses coming from other devices like power meters, water flow meters and gas meters. This gives up to 9 different inputs for measuring energy consumptions from different sources.
SCT-013-005 and SCT-013-030 current clamps from YHDC have been used for the tests. These transformers basically convert AC current to AC voltage (maximum amplitude = 1V) so depending on the current to be measured we may decide to use the 5A version or the 30A one... or even the 50A one. But how does the on-board panStamp calculates power consumption from real-time voltage and currents? The firmwareCalculations basically rely on the following method: /** * update * * Update AC channel readings * * Return: * 0 if the function still needs to take additional samples * 1 if the function read the necessary amount of samples * 2 if the function detected no VAC signal after reading the samples */ byte CHANNEL::update(void) { unsigned long adcV1, adcV2, adcI; float voltage, current; static double accumulated; static int i = 0; const float peakToRMS = 0.707106781; // Peak to RMS conversion factor unsigned long currentTime, elapsedTime; double energy; bool getEnergy = false; const float scale = ACVOLT_SCALE; static bool noVac = true; //Read voltage and current adcV1 = analogRead(voltagePin); // First AC voltage reading adcI = analogRead(currentPin); // AC current reading adcV2 = analogRead(voltagePin); // Second AC current reading adcV1 += adcV2; adcV1 /= 2; // Average between both voltage readings. This should give us // an approximate value of the voltage at the moment of reading // the current value // Discard 0 and negative voltages since we are working with a rectified voltage signal if (adcV1 > 0) { if (noVac) noVac = false; // VAC signal detected // Process AC voltage adcV1 = adcV1 * voltageSupply; adcV1 *= scale; voltage = adcV1 / 1023; voltage += ACVOLT_OFFSET_DIODE; // Apply offset voltage *= voltageScale; voltage /= 1000; // convert to volts //Process AC current adcI = adcI * voltageSupply; current = adcI / 1023; current -= voltageSupply/2; // Apply offset current *= currentScale; current /= 1000; // Convert to amps // Update peak current if (current > peakCurrent) peakCurrent = current; // Update peak voltage if (voltage > peakVoltage) peakVoltage = voltage; // Prepare for active power calculation accumulated += voltage * current; i++; // When a given amount of samples is read if (i == NB_OF_SAMPLES) { // No VAC signal detected? if (noVac) return CHANNEL_NO_VAC_SIGNAL; // Read current time currentTime = millis(); if (lastTime > 0) { // Elapsed time between readings elapsedTime = currentTime - lastTime; // Calculate KWh this time getEnergy = true; } // Update last time lastTime = currentTime; // Active power (W) if (accumulated < 0) accumulated = 0; actPower = accumulated / (NB_OF_SAMPLES/2); accumulated = 0; // RMS voltage (V) rmsVoltage = peakVoltage * peakToRMS; peakVoltage = 0; // RMS current (A) rmsCurrent = peakCurrent * peakToRMS; peakCurrent = 0; // Apparent power (VA) appPower = rmsVoltage * rmsCurrent; // Power factor powerFactor = actPower / appPower; // Can't be greater than 1 if (powerFactor > 1.0) { powerFactor = 1; actPower = appPower; } i = 0; // Power factor offset to be applied? if (pfOffset > 0 && powerFactor < 1) { // Correct power factor powerFactor += pfOffset; if (powerFactor > 1) powerFactor = 1; // Back calculate active power actPower = appPower * powerFactor; } if (getEnergy) { energy = actPower * elapsedTime; energy /= 3600000; kwh += energy; } return CHANNEL_SAMPLES_COMPLETED; } } return CHANNEL_SAMPLES_NOT_COMPLETED; } (The complete "meter" sketch can be downloaded from SVN too) The mathsActive power: P = (V0 x I0 + V1 x I1 + V2 x I2 + ... + VN x IN) / N being N the amount of samples read. At the moment of writing this review, 80 samples are read before doing any calculation. Around 40 of those 80 samples are discarded since the board is really measuring a half-wave version of the original low-level AC voltage. RMS values: VRMS = VMAX / √2 IRMS = IMAX / √2 Apparent power: S = VRMS x IRMS PF = S / P Energy consumed: Energy = P x time It gives an idea about the effectiveness of the energy being consumed and it basically depends on the type of load being powered.Thus, for pure resistive loads, the phase difference is 0 (voltage and current signals in phase) so power factor equals 1. The more reactive the load is the bigger the phase difference is and the lower the power factor is. The problem about transformers is that they tend to shift the signal a bit on the secondary so we need a way to calibrate this when this additional phase shift affects readings significantly. Wireless capabilitiesIn order to provide support for calibration, the on-board panStamp application provides some SWAP configuration registers, letting the user enter the following settings wirelessly: For current transformer inputs:
For counter inputs:
This device is already defined in the current Device Definition Files database so SWAPdmt is able to detect it and understand the contents of each register. The communityAs you can see, a lot of work has been done over the last weeks to get a first working version. However, we still need to run many additional tests, answer some questions... and even ask new ones before going to production. A new thread has been created in the forum in order to address questions and responses from/to our community. Feel free to drop your ideas and suggestions from there! |
Announcements >