C-ASPT QUICK START GUIDE

C-ASPT Quick Start Guide

C-ASPT Naming Conventions

The C-Language Adaptive Signal Processing Toolbox (C-ASPT) defines each of its filters as a C-language structure. The library provides APIs to easily and efficiently work with each filter without the need to know details of the filter internal data structures. C-ASPT provides several implementations for each filter in the different supported data types. For instance, a single precision and double precision floating point LMS adaptive filters can be used simultaneously in the same application by using an asptLms32f and an asptLms64f filters. Other applications might use 16-bit and 32-bit signed integer NLMS filters by declaring an asptNlms16s and asptNlms32s variables. The naming convention should be clear by now, C-ASPT filter names consist of three sections. The first is the aspt prefix, the second is the algorithm name with the first letter in Capital, and the third is the data type used in the calculations. The data type part can be one of the following, 64f (64-bit float), 32f (32-bit float), 32s (32-bit signed integer), or 16s (16-bit signed integers). Note that the current release implements the 64f and 32f versions only.

C-ASPT defines several API functions for each filter, the most important ones are those performing initialization and filtering/update functions. The APIs are consistent throughout the whole library, which makes it very easy to learn how to use it. For instance, if you know how to use one filter, you will probably be able to use any other filter as easily, since the API functions are almost the same for all the filters (within the range the filter algorithm itself allows). The naming conventions of the API functions are also easy to understand, and you do not need to memorize the function names for each filter. For instance, to initialize an NLMS filter of 10 adaptive coefficients and filter a signal of L samples stored in the array x[] through the filter while updating the coefficients so that the filter output approaches the signal d[], you would use the following code fragment (assuming using single precision floating point).

              #include "aspt32f.h" /* All aspt declarations              */
              asptNlms32f nlms;    /* declare a static NLMS structure    */
              /* initialize nlms to be 10 coef. and use 0.01 step size   */
              nlms32fInit(&nlms,10, 0.01f);
              for(i=0;i<L;i++)     /* filter and update the coefficients */
              nlms32fFilterUpdate(&nlms, x[i], d[i]);
            

From this example, you can guess the C-ASPT API naming conventions. Each API name consists of three parts. The first indicates the algorithm used (for example nlms or bfdaf), the second indicates the data type, and the third indicates the function performed by the API with the first letter in Capital. As another simple example, suppose we would like to replace the above NLMS by a simpler (in terms of computation complexity) LMS filter. This is easily done by just replacing each occurrence of nlms in the above code by lms as following.

              #include "aspt32f.h" /* All aspt declarations              */
              asptLms32f lms;      /* declare a static NLMS structure    */
              /* initialize nlms to be 10 coef. and use 0.01 step size   */
              lms32fInit(&lms,10, 0.01f);
              for (i=0;i<L;i++)    /* filter and update the coefficients */
              lms32fFilterUpdate(&lms, x[i], d[i]);
            

The above example is very simplistic, since the API parameters of the LMS matches those of the NLMS filter, but the example clearly shows the naming convention, which is essential to using ASPT.

Back To Top

C-ASPT API Summary

Several API functions are defined for each C-ASPT filter. The main API functions are more or less identical across all filters, although more complex filter algorithms define more APIs, and less complex ones define less APIs. The table below summarizes the API functions common to most filters and explain their purpose. The single precision floating point NLMS filter is used here as an example. The input parameters and return values have been omitted in the table for clarity. APIs implemented as macros are indicated by [MACRO] sign.

API Description
API to create and delete an asptNlms32f filters
nlms32fInit() Initializes an asptNlms32f filter using the input parameters and dynamically allocates the memory storage required for the filter coefficients, delay line, and other necessary storage.
nlms32fInitStatic() Initializes an asptNlms32f but does no memory allocation. Pointers to a two pre-allocated (possibly static) memory location are passed to this function, one to be used for filter coefficients and the other for data storage. This separation makes ASPT ready for porting to platforms with several memory buses (DSPs).
nlms32fFree() This function is used to free the memory previously allocated by nlms32fInit(). No similar function is needed for nlms32fInitStatic() since it does not allocate any memory, it uses the given pre-allocated (or static) memory.
API to filter through and update an asptNlms32f filters
nlms32fFilterUpdate() Filters one sample through this filter (FIR mode) and updates the filter coefficients according to the NLMS algorithm.
nlms32fFilterOnly() Filters one sample through this filter (FIR mode) but does not update the filter coefficients. It also updates the internal filter states to quickly converge when updating starts again. This function is required by many ITU-T standards, such as the G.165 and G.168 echo cancellers.
nlms32fLCFilterUpdate() Filters one sample through this filter (Linear Combiner mode) and updates the filter coefficients according to the NLMS algorithm. The linear combiner mode allows many input signals to be processed in parallel, which is necessary for array processing for instance.
nlms32fLCFilterOnly() Filters one sample through this filter (Linear Combiner mode) but does not update the filter coefficients. It also updates the internal filter states to quickly converge when updating starts again.
API to retrieve the properties of an asptNlms32f filter
nlms32fGetCoef() Copies N internal filter coefficients starting from coefficient number I to a given buffer, optionally inverting the coefficient order while copying.
nlms32fGetDelayLine() Copies N samples from the filter internal delay line starting from coefficient number I to a given buffer, optionally inverting the samples order while copying.
nlms32fGetCoefPtr() [MACRO] Returns a pointer to the filter coefficients vector.
nlms32fGetFilterLength() [MACRO] Returns this filter's number of filter coefficients.
nlms32fGetDelayLineLength() [MACRO] Returns this filter's delay line length. Delay line length is not necessary equals to the filter length.
nlms32fGetLastErrorSample() [MACRO] FilterUpdate functions store the error sample in an internal variable that can be retrieved by calling this macro.
nlms32fGetStepSize() [MACRO] Returns this filter's convergence constant (step size).
API to set the properties of an asptNlms32f filter
nlms32fReset() Resets all filter coefficients of this filter to zeros. This function is necessary for many ITU-T standards such as G-165 and G-168 echo cancellers. It is an external reset button for the filter.
nlms32fResetDelayLine() Resets all samples in this filter's delay line to zeros.
nlms32fResize() Changes the filter size (number of coefficients) on-the-fly while keeping as much of the filter state as possible, so that no interruption of the filter output occur for samples processed after resizing. This function can be used with dynamically allocated filters only.
nlms32fSetCoef() Sets N of this filter's coefficients starting from coefficient number I to the contents of the given buffer, optionally reversing the order of the buffer contents while copying.
nlms32fSetDelayLine() Sets N of this filter's delay line samples starting from sample number I to the contents of the given buffer, optionally reversing the order of the buffer contents while copying.
nlms32fSetStepSize() [MACRO] Changes this filter's step size to the new given value.


