CubicSDR/external/liquid-dsp/include/liquid/liquid.h
2014-11-07 00:39:53 -05:00

5730 lines
259 KiB
C++

/*
* Copyright (c) 2007 - 2014 Joseph Gaeddert
*
* This file is part of liquid.
*
* liquid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* liquid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with liquid. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LIQUID_H__
#define __LIQUID_H__
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4003 )
#endif
#ifdef __cplusplus
extern "C" {
# define LIQUID_USE_COMPLEX_H 0
#else
# define LIQUID_USE_COMPLEX_H 1
#endif // __cplusplus
//
// Make sure the version and version number macros weren't defined by
// some prevoiusly included header file.
//
#ifdef LIQUID_VERSION
# undef LIQUID_VERSION
#endif
#ifdef LIQUID_VERSION_NUMBER
# undef LIQUID_VERSION_NUMBER
#endif
//
// Compile-time version numbers
//
// LIQUID_VERSION = "X.Y.Z"
// LIQUID_VERSION_NUMBER = (X*1000000 + Y*1000 + Z)
//
#define LIQUID_VERSION "1.2.0"
#define LIQUID_VERSION_NUMBER 1002000
//
// Run-time library version numbers
//
extern const char liquid_version[];
const char * liquid_libversion(void);
int liquid_libversion_number(void);
// run-time library validation
#define LIQUID_VALIDATE_LIBVERSION \
if (LIQUID_VERSION_NUMBER != liquid_libversion_number()) { \
fprintf(stderr,"%s:%u: ", __FILE__,__LINE__); \
fprintf(stderr,"error: invalid liquid runtime library\n"); \
exit(1); \
} \
#define LIQUID_CONCAT(prefix, name) prefix ## name
#define LIQUID_VALIDATE_INPUT
/*
* Compile-time complex data type definitions
*
* Default: use the C99 complex data type, otherwise
* define complex type compatible with the C++ complex standard,
* otherwise resort to defining binary compatible array.
*/
#if LIQUID_USE_COMPLEX_H==1
# include <complex.h>
# define LIQUID_DEFINE_COMPLEX(R,C) typedef R _Complex C
#elif defined _GLIBCXX_COMPLEX || defined _LIBCPP_COMPLEX
# define LIQUID_DEFINE_COMPLEX(R,C) typedef std::complex<R> C
#else
# define LIQUID_DEFINE_COMPLEX(R,C) typedef struct {R real; R imag;} C;
#endif
//# define LIQUID_DEFINE_COMPLEX(R,C) typedef R C[2]
LIQUID_DEFINE_COMPLEX(float, liquid_float_complex);
LIQUID_DEFINE_COMPLEX(double, liquid_double_complex);
//
// MODULE : agc (automatic gain control)
//
#define AGC_MANGLE_CRCF(name) LIQUID_CONCAT(agc_crcf, name)
#define AGC_MANGLE_RRRF(name) LIQUID_CONCAT(agc_rrrf, name)
// large macro
// AGC : name-mangling macro
// T : primitive data type
// TC : input/output data type
#define LIQUID_AGC_DEFINE_API(AGC,T,TC) \
typedef struct AGC(_s) * AGC(); \
\
/* create automatic gain control object */ \
AGC() AGC(_create)(void); \
\
/* destroy object, freeing all internally-allocated memory */ \
void AGC(_destroy)(AGC() _q); \
\
/* print object properties to stdout */ \
void AGC(_print)(AGC() _q); \
\
/* reset object's internal state */ \
void AGC(_reset)(AGC() _q); \
\
/* execute automatic gain control on an single input sample */ \
/* _q : automatic gain control object */ \
/* _x : input sample */ \
/* _y : output sample */ \
void AGC(_execute)(AGC() _q, \
TC _x, \
TC * _y); \
\
/* execute automatic gain control on block of samples */ \
/* _q : automatic gain control object */ \
/* _x : input data array, [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _y : output data array, [szie: _n x 1] */ \
void AGC(_execute_block)(AGC() _q, \
TC * _x, \
unsigned int _n, \
TC * _y); \
\
/* lock/unlock gain control */ \
void AGC(_lock)( AGC() _q); \
void AGC(_unlock)(AGC() _q); \
\
/* get/set loop filter bandwidth; attack/release time */ \
float AGC(_get_bandwidth)(AGC() _q); \
void AGC(_set_bandwidth)(AGC() _q, float _bt); \
\
/* get/set signal level (linear) relative to unity energy */ \
float AGC(_get_signal_level)(AGC() _q); \
void AGC(_set_signal_level)(AGC() _q, float _signal_level); \
\
/* get/set signal level (dB) relative to unity energy */ \
float AGC(_get_rssi)(AGC() _q); \
void AGC(_set_rssi)(AGC() _q, float _rssi); \
\
/* get/set gain value (linear) relative to unity energy */ \
float AGC(_get_gain)(AGC() _q); \
void AGC(_set_gain)(AGC() _q, float _gain); \
\
/* initialize internal gain on input array */ \
/* _q : automatic gain control object */ \
/* _x : input data array, [size: _n x 1] */ \
/* _n : number of input, output samples */ \
void AGC(_init)(AGC() _q, \
TC * _x, \
unsigned int _n); \
// Define agc APIs
LIQUID_AGC_DEFINE_API(AGC_MANGLE_CRCF, float, liquid_float_complex)
LIQUID_AGC_DEFINE_API(AGC_MANGLE_RRRF, float, float)
//
// MODULE : audio
//
// CVSD: continuously variable slope delta
typedef struct cvsd_s * cvsd;
// create cvsd object
// _num_bits : number of adjacent bits to observe (4 recommended)
// _zeta : slope adjustment multiplier (1.5 recommended)
// _alpha : pre-/post-emphasis filter coefficient (0.9 recommended)
// NOTE: _alpha must be in [0,1]
cvsd cvsd_create(unsigned int _num_bits,
float _zeta,
float _alpha);
// destroy cvsd object
void cvsd_destroy(cvsd _q);
// print cvsd object parameters
void cvsd_print(cvsd _q);
// encode/decode single sample
unsigned char cvsd_encode(cvsd _q, float _audio_sample);
float cvsd_decode(cvsd _q, unsigned char _bit);
// encode/decode 8 samples at a time
void cvsd_encode8(cvsd _q, float * _audio, unsigned char * _data);
void cvsd_decode8(cvsd _q, unsigned char _data, float * _audio);
//
// MODULE : buffer
//
// circular buffer
#define CBUFFER_MANGLE_FLOAT(name) LIQUID_CONCAT(cbufferf, name)
#define CBUFFER_MANGLE_CFLOAT(name) LIQUID_CONCAT(cbuffercf, name)
// large macro
// CBUFFER : name-mangling macro
// T : data type
#define LIQUID_CBUFFER_DEFINE_API(CBUFFER,T) \
typedef struct CBUFFER(_s) * CBUFFER(); \
\
/* create circular buffer object of a particular size */ \
CBUFFER() CBUFFER(_create)(unsigned int _max_size); \
\
/* create circular buffer object of a particular size and */ \
/* specify the maximum number of elements that can be read */ \
/* at any given time. */ \
CBUFFER() CBUFFER(_create_max)(unsigned int _max_size, \
unsigned int _max_read); \
\
/* destroy cbuffer object, freeing all internal memory */ \
void CBUFFER(_destroy)(CBUFFER() _q); \
\
/* print cbuffer object properties */ \
void CBUFFER(_print)(CBUFFER() _q); \
\
/* print cbuffer object properties and internal state */ \
void CBUFFER(_debug_print)(CBUFFER() _q); \
\
/* clear internal buffer */ \
void CBUFFER(_clear)(CBUFFER() _q); \
\
/* get the number of elements currently in the buffer */ \
unsigned int CBUFFER(_size)(CBUFFER() _q); \
\
/* get the maximum number of elements the buffer can hold */ \
unsigned int CBUFFER(_max_size)(CBUFFER() _q); \
\
/* get the maximum number of elements you may read at once */ \
unsigned int CBUFFER(_max_read)(CBUFFER() _q); \
\
/* get the number of available slots (max_size - size) */ \
unsigned int CBUFFER(_space_available)(CBUFFER() _q); \
\
/* is buffer full? */ \
int CBUFFER(_is_full)(CBUFFER() _q); \
\
/* write a single sample into the buffer */ \
/* _q : circular buffer object */ \
/* _v : input sample */ \
void CBUFFER(_push)(CBUFFER() _q, \
T _v); \
\
/* write samples to the buffer */ \
/* _q : circular buffer object */ \
/* _v : output array */ \
/* _n : number of samples to write */ \
void CBUFFER(_write)(CBUFFER() _q, \
T * _v, \
unsigned int _n); \
\
/* remove and return a single element from the buffer */ \
/* _q : circular buffer object */ \
/* _v : pointer to sample output */ \
void CBUFFER(_pop)(CBUFFER() _q, \
T * _v); \
\
/* read buffer contents */ \
/* _q : circular buffer object */ \
/* _num_requested : number of elements requested */ \
/* _v : output pointer */ \
/* _nr : number of elements referenced by _v */ \
void CBUFFER(_read)(CBUFFER() _q, \
unsigned int _num_requested, \
T ** _v, \
unsigned int * _num_read); \
\
/* release _n samples from the buffer */ \
void CBUFFER(_release)(CBUFFER() _q, \
unsigned int _n); \
// Define buffer APIs
LIQUID_CBUFFER_DEFINE_API(CBUFFER_MANGLE_FLOAT, float)
LIQUID_CBUFFER_DEFINE_API(CBUFFER_MANGLE_CFLOAT, liquid_float_complex)
// Windowing functions
#define WINDOW_MANGLE_FLOAT(name) LIQUID_CONCAT(windowf, name)
#define WINDOW_MANGLE_CFLOAT(name) LIQUID_CONCAT(windowcf, name)
// large macro
// WINDOW : name-mangling macro
// T : data type
#define LIQUID_WINDOW_DEFINE_API(WINDOW,T) \
\
typedef struct WINDOW(_s) * WINDOW(); \
\
/* create window buffer object of length _n */ \
WINDOW() WINDOW(_create)(unsigned int _n); \
\
/* recreate window buffer object with new length */ \
/* _q : old window object */ \
/* _n : new window length */ \
WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n); \
\
/* destroy window object, freeing all internally memory */ \
void WINDOW(_destroy)(WINDOW() _q); \
\
/* print window object to stdout */ \
void WINDOW(_print)(WINDOW() _q); \
\
/* print window object to stdout (with extra information) */ \
void WINDOW(_debug_print)(WINDOW() _q); \
\
/* clear/reset window object (initialize to zeros) */ \
void WINDOW(_clear)(WINDOW() _q); \
\
/* read window buffer contents */ \
/* _q : window object */ \
/* _v : output pointer (set to internal array) */ \
void WINDOW(_read)(WINDOW() _q, T ** _v); \
\
/* index single element in buffer at a particular index */ \
/* _q : window object */ \
/* _i : index of element to read */ \
/* _v : output value pointer */ \
void WINDOW(_index)(WINDOW() _q, \
unsigned int _i, \
T * _v); \
\
/* push single element onto window buffer */ \
/* _q : window object */ \
/* _v : single input element */ \
void WINDOW(_push)(WINDOW() _q, \
T _v); \
\
/* write array of elements onto window buffer */ \
/* _q : window object */ \
/* _v : input array of values to write */ \
/* _n : number of input values to write */ \
void WINDOW(_write)(WINDOW() _q, \
T * _v, \
unsigned int _n); \
// Define window APIs
LIQUID_WINDOW_DEFINE_API(WINDOW_MANGLE_FLOAT, float)
LIQUID_WINDOW_DEFINE_API(WINDOW_MANGLE_CFLOAT, liquid_float_complex)
//LIQUID_WINDOW_DEFINE_API(WINDOW_MANGLE_UINT, unsigned int)
// wdelay functions : windowed-delay
// Implements an efficient z^-k delay with minimal memory
#define WDELAY_MANGLE_FLOAT(name) LIQUID_CONCAT(wdelayf, name)
#define WDELAY_MANGLE_CFLOAT(name) LIQUID_CONCAT(wdelaycf, name)
#define WDELAY_MANGLE_UINT(name) LIQUID_CONCAT(wdelayui, name)
// large macro
// WDELAY : name-mangling macro
// T : data type
#define LIQUID_WDELAY_DEFINE_API(WDELAY,T) \
typedef struct WDELAY(_s) * WDELAY(); \
\
/* create delay buffer object with '_delay' samples */ \
WDELAY() WDELAY(_create)(unsigned int _delay); \
\
/* re-create delay buffer object with '_delay' samples */ \
/* _q : old delay buffer object */ \
/* _delay : delay for new object */ \
WDELAY() WDELAY(_recreate)(WDELAY() _q, \
unsigned int _delay); \
\
/* destroy delay buffer object, freeing internal memory */ \
void WDELAY(_destroy)(WDELAY() _q); \
\
/* print delay buffer object's state to stdout */ \
void WDELAY(_print)(WDELAY() _q); \
\
/* clear/reset state of object */ \
void WDELAY(_clear)(WDELAY() _q); \
\
/* read delayed sample from delay buffer object */ \
/* _q : delay buffer object */ \
/* _v : value of delayed element */ \
void WDELAY(_read)(WDELAY() _q, \
T * _v); \
\
/* push new sample into delay buffer object */ \
/* _q : delay buffer object */ \
/* _v : new value to be added to buffer */ \
void WDELAY(_push)(WDELAY() _q, \
T _v); \
// Define wdelay APIs
LIQUID_WDELAY_DEFINE_API(WDELAY_MANGLE_FLOAT, float)
LIQUID_WDELAY_DEFINE_API(WDELAY_MANGLE_CFLOAT, liquid_float_complex)
//LIQUID_WDELAY_DEFINE_API(WDELAY_MANGLE_UINT, unsigned int)
//
// MODULE : dotprod (vector dot product)
//
#define DOTPROD_MANGLE_RRRF(name) LIQUID_CONCAT(dotprod_rrrf,name)
#define DOTPROD_MANGLE_CCCF(name) LIQUID_CONCAT(dotprod_cccf,name)
#define DOTPROD_MANGLE_CRCF(name) LIQUID_CONCAT(dotprod_crcf,name)
// large macro
// DOTPROD : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_DOTPROD_DEFINE_API(DOTPROD,TO,TC,TI) \
\
/* run dot product without creating object [unrolled loop] */ \
/* _v : coefficients array [size: _n x 1] */ \
/* _x : input array [size: _n x 1] */ \
/* _n : dotprod length, _n > 0 */ \
/* _y : output sample pointer */ \
void DOTPROD(_run)( TC *_v, TI *_x, unsigned int _n, TO *_y); \
void DOTPROD(_run4)(TC *_v, TI *_x, unsigned int _n, TO *_y); \
\
typedef struct DOTPROD(_s) * DOTPROD(); \
\
/* create dot product object */ \
/* _v : coefficients array [size: _n x 1] */ \
/* _n : dotprod length, _n > 0 */ \
DOTPROD() DOTPROD(_create)(TC * _v, \
unsigned int _n); \
\
/* re-create dot product object */ \
/* _q : old dotprod object */ \
/* _v : coefficients array [size: _n x 1] */ \
/* _n : dotprod length, _n > 0 */ \
DOTPROD() DOTPROD(_recreate)(DOTPROD() _q, \
TC * _v, \
unsigned int _n); \
\
/* destroy dotprod object, freeing all internal memory */ \
void DOTPROD(_destroy)(DOTPROD() _q); \
\
/* print dotprod object internals to standard output */ \
void DOTPROD(_print)(DOTPROD() _q); \
\
/* execute dot product */ \
/* _q : dotprod object */ \
/* _x : input array [size: _n x 1] */ \
/* _y : output sample pointer */ \
void DOTPROD(_execute)(DOTPROD() _q, \
TI * _x, \
TO * _y); \
LIQUID_DOTPROD_DEFINE_API(DOTPROD_MANGLE_RRRF,
float,
float,
float)
LIQUID_DOTPROD_DEFINE_API(DOTPROD_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
LIQUID_DOTPROD_DEFINE_API(DOTPROD_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
//
// sum squared methods
//
float liquid_sumsqf(float * _v,
unsigned int _n);
float liquid_sumsqcf(liquid_float_complex * _v,
unsigned int _n);
//
// MODULE : equalization
//
// least mean-squares (LMS)
#define EQLMS_MANGLE_RRRF(name) LIQUID_CONCAT(eqlms_rrrf,name)
#define EQLMS_MANGLE_CCCF(name) LIQUID_CONCAT(eqlms_cccf,name)
// large macro
// EQLMS : name-mangling macro
// T : data type
#define LIQUID_EQLMS_DEFINE_API(EQLMS,T) \
typedef struct EQLMS(_s) * EQLMS(); \
\
/* create LMS EQ initialized with external coefficients */ \
/* _h : filter coefficients (NULL for {1,0,0...}) */ \
/* _p : filter length */ \
EQLMS() EQLMS(_create)(T * _h, \
unsigned int _p); \
\
/* create LMS EQ initialized with square-root Nyquist */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _k : samples/symbol */ \
/* _m : filter delay (symbols) */ \
/* _beta : rolloff factor (0 < beta <= 1) */ \
/* _dt : fractional sample delay */ \
EQLMS() EQLMS(_create_rnyquist)(int _type, \
unsigned int _k, \
unsigned int _m, \
float _beta, \
float _dt); \
\
/* re-create EQ initialized with external coefficients */ \
/* _q : equalizer object */ \
/* _h : filter coefficients (NULL for {1,0,0...}) */ \
/* _p : filter length */ \
EQLMS() EQLMS(_recreate)(EQLMS() _q, \
T * _h, \
unsigned int _p); \
\
/* destroy equalizer object, freeing all internal memory */ \
void EQLMS(_destroy)(EQLMS() _q); \
\
/* reset equalizer object, clearing internal state */ \
void EQLMS(_reset)(EQLMS() _q); \
\
/* print equalizer internal state */ \
void EQLMS(_print)(EQLMS() _q); \
\
/* get/set equalizer learning rate */ \
float EQLMS(_get_bw)(EQLMS() _q); \
void EQLMS(_set_bw)(EQLMS() _q, \
float _lambda); \
\
/* push sample into equalizer internal buffer */ \
void EQLMS(_push)(EQLMS() _q, \
T _x); \
\
/* execute internal dot product and return result */ \
/* _q : equalizer object */ \
/* _y : output sample */ \
void EQLMS(_execute)(EQLMS() _q, \
T * _y); \
\
/* step through one cycle of equalizer training */ \
/* _q : equalizer object */ \
/* _d : desired output */ \
/* _d_hat : actual output */ \
void EQLMS(_step)(EQLMS() _q, \
T _d, \
T _d_hat); \
\
/* get equalizer's internal coefficients */ \
/* _q : equalizer object */ \
/* _w : weights [size: _p x 1] */ \
void EQLMS(_get_weights)(EQLMS() _q, \
T * _w); \
\
/* train equalizer object on group of samples */ \
/* _q : equalizer object */ \
/* _w : input/output weights [size: _p x 1] */ \
/* _x : received sample vector [size: _n x 1] */ \
/* _d : desired output vector [size: _n x 1] */ \
/* _n : input, output vector length */ \
void EQLMS(_train)(EQLMS() _q, \
T * _w, \
T * _x, \
T * _d, \
unsigned int _n); \
LIQUID_EQLMS_DEFINE_API(EQLMS_MANGLE_RRRF, float);
LIQUID_EQLMS_DEFINE_API(EQLMS_MANGLE_CCCF, liquid_float_complex);
// recursive least-squares (RLS)
#define EQRLS_MANGLE_RRRF(name) LIQUID_CONCAT(eqrls_rrrf,name)
#define EQRLS_MANGLE_CCCF(name) LIQUID_CONCAT(eqrls_cccf,name)
// large macro
// EQRLS : name-mangling macro
// T : data type
#define LIQUID_EQRLS_DEFINE_API(EQRLS,T) \
typedef struct EQRLS(_s) * EQRLS(); \
\
/* create RLS EQ initialized with external coefficients */ \
/* _h : filter coefficients (NULL for {1,0,0...}) */ \
/* _p : filter length */ \
EQRLS() EQRLS(_create)(T * _h, \
unsigned int _p); \
\
/* re-create RLS EQ initialized with external coefficients */ \
/* _q : initial equalizer object */ \
/* _h : filter coefficients (NULL for {1,0,0...}) */ \
/* _p : filter length */ \
EQRLS() EQRLS(_recreate)(EQRLS() _q, \
T * _h, \
unsigned int _p); \
\
/* destroy equalizer object, freeing all internal memory */ \
void EQRLS(_destroy)(EQRLS() _q); \
\
/* print equalizer internal state */ \
void EQRLS(_print)(EQRLS() _q); \
\
/* reset equalizer object, clearing internal state */ \
void EQRLS(_reset)(EQRLS() _q); \
\
/* get/set equalizer learning rate */ \
float EQRLS(_get_bw)(EQRLS() _q); \
void EQRLS(_set_bw)(EQRLS() _q, \
float _mu); \
\
/* push sample into equalizer internal buffer */ \
void EQRLS(_push)(EQRLS() _q, T _x); \
\
/* execute internal dot product and return result */ \
/* _q : equalizer object */ \
/* _y : output sample */ \
void EQRLS(_execute)(EQRLS() _q, T * _y); \
\
/* step through one cycle of equalizer training */ \
/* _q : equalizer object */ \
/* _d : desired output */ \
/* _d_hat : actual output */ \
void EQRLS(_step)(EQRLS() _q, T _d, T _d_hat); \
\
/* retrieve internal filter coefficients */ \
/* _q : equalizer object */ \
/* _w : weights [size: _p x 1] */ \
void EQRLS(_get_weights)(EQRLS() _q, \
T * _w); \
\
/* train equalizer object on group of samples */ \
/* _q : equalizer object */ \
/* _w : input/output weights [size: _p x 1] */ \
/* _x : received sample vector [size: _n x 1] */ \
/* _d : desired output vector [size: _n x 1] */ \
/* _n : input, output vector length */ \
void EQRLS(_train)(EQRLS() _q, \
T * _w, \
T * _x, \
T * _d, \
unsigned int _n);
LIQUID_EQRLS_DEFINE_API(EQRLS_MANGLE_RRRF, float);
LIQUID_EQRLS_DEFINE_API(EQRLS_MANGLE_CCCF, liquid_float_complex);
//
// MODULE : fec (forward error-correction)
//
// soft bit values
#define LIQUID_SOFTBIT_0 (0)
#define LIQUID_SOFTBIT_1 (255)
#define LIQUID_SOFTBIT_ERASURE (127)
// available CRC schemes
#define LIQUID_CRC_NUM_SCHEMES 7
typedef enum {
LIQUID_CRC_UNKNOWN=0, // unknown/unavailable CRC scheme
LIQUID_CRC_NONE, // no error-detection
LIQUID_CRC_CHECKSUM, // 8-bit checksum
LIQUID_CRC_8, // 8-bit CRC
LIQUID_CRC_16, // 16-bit CRC
LIQUID_CRC_24, // 24-bit CRC
LIQUID_CRC_32 // 32-bit CRC
} crc_scheme;
// pretty names for crc schemes
extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2];
// Print compact list of existing and available CRC schemes
void liquid_print_crc_schemes();
// returns crc_scheme based on input string
crc_scheme liquid_getopt_str2crc(const char * _str);
// get length of CRC (bytes)
unsigned int crc_get_length(crc_scheme _scheme);
// generate error-detection key
//
// _scheme : error-detection scheme
// _msg : input data message, [size: _n x 1]
// _n : input data message size
unsigned int crc_generate_key(crc_scheme _scheme,
unsigned char * _msg,
unsigned int _n);
// validate message using error-detection key
//
// _scheme : error-detection scheme
// _msg : input data message, [size: _n x 1]
// _n : input data message size
// _key : error-detection key
int crc_validate_message(crc_scheme _scheme,
unsigned char * _msg,
unsigned int _n,
unsigned int _key);
// available FEC schemes
#define LIQUID_FEC_NUM_SCHEMES 28
typedef enum {
LIQUID_FEC_UNKNOWN=0, // unknown/unsupported scheme
LIQUID_FEC_NONE, // no error-correction
LIQUID_FEC_REP3, // simple repeat code, r1/3
LIQUID_FEC_REP5, // simple repeat code, r1/5
LIQUID_FEC_HAMMING74, // Hamming (7,4) block code, r1/2 (really 4/7)
LIQUID_FEC_HAMMING84, // Hamming (7,4) with extra parity bit, r1/2
LIQUID_FEC_HAMMING128, // Hamming (12,8) block code, r2/3
LIQUID_FEC_GOLAY2412, // Golay (24,12) block code, r1/2
LIQUID_FEC_SECDED2216, // SEC-DED (22,16) block code, r8/11
LIQUID_FEC_SECDED3932, // SEC-DED (39,32) block code
LIQUID_FEC_SECDED7264, // SEC-DED (72,64) block code, r8/9
// codecs not defined internally (see http://www.ka9q.net/code/fec/)
LIQUID_FEC_CONV_V27, // r1/2, K=7, dfree=10
LIQUID_FEC_CONV_V29, // r1/2, K=9, dfree=12
LIQUID_FEC_CONV_V39, // r1/3, K=9, dfree=18
LIQUID_FEC_CONV_V615, // r1/6, K=15, dfree<=57 (Heller 1968)
// punctured (perforated) codes
LIQUID_FEC_CONV_V27P23, // r2/3, K=7, dfree=6
LIQUID_FEC_CONV_V27P34, // r3/4, K=7, dfree=5
LIQUID_FEC_CONV_V27P45, // r4/5, K=7, dfree=4
LIQUID_FEC_CONV_V27P56, // r5/6, K=7, dfree=4
LIQUID_FEC_CONV_V27P67, // r6/7, K=7, dfree=3
LIQUID_FEC_CONV_V27P78, // r7/8, K=7, dfree=3
LIQUID_FEC_CONV_V29P23, // r2/3, K=9, dfree=7
LIQUID_FEC_CONV_V29P34, // r3/4, K=9, dfree=6
LIQUID_FEC_CONV_V29P45, // r4/5, K=9, dfree=5
LIQUID_FEC_CONV_V29P56, // r5/6, K=9, dfree=5
LIQUID_FEC_CONV_V29P67, // r6/7, K=9, dfree=4
LIQUID_FEC_CONV_V29P78, // r7/8, K=9, dfree=4
// Reed-Solomon codes
LIQUID_FEC_RS_M8 // m=8, n=255, k=223
} fec_scheme;
// pretty names for fec schemes
extern const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2];
// Print compact list of existing and available FEC schemes
void liquid_print_fec_schemes();
// returns fec_scheme based on input string
fec_scheme liquid_getopt_str2fec(const char * _str);
// fec object (pointer to fec structure)
typedef struct fec_s * fec;
// return the encoded message length using a particular error-
// correction scheme (object-independent method)
// _scheme : forward error-correction scheme
// _msg_len : raw, uncoded message length
unsigned int fec_get_enc_msg_length(fec_scheme _scheme,
unsigned int _msg_len);
// get the theoretical rate of a particular forward error-
// correction scheme (object-independent method)
float fec_get_rate(fec_scheme _scheme);
// create a fec object of a particular scheme
// _scheme : error-correction scheme
// _opts : (ignored)
fec fec_create(fec_scheme _scheme,
void *_opts);
// recreate fec object
// _q : old fec object
// _scheme : new error-correction scheme
// _opts : (ignored)
fec fec_recreate(fec _q,
fec_scheme _scheme,
void *_opts);
// destroy fec object
void fec_destroy(fec _q);
// print fec object internals
void fec_print(fec _q);
// encode a block of data using a fec scheme
// _q : fec object
// _dec_msg_len : decoded message length
// _msg_dec : decoded message
// _msg_enc : encoded message
void fec_encode(fec _q,
unsigned int _dec_msg_len,
unsigned char * _msg_dec,
unsigned char * _msg_enc);
// decode a block of data using a fec scheme
// _q : fec object
// _dec_msg_len : decoded message length
// _msg_enc : encoded message
// _msg_dec : decoded message
void fec_decode(fec _q,
unsigned int _dec_msg_len,
unsigned char * _msg_enc,
unsigned char * _msg_dec);
// decode a block of data using a fec scheme (soft decision)
// _q : fec object
// _dec_msg_len : decoded message length
// _msg_enc : encoded message (soft bits)
// _msg_dec : decoded message
void fec_decode_soft(fec _q,
unsigned int _dec_msg_len,
unsigned char * _msg_enc,
unsigned char * _msg_dec);
//
// Packetizer
//
// computes the number of encoded bytes after packetizing
//
// _n : number of uncoded input bytes
// _crc : error-detecting scheme
// _fec0 : inner forward error-correction code
// _fec1 : outer forward error-correction code
unsigned int packetizer_compute_enc_msg_len(unsigned int _n,
int _crc,
int _fec0,
int _fec1);
// computes the number of decoded bytes before packetizing
//
// _k : number of encoded bytes
// _crc : error-detecting scheme
// _fec0 : inner forward error-correction code
// _fec1 : outer forward error-correction code
unsigned int packetizer_compute_dec_msg_len(unsigned int _k,
int _crc,
int _fec0,
int _fec1);
typedef struct packetizer_s * packetizer;
// create packetizer object
//
// _n : number of uncoded input bytes
// _crc : error-detecting scheme
// _fec0 : inner forward error-correction code
// _fec1 : outer forward error-correction code
packetizer packetizer_create(unsigned int _dec_msg_len,
int _crc,
int _fec0,
int _fec1);
// re-create packetizer object
//
// _p : initialz packetizer object
// _n : number of uncoded input bytes
// _crc : error-detecting scheme
// _fec0 : inner forward error-correction code
// _fec1 : outer forward error-correction code
packetizer packetizer_recreate(packetizer _p,
unsigned int _dec_msg_len,
int _crc,
int _fec0,
int _fec1);
// destroy packetizer object
void packetizer_destroy(packetizer _p);
// print packetizer object internals
void packetizer_print(packetizer _p);
unsigned int packetizer_get_dec_msg_len(packetizer _p);
unsigned int packetizer_get_enc_msg_len(packetizer _p);
// packetizer_encode()
//
// Execute the packetizer on an input message
//
// _p : packetizer object
// _msg : input message (uncoded bytes)
// _pkt : encoded output message
void packetizer_encode(packetizer _p,
unsigned char * _msg,
unsigned char * _pkt);
// packetizer_decode()
//
// Execute the packetizer to decode an input message, return validity
// check of resulting data
//
// _p : packetizer object
// _pkt : input message (coded bytes)
// _msg : decoded output message
int packetizer_decode(packetizer _p,
unsigned char * _pkt,
unsigned char * _msg);
// Execute the packetizer to decode an input message, return validity
// check of resulting data
//
// _p : packetizer object
// _pkt : input message (coded soft bits)
// _msg : decoded output message
int packetizer_decode_soft(packetizer _p,
unsigned char * _pkt,
unsigned char * _msg);
//
// interleaver
//
typedef struct interleaver_s * interleaver;
// create interleaver
// _n : number of bytes
interleaver interleaver_create(unsigned int _n);
// destroy interleaver object
void interleaver_destroy(interleaver _q);
// print interleaver object internals
void interleaver_print(interleaver _q);
// set depth (number of internal iterations)
// _q : interleaver object
// _depth : depth
void interleaver_set_depth(interleaver _q,
unsigned int _depth);
// execute forward interleaver (encoder)
// _q : interleaver object
// _msg_dec : decoded (un-interleaved) message
// _msg_enc : encoded (interleaved) message
void interleaver_encode(interleaver _q,
unsigned char * _msg_dec,
unsigned char * _msg_enc);
// execute forward interleaver (encoder) on soft bits
// _q : interleaver object
// _msg_dec : decoded (un-interleaved) message
// _msg_enc : encoded (interleaved) message
void interleaver_encode_soft(interleaver _q,
unsigned char * _msg_dec,
unsigned char * _msg_enc);
// execute reverse interleaver (decoder)
// _q : interleaver object
// _msg_enc : encoded (interleaved) message
// _msg_dec : decoded (un-interleaved) message
void interleaver_decode(interleaver _q,
unsigned char * _msg_enc,
unsigned char * _msg_dec);
// execute reverse interleaver (decoder) on soft bits
// _q : interleaver object
// _msg_enc : encoded (interleaved) message
// _msg_dec : decoded (un-interleaved) message
void interleaver_decode_soft(interleaver _q,
unsigned char * _msg_enc,
unsigned char * _msg_dec);
//
// MODULE : fft (fast Fourier transform)
//
// type of transform
typedef enum {
LIQUID_FFT_UNKNOWN = 0, // unknown transform type
// regular complex one-dimensional transforms
LIQUID_FFT_FORWARD = +1, // complex one-dimensional FFT
LIQUID_FFT_BACKWARD = -1, // complex one-dimensional inverse FFT
// discrete cosine transforms
LIQUID_FFT_REDFT00 = 10, // real one-dimensional DCT-I
LIQUID_FFT_REDFT10 = 11, // real one-dimensional DCT-II
LIQUID_FFT_REDFT01 = 12, // real one-dimensional DCT-III
LIQUID_FFT_REDFT11 = 13, // real one-dimensional DCT-IV
// discrete sine transforms
LIQUID_FFT_RODFT00 = 20, // real one-dimensional DST-I
LIQUID_FFT_RODFT10 = 21, // real one-dimensional DST-II
LIQUID_FFT_RODFT01 = 22, // real one-dimensional DST-III
LIQUID_FFT_RODFT11 = 23, // real one-dimensional DST-IV
// modified discrete cosine transform
LIQUID_FFT_MDCT = 30, // MDCT
LIQUID_FFT_IMDCT = 31, // IMDCT
} liquid_fft_type;
#define LIQUID_FFT_MANGLE_FLOAT(name) LIQUID_CONCAT(fft,name)
// Macro : FFT
// FFT : name-mangling macro
// T : primitive data type
// TC : primitive data type (complex)
#define LIQUID_FFT_DEFINE_API(FFT,T,TC) \
\
typedef struct FFT(plan_s) * FFT(plan); \
\
/* create regular complex one-dimensional transform */ \
/* _n : transform size */ \
/* _x : pointer to input array [size: _n x 1] */ \
/* _y : pointer to output array [size: _n x 1] */ \
/* _dir : direction (e.g. LIQUID_FFT_FORWARD) */ \
/* _flags : options, optimization */ \
FFT(plan) FFT(_create_plan)(unsigned int _n, \
TC * _x, \
TC * _y, \
int _dir, \
int _flags); \
\
/* create real-to-real transform */ \
/* _n : transform size */ \
/* _x : pointer to input array [size: _n x 1] */ \
/* _y : pointer to output array [size: _n x 1] */ \
/* _type : transform type (e.g. LIQUID_FFT_REDFT00) */ \
/* _flags : options, optimization */ \
FFT(plan) FFT(_create_plan_r2r_1d)(unsigned int _n, \
T * _x, \
T * _y, \
int _type, \
int _flags); \
\
/* destroy transform */ \
void FFT(_destroy_plan)(FFT(plan) _p); \
\
/* print transform plan and internal strategy */ \
void FFT(_print_plan)(FFT(plan) _p); \
\
/* run the transform */ \
void FFT(_execute)(FFT(plan) _p); \
\
/* object-independent methods */ \
\
/* perform n-point FFT allocating plan internally */ \
/* _nfft : fft size */ \
/* _x : input array [size: _nfft x 1] */ \
/* _y : output array [size: _nfft x 1] */ \
/* _dir : fft direction: LIQUID_FFT_{FORWARD,BACKWARD} */ \
/* _flags : fft flags */ \
void FFT(_run)(unsigned int _n, \
TC * _x, \
TC * _y, \
int _dir, \
int _flags); \
\
/* perform n-point real FFT allocating plan internally */ \
/* _nfft : fft size */ \
/* _x : input array [size: _nfft x 1] */ \
/* _y : output array [size: _nfft x 1] */ \
/* _type : fft type, e.g. LIQUID_FFT_REDFT10 */ \
/* _flags : fft flags */ \
void FFT(_r2r_1d_run)(unsigned int _n, \
T * _x, \
T * _y, \
int _type, \
int _flags); \
\
/* perform _n-point fft shift */ \
void FFT(_shift)(TC * _x, \
unsigned int _n); \
LIQUID_FFT_DEFINE_API(LIQUID_FFT_MANGLE_FLOAT,float,liquid_float_complex)
// antiquated fft methods
// FFT(plan) FFT(_create_plan_mdct)(unsigned int _n,
// T * _x,
// T * _y,
// int _kind,
// int _flags);
//
// spectral periodogram
//
#define LIQUID_SPGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(spgramcf,name)
#define LIQUID_SPGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(spgramf, name)
// Macro : SPGRAM
// SPGRAM : name-mangling macro
// T : primitive data type
// TC : primitive data type (complex)
// TI : primitive data type (input)
#define LIQUID_SPGRAM_DEFINE_API(SPGRAM,T,TC,TI) \
\
typedef struct SPGRAM(_s) * SPGRAM(); \
\
/* create spgram object */ \
/* _nfft : FFT size */ \
/* _window : window [size: _window_len x 1] */ \
/* _window_len : window length */ \
SPGRAM() SPGRAM(_create)(unsigned int _nfft, \
float * _window, \
unsigned int _window_len); \
\
/* create spgram object with Kaiser-Bessel window */ \
/* _nfft : FFT size */ \
/* _window_len : window length */ \
/* _beta : Kaiser-Bessel parameter (_beta > 0) */ \
SPGRAM() SPGRAM(_create_kaiser)(unsigned int _nfft, \
unsigned int _window_len, \
float _beta); \
\
/* destroy spgram object */ \
void SPGRAM(_destroy)(SPGRAM() _q); \
\
/* resets the internal state of the spgram object */ \
void SPGRAM(_reset)(SPGRAM() _q); \
\
/* push samples into spgram object */ \
/* _q : spgram object */ \
/* _x : input buffer [size: _n x 1] */ \
/* _n : input buffer length */ \
void SPGRAM(_push)(SPGRAM() _q, \
TI * _x, \
unsigned int _n); \
\
/* compute spectral periodogram output from current buffer */ \
/* contents */ \
/* _q : spgram object */ \
/* _X : output complex spectrum [size: _nfft x 1] */ \
void SPGRAM(_execute)(SPGRAM() _q, \
TC * _X); \
\
/* accumulate power spectral density */ \
/* _q : spgram object */ \
/* _x : input buffer [size: _n x 1] */ \
/* _n : input buffer length */ \
void SPGRAM(_accumulate_psd)(SPGRAM() _q, \
TI * _x, \
unsigned int _n); \
\
/* write accumulated psd */ \
/* _q : spgram object */ \
/* _x : input buffer [size: _n x 1] */ \
/* _n : input buffer length [size: _nfft x 1] */ \
void SPGRAM(_write_accumulation)(SPGRAM() _q, \
T * _x); \
\
/* estimate spectrum on input signal */ \
/* _q : spgram object */ \
/* _x : input signal [size: _n x 1] */ \
/* _n : input signal length */ \
/* _psd : output spectrum, [size: _nfft x 1] */ \
void SPGRAM(_estimate_psd)(SPGRAM() _q, \
TI * _x, \
unsigned int _n, \
T * _psd); \
LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_CFLOAT,
float,
liquid_float_complex,
liquid_float_complex)
LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_FLOAT,
float,
liquid_float_complex,
float)
// ascii spectrogram
typedef struct asgram_s * asgram;
// create asgram object
// _nfft : FFT size
asgram asgram_create(unsigned int _nfft);
void asgram_destroy(asgram _q);
void asgram_reset(asgram _q);
void asgram_set_scale(asgram _q, float _offset, float _scale);
// push samples into asgram object
// _q : asgram object
// _x : input buffer [size: _n x 1]
// _n : input buffer length
void asgram_push(asgram _q,
liquid_float_complex * _x,
unsigned int _n);
// execute asgram
// _q : asgram object
// _ascii : ASCII character output buffer [size: _nfft x 1]
// _peakval : peak PSD value [dB]
// _peakfreq : normalized frequency of peak PSD value
void asgram_execute(asgram _q,
char * _ascii,
float * _peakval,
float * _peakfreq);
//
// MODULE : filter
//
//
// firdes: finite impulse response filter design
//
// prototypes
typedef enum {
LIQUID_FIRFILT_UNKNOWN=0, // unknown filter type
// Nyquist filter prototypes
LIQUID_FIRFILT_KAISER, // Nyquist Kaiser filter
LIQUID_FIRFILT_PM, // Parks-McClellan filter
LIQUID_FIRFILT_RCOS, // raised-cosine filter
LIQUID_FIRFILT_FEXP, // flipped exponential
LIQUID_FIRFILT_FSECH, // flipped hyperbolic secant
LIQUID_FIRFILT_FARCSECH, // flipped arc-hyperbolic secant
// root-Nyquist filter prototypes
LIQUID_FIRFILT_ARKAISER, // root-Nyquist Kaiser (approximate optimum)
LIQUID_FIRFILT_RKAISER, // root-Nyquist Kaiser (true optimum)
LIQUID_FIRFILT_RRC, // root raised-cosine
LIQUID_FIRFILT_hM3, // harris-Moerder-3 filter
LIQUID_FIRFILT_GMSKTX, // GMSK transmit filter
LIQUID_FIRFILT_GMSKRX, // GMSK receive filter
LIQUID_FIRFILT_RFEXP, // flipped exponential
LIQUID_FIRFILT_RFSECH, // flipped hyperbolic secant
LIQUID_FIRFILT_RFARCSECH, // flipped arc-hyperbolic secant
} liquid_firfilt_type;
// returns filter type based on input string
int liquid_getopt_str2firfilt(const char * _str);
// estimate required filter length given
// _df : transition bandwidth (0 < _b < 0.5)
// _As : stop-band attenuation [dB], _As > 0
unsigned int estimate_req_filter_len(float _df,
float _As);
// estimate filter stop-band attenuation given
// _df : transition bandwidth (0 < _b < 0.5)
// _N : filter length
float estimate_req_filter_As(float _df,
unsigned int _N);
// estimate filter transition bandwidth given
// _As : stop-band attenuation [dB], _As > 0
// _N : filter length
float estimate_req_filter_df(float _As,
unsigned int _N);
// returns the Kaiser window beta factor give the filter's target
// stop-band attenuation (As) [Vaidyanathan:1993]
// _As : target filter's stop-band attenuation [dB], _As > 0
float kaiser_beta_As(float _As);
// Design Nyquist filter
// _type : filter type (e.g. LIQUID_FIRFILT_RCOS)
// _k : samples/symbol
// _m : symbol delay
// _beta : excess bandwidth factor, _beta in [0,1]
// _dt : fractional sample delay
// _h : output coefficient buffer (length: 2*k*m+1)
void liquid_firdes_nyquist(liquid_firfilt_type _type,
unsigned int _k,
unsigned int _m,
float _beta,
float _dt,
float * _h);
// Design FIR filter using Parks-McClellan algorithm
// band type specifier
typedef enum {
LIQUID_FIRDESPM_BANDPASS=0, // regular band-pass filter
LIQUID_FIRDESPM_DIFFERENTIATOR, // differentiating filter
LIQUID_FIRDESPM_HILBERT // Hilbert transform
} liquid_firdespm_btype;
// weighting type specifier
typedef enum {
LIQUID_FIRDESPM_FLATWEIGHT=0, // flat weighting
LIQUID_FIRDESPM_EXPWEIGHT, // exponential weighting
LIQUID_FIRDESPM_LINWEIGHT, // linear weighting
} liquid_firdespm_wtype;
// run filter design (full life cycle of object)
// _h_len : length of filter (number of taps)
// _num_bands : number of frequency bands
// _bands : band edges, f in [0,0.5], [size: _num_bands x 2]
// _des : desired response [size: _num_bands x 1]
// _weights : response weighting [size: _num_bands x 1]
// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1]
// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS)
// _h : output coefficients array [size: _h_len x 1]
void firdespm_run(unsigned int _h_len,
unsigned int _num_bands,
float * _bands,
float * _des,
float * _weights,
liquid_firdespm_wtype * _wtype,
liquid_firdespm_btype _btype,
float * _h);
// structured object
typedef struct firdespm_s * firdespm;
// create firdespm object
// _h_len : length of filter (number of taps)
// _num_bands : number of frequency bands
// _bands : band edges, f in [0,0.5], [size: _num_bands x 2]
// _des : desired response [size: _num_bands x 1]
// _weights : response weighting [size: _num_bands x 1]
// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1]
// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS)
firdespm firdespm_create(unsigned int _h_len,
unsigned int _num_bands,
float * _bands,
float * _des,
float * _weights,
liquid_firdespm_wtype * _wtype,
liquid_firdespm_btype _btype);
// destroy firdespm object
void firdespm_destroy(firdespm _q);
// print firdespm object internals
void firdespm_print(firdespm _q);
// execute filter design, storing result in _h
void firdespm_execute(firdespm _q, float * _h);
// Design FIR using kaiser window
// _n : filter length, _n > 0
// _fc : cutoff frequency, 0 < _fc < 0.5
// _As : stop-band attenuation [dB], _As > 0
// _mu : fractional sample offset, -0.5 < _mu < 0.5
// _h : output coefficient buffer, [size: _n x 1]
void liquid_firdes_kaiser(unsigned int _n,
float _fc,
float _As,
float _mu,
float *_h);
// Design FIR doppler filter
// _n : filter length
// _fd : normalized doppler frequency (0 < _fd < 0.5)
// _K : Rice fading factor (K >= 0)
// _theta : LoS component angle of arrival
// _h : output coefficient buffer
void liquid_firdes_doppler(unsigned int _n,
float _fd,
float _K,
float _theta,
float *_h);
// Design Nyquist raised-cosine filter
// _k : samples/symbol
// _m : symbol delay
// _beta : rolloff factor (0 < beta <= 1)
// _dt : fractional sample delay
// _h : output coefficient buffer (length: 2*k*m+1)
void liquid_firdes_rcos(unsigned int _k,
unsigned int _m,
float _beta,
float _dt,
float * _h);
// Design root-Nyquist filter
// _type : filter type (e.g. LIQUID_FIRFILT_RRC)
// _k : samples/symbol, _k > 1
// _m : symbol delay, _m > 0
// _beta : excess bandwidth factor, _beta in [0,1)
// _dt : fractional sample delay, _dt in [-1,1]
// _h : output coefficient buffer (length: 2*_k*_m+1)
void liquid_firdes_rnyquist(liquid_firfilt_type _type,
unsigned int _k,
unsigned int _m,
float _beta,
float _dt,
float * _h);
// Design root-Nyquist raised-cosine filter
void liquid_firdes_rrcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design root-Nyquist Kaiser filter
void liquid_firdes_rkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design (approximate) root-Nyquist Kaiser filter
void liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design root-Nyquist harris-Moerder filter
void liquid_firdes_hM3(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design GMSK transmit and receive filters
void liquid_firdes_gmsktx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
void liquid_firdes_gmskrx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design flipped exponential Nyquist/root-Nyquist filters
void liquid_firdes_fexp( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
void liquid_firdes_rfexp(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design flipped hyperbolic secand Nyquist/root-Nyquist filters
void liquid_firdes_fsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
void liquid_firdes_rfsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Design flipped arc-hyperbolic secand Nyquist/root-Nyquist filters
void liquid_firdes_farcsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
void liquid_firdes_rfarcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h);
// Compute group delay for an FIR filter
// _h : filter coefficients array
// _n : filter length
// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5)
float fir_group_delay(float * _h,
unsigned int _n,
float _fc);
// Compute group delay for an IIR filter
// _b : filter numerator coefficients
// _nb : filter numerator length
// _a : filter denominator coefficients
// _na : filter denominator length
// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5)
float iir_group_delay(float * _b,
unsigned int _nb,
float * _a,
unsigned int _na,
float _fc);
// liquid_filter_autocorr()
//
// Compute auto-correlation of filter at a specific lag.
//
// _h : filter coefficients [size: _h_len x 1]
// _h_len : filter length
// _lag : auto-correlation lag (samples)
float liquid_filter_autocorr(float * _h,
unsigned int _h_len,
int _lag);
// liquid_filter_crosscorr()
//
// Compute cross-correlation of two filters at a specific lag.
//
// _h : filter coefficients [size: _h_len]
// _h_len : filter length
// _g : filter coefficients [size: _g_len]
// _g_len : filter length
// _lag : cross-correlation lag (samples)
float liquid_filter_crosscorr(float * _h,
unsigned int _h_len,
float * _g,
unsigned int _g_len,
int _lag);
// liquid_filter_isi()
//
// Compute inter-symbol interference (ISI)--both RMS and
// maximum--for the filter _h.
//
// _h : filter coefficients [size: 2*_k*_m+1 x 1]
// _k : filter over-sampling rate (samples/symbol)
// _m : filter delay (symbols)
// _rms : output root mean-squared ISI
// _max : maximum ISI
void liquid_filter_isi(float * _h,
unsigned int _k,
unsigned int _m,
float * _rms,
float * _max);
// Compute relative out-of-band energy
//
// _h : filter coefficients [size: _h_len x 1]
// _h_len : filter length
// _fc : analysis cut-off frequency
// _nfft : fft size
float liquid_filter_energy(float * _h,
unsigned int _h_len,
float _fc,
unsigned int _nfft);
//
// IIR filter design
//
// IIR filter design filter type
typedef enum {
LIQUID_IIRDES_BUTTER=0,
LIQUID_IIRDES_CHEBY1,
LIQUID_IIRDES_CHEBY2,
LIQUID_IIRDES_ELLIP,
LIQUID_IIRDES_BESSEL
} liquid_iirdes_filtertype;
// IIR filter design band type
typedef enum {
LIQUID_IIRDES_LOWPASS=0,
LIQUID_IIRDES_HIGHPASS,
LIQUID_IIRDES_BANDPASS,
LIQUID_IIRDES_BANDSTOP
} liquid_iirdes_bandtype;
// IIR filter design coefficients format
typedef enum {
LIQUID_IIRDES_SOS=0,
LIQUID_IIRDES_TF
} liquid_iirdes_format;
// IIR filter design template
// _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER)
// _btype : band type (e.g. LIQUID_IIRDES_BANDPASS)
// _format : coefficients format (e.g. LIQUID_IIRDES_SOS)
// _n : filter order
// _fc : low-pass prototype cut-off frequency
// _f0 : center frequency (band-pass, band-stop)
// _Ap : pass-band ripple in dB
// _As : stop-band ripple in dB
// _B : numerator
// _A : denominator
void liquid_iirdes(liquid_iirdes_filtertype _ftype,
liquid_iirdes_bandtype _btype,
liquid_iirdes_format _format,
unsigned int _n,
float _fc,
float _f0,
float _Ap,
float _As,
float * _B,
float * _A);
// compute analog zeros, poles, gain for specific filter types
void butter_azpkf(unsigned int _n,
liquid_float_complex * _za,
liquid_float_complex * _pa,
liquid_float_complex * _ka);
void cheby1_azpkf(unsigned int _n,
float _ep,
liquid_float_complex * _z,
liquid_float_complex * _p,
liquid_float_complex * _k);
void cheby2_azpkf(unsigned int _n,
float _es,
liquid_float_complex * _z,
liquid_float_complex * _p,
liquid_float_complex * _k);
void ellip_azpkf(unsigned int _n,
float _ep,
float _es,
liquid_float_complex * _z,
liquid_float_complex * _p,
liquid_float_complex * _k);
void bessel_azpkf(unsigned int _n,
liquid_float_complex * _z,
liquid_float_complex * _p,
liquid_float_complex * _k);
// compute frequency pre-warping factor
float iirdes_freqprewarp(liquid_iirdes_bandtype _btype,
float _fc,
float _f0);
// convert analog z/p/k form to discrete z/p/k form (bilinear z-transform)
// _za : analog zeros [length: _nza]
// _nza : number of analog zeros
// _pa : analog poles [length: _npa]
// _npa : number of analog poles
// _m : frequency pre-warping factor
// _zd : output digital zeros [length: _npa]
// _pd : output digital poles [length: _npa]
// _kd : output digital gain (should actually be real-valued)
void bilinear_zpkf(liquid_float_complex * _za,
unsigned int _nza,
liquid_float_complex * _pa,
unsigned int _npa,
liquid_float_complex _ka,
float _m,
liquid_float_complex * _zd,
liquid_float_complex * _pd,
liquid_float_complex * _kd);
// digital z/p/k low-pass to high-pass
// _zd : digital zeros (low-pass prototype), [length: _n]
// _pd : digital poles (low-pass prototype), [length: _n]
// _n : low-pass filter order
// _zdt : output digital zeros transformed [length: _n]
// _pdt : output digital poles transformed [length: _n]
void iirdes_dzpk_lp2hp(liquid_float_complex * _zd,
liquid_float_complex * _pd,
unsigned int _n,
liquid_float_complex * _zdt,
liquid_float_complex * _pdt);
// digital z/p/k low-pass to band-pass
// _zd : digital zeros (low-pass prototype), [length: _n]
// _pd : digital poles (low-pass prototype), [length: _n]
// _n : low-pass filter order
// _f0 : center frequency
// _zdt : output digital zeros transformed [length: 2*_n]
// _pdt : output digital poles transformed [length: 2*_n]
void iirdes_dzpk_lp2bp(liquid_float_complex * _zd,
liquid_float_complex * _pd,
unsigned int _n,
float _f0,
liquid_float_complex * _zdt,
liquid_float_complex * _pdt);
// convert discrete z/p/k form to transfer function
// _zd : digital zeros [length: _n]
// _pd : digital poles [length: _n]
// _n : filter order
// _kd : digital gain
// _b : output numerator [length: _n+1]
// _a : output denominator [length: _n+1]
void iirdes_dzpk2tff(liquid_float_complex * _zd,
liquid_float_complex * _pd,
unsigned int _n,
liquid_float_complex _kd,
float * _b,
float * _a);
// convert discrete z/p/k form to second-order sections
// _zd : digital zeros [length: _n]
// _pd : digital poles [length: _n]
// _n : filter order
// _kd : digital gain
// _B : output numerator [size: 3 x L+r]
// _A : output denominator [size: 3 x L+r]
// where r = _n%2, L = (_n-r)/2
void iirdes_dzpk2sosf(liquid_float_complex * _zd,
liquid_float_complex * _pd,
unsigned int _n,
liquid_float_complex _kd,
float * _B,
float * _A);
// additional IIR filter design templates
// design 2nd-order IIR filter (active lag)
// 1 + t2 * s
// F(s) = ------------
// 1 + t1 * s
//
// _w : filter bandwidth
// _zeta : damping factor (1/sqrt(2) suggested)
// _K : loop gain (1000 suggested)
// _b : output feed-forward coefficients [size: 3 x 1]
// _a : output feed-back coefficients [size: 3 x 1]
void iirdes_pll_active_lag(float _w,
float _zeta,
float _K,
float * _b,
float * _a);
// design 2nd-order IIR filter (active PI)
// 1 + t2 * s
// F(s) = ------------
// t1 * s
//
// _w : filter bandwidth
// _zeta : damping factor (1/sqrt(2) suggested)
// _K : loop gain (1000 suggested)
// _b : output feed-forward coefficients [size: 3 x 1]
// _a : output feed-back coefficients [size: 3 x 1]
void iirdes_pll_active_PI(float _w,
float _zeta,
float _K,
float * _b,
float * _a);
// checks stability of iir filter
// _b : feed-forward coefficients [size: _n x 1]
// _a : feed-back coefficients [size: _n x 1]
// _n : number of coefficients
int iirdes_isstable(float * _b,
float * _a,
unsigned int _n);
//
// linear prediction
//
// compute the linear prediction coefficients for an input signal _x
// _x : input signal [size: _n x 1]
// _n : input signal length
// _p : prediction filter order
// _a : prediction filter [size: _p+1 x 1]
// _e : prediction error variance [size: _p+1 x 1]
void liquid_lpc(float * _x,
unsigned int _n,
unsigned int _p,
float * _a,
float * _g);
// solve the Yule-Walker equations using Levinson-Durbin recursion
// for _symmetric_ autocorrelation
// _r : autocorrelation array [size: _p+1 x 1]
// _p : filter order
// _a : output coefficients [size: _p+1 x 1]
// _e : error variance [size: _p+1 x 1]
//
// NOTES:
// By definition _a[0] = 1.0
void liquid_levinson(float * _r,
unsigned int _p,
float * _a,
float * _e);
//
// auto-correlator (delay cross-correlation)
//
#define AUTOCORR_MANGLE_CCCF(name) LIQUID_CONCAT(autocorr_cccf,name)
#define AUTOCORR_MANGLE_RRRF(name) LIQUID_CONCAT(autocorr_rrrf,name)
// Macro:
// AUTOCORR : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_AUTOCORR_DEFINE_API(AUTOCORR,TO,TC,TI) \
\
typedef struct AUTOCORR(_s) * AUTOCORR(); \
\
/* create auto-correlator object */ \
/* _window_size : size of the correlator window */ \
/* _delay : correlator delay [samples] */ \
AUTOCORR() AUTOCORR(_create)(unsigned int _window_size, \
unsigned int _delay); \
\
/* destroy auto-correlator object, freeing internal memory */ \
void AUTOCORR(_destroy)(AUTOCORR() _q); \
\
/* reset auto-correlator object's internals */ \
void AUTOCORR(_reset)(AUTOCORR() _q); \
\
/* print auto-correlator parameters to stdout */ \
void AUTOCORR(_print)(AUTOCORR() _q); \
\
/* push sample into auto-correlator object */ \
void AUTOCORR(_push)(AUTOCORR() _q, \
TI _x); \
\
/* compute single auto-correlation output */ \
void AUTOCORR(_execute)(AUTOCORR() _q, \
TO * _rxx); \
\
/* compute auto-correlation on block of samples; the input */ \
/* and output arrays may have the same pointer */ \
/* _q : auto-correlation object */ \
/* _x : input array [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _rxx : input array [size: _n x 1] */ \
void AUTOCORR(_execute_block)(AUTOCORR() _q, \
TI * _x, \
unsigned int _n, \
TO * _rxx); \
\
/* return sum of squares of buffered samples */ \
float AUTOCORR(_get_energy)(AUTOCORR() _q); \
LIQUID_AUTOCORR_DEFINE_API(AUTOCORR_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
LIQUID_AUTOCORR_DEFINE_API(AUTOCORR_MANGLE_RRRF,
float,
float,
float)
//
// Finite impulse response filter
//
#define FIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(firfilt_rrrf,name)
#define FIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(firfilt_crcf,name)
#define FIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(firfilt_cccf,name)
// Macro:
// FIRFILT : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FIRFILT_DEFINE_API(FIRFILT,TO,TC,TI) \
typedef struct FIRFILT(_s) * FIRFILT(); \
\
FIRFILT() FIRFILT(_create)(TC * _h, unsigned int _n); \
\
/* create using Kaiser-Bessel windowed sinc method */ \
/* _n : filter length, _n > 0 */ \
/* _fc : filter cut-off frequency 0 < _fc < 0.5 */ \
/* _As : filter stop-band attenuation [dB], _As > 0 */ \
/* _mu : fractional sample offset, -0.5 < _mu < 0.5 */ \
FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, \
float _fc, \
float _As, \
float _mu); \
\
/* create from square-root Nyquist prototype */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _k : nominal samples/symbol, _k > 1 */ \
/* _m : filter delay [symbols], _m > 0 */ \
/* _beta : rolloff factor, 0 < beta <= 1 */ \
/* _mu : fractional sample offset,-0.5 < _mu < 0.5 */ \
FIRFILT() FIRFILT(_create_rnyquist)(int _type, \
unsigned int _k, \
unsigned int _m, \
float _beta, \
float _mu); \
\
/* re-create filter */ \
/* _q : original filter object */ \
/* _h : pointer to filter coefficients [size: _n x 1] */ \
/* _n : filter length, _n > 0 */ \
FIRFILT() FIRFILT(_recreate)(FIRFILT() _q, \
TC * _h, \
unsigned int _n); \
\
/* destroy filter object and free all internal memory */ \
void FIRFILT(_destroy)(FIRFILT() _q); \
\
/* reset filter object's internal buffer */ \
void FIRFILT(_reset)(FIRFILT() _q); \
\
/* print filter object information */ \
void FIRFILT(_print)(FIRFILT() _q); \
\
/* set output scaling for filter */ \
void FIRFILT(_set_scale)(FIRFILT() _q, \
TC _g); \
\
/* push sample into filter object's internal buffer */ \
/* _q : filter object */ \
/* _x : single input sample */ \
void FIRFILT(_push)(FIRFILT() _q, \
TI _x); \
\
/* execute the filter on internal buffer and coefficients */ \
/* _q : filter object */ \
/* _y : pointer to single output sample */ \
void FIRFILT(_execute)(FIRFILT() _q, \
TO * _y); \
\
/* execute the filter on a block of input samples; the */ \
/* input and output buffers may be the same */ \
/* _q : filter object */ \
/* _x : pointer to input array [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _y : pointer to output array [size: _n x 1] */ \
void FIRFILT(_execute_block)(FIRFILT() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
\
/* return length of filter object */ \
unsigned int FIRFILT(_get_length)(FIRFILT() _q); \
\
/* compute complex frequency response of filter object */ \
/* _q : filter object */ \
/* _fc : frequency to evaluate */ \
/* _H : pointer to output complex frequency response */ \
void FIRFILT(_freqresponse)(FIRFILT() _q, \
float _fc, \
liquid_float_complex * _H); \
\
/* compute and return group delay of filter object */ \
/* _q : filter object */ \
/* _fc : frequency to evaluate */ \
float FIRFILT(_groupdelay)(FIRFILT() _q, \
float _fc); \
LIQUID_FIRFILT_DEFINE_API(FIRFILT_MANGLE_RRRF,
float,
float,
float)
LIQUID_FIRFILT_DEFINE_API(FIRFILT_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FIRFILT_DEFINE_API(FIRFILT_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// FIR Hilbert transform
// 2:1 real-to-complex decimator
// 1:2 complex-to-real interpolator
//
#define FIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(firhilbf, name)
//#define FIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(firhilb, name)
// NOTES:
// Although firhilb is a placeholder for both decimation and
// interpolation, separate objects should be used for each task.
#define LIQUID_FIRHILB_DEFINE_API(FIRHILB,T,TC) \
typedef struct FIRHILB(_s) * FIRHILB(); \
\
/* create finite impulse reponse Hilbert transform */ \
/* _m : filter semi-length, delay is 2*m+1 */ \
/* _As : filter stop-band attenuation [dB] */ \
FIRHILB() FIRHILB(_create)(unsigned int _m, \
float _As); \
\
/* destroy finite impulse reponse Hilbert transform */ \
void FIRHILB(_destroy)(FIRHILB() _q); \
\
/* print firhilb object internals to stdout */ \
void FIRHILB(_print)(FIRHILB() _q); \
\
/* reset firhilb object internal state */ \
void FIRHILB(_reset)(FIRHILB() _q); \
\
/* execute Hilbert transform (real to complex) */ \
/* _q : Hilbert transform object */ \
/* _x : real-valued input sample */ \
/* _y : complex-valued output sample */ \
void FIRHILB(_r2c_execute)(FIRHILB() _q, \
T _x, \
TC * _y); \
\
/* execute Hilbert transform (complex to real) */ \
/* _q : Hilbert transform object */ \
/* _x : complex-valued input sample */ \
/* _y : real-valued output sample */ \
void FIRHILB(_c2r_execute)(FIRHILB() _q, \
TC _x, \
T * _y); \
\
/* execute Hilbert transform decimator (real to complex) */ \
/* _q : Hilbert transform object */ \
/* _x : real-valued input array [size: 2 x 1] */ \
/* _y : complex-valued output sample */ \
void FIRHILB(_decim_execute)(FIRHILB() _q, \
T * _x, \
TC * _y); \
\
/* execute Hilbert transform interpolator (real to complex) */ \
/* _q : Hilbert transform object */ \
/* _x : complex-valued input sample */ \
/* _y : real-valued output array [size: 2 x 1] */ \
void FIRHILB(_interp_execute)(FIRHILB() _q, \
TC _x, \
T * _y); \
LIQUID_FIRHILB_DEFINE_API(FIRHILB_MANGLE_FLOAT, float, liquid_float_complex)
//LIQUID_FIRHILB_DEFINE_API(FIRHILB_MANGLE_DOUBLE, double, liquid_double_complex)
//
// FFT-based finite impulse response filter
//
#define FFTFILT_MANGLE_RRRF(name) LIQUID_CONCAT(fftfilt_rrrf,name)
#define FFTFILT_MANGLE_CRCF(name) LIQUID_CONCAT(fftfilt_crcf,name)
#define FFTFILT_MANGLE_CCCF(name) LIQUID_CONCAT(fftfilt_cccf,name)
// Macro:
// FFTFILT : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FFTFILT_DEFINE_API(FFTFILT,TO,TC,TI) \
typedef struct FFTFILT(_s) * FFTFILT(); \
\
/* create FFT-based FIR filter using external coefficients */ \
/* _h : filter coefficients [size: _h_len x 1] */ \
/* _h_len : filter length, _h_len > 0 */ \
/* _n : block size = nfft/2, at least _h_len-1 */ \
FFTFILT() FFTFILT(_create)(TC * _h, \
unsigned int _h_len, \
unsigned int _n); \
\
/* destroy filter object and free all internal memory */ \
void FFTFILT(_destroy)(FFTFILT() _q); \
\
/* reset filter object's internal buffer */ \
void FFTFILT(_reset)(FFTFILT() _q); \
\
/* print filter object information */ \
void FFTFILT(_print)(FFTFILT() _q); \
\
/* set output scaling for filter */ \
void FFTFILT(_set_scale)(FFTFILT() _q, \
TC _g); \
\
/* execute the filter on internal buffer and coefficients */ \
/* _q : filter object */ \
/* _x : pointer to input data array [size: _n x 1] */ \
/* _y : pointer to output data array [size: _n x 1] */ \
void FFTFILT(_execute)(FFTFILT() _q, \
TI * _x, \
TO * _y); \
\
/* return length of filter object's internal coefficients */ \
unsigned int FFTFILT(_get_length)(FFTFILT() _q); \
LIQUID_FFTFILT_DEFINE_API(FFTFILT_MANGLE_RRRF,
float,
float,
float)
LIQUID_FFTFILT_DEFINE_API(FFTFILT_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FFTFILT_DEFINE_API(FFTFILT_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Infinite impulse response filter
//
#define IIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(iirfilt_rrrf,name)
#define IIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(iirfilt_crcf,name)
#define IIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(iirfilt_cccf,name)
// Macro:
// IIRFILT : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_IIRFILT_DEFINE_API(IIRFILT,TO,TC,TI) \
\
typedef struct IIRFILT(_s) * IIRFILT(); \
\
/* create infinite impulse reponse filter */ \
/* _b : feed-forward coefficients [size: _nb x 1] */ \
/* _nb : number of feed-forward coefficients */ \
/* _a : feed-back coefficients [size: _na x 1] */ \
/* _na : number of feed-back coefficients */ \
IIRFILT() IIRFILT(_create)(TC * _b, \
unsigned int _nb, \
TC * _a, \
unsigned int _na); \
\
/* create IIR filter using 2nd-order secitons */ \
/* _B : feed-forward coefficients [size: _nsos x 3] */ \
/* _A : feed-back coefficients [size: _nsos x 3] */ \
IIRFILT() IIRFILT(_create_sos)(TC * _B, \
TC * _A, \
unsigned int _nsos); \
\
/* create IIR filter from design template */ \
/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \
/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \
/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \
/* _n : filter order */ \
/* _fc : low-pass prototype cut-off frequency */ \
/* _f0 : center frequency (band-pass, band-stop) */ \
/* _Ap : pass-band ripple in dB */ \
/* _As : stop-band ripple in dB */ \
IIRFILT() IIRFILT(_create_prototype)( \
liquid_iirdes_filtertype _ftype, \
liquid_iirdes_bandtype _btype, \
liquid_iirdes_format _format, \
unsigned int _order, \
float _fc, \
float _f0, \
float _Ap, \
float _As); \
\
/* create 8th-order integrator filter */ \
IIRFILT() IIRFILT(_create_integrator)(); \
\
/* create 8th-order differentiator filter */ \
IIRFILT() IIRFILT(_create_differentiator)(); \
\
/* create simple DC-blocking filter */ \
IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha); \
\
/* create phase-locked loop iirfilt object */ \
/* _w : filter bandwidth */ \
/* _zeta : damping factor (1/sqrt(2) suggested) */ \
/* _K : loop gain (1000 suggested) */ \
IIRFILT() IIRFILT(_create_pll)(float _w, \
float _zeta, \
float _K); \
\
/* destroy iirfilt object, freeing all internal memory */ \
void IIRFILT(_destroy)(IIRFILT() _q); \
\
/* print iirfilt object properties to stdout */ \
void IIRFILT(_print)(IIRFILT() _q); \
\
/* clear/reset iirfilt object internals */ \
void IIRFILT(_reset)(IIRFILT() _q); \
\
/* compute filter output */ \
/* _q : iirfilt object */ \
/* _x : input sample */ \
/* _y : output sample pointer */ \
void IIRFILT(_execute)(IIRFILT() _q, \
TI _x, \
TO * _y); \
\
/* execute the filter on a block of input samples; the */ \
/* input and output buffers may be the same */ \
/* _q : filter object */ \
/* _x : pointer to input array [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _y : pointer to output array [size: _n x 1] */ \
void IIRFILT(_execute_block)(IIRFILT() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
\
/* return iirfilt object's filter length (order + 1) */ \
unsigned int IIRFILT(_get_length)(IIRFILT() _q); \
\
/* compute complex frequency response of filter object */ \
/* _q : filter object */ \
/* _fc : frequency to evaluate */ \
/* _H : pointer to output complex frequency response */ \
void IIRFILT(_freqresponse)(IIRFILT() _q, \
float _fc, \
liquid_float_complex * _H); \
\
/* compute and return group delay of filter object */ \
/* _q : filter object */ \
/* _fc : frequency to evaluate */ \
float IIRFILT(_groupdelay)(IIRFILT() _q, float _fc); \
LIQUID_IIRFILT_DEFINE_API(IIRFILT_MANGLE_RRRF,
float,
float,
float)
LIQUID_IIRFILT_DEFINE_API(IIRFILT_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_IIRFILT_DEFINE_API(IIRFILT_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// FIR Polyphase filter bank
//
#define FIRPFB_MANGLE_RRRF(name) LIQUID_CONCAT(firpfb_rrrf,name)
#define FIRPFB_MANGLE_CRCF(name) LIQUID_CONCAT(firpfb_crcf,name)
#define FIRPFB_MANGLE_CCCF(name) LIQUID_CONCAT(firpfb_cccf,name)
// Macro:
// FIRPFB : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FIRPFB_DEFINE_API(FIRPFB,TO,TC,TI) \
\
typedef struct FIRPFB(_s) * FIRPFB(); \
\
/* create firpfb from external coefficients */ \
/* _M : number of filters in the bank */ \
/* _h : coefficients [size: _M*_h_len x 1] */ \
/* _h_len : filter delay (symbols) */ \
FIRPFB() FIRPFB(_create)(unsigned int _M, \
TC * _h, \
unsigned int _h_len); \
\
/* create firpfb from square-root Nyquist prototype */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _npfb : number of filters in the bank */ \
/* _k : nominal samples/symbol */ \
/* _m : filter delay (symbols) */ \
/* _beta : rolloff factor (0 < beta <= 1) */ \
FIRPFB() FIRPFB(_create_rnyquist)(int _type, \
unsigned int _npfb, \
unsigned int _k, \
unsigned int _m, \
float _beta); \
\
/* create from square-root derivative Nyquist prototype */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _npfb : number of filters in the bank */ \
/* _k : nominal samples/symbol */ \
/* _m : filter delay (symbols) */ \
/* _beta : rolloff factor (0 < beta <= 1) */ \
FIRPFB() FIRPFB(_create_drnyquist)(int _type, \
unsigned int _npfb, \
unsigned int _k, \
unsigned int _m, \
float _beta); \
\
/* re-create filterbank object */ \
/* _q : original firpfb object */ \
/* _M : number of filters in the bank */ \
/* _h : coefficients [size: _M x _h_len] */ \
/* _h_len : length of each filter */ \
FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, \
unsigned int _M, \
TC * _h, \
unsigned int _h_len); \
\
/* destroy firpfb object, freeing all internal memory */ \
void FIRPFB(_destroy)(FIRPFB() _q); \
\
/* print firpfb object's parameters */ \
void FIRPFB(_print)(FIRPFB() _q); \
\
/* clear/reset firpfb object internal state */ \
void FIRPFB(_reset)(FIRPFB() _q); \
\
/* push sample into firpfb internal buffer */ \
void FIRPFB(_push)(FIRPFB() _q, TI _x); \
\
/* execute the filter on internal buffer and coefficients */ \
/* _q : firpfb object */ \
/* _i : index of filter to use */ \
/* _y : pointer to output sample */ \
void FIRPFB(_execute)(FIRPFB() _q, \
unsigned int _i, \
TO * _y); \
LIQUID_FIRPFB_DEFINE_API(FIRPFB_MANGLE_RRRF,
float,
float,
float)
LIQUID_FIRPFB_DEFINE_API(FIRPFB_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FIRPFB_DEFINE_API(FIRPFB_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Interpolators
//
// firinterp : finite impulse response interpolator
#define FIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(firinterp_rrrf,name)
#define FIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(firinterp_crcf,name)
#define FIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(firinterp_cccf,name)
#define LIQUID_FIRINTERP_DEFINE_API(FIRINTERP,TO,TC,TI) \
\
typedef struct FIRINTERP(_s) * FIRINTERP(); \
\
/* create interpolator from external coefficients */ \
/* _M : interpolation factor */ \
/* _h : filter coefficients [size: _h_len x 1] */ \
/* _h_len : filter length */ \
FIRINTERP() FIRINTERP(_create)(unsigned int _M, \
TC * _h, \
unsigned int _h_len); \
\
/* create interpolator from prototype */ \
/* _M : interpolation factor */ \
/* _m : filter delay (symbols) */ \
/* _As : stop-band attenuation [dB] */ \
FIRINTERP() FIRINTERP(_create_prototype)(unsigned int _M, \
unsigned int _m, \
float _As); \
\
/* create Nyquist interpolator */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \
/* _k : samples/symbol, _k > 1 */ \
/* _m : filter delay (symbols), _m > 0 */ \
/* _beta : excess bandwidth factor, _beta < 1 */ \
/* _dt : fractional sample delay, _dt in (-1, 1) */ \
FIRINTERP() FIRINTERP(_create_nyquist)(int _type, \
unsigned int _k, \
unsigned int _m, \
float _beta, \
float _dt); \
\
/* create square-root Nyquist interpolator */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _k : samples/symbol, _k > 1 */ \
/* _m : filter delay (symbols), _m > 0 */ \
/* _beta : excess bandwidth factor, _beta < 1 */ \
/* _dt : fractional sample delay, _dt in (-1, 1) */ \
FIRINTERP() FIRINTERP(_create_rnyquist)(int _type, \
unsigned int _k, \
unsigned int _m, \
float _beta, \
float _dt); \
\
/* destroy firinterp object, freeing all internal memory */ \
void FIRINTERP(_destroy)(FIRINTERP() _q); \
\
/* print firinterp object's internal properties to stdout */ \
void FIRINTERP(_print)(FIRINTERP() _q); \
\
/* reset internal state */ \
void FIRINTERP(_reset)(FIRINTERP() _q); \
\
/* execute interpolation on single input sample */ \
/* _q : firinterp object */ \
/* _x : input sample */ \
/* _y : output sample array [size: _M x 1] */ \
void FIRINTERP(_execute)(FIRINTERP() _q, \
TI _x, \
TO * _y); \
\
/* execute interpolation on block of input samples */ \
/* _q : firinterp object */ \
/* _x : input array [size: _n x 1] */ \
/* _n : size of input array */ \
/* _y : output sample array [size: _M*_n x 1] */ \
void FIRINTERP(_execute_block)(FIRINTERP() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
LIQUID_FIRINTERP_DEFINE_API(FIRINTERP_MANGLE_RRRF,
float,
float,
float)
LIQUID_FIRINTERP_DEFINE_API(FIRINTERP_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FIRINTERP_DEFINE_API(FIRINTERP_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
// iirinterp : infinite impulse response interpolator
#define IIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(iirinterp_rrrf,name)
#define IIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(iirinterp_crcf,name)
#define IIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(iirinterp_cccf,name)
#define LIQUID_IIRINTERP_DEFINE_API(IIRINTERP,TO,TC,TI) \
typedef struct IIRINTERP(_s) * IIRINTERP(); \
\
/* create interpolator from external coefficients */ \
/* _M : interpolation factor */ \
/* _b : feed-back coefficients [size: _nb x 1] */ \
/* _nb : feed-back coefficients length */ \
/* _a : feed-forward coefficients [size: _na x 1] */ \
/* _na : feed-forward coefficients length */ \
IIRINTERP() IIRINTERP(_create)(unsigned int _M, \
TC * _b, \
unsigned int _nb, \
TC * _a, \
unsigned int _na); \
\
/* create interpolator from prototype */ \
/* _M : interpolation factor */ \
IIRINTERP() IIRINTERP(_create_prototype)( \
unsigned int _M, \
liquid_iirdes_filtertype _ftype, \
liquid_iirdes_bandtype _btype, \
liquid_iirdes_format _format, \
unsigned int _order, \
float _fc, \
float _f0, \
float _Ap, \
float _As); \
\
/* destroy interpolator object and free internal memory */ \
void IIRINTERP(_destroy)(IIRINTERP() _q); \
\
/* print interpolator object internals */ \
void IIRINTERP(_print)(IIRINTERP() _q); \
\
/* reset interpolator object */ \
void IIRINTERP(_reset)(IIRINTERP() _q); \
\
/* execute interpolation on single input sample */ \
/* _q : iirinterp object */ \
/* _x : input sample */ \
/* _y : output sample array [size: _M x 1] */ \
void IIRINTERP(_execute)(IIRINTERP() _q, \
TI _x, \
TO * _y); \
\
/* execute interpolation on block of input samples */ \
/* _q : iirinterp object */ \
/* _x : input array [size: _n x 1] */ \
/* _n : size of input array */ \
/* _y : output sample array [size: _M*_n x 1] */ \
void IIRINTERP(_execute_block)(IIRINTERP() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
\
/* get system group delay at frequency _fc */ \
float IIRINTERP(_groupdelay)(IIRINTERP() _q, float _fc); \
LIQUID_IIRINTERP_DEFINE_API(IIRINTERP_MANGLE_RRRF,
float,
float,
float)
LIQUID_IIRINTERP_DEFINE_API(IIRINTERP_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_IIRINTERP_DEFINE_API(IIRINTERP_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Decimators
//
// firdecim : finite impulse response decimator
#define FIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(firdecim_rrrf,name)
#define FIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(firdecim_crcf,name)
#define FIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(firdecim_cccf,name)
#define LIQUID_FIRDECIM_DEFINE_API(FIRDECIM,TO,TC,TI) \
typedef struct FIRDECIM(_s) * FIRDECIM(); \
\
/* create decimator from external coefficients */ \
/* _M : decimation factor */ \
/* _h : filter coefficients [size: _h_len x 1] */ \
/* _h_len : filter coefficients length */ \
FIRDECIM() FIRDECIM(_create)(unsigned int _M, \
TC * _h, \
unsigned int _h_len); \
\
/* create decimator from prototype */ \
/* _M : decimation factor */ \
/* _m : filter delay (symbols) */ \
/* _As : stop-band attenuation [dB] */ \
FIRDECIM() FIRDECIM(_create_prototype)(unsigned int _M, \
unsigned int _m, \
float _As); \
\
/* create square-root Nyquist decimator */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _M : samples/symbol (decimation factor) */ \
/* _m : filter delay (symbols) */ \
/* _beta : rolloff factor (0 < beta <= 1) */ \
/* _dt : fractional sample delay */ \
FIRDECIM() FIRDECIM(_create_rnyquist)(int _type, \
unsigned int _M, \
unsigned int _m, \
float _beta, \
float _dt); \
\
/* destroy decimator object */ \
void FIRDECIM(_destroy)(FIRDECIM() _q); \
\
/* print decimator object propreties to stdout */ \
void FIRDECIM(_print)(FIRDECIM() _q); \
\
/* reset decimator object internal state */ \
void FIRDECIM(_clear)(FIRDECIM() _q); \
\
/* execute decimator on _M input samples */ \
/* _q : decimator object */ \
/* _x : input samples [size: _M x 1] */ \
/* _y : output sample pointer */ \
void FIRDECIM(_execute)(FIRDECIM() _q, \
TI * _x, \
TO * _y); \
\
/* execute decimator on block of _n*_M input samples */ \
/* _q : decimator object */ \
/* _x : input array [size: _n*_M x 1] */ \
/* _n : number of _output_ samples */ \
/* _y : output array [_sze: _n x 1] */ \
void FIRDECIM(_execute_block)(FIRDECIM() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
LIQUID_FIRDECIM_DEFINE_API(FIRDECIM_MANGLE_RRRF,
float,
float,
float)
LIQUID_FIRDECIM_DEFINE_API(FIRDECIM_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FIRDECIM_DEFINE_API(FIRDECIM_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
// iirdecim : infinite impulse response decimator
#define IIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(iirdecim_rrrf,name)
#define IIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(iirdecim_crcf,name)
#define IIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(iirdecim_cccf,name)
#define LIQUID_IIRDECIM_DEFINE_API(IIRDECIM,TO,TC,TI) \
typedef struct IIRDECIM(_s) * IIRDECIM(); \
\
/* create decimator from external coefficients */ \
/* _M : decimation factor */ \
/* _b : feed-back coefficients [size: _nb x 1] */ \
/* _nb : feed-back coefficients length */ \
/* _a : feed-forward coefficients [size: _na x 1] */ \
/* _na : feed-forward coefficients length */ \
IIRDECIM() IIRDECIM(_create)(unsigned int _M, \
TC * _b, \
unsigned int _nb, \
TC * _a, \
unsigned int _na); \
\
/* create decimator from prototype */ \
/* _M : decimation factor */ \
IIRDECIM() IIRDECIM(_create_prototype)( \
unsigned int _M, \
liquid_iirdes_filtertype _ftype, \
liquid_iirdes_bandtype _btype, \
liquid_iirdes_format _format, \
unsigned int _order, \
float _fc, \
float _f0, \
float _Ap, \
float _As); \
\
/* destroy decimator object and free internal memory */ \
void IIRDECIM(_destroy)(IIRDECIM() _q); \
\
/* print decimator object internals */ \
void IIRDECIM(_print)(IIRDECIM() _q); \
\
/* reset decimator object */ \
void IIRDECIM(_reset)(IIRDECIM() _q); \
\
/* execute decimator on _M input samples */ \
/* _q : decimator object */ \
/* _x : input samples [size: _M x 1] */ \
/* _y : output sample pointer */ \
void IIRDECIM(_execute)(IIRDECIM() _q, \
TI * _x, \
TO * _y); \
\
/* execute decimator on block of _n*_M input samples */ \
/* _q : decimator object */ \
/* _x : input array [size: _n*_M x 1] */ \
/* _n : number of _output_ samples */ \
/* _y : output array [_sze: _n x 1] */ \
void IIRDECIM(_execute_block)(IIRDECIM() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
\
/* get system group delay at frequency _fc */ \
float IIRDECIM(_groupdelay)(IIRDECIM() _q, float _fc); \
LIQUID_IIRDECIM_DEFINE_API(IIRDECIM_MANGLE_RRRF,
float,
float,
float)
LIQUID_IIRDECIM_DEFINE_API(IIRDECIM_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_IIRDECIM_DEFINE_API(IIRDECIM_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Half-band resampler
//
#define RESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(resamp2_rrrf,name)
#define RESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(resamp2_crcf,name)
#define RESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(resamp2_cccf,name)
#define LIQUID_RESAMP2_DEFINE_API(RESAMP2,TO,TC,TI) \
typedef struct RESAMP2(_s) * RESAMP2(); \
\
/* create half-band resampler */ \
/* _m : filter semi-length (h_len = 4*m+1) */ \
/* _f0 : filter center frequency */ \
/* _As : stop-band attenuation [dB] */ \
RESAMP2() RESAMP2(_create)(unsigned int _m, \
float _f0, \
float _As); \
\
/* re-create half-band resampler with new properties */ \
/* _q : original half-band resampler object */ \
/* _m : filter semi-length (h_len = 4*m+1) */ \
/* _f0 : filter center frequency */ \
/* _As : stop-band attenuation [dB] */ \
RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \
unsigned int _m, \
float _f0, \
float _As); \
\
/* destroy half-band resampler */ \
void RESAMP2(_destroy)(RESAMP2() _q); \
\
/* print resamp2 object's internals */ \
void RESAMP2(_print)(RESAMP2() _q); \
\
/* reset internal buffer */ \
void RESAMP2(_clear)(RESAMP2() _q); \
\
/* get resampler filter delay (semi-length m) */ \
unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \
\
/* execute resamp2 as half-band filter */ \
/* _q : resamp2 object */ \
/* _x : input sample */ \
/* _y0 : output sample pointer (low frequency) */ \
/* _y1 : output sample pointer (high frequency) */ \
void RESAMP2(_filter_execute)(RESAMP2() _q, \
TI _x, \
TO * _y0, \
TO * _y1); \
\
/* execute resamp2 as half-band analysis filterbank */ \
/* _q : resamp2 object */ \
/* _x : input array [size: 2 x 1] */ \
/* _y : output array [size: 2 x 1] */ \
void RESAMP2(_analyzer_execute)(RESAMP2() _q, \
TI * _x, \
TO * _y); \
\
/* execute resamp2 as half-band synthesis filterbank */ \
/* _q : resamp2 object */ \
/* _x : input array [size: 2 x 1] */ \
/* _y : output array [size: 2 x 1] */ \
void RESAMP2(_synthesizer_execute)(RESAMP2() _q, \
TI * _x, \
TO * _y); \
\
/* execute resamp2 as half-band decimator */ \
/* _q : resamp2 object */ \
/* _x : input array [size: 2 x 1] */ \
/* _y : output sample pointer */ \
void RESAMP2(_decim_execute)(RESAMP2() _q, \
TI * _x, \
TO * _y); \
\
/* execute resamp2 as half-band interpolator */ \
/* _q : resamp2 object */ \
/* _x : input sample */ \
/* _y : output array [size: 2 x 1] */ \
void RESAMP2(_interp_execute)(RESAMP2() _q, \
TI _x, \
TO * _y); \
LIQUID_RESAMP2_DEFINE_API(RESAMP2_MANGLE_RRRF,
float,
float,
float)
LIQUID_RESAMP2_DEFINE_API(RESAMP2_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_RESAMP2_DEFINE_API(RESAMP2_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Arbitrary resampler
//
#define RESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(resamp_rrrf,name)
#define RESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(resamp_crcf,name)
#define RESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(resamp_cccf,name)
#define LIQUID_RESAMP_DEFINE_API(RESAMP,TO,TC,TI) \
typedef struct RESAMP(_s) * RESAMP(); \
\
/* create arbitrary resampler object */ \
/* _rate : arbitrary resampling rate */ \
/* _m : filter semi-length (delay) */ \
/* _fc : filter cutoff frequency, 0 < _fc < 0.5 */ \
/* _As : filter stop-band attenuation [dB] */ \
/* _npfb : number of filters in the bank */ \
RESAMP() RESAMP(_create)(float _rate, \
unsigned int _m, \
float _fc, \
float _As, \
unsigned int _npfb); \
\
/* destroy arbitrary resampler object */ \
void RESAMP(_destroy)(RESAMP() _q); \
\
/* print resamp object internals to stdout */ \
void RESAMP(_print)(RESAMP() _q); \
\
/* reset resamp object internals */ \
void RESAMP(_reset)(RESAMP() _q); \
\
/* get resampler delay (output samples) */ \
unsigned int RESAMP(_get_delay)(RESAMP() _q); \
\
/* set rate of arbitrary resampler */ \
void RESAMP(_setrate)(RESAMP() _q, float _rate); \
\
/* execute arbitrary resampler */ \
/* _q : resamp object */ \
/* _x : single input sample */ \
/* _y : output sample array (pointer) */ \
/* _num_written : number of samples written to _y */ \
void RESAMP(_execute)(RESAMP() _q, \
TI _x, \
TO * _y, \
unsigned int * _num_written); \
\
/* execute arbitrary resampler on a block of samples */ \
/* _q : resamp object */ \
/* _x : input buffer [size: _nx x 1] */ \
/* _nx : input buffer */ \
/* _y : output sample array (pointer) */ \
/* _ny : number of samples written to _y */ \
void RESAMP(_execute_block)(RESAMP() _q, \
TI * _x, \
unsigned int _nx, \
TO * _y, \
unsigned int * _ny); \
LIQUID_RESAMP_DEFINE_API(RESAMP_MANGLE_RRRF,
float,
float,
float)
LIQUID_RESAMP_DEFINE_API(RESAMP_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_RESAMP_DEFINE_API(RESAMP_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Multi-stage half-band resampler
//
// resampling type (interpolator/decimator)
typedef enum {
LIQUID_RESAMP_INTERP=0, // interpolator
LIQUID_RESAMP_DECIM, // decimator
} liquid_resamp_type;
#define MSRESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp2_rrrf,name)
#define MSRESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp2_crcf,name)
#define MSRESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp2_cccf,name)
#define LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2,TO,TC,TI) \
typedef struct MSRESAMP2(_s) * MSRESAMP2(); \
\
/* create multi-stage half-band resampler */ \
/* _type : resampler type (e.g. LIQUID_RESAMP_DECIM) */ \
/* _num_stages : number of resampling stages */ \
/* _fc : filter cut-off frequency 0 < _fc < 0.5 */ \
/* _f0 : filter center frequency */ \
/* _As : stop-band attenuation [dB] */ \
MSRESAMP2() MSRESAMP2(_create)(int _type, \
unsigned int _num_stages, \
float _fc, \
float _f0, \
float _As); \
\
/* destroy multi-stage half-bandresampler */ \
void MSRESAMP2(_destroy)(MSRESAMP2() _q); \
\
/* print msresamp object internals to stdout */ \
void MSRESAMP2(_print)(MSRESAMP2() _q); \
\
/* reset msresamp object internal state */ \
void MSRESAMP2(_reset)(MSRESAMP2() _q); \
\
/* get group delay (number of output samples) */ \
float MSRESAMP2(_get_delay)(MSRESAMP2() _q); \
\
/* execute multi-stage resampler, M = 2^num_stages */ \
/* LIQUID_RESAMP_INTERP: input: 1, output: M */ \
/* LIQUID_RESAMP_DECIM: input: M, output: 1 */ \
/* _q : msresamp object */ \
/* _x : input sample array */ \
/* _y : output sample array */ \
void MSRESAMP2(_execute)(MSRESAMP2() _q, \
TI * _x, \
TO * _y); \
LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2_MANGLE_RRRF,
float,
float,
float)
LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Multi-stage arbitrary resampler
//
#define MSRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp_rrrf,name)
#define MSRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp_crcf,name)
#define MSRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp_cccf,name)
#define LIQUID_MSRESAMP_DEFINE_API(MSRESAMP,TO,TC,TI) \
typedef struct MSRESAMP(_s) * MSRESAMP(); \
\
/* create multi-stage arbitrary resampler */ \
/* _r : resampling rate [output/input] */ \
/* _As : stop-band attenuation [dB] */ \
MSRESAMP() MSRESAMP(_create)(float _r, \
float _As); \
\
/* destroy multi-stage arbitrary resampler */ \
void MSRESAMP(_destroy)(MSRESAMP() _q); \
\
/* print msresamp object internals to stdout */ \
void MSRESAMP(_print)(MSRESAMP() _q); \
\
/* reset msresamp object internal state */ \
void MSRESAMP(_reset)(MSRESAMP() _q); \
\
/* get filter delay (output samples) */ \
float MSRESAMP(_get_delay)(MSRESAMP() _q); \
\
/* execute multi-stage resampler */ \
/* _q : msresamp object */ \
/* _x : input sample array [size: _nx x 1] */ \
/* _nx : input sample array size */ \
/* _y : output sample array [size: variable] */ \
/* _ny : number of samples written to _y */ \
void MSRESAMP(_execute)(MSRESAMP() _q, \
TI * _x, \
unsigned int _nx, \
TO * _y, \
unsigned int * _ny); \
LIQUID_MSRESAMP_DEFINE_API(MSRESAMP_MANGLE_RRRF,
float,
float,
float)
LIQUID_MSRESAMP_DEFINE_API(MSRESAMP_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_MSRESAMP_DEFINE_API(MSRESAMP_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Symbol timing recovery (symbol synchronizer)
//
#define SYMSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(symsync_rrrf,name)
#define SYMSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(symsync_crcf,name)
#define LIQUID_SYMSYNC_DEFINE_API(SYMSYNC,TO,TC,TI) \
\
typedef struct SYMSYNC(_s) * SYMSYNC(); \
\
/* create synchronizer object from external coefficients */ \
/* _k : samples per symbol */ \
/* _M : number of filters in the bank */ \
/* _h : matched filter coefficients [size: */ \
/* _h_len : length of matched filter */ \
SYMSYNC() SYMSYNC(_create)(unsigned int _k, \
unsigned int _M, \
TC * _h, \
unsigned int _h_len); \
\
/* create square-root Nyquist symbol synchronizer */ \
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
/* _k : samples/symbol */ \
/* _m : symbol delay */ \
/* _beta : rolloff factor, beta in (0,1] */ \
/* _M : number of filters in the bank */ \
SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, \
unsigned int _k, \
unsigned int _m, \
float _beta, \
unsigned int _M); \
\
/* create symsync using Kaiser filter interpolator; useful */ \
/* when the input signal has matched filter applied already */ \
/* _k : input samples/symbol */ \
/* _m : symbol delay */ \
/* _beta : rolloff factor, beta in (0,1] */ \
/* _M : number of filters in the bank */ \
SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k, \
unsigned int _m, \
float _beta, \
unsigned int _M); \
\
/* destroy symsync object, freeing all internal memory */ \
void SYMSYNC(_destroy)(SYMSYNC() _q); \
\
/* print symsync object's parameters */ \
void SYMSYNC(_print)(SYMSYNC() _q); \
\
/* reset symsync internal state */ \
void SYMSYNC(_reset)(SYMSYNC() _q); \
\
/* lock/unlock loop control */ \
void SYMSYNC(_lock)( SYMSYNC() _q); \
void SYMSYNC(_unlock)(SYMSYNC() _q); \
\
/* set synchronizer output rate (samples/symbol) */ \
/* _q : synchronizer object */ \
/* _k_out : output samples/symbol */ \
void SYMSYNC(_set_output_rate)(SYMSYNC() _q, \
unsigned int _k_out); \
\
/* set loop-filter bandwidth */ \
/* _q : synchronizer object */ \
/* _bt : loop bandwidth */ \
void SYMSYNC(_set_lf_bw)(SYMSYNC() _q, \
float _bt); \
\
/* return instantaneous fractional timing offset estimate */ \
float SYMSYNC(_get_tau)(SYMSYNC() _q); \
\
/* execute synchronizer on input data array */ \
/* _q : synchronizer object */ \
/* _x : input data array */ \
/* _nx : number of input samples */ \
/* _y : output data array */ \
/* _ny : number of samples written to output buffer */ \
void SYMSYNC(_execute)(SYMSYNC() _q, \
TI * _x, \
unsigned int _nx, \
TO * _y, \
unsigned int * _ny); \
LIQUID_SYMSYNC_DEFINE_API(SYMSYNC_MANGLE_RRRF,
float,
float,
float)
LIQUID_SYMSYNC_DEFINE_API(SYMSYNC_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
//
// Finite impulse response Farrow filter
//
#define FIRFARROW_MANGLE_RRRF(name) LIQUID_CONCAT(firfarrow_rrrf,name)
#define FIRFARROW_MANGLE_CRCF(name) LIQUID_CONCAT(firfarrow_crcf,name)
//#define FIRFARROW_MANGLE_CCCF(name) LIQUID_CONCAT(firfarrow_cccf,name)
// Macro:
// FIRFARROW : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FIRFARROW_DEFINE_API(FIRFARROW,TO,TC,TI) \
\
typedef struct FIRFARROW(_s) * FIRFARROW(); \
\
/* create firfarrow object */ \
/* _h_len : filter length */ \
/* _p : polynomial order */ \
/* _fc : filter cutoff frequency */ \
/* _As : stopband attenuation [dB] */ \
FIRFARROW() FIRFARROW(_create)(unsigned int _h_len, \
unsigned int _p, \
float _fc, \
float _As); \
\
/* destroy firfarrow object, freeing all internal memory */ \
void FIRFARROW(_destroy)(FIRFARROW() _q); \
\
/* print firfarrow object's internal properties */ \
void FIRFARROW(_print)(FIRFARROW() _q); \
\
/* reset firfarrow object's internal state */ \
void FIRFARROW(_reset)(FIRFARROW() _q); \
\
/* push sample into firfarrow object */ \
/* _q : firfarrow object */ \
/* _x : input sample */ \
void FIRFARROW(_push)(FIRFARROW() _q, \
TI _x); \
\
/* set fractional delay of firfarrow object */ \
/* _q : firfarrow object */ \
/* _mu : fractional sample delay */ \
void FIRFARROW(_set_delay)(FIRFARROW() _q, \
float _mu); \
\
/* execute firfarrow internal dot product */ \
/* _q : firfarrow object */ \
/* _y : output sample pointer */ \
void FIRFARROW(_execute)(FIRFARROW() _q, \
TO * _y); \
\
/* compute firfarrow filter on block of samples; the input */ \
/* and output arrays may have the same pointer */ \
/* _q : firfarrow object */ \
/* _x : input array [size: _n x 1] */ \
/* _n : input, output array size */ \
/* _y : output array [size: _n x 1] */ \
void FIRFARROW(_execute_block)(FIRFARROW() _q, \
TI * _x, \
unsigned int _n, \
TO * _y); \
\
/* get length of firfarrow object (number of filter taps) */ \
unsigned int FIRFARROW(_get_length)(FIRFARROW() _q); \
\
/* get coefficients of firfarrow object */ \
/* _q : firfarrow object */ \
/* _h : output coefficients pointer */ \
void FIRFARROW(_get_coefficients)(FIRFARROW() _q, \
float * _h); \
\
/* compute complex frequency response */ \
/* _q : filter object */ \
/* _fc : frequency */ \
/* _H : output frequency response */ \
void FIRFARROW(_freqresponse)(FIRFARROW() _q, \
float _fc, \
liquid_float_complex * _H); \
\
/* compute group delay [samples] */ \
/* _q : filter object */ \
/* _fc : frequency */ \
float FIRFARROW(_groupdelay)(FIRFARROW() _q, \
float _fc); \
LIQUID_FIRFARROW_DEFINE_API(FIRFARROW_MANGLE_RRRF,
float,
float,
float)
LIQUID_FIRFARROW_DEFINE_API(FIRFARROW_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
//
// MODULE : framing
//
// framesyncstats : generic frame synchronizer statistic structure
typedef struct {
// signal quality
float evm; // error vector magnitude [dB]
float rssi; // received signal strength indicator [dB]
float cfo; // carrier frequency offset (f/Fs)
// demodulated frame symbols
liquid_float_complex * framesyms; // pointer to array [size: framesyms x 1]
unsigned int num_framesyms; // length of framesyms
// modulation/coding scheme etc.
unsigned int mod_scheme; // modulation scheme
unsigned int mod_bps; // modulation depth (bits/symbol)
unsigned int check; // data validity check (crc, checksum)
unsigned int fec0; // forward error-correction (inner)
unsigned int fec1; // forward error-correction (outer)
} framesyncstats_s;
// external framesyncstats default object
extern framesyncstats_s framesyncstats_default;
// initialize framesyncstats object on default
void framesyncstats_init_default(framesyncstats_s * _stats);
// print framesyncstats object
void framesyncstats_print(framesyncstats_s * _stats);
// Generic frame synchronizer callback function type
// _header : header data [size: 8 bytes]
// _header_valid : is header valid? (0:no, 1:yes)
// _payload : payload data [size: _payload_len]
// _payload_len : length of payload (bytes)
// _payload_valid : is payload valid? (0:no, 1:yes)
// _stats : frame statistics object
// _userdata : pointer to userdata
typedef int (*framesync_callback)(unsigned char * _header,
int _header_valid,
unsigned char * _payload,
unsigned int _payload_len,
int _payload_valid,
framesyncstats_s _stats,
void * _userdata);
// framesync csma callback functions invoked when signal levels is high or low
// _userdata : user-defined data pointer
typedef void (*framesync_csma_callback)(void * _userdata);
//
// Basic frame generator (64 bytes data payload)
//
// frame length in samples
#define LIQUID_FRAME64_LEN (1340)
typedef struct framegen64_s * framegen64;
// create frame generator
framegen64 framegen64_create();
// destroy frame generator
void framegen64_destroy(framegen64 _q);
// print frame generator internal properties
void framegen64_print(framegen64 _q);
// generate frame
// _q : frame generator object
// _header : 8-byte header data
// _payload : 64-byte payload data
// _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1]
void framegen64_execute(framegen64 _q,
unsigned char * _header,
unsigned char * _payload,
liquid_float_complex * _frame);
typedef struct framesync64_s * framesync64;
// create framesync64 object
// _callback : callback function
// _userdata : user data pointer passed to callback function
framesync64 framesync64_create(framesync_callback _callback,
void * _userdata);
// destroy frame synchronizer
void framesync64_destroy(framesync64 _q);
// print frame synchronizer internal properties
void framesync64_print(framesync64 _q);
// reset frame synchronizer internal state
void framesync64_reset(framesync64 _q);
// push samples through frame synchronizer
// _q : frame synchronizer object
// _x : input samples [size: _n x 1]
// _n : number of input samples
void framesync64_execute(framesync64 _q,
liquid_float_complex * _x,
unsigned int _n);
// enable/disable debugging
void framesync64_debug_enable(framesync64 _q);
void framesync64_debug_disable(framesync64 _q);
void framesync64_debug_print(framesync64 _q, const char * _filename);
#if 0
// advanced modes
void framesync64_set_csma_callbacks(framesync64 _q,
framesync_csma_callback _csma_lock,
framesync_csma_callback _csma_unlock,
void * _csma_userdata);
#endif
//
// Flexible frame : adjustable payload, mod scheme, etc., but bring
// your own error correction, redundancy check
//
// frame generator
typedef struct {
unsigned int check; // data validity check
unsigned int fec0; // forward error-correction scheme (inner)
unsigned int fec1; // forward error-correction scheme (outer)
unsigned int mod_scheme; // modulation scheme
} flexframegenprops_s;
void flexframegenprops_init_default(flexframegenprops_s * _fgprops);
typedef struct flexframegen_s * flexframegen;
// create flexframegen object
// _props : frame properties (modulation scheme, etc.)
flexframegen flexframegen_create(flexframegenprops_s * _props);
// destroy flexframegen object
void flexframegen_destroy(flexframegen _q);
// print flexframegen object internals
void flexframegen_print(flexframegen _q);
// reset flexframegen object internals
void flexframegen_reset(flexframegen _q);
// is frame assembled?
int flexframegen_is_assembled(flexframegen _q);
// get frame properties
void flexframegen_getprops(flexframegen _q, flexframegenprops_s * _props);
// set frame properties
void flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props);
// get length of assembled frame (samples)
unsigned int flexframegen_getframelen(flexframegen _q);
// assemble a frame from an array of data
// _q : frame generator object
// _header : frame header
// _payload : payload data [size: _payload_len x 1]
// _payload_len : payload data length
void flexframegen_assemble(flexframegen _q,
unsigned char * _header,
unsigned char * _payload,
unsigned int _payload_len);
// write samples of assembled frame, two samples at a time, returning
// '1' when frame is complete, '0' otherwise
// _q : frame generator object
// _buffer : output buffer [size: 2 x 1]
int flexframegen_write_samples(flexframegen _q,
liquid_float_complex * _buffer);
// frame synchronizer
typedef struct flexframesync_s * flexframesync;
// create flexframesync object
// _callback : callback function
// _userdata : user data pointer passed to callback function
flexframesync flexframesync_create(framesync_callback _callback,
void * _userdata);
// destroy frame synchronizer
void flexframesync_destroy(flexframesync _q);
// print frame synchronizer internal properties
void flexframesync_print(flexframesync _q);
// reset frame synchronizer internal state
void flexframesync_reset(flexframesync _q);
// push samples through frame synchronizer
// _q : frame synchronizer object
// _x : input samples [size: _n x 1]
// _n : number of input samples
void flexframesync_execute(flexframesync _q,
liquid_float_complex * _x,
unsigned int _n);
// enable/disable debugging
void flexframesync_debug_enable(flexframesync _q);
void flexframesync_debug_disable(flexframesync _q);
void flexframesync_debug_print(flexframesync _q,
const char * _filename);
#if 0
// advanced modes
void flexframesync_set_csma_callbacks(flexframesync _fs,
framesync_csma_callback _csma_lock,
framesync_csma_callback _csma_unlock,
void * _csma_userdata);
#endif
//
// bpacket : binary packet suitable for data streaming
//
//
// bpacket generator/encoder
//
typedef struct bpacketgen_s * bpacketgen;
// create bpacketgen object
// _m : p/n sequence length (ignored)
// _dec_msg_len : decoded message length (original uncoded data)
// _crc : data validity check (e.g. cyclic redundancy check)
// _fec0 : inner forward error-correction code scheme
// _fec1 : outer forward error-correction code scheme
bpacketgen bpacketgen_create(unsigned int _m,
unsigned int _dec_msg_len,
int _crc,
int _fec0,
int _fec1);
// re-create bpacketgen object from old object
// _q : old bpacketgen object
// _m : p/n sequence length (ignored)
// _dec_msg_len : decoded message length (original uncoded data)
// _crc : data validity check (e.g. cyclic redundancy check)
// _fec0 : inner forward error-correction code scheme
// _fec1 : outer forward error-correction code scheme
bpacketgen bpacketgen_recreate(bpacketgen _q,
unsigned int _m,
unsigned int _dec_msg_len,
int _crc,
int _fec0,
int _fec1);
// destroy bpacketgen object, freeing all internally-allocated memory
void bpacketgen_destroy(bpacketgen _q);
// print bpacketgen internals
void bpacketgen_print(bpacketgen _q);
// return length of full packet
unsigned int bpacketgen_get_packet_len(bpacketgen _q);
// encode packet
void bpacketgen_encode(bpacketgen _q,
unsigned char * _msg_dec,
unsigned char * _packet);
//
// bpacket synchronizer/decoder
//
typedef struct bpacketsync_s * bpacketsync;
typedef int (*bpacketsync_callback)(unsigned char * _payload,
int _payload_valid,
unsigned int _payload_len,
framesyncstats_s _stats,
void * _userdata);
bpacketsync bpacketsync_create(unsigned int _m,
bpacketsync_callback _callback,
void * _userdata);
void bpacketsync_destroy(bpacketsync _q);
void bpacketsync_print(bpacketsync _q);
void bpacketsync_reset(bpacketsync _q);
// run synchronizer on array of input bytes
// _q : bpacketsync object
// _bytes : input data array [size: _n x 1]
// _n : input array size
void bpacketsync_execute(bpacketsync _q,
unsigned char * _bytes,
unsigned int _n);
// run synchronizer on input byte
// _q : bpacketsync object
// _byte : input byte
void bpacketsync_execute_byte(bpacketsync _q,
unsigned char _byte);
// run synchronizer on input symbol
// _q : bpacketsync object
// _sym : input symbol with _bps significant bits
// _bps : number of bits in input symbol
void bpacketsync_execute_sym(bpacketsync _q,
unsigned char _sym,
unsigned int _bps);
// execute one bit at a time
void bpacketsync_execute_bit(bpacketsync _q,
unsigned char _bit);
//
// GMSK frame generator
//
typedef struct gmskframegen_s * gmskframegen;
// create GMSK frame generator
gmskframegen gmskframegen_create();
void gmskframegen_destroy(gmskframegen _fg);
void gmskframegen_print(gmskframegen _fg);
void gmskframegen_reset(gmskframegen _fg);
void gmskframegen_assemble(gmskframegen _fg,
unsigned char * _header,
unsigned char * _payload,
unsigned int _payload_len,
crc_scheme _check,
fec_scheme _fec0,
fec_scheme _fec1);
unsigned int gmskframegen_getframelen(gmskframegen _q);
int gmskframegen_write_samples(gmskframegen _fg,
liquid_float_complex * _y);
//
// GMSK frame synchronizer
//
typedef struct gmskframesync_s * gmskframesync;
// create GMSK frame synchronizer
// _callback : callback function
// _userdata : user data pointer passed to callback function
gmskframesync gmskframesync_create(framesync_callback _callback,
void * _userdata);
void gmskframesync_destroy(gmskframesync _q);
void gmskframesync_print(gmskframesync _q);
void gmskframesync_reset(gmskframesync _q);
void gmskframesync_execute(gmskframesync _q,
liquid_float_complex * _x,
unsigned int _n);
// debugging
void gmskframesync_debug_enable(gmskframesync _q);
void gmskframesync_debug_disable(gmskframesync _q);
void gmskframesync_debug_print(gmskframesync _q, const char * _filename);
//
// OFDM flexframe generator
//
// ofdm frame generator properties
typedef struct {
unsigned int check; // data validity check
unsigned int fec0; // forward error-correction scheme (inner)
unsigned int fec1; // forward error-correction scheme (outer)
unsigned int mod_scheme; // modulation scheme
//unsigned int block_size; // framing block size
} ofdmflexframegenprops_s;
void ofdmflexframegenprops_init_default(ofdmflexframegenprops_s * _props);
typedef struct ofdmflexframegen_s * ofdmflexframegen;
// create OFDM flexible framing generator object
// _M : number of subcarriers, >10 typical
// _cp_len : cyclic prefix length
// _taper_len : taper length (OFDM symbol overlap)
// _p : subcarrier allocation (null, pilot, data), [size: _M x 1]
// _fgprops : frame properties (modulation scheme, etc.)
ofdmflexframegen ofdmflexframegen_create(unsigned int _M,
unsigned int _cp_len,
unsigned int _taper_len,
unsigned char * _p,
ofdmflexframegenprops_s * _fgprops);
// destroy ofdmflexframegen object
void ofdmflexframegen_destroy(ofdmflexframegen _q);
// print parameters, properties, etc.
void ofdmflexframegen_print(ofdmflexframegen _q);
// reset ofdmflexframegen object internals
void ofdmflexframegen_reset(ofdmflexframegen _q);
// is frame assembled?
int ofdmflexframegen_is_assembled(ofdmflexframegen _q);
// get properties
void ofdmflexframegen_getprops(ofdmflexframegen _q,
ofdmflexframegenprops_s * _props);
// set properties
void ofdmflexframegen_setprops(ofdmflexframegen _q,
ofdmflexframegenprops_s * _props);
// get length of frame (symbols)
// _q : OFDM frame generator object
unsigned int ofdmflexframegen_getframelen(ofdmflexframegen _q);
// assemble a frame from an array of data
// _q : OFDM frame generator object
// _header : frame header [8 bytes]
// _payload : payload data [size: _payload_len x 1]
// _payload_len : payload data length
void ofdmflexframegen_assemble(ofdmflexframegen _q,
unsigned char * _header,
unsigned char * _payload,
unsigned int _payload_len);
// write symbols of assembled frame
// _q : OFDM frame generator object
// _buffer : output buffer [size: M+cp_len x 1]
int ofdmflexframegen_writesymbol(ofdmflexframegen _q,
liquid_float_complex * _buffer);
//
// OFDM flex frame synchronizer
//
typedef struct ofdmflexframesync_s * ofdmflexframesync;
// create OFDM flexible framing synchronizer object
// _M : number of subcarriers
// _cp_len : cyclic prefix length
// _taper_len : taper length (OFDM symbol overlap)
// _p : subcarrier allocation (null, pilot, data), [size: _M x 1]
// _callback : user-defined callback function
// _userdata : user-defined data pointer
ofdmflexframesync ofdmflexframesync_create(unsigned int _M,
unsigned int _cp_len,
unsigned int _taper_len,
unsigned char * _p,
framesync_callback _callback,
void * _userdata);
void ofdmflexframesync_destroy(ofdmflexframesync _q);
void ofdmflexframesync_print(ofdmflexframesync _q);
void ofdmflexframesync_reset(ofdmflexframesync _q);
void ofdmflexframesync_execute(ofdmflexframesync _q,
liquid_float_complex * _x,
unsigned int _n);
// query the received signal strength indication
float ofdmflexframesync_get_rssi(ofdmflexframesync _q);
// query the received carrier offset estimate
float ofdmflexframesync_get_cfo(ofdmflexframesync _q);
// enable/disable debugging
void ofdmflexframesync_debug_enable(ofdmflexframesync _q);
void ofdmflexframesync_debug_disable(ofdmflexframesync _q);
void ofdmflexframesync_debug_print(ofdmflexframesync _q,
const char * _filename);
//
// Binary P/N synchronizer
//
#define BSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(bsync_rrrf,name)
#define BSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(bsync_crcf,name)
#define BSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bsync_cccf,name)
// Macro:
// BSYNC : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_BSYNC_DEFINE_API(BSYNC,TO,TC,TI) \
typedef struct BSYNC(_s) * BSYNC(); \
\
BSYNC() BSYNC(_create)(unsigned int _n, TC * _v); \
\
/* create binary synchronizer from m-sequence */ \
/* _g : m-sequence generator polynomial */ \
/* _k : samples/symbol (over-sampling factor) */ \
BSYNC() BSYNC(_create_msequence)(unsigned int _g, \
unsigned int _k); \
void BSYNC(_destroy)(BSYNC() _fs); \
void BSYNC(_print)(BSYNC() _fs); \
void BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO * _y);
LIQUID_BSYNC_DEFINE_API(BSYNC_MANGLE_RRRF,
float,
float,
float)
LIQUID_BSYNC_DEFINE_API(BSYNC_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_BSYNC_DEFINE_API(BSYNC_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Pre-demodulation synchronizers (binary and otherwise)
//
#define PRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT( presync_cccf,name)
#define BPRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bpresync_cccf,name)
// Macro:
// PRESYNC : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_PRESYNC_DEFINE_API(PRESYNC,TO,TC,TI) \
typedef struct PRESYNC(_s) * PRESYNC(); \
\
/* create pre-demod synchronizer */ \
/* _v : baseband sequence */ \
/* _n : baseband sequence length */ \
/* _dphi_max : maximum absolute frequency deviation */ \
/* _m : number of correlators */ \
PRESYNC() PRESYNC(_create)(TC * _v, \
unsigned int _n, \
float _dphi_max, \
unsigned int _m); \
\
/* destroy pre-demod synchronizer */ \
void PRESYNC(_destroy)(PRESYNC() _q); \
\
/* print pre-demod synchronizer internal state */ \
void PRESYNC(_print)(PRESYNC() _q); \
\
/* reset pre-demod synchronizer internal state */ \
void PRESYNC(_reset)(PRESYNC() _q); \
\
/* push input sample into pre-demod synchronizer */ \
/* _q : pre-demod synchronizer object */ \
/* _x : input sample */ \
void PRESYNC(_push)(PRESYNC() _q, \
TI _x); \
\
/* correlate input sequence */ \
/* _q : pre-demod synchronizer object */ \
/* _rxy : output cross correlation */ \
/* _dphi_hat : output frequency offset estiamte */ \
void PRESYNC(_correlate)(PRESYNC() _q, \
TO * _rxy, \
float * _dphi_hat); \
// non-binary pre-demodulation synchronizer
LIQUID_PRESYNC_DEFINE_API(PRESYNC_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
// binary pre-demodulation synchronizer
LIQUID_PRESYNC_DEFINE_API(BPRESYNC_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Pre-demodulation detector
//
typedef struct detector_cccf_s * detector_cccf;
// create pre-demod detector
// _s : sequence
// _n : sequence length
// _threshold : detection threshold (default: 0.7)
// _dphi_max : maximum carrier offset
detector_cccf detector_cccf_create(liquid_float_complex * _s,
unsigned int _n,
float _threshold,
float _dphi_max);
// destroy pre-demo detector object
void detector_cccf_destroy(detector_cccf _q);
// print pre-demod detector internal state
void detector_cccf_print(detector_cccf _q);
// reset pre-demod detector internal state
void detector_cccf_reset(detector_cccf _q);
// Run sample through pre-demod detector's correlator.
// Returns '1' if signal was detected, '0' otherwise
// _q : pre-demod detector
// _x : input sample
// _tau_hat : fractional sample offset estimate (set when detected)
// _dphi_hat : carrier frequency offset estimate (set when detected)
// _gamma_hat : channel gain estimate (set when detected)
int detector_cccf_correlate(detector_cccf _q,
liquid_float_complex _x,
float * _tau_hat,
float * _dphi_hat,
float * _gamma_hat);
//
// MODULE : math
//
// ln( Gamma(z) )
float liquid_lngammaf(float _z);
// Gamma(z)
float liquid_gammaf(float _z);
// ln( gamma(z,alpha) ) : lower incomplete gamma function
float liquid_lnlowergammaf(float _z, float _alpha);
// ln( Gamma(z,alpha) ) : upper incomplete gamma function
float liquid_lnuppergammaf(float _z, float _alpha);
// gamma(z,alpha) : lower incomplete gamma function
float liquid_lowergammaf(float _z, float _alpha);
// Gamma(z,alpha) : upper incomplete gamma function
float liquid_uppergammaf(float _z, float _alpha);
// n!
float liquid_factorialf(unsigned int _n);
// ln(I_v(z)) : log Modified Bessel function of the first kind
float liquid_lnbesselif(float _nu, float _z);
// I_v(z) : Modified Bessel function of the first kind
float liquid_besselif(float _nu, float _z);
// I_0(z) : Modified Bessel function of the first kind (order zero)
float liquid_besseli0f(float _z);
// J_v(z) : Bessel function of the first kind
float liquid_besseljf(float _nu, float _z);
// J_0(z) : Bessel function of the first kind (order zero)
float liquid_besselj0f(float _z);
// Q function
float liquid_Qf(float _z);
// Marcum Q-function
float liquid_MarcumQf(int _M,
float _alpha,
float _beta);
// Marcum Q-function (M=1)
float liquid_MarcumQ1f(float _alpha,
float _beta);
// sin(pi x) / (pi x)
float sincf(float _x);
// next power of 2 : y = ceil(log2(_x))
unsigned int liquid_nextpow2(unsigned int _x);
// (n choose k) = n! / ( k! (n-k)! )
float liquid_nchoosek(unsigned int _n, unsigned int _k);
//
// Windowing functions
//
// Kaiser-Bessel derived window (single sample)
// _n : index (0 <= _n < _N)
// _N : length of filter (must be even)
// _beta : Kaiser window parameter (_beta > 0)
float liquid_kbd(unsigned int _n, unsigned int _N, float _beta);
// Kaiser-Bessel derived window (full window)
// _n : length of filter (must be even)
// _beta : Kaiser window parameter (_beta > 0)
// _w : resulting window
void liquid_kbd_window(unsigned int _n, float _beta, float * _w);
// Kaiser window
// _n : window index
// _N : full window length
// _beta : Kaiser-Bessel window shape parameter
// _dt : fractional sample offset
float kaiser(unsigned int _n,
unsigned int _N,
float _beta,
float _dt);
// Hamming window
// _n : window index
// _N : full window length
float hamming(unsigned int _n, unsigned int _N);
// Hann window
// _n : window index
// _N : full window length
float hann(unsigned int _n, unsigned int _N);
// Blackman-harris window
// _n : window index
// _N : full window length
float blackmanharris(unsigned int _n, unsigned int _N);
// polynomials
#define POLY_MANGLE_DOUBLE(name) LIQUID_CONCAT(poly, name)
#define POLY_MANGLE_FLOAT(name) LIQUID_CONCAT(polyf, name)
#define POLY_MANGLE_CDOUBLE(name) LIQUID_CONCAT(polyc, name)
#define POLY_MANGLE_CFLOAT(name) LIQUID_CONCAT(polycf, name)
// large macro
// POLY : name-mangling macro
// T : data type
// TC : data type (complex)
#define LIQUID_POLY_DEFINE_API(POLY,T,TC) \
/* evaluate polynomial _p (order _k-1) at value _x */ \
T POLY(_val)(T * _p, unsigned int _k, T _x); \
\
/* least-squares polynomial fit (order _k-1) */ \
void POLY(_fit)(T * _x, \
T * _y, \
unsigned int _n, \
T * _p, \
unsigned int _k); \
\
/* Lagrange polynomial exact fit (order _n-1) */ \
void POLY(_fit_lagrange)(T * _x, \
T * _y, \
unsigned int _n, \
T * _p); \
\
/* Lagrange polynomial interpolation */ \
T POLY(_interp_lagrange)(T * _x, \
T * _y, \
unsigned int _n, \
T _x0); \
\
/* Lagrange polynomial fit (barycentric form) */ \
void POLY(_fit_lagrange_barycentric)(T * _x, \
unsigned int _n, \
T * _w); \
\
/* Lagrange polynomial interpolation (barycentric form) */ \
T POLY(_val_lagrange_barycentric)(T * _x, \
T * _y, \
T * _w, \
T _x0, \
unsigned int _n); \
\
/* expands the polynomial: \
* P_n(x) = (1+x)^n \
* as \
* P_n(x) = p[0] + p[1]*x + p[2]*x^2 + ... + p[n]x^n \
* NOTE: _p has order n=m+k (array is length n+1) \
*/ \
void POLY(_expandbinomial)(unsigned int _n, \
T * _p); \
\
/* expands the polynomial: \
* P_n(x) = (1+x)^m * (1-x)^k \
* as \
* P_n(x) = p[0] + p[1]*x + p[2]*x^2 + ... + p[n]x^n \
* NOTE: _p has order n=m+k (array is length n+1) \
*/ \
void POLY(_expandbinomial_pm)(unsigned int _m, \
unsigned int _k, \
T * _p); \
\
/* expands the polynomial: \
* P_n(x) = (x-r[0]) * (x-r[1]) * ... * (x-r[n-1]) \
* as \
* P_n(x) = c[0] + c[1]*x + ... + c[n]*x^n \
* where r[0],r[1],...,r[n-1] are the roots of P_n(x) \
* NOTE: _c has order _n (array is length _n+1) \
*/ \
void POLY(_expandroots)(T * _a, \
unsigned int _n, \
T * _c); \
\
/* expands the polynomial: \
* P_n(x) = \
* (x*b[0]-a[0]) * (x*b[1]-a[1]) * ... * (x*b[n-1]-a[n-1]) \
* as \
* P_n(x) = c[0] + c[1]*x + ... + c[n]*x^n \
* NOTE: _c has order _n (array is length _n+1) \
*/ \
void POLY(_expandroots2)(T * _a, \
T * _b, \
unsigned int _n, \
T * _c); \
\
/* find roots of the polynomial (complex) */ \
/* _poly : poly array, ascending powers [size: _k x 1] */ \
/* _k : poly length (poly order = _k - 1) */ \
/* _roots : resulting complex roots [size: _k-1 x 1] */ \
void POLY(_findroots)(T * _poly, \
unsigned int _n, \
TC * _roots); \
\
/* find the complex roots of the polynomial using the */ \
/* Durand-Kerner method */ \
void POLY(_findroots_durandkerner)(T * _poly, \
unsigned int _k, \
TC * _roots); \
\
/* find the complex roots of the polynomial using */ \
/* Bairstow's method */ \
void POLY(_findroots_bairstow)(T * _poly, \
unsigned int _k, \
TC * _roots); \
\
/* expands the multiplication of two polynomials */ \
void POLY(_mul)(T * _a, \
unsigned int _order_a, \
T * _b, \
unsigned int _order_b, \
T * _c); \
LIQUID_POLY_DEFINE_API(POLY_MANGLE_DOUBLE,
double,
liquid_double_complex)
LIQUID_POLY_DEFINE_API(POLY_MANGLE_FLOAT,
float,
liquid_float_complex)
LIQUID_POLY_DEFINE_API(POLY_MANGLE_CDOUBLE,
liquid_double_complex,
liquid_double_complex)
LIQUID_POLY_DEFINE_API(POLY_MANGLE_CFLOAT,
liquid_float_complex,
liquid_float_complex)
#if 0
// expands the polynomial: (1+x)^n
void poly_binomial_expand(unsigned int _n, int * _c);
// expands the polynomial: (1+x)^k * (1-x)^(n-k)
void poly_binomial_expand_pm(unsigned int _n,
unsigned int _k,
int * _c);
#endif
//
// modular arithmetic, etc.
//
// maximum number of factors
#define LIQUID_MAX_FACTORS (40)
// is number prime?
int liquid_is_prime(unsigned int _n);
// compute number's prime factors
// _n : number to factor
// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1]
// _num_factors: number of factors found, sorted ascending
void liquid_factor(unsigned int _n,
unsigned int * _factors,
unsigned int * _num_factors);
// compute number's unique prime factors
// _n : number to factor
// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1]
// _num_factors: number of unique factors found, sorted ascending
void liquid_unique_factor(unsigned int _n,
unsigned int * _factors,
unsigned int * _num_factors);
// compute c = base^exp (mod n)
unsigned int liquid_modpow(unsigned int _base,
unsigned int _exp,
unsigned int _n);
// find smallest primitive root of _n
unsigned int liquid_primitive_root(unsigned int _n);
// find smallest primitive root of _n, assuming _n is prime
unsigned int liquid_primitive_root_prime(unsigned int _n);
// Euler's totient function
unsigned int liquid_totient(unsigned int _n);
//
// MODULE : matrix
//
#define MATRIX_MANGLE_DOUBLE(name) LIQUID_CONCAT(matrix, name)
#define MATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(matrixf, name)
#define MATRIX_MANGLE_CDOUBLE(name) LIQUID_CONCAT(matrixc, name)
#define MATRIX_MANGLE_CFLOAT(name) LIQUID_CONCAT(matrixcf, name)
// large macro
// MATRIX : name-mangling macro
// T : data type
#define LIQUID_MATRIX_DEFINE_API(MATRIX,T) \
void MATRIX(_print)(T * _x, \
unsigned int _rx, \
unsigned int _cx); \
void MATRIX(_add)(T * _x, \
T * _y, \
T * _z, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_sub)(T * _x, \
T * _y, \
T * _z, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_pmul)(T * _x, \
T * _y, \
T * _z, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_pdiv)(T * _x, \
T * _y, \
T * _z, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_mul)(T * _x, unsigned int _rx, unsigned int _cx, \
T * _y, unsigned int _ry, unsigned int _cy, \
T * _z, unsigned int _rz, unsigned int _cz); \
void MATRIX(_div)(T * _x, T * _y, T * _z, unsigned int _n); \
T MATRIX(_det)(T * _x, unsigned int _r, unsigned int _c); \
void MATRIX(_trans)(T * _x, unsigned int _rx, unsigned int _cx);\
void MATRIX(_hermitian)(T * _x, \
unsigned int _rx, \
unsigned int _cx); \
\
/* compute x*x' on [m x n] matrix, result: [m x m] */ \
void MATRIX(_mul_transpose)(T * _x, \
unsigned int _m, \
unsigned int _n, \
T * _xxT); \
/* compute x'*x on [m x n] matrix, result: [n x n] */ \
void MATRIX(_transpose_mul)(T * _x, \
unsigned int _m, \
unsigned int _n, \
T * _xTx); \
/* compute x*x.' on [m x n] matrix, result: [m x m] */ \
void MATRIX(_mul_hermitian)(T * _x, \
unsigned int _m, \
unsigned int _n, \
T * _xxH); \
/* compute x.'*x on [m x n] matrix, result: [n x n] */ \
void MATRIX(_hermitian_mul)(T * _x, \
unsigned int _m, \
unsigned int _n, \
T * _xHx); \
\
void MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx, \
T * _y, unsigned int _ry, unsigned int _cy, \
T * _z, unsigned int _rz, unsigned int _cz); \
void MATRIX(_inv)(T * _x, \
unsigned int _rx, \
unsigned int _cx); \
void MATRIX(_eye)(T * _x, \
unsigned int _n); \
void MATRIX(_ones)(T * _x, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_zeros)(T * _x, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_gjelim)(T * _x, \
unsigned int _rx, \
unsigned int _cx); \
void MATRIX(_pivot)(T * _x, \
unsigned int _rx, \
unsigned int _cx, \
unsigned int _r, \
unsigned int _c); \
void MATRIX(_swaprows)(T * _x, \
unsigned int _rx, \
unsigned int _cx, \
unsigned int _r1, \
unsigned int _r2); \
void MATRIX(_linsolve)(T * _A, \
unsigned int _r, \
T * _b, \
T * _x, \
void * _opts); \
void MATRIX(_cgsolve)(T * _A, \
unsigned int _r, \
T * _b, \
T * _x, \
void * _opts); \
void MATRIX(_ludecomp_crout)(T * _x, \
unsigned int _rx, \
unsigned int _cx, \
T * _L, \
T * _U, \
T * _P); \
void MATRIX(_ludecomp_doolittle)(T * _x, \
unsigned int _rx, \
unsigned int _cx, \
T * _L, \
T * _U, \
T * _P); \
void MATRIX(_gramschmidt)(T * _A, \
unsigned int _rx, \
unsigned int _cx, \
T * _U); \
void MATRIX(_qrdecomp_gramschmidt)(T * _x, \
unsigned int _rx, \
unsigned int _cx, \
T * _Q, \
T * _R); \
void MATRIX(_chol)(T * _A, \
unsigned int _n, \
T * _L); \
#define matrix_access(X,R,C,r,c) ((X)[(r)*(C)+(c)])
#define matrixc_access(X,R,C,r,c) matrix_access(X,R,C,r,c)
#define matrixf_access(X,R,C,r,c) matrix_access(X,R,C,r,c)
#define matrixcf_access(X,R,C,r,c) matrix_access(X,R,C,r,c)
LIQUID_MATRIX_DEFINE_API(MATRIX_MANGLE_FLOAT, float)
LIQUID_MATRIX_DEFINE_API(MATRIX_MANGLE_DOUBLE, double)
LIQUID_MATRIX_DEFINE_API(MATRIX_MANGLE_CFLOAT, liquid_float_complex)
LIQUID_MATRIX_DEFINE_API(MATRIX_MANGLE_CDOUBLE, liquid_double_complex)
#define SMATRIX_MANGLE_BOOL(name) LIQUID_CONCAT(smatrixb, name)
#define SMATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(smatrixf, name)
#define SMATRIX_MANGLE_INT(name) LIQUID_CONCAT(smatrixi, name)
// sparse 'alist' matrix type (similar to MacKay, Davey Lafferty convention)
// large macro
// SMATRIX : name-mangling macro
// T : primitive data type
#define LIQUID_SMATRIX_DEFINE_API(SMATRIX,T) \
typedef struct SMATRIX(_s) * SMATRIX(); \
\
/* create _M x _N matrix, initialized with zeros */ \
SMATRIX() SMATRIX(_create)(unsigned int _M, \
unsigned int _N); \
\
/* create _M x _N matrix, initialized on array */ \
SMATRIX() SMATRIX(_create_array)(T * _x, \
unsigned int _m, \
unsigned int _n); \
\
/* destroy object */ \
void SMATRIX(_destroy)(SMATRIX() _q); \
\
/* print compact form */ \
void SMATRIX(_print)(SMATRIX() _q); \
\
/* print expanded form */ \
void SMATRIX(_print_expanded)(SMATRIX() _q); \
\
/* query properties methods */ \
void SMATRIX(_size)(SMATRIX() _q, \
unsigned int * _m, \
unsigned int * _n); \
\
/* zero all elements */ \
void SMATRIX(_clear)(SMATRIX() _q); /* zero and keep memory */ \
void SMATRIX(_reset)(SMATRIX() _q); /* zero and clear memory */ \
\
/* determine if value has been set (allocated memory) */ \
int SMATRIX(_isset)(SMATRIX() _q, \
unsigned int _m, \
unsigned int _n); \
\
/* inserts/deletes element at index (memory allocation) */ \
void SMATRIX(_insert)(SMATRIX() _q, \
unsigned int _m, \
unsigned int _n, \
T _v); \
void SMATRIX(_delete)(SMATRIX() _q, \
unsigned int _m, \
unsigned int _n); \
\
/* sets/gets the value (with memory allocation if needed) */ \
void SMATRIX(_set)(SMATRIX() _q, \
unsigned int _m, \
unsigned int _n, \
T _v); \
T SMATRIX(_get)(SMATRIX() _q, \
unsigned int _m, \
unsigned int _n); \
\
/* initialize to identity matrix */ \
void SMATRIX(_eye)(SMATRIX() _q); \
\
/* multiply two sparse binary matrices */ \
void SMATRIX(_mul)(SMATRIX() _x, \
SMATRIX() _y, \
SMATRIX() _z); \
\
/* multiply sparse matrix by vector */ \
/* _q : sparse matrix */ \
/* _x : input vector [size: _N x 1] */ \
/* _y : output vector [size: _M x 1] */ \
void SMATRIX(_vmul)(SMATRIX() _q, \
T * _x, \
T * _y); \
LIQUID_SMATRIX_DEFINE_API(SMATRIX_MANGLE_BOOL, unsigned char)
LIQUID_SMATRIX_DEFINE_API(SMATRIX_MANGLE_FLOAT, float)
LIQUID_SMATRIX_DEFINE_API(SMATRIX_MANGLE_INT, short int)
//
// smatrix cross methods
//
// multiply sparse binary matrix by floating-point matrix
// _q : sparse matrix [size: A->M x A->N]
// _x : input vector [size: mx x nx ]
// _y : output vector [size: my x ny ]
void smatrixb_mulf(smatrixb _A,
float * _x,
unsigned int _mx,
unsigned int _nx,
float * _y,
unsigned int _my,
unsigned int _ny);
// multiply sparse binary matrix by floating-point vector
// _q : sparse matrix
// _x : input vector [size: _N x 1]
// _y : output vector [size: _M x 1]
void smatrixb_vmulf(smatrixb _q,
float * _x,
float * _y);
//
// MODULE : modem (modulator/demodulator)
//
// Maximum number of allowed bits per symbol
#define MAX_MOD_BITS_PER_SYMBOL 8
// Modulation schemes available
#define LIQUID_MODEM_NUM_SCHEMES (52)
typedef enum {
LIQUID_MODEM_UNKNOWN=0, // Unknown modulation scheme
// Phase-shift keying (PSK)
LIQUID_MODEM_PSK2, LIQUID_MODEM_PSK4,
LIQUID_MODEM_PSK8, LIQUID_MODEM_PSK16,
LIQUID_MODEM_PSK32, LIQUID_MODEM_PSK64,
LIQUID_MODEM_PSK128, LIQUID_MODEM_PSK256,
// Differential phase-shift keying (DPSK)
LIQUID_MODEM_DPSK2, LIQUID_MODEM_DPSK4,
LIQUID_MODEM_DPSK8, LIQUID_MODEM_DPSK16,
LIQUID_MODEM_DPSK32, LIQUID_MODEM_DPSK64,
LIQUID_MODEM_DPSK128, LIQUID_MODEM_DPSK256,
// amplitude-shift keying
LIQUID_MODEM_ASK2, LIQUID_MODEM_ASK4,
LIQUID_MODEM_ASK8, LIQUID_MODEM_ASK16,
LIQUID_MODEM_ASK32, LIQUID_MODEM_ASK64,
LIQUID_MODEM_ASK128, LIQUID_MODEM_ASK256,
// rectangular quadrature amplitude-shift keying (QAM)
LIQUID_MODEM_QAM4,
LIQUID_MODEM_QAM8, LIQUID_MODEM_QAM16,
LIQUID_MODEM_QAM32, LIQUID_MODEM_QAM64,
LIQUID_MODEM_QAM128, LIQUID_MODEM_QAM256,
// amplitude phase-shift keying (APSK)
LIQUID_MODEM_APSK4,
LIQUID_MODEM_APSK8, LIQUID_MODEM_APSK16,
LIQUID_MODEM_APSK32, LIQUID_MODEM_APSK64,
LIQUID_MODEM_APSK128, LIQUID_MODEM_APSK256,
// specific modem types
LIQUID_MODEM_BPSK, // Specific: binary PSK
LIQUID_MODEM_QPSK, // specific: quaternary PSK
LIQUID_MODEM_OOK, // Specific: on/off keying
LIQUID_MODEM_SQAM32, // 'square' 32-QAM
LIQUID_MODEM_SQAM128, // 'square' 128-QAM
LIQUID_MODEM_V29, // V.29 star constellation
LIQUID_MODEM_ARB16OPT, // optimal 16-QAM
LIQUID_MODEM_ARB32OPT, // optimal 32-QAM
LIQUID_MODEM_ARB64OPT, // optimal 64-QAM
LIQUID_MODEM_ARB128OPT, // optimal 128-QAM
LIQUID_MODEM_ARB256OPT, // optimal 256-QAM
LIQUID_MODEM_ARB64VT, // Virginia Tech logo
// arbitrary modem type
LIQUID_MODEM_ARB // arbitrary QAM
} modulation_scheme;
// structure for holding full modulation type descriptor
struct modulation_type_s {
const char * name; // short name (e.g. 'bpsk')
const char * fullname; // full name (e.g. 'binary phase-shift keying')
modulation_scheme scheme; // modulation scheme (e.g. LIQUID_MODEM_BPSK)
unsigned int bps; // modulation depth (e.g. 1)
};
// full modulation type descriptor
extern const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES];
// Print compact list of existing and available modulation schemes
void liquid_print_modulation_schemes();
// returns modulation_scheme based on input string
modulation_scheme liquid_getopt_str2mod(const char * _str);
// query basic modulation types
int liquid_modem_is_psk(modulation_scheme _ms);
int liquid_modem_is_dpsk(modulation_scheme _ms);
int liquid_modem_is_ask(modulation_scheme _ms);
int liquid_modem_is_qam(modulation_scheme _ms);
int liquid_modem_is_apsk(modulation_scheme _ms);
// useful functions
// counts the number of different bits between two symbols
unsigned int count_bit_errors(unsigned int _s1, unsigned int _s2);
// counts the number of different bits between two arrays of symbols
// _msg0 : original message [size: _n x 1]
// _msg1 : copy of original message [size: _n x 1]
// _n : message size
unsigned int count_bit_errors_array(unsigned char * _msg0,
unsigned char * _msg1,
unsigned int _n);
// converts binary-coded decimal (BCD) to gray, ensuring successive values
// differ by exactly one bit
unsigned int gray_encode(unsigned int symbol_in);
// converts a gray-encoded symbol to binary-coded decimal (BCD)
unsigned int gray_decode(unsigned int symbol_in);
// pack soft bits into symbol
// _soft_bits : soft input bits [size: _bps x 1]
// _bps : bits per symbol
// _sym_out : output symbol, value in [0,2^_bps)
void liquid_pack_soft_bits(unsigned char * _soft_bits,
unsigned int _bps,
unsigned int * _sym_out);
// unpack soft bits into symbol
// _sym_in : input symbol, value in [0,2^_bps)
// _bps : bits per symbol
// _soft_bits : soft output bits [size: _bps x 1]
void liquid_unpack_soft_bits(unsigned int _sym_in,
unsigned int _bps,
unsigned char * _soft_bits);
//
// Linear modem
//
#define LIQUID_MODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(modem,name)
// Macro : MODEM
// MODEM : name-mangling macro
// T : primitive data type
// TC : primitive data type (complex)
#define LIQUID_MODEM_DEFINE_API(MODEM,T,TC) \
\
/* define struct pointer */ \
typedef struct MODEM(_s) * MODEM(); \
\
/* create digital modem object, allocating memory as necessary */ \
MODEM() MODEM(_create)(modulation_scheme _scheme); \
\
/* create arbitrary digital modem object */ \
MODEM() MODEM(_create_arbitrary)(TC * _table, unsigned int _M); \
\
/* recreate modulation scheme, re-allocating memory as necessary */ \
MODEM() MODEM(_recreate)(MODEM() _q, \
modulation_scheme _scheme); \
\
void MODEM(_destroy)(MODEM() _q); \
void MODEM(_print)( MODEM() _q); \
void MODEM(_reset)( MODEM() _q); \
\
/* generate random symbol */ \
unsigned int MODEM(_gen_rand_sym)(MODEM() _q); \
\
/* Accessor functions */ \
unsigned int MODEM(_get_bps)(MODEM() _q); \
\
/* generic modulate function; simply queries modem scheme */ \
/* and calls appropriate subroutine */ \
/* _q : modem object */ \
/* _s : input symbol */ \
/* _x : output sample */ \
void MODEM(_modulate)(MODEM() _q, \
unsigned int _s, \
TC *_y); \
\
/* generic hard-decision demodulation function */ \
/* _q : modem object */ \
/* _x : input sample */ \
/* _s : output symbol */ \
void MODEM(_demodulate)(MODEM() _q, \
TC _x, \
unsigned int * _s); \
\
/* generic soft-decision demodulation function */ \
/* _q : modem object */ \
/* _x : input sample */ \
/* _s : output hard symbol */ \
/* _soft_bits : output soft bits */ \
void MODEM(_demodulate_soft)(MODEM() _q, \
TC _x, \
unsigned int * _s, \
unsigned char * _soft_bits); \
\
/* get demodulator's estimated transmit sample */ \
void MODEM(_get_demodulator_sample)(MODEM() _q, \
TC * _x_hat); \
\
/* get demodulator phase error */ \
float MODEM(_get_demodulator_phase_error)(MODEM() _q); \
\
/* get demodulator error vector magnitude */ \
float MODEM(_get_demodulator_evm)(MODEM() _q); \
// define modem APIs
LIQUID_MODEM_DEFINE_API(LIQUID_MODEM_MANGLE_FLOAT,float,liquid_float_complex)
//
// continuous-phase modulation
//
// gmskmod : GMSK modulator
typedef struct gmskmod_s * gmskmod;
// create gmskmod object
// _k : samples/symbol
// _m : filter delay (symbols)
// _BT : excess bandwidth factor
gmskmod gmskmod_create(unsigned int _k,
unsigned int _m,
float _BT);
void gmskmod_destroy(gmskmod _q);
void gmskmod_print(gmskmod _q);
void gmskmod_reset(gmskmod _q);
void gmskmod_modulate(gmskmod _q,
unsigned int _sym,
liquid_float_complex * _y);
// gmskdem : GMSK demodulator
typedef struct gmskdem_s * gmskdem;
// create gmskdem object
// _k : samples/symbol
// _m : filter delay (symbols)
// _BT : excess bandwidth factor
gmskdem gmskdem_create(unsigned int _k,
unsigned int _m,
float _BT);
void gmskdem_destroy(gmskdem _q);
void gmskdem_print(gmskdem _q);
void gmskdem_reset(gmskdem _q);
void gmskdem_set_eq_bw(gmskdem _q, float _bw);
void gmskdem_demodulate(gmskdem _q,
liquid_float_complex * _y,
unsigned int * _sym);
//
// Analog frequency modulator
//
#define LIQUID_FREQMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(freqmod,name)
// Macro : FREQMOD (analog frequency modulator)
// FREQMOD : name-mangling macro
// T : primitive data type
// TC : primitive data type (complex)
#define LIQUID_FREQMOD_DEFINE_API(FREQMOD,T,TC) \
\
/* define struct pointer */ \
typedef struct FREQMOD(_s) * FREQMOD(); \
\
/* create freqmod object (frequency modulator) */ \
/* _kf : modulation factor */ \
FREQMOD() FREQMOD(_create)(float _kf); \
\
/* destroy freqmod object */ \
void FREQMOD(_destroy)(FREQMOD() _q); \
\
/* print freqmod object internals */ \
void FREQMOD(_print)(FREQMOD() _q); \
\
/* reset state */ \
void FREQMOD(_reset)(FREQMOD() _q); \
\
/* modulate single sample */ \
/* _q : frequency modulator object */ \
/* _m : message signal m(t) */ \
/* _s : complex baseband signal s(t) */ \
void FREQMOD(_modulate)(FREQMOD() _q, \
T _m, \
TC * _s); \
\
/* modulate block of samples */ \
/* _q : frequency modulator object */ \
/* _m : message signal m(t), [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _s : complex baseband signal s(t) [size: _n x 1] */ \
void FREQMOD(_modulate_block)(FREQMOD() _q, \
T * _m, \
unsigned int _n, \
TC * _s); \
// define freqmod APIs
LIQUID_FREQMOD_DEFINE_API(LIQUID_FREQMOD_MANGLE_FLOAT,float,liquid_float_complex)
//
// Analog frequency demodulator
//
#define LIQUID_FREQDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(freqdem,name)
// Macro : FREQDEM (analog frequency modulator)
// FREQDEM : name-mangling macro
// T : primitive data type
// TC : primitive data type (complex)
#define LIQUID_FREQDEM_DEFINE_API(FREQDEM,T,TC) \
\
/* define struct pointer */ \
typedef struct FREQDEM(_s) * FREQDEM(); \
\
/* create freqdem object (frequency modulator) */ \
/* _kf : modulation factor */ \
FREQDEM() FREQDEM(_create)(float _kf); \
\
/* destroy freqdem object */ \
void FREQDEM(_destroy)(FREQDEM() _q); \
\
/* print freqdem object internals */ \
void FREQDEM(_print)(FREQDEM() _q); \
\
/* reset state */ \
void FREQDEM(_reset)(FREQDEM() _q); \
\
/* demodulate sample */ \
/* _q : frequency modulator object */ \
/* _r : received signal r(t) */ \
/* _m : output message signal m(t) */ \
void FREQDEM(_demodulate)(FREQDEM() _q, \
TC _r, \
T * _m); \
\
/* demodulate block of samples */ \
/* _q : frequency demodulator object */ \
/* _r : received signal r(t) [size: _n x 1] */ \
/* _n : number of input, output samples */ \
/* _m : message signal m(t), [size: _n x 1] */ \
void FREQDEM(_demodulate_block)(FREQDEM() _q, \
TC * _r, \
unsigned int _n, \
T * _m); \
// define freqdem APIs
LIQUID_FREQDEM_DEFINE_API(LIQUID_FREQDEM_MANGLE_FLOAT,float,liquid_float_complex)
// amplitude modulation types
typedef enum {
LIQUID_AMPMODEM_DSB=0, // double side-band
LIQUID_AMPMODEM_USB, // single side-band (upper)
LIQUID_AMPMODEM_LSB // single side-band (lower)
} liquid_ampmodem_type;
typedef struct ampmodem_s * ampmodem;
// create ampmodem object
// _m : modulation index
// _fc : carrier frequency, range: [-0.5,0.5]
// _type : AM type (e.g. LIQUID_AMPMODEM_DSB)
// _suppressed_carrier : carrier suppression flag
ampmodem ampmodem_create(float _m,
float _fc,
liquid_ampmodem_type _type,
int _suppressed_carrier);
// destroy ampmodem object
void ampmodem_destroy(ampmodem _fm);
// print ampmodem object internals
void ampmodem_print(ampmodem _fm);
// reset ampmodem object state
void ampmodem_reset(ampmodem _fm);
// modulate sample
void ampmodem_modulate(ampmodem _fm,
float _x,
liquid_float_complex *_y);
// demodulate sample
void ampmodem_demodulate(ampmodem _fm,
liquid_float_complex _y,
float *_x);
//
// MODULE : multichannel
//
#define FIRPFBCH_NYQUIST 0
#define FIRPFBCH_ROOTNYQUIST 1
#define LIQUID_ANALYZER 0
#define LIQUID_SYNTHESIZER 1
//
// Finite impulse response polyphase filterbank channelizer
//
#define FIRPFBCH_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch_crcf,name)
#define FIRPFBCH_MANGLE_CCCF(name) LIQUID_CONCAT(firpfbch_cccf,name)
// Macro:
// FIRPFBCH : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH,TO,TC,TI) \
typedef struct FIRPFBCH(_s) * FIRPFBCH(); \
\
/* create finite impulse response polyphase filter-bank */ \
/* channelizer object from external coefficients */ \
/* _type : channelizer type, e.g. LIQUID_ANALYZER */ \
/* _M : number of channels */ \
/* _p : number of coefficients for each channel */ \
/* _h : coefficients [size: _M*_p x 1] */ \
FIRPFBCH() FIRPFBCH(_create)(int _type, \
unsigned int _M, \
unsigned int _p, \
TC * _h); \
\
/* create FIR polyphase filterbank channelizer object with */ \
/* prototype filter based on windowed Kaiser design */ \
/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \
/* _M : number of channels */ \
/* _m : filter delay (symbols) */ \
/* _As : stop-band attentuation [dB] */ \
FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, \
unsigned int _M, \
unsigned int _m, \
float _As); \
\
/* create FIR polyphase filterbank channelizer object with */ \
/* prototype root-Nyquist filter */ \
/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \
/* _M : number of channels */ \
/* _m : filter delay (symbols) */ \
/* _beta : filter excess bandwidth factor, in [0,1] */ \
/* _ftype : filter prototype (rrcos, rkaiser, etc.) */ \
FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, \
unsigned int _M, \
unsigned int _m, \
float _beta, \
int _ftype); \
\
/* destroy firpfbch object */ \
void FIRPFBCH(_destroy)(FIRPFBCH() _q); \
\
/* clear/reset firpfbch internal state */ \
void FIRPFBCH(_reset)(FIRPFBCH() _q); \
\
/* print firpfbch internal parameters to stdout */ \
void FIRPFBCH(_print)(FIRPFBCH() _q); \
\
/* execute filterbank as synthesizer on block of samples */ \
/* _q : filterbank channelizer object */ \
/* _x : channelized input, [size: num_channels x 1] */ \
/* _y : output time series, [size: num_channels x 1] */ \
void FIRPFBCH(_synthesizer_execute)(FIRPFBCH() _q, \
TI * _x, \
TO * _y); \
\
/* execute filterbank as analyzer on block of samples */ \
/* _q : filterbank channelizer object */ \
/* _x : input time series, [size: num_channels x 1] */ \
/* _y : channelized output, [size: num_channels x 1] */ \
void FIRPFBCH(_analyzer_execute)(FIRPFBCH() _q, \
TI * _x, \
TO * _y); \
LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH_MANGLE_CCCF,
liquid_float_complex,
liquid_float_complex,
liquid_float_complex)
//
// Finite impulse response polyphase filterbank channelizer
// with output rate 2 Fs / M
//
#define FIRPFBCH2_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch2_crcf,name)
// Macro:
// FIRPFBCH2 : name-mangling macro
// TO : output data type
// TC : coefficients data type
// TI : input data type
#define LIQUID_FIRPFBCH2_DEFINE_API(FIRPFBCH2,TO,TC,TI) \
typedef struct FIRPFBCH2(_s) * FIRPFBCH2(); \
\
/* create firpfbch2 object */ \
/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \
/* _M : number of channels (must be even) */ \
/* _m : prototype filter semi-lenth, length=2*M*m */ \
/* _h : prototype filter coefficient array */ \
FIRPFBCH2() FIRPFBCH2(_create)(int _type, \
unsigned int _M, \
unsigned int _m, \
TC * _h); \
\
/* create firpfbch2 object using Kaiser window prototype */ \
/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \
/* _M : number of channels (must be even) */ \
/* _m : prototype filter semi-lenth, length=2*M*m+1 */ \
/* _As : filter stop-band attenuation [dB] */ \
FIRPFBCH2() FIRPFBCH2(_create_kaiser)(int _type, \
unsigned int _M, \
unsigned int _m, \
float _As); \
\
/* destroy firpfbch2 object, freeing internal memory */ \
void FIRPFBCH2(_destroy)(FIRPFBCH2() _q); \
\
/* reset firpfbch2 object internals */ \
void FIRPFBCH2(_reset)(FIRPFBCH2() _q); \
\
/* print firpfbch2 object internals */ \
void FIRPFBCH2(_print)(FIRPFBCH2() _q); \
\
/* execute filterbank channelizer */ \
/* LIQUID_ANALYZER: input: M/2, output: M */ \
/* LIQUID_SYNTHESIZER: input: M, output: M/2 */ \
/* _x : channelizer input */ \
/* _y : channelizer output */ \
void FIRPFBCH2(_execute)(FIRPFBCH2() _q, \
TI * _x, \
TO * _y); \
LIQUID_FIRPFBCH2_DEFINE_API(FIRPFBCH2_MANGLE_CRCF,
liquid_float_complex,
float,
liquid_float_complex)
#define OFDMFRAME_SCTYPE_NULL 0
#define OFDMFRAME_SCTYPE_PILOT 1
#define OFDMFRAME_SCTYPE_DATA 2
// initialize default subcarrier allocation
// _M : number of subcarriers
// _p : output subcarrier allocation array, [size: _M x 1]
void ofdmframe_init_default_sctype(unsigned int _M,
unsigned char * _p);
// validate subcarrier type (count number of null, pilot, and data
// subcarriers in the allocation)
// _p : subcarrier allocation array, [size: _M x 1]
// _M : number of subcarriers
// _M_null : output number of null subcarriers
// _M_pilot : output number of pilot subcarriers
// _M_data : output number of data subcarriers
void ofdmframe_validate_sctype(unsigned char * _p,
unsigned int _M,
unsigned int * _M_null,
unsigned int * _M_pilot,
unsigned int * _M_data);
// print subcarrier allocation to screen
// _p : output subcarrier allocation array, [size: _M x 1]
// _M : number of subcarriers
void ofdmframe_print_sctype(unsigned char * _p,
unsigned int _M);
//
// OFDM frame (symbol) generator
//
typedef struct ofdmframegen_s * ofdmframegen;
// create OFDM framing generator object
// _M : number of subcarriers, >10 typical
// _cp_len : cyclic prefix length
// _taper_len : taper length (OFDM symbol overlap)
// _p : subcarrier allocation (null, pilot, data), [size: _M x 1]
ofdmframegen ofdmframegen_create(unsigned int _M,
unsigned int _cp_len,
unsigned int _taper_len,
unsigned char * _p);
void ofdmframegen_destroy(ofdmframegen _q);
void ofdmframegen_print(ofdmframegen _q);
void ofdmframegen_reset(ofdmframegen _q);
// write first S0 symbol
void ofdmframegen_write_S0a(ofdmframegen _q,
liquid_float_complex *_y);
// write second S0 symbol
void ofdmframegen_write_S0b(ofdmframegen _q,
liquid_float_complex *_y);
// write S1 symbol
void ofdmframegen_write_S1(ofdmframegen _q,
liquid_float_complex *_y);
// write data symbol
void ofdmframegen_writesymbol(ofdmframegen _q,
liquid_float_complex * _x,
liquid_float_complex *_y);
// write tail
void ofdmframegen_writetail(ofdmframegen _q,
liquid_float_complex * _x);
//
// OFDM frame (symbol) synchronizer
//
typedef int (*ofdmframesync_callback)(liquid_float_complex * _y,
unsigned char * _p,
unsigned int _M,
void * _userdata);
typedef struct ofdmframesync_s * ofdmframesync;
// create OFDM framing synchronizer object
// _M : number of subcarriers, >10 typical
// _cp_len : cyclic prefix length
// _taper_len : taper length (OFDM symbol overlap)
// _p : subcarrier allocation (null, pilot, data), [size: _M x 1]
// _callback : user-defined callback function
// _userdata : user-defined data pointer
ofdmframesync ofdmframesync_create(unsigned int _M,
unsigned int _cp_len,
unsigned int _taper_len,
unsigned char * _p,
ofdmframesync_callback _callback,
void * _userdata);
void ofdmframesync_destroy(ofdmframesync _q);
void ofdmframesync_print(ofdmframesync _q);
void ofdmframesync_reset(ofdmframesync _q);
void ofdmframesync_execute(ofdmframesync _q,
liquid_float_complex * _x,
unsigned int _n);
// query methods
float ofdmframesync_get_rssi(ofdmframesync _q); // received signal strength indication
float ofdmframesync_get_cfo(ofdmframesync _q); // carrier offset estimate
// debugging
void ofdmframesync_debug_enable(ofdmframesync _q);
void ofdmframesync_debug_disable(ofdmframesync _q);
void ofdmframesync_debug_print(ofdmframesync _q, const char * _filename);
//
// MODULE : nco (numerically-controlled oscillator)
//
// oscillator type
// LIQUID_NCO : numerically-controlled oscillator (fast)
// LIQUID_VCO : "voltage"-controlled oscillator (precise)
typedef enum {
LIQUID_NCO=0,
LIQUID_VCO
} liquid_ncotype;
#define NCO_MANGLE_FLOAT(name) LIQUID_CONCAT(nco_crcf, name)
// large macro
// NCO : name-mangling macro
// T : primitive data type
// TC : input/output data type
#define LIQUID_NCO_DEFINE_API(NCO,T,TC) \
typedef struct NCO(_s) * NCO(); \
\
NCO() NCO(_create)(liquid_ncotype _type); \
void NCO(_destroy)(NCO() _q); \
void NCO(_print)(NCO() _q); \
\
/* set phase/frequency to zero, reset pll filter */ \
void NCO(_reset)(NCO() _q); \
\
/* get/set/adjust internal frequency/phase */ \
T NCO(_get_frequency)( NCO() _q); \
void NCO(_set_frequency)( NCO() _q, T _f); \
void NCO(_adjust_frequency)(NCO() _q, T _df); \
T NCO(_get_phase)( NCO() _q); \
void NCO(_set_phase)( NCO() _q, T _phi); \
void NCO(_adjust_phase)( NCO() _q, T _dphi); \
\
/* increment phase by internal phase step (frequency) */ \
void NCO(_step)(NCO() _q); \
\
/* compute trigonometric functions */ \
T NCO(_sin)(NCO() _q); \
T NCO(_cos)(NCO() _q); \
void NCO(_sincos)(NCO() _q, T* _s, T* _c); \
void NCO(_cexpf)(NCO() _q, TC * _y); \
\
/* pll : phase-locked loop */ \
void NCO(_pll_set_bandwidth)(NCO() _q, T _b); \
void NCO(_pll_step)(NCO() _q, T _dphi); \
\
/* Rotate input sample up by NCO angle (no stepping) */ \
void NCO(_mix_up)(NCO() _q, TC _x, TC *_y); \
\
/* Rotate input sample down by NCO angle (no stepping) */ \
void NCO(_mix_down)(NCO() _q, TC _x, TC *_y); \
\
/* Rotate input vector up by NCO angle (stepping) */ \
/* _q : nco object */ \
/* _x : input vector [size: _N x 1] */ \
/* _y : output vector [size: _N x 1] */ \
/* _N : vector size */ \
void NCO(_mix_block_up)(NCO() _q, \
TC *_x, \
TC *_y, \
unsigned int _N); \
\
/* Rotate input vector down by NCO angle (stepping) */ \
/* _q : nco object */ \
/* _x : input vector [size: _N x 1] */ \
/* _y : output vector [size: _N x 1] */ \
/* _N : vector size */ \
void NCO(_mix_block_down)(NCO() _q, \
TC *_x, \
TC *_y, \
unsigned int _N); \
// Define nco APIs
LIQUID_NCO_DEFINE_API(NCO_MANGLE_FLOAT, float, liquid_float_complex)
// nco utilities
// unwrap phase of array (basic)
void liquid_unwrap_phase(float * _theta, unsigned int _n);
// unwrap phase of array (advanced)
void liquid_unwrap_phase2(float * _theta, unsigned int _n);
//
// MODULE : optimization
//
// utility function pointer definition
typedef float (*utility_function)(void * _userdata,
float * _v,
unsigned int _n);
// n-dimensional Rosenbrock utility function (minimum at _v = {1,1,1...}
// _userdata : user-defined data structure (convenience)
// _v : input vector [size: _n x 1]
// _n : input vector size
float liquid_rosenbrock(void * _userdata,
float * _v,
unsigned int _n);
// n-dimensional inverse Gauss utility function (minimum at _v = {0,0,0...}
// _userdata : user-defined data structure (convenience)
// _v : input vector [size: _n x 1]
// _n : input vector size
float liquid_invgauss(void * _userdata,
float * _v,
unsigned int _n);
// n-dimensional multimodal utility function (minimum at _v = {0,0,0...}
// _userdata : user-defined data structure (convenience)
// _v : input vector [size: _n x 1]
// _n : input vector size
float liquid_multimodal(void * _userdata,
float * _v,
unsigned int _n);
// n-dimensional spiral utility function (minimum at _v = {0,0,0...}
// _userdata : user-defined data structure (convenience)
// _v : input vector [size: _n x 1]
// _n : input vector size
float liquid_spiral(void * _userdata,
float * _v,
unsigned int _n);
//
// Gradient search
//
#define LIQUID_OPTIM_MINIMIZE (0)
#define LIQUID_OPTIM_MAXIMIZE (1)
typedef struct gradsearch_s * gradsearch;
// Create a gradient search object
// _userdata : user data object pointer
// _v : array of parameters to optimize
// _num_parameters : array length (number of parameters to optimize)
// _u : utility function pointer
// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE)
gradsearch gradsearch_create(void * _userdata,
float * _v,
unsigned int _num_parameters,
utility_function _utility,
int _direction);
// Destroy a gradsearch object
void gradsearch_destroy(gradsearch _q);
// Prints current status of search
void gradsearch_print(gradsearch _q);
// Iterate once
float gradsearch_step(gradsearch _q);
// Execute the search
float gradsearch_execute(gradsearch _q,
unsigned int _max_iterations,
float _target_utility);
// quasi-Newton search
typedef struct qnsearch_s * qnsearch;
// Create a simple qnsearch object; parameters are specified internally
// _userdata : userdata
// _v : array of parameters to optimize
// _num_parameters : array length
// _get_utility : utility function pointer
// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE)
qnsearch qnsearch_create(void * _userdata,
float * _v,
unsigned int _num_parameters,
utility_function _u,
int _direction);
// Destroy a qnsearch object
void qnsearch_destroy(qnsearch _g);
// Prints current status of search
void qnsearch_print(qnsearch _g);
// Resets internal state
void qnsearch_reset(qnsearch _g);
// Iterate once
void qnsearch_step(qnsearch _g);
// Execute the search
float qnsearch_execute(qnsearch _g,
unsigned int _max_iterations,
float _target_utility);
//
// chromosome (for genetic algorithm search)
//
typedef struct chromosome_s * chromosome;
// create a chromosome object, variable bits/trait
chromosome chromosome_create(unsigned int * _bits_per_trait,
unsigned int _num_traits);
// create a chromosome object, all traits same resolution
chromosome chromosome_create_basic(unsigned int _num_traits,
unsigned int _bits_per_trait);
// create a chromosome object, cloning a parent
chromosome chromosome_create_clone(chromosome _parent);
// copy existing chromosomes' internal traits (all other internal
// parameters must be equal)
void chromosome_copy(chromosome _parent, chromosome _child);
// Destroy a chromosome object
void chromosome_destroy(chromosome _c);
// get number of traits in chromosome
unsigned int chromosome_get_num_traits(chromosome _c);
// Print chromosome values to screen (binary representation)
void chromosome_print(chromosome _c);
// Print chromosome values to screen (floating-point representation)
void chromosome_printf(chromosome _c);
// clear chromosome (set traits to zero)
void chromosome_clear(chromosome _c);
// initialize chromosome on integer values
void chromosome_init(chromosome _c,
unsigned int * _v);
// initialize chromosome on floating-point values
void chromosome_initf(chromosome _c,
float * _v);
// Mutates chromosome _c at _index
void chromosome_mutate(chromosome _c, unsigned int _index);
// Resulting chromosome _c is a crossover of parents _p1 and _p2 at _threshold
void chromosome_crossover(chromosome _p1,
chromosome _p2,
chromosome _c,
unsigned int _threshold);
// Initializes chromosome to random value
void chromosome_init_random(chromosome _c);
// Returns integer representation of chromosome
unsigned int chromosome_value(chromosome _c,
unsigned int _index);
// Returns floating-point representation of chromosome
float chromosome_valuef(chromosome _c,
unsigned int _index);
//
// genetic algorithm search
//
typedef struct gasearch_s * gasearch;
typedef float (*gasearch_utility)(void * _userdata, chromosome _c);
// Create a simple gasearch object; parameters are specified internally
// _utility : chromosome fitness utility function
// _userdata : user data, void pointer passed to _get_utility() callback
// _parent : initial population parent chromosome, governs precision, etc.
// _minmax : search direction
gasearch gasearch_create(gasearch_utility _u,
void * _userdata,
chromosome _parent,
int _minmax);
// Create a gasearch object, specifying search parameters
// _utility : chromosome fitness utility function
// _userdata : user data, void pointer passed to _get_utility() callback
// _parent : initial population parent chromosome, governs precision, etc.
// _minmax : search direction
// _population_size : number of chromosomes in population
// _mutation_rate : probability of mutating chromosomes
gasearch gasearch_create_advanced(gasearch_utility _utility,
void * _userdata,
chromosome _parent,
int _minmax,
unsigned int _population_size,
float _mutation_rate);
// Destroy a gasearch object
void gasearch_destroy(gasearch _q);
// print search parameter internals
void gasearch_print(gasearch _q);
// set mutation rate
void gasearch_set_mutation_rate(gasearch _q,
float _mutation_rate);
// set population/selection size
// _q : ga search object
// _population_size : new population size (number of chromosomes)
// _selection_size : selection size (number of parents for new generation)
void gasearch_set_population_size(gasearch _q,
unsigned int _population_size,
unsigned int _selection_size);
// Execute the search
// _q : ga search object
// _max_iterations : maximum number of iterations to run before bailing
// _target_utility : target utility
float gasearch_run(gasearch _q,
unsigned int _max_iterations,
float _target_utility);
// iterate over one evolution of the search algorithm
void gasearch_evolve(gasearch _q);
// get optimal chromosome
// _q : ga search object
// _c : output optimal chromosome
// _utility_opt : fitness of _c
void gasearch_getopt(gasearch _q,
chromosome _c,
float * _utility_opt);
//
// MODULE : quantization
//
float compress_mulaw(float _x, float _mu);
float expand_mulaw(float _x, float _mu);
void compress_cf_mulaw(liquid_float_complex _x, float _mu, liquid_float_complex * _y);
void expand_cf_mulaw(liquid_float_complex _y, float _mu, liquid_float_complex * _x);
//float compress_alaw(float _x, float _a);
//float expand_alaw(float _x, float _a);
// inline quantizer: 'analog' signal in [-1, 1]
unsigned int quantize_adc(float _x, unsigned int _num_bits);
float quantize_dac(unsigned int _s, unsigned int _num_bits);
// structured quantizer
typedef enum {
LIQUID_COMPANDER_NONE=0,
LIQUID_COMPANDER_LINEAR,
LIQUID_COMPANDER_MULAW,
LIQUID_COMPANDER_ALAW
} liquid_compander_type;
#define QUANTIZER_MANGLE_FLOAT(name) LIQUID_CONCAT(quantizerf, name)
#define QUANTIZER_MANGLE_CFLOAT(name) LIQUID_CONCAT(quantizercf, name)
// large macro
// QUANTIZER : name-mangling macro
// T : data type
#define LIQUID_QUANTIZER_DEFINE_API(QUANTIZER,T) \
typedef struct QUANTIZER(_s) * QUANTIZER(); \
QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, \
float _range, \
unsigned int _num_bits); \
void QUANTIZER(_destroy)(QUANTIZER() _q); \
void QUANTIZER(_print)(QUANTIZER() _q); \
void QUANTIZER(_execute_adc)(QUANTIZER() _q, \
T _x, \
unsigned int * _sample); \
void QUANTIZER(_execute_dac)(QUANTIZER() _q, \
unsigned int _sample, \
T * _x);
LIQUID_QUANTIZER_DEFINE_API(QUANTIZER_MANGLE_FLOAT, float)
LIQUID_QUANTIZER_DEFINE_API(QUANTIZER_MANGLE_CFLOAT, liquid_float_complex)
//
// MODULE : random (number generators)
//
// Uniform random number generator, (0,1]
float randf();
float randf_pdf(float _x);
float randf_cdf(float _x);
// Gauss random number generator, N(0,1)
// f(x) = 1/sqrt(2*pi*sigma^2) * exp{-(x-eta)^2/(2*sigma^2)}
//
// where
// eta = mean
// sigma = standard deviation
//
float randnf();
void awgn(float *_x, float _nstd);
void crandnf(liquid_float_complex *_y);
void cawgn(liquid_float_complex *_x, float _nstd);
float randnf_pdf(float _x, float _eta, float _sig);
float randnf_cdf(float _x, float _eta, float _sig);
// Exponential
// f(x) = lambda exp{ -lambda x }
// where
// lambda = spread parameter, lambda > 0
// x >= 0
float randexpf(float _lambda);
float randexpf_pdf(float _x, float _lambda);
float randexpf_cdf(float _x, float _lambda);
// Weibull
// f(x) = (a/b) (x/b)^(a-1) exp{ -(x/b)^a }
// where
// a = alpha : shape parameter
// b = beta : scaling parameter
// g = gamma : location (threshold) parameter
//
float randweibf(float _alpha, float _beta, float _gamma);
float randweibf_pdf(float _x, float _a, float _b, float _g);
float randweibf_cdf(float _x, float _a, float _b, float _g);
// Gamma
// x^(a-1) exp(-x/b)
// f(x) = -------------------
// Gamma(a) b^a
// where
// a = alpha : shape parameter, a > 0
// b = beta : scale parameter, b > 0
// Gamma(z) = regular gamma function
// x >= 0
float randgammaf(float _alpha, float _beta);
float randgammaf_pdf(float _x, float _alpha, float _beta);
float randgammaf_cdf(float _x, float _alpha, float _beta);
// Nakagami-m
// f(x) = (2/Gamma(m)) (m/omega)^m x^(2m-1) exp{-(m/omega)x^2}
// where
// m : shape parameter, m >= 0.5
// omega : spread parameter, omega > 0
// Gamma(z): regular complete gamma function
// x >= 0
float randnakmf(float _m, float _omega);
float randnakmf_pdf(float _x, float _m, float _omega);
float randnakmf_cdf(float _x, float _m, float _omega);
// Rice-K
// f(x) = (x/sigma^2) exp{ -(x^2+s^2)/(2sigma^2) } I0( x s / sigma^2 )
// where
// s = sqrt( omega*K/(K+1) )
// sigma = sqrt(0.5 omega/(K+1))
// and
// K = shape parameter
// omega = spread parameter
// I0 = modified Bessel function of the first kind
// x >= 0
float randricekf(float _K, float _omega);
float randricekf_cdf(float _x, float _K, float _omega);
float randricekf_pdf(float _x, float _K, float _omega);
// Data scrambler : whiten data sequence
void scramble_data(unsigned char * _x, unsigned int _len);
void unscramble_data(unsigned char * _x, unsigned int _len);
void unscramble_data_soft(unsigned char * _x, unsigned int _len);
//
// MODULE : sequence
//
// Binary sequence (generic)
typedef struct bsequence_s * bsequence;
// Create a binary sequence of a specific length (number of bits)
bsequence bsequence_create(unsigned int num_bits);
// Free memory in a binary sequence
void bsequence_destroy(bsequence _bs);
// Clear binary sequence (set to 0's)
void bsequence_clear(bsequence _bs);
// initialize sequence on external array
void bsequence_init(bsequence _bs,
unsigned char * _v);
// Print sequence to the screen
void bsequence_print(bsequence _bs);
// Push bit into to back of a binary sequence
void bsequence_push(bsequence _bs,
unsigned int _bit);
// circular shift (left)
void bsequence_circshift(bsequence _bs);
// Correlate two binary sequences together
int bsequence_correlate(bsequence _bs1, bsequence _bs2);
// compute the binary addition of two bit sequences
void bsequence_add(bsequence _bs1, bsequence _bs2, bsequence _bs3);
// compute the binary multiplication of two bit sequences
void bsequence_mul(bsequence _bs1, bsequence _bs2, bsequence _bs3);
// accumulate the 1's in a binary sequence
unsigned int bsequence_accumulate(bsequence _bs);
// accessor functions
unsigned int bsequence_get_length(bsequence _bs);
unsigned int bsequence_index(bsequence _bs, unsigned int _i);
// Complementary codes
// intialize two sequences to complementary codes. sequences must
// be of length at least 8 and a power of 2 (e.g. 8, 16, 32, 64,...)
// _a : sequence 'a' (bsequence object)
// _b : sequence 'b' (bsequence object)
void bsequence_create_ccodes(bsequence _a,
bsequence _b);
// M-Sequence
#define LIQUID_MAX_MSEQUENCE_LENGTH 32767
// default m-sequence generators: g (hex) m n g (oct) g (binary)
#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0007 // 2 3 7 111
#define LIQUID_MSEQUENCE_GENPOLY_M3 0x000B // 3 7 13 1011
#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0013 // 4 15 23 10011
#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0025 // 5 31 45 100101
#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0043 // 6 63 103 1000011
#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0089 // 7 127 211 10001001
#define LIQUID_MSEQUENCE_GENPOLY_M8 0x011D // 8 255 435 100101101
#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0211 // 9 511 1021 1000010001
#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0409 // 10 1023 2011 10000001001
#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0805 // 11 2047 4005 100000000101
#define LIQUID_MSEQUENCE_GENPOLY_M12 0x1053 // 12 4095 10123 1000001010011
#define LIQUID_MSEQUENCE_GENPOLY_M13 0x201b // 13 8191 20033 10000000011011
#define LIQUID_MSEQUENCE_GENPOLY_M14 0x402b // 14 16383 40053 100000000101011
#define LIQUID_MSEQUENCE_GENPOLY_M15 0x8003 // 15 32767 100003 1000000000000011
typedef struct msequence_s * msequence;
// create a maximal-length sequence (m-sequence) object with
// an internal shift register length of _m bits.
// _m : generator polynomial length, sequence length is (2^m)-1
// _g : generator polynomial, starting with most-significant bit
// _a : initial shift register state, default: 000...001
msequence msequence_create(unsigned int _m,
unsigned int _g,
unsigned int _a);
// create a maximal-length sequence (m-sequence) object from a generator polynomial
msequence msequence_create_genpoly(unsigned int _g);
// creates a default maximal-length sequence
msequence msequence_create_default(unsigned int _m);
// destroy an msequence object, freeing all internal memory
void msequence_destroy(msequence _m);
// prints the sequence's internal state to the screen
void msequence_print(msequence _m);
// advance msequence on shift register, returning output bit
unsigned int msequence_advance(msequence _ms);
// generate pseudo-random symbol from shift register by
// advancing _bps bits and returning compacted symbol
// _ms : m-sequence object
// _bps : bits per symbol of output
unsigned int msequence_generate_symbol(msequence _ms,
unsigned int _bps);
// reset msequence shift register to original state, typically '1'
void msequence_reset(msequence _ms);
// initialize a bsequence object on an msequence object
// _bs : bsequence object
// _ms : msequence object
void bsequence_init_msequence(bsequence _bs,
msequence _ms);
// get the length of the sequence
unsigned int msequence_get_length(msequence _ms);
// get the internal state of the sequence
unsigned int msequence_get_state(msequence _ms);
// set the internal state of the sequence
void msequence_set_state(msequence _ms,
unsigned int _a);
//
// MODULE : utility
//
// pack binary array with symbol(s)
// _src : source array [size: _n x 1]
// _n : input source array length
// _k : bit index to write in _src
// _b : number of bits in input symbol
// _sym_in : input symbol
void liquid_pack_array(unsigned char * _src,
unsigned int _n,
unsigned int _k,
unsigned int _b,
unsigned char _sym_in);
// unpack symbols from binary array
// _src : source array [size: _n x 1]
// _n : input source array length
// _k : bit index to write in _src
// _b : number of bits in output symbol
// _sym_out : output symbol
void liquid_unpack_array(unsigned char * _src,
unsigned int _n,
unsigned int _k,
unsigned int _b,
unsigned char * _sym_out);
// pack one-bit symbols into bytes (8-bit symbols)
// _sym_in : input symbols array [size: _sym_in_len x 1]
// _sym_in_len : number of input symbols
// _sym_out : output symbols
// _sym_out_len : number of bytes allocated to output symbols array
// _num_written : number of output symbols actually written
void liquid_pack_bytes(unsigned char * _sym_in,
unsigned int _sym_in_len,
unsigned char * _sym_out,
unsigned int _sym_out_len,
unsigned int * _num_written);
// unpack 8-bit symbols (full bytes) into one-bit symbols
// _sym_in : input symbols array [size: _sym_in_len x 1]
// _sym_in_len : number of input symbols
// _sym_out : output symbols array
// _sym_out_len : number of bytes allocated to output symbols array
// _num_written : number of output symbols actually written
void liquid_unpack_bytes(unsigned char * _sym_in,
unsigned int _sym_in_len,
unsigned char * _sym_out,
unsigned int _sym_out_len,
unsigned int * _num_written);
// repack bytes with arbitrary symbol sizes
// _sym_in : input symbols array [size: _sym_in_len x 1]
// _sym_in_bps : number of bits per input symbol
// _sym_in_len : number of input symbols
// _sym_out : output symbols array
// _sym_out_bps : number of bits per output symbol
// _sym_out_len : number of bytes allocated to output symbols array
// _num_written : number of output symbols actually written
void liquid_repack_bytes(unsigned char * _sym_in,
unsigned int _sym_in_bps,
unsigned int _sym_in_len,
unsigned char * _sym_out,
unsigned int _sym_out_bps,
unsigned int _sym_out_len,
unsigned int * _num_written);
// shift array to the left _b bits, filling in zeros
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bits to shift
void liquid_lbshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// shift array to the right _b bits, filling in zeros
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bits to shift
void liquid_rbshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// circularly shift array to the left _b bits
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bits to shift
void liquid_lbcircshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// circularly shift array to the right _b bits
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bits to shift
void liquid_rbcircshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// shift array to the left _b bytes, filling in zeros
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bytes to shift
void liquid_lshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// shift array to the right _b bytes, filling in zeros
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bytes to shift
void liquid_rshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// circular shift array to the left _b bytes
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bytes to shift
void liquid_lcircshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// circular shift array to the right _b bytes
// _src : source address [size: _n x 1]
// _n : input data array size
// _b : number of bytes to shift
void liquid_rcircshift(unsigned char * _src,
unsigned int _n,
unsigned int _b);
// Count the number of ones in an integer
unsigned int liquid_count_ones(unsigned int _x);
// count number of ones in an integer, modulo 2
unsigned int liquid_count_ones_mod2(unsigned int _x);
// compute bindary dot-product between two integers
unsigned int liquid_bdotprod(unsigned int _x,
unsigned int _y);
// Count leading zeros in an integer
unsigned int liquid_count_leading_zeros(unsigned int _x);
// Most-significant bit index
unsigned int liquid_msb_index(unsigned int _x);
// Print string of bits to stdout
void liquid_print_bitstring(unsigned int _x,
unsigned int _n);
// reverse byte, word, etc.
unsigned char liquid_reverse_byte( unsigned char _x);
unsigned int liquid_reverse_uint16(unsigned int _x);
unsigned int liquid_reverse_uint24(unsigned int _x);
unsigned int liquid_reverse_uint32(unsigned int _x);
//
// MODULE : vector
//
#define VECTOR_MANGLE_RF(name) LIQUID_CONCAT(liquid_vectorf, name)
#define VECTOR_MANGLE_CF(name) LIQUID_CONCAT(liquid_vectorcf,name)
// large macro
// VECTOR : name-mangling macro
// T : data type
// TP : data type (primitive)
#define LIQUID_VECTOR_DEFINE_API(VECTOR,T,TP) \
\
/* initialize vector with scalar: x[i] = c (scalar) */ \
void VECTOR(_init)(T _c, \
T * _x, \
unsigned int _n); \
\
/* add each element: z[i] = x[i] + y[i] */ \
void VECTOR(_add)(T * _x, \
T * _y, \
unsigned int _n, \
T * _z); \
/* add scalar to each element: y[i] = x[i] + c */ \
void VECTOR(_addscalar)(T * _x, \
unsigned int _n, \
T _c, \
T * _y); \
\
/* multiply each element: z[i] = x[i] * y[i] */ \
void VECTOR(_mul)(T * _x, \
T * _y, \
unsigned int _n, \
T * _z); \
/* multiply each element with scalar: y[i] = x[i] * c */ \
void VECTOR(_mulscalar)(T * _x, \
unsigned int _n, \
T _c, \
T * _y); \
\
/* compute complex phase rotation: x[i] = exp{j theta[i]} */ \
void VECTOR(_cexpj)(TP * _theta, \
unsigned int _n, \
T * _x); \
/* compute angle of each element: theta[i] = arg{ x[i] } */ \
void VECTOR(_carg)(T * _x, \
unsigned int _n, \
TP * _theta); \
/* compute absolute value of each element: y[i] = |x[i]| */ \
void VECTOR(_abs)(T * _x, \
unsigned int _n, \
TP * _y); \
\
/* compute sum of squares: sum{ |x|^2 } */ \
TP VECTOR(_sumsq)(T * _x, \
unsigned int _n); \
\
/* compute l-2 norm: sqrt{ sum{ |x|^2 } } */ \
TP VECTOR(_norm)(T * _x, \
unsigned int _n); \
\
/* compute l-p norm: { sum{ |x|^p } }^(1/p) */ \
TP VECTOR(_pnorm)(T * _x, \
unsigned int _n, \
TP _p); \
\
/* scale vector elements by l-2 norm: y[i] = x[i]/norm(x) */ \
void VECTOR(_normalize)(T * _x, \
unsigned int _n, \
T * _y); \
LIQUID_VECTOR_DEFINE_API(VECTOR_MANGLE_RF, float, float);
LIQUID_VECTOR_DEFINE_API(VECTOR_MANGLE_CF, liquid_float_complex, float);
//
// mixed types
//
#if 0
void liquid_vectorf_add(float * _a,
float * _b,
unsigned int _n,
float * _c);
#endif
#ifdef __cplusplus
} //extern "C"
#endif // __cplusplus
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif // __LIQUID_H__