Generate a Test Data Buffer

From DSignT Support Database
Jump to: navigation, search

1 Generate a Buffer with Test Data

To debug and test signal processing algorithms it is recommended to use a test data set instead of "real world" data acquired by an ADC. The following code shows an example to generate a buffer filled with a sine wave. The data is truncated to the desired resolution and optionally dithered.

1.1 Includes

#include <stdint.h>
#include <math.h>

1.2 Defines

The following defines control the signal generation.

#define PI 3.1415926535898  /**< pi                                   */
#define FS_IN 	     44100  /**< input sampling frequency in Hz       */
#define RES_IN   	16  /**< input resolution in bits             */
#define SIG_IN        1000  /**< input signal frequency in Hz         */
#define AMPL_IN      0.995  /**< input signal amplitude (0.0 - 1.0)   */
#define PHASE_IN    (PI/2)  /**< input signal phase (-pi to pi)       */

#define INBUF_SIZE      32768

#define DITHER_NONE	0    /**< no dither                           */
#define DITHER_RECT	1    /**< flat spectrum 1/2 LSB	dither        */
#define DITHER_TRIANGLE	2    /**< high-pass filtered triangular dither*/
#define DITHER_SHAPED	3    /**< Lipschitz minimal audible dither    */

#define DITHER_TYPE	(DITHER_SHAPED)
#define DITHERSCALE  	(1.0/((double)RAND_MAX - 0.5))

1.3 Buffer

Depending on the selected resolution the generated test data set is stored in an int8_t, int16_t or int32_t buffer. Data is always stored left justified, i.e. if RES_IN was set to 12, data is stored in a 16-bit buffer with D[15]=MSB, D[4] = LSB, and D[3:0] = 0

#if RES_IN <= 8
int8_t acqbuf[INBUF_SIZE];
#elif RES_IN <= 16
int16_t acqbuf[INBUF_SIZE];
#else
int32_t acqbuf[INBUF_SIZE];
#endif

1.4 Functions

1.4.1 quantisize()

This function quantisizes a normalized double float (range -1.0 to 1.0) to the desired integer size and optionally performs dithering

/*******************************************************************//**
 @brief     quantisize a normalized double (-1 to +1) to
            N-bit integer and store in buffer

 @param	    data        - double data
 @param     bits        - resolution in bits
 @param     buffer_addr - storage location

 @return    next buffer address

 @note	    requires the following defines:
 @note	    - DITHER_TYPE (DITHER_NONE, DITHER_RECT,
              DITHER_TRIANGLE, or DITHER_SHAPED)

***********************************************************************/
uint32_t quantisize (double data, uint32_t bits, uint32_t buffer_addr)
{
    /*******************************************************************
      locals
    *******************************************************************/
    double scale;
    uint32_t addr = buffer_addr;

#if DITHER_TYPE != DITHER_NONE
    double r;
#endif

#if DITHER_TYPE == DITHER_TRIANGLE
    static double dither_last = 0.0;
#endif

#if DITHER_TYPE == DITHER_SHAPED
    /* Lipshitz's minimally audible FIR */
    static double dither_coeff[5]  = {2.033, -2.165, 1.959, -1.590, 0.6149};
    static double dither_buffer[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    static uint32_t dither_phase = 0;
    uint32_t idx;
    double x;
#endif

    /*******************************************************************
      scale data
    *******************************************************************/
    scale = pow(2.0, (double)(bits-1)) - 2.0;
    data = data * scale;

#if DITHER_TYPE == DITHER_NONE
    /*******************************************************************
      round to nearest integer
    *******************************************************************/
    data = floor (data + 0.5);
#endif

#if (DITHER_TYPE == DITHER_RECT)
    /*******************************************************************
      add dither and round to nearest integer
    *******************************************************************/
    r = (double)rand() * DITHERSCALE;
    data = floor (data + r + 0.5);
#endif

#if (DITHER_TYPE == DITHER_TRIANGLE)
    /*******************************************************************
      add high-pass filtered dither and round to nearest integer
    *******************************************************************/
    r = (double)rand() * DITHERSCALE;
    data = floor (data + r - dither_last + 0.5);
    dither_last = r;
#endif

#if DITHER_TYPE == DITHER_SHAPED
    /*******************************************************************
      dither noise shaping in FIR filter
      add noise shaped + triangular dither
      store last error and roll buffer
    *******************************************************************/
    x = data;
    for (idx = 0; idx < 5; idx++)
    {
	x = x + dither_buffer[(dither_phase - idx) & 7] * dither_coeff[idx];
    }
    r = (double)rand() * DITHERSCALE;
    r += (double)rand() * DITHERSCALE;
    data = x + r;

    dither_phase++;
    dither_phase &= 7;
    data = floor (data + 0.5);
    dither_buffer[dither_phase] = x - data;
#endif

    /*******************************************************************
      saturate
    *******************************************************************/
    if (data > scale) data = scale;
    if (data < -scale) data = -scale;

    /*******************************************************************
      store in buffer
    *******************************************************************/
    if (bits <= 8)
    {
        *(int8_t *)addr = (int8_t)data << (8-bits);
        addr += 1;
    }
    else if (bits <= 16)
    {
        *(int16_t *)addr = (int16_t)data << (16-bits);
        addr +=2;
    }
    else
    {
        *(int32_t *)addr = (int32_t)data << (32-bits);
        addr += 4;
    }

    /*******************************************************************
      update address
    *******************************************************************/
    return addr;
}
1.4.2 Sinewave Generator

generate a sinewave, calls quantisize

/*******************************************************************//**
 @brief     generate a sinewave signal

 @param	    fs - sampling frequency in Hz
 @param	    fsig - signal frequency in Hz
 @param	    asig - signal amplitude (0.0 to 1.0)
 @param	    psig - signal phase (-pi to pi)
 @param     bits - signal resolution in bits
 @param	    buffer - pointer to buffer memory
 @param	    buffersize - size of buffer in samples

 @note	    output array is left justified
 @note      calls quantisize()

***********************************************************************/
void sinegen ( uint32_t fs, double fsig, double asig, double psig, uint32_t bits, void* buffer, uint32_t buffersize)
{
    /*******************************************************************
      locals
    *******************************************************************/
    double arg;
    double tmp;
    uint32_t idx;
    uint32_t addr = (uint32_t)buffer;

    /*******************************************************************
      calculate argument
    *******************************************************************/
    arg = 2.0 * PI * fsig / (double)fs;

    /*******************************************************************
      calculate sinewave
    *******************************************************************/
    for (idx = 0; idx < buffersize; idx++)
    {
	tmp = asig * sin (arg * (double)idx  + psig);
	addr = quantisize (tmp, bits, addr);
    }
}
1.4.3 Example
/***********************************************************************

  MAIN PROGRAM

***********************************************************************/
void main (void)
{
    /*******************************************************************
      generate acquisition sample buffer
    *******************************************************************/
    sinegen (FS_IN, SIG_IN, AMPL_IN, PHASE_IN, RES_IN, acqbuf, INBUF_SIZE);
}

1.5 Dither Modes

The following spectrum plots show the effect of dithering: 16bit no dither.png 16bit rectangular dither.png 16bit triangular hp dither.png 16bit shaped dither.png


Arr u.png    back to top

2 Additional Tags

Sinewave Dither Noiseshaping



Contact Post.png Support Tool.png