Noisy data on monitoring program

I have a program for monitoring a sensor and providing feedback:

Control Anything 4-20ma 4 Channel receiver
Particle Photon

  1. I have NOT added any caps or resistors or any electrical circuits to smooth out the data.
  2. I do have a very good power supply.
  3. The photon is set to 16 bit resolution
  4. I have tweaked sampling rates from 5000 to 1.
  5. I am using an industrial Extech Instruments Oyster 4-20ma signal generator which precisely generates signals with accuracy of .01ma in the current loop.

My results show data sampling numbers that are all over the place. The error rate is too large for me to use the data for position feedback in a control circuit and I am not sure if the problem is in the Photon and code or the hardware from Control Anything.

Here is the code:

// This code is designed to work with the MCP3428_I2CADC I2C Mini Module available from ControlEverything.com.
// https://store.ncd.io/shop/?fwp_product_type=4-20ma-input-output

#include <application.h>
#include <spark_wiring_i2c.h>

// MCP3428 I2C address is 0x68(104)
#define Addr 0x68

int raw_adc = 0;
void setup()
{
  // Set variable
  Particle.variable("i2cdevice", "MCP3428");
  Particle.variable("rawADC", raw_adc);

  // Initialise I2C communication as MASTER
  Wire.begin();
  // Start serial communication and set baud rate = 9600
  Serial.begin(9600);
}

void loop()
{
  unsigned int data[2];

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select configuration command
  // Continuous conversion mode, Channel-1, 16-bit resolution, gain 2
  Wire.write(0x19);
  // Stop I2C Transmission
  Wire.endTransmission();
  delay(500);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select data register
  Wire.write(0x00);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Request 2 bytes of data
  Wire.requestFrom(Addr, 2);

  // Read 2 bytes of data
  // raw_adc msb, raw_adc lsb
  if (Wire.available() == 2)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
  }

  // Convert the data to 16-bits
  raw_adc = (data[0]) * 256 + data[1];
  if (raw_adc > 32767)
  {
    raw_adc -= 65536;
  }

  // Output data to console
  Particle.publish("Digital value on Channel-1: ", String(raw_adc));
  delay(1000);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select configuration command
  // Continuous conversion mode, Channel-2, 16-bit resolution, gain 2
  Wire.write(0x39);
  // Stop I2C Transmission
  Wire.endTransmission();
  delay(500);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select data register
  Wire.write(0x00);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Request 2 bytes of data
  Wire.requestFrom(Addr, 2);

  // Read 2 bytes of data
  // raw_adc msb, raw_adc lsb
  if (Wire.available() == 2)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
  }

  // Convert the data to 16-bits
  raw_adc = (data[0]) * 256 + data[1];
  if (raw_adc > 32767)
  {
    raw_adc -= 65536;
  }

  // Output data to console
  Particle.publish("Digital value on Channel-2: ", String(raw_adc));
  delay(1000);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select configuration command
  // Continuous conversion mode, Channel-3, 16-bit resolution gain 2
  Wire.write(0x59);
  // Stop I2C Transmission
  Wire.endTransmission();
  delay(500);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select data register
  Wire.write(0x00);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Request 2 bytes of data
  Wire.requestFrom(Addr, 2);

  // Read 2 bytes of data
  // raw_adc msb, raw_adc lsb
  if (Wire.available() == 2)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
  }

  // Convert the data to 16-bits
  raw_adc = (data[0]) * 256 + data[1];
  if (raw_adc > 32767)
  {
    raw_adc -= 65536;
  }

  // Output data to console
  Particle.publish("Digital value on Channel-3: ", String(raw_adc));
  delay(1000);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select configuration command
  // Continuous conversion mode, Channel-4, 16-bit resolution gain 2
  Wire.write(0x79);
  // Stop I2C Transmission
  Wire.endTransmission();
  delay(500);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select data register
  Wire.write(0x00);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Request 2 bytes of data
  Wire.requestFrom(Addr, 2);

  // Read 2 bytes of data
  // raw_adc msb, raw_adc lsb
  if (Wire.available() == 2)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
  }

  // Convert the data to 16-bits
  raw_adc = (data[0]) * 256 + data[1];
  if (raw_adc > 32767)
  {
    raw_adc -= 65536;
  }

  // Output data to console
  Particle.publish("Digital value on Channel-4: ", String(raw_adc));
  delay(1000);
}

It would help to format your code for readability. You can add this: ```C++

before your code and this: ```

after your code.

I fixed your formatting just now as @ninjatill suggested–you can go back and edit your post by clicking the little pencil icon.

How much noise are you seeing?

Please note that on 4-20mA current loop, a resolution of 0.01mA is still only 1600 steps or around 11 bits of precision. The bottom 5 or 6 bits of your 16-bit result are essentially always going to be random.

2 Likes

When I set the Oyster to say 12ma exactly. I see values from:

at 12ma: 17218 to 17593

at 16ma: 23049 to 23408

at 20ma: 28881 to 29135

I guess these are very accurate. which is certainly within 1600 steps.

to get .01 resolution on positioning in 90 degrees arc of turn, I figure that I need 9,000 data points.

log(9000)/log(2) gives me 13 bit resolution so I am guessing that 16 bit works for what I want to do here?

Hi @ATI

log2(9000) is 13.1357 so to be sure, you would need 14-bit resolution.

More resolution (16-bits say) is not necessarily bad, but you might have to filter your noisy measurements depending on your application.

Could you take your 16-bit measurement value and divide by the number of steps you require? Then use a round() function to get the nearest step. [EDIT: I was tired when I wrote that… I don’t think that’s the correct math.] You can include the math.h library as described here: Round() Function Error - Web IDE [SOLVED]. You can use any of the c++ math.h functions as found here: http://www.cplusplus.com/reference/cmath/.

Actually, using the map() function as described in the docs might get you to where you need to be. There is a discussion on the map() function here: Help 4-20mA Convert Data Code and Adjust Readings