Distance measurement issue

Hello, We have two Dwm3001cdk eavl boards, wew flashed the code downloaded from website, using tera term for serial communication. one board is in initiator and another board is in responder. Distance is showing 30-40 cm less variation from actual. for example we separated the two devices with 150cm but its showing only 100-125 cm and also “LPDoA_deg”:0,“LAoA_deg
˓→”:0,“LFoM”:0,“RAoA_deg”:0,“CFO_ppm”:-120}]}. all measurement values showing 0 only , please help me to calibrate the distance and angle.

A constant offset in range is normally due to an error in antenna delay calibration. This varies slightly unit to unit and an error will result in all measurements being too long or too short.

Hi @omsainath ,

See antenna delay calibration App note for more information Important Notice - Qorvo

About the angle being reported to 0, this is expected as DWM3001CDK has only one antenna and then it’s not able to calculate angle based on this.

Hello wassim, thanks for the reply. The link which you have shared is showing “The document you requested is associated with multiple products and some of these are not currently in Production status”.
can you share the related documents.
Based on your input, DWM3001CDK has only one antenna, and if we use one initiator and two responders, can we able to find angle LPDoA/LAOa??,
can i get any docs reg the angle measurement.

The supplied link works. Scroll down and click the Proceed button.

To get angle information you need a dual antenna device. The angle is calculated by measuring the difference in the same signal being received on both antennas. Two separate units can’t perform this unless they are very tightly synchronised, this is in theory possible but is not a simple task and requires special hardware.
So no, you can’t do it with two responders.

Hi, I’m having problem to process the distance value after the TWR. How did you managed the bias?

Which bias? The range bias caused by the antenna delay?
You measure it and subtract it from the results.

But then that’s true for just about any bias.

If you only have 2 devices then you can’t measure how much of the bias is due to each device but it doesn’t matter much, simply assign it 50/50 between the two. With 3 or more devices you can calculate the delay on each device. There are lots of posts here describing various methods to do this.

Thank You, can I ask you how did you get out CIR values?

By reading the CIR data registers. :slight_smile:

I didn’t use the same hardware as you and it’s been a while since I used the dacawave API but I believe there is a read CIR command. Failing that look up the register number in the user manual and read that.
Three things that sometimes trip people up reading the CIR data:
For each read the first byte received as part of that SPI transaction is junk. If you want 8 bytes of the CIR data you need to read 9 bytes. The CIR is a lot of data so you are normally combining multiple SPI reads to get everything, make sure you remove that junk byte before combining things.
You need to read the CIR after the receive is complete and before re-arming the chip. Once you start a receive or transmit the CIR data is lost.
Make sure you unpack the data correctly. I can’t remember off hand if it was the DW1000 or DW3000 (or both) that had something like 18 bit values for the CIR data. When receiving this data you will probably want to convert it to a signed 32 bit integer. You need to make sure you handle negative numbers correctly. e.g. for an 18 bit number if bit 18 is 1 then set bits 19 to 31 to 1.

Also when plotting that data plot the total magnitude ( sqrt(II + QQ) ), the I and Q data on their own don’t make a lot of sense.

