Energy Monitor Shield Nokia 5100 Display

The Energy Monitor Shield is supplied with a Nokia 5110 LCD for displaying instantaneous power consumption etc. There is an excellent Netduino driver for the Nokia 5100 display by omar, and with a few modifications this works with the Energy Monitor Shield. I removed the backlight support and made a few other simple modifications.

Nokia_5110 Lcd = new Nokia_5110(Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D5);

while (true)
{
   Lcd.Clear();
   Lcd.DrawString(0, 0, DateTime.Now.ToString("HH:mm:ss"), true);
   Lcd.DrawString(0, 1, DateTime.Now.ToString("HH:mm:ss"), true);
   Lcd.DrawString(0, 2, DateTime.Now.ToString("HH:mm:ss"), true);
   Lcd.Refresh();
   Thread.Sleep(500)
}

Netduino Nokia 5110 driver

Energy Monitor Shield Noise Reduction

In a couple of previous posts the noise on the Netduino AnalogInput and the impact of this on the RMS current measurement was discussed. I trialled two versions of the code to see if my approach worked. Both versions used the initial calibration phase to measure the maximum and minimum values of the noise.

int valueSum = 0;
int valueNoiseMinimum = int.MaxValue;
int valueNoiseMaximum = int.MinValue;
int valueSumSqr = 0;
int offset;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

// Calculate the sum for offset for first run
for (int i = 0; i < SampleCount; i++)
{
  int value = x1.ReadRaw();
  valueSum = valueSum + value;

   if (value < valueNoiseMinimum)
   {
      valueNoiseMinimum = value;
   }
   if (value > valueNoiseMaximum)
   {
      valueNoiseMaximum = value;
   }
}

offset = valueSum / SampleCount;
valueNoiseMinimum -= offset;
valueNoiseMaximum -= offset;

The first version used only the initial offset

Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();

for (int i = 0; i < SampleCount; i++)
{
   int value = x1.ReadRaw();
   value -= offset;

   if ((value &gt; valueNoiseMaximum) || (value &lt; valueNoiseMinimum))
   {
   valueSumSqr += (value * value);
   }
}
stopwatch.Stop();

RMS 42.2729 RMS Current 3.4A RMS Power 775W Duration = 3301 mSec 30293/sec
RMS 42.2137 RMS Current 3.4A RMS Power 774W Duration = 3302 mSec 30284/sec
RMS 42.2374 RMS Current 3.4A RMS Power 775W Duration = 3302 mSec 30284/sec
RMS 42.1307 RMS Current 3.4A RMS Power 773W Duration = 3302 mSec 30284/sec
RMS 42.1307 RMS Current 3.4A RMS Power 773W Duration = 3302 mSec 30284/sec
RMS 42.1189 RMS Current 3.4A RMS Power 773W Duration = 3302 mSec 30284/sec
RMS 42.1307 RMS Current 3.4A RMS Power 773W Duration = 3302 mSec 30284/sec
RMS 42.1070 RMS Current 3.4A RMS Power 772W Duration = 3302 mSec 30284/sec
RMS 42.1189 RMS Current 3.4A RMS Power 773W Duration = 3302 mSec 30284/sec
RMS 42.1426 RMS Current 3.4A RMS Power 773W Duration = 3303 mSec 30275/sec

The second version updated the offset every iteration

Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();

for (int i = 0; i &lt; SampleCount; i++)
{
   int value = x1.ReadRaw();
   valueSum += value;
   value -= offset;

   if ((value &gt; valueNoiseMaximum) || (value &lt; valueNoiseMinimum))
   {
      valueSumSqr += (value * value);
   }
}
stopwatch.Stop();
offset = valueSum / SampleCount;

This was slightly slower due to the extra addition operation in the sampling loop

