How do we reduce variation of the coordinates.

Hello everyone, i am doing a indoor positioning project, using 4 anchors, 1 pozyx tag and 1 Arduino Uno R3. I can successfully retrieve the coordinates of the position of the tag(mounted on the arduino ) when i move it around. However, when i place it on the table without moving it the coordinates doesn’t stay or rather it varies a lot like around +/- 200.?

Does anyone know how to reduce the variations and get a more accurate reading.? :slight_smile:

I appreciate your help :slight_smile: Thank you very much

Have you considered averaging the values?

Paul

Values like +/- 200 are completely meaningless without stating the units of measurement.

Hello Paul_KD7HB & jremington Thanks for the reply.

Yes, I have tried averaging the values, but it still deviates too much.

Sorry jremington for my negligence, it is in millimetres. +/- 200mm

Pozyx claims +/- 1 cm accuracy, but you claim to be getting +/- 20 cm.

That is a problem that I would bring to the attention of the Pozyx people.

I do have trouble believing that averaging does not help. Averaging should reduce the standard error by a factor of sqrt(N), where N is the number of samples averaged. So, averaging 16 samples should reduce the standard deviation to +/- 5 cm.

Post your code.

Hi jremington Thank you so much for your reply.

I am a little confused about your statement about implementing a square root to lower the standard deviation.

This is my code
:

#include <Pozyx.h>
#include <Pozyx_definitions.h>
#include <Wire.h>

////////////////////////////////////////////////
////////////////// PARAMETERS //////////////////
////////////////////////////////////////////////

uint16_t remote_id ;
boolean use_processing = false;   
bool remote = false;
coordinates_t coor;

const uint8_t num_anchors = 4;                                           // the number of anchors
uint16_t anchors_id[num_anchors] = {0x6e6d, 0x6923, 0x6961, 0x6969};     // the network id of the anchors: change these to the network ids of your anchors.
int32_t anchors_x[num_anchors] =   {0,       0,      3420,    3380};       // anchor x-coorindates in mm
int32_t anchors_y[num_anchors] =   {0,      6880,      0,     6130};       // anchor y-coordinates in mm
int32_t heights[num_anchors]   =   {900,      470,     1060,    760};       // anchor z-coordinates in mm

uint8_t algorithm = POZYX_POS_ALG_TRACKING;                              // positioning algorithm to use. try POZYX_POS_ALG_TRACKING for fast moving objects.
uint8_t dimension = POZYX_3D;                                            // positioning dimension. ( 2.5D fixed height, 3D variable height)

int  setOperationMode(POZYX_TAG_MODE, remote_id);                        //to tell the system that the local device is a tag and not a anchor

////////////////////////////////////////////////

void setup(){
  Serial.begin(115200);
   
  while(!Serial); // for the Arduino Leonardo/Micro only

  Pozyx.begin();

  if(!remote){
    remote_id = NULL;
  }

  Serial.println(F("----------POZYX POSITIONING V1.1----------"));
  Serial.println(F("NOTES:"));
  Serial.println(F("- No parameters required."));
  Serial.println();
  Serial.println(F("- System will auto start anchor configuration"));
  Serial.println();
  Serial.println(F("- System will auto start positioning"));
  Serial.println(F("----------POZYX POSITIONING V1.1----------"));
  Serial.println();
  Serial.println(F("Performing manual anchor configuration:"));

  // clear all previous devices in the device list
    Pozyx.clearDevices(remote_id);
  // sets the anchor manually
  setAnchorsManual();

  delay(2000);
  printCalibrationResult();
  
  Serial.println(F("Starting positioning: "));
  Serial.print("\n");
  
  
}



void loop(){


  coordinates_t position;
    int status;
    
    Pozyx.begin();

    int32_t height = coor.z;                                                      // height of device

  if(remote){
   status = Pozyx.doRemotePositioning(remote_id, &position, dimension, height,algorithm);
  }
  else{
    status = Pozyx.doPositioning(&position, dimension, height, algorithm);
  }
 if (status == POZYX_SUCCESS){
    // prints out the result
    printCoordinates(position);
  }
 
}


