ATFA is the Ambiente de Testes para Filtros Adaptativos (Testing environment for adaptive filters).
This repository
- provides examples of adaptive filtering algorithms implemented in C++ and C, and exposing the API that ATFA expects;
- explains how to understand the examples, how to modify them, how to write your own algorithms, and how to compile them;
- provides scripts to compile the algorithms into the file format that
ATFA expects, namely dynamic shared objects, or DSOs (
*.so
).
The algorithms must be compiled and linked into an *.so
file. This can
be done manually, or by using the helper script build.py
.
Aditionally, the script build-all.sh
can also be used to compile
all of the examples at once.
If you just want to compile the examples to use from ATFA, type:
$ cd atfa-examples
$ bash build-all.sh
See the section on using the build.py
script for more information.
ATFA accepts custom adaptive filtering algorithms in the form of dynamic
shared object (*.so
) files. Each adaptive filter DSO must export the
following symbols:
The last two (adapf_title
and adapf_listing
) are generated
automatically by the build.py
script. Below, each of the
functions to be exported is explained:
The adapf_init
function initializes (e.g., acquires memory for) the
data structures that the algorithm will use. This data structure might
include, for example, the impulse response vector (vector of filter
coefficients), the input vector, and any other kind of parameter that
the algorithm needs to keep track of.
This function must return a pointer to the initialized data.
This function resets the information contained in data
(e.g., zeroes
out the impulse response that has been learned so far), and returns a
pointer to the zeroed data. This function might free the memory pointed
to by the old data and return a pointer newly allocated-and-initialized
memory.
This function releases the resources acquired in adapf_init
. ATFA will
call it before closing the access to the DSO, in order to prevent memory
leaking. The pointer passed to adapf_close
is the one returned by
adapf_init
, and the value returned from adapf_close
should be zero
if it fails and nonzero otherwise.
This is the function which implements the algorithm itself. Given an
audio sample from the input of the filter (sample
) and an audio
sample from the desired signal (y
), adapf_run
should calculate
the filter output, say y_hat
, and then return the error y - y_hat
.
This function can read from and write to *data
in order to access
and/or update values such as the filter coefficients, the input
vector (with memory), etc.
adapf_run
is the only function that's called from within the audio
run-time loop. The other functions are all allowed to request
resources to the OS, and perform slow operations in general, but this
one isn't.
This function is called by ATFA in order to introspect the filter
coefficients. It must place at *begin
a pointer to the first element
of the array of filter coefficients, and at *n
the number of elements
that can be read from that array (that is, the number of coefficients,
which is N+1
, where N
is the filter order).
This function should just return a static string containing a short
"name" for the adaptive filter algorithm. For example, if the algorithm
is an implementation of the NLMS algorithm with mu=0.7
and
Delta=1.5
, then the returned string could be "NLMS: 0.7, 1.5"
or
maybe just "NLMS"
.
This function must return a static string, just like adapf_title
. The
string returned from adapf_listing
is an algorithmic description of
the adaptive filter, which is shown to the users when they click the
"Show filter code" button in ATFA.
Inside the LMS/
, NLMS/
, and AP/
directories,
you will find C++ source files implementing these three adaptive
filtering algorithms.
The no-op/
direcory contains a file for a dummy algorithm,
which does nothing at all. The source file inside
static-w/
implements a static (instead of an adaptive)
filter (the filter coefficients are never updated). Both of these can
be used for test purposes.
All of the above are implemented in C++. See LMS-C/
for an
example using plain C.
To compile an algorithm into a DSO file to be used with ATFA, you can do
so manually—just generate an *.so
that exports all of the functions
mentioned above—, or you can use the build.py
helper script.
To use this script, open a shell inside the directory containing your
source file(s), and then run the script. For example, to compile the
LMS/
algorithm, type:
$ cd atfa-examples
$ cd LMS
$ python3 ../build.py
By default, build.py
will compile and link all of the *.c
and
*.cpp
files in the current directory. To use a custom set of sources,
just pass them as arguments:
$ python3 ../build.py source1.cpp source2.cpp
The full set of source files specified on the command-line (or present
in the directory, if none is specified) must contain the definitions of
all of the functions mentioned above, except atfa_title
and
atfa_listing
. These will be automatically generated.
By default, the title is made up based on the command line, and the
algorithm listing is just a transcription of the source files. If you
want to use a custom title, use the -t/--title
flag. If you want to
specify a custom file containing the listing, use the -l/--listing
flag:
$ python3 ../build.py --title "My Algorithm" --listing my_algorithm.txt
If you want to provide the atfa_title
or atfa_listing
functions
yourself, use the +t
or +l
flags:
$ python3 ../build.py main_source.cpp title_and_listing.cpp +tl
For more options, type:
$ python3 ../build.py --help
You can also use the convenience script build-all.sh
. This script
will just call python3 ../build.py
from inside each subdirectory of the
current directory. It will also pass the name of the directory in the
--title
flag.