RMS 41.5933 RMS Current 3.3A RMS Power 763W Duration = 3537 mSec 28272/sec
RMS 41.6653 RMS Current 3.3A RMS Power 764W Duration = 3541 mSec 28240/sec
RMS 41.6053 RMS Current 3.3A RMS Power 763W Duration = 3538 mSec 28264/sec
RMS 41.5572 RMS Current 3.3A RMS Power 762W Duration = 3537 mSec 28272/sec
RMS 41.5572 RMS Current 3.3A RMS Power 762W Duration = 3537 mSec 28272/sec
RMS 41.5331 RMS Current 3.3A RMS Power 762W Duration = 3537 mSec 28272/sec
RMS 41.4970 RMS Current 3.3A RMS Power 761W Duration = 3540 mSec 28248/sec
RMS 41.4849 RMS Current 3.3A RMS Power 761W Duration = 3538 mSec 28264/sec
RMS 41.4849 RMS Current 3.3A RMS Power 761W Duration = 3538 mSec 28264/sec
RMS 41.4849 RMS Current 3.3A RMS Power 761W Duration = 3516 mSec 28441/sec

At 28K4 samples per second the self adjusting RMS calculation is sampling the 50Hz waveform much more frequently than required.

Energy Monitor Shield RMS Calculation

The voltage output by the current sensor and measured by the Netduino needs to be corrected using the offset value then the RMS value calculated. This RMS value then needs to be adjusted taking into account the voltage range of the Netduino analog input (0V-3V3), the resolution of the analog input (12 bits) and the voltage output by the non-invasive current sensor (0~1V for 0~30A).

My approach appears to produce reasonable values but I will need to compare them with a calibrated reference device to check its accuracy. The 18W measurement with no current flowing is due to the noise on the analog input discussed in an earlier post.

The first version of the software used the initial offset value, the second version updates the offset value at the end of each set of samples.

int valueSum = 0;
int valueSumSqr = 0;
int offset;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

// Calculate the sum for initial offset
for (int i = 0; i < SampleCount; i++)
{
valueSum += x1.ReadRaw();
}
offset = valueSum / SampleCount;

Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();

for (int i = 0; i < SampleCount; i++)
{
int value = x1.ReadRaw();

value -= offset;

valueSumSqr += (value * value);
}
stopwatch.Stop();

double rms = System.Math.Sqrt((double)(valueSumSqr / SampleCount));
double rmsCurrent = rms * (3.3 / 4096.0) * 3.3 * 30.0;
double rmsWatts = rmsCurrent * 230;

Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2588 mSec 38639/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2587 mSec 38654/sec RMS 1.0 RMS Current 0.1A RMS Power 18W

int valueSum = 0;
int valueSumSqr = 0;
int offset;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
// Calculate the sum for initial offset
for (int i = 0; i < SampleCount; i++)
{
valueSum += x1.ReadRaw();
}
offset = valueSum / SampleCount;

Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();

for (int i = 0; i < SampleCount; i++)
{
int value = x1.ReadRaw();

valueSum += value;

value -= offset;

valueSumSqr += (value * value);
}
stopwatch.Stop();

offset = valueSum / SampleCount;

double rms = System.Math.Sqrt((double)(valueSumSqr / SampleCount));
double rmsCurrent = rms * (3.3 / 4096.0) * 3.3 * 30.0 ;
double rmsWatts = rmsCurrent * 230;

Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W
Duration = 2816 mSec 35511/sec RMS 1.0 RMS Current 0.1A RMS Power 18W

Both versions appear to sample the output of the non-invasive current sensor at a more than sufficient rate.

Energy Monitor Shield Analog Input Noise

While writing the calibration code I noticed that the voltage reading was a bit noisy so I modified the code to record the minimum & maximum values then put the current sensor clamp on a wire not carrying any current.

int value;
int valueSum = 0;
int valueMinimum = int.MaxValue;
int valueMaximum = int.MinValue;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.ReadRaw();

if (value < valueMinimum)
{
valueMinimum = value;
}
if (value > valueMaximum)
{
valueMaximum = value;
}
valueSum += value;
}
stopwatch.Stop();

Duration = 3509 mSec 28498/sec Min=2031 Max=2052 Avg=2041
Duration = 3501 mSec 28563/sec Min=2031 Max=2052 Avg=2041
Duration = 3500 mSec 28571/sec Min=2031 Max=2053 Avg=2041
Duration = 3501 mSec 28563/sec Min=2031 Max=2053 Avg=2041
Duration = 3500 mSec 28571/sec Min=2031 Max=2051 Avg=2041
Duration = 3500 mSec 28571/sec Min=2031 Max=2052 Avg=2041
Duration = 3500 mSec 28571/sec Min=2031 Max=2053 Avg=2041
Duration = 3501 mSec 28563/sec Min=2032 Max=2053 Avg=2041
Duration = 3500 mSec 28571/sec Min=2031 Max=2053 Avg=2041
Duration = 3500 mSec 28571/sec Min=2030 Max=2052 Avg=2041