Thank you again for your help, one last question if ever happend to you too. When i capture CIR values i have some problems:
CIR_real_values = [-34 Tn-4 Tn55 Tn28 Tn0 Tn-22 Tn-23 Tn-28 Tn-33 Tn-24 Tn52 Tn108 Tn93 Tn26 Tn-10 Tn23 Tn9 Tn23 Tn-17 Tn-8 Tn27 Tn21 Tn19 Tn-15 Tn-33 Tn-44 Tn-3 Tn43. I have these kind of values. Do you know how to solve these TN values?
Thank you in advance.

this is the code i’m using for the CIR.

void printCIR() {
int CIR_length = 900; // Number of complex CIR samples we want to read
// uint8_t CIR[6 * CIR_length + 1];
// uint8_t CIRsample[3];
int32_t realSample[CIR_length];
int32_t imagSample[CIR_length];
//uint8_t binaryValue[3];
//binaryValue[0]= 0x7F;//127
// binaryValue[1]= 0xFF;//255
//binaryValue[2]= 0xFF; // 255

//int32_t decimalValue = convertBinaryToDecimal(binaryValue);

char* CIR_string_real;
char* CIR_string_real_sv;
char* CIR_string_imag_sv;
char* CIR_string_imag;
//char* teststring;
CIR_string_real = (char*)malloc(5000);
CIR_string_imag = (char*)malloc(5000); // Allocate memory for the string buffer
CIR_string_real_sv = (char*)malloc(10);
CIR_string_imag_sv = (char*)malloc(10); // Allocate memory for the string buffer

//teststring= (char*)malloc(500);
readDW3000CIRData(realSample,imagSample,CIR_length,0);

/* dwt_readaccdata(CIR, 6 * CIR_length + 1, 0);
for (int i = 0; i < CIR_length; i++) {
CIRsample[0] = CIR[i * 6 + 1]; // Assign each element individually
CIRsample[1] = CIR[i * 6 + 2];
CIRsample[2] = CIR[i * 6 + 3];
realSample[i] = readDW3000CIRData(CIRsample,CIR_length,0);
CIRsample[0] = CIR[i * 6 + 4];
CIRsample[1] = CIR[i * 6 + 5];
CIRsample[2] = CIR[i * 6 + 6];
imagSample[i] = readDW3000CIRData(CIRsample,CIR_length,0);
}
*/
// int len = 0; // Current length of the output string
//snprintf(teststring,500,“Check: %ld \n”, decimalValue);
reporter_instance.print(“\nCIR_real_values\n”, 17);
int len = 0;
for (int i = 0; i < CIR_length; i++) {
snprintf(CIR_string_real,10, "%ld ", (realSample[i]));
//len += snprintf(CIR_string_real + len, 5000 - len, “%ld “, (realSample[i]));
reporter_instance.print(CIR_string_real, 10);
}
reporter_instance.print(”\nCIR_imag_values\n”, 17);
len = 0;
for (int i = 0; i < CIR_length; i++) {
snprintf(CIR_string_imag,10, "%ld ", (imagSample[i]));

    //len += snprintf(CIR_string_imag + len, 5000 - len, "%ld ", (imagSample[i]));
    reporter_instance.print(CIR_string_imag, 10);
}

reporter_instance.print(“\n”, 1);

//reporter_instance.print(CIR_string, len);
reporter_instance.print("\nCIR_real_values\n", 17);
//reporter_instance.print(CIR_string, len);

reporter_instance.print(strcat(CIR_string_real, "\n"), 50);

reporter_instance.print("\nCIR_imag_values\n", 17);
reporter_instance.print(strcat(CIR_string_imag, "\n"), 50);
//reporter_instance.print(strcat(teststring, "\n"), 20);

//

free(CIR_string_real);
free(CIR_string_imag); // Deallocate the memory for the string buffer

I’m having trouble following your code. Can you please edit/repost it using the preformated option so that it has sensible formatting. Also include any user defined functions that are being used (readDW3000CIRData doesn’t look to be defined anywhere). It also looks like half those lines are commented out. It would make things simpler if you removed them from your post. Without sensible formating it’s hard to tell which lines are doing something and which are comments.

*[quote=“AndyA, post:12, topic:16517, full:true”]
I’m having trouble following your code. Can you please edit/repost it using the preformated option so that it has sensible formatting. Also include any user defined functions that are being used (readDW3000CIRData doesn’t look to be defined anywhere). It also looks like half those lines are commented out. It would make things simpler if you removed them from your post. Without sensible formating it’s hard to tell which lines are doing something and which are comments.
[/quote]

/// store magnitudes in float array CIRValues
 readDW3000CIRData(int32_t *realvalues, int32_t *imgvalues ,int len, int offset) {

    

    if ((len + offset)>1016)
        len = 1016-offset;
    if (len <1) 
        return false;

    const int bytesPerValue = 6; // dw3000


    uint8_t cir_buffer[1016*bytesPerValue+1]; // worst case

    dwt_readaccdata(cir_buffer, len*bytesPerValue+1, offset);
    int byteAddress = 1;
    for (int i=0;i<len;i++) {
        int32_t iValue = cir_buffer[byteAddress++];
        iValue |= ((int32_t)cir_buffer[byteAddress++]<<8);
        iValue |= ((int32_t)(cir_buffer[byteAddress++] & 0x03)<<16);

        int32_t qValue = cir_buffer[byteAddress++];
        qValue |= ((int32_t)cir_buffer[byteAddress++]<<8);         
        qValue |= ((int32_t)(cir_buffer[byteAddress++] & 0x03)<<16);
	
        if (iValue & 0x020000)  // MSB of 18 bit value is 1
            iValue |= 0xfffc0000;
        if (qValue & 0x020000)  // MSB of 18 bit value is 1
            qValue |= 0xfffc0000;

        realvalues[i]=iValue;
        imgvalues[i]=qValue;
       // *(CIRValues+i) = sqrt((float)(iValue*iValue+qValue*qValue));
    }
    return true;	
}


void printCIR() {
    int CIR_length = 900; // Number of complex CIR samples we want to read
 
    int32_t realSample[CIR_length];
    int32_t imagSample[CIR_length];
    


    char* CIR_string_real;
    char* CIR_string_real_sv;
    char* CIR_string_imag_sv;
    char* CIR_string_imag;
    //char* teststring;
    CIR_string_real = (char*)malloc(5000);
    CIR_string_imag = (char*)malloc(5000); // Allocate memory for the string buffer
    CIR_string_real_sv = (char*)malloc(10);
    CIR_string_imag_sv = (char*)malloc(10); // Allocate memory for the string buffer

    //teststring= (char*)malloc(500);
    readDW3000CIRData(realSample,imagSample,CIR_length,0);
 
  
reporter_instance.print("\nCIR_real_values\n", 17);
   int len = 0;
    for (int i = 0; i < CIR_length; i++) {
        snprintf(CIR_string_real,10, "%ld ", (realSample[i]));
        //len += snprintf(CIR_string_real + len, 5000 - len, "%ld ", (realSample[i]));
        reporter_instance.print(CIR_string_real, 10);
    }
 reporter_instance.print("\nCIR_imag_values\n", 17);
   len = 0;
    for (int i = 0; i < CIR_length; i++) {
          snprintf(CIR_string_imag,10, "%ld ", (imagSample[i]));
  
        //len += snprintf(CIR_string_imag + len, 5000 - len, "%ld ", (imagSample[i]));
        reporter_instance.print(CIR_string_imag, 10);
    }
 reporter_instance.print("\n", 1);
 

    
    reporter_instance.print("\nCIR_real_values\n", 17);
    

    reporter_instance.print(strcat(CIR_string_real, "\n"), 50);

    reporter_instance.print("\nCIR_imag_values\n", 17);
    reporter_instance.print(strcat(CIR_string_imag, "\n"), 50);
  

    free(CIR_string_real);
    free(CIR_string_imag); // Deallocate the memory for the string buffer
}


Sorry for the previous question, i hope this is semplified. I’m writing this in the dw3000_mcps_mcu.c file

I think this is purely an output formatting issue.

snprintf(CIR_string_imag,10, "%ld ", (imagSample[i]));
will populate CIR_string_imag with the number, a space and a null character using up to 10 characters. If the numbers are small then the remaining portion of the allocated 10 bytes of memory will be unchanged.

I’m not sure what the details of your reporter_inastance are doing but I’m guessing that
reporter_instance.print(CIR_string_imag, 10);
Is printing out the 10 bytes starting at CIR_string_imag rather than stopping at the first null character. Which means it’s also printing any junk that was still in that memory.

Try:
int len = snprintf(CIR_string_imag,10, "%ld ", (imagSample[i]));
reporter_instance.print(CIR_string_imag, len);

and see if only printing the characters that snprintf used fixes the issue.

Thank You so much, i think the problem is fixed since i don’t receive any Tn value.
I wanted to ask You if it is normal that when i launch the initiator and the responder command on the two boards, the responder side will show me only the CIR value and not the Distance estimation, while if i don’t use the CIR it will show me the distance.
Thank you again for your time.

Issues like this are what makes c / c++ one of the harder languages to use. Unfortunately they are also what makes it one of the faster and most efficient languages to use. :slight_smile:

There is no reason why you can’t get the CIR and distance at the same time. I’d check that when outputting CIR you’re not skipping part of the ranging code.
The other possibility is that you are hitting timing issues. Reading the CIR data takes a while, if you need to send a reply or listen for a new packet soon after receiving the packet you are getting the CIR from then you may be missing the required time because you’re still reading the data out of the chip.

Also printing the data out over a serial port will take a huge amount of time. Printf isn’t fast and physical serial ports move at a crawl. Unless your serial output is running at full USB speed or is set up to buffer the data and output it in the background then outputting that much data as soon as you get it will guarantee you miss any future time requirements. If timing is critical then save the CIR data into an array and output it later.

Hi AndyA, I tried to read the code i’ve used but it seems it give me always the same output.
What the terminal displays is:
Init side:
initfJS0134{"F PARAMS":{ "SLOT, rstu":2400, "Ranging Period, ms":200, "Ranging round, slots":25, "Ranging round usage (Unicast,SS,DS)":2, "Session_ID":42, "RFRAME":3, "SFD ID":2, "Multi node mode":0, "Round hopping":0, "Vupper64":"0102030405060708", "Initiator Addr":"0x0000", "Responder[0] Addr":"0x0001" }} ok {"Addr":"0x0001","Status":"Err"} {"Addr":"0x0001","Status":"Err"} {"Addr":"0x0001","Status":"Err"} {"Addr":"0x0001","Status":"Err"} {"Addr":"0x0001","Status":"Err"} {"Addr":"0x0001","Status":"Err"}
Reponder side shows me just CIR. I’m sharing with you the code used to launch the fira:

static void report_cb(const struct ranging_results *results, void *user_data) { //anthony 2

   // int32_t binaryValue = 111111111111111111111111;  // Example 24-bit binary value

    //int32_t decimalValue = convertBinaryToDecimal(binaryValue);

    int len = 0;
    struct ranging_measurements *rm;

    struct string_measurement *str_result = (struct string_measurement *)user_data;

    if (results->stopped_reason != 0xFF) {
        len = snprintf(str_result->str, str_result->len, "{\"Session Stopped\":\"%s\"}\r\n",
                      (results->stopped_reason == 0x0) ? "Stop request" :
                      (results->stopped_reason == 0x1) ? "Inband Stop" :
                      (results->stopped_reason == 0x2) ? "Max attempts" : "Unknown");

        reporter_instance.print(str_result->str, len);
        return;
    }

   // len = snprintf(str_result->str, str_result->len, "{\r\n\"Block\": %" PRIu32 ",", results->block_index);

    for (int i = 0; i < results->n_measurements; i++) {
        if (i > 0) {
            len += snprintf(&str_result->str[len], str_result->len - len, ",");
        }

        rm = (struct ranging_measurements *)(&results->measurements[i]);
    
    
        len += snprintf(&str_result->str[len], str_result->len - len,
                        "{\"Addr\":\"0x%04x\",\"Status\":\"%s\"",
                        rm->short_addr, (rm->status) ? ("Err") : ("Ok")); 
                    
        if (rm->status == 0) {
            len += snprintf(&str_result->str[len], str_result->len - len,"\"D_cm\":%d \r\n",
                            (int)(rm->distance_mm / 10));
                            //decimalValue);

And the CIR  is the one before provided. I don't know why it doesn't show me the distance anymore, but it would be really appriciated your help. 
Really sorry for the amount of questions.
Kind Regards.

Also i tried to build two different firmware, one for the responder and one for the initiator.

  1. For the initiator, i didn’t change anything in the code(about the distance and CIR printing).

  2. For the responder, i commented out the PrintCIR function and left the distance part of the code as it is.

When i’m launching the initf & respf command the initiator will list me CIR values very fast, while the responder side is showing distance.
But Will these values be consistent?
Thank You again Andy for helping me.

I’m not sure where the issue is and it’s hard to say without the full code. What you posted will output the results stored in the measurements structure but doesn’t give any indication of how the results get into that structure in the first place.

But what if as you said in your previous answer I’m hitting time issues for the CIR to be read. Do you have some suggest to fix it?