DW1000 : Wrong CIR value from Accumulator

Hi everyone,

I’m working on the detection of LOS/NLOS scenario with DW1000. First, i worked with the reported diagnostics (First path, peak path, amplitude etc…) but i need to go further by analyzing the CIR values in the accumulator. When i plot the values, it seems that there is a lot of noise and the values reported by the diagnostics don’t match any of the value i get from the accumulator data (Amplitude and index of firstPath/peakPath). Moreover, in the different application notes provided by Decawave, the max amplitude of every CIRs figures is lower than 20 000 and mine is greater than 30 000.

Here is the code for the Accumulator data extraction :
- I’m reading tap by tap for memory issue
- The computed magnitude is the approximation of the SQRT func used by the hardware

[font=Courier New]for(int i = 0;i<992;i++)
[/font]
[font=Courier New] {[/font]
[font=Courier New] uint8 cir; cir = (uint8 )malloc(4sizeof(uint8));[/font]
[font=Courier New] dwt_readaccdata(cir, 4, CIR_OFFSET+4
i);[/font]
[font=Courier New] int16 real =0;[/font]
[font=Courier New] int16 imag =0;[/font]
[font=Courier New] double amp = 0;[/font]

[font=Courier New] real = (int16)(cir[1] << 8) | (int16)(cir[0]);/printf("%i,",real);/[/font]
[font=Courier New] imag = (int16)(cir[3] << 8) | (int16)(cir[2]); /printf("%u\n",imag);/[/font]

[font=Courier New] amp = max(abs(real),abs(imag)) + 1/4*min(abs(real),abs(imag));[/font]

[font=Courier New] printf("%u,", real);[/font]
[font=Courier New] printf("%u,",imag);[/font]
[font=Courier New] printf("%f\n", amp);[/font]
[font=Courier New] free(cir);[/font]
[font=Courier New]}[/font]

Im trying to figure out what can be wrong in my process but i’m still stuck with this problem and can’t fix it.

You’ll find in attached file the plot of the CIR magnitude with the data

[font=Courier New] Value read in ACC / Reported value (dw_diagnostics)[/font]
[font=Courier New]------------------------------------[/font]
[font=Courier New]FPAmp1 19690.0 / 339.0[/font]
[font=Courier New]FPAmp2 23830.0 / 278.0[/font]
[font=Courier New]FPAmp3 9238.0 / 209.0[/font]
[font=Courier New]PeakAmp 32256.0 / 727.0[/font]
[font=Courier New]FPAmp 2582.0 / 339.0[/font]
[font=Courier New]PeakIndex 751 / 749.0[/font]

I have read all the application notes and the different thread concerning that problem on this forum but i still can’t manage to fix my problem and go ahead in my work.

Does someone have an idea about this ? :huh: :huh: Thanks a lot for your help !

Best regards,
Morgan