Looks like there is a little bit of noise on the input when there is no current flowing.

I also tried using the baked in Min & Max functions but these were a bit slower which was not what I was expecting

int value;
int valueSum = 0;
int valueMinimum = int.MaxValue;
int valueMaximum = int.MinValue;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.ReadRaw();

valueMinimum = System.Math.Min(value, valueMinimum);
valueMaximum = System.Math.Max(value, valueMaximum);

valueSum += value;
}
stopwatch.Stop();

Duration = 4672 mSec 21390/sec Min=2036 Max=2048 Avg=2041
Duration = 4665 mSec 21436/sec Min=2036 Max=2049 Avg=2041
Duration = 4665 mSec 21436/sec Min=2035 Max=2049 Avg=2041
Duration = 4664 mSec 21440/sec Min=2036 Max=2048 Avg=2041
Duration = 4664 mSec 21440/sec Min=2036 Max=2048 Avg=2041
Duration = 4664 mSec 21440/sec Min=2036 Max=2049 Avg=2041
Duration = 4664 mSec 21440/sec Min=2035 Max=2048 Avg=2041
Duration = 4664 mSec 21440/sec Min=2035 Max=2048 Avg=2041
Duration = 4664 mSec 21440/sec Min=2035 Max=2049 Avg=2041
Duration = 4664 mSec 21440/sec Min=2035 Max=2048 Avg=2041

Energy Monitor Shield Sensor Calibration

The Netduino 2 Plus AnalogInput has a range of 0V to 3V3. The Non Invasive Current Sensor we are using returns 0-1V AC for 0-30 Amps AC. To measure the sensor’s output waveform the Energy Monitor Shield uses a voltage divider to offset the reference voltage to 3v3/2. To calibrate the sensor we averaged the input voltage and over 100,000 readings.

The initial code looked like this

int value;
int valueSum = 0;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.ReadRaw();

valueSum = valueSum + value;
}
stopwatch.Stop();

Duration = 2272 mSec 44014/sec
Duration = 2273 mSec 43994/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec
Duration = 2272 mSec 44014/sec

I then modified the code to not use a temporary variable

int valueSum = 0;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
valueSum = valueSum + x1.ReadRaw();
}
stopwatch.Stop();

Duration = 2181 mSec 45829/sec
Duration = 2182 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec
Duration = 2181 mSec 45829/sec

The code without the temporary variable was slightly faster.

 

Netduino AnalogInput read rates

At CodeClub some of the students are building a netduino based power consumption monitor using an Energy Monitor Shield (with my modifications). The approach for the software was “inspired” by the Arduino code developed by the Open Energy Monitor project. First step was to confirm that the Netduino 2 Plus we were using could sample the Alternating Current(AC) waveform often enough.

The first version of the code called the Microsoft.Spot.Hardware.AnalogInput.Read method (which returns a floating point number) 100,000 times. The duration was measured using a Stopwatch class written by ChrisW of Secretlabs.

double value;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);

Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.Read();
}
stopwatch.Stop();

Duration = 5496 mSec 18195/sec
Duration = 5497 mSec 18191/sec
Duration = 5496 mSec 18195/sec
Duration = 5496 mSec 18195/sec
Duration = 5497 mSec 18191/sec
Duration = 5496 mSec 18195/sec
Duration = 5496 mSec 18195/sec
Duration = 5496 mSec 18195/sec
Duration = 5496 mSec 18195/sec
Duration = 5497 mSec 18191/sec

The AnalogPort also has a overloaded Read method which returns an integer

int value;
AnalogInput x1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_0);
stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.ReadRaw();
}
stopwatch.Stop();

Duration = 2081 mSec 48053/sec
Duration = 2082 mSec 48030/sec
Duration = 2081 mSec 48053/sec
Duration = 2081 mSec 48053/sec
Duration = 2082 mSec 48030/sec
Duration = 2081 mSec 48053/sec
Duration = 2081 mSec 48053/sec
Duration = 2081 mSec 48053/sec
Duration = 2081 mSec 48053/sec
Duration = 2081 mSec 48053/sec

There is also a Secret labs AnalogInput which has a Read method which returns an integer