// prints the coordinates for either humans or for processing
void printCoordinates(coordinates_t coor){
  if (remote_id == NULL){
    remote_id = 0;
  }

  if(!use_processing){
    Serial.print("POSITION 0x");
    Serial.println(remote_id , HEX);
    Serial.print(", x(mm): ");
    Serial.print(coor.x);
    Serial.print(", y(mm): ");
    Serial.print(coor.y);
    Serial.print(", z(mm): ");
    Serial.println(coor.z);
  }else{
    Serial.print("POSITION 0x");
    Serial.print(remote_id ,HEX);
    Serial.print(",");
    Serial.print(coor.x);
    Serial.print(",");
    Serial.print(coor.y);
    Serial.print(",");
    Serial.println(coor.z);
  }
  return;
}


// function to manually set the anchor coordinates
void setAnchorsManual(){
  for(int i = 0; i < num_anchors; i++){
    device_coordinates_t anchor;                     // Define-ing each anchor as a device_coordinates_t object.
    anchor.network_id = anchors_id[i];
    anchor.flag = 0x1;                               // choose that it is an anchor and not a tag
    anchor.pos.x = anchors_x[i];
    anchor.pos.y = anchors_y[i];
    anchor.pos.z = heights[i];
    Pozyx.addDevice(anchor);                         //adds anchor into the device list of the tag.
  }

}

void printCalibrationResult(){
  
  uint8_t list_size;
  int status;
  
  status = Pozyx.getDeviceListSize(&list_size, remote_id);
  Serial.print("list size: ");
  Serial.println(status*list_size);


  uint16_t anchors_id[list_size];
  Pozyx.getDeviceIds(anchors_id, list_size, remote_id);
  Serial.println(F("Calibration result:"));
  Serial.print(F("Anchors found: "));
  Serial.println(list_size);
  
  coordinates_t anchor_coor;
  for(int i = 0; i < list_size; i++)
  {
    Serial.print("ANCHOR,");
    Serial.print("0x");
    Serial.print(anchors_id[i], HEX);
    Serial.print(",");
    Pozyx.getDeviceCoordinates(anchors_id[i], &anchor_coor, remote_id);
    Serial.print(anchor_coor.x);
    Serial.print(",");
    Serial.print(anchor_coor.y);
    Serial.print(",");
    Serial.println(anchor_coor.z);
  }
}

There is no coordinate averaging in that code. Try it and post the results.

What do you find confusing about this statement?

Averaging should reduce the standard error by a factor of sqrt(N), where N is the number of samples averaged.

Hi jremington, so sorry to trouble you, but thank you so much for your effort to reply and help me.

Maybe your term of " averaging the coordinates " and mine is a little different. Averaging as in adding the coordinates and dividing.?

Averaging, as commonly understood, means to add up N numbers (for example, X-coordinates) and divide the result by N.

Choose a number for N (like 10 or 100) and proceed for X, Y and Z coordinates separately.

Hello jremington, thank you for replying. :)

Alright, i understand where you're coming from right now.

But here's another problem. Let's say for my X Axis, the value for my X Axie is stored inside the variable " coor.x "

each time the void loop() , loops, it produces different X value. So how can i code for it to add up the different X values.? Like for eg, the first time it loops, coor.x = 1000mm , second time it loops, coor.x = 1150, third time it loops coor.x = 1200. when the pozyx isnt even moving, which is the current problem now, when it doesn't move at all the X, Y and Z coordinates varies too much.

Though after each loop the value is different, the variable that stores it is the same. So i don't really know how to code for it.

I am very sure if i just change it like this, the results won't be the expected results.

if(!use_processing){

int avg_x_coor; Serial.print("POSITION 0x"); Serial.println(remote_id , HEX); Serial.print(", x(mm): "); avg_x_coor = coor.x + coor.x; Serial.print(avg_x_coor);

Serial.print(", y(mm): "); Serial.print(coor.y); Serial.print(", z(mm): "); Serial.println(coor.z); }

So i don't really know how to code for the averaging.

i understand where you're coming from now and it makes a lot of sense, just that i am not very familliar with c++ coding, thus i don't know how to code for it. Sorry if i caused a lot of trouble for you.

float avg_x = 0.0;
for (int i=0; i<10; i++) {
   get_new_coordinates(); //or whatever is required
   avg_x = avg_x + coor.x;
}
avg_x = avg_x/10.0; //calculate the average of 10 X coordinates