Back To Top

A Complete Example

In this section the complete source code for a practical system identification application using the Block Frequency Domain Adaptive Filter (BFDAF) is given. The BFDAF filter is a very efficient and fast converging filter, which makes it very attractive for demanding real-time adaptive applications, and also makes the example more interesting. This example demonstrate how C-ASPT functions are used in block processing mode, and shows how little code is needed to create and successfully employ such a complex filter in an practical application. The code assumes that an experiment has already been performed to collect the required data for the system identification process (obtaining a model for a physical system). The experiment is simply feeding the physical system to be modeled by an input signal and recording both the input and the system response (its output). The measured input signal is used as input to the adaptive filter and the system output is used as a desired signal as shown in the figure below. The code assumes that 5000 samples have been collected, the input samples are to be placed in the inpBuf[] array and the system output (adaptive model desired signal) is to be placed in the desBuf[]. The adaptive system identification process then tries to adjust the filter coefficients so that the filter output becomes as close as possible to the measured physical system response. If this is successful, the adaptive filters coefficients will be close to the physical system impulse response.

The application first declares an asptBfdaf32f filter and initializes it using bfdaf32fInit() to have 10 time domain coefficients (we expect the physical system response to be approximately 10 samples long), and the filter will process 6 samples each call to bfdaf32fFilterUpdate(). In this example, constrained BFDAF filter is used with a step size of 0.05. Note that the pointers to the tables required for the Fast Fourier Transform (FFT) are also passed to bfdaf32fInit(). Those tables can be created in a header file (in this case rfft16.h) by the mktable tool provided with C-ASPT. The application also checks that the filter has been created successfully by looking whether the init function returned an integer less than zero, which indicates an error. Following initialization, the processing loop is started, in each iteration, 6 samples of the input and desired are processed by bfdaf32fFilterUpdate() to calculate 6 samples of the model output and update the frequency domain filter coefficients. After processing all samples, the model coefficients should be a good estimate of the physical system transfer function (assuming the process has converged). The time-domain filter coefficients are then copied to the sys[] buffer to be used, for example, in designing a controller for this physical system.

              #include "asptbfdaf32f.h"  /* defines the BFDAF filter and its APIs */
              #include "rfft16.h"        /* defines bit reversal and twiddle factor
              tables for 16-point real FFT */

              #define NSAMPLES 5000
              int main(int argc, char* argv[])
              {
              int          i;
              asptBfdaf32f bfdaf ;       /* adaptive filter               */
              int          NC = 10;      /* filter length                 */
              int          NL = 6;       /* block length                  */
              int          cs = 1;       /* use constrained BFDAF         */
              float        mu = 0.05f;   /* step size                     */
              int         *ip = ip16;    /* FFT twiddle factor table      */
              float       *w  = w16;     /* bit reversal table            */
              float       sys[10];       /* unknown system coefficients   */
              float	inpBuf[NSAMPLES];    /* measured system input signal  */
              float	desBuf[NSAMPLES];    /* measured system output signal */
              float	errBuf[NSAMPLES];    /* estimation error              */
              float	outBuf[NSAMPLES];    /* filter output                 */

              /* Copy here the measured system input to inpBuf   */
              /* Copy here the measured system output to outBuf  */
              /* Initialize the asptBfdaf filter            */
              i = bfdaf32fInit(&bfdaf,NC,NL,mu,cs, ip,w);
              if (i < 0){
              printf("Error creating asptBfdaf filter\n");
              exit(-1);
              }

              for (i=0; i < (NSAMPLES-Nl);i+=Nl)	{
              /* filter and update the filter coefficients */
              bfdaf32fFilterUpdate(&bfdaf, inpBuf[i], desBuf[i], outBuf[i],errBuf[i]);
              }


              /* coefficients of bfdaf are now equal to the system transfer function
              copy NL coefficients starting at index 0 to external buffer.     */
              bfdaf32fGetCoef(&bfdaf, sys, 0, NL, 0);
              bfdaf32fFree(&bfdaf);
              return 0;
              }
            


Back To Top