int value;
SecretLabs.NETMF.Hardware.AnalogInput x1 = new SecretLabs.NETMF.Hardware.AnalogInput(Pins.GPIO_PIN_A0);
stopwatch.Start();
for (int i = 0; i < SampleCount; i++)
{
value = x1.Read();
}
stopwatch.Stop();

Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8564 mSec 11676/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec
Duration = 8563 mSec 11678/sec

The int Microsoft.Spot.Hardware.AnalogInput.ReadRaw() appears to be  quite a bit faster than the other two approaches.

Energy Monitor Shield Sensor Box by Tardis

My initial way of connecting the current sensor for the Energy Monitor Shield was not really suitable for CodeClub. Carefully cutting the insulation with a craft knife and gently pulling out the phase wire could end really badly.

Image

I approached a local company Tardis Communications and they made Code Club these neat enclosures which ensure the students can’t come into contact with any live connections.

Image

Canterbury Software Cluster Internet of Things Presentation

For my presentation last week I prepared a sample xively and Netduino based application to illustrate what could be built with off the shelf kit. I built a wireless home monitoring system which had two energy consumption monitoring devices and a dual temperature sensor device. These devices uploaded their data using MQTT to xively in close to real time. Prices as at May 2014

The devices connected to the internet via a gateway.

Image

The software running on the Netduino was built using the NetMF library from KittyHawkMQ and the nRF24L01+ library from codeplex

Testing the solar powered temperature sensor monitoring my kitchen fridge. The fridge was 4° and the freezer was -18°

Image

The software was based on the nRF24L01library on codeplex,  Brad’s One-Wire and DS18B20 library with fixes from here.

Testing the power consumption monitor devices, with my “modified” power lead.

Image

The software was based on the approach in the Arduino code of the emon libraries from the Open Energy Monitor project which I’ll discuss in more detail in a future post.

Energy Monitor Shield nRF24L01+

The nRF24L01 functionality looked like a good place to start so I had a look at the documentation. The interface for connecting the nRF24L01+ module was specified as

D11 – MOSI
D12 – MISO
D13 – SCK
D8 – RF_CE
D7 – RF_CSN
D2 – RF_IRQ

I have used the Nordic nRF240L1+ .Net Micro Framework Driver on a couple of other projects but initially struggled to get it working with this configuration. After looking at the pin outs of the nRF24L01+ and the Energy Monitor Shield schematic I think the CSN & CE are reversed.(as at March 2014).

This code works and was adapted from the sample application provided with the driver on codeplex

public class nRF240l1Module
{
private const byte channel = 10;
private readonly OutputPort _led = new OutputPort(Pins.ONBOARD_LED, false);
private readonly NRF24L01Plus _module;
private Timer _timer;
private byte _token;

private readonly byte[] _myAddress = Encoding.UTF8.GetBytes(“NetP1”);
//private readonly byte[] _myAddress = Encoding.UTF8.GetBytes(“NetP2”);
private readonly byte[] _otherBoard = Encoding.UTF8.GetBytes(“NetP2”);
//private readonly byte[] _otherBoard = Encoding.UTF8.GetBytes(“NetP1”);

public nRF240l1Module()
{
_module = new NRF24L01Plus();
}

public void Run()
{
_module.OnDataReceived += OnReceive;
_module.OnTransmitFailed += OnSendFailure;
_module.OnTransmitSuccess += OnSendSuccess;

_module.Initialize(SPI.SPI_module.SPI1, Pins.GPIO_PIN_D8, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D2);
_module.Configure(_myAddress, channel, NRFDataRate.DR250kbps);
_module.Enable();

_timer = new Timer(SendMessage, null, new TimeSpan(0, 0, 0, 1), new TimeSpan(0, 0, 0, 1));
}

private void OnSendSuccess()
{
_led.Write(false);
}

private void OnSendFailure()
{
Debug.Print(“Send failed!”);
}

private void OnReceive(byte[] data)
{
Debug.Print(“Token <- ” + data[0]);
}

private void SendMessage(object state)
{
_led.Write(true);
_module.SendTo(_otherBoard, new[] { _token });
Debug.Print(“Token -> ” + _token);
_token++;
}

}

Energy Shield with nRF24L01Plus

Energy Shield with nRF24L01Plus