liquid-dsp documentation¶
Software-Defined Radio Digital Signal Processing Library - https://liquidsdr.org
liquid-dsp is a free and open-source digital signal processing (DSP) library designed specifically for software-defined radios on embedded platforms. The aim is to provide a lightweight DSP library that does not rely on a myriad of external dependencies or proprietary and otherwise cumbersome frameworks. All signal processing elements are designed to be flexible, scalable, and dynamic, including filters, filter design, oscillators, modems, synchronizers, complex mathematical operations, and much more.
// get in, process data, get out
#include <liquid/liquid.h>
int main() {
unsigned int M = 4; // interpolation factor
unsigned int m = 12; // filter delay [symbols]
float As = 60.0f; // filter stop-band attenuation [dB]
// create interpolator from prototype
firinterp_crcf interp = firinterp_crcf_create_kaiser(M,m,As);
float complex x = 1.0f; // input sample
float complex y[M]; // interpolated output buffer
// repeat on input sample data as needed
{
firinterp_crcf_execute(interp, x, y);
}
// destroy interpolator object
firinterp_crcf_destroy(interp);
return 0;
}
For more information, please refer to the documentation online.
Installation and Dependencies¶
liquid-dsp only relies on libc
and libm
(standard C and math)
libraries to run; however liquid will take advantage of other libraries
(such as FFTW if they are available.
Starting with version 1.7.0, liquid-dsp has moved to the
CMake build system which can be installed with
brew install cmake
on macOS,
sudo apt-get install cmake
on Debian variants.
Installation¶
The recommended way to obtain the source code is to clone the entire repository from GitHub:
git clone git://github.com/jgaeddert/liquid-dsp.git
Building and installing the main library is a simple as
mkdir build
cd build
cmake ..
make
sudo make install
If you are installing on Linux for the first time, you will also need
to rebind your dynamic libraries with sudo ldconfig
to make the
shared object available.
This is not necessary on macOS.
Run all test scripts¶
Source code validation is a critical step in any software library,
particularly for verifying the portability of code to different
processors and platforms. Packaged with liquid-dsp are a number of
automatic test scripts to validate the correctness of the source code.
The test scripts are located under each module’s tests/
directory and
take the form of a C source file. When configured with BUILD_AUTOTESTS
enabled, these tests are parsed, compliled, and linked into an executable
which will run the tests.
./xautotest
# ...
# autotest seed: 1738416409
# ==================================
# PASSED ALL 716450 CHECKS
# ==================================
There are currently more than 700,000 checks across 1,316 tests to verify functional correctness. Drop me a line if these aren’t running on your platform.
Testing Code Coverage¶
In addition to the full test suite, you can configure gcc
to export symbol
files to check for code coverage and then use gcovr
to generate a full
report of precisely which lines are covered in the autotests. These symbol
files aren’t generated by default and need to be enabled at compile-time
through a CMake option:
cmake -DBUILD_AUTOTESTS=ON -DCOVERAGE=ON ..
A coverage report can be generated by running the autotests and running gcovr:
make -j4 xautotest
./xautotest -q -o autotest.json
cd ..
gcovr --filter="src/.*/src/.*.c" --print-summary
# ...
# ------------------------------------------------------------------------------
# TOTAL 20730 17014 82%
# ------------------------------------------------------------------------------
# lines: 82.1% (17014 out of 20730)
# functions: 62.9% (1742 out of 2770)
# branches: 64.0% (5676 out of 8874)
Examples¶
Nearly all signal processing elements have a corresponding example in
the examples/
directory. Most example scripts generate an output
.m
file for plotting with GNU octave
All examples are built as stand-alone programs and can be compiled with
the BUILD_EXAMPLES
CMake flag:
cmake -DBUILD_EXAMPLES=ON ..
make
./examples/modem_example -m qpsk
# <liquid.modemcf, scheme="qpsk", order=4>
# 0 : 0.70710677 + j* 0.70710677
# 1 : -0.70710677 + j* 0.70710677
# 2 : 0.70710677 + j* -0.70710677
# 3 : -0.70710677 + j* -0.70710677
# num sym errors: 0 / 4
# num bit errors: 0 / 8
# results written to modem_example.m.
Sometimes, however, it is useful to build one example individually.
This can be accomplished by directly targeting its binary
(e.g. make examples/modem_example
). The example then can be run at the
command line, viz. ./examples/modem_example
.
Benchmarking Tool¶
Packaged with liquid are benchmarks to determine the speed each signal processing element can run on your machine. Initially the tool provides an estimate of the processor’s clock frequency and will then estimate the number of trials so that each benchmark will take between 50 and 500 ms to run. You can build and run the benchmark program with the following command:
make bench
Linking from C++¶
Compiling and linking to C++ programs is straightforward.
Just include <complex>
before <liquid/liquid.h>
and use
std::complex<float>
in favor of float complex
.
Here is the same example as the one above but in C++ instead of C:
// get in, process data, get out
#include <complex>
#include <liquid/liquid.h>
int main() {
unsigned int M = 4; // interpolation factor
unsigned int m = 12; // filter delay [symbols]
float As = 60.0f; // filter stop-band attenuation [dB]
// create interpolator from prototype
firinterp_crcf interp = firinterp_crcf_create_kaiser(M,m,As);
std::complex<float> x = 1.0f; // input sample
std::complex<float> y[M]; // interpolated output buffer
// repeat on input sample data as needed
{
firinterp_crcf_execute(interp, x, y);
}
// destroy interpolator object
firinterp_crcf_destroy(interp);
return 0;
}
PlatformIO¶
Cross-compling for embedded platforms is most easily achieved with
platformio.
Just add liquid-dsp
to your platform.io
list of dependencies:
[env:native]
platform = native
lib_deps = https://github.com/jgaeddert/liquid-dsp.git
To test this, compile the example program for a Raspberry Pi Pico microcontroller:
# create a virtual environment, install platformio, and compile an example
virtualenv pio
source pio/bin/activate
pip install platformio
pio ci --lib="." --board=pico examples/platformio_example.c
# ...
# Generating UF2 image
# elf2uf2 ".pio/build/pico/firmware.elf" ".pio/build/pico/firmware.uf2"
# Checking size .pio/build/pico/firmware.elf
# Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
# RAM: [== ] 15.5% (used 41820 bytes from 270336 bytes)
# Flash: [ ] 0.2% (used 5196 bytes from 2097152 bytes)
# Building .pio/build/pico/firmware.bin
# ===================== [SUCCESS] Took 23.63 seconds =====================
Build¶
Here is a table of CMake options available for configuring liquid:
Option |
Default |
Description |
---|---|---|
|
ON |
Compile example programs |
|
ON |
Parse and compile autotests into executable binary |
|
ON |
Parse and compile benchmarks into executable binary |
|
ON |
Enable use of single instruction, multiple data (SIMD) extensions |
|
OFF |
Compile sandbox (testing) programs |
|
OFF |
Generate documentation |
|
OFF |
Set flags to enable code coverage testing |
For example, if you want to benchmark how fast a vector dot product runs without SIMD extensions, you could run the following:
cmake -DENABLE_SIMD=OFF -DBUILD_BENCHMARKS=ON ..
make
./benchmark -s dotprod_rrrf
Available Modules¶
agc: automatic gain control, received signal strength
audio: source audio encoders/decoders: cvsd, filterbanks
buffer: internal buffering, circular/static, ports (threaded)
channel: additive noise, multi-path fading, carrier phase/frequency offsets, timing phase/rate offsets
dotprod: inner dot products (real, complex), vector sum of squares
equalization: adaptive equalizers: least mean-squares, recursive least squares, semi-blind
fec: basic forward error correction codes including several Hamming codes, single error correction/double error detection, Golay block code, as well as several checksums and cyclic redundancy checks, interleaving, soft decoding
fft: fast Fourier transforms (arbitrary length), discrete sin/cos transforms
filter: finite/infinite impulse response, polyphase, hilbert, interpolation, decimation, filter design, resampling, symbol timing recovery
framing: flexible framing structures for amazingly easy packet software radio; dynamically adjust modulation and coding on the fly with single- and multi-carrier framing structures
math: transcendental functions not in the C standard library (gamma, besseli, etc.), polynomial operations (curve-fitting, root-finding, etc.)
matrix: basic math, LU/QR/Cholesky factorization, inversion, Gauss elimination, Gram-Schmidt decomposition, linear solver, sparse matrix representation
modem: modulate, demodulate, PSK, differential PSK, QAM, optimal QAM, as well as analog and non-linear digital modulations GMSK)
multichannel: filterbank channelizers, OFDM
nco: numerically-controlled oscillator: mixing, frequency synthesis, phase-locked loops
optim: (non-linear optimization) Newton-Raphson, evoluationary algorithms, gradient descent, line search
quantization: analog/digital converters, compression/expansion
random: (random number generators) uniform, exponential, gamma, Nakagami-m, Gauss, Rice-K, Weibull
sequence: linear feedback shift registers, complementary codes, maximal-length sequences
utility: useful miscellany, mostly bit manipulation (shifting, packing, and unpacking of arrays)
vector: generic vector operations
License¶
liquid projects are released under the X11/MIT license.
By default, this project will try to link to FFTW if it
is available on your build platform.
Because FFTW starting with version 1.3 is
licensed
under the GNU General Public License v2
this unfortunately means that (and I’m clearly not a lawyer, here)
you cannot distribute liquid-dsp
without also distributing the source code
if you link to FFTW.
This is a similar situation with the classic
libfec
which uses the
GNU Lesser GPL.
Finally, liquid-dsp
makes extensive use of GNU
autoconf,
automake,
and related tools.
These are fantastic libraires with amazing functionality and their authors
should be lauded for their efforts.
In a similar vain, much the software I write for a living I give away for
free;
however I believe in more permissive licenses to allow individuals the
flexibility to use software with fewer limitations.
If these restrictions are not acceptible, liquid-dsp
can be compiled and run
without use of these external libraries, albeit a bit slower and with limited
functionality.
Short version: this code is copyrighted to me (Joseph D. Gaeddert), I give you full permission to do whatever you want with it except remove my name from the credits. Seriously, go nuts! but take caution when linking to other libraries with different licenses. See the license for specific terms.
Here is some math
Here is some math inline \(a^2 + b^2 = c^2\) that gets rendered properly. We can refer to (1) as well!