Hi [color=#333333]Morgan,[/color]

[color=#333333]You miss a important point that the first byte is [/color][color=#ff3333]ALWAYS [/color][color=#333333]a dummy byte when you call the dwt_readaccdata().[/color]

[color=#333333]For the details, please read the DW1000 software API guide p.56.[/color]
[color=#333333]You should get the correct result with below highlighted updates.[/color]

[color=#333333][color=#333333][font=Courier New]for(int i = 0;i<992;i++)
[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New]{[/font][/color][/color]
[font=Courier New][color=#333333] uint8 *cir; cir = (uint8 *)malloc([/color][color=#ff3333]5[/color][color=#333333]sizeof(uint8));[/color][/font]
[font=Courier New][color=#333333] dwt_readaccdata(cir, [/color][color=#ff3333][size=small]5[/size][/color][color=#333333], CIR_OFFSET+4
i);[/color][/font]
[color=#333333][color=#333333][font=Courier New] int16 real =0;[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New] int16 imag =0;[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New] double amp = 0;[/font][/color][/color]

[font=Courier New][color=#333333] real = (int16)(cir[[/color][color=#ff3333]2[/color][color=#333333]] << 8) | (int16)(cir[[/color][color=#ff3333]1[/color][color=#333333]]);/printf("%i,",real);/[/color][/font]
[font=Courier New][color=#333333] imag = (int16)(cir[[/color][color=#ff3333]4[/color][color=#333333]] << 8) | (int16)(cir[[/color][color=#ff3333]3[/color][color=#333333]]); /printf("%u\n",imag);/[/color][/font]

[color=#333333][color=#333333][font=Courier New] amp = max(abs(real),abs(imag)) + 1/4*min(abs(real),abs(imag));[/font][/color][/color]

[color=#333333][color=#333333][font=Courier New] printf("%u,", real);[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New] printf("%u,",imag);[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New] printf("%f\n", amp);[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New] free(cir);[/font][/color][/color]
[color=#333333][color=#333333][font=Courier New]}[/font][/color][/color]

[color=#333333]Attached my result for your reference.[/color]

Hi mhc,

Thanks a lot for your reply, it works very well now!

Hi mhc and Courivam,

Thank you for your posts. I am also working on getting the CIR data, and your posts helped me a lot. But when I applied your code to my project, I cannot make it display correctly. I am using MDEK1001 and displaying results via UART. I appreciate if you could let me know what’s wrong. The screenshot is attached and the code is shown below:

/*! ----------------------------------------------------------------------------

  • @file ss_init_main.c
    */
    #include <stdio.h>
    #include <string.h>
    #include “FreeRTOS.h”
    #include “task.h”
    #include “deca_device_api.h”
    #include “deca_regs.h”
    #include “port_platform.h”

#define APP_NAME “SIMPLE RX with Diag”

/* Inter-ranging delay period, in milliseconds. */
#define RNG_DELAY_MS 4500

static uint8 rx_resp_msg[] = {0xC5, 0, ‘D’, ‘E’, ‘C’, ‘A’, ‘W’, ‘A’, ‘V’, ‘E’, 0, 0};
/* Length of the common part of the message (up to and including the function code, see NOTE 1 below). /
#define ALL_MSG_COMMON_LEN 10
/
Indexes to access some of the fields in the frames defined above. */
#define ALL_MSG_SN_IDX 1
#define RESP_MSG_POLL_RX_TS_IDX 10
#define RESP_MSG_RESP_TX_TS_IDX 14
#define RESP_MSG_TS_LEN 4

#define ACCUM_DATA_LEN 1016

static dwt_rxdiag_t rx_diag;

/* Buffer to store received response message.

  • Its size is adjusted to longest frame that this example code is supposed to handle. */
    #define RX_BUF_LEN 127
    static uint8 rx_buffer[RX_BUF_LEN];

/* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */
static uint32 status_reg = 0;

/*Transactions Counters */
static volatile int tx_count = 0 ; // Successful transmit counter
static volatile int rx_count = 0 ; // Successful receive counter

/*! ------------------------------------------------------------------------------------------------------------------

  • @fn main()

  • @brief Application entry point.

  • @param none

  • @return none
    /
    int ss_init_run(void)
    {
    /
    Loop forever initiating ranging exchanges. */
    int i;
    for(i=0;i<RX_BUF_LEN;i++){
    rx_buffer[i] = 0;
    }

    rx_diag.firstPath = 0;
    rx_diag.firstPathAmp1 = 0;
    rx_diag.firstPathAmp2 = 0;
    rx_diag.firstPathAmp3 = 0;
    rx_diag.maxGrowthCIR = 0;
    rx_diag.rxPreamCount = 0;
    rx_diag.maxNoise = 0;
    rx_diag.stdNoise = 0;

    dwt_rxenable(DWT_START_RX_IMMEDIATE);

    while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
    {};

    if (status_reg & SYS_STATUS_RXFCG)
    {

    uint16 frame_len = 0;

    // frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_MASK;
    frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;

    if (frame_len <= RX_BUF_LEN)
    {
    dwt_readrxdata(rx_buffer, frame_len, 0);
    }

    /* Clear good RX frame event in the DW1000 status register. */
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);

    tx_count = rx_buffer[ALL_MSG_SN_IDX];
    rx_buffer[ALL_MSG_SN_IDX] = 0;
    if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0)
    {
    rx_count++;
    printf(“Reception # : %d\r\n”,rx_count);
    printf(“Received from # %d transmission \r\n”, tx_count);

    dwt_readdiagnostics(&rx_diag);
    
    uint16 fp_int = rx_diag.firstPath / 64;
    
    printf("Count of preamble symbols accumulated: %d \r\n",rx_diag.rxPreamCount);
    printf("Index of first path is %d \r\n", rx_diag.firstPath / 64);
    printf("CIR max growth CIR: % d \r\n",rx_diag.maxGrowthCIR);
    printf("LDE max value of noise: %d \r\n", rx_diag.maxNoise);
    printf("Std of noise is %d \r\n",rx_diag.stdNoise);
    printf("First Path AMP2: %d \r\n",rx_diag.firstPathAmp2);
    printf("First Path AMP3: %d \r\n",rx_diag.firstPathAmp3);
    printf("First Path AMP1: %d \r\n",rx_diag.firstPathAmp1);
    
    // read accumulated data
    for (i=0;i<ACCUM_DATA_LEN;i++){
      uint8 *cir;
      cir = (uint8 *)malloc(5*sizeof(uint8));
      dwt_readaccdata(cir,5, 4*i);
      int16 real = 0;
      int16 imag = 0;
      // double amp = 0;
    
      real = (int16) (cir[2]<<8) | (int16)(cir[1]);
      imag = (int16) (cir[4]<<8) | (int16)(cir[3]);
      // amp = MAX(abs(real),abs(imag)) + 1/4*MIN(abs(real),abs(imag));
    
      printf("%u,",real);
      printf("%u \n",imag);
      // printf("%f\n", amp);
    
      free(cir);
    }
    

    }
    }
    else
    {
    /* Clear RX error/timeout events in the DW1000 status register. */
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);

    /* Reset RX to properly reinitialise LDE operation. */
    dwt_rxreset();
    }

    /* Execute a delay between ranging exchanges. */
    // deca_sleep(RNG_DELAY_MS);

    // return(1);
    }

/*! ------------------------------------------------------------------------------------------------------------------

/**@brief SS TWR Initiator task entry function.
*

  • @param[in] pvParameter Pointer that will be used as the parameter for the task.
    */
    void ss_initiator_task_function (void * pvParameter)
    {
    UNUSED_PARAMETER(pvParameter);

    //dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);

    dwt_setleds(DWT_LEDS_ENABLE);

    while (true)
    {
    ss_init_run();
    /* Delay a task for a given number of ticks /
    vTaskDelay(RNG_DELAY_MS);
    /
    Tasks must be implemented to never return… */
    }
    }

Hi Chang,

In windows, you must add “\r\n” for the newline.
As the real and imag value is signed value, so it is better to using %d to display.
Otherwise, you will see a large value of integer but not a negative value.

[color=#333333]printf("%[/color][color=#ff3333]d[/color][color=#333333],",real);[/color]
[color=#333333]printf("%[/color][color=#cc3333]d \r[/color][color=#333333]\n",imag);[/color]
[color=#333333]// printf("%f\n", amp);[/color]
[hr]

Hi Morgan,

May I know which library you use in below caculation?
I am just wondering why below calculation can find the amplitude of a complex number as it do not use the math of square and square root.

[color=#333333][font=Courier New]amp = max(abs(real),abs(imag)) + 1/4*min(abs(real),abs(imag));[/font][/color]

Hi mhc,

Thanks for your reply and kind help. After using “\r\n” it looks better now. However, there is still one issue, which you can see from the attached screenshot. After several lines, the display becomes strange. Do you know the reason of this problem? Thank you so much in advance.

The code is the same as I showed in my last post. I only changed “\n” to “\r\n”.

Hi Morgan,

I am also interested to know why you used

amp = max(abs(real),abs(imag)) + 1/4*min(abs(real),abs(imag));

to calculate the amplitude. Could you provide a reference?

Thanks.

Best regards,
Chang

Hi Chang,
Indeed, the hardware does not use the SQRT function to compute the magnitude but the function [ MAX(I,Q) + MIN(I,Q)/4 ] where I,Q are the imaginary and real part read in the accumulator. I have no other references than this thread on this forum https://www.decawave.com/decaforum/archive/index.php?thread-4.html.

Regards.

HI All Is there an updated CODE ?? I would love if some one can send me this!!

Hi !

I may have something for you, it’s the code i wrote and works well to extract the CIR from the DW1000

void dwNLOS_ExtractAndPrintCIR()
{
	for(int i = 0;i<992;i++)
{
	uint8 *cir; cir = (uint8 *)malloc(5*sizeof(uint8));
	dwt_readaccdata(cir, 5, CIR_OFFSET+4*i);
	int16 real =0;
	int16 imag =0;
	double amp=0;
	real =  (int16)cir[2] << 8 | (int16)cir[1];/*printf("%i,",real);*/
	imag =  (int16)cir[4] << 8 | (int16)cir[3]; /*printf("%u\n",imag);*/
	
	amp = max(abs(real),abs(imag)) + min(abs(real),abs(imag))/4;
	printf("%u,",real);
	printf("%u,",imag);
	printf("%f,,,,,,,,,\n",amp);
	free(cir);
}

}

the function dwt_readaccdata() is provided in the file “deca_device.c”

1 Like

Hi! I am read CIR value from Accumulator, but the results show a lot of peaks and the max value is more than 30000, why this happened? Here is the code I got the data
int main(void)
{
/* Start with board specific hardware init. /
peripherals_init();
/
Display application name on LCD. /
// lcd_display_str(APP_NAME);
/
Reset and initialise DW1000.
* For initialisation, DW1000 clocks must be temporarily set to crystal speed. After initialisation SPI rate can be increased for optimum
* performance. /
reset_DW1000();//??DW1000 /
Target specific drive of RSTn line into DW1000 low for a period. /
spi_set_rate_low();
dwt_initialise(DWT_LOADUCODE);
ProgramSetup();
spi_set_rate_high();
/
Configure DW1000. See NOTE 6 below. */
dwt_configure(&config);

/* Apply default antenna delay value. See NOTE 1 below. */
dwt_setrxantennadelay(RX_ANT_DLY);		
dwt_settxantennadelay(TX_ANT_DLY);	
  send[0]=0x6DD6;

/* Set expected response's delay and timeout. See NOTE 4 and 5 below.
 * As this example only handles one incoming frame with always the same delay and timeout, those values can be set here once for all. */
dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS);
dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);			

tx_poll_msg[GROUPID] = GROUP_ID;
if(Work_Mode)
{
tx_poll_msg[SOURCEID] = ANCHOR_ID|0x80;

	}else{
		tx_poll_msg[SOURCEID] = TAG_ID;
	}
/* Loop forever initiating ranging exchanges. */

// if(Work_Mode&&ANCHOR_ID==0)
// {Timer_Init();
// }
if(!Work_Mode) (ANCHOR??)
{
while (1)
{

	UART_CheckReceive();
    jumptime =5;
					/* Write frame data to DW1000 and prepare transmission. See NOTE 7 below. */
		dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS);
    dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);
		tx_poll_msg[MESSAGETYPE] = POLL;
		//tx_poll_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
		dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0);
		dwt_writetxfctrl(sizeof(tx_poll_msg), 0);
		/* Start transmission, indicating that a response is expected so that reception is enabled automatically after the frame is sent and the delay
		 * set by dwt_setrxaftertxdelay() has elapsed. */
		dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);
		/* Increment frame sequence number after transmission of the poll message (modulo 256). */
		frame_seq_nb++;
		deca_sleep(1000);
		//Delayms(1000);
	}}else{
	while (1)//ANCHOR
{
		int i;
		 for(i=0;i<FRAME_LEN_MAX;i++){
		    rx_buffer[i]=0;
		 }
	   for(i=0;i<ACCUM_DATA_LEN;i++){
		    accum_data[i]=0;
		 }
	   rx_diag.firstPath=0;
		 rx_diag.firstPathAmp1=0;
		 rx_diag.firstPathAmp2=0;
		 rx_diag.firstPathAmp3=0;
		 rx_diag.maxGrowthCIR=0;
		 rx_diag.maxNoise=0;
		 fp_int=0;

		dwt_setrxtimeout(0);
	  dwt_rxenable(0);
//	 USART_putc(0x01);
  while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR)))
		{ UART_CheckReceive();};
		if (status_reg & SYS_STATUS_RXFCG)
		{ 
				uint32 frame_len;
			//	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
				/* Clear good RX frame event in the DW1000 status register. */
				dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
				/* A frame has been received, read it into the local buffer. */
				frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
				dwt_readrxdata(rx_buffer, frame_len, 0);
				
			//	USART_putc(0x02);
				/* Check that the frame is a poll sent by "DS TWR initiator" example.
				 * As the sequence number field of the frame is not relevant, it is cleared to simplify the validation of the frame. */
			rx_buffer[ALL_MSG_SN_IDX] = 0;
			dwt_readdiagnostics(&rx_diag);
    fp_int=rx_diag.firstPath/64;			dwt_readaccdata(accum_data,ACCUM_DATA_LEN,(fp_int - 5) *4 );
    for(i=0;i<ACCUM_DATA_LEN;i++){
			  send[i+1]=accum_data[i];
			}
    //send[i+9]=0x0001;				
			USART_puts((uint8_t*)send,(1+ACCUM_DATA_LEN)*2);
			Delayms(1000);
	 	}else{}
		/* Clear RX error events in the DW1000 status register. */
		dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
}	
}

}

Why does my CIR data show this?image

Hi,Courivam
I have some problem with your code. When I rebuild the project. I get error: use of undeclared identifier ‘CIR_OFFSET’ . Could you please tell me how can I solve the problem.
Thank you!
Best regard.
yzdll

Hi, how did you solve this problem? what is CIR_OFFSET?

Hi Nori,
Thank you. I get only zero values. The CIR can be plotted for only one packet received by the receiver?