mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-15 16:41:54 -05:00
8672 lines
471 KiB
C++
8672 lines
471 KiB
C++
/*
|
|
* Copyright (c) 2007 - 2019 Joseph Gaeddert
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#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
|
|
|
|
// common headers
|
|
#include <inttypes.h>
|
|
|
|
//
|
|
// 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.3.2"
|
|
#define LIQUID_VERSION_NUMBER 1003002
|
|
|
|
//
|
|
// 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)
|
|
//
|
|
|
|
// available squelch modes
|
|
typedef enum {
|
|
LIQUID_AGC_SQUELCH_UNKNOWN=0, // unknown/unavailable squelch mode
|
|
LIQUID_AGC_SQUELCH_ENABLED, // squelch enabled but signal not detected
|
|
LIQUID_AGC_SQUELCH_RISE, // signal first hit/exceeded threshold
|
|
LIQUID_AGC_SQUELCH_SIGNALHI, // signal level high (above threshold)
|
|
LIQUID_AGC_SQUELCH_FALL, // signal first dropped below threshold
|
|
LIQUID_AGC_SQUELCH_SIGNALLO, // signal level low (below threshold)
|
|
LIQUID_AGC_SQUELCH_TIMEOUT, // signal level low (below threshold for a certain time)
|
|
LIQUID_AGC_SQUELCH_DISABLED, // squelch not enabled
|
|
} agc_squelch_mode;
|
|
|
|
#define LIQUID_AGC_MANGLE_CRCF(name) LIQUID_CONCAT(agc_crcf, name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Automatic gain control (agc) for level correction and signal */ \
|
|
/* detection */ \
|
|
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, including received signal */ \
|
|
/* strength indication (RSSI), loop bandwidth, lock status, and squelch */ \
|
|
/* status. */ \
|
|
void AGC(_print)(AGC() _q); \
|
|
\
|
|
/* Reset internal state of agc object, including gain estimate, input */ \
|
|
/* signal level estimate, lock status, and squelch mode */ \
|
|
/* If the squelch mode is disabled, it stays disabled, but all enabled */ \
|
|
/* modes (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) resets to just */ \
|
|
/* LIQUID_AGC_SQUELCH_ENABLED. */ \
|
|
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 pointed to by _x */ \
|
|
/* and store the result in the array of the same length _y. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _x : input data array, [size: _n x 1] */ \
|
|
/* _n : number of input, output samples */ \
|
|
/* _y : output data array, [size: _n x 1] */ \
|
|
void AGC(_execute_block)(AGC() _q, \
|
|
TC * _x, \
|
|
unsigned int _n, \
|
|
TC * _y); \
|
|
\
|
|
/* Lock agc object. When locked, the agc object still makes an estimate */ \
|
|
/* of the signal level, but the gain setting is fixed and does not */ \
|
|
/* change. */ \
|
|
/* This is useful for providing coarse input signal level correction */ \
|
|
/* and quickly detecting a packet burst but not distorting signals with */ \
|
|
/* amplitude variation due to modulation. */ \
|
|
void AGC(_lock)(AGC() _q); \
|
|
\
|
|
/* Unlock agc object, and allow amplitude correction to resume. */ \
|
|
void AGC(_unlock)(AGC() _q); \
|
|
\
|
|
/* Set loop filter bandwidth: attack/release time. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _bt : bandwidth-time constant, _bt > 0 */ \
|
|
void AGC(_set_bandwidth)(AGC() _q, float _bt); \
|
|
\
|
|
/* Get the agc object's loop filter bandwidth. */ \
|
|
float AGC(_get_bandwidth)(AGC() _q); \
|
|
\
|
|
/* Get the input signal's estimated energy level, relative to unity. */ \
|
|
/* The result is a linear value. */ \
|
|
float AGC(_get_signal_level)(AGC() _q); \
|
|
\
|
|
/* Set the agc object's estimate of the input signal by specifying an */ \
|
|
/* explicit linear value. This is useful for initializing the agc */ \
|
|
/* object with a preliminary estimate of the signal level to help gain */ \
|
|
/* convergence. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _x2 : signal level of input, _x2 > 0 */ \
|
|
void AGC(_set_signal_level)(AGC() _q, \
|
|
float _x2); \
|
|
\
|
|
/* Get the agc object's estimated received signal strength indication */ \
|
|
/* (RSSI) on the input signal. */ \
|
|
/* This is similar to getting the signal level (above), but returns the */ \
|
|
/* result in dB rather than on a linear scale. */ \
|
|
float AGC(_get_rssi)(AGC() _q); \
|
|
\
|
|
/* Set the agc object's estimated received signal strength indication */ \
|
|
/* (RSSI) on the input signal by specifying an explicit value in dB. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _rssi : signal level of input [dB] */ \
|
|
void AGC(_set_rssi)(AGC() _q, float _rssi); \
|
|
\
|
|
/* Get the gain value currently being applied to the input signal */ \
|
|
/* (linear). */ \
|
|
float AGC(_get_gain)(AGC() _q); \
|
|
\
|
|
/* Set the agc object's internal gain by specifying an explicit linear */ \
|
|
/* value. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _gain : gain to apply to input signal, _gain > 0 */ \
|
|
void AGC(_set_gain)(AGC() _q, \
|
|
float _gain); \
|
|
\
|
|
/* Get the ouput scaling applied to each sample (linear). */ \
|
|
float AGC(_get_scale)(AGC() _q); \
|
|
\
|
|
/* Set the agc object's output scaling (linear). Note that this does */ \
|
|
/* affect the response of the AGC. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _gain : gain to apply to input signal, _gain > 0 */ \
|
|
void AGC(_set_scale)(AGC() _q, \
|
|
float _scale); \
|
|
\
|
|
/* Estimate signal level and initialize internal gain on an 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); \
|
|
\
|
|
/* Enable squelch mode. */ \
|
|
void AGC(_squelch_enable)(AGC() _q); \
|
|
\
|
|
/* Disable squelch mode. */ \
|
|
void AGC(_squelch_disable)(AGC() _q); \
|
|
\
|
|
/* Return flag indicating if squelch is enabled or not. */ \
|
|
int AGC(_squelch_is_enabled)(AGC() _q); \
|
|
\
|
|
/* Set threshold for enabling/disabling squelch. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _thresh : threshold for enabling squelch [dB] */ \
|
|
void AGC(_squelch_set_threshold)(AGC() _q, \
|
|
T _thresh); \
|
|
\
|
|
/* Get squelch threshold (value in dB) */ \
|
|
T AGC(_squelch_get_threshold)(AGC() _q); \
|
|
\
|
|
/* Set timeout before enabling squelch. */ \
|
|
/* _q : automatic gain control object */ \
|
|
/* _timeout : timeout before enabling squelch [samples] */ \
|
|
void AGC(_squelch_set_timeout)(AGC() _q, \
|
|
unsigned int _timeout); \
|
|
\
|
|
/* Get squelch timeout (number of samples) */ \
|
|
unsigned int AGC(_squelch_get_timeout)(AGC() _q); \
|
|
\
|
|
/* Get squelch status (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) */ \
|
|
int AGC(_squelch_get_status)(AGC() _q); \
|
|
|
|
// Define agc APIs
|
|
LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_CRCF, float, liquid_float_complex)
|
|
LIQUID_AGC_DEFINE_API(LIQUID_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 LIQUID_CBUFFER_MANGLE_FLOAT(name) LIQUID_CONCAT(cbufferf, name)
|
|
#define LIQUID_CBUFFER_MANGLE_CFLOAT(name) LIQUID_CONCAT(cbuffercf, name)
|
|
|
|
// large macro
|
|
// CBUFFER : name-mangling macro
|
|
// T : data type
|
|
#define LIQUID_CBUFFER_DEFINE_API(CBUFFER,T) \
|
|
\
|
|
/* Circular buffer object for storing and retrieving samples in a */ \
|
|
/* first-in/first-out (FIFO) manner using a minimal amount of memory */ \
|
|
typedef struct CBUFFER(_s) * CBUFFER(); \
|
|
\
|
|
/* Create circular buffer object of a particular maximum storage length */ \
|
|
/* _max_size : maximum buffer size, _max_size > 0 */ \
|
|
CBUFFER() CBUFFER(_create)(unsigned int _max_size); \
|
|
\
|
|
/* Create circular buffer object of a particular maximum storage size */ \
|
|
/* and specify the maximum number of elements that can be read at any */ \
|
|
/* any given time */ \
|
|
/* _max_size : maximum buffer size, _max_size > 0 */ \
|
|
/* _max_read : maximum size that will be read from buffer */ \
|
|
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 to stdout */ \
|
|
void CBUFFER(_print)(CBUFFER() _q); \
|
|
\
|
|
/* Print cbuffer object properties and internal state */ \
|
|
void CBUFFER(_debug_print)(CBUFFER() _q); \
|
|
\
|
|
/* Clear internal buffer */ \
|
|
void CBUFFER(_reset)(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); \
|
|
\
|
|
/* Return flag indicating if the buffer is full or not */ \
|
|
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 a block of samples to the buffer */ \
|
|
/* _q : circular buffer object */ \
|
|
/* _v : array of samples to write to buffer */ \
|
|
/* _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 by setting the */ \
|
|
/* value of the output sample pointed to by _v */ \
|
|
/* _q : circular buffer object */ \
|
|
/* _v : pointer to sample output */ \
|
|
void CBUFFER(_pop)(CBUFFER() _q, \
|
|
T * _v); \
|
|
\
|
|
/* Read buffer contents by returning a pointer to the linearized array; */ \
|
|
/* note that the returned pointer is only valid until another operation */ \
|
|
/* is performed on the circular buffer object */ \
|
|
/* _q : circular buffer object */ \
|
|
/* _num_requested : number of elements requested */ \
|
|
/* _v : output pointer */ \
|
|
/* _num_read : 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 */ \
|
|
/* _q : circular buffer object */ \
|
|
/* _n : number of elements to release */ \
|
|
void CBUFFER(_release)(CBUFFER() _q, \
|
|
unsigned int _n); \
|
|
|
|
// Define buffer APIs
|
|
LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_FLOAT, float)
|
|
LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_CFLOAT, liquid_float_complex)
|
|
|
|
|
|
|
|
// Windowing functions
|
|
#define LIQUID_WINDOW_MANGLE_FLOAT(name) LIQUID_CONCAT(windowf, name)
|
|
#define LIQUID_WINDOW_MANGLE_CFLOAT(name) LIQUID_CONCAT(windowcf, name)
|
|
|
|
// large macro
|
|
// WINDOW : name-mangling macro
|
|
// T : data type
|
|
#define LIQUID_WINDOW_DEFINE_API(WINDOW,T) \
|
|
\
|
|
/* Sliding window first-in/first-out buffer with a fixed size */ \
|
|
typedef struct WINDOW(_s) * WINDOW(); \
|
|
\
|
|
/* Create window buffer object of a fixed length */ \
|
|
WINDOW() WINDOW(_create)(unsigned int _n); \
|
|
\
|
|
/* Recreate window buffer object with new length. */ \
|
|
/* This extends an existing window's size, similar to the standard C */ \
|
|
/* library's realloc() to n samples. */ \
|
|
/* If the size of the new window is larger than the old one, the newest */ \
|
|
/* values are retained at the beginning of the buffer and the oldest */ \
|
|
/* values are truncated. If the size of the new window is smaller than */ \
|
|
/* the old one, the oldest values are truncated. */ \
|
|
/* _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); \
|
|
\
|
|
/* Reset window object (initialize to zeros) */ \
|
|
void WINDOW(_reset)(WINDOW() _q); \
|
|
\
|
|
/* Read the contents of the window by returning a pointer to the */ \
|
|
/* aligned internal memory array. This method guarantees that the */ \
|
|
/* elements are linearized. This method should only be used for */ \
|
|
/* reading; writing values to the buffer has unspecified results. */ \
|
|
/* Note that the returned pointer is only valid until another operation */ \
|
|
/* is performed on the window buffer object */ \
|
|
/* _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 */ \
|
|
/* This retrieves the \(i^{th}\) sample in the window, storing the */ \
|
|
/* output value in _v. */ \
|
|
/* This is equivalent to first invoking read() and then indexing on the */ \
|
|
/* resulting pointer; however the result is obtained much faster. */ \
|
|
/* Therefore setting the index to 0 returns the oldest value in the */ \
|
|
/* window. */ \
|
|
/* _q : window object */ \
|
|
/* _i : index of element to read */ \
|
|
/* _v : output value pointer */ \
|
|
void WINDOW(_index)(WINDOW() _q, \
|
|
unsigned int _i, \
|
|
T * _v); \
|
|
\
|
|
/* Shifts a single sample into the right side of the window, pushing */ \
|
|
/* the oldest (left-most) sample out of the end. Unlike stacks, the */ \
|
|
/* window object has no equivalent "pop" method, as values are retained */ \
|
|
/* in memory until they are overwritten. */ \
|
|
/* _q : window object */ \
|
|
/* _v : single input element */ \
|
|
void WINDOW(_push)(WINDOW() _q, \
|
|
T _v); \
|
|
\
|
|
/* Write array of elements onto window buffer */ \
|
|
/* Effectively, this is equivalent to pushing each sample one at a */ \
|
|
/* time, but executes much faster. */ \
|
|
/* _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(LIQUID_WINDOW_MANGLE_FLOAT, float)
|
|
LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_CFLOAT, liquid_float_complex)
|
|
//LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_UINT, unsigned int)
|
|
|
|
|
|
// wdelay functions : windowed-delay
|
|
// Implements an efficient z^-k delay with minimal memory
|
|
#define LIQUID_WDELAY_MANGLE_FLOAT(name) LIQUID_CONCAT(wdelayf, name)
|
|
#define LIQUID_WDELAY_MANGLE_CFLOAT(name) LIQUID_CONCAT(wdelaycf, name)
|
|
//#define LIQUID_WDELAY_MANGLE_UINT(name) LIQUID_CONCAT(wdelayui, name)
|
|
|
|
// large macro
|
|
// WDELAY : name-mangling macro
|
|
// T : data type
|
|
#define LIQUID_WDELAY_DEFINE_API(WDELAY,T) \
|
|
\
|
|
/* Efficient digital delay line using a minimal amount of memory */ \
|
|
typedef struct WDELAY(_s) * WDELAY(); \
|
|
\
|
|
/* Create delay buffer object with a particular number of samples of */ \
|
|
/* delay */ \
|
|
/* _delay : number of samples of delay in the wdelay object */ \
|
|
WDELAY() WDELAY(_create)(unsigned int _delay); \
|
|
\
|
|
/* Re-create delay buffer object, adjusting the delay size, preserving */ \
|
|
/* the internal state of the object */ \
|
|
/* _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(_reset)(WDELAY() _q); \
|
|
\
|
|
/* Read delayed sample at the head of the buffer and store it to the */ \
|
|
/* output pointer */ \
|
|
/* _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(LIQUID_WDELAY_MANGLE_FLOAT, float)
|
|
LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_CFLOAT, liquid_float_complex)
|
|
//LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_UINT, unsigned int)
|
|
|
|
|
|
|
|
//
|
|
// MODULE : channel
|
|
//
|
|
|
|
#define LIQUID_CHANNEL_MANGLE_CCCF(name) LIQUID_CONCAT(channel_cccf,name)
|
|
|
|
// large macro
|
|
// CHANNEL : name-mangling macro
|
|
// TO : output data type
|
|
// TC : coefficients data type
|
|
// TI : input data type
|
|
#define LIQUID_CHANNEL_DEFINE_API(CHANNEL,TO,TC,TI) \
|
|
\
|
|
/* Channel emulation */ \
|
|
typedef struct CHANNEL(_s) * CHANNEL(); \
|
|
\
|
|
/* Create channel object with default parameters */ \
|
|
CHANNEL() CHANNEL(_create)(void); \
|
|
\
|
|
/* Destroy channel object, freeing all internal memory */ \
|
|
void CHANNEL(_destroy)(CHANNEL() _q); \
|
|
\
|
|
/* Print channel object internals to standard output */ \
|
|
void CHANNEL(_print)(CHANNEL() _q); \
|
|
\
|
|
/* Include additive white Gausss noise impairment */ \
|
|
/* _q : channel object */ \
|
|
/* _N0dB : noise floor power spectral density [dB] */ \
|
|
/* _SNRdB : signal-to-noise ratio [dB] */ \
|
|
void CHANNEL(_add_awgn)(CHANNEL() _q, \
|
|
float _N0dB, \
|
|
float _SNRdB); \
|
|
\
|
|
/* Include carrier offset impairment */ \
|
|
/* _q : channel object */ \
|
|
/* _frequency : carrier frequency offset [radians/sample] */ \
|
|
/* _phase : carrier phase offset [radians] */ \
|
|
void CHANNEL(_add_carrier_offset)(CHANNEL() _q, \
|
|
float _frequency, \
|
|
float _phase); \
|
|
\
|
|
/* Include multi-path channel impairment */ \
|
|
/* _q : channel object */ \
|
|
/* _h : channel coefficients (NULL for random) */ \
|
|
/* _h_len : number of channel coefficients */ \
|
|
void CHANNEL(_add_multipath)(CHANNEL() _q, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Include slowly-varying shadowing impairment */ \
|
|
/* _q : channel object */ \
|
|
/* _sigma : standard deviation for log-normal shadowing */ \
|
|
/* _fd : Doppler frequency, 0 <= _fd < 0.5 */ \
|
|
void CHANNEL(_add_shadowing)(CHANNEL() _q, \
|
|
float _sigma, \
|
|
float _fd); \
|
|
\
|
|
/* Apply channel impairments on single input sample */ \
|
|
/* _q : channel object */ \
|
|
/* _x : input sample */ \
|
|
/* _y : pointer to output sample */ \
|
|
void CHANNEL(_execute)(CHANNEL() _q, \
|
|
TI _x, \
|
|
TO * _y); \
|
|
\
|
|
/* Apply channel impairments on block of samples */ \
|
|
/* _q : channel object */ \
|
|
/* _x : input array, [size: _n x 1] */ \
|
|
/* _n : input array, length */ \
|
|
/* _y : output array, [size: _n x 1] */ \
|
|
void CHANNEL(_execute_block)(CHANNEL() _q, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
|
|
LIQUID_CHANNEL_DEFINE_API(LIQUID_CHANNEL_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// time-varying multi-path channel
|
|
//
|
|
#define LIQUID_TVMPCH_MANGLE_CCCF(name) LIQUID_CONCAT(tvmpch_cccf,name)
|
|
|
|
// large macro
|
|
// TVMPCH : name-mangling macro
|
|
// TO : output data type
|
|
// TC : coefficients data type
|
|
// TI : input data type
|
|
#define LIQUID_TVMPCH_DEFINE_API(TVMPCH,TO,TC,TI) \
|
|
\
|
|
/* Time-varying multipath channel emulation */ \
|
|
typedef struct TVMPCH(_s) * TVMPCH(); \
|
|
\
|
|
/* Create time-varying multi-path channel emulator object, specifying */ \
|
|
/* the number of coefficients, the standard deviation of coefficients, */ \
|
|
/* and the coherence time. The larger the standard deviation, the more */ \
|
|
/* dramatic the frequency response of the channel. The shorter the */ \
|
|
/* coeherent time, the faster the channel effects. */ \
|
|
/* _n : number of coefficients, _n > 0 */ \
|
|
/* _std : standard deviation, _std >= 0 */ \
|
|
/* _tau : normalized coherence time, 0 < _tau < 1 */ \
|
|
TVMPCH() TVMPCH(_create)(unsigned int _n, \
|
|
float _std, \
|
|
float _tau); \
|
|
\
|
|
/* Destroy channel object, freeing all internal memory */ \
|
|
void TVMPCH(_destroy)(TVMPCH() _q); \
|
|
\
|
|
/* Reset object */ \
|
|
void TVMPCH(_reset)(TVMPCH() _q); \
|
|
\
|
|
/* Print channel object internals to standard output */ \
|
|
void TVMPCH(_print)(TVMPCH() _q); \
|
|
\
|
|
/* Push sample into emulator */ \
|
|
/* _q : channel object */ \
|
|
/* _x : input sample */ \
|
|
void TVMPCH(_push)(TVMPCH() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Compute output sample */ \
|
|
/* _q : channel object */ \
|
|
/* _y : output sample */ \
|
|
void TVMPCH(_execute)(TVMPCH() _q, \
|
|
TO * _y); \
|
|
\
|
|
/* Apply channel impairments on a block of samples */ \
|
|
/* _q : channel object */ \
|
|
/* _x : input array, [size: _n x 1] */ \
|
|
/* _n : input array length */ \
|
|
/* _y : output array, [size: _n x 1] */ \
|
|
void TVMPCH(_execute_block)(TVMPCH() _q, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
|
|
LIQUID_TVMPCH_DEFINE_API(LIQUID_TVMPCH_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// MODULE : dotprod (vector dot product)
|
|
//
|
|
|
|
#define LIQUID_DOTPROD_MANGLE_RRRF(name) LIQUID_CONCAT(dotprod_rrrf,name)
|
|
#define LIQUID_DOTPROD_MANGLE_CCCF(name) LIQUID_CONCAT(dotprod_cccf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Vector dot product operation */ \
|
|
typedef struct DOTPROD(_s) * DOTPROD(); \
|
|
\
|
|
/* Run dot product without creating object. This is less efficient than */ \
|
|
/* creating the object as it is an unoptimized portable implementation */ \
|
|
/* that doesn't take advantage of processor extensions. It is meant to */ \
|
|
/* provide a baseline for performance comparison and a convenient way */ \
|
|
/* to invoke a dot product operation when fast operation is not */ \
|
|
/* necessary. */ \
|
|
/* _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); \
|
|
\
|
|
/* This provides the same unoptimized operation as the 'run()' method */ \
|
|
/* above, but with the loop unrolled by a factor of 4. It is marginally */ \
|
|
/* faster than 'run()' without unrolling the 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(_run4)( TC * _v, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
\
|
|
/* Create vector 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 of potentially a different length with */ \
|
|
/* different coefficients. If the length of the dot product object does */ \
|
|
/* not change, not memory reallocation is invoked. */ \
|
|
/* _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 on an input array */ \
|
|
/* _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(LIQUID_DOTPROD_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_DOTPROD_DEFINE_API(LIQUID_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 LIQUID_EQLMS_MANGLE_RRRF(name) LIQUID_CONCAT(eqlms_rrrf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Least mean-squares equalization object */ \
|
|
typedef struct EQLMS(_s) * EQLMS(); \
|
|
\
|
|
/* Create LMS EQ initialized with external coefficients */ \
|
|
/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \
|
|
/* _n : filter length */ \
|
|
EQLMS() EQLMS(_create)(T * _h, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Create LMS EQ initialized with square-root Nyquist prototype filter */ \
|
|
/* as initial set of coefficients. This is useful for applications */ \
|
|
/* where the baseline matched filter is a good starting point, but */ \
|
|
/* where equalization is needed to properly remove inter-symbol */ \
|
|
/* interference. */ \
|
|
/* The filter length is \(2 k m + 1\) */ \
|
|
/* _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); \
|
|
\
|
|
/* Create LMS EQ initialized with low-pass filter */ \
|
|
/* _n : filter length */ \
|
|
/* _fc : filter cut-off normalized to sample rate, 0 < _fc <= 0.5 */ \
|
|
EQLMS() EQLMS(_create_lowpass)(unsigned int _n, \
|
|
float _fc); \
|
|
\
|
|
/* Re-create EQ initialized with external coefficients */ \
|
|
/* _q : equalizer object */ \
|
|
/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \
|
|
/* _h_len : filter length */ \
|
|
EQLMS() EQLMS(_recreate)(EQLMS() _q, \
|
|
T * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* 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 equalizer learning rate */ \
|
|
float EQLMS(_get_bw)(EQLMS() _q); \
|
|
\
|
|
/* Set equalizer learning rate */ \
|
|
/* _q : equalizer object */ \
|
|
/* _lambda : learning rate, _lambda > 0 */ \
|
|
void EQLMS(_set_bw)(EQLMS() _q, \
|
|
float _lambda); \
|
|
\
|
|
/* Push sample into equalizer internal buffer */ \
|
|
/* _q : equalizer object */ \
|
|
/* _x : input sample */ \
|
|
void EQLMS(_push)(EQLMS() _q, \
|
|
T _x); \
|
|
\
|
|
/* Push block of samples into internal buffer of equalizer object */ \
|
|
/* _q : equalizer object */ \
|
|
/* _x : input sample array, [size: _n x 1] */ \
|
|
/* _n : input sample array length */ \
|
|
void EQLMS(_push_block)(EQLMS() _q, \
|
|
T * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Execute internal dot product and return result */ \
|
|
/* _q : equalizer object */ \
|
|
/* _y : output sample */ \
|
|
void EQLMS(_execute)(EQLMS() _q, \
|
|
T * _y); \
|
|
\
|
|
/* Execute equalizer with block of samples using constant */ \
|
|
/* modulus algorithm, operating on a decimation rate of _k */ \
|
|
/* samples. */ \
|
|
/* _q : equalizer object */ \
|
|
/* _k : down-sampling rate */ \
|
|
/* _x : input sample array [size: _n x 1] */ \
|
|
/* _n : input sample array length */ \
|
|
/* _y : output sample array [size: _n x 1] */ \
|
|
void EQLMS(_execute_block)(EQLMS() _q, \
|
|
unsigned int _k, \
|
|
T * _x, \
|
|
unsigned int _n, \
|
|
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); \
|
|
\
|
|
/* Step through one cycle of equalizer training (blind) */ \
|
|
/* _q : equalizer object */ \
|
|
/* _d_hat : actual output */ \
|
|
void EQLMS(_step_blind)(EQLMS() _q, \
|
|
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(LIQUID_EQLMS_MANGLE_RRRF, float)
|
|
LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_CCCF, liquid_float_complex)
|
|
|
|
|
|
// recursive least-squares (RLS)
|
|
#define LIQUID_EQRLS_MANGLE_RRRF(name) LIQUID_CONCAT(eqrls_rrrf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Recursive least mean-squares equalization object */ \
|
|
typedef struct EQRLS(_s) * EQRLS(); \
|
|
\
|
|
/* Create RLS EQ initialized with external coefficients */ \
|
|
/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \
|
|
/* _n : filter length */ \
|
|
EQRLS() EQRLS(_create)(T * _h, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Re-create EQ initialized with external coefficients */ \
|
|
/* _q : equalizer object */ \
|
|
/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \
|
|
/* _n : filter length */ \
|
|
EQRLS() EQRLS(_recreate)(EQRLS() _q, \
|
|
T * _h, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Destroy equalizer object, freeing all internal memory */ \
|
|
void EQRLS(_destroy)(EQRLS() _q); \
|
|
\
|
|
/* Reset equalizer object, clearing internal state */ \
|
|
void EQRLS(_reset)(EQRLS() _q); \
|
|
\
|
|
/* Print equalizer internal state */ \
|
|
void EQRLS(_print)(EQRLS() _q); \
|
|
\
|
|
/* Get equalizer learning rate */ \
|
|
float EQRLS(_get_bw)(EQRLS() _q); \
|
|
\
|
|
/* Set equalizer learning rate */ \
|
|
/* _q : equalizer object */ \
|
|
/* _mu : learning rate, _mu > 0 */ \
|
|
void EQRLS(_set_bw)(EQRLS() _q, \
|
|
float _mu); \
|
|
\
|
|
/* Push sample into equalizer internal buffer */ \
|
|
/* _q : equalizer object */ \
|
|
/* _x : input sample */ \
|
|
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); \
|
|
\
|
|
/* Get equalizer's internal 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(LIQUID_EQRLS_MANGLE_RRRF, float)
|
|
LIQUID_EQRLS_DEFINE_API(LIQUID_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);
|
|
|
|
// generate error-detection key and append to end of message
|
|
// _scheme : error-detection scheme (resulting in 'p' bytes)
|
|
// _msg : input data message, [size: _n+p x 1]
|
|
// _n : input data message size (excluding key at end)
|
|
void crc_append_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);
|
|
|
|
// check message with key appended to end of array
|
|
// _scheme : error-detection scheme (resulting in 'p' bytes)
|
|
// _msg : input data message, [size: _n+p x 1]
|
|
// _n : input data message size (excluding key at end)
|
|
int crc_check_key(crc_scheme _scheme,
|
|
unsigned char * _msg,
|
|
unsigned int _n);
|
|
|
|
// get size of key (bytes)
|
|
unsigned int crc_sizeof_key(crc_scheme _scheme);
|
|
|
|
|
|
// 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);
|
|
|
|
// access methods
|
|
unsigned int packetizer_get_dec_msg_len(packetizer _p);
|
|
unsigned int packetizer_get_enc_msg_len(packetizer _p);
|
|
crc_scheme packetizer_get_crc (packetizer _p);
|
|
fec_scheme packetizer_get_fec0 (packetizer _p);
|
|
fec_scheme packetizer_get_fec1 (packetizer _p);
|
|
|
|
|
|
// Execute the packetizer on an input message
|
|
//
|
|
// _p : packetizer object
|
|
// _msg : input message (uncoded bytes)
|
|
// _pkt : encoded output message
|
|
void packetizer_encode(packetizer _p,
|
|
const unsigned char * _msg,
|
|
unsigned char * _pkt);
|
|
|
|
// 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,
|
|
const 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,
|
|
const 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) \
|
|
\
|
|
/* Fast Fourier Transform (FFT) and inverse (plan) object */ \
|
|
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 one-dimensional 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 and free all internally-allocated memory */ \
|
|
void FFT(_destroy_plan)(FFT(plan) _p); \
|
|
\
|
|
/* Print transform plan and internal strategy to stdout. This includes */ \
|
|
/* information on the strategy for computing large transforms with many */ \
|
|
/* prime factors or with large prime factors. */ \
|
|
void FFT(_print_plan)(FFT(plan) _p); \
|
|
\
|
|
/* Run the transform */ \
|
|
void FFT(_execute)(FFT(plan) _p); \
|
|
\
|
|
/* 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 one-dimensional 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 */ \
|
|
/* _x : input array [size: _n x 1] */ \
|
|
/* _n : input array size */ \
|
|
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) \
|
|
\
|
|
/* Spectral periodogram object for computing power spectral density */ \
|
|
/* estimates of various signals */ \
|
|
typedef struct SPGRAM(_s) * SPGRAM(); \
|
|
\
|
|
/* Create spgram object, fully defined */ \
|
|
/* _nfft : transform (FFT) size, _nfft >= 2 */ \
|
|
/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \
|
|
/* _window_len : window length, 1 <= _window_len <= _nfft */ \
|
|
/* _delay : delay between transforms, _delay > 0 */ \
|
|
SPGRAM() SPGRAM(_create)(unsigned int _nfft, \
|
|
int _wtype, \
|
|
unsigned int _window_len, \
|
|
unsigned int _delay); \
|
|
\
|
|
/* Create default spgram object of a particular transform size using */ \
|
|
/* the Kaiser-Bessel window (LIQUID_WINDOW_KAISER), a window length */ \
|
|
/* equal to _nfft/2, and a delay of _nfft/4 */ \
|
|
/* _nfft : FFT size, _nfft >= 2 */ \
|
|
SPGRAM() SPGRAM(_create_default)(unsigned int _nfft); \
|
|
\
|
|
/* Destroy spgram object, freeing all internally-allocated memory */ \
|
|
void SPGRAM(_destroy)(SPGRAM() _q); \
|
|
\
|
|
/* Clears the internal state of the object, but not the internal buffer */ \
|
|
void SPGRAM(_clear)(SPGRAM() _q); \
|
|
\
|
|
/* Reset the object to its original state completely. This effectively */ \
|
|
/* executes the clear() method and then resets the internal buffer */ \
|
|
void SPGRAM(_reset)(SPGRAM() _q); \
|
|
\
|
|
/* Print internal state of the object to stdout */ \
|
|
void SPGRAM(_print)(SPGRAM() _q); \
|
|
\
|
|
/* Set the forgetting factor (filter bandwidth) for accumulating */ \
|
|
/* independent transform squared magnitude outputs. */ \
|
|
/* This is used to compute a running time-average power spectral */ \
|
|
/* density output. */ \
|
|
/* The value of _alpha determines how the power spectral estimate is */ \
|
|
/* accumulated across transforms and can range from 0 to 1 with a */ \
|
|
/* special case of -1 to accumulate infinitely. */ \
|
|
/* Setting _alpha to 0 minimizes the bandwidth and the PSD estimate */ \
|
|
/* will never update. */ \
|
|
/* Setting _alpha to 1 forces the object to always use the most recent */ \
|
|
/* spectral estimate. */ \
|
|
/* Setting _alpha to -1 is a special case to enable infinite spectral */ \
|
|
/* accumulation. */ \
|
|
/* _q : spectral periodogram object */ \
|
|
/* _alpha : forgetting factor, set to -1 for infinite, 0<=_alpha<=1 */ \
|
|
int SPGRAM(_set_alpha)(SPGRAM() _q, \
|
|
float _alpha); \
|
|
\
|
|
/* Set the center frequency of the received signal. */ \
|
|
/* This is for display purposes only when generating the output image. */ \
|
|
/* _q : spectral periodogram object */ \
|
|
/* _freq : center frequency [Hz] */ \
|
|
int SPGRAM(_set_freq)(SPGRAM() _q, \
|
|
float _freq); \
|
|
\
|
|
/* Set the sample rate (frequency) of the received signal. */ \
|
|
/* This is for display purposes only when generating the output image. */ \
|
|
/* _q : spectral periodogram object */ \
|
|
/* _rate : sample rate [Hz] */ \
|
|
int SPGRAM(_set_rate)(SPGRAM() _q, \
|
|
float _rate); \
|
|
\
|
|
/* Get transform (FFT) size */ \
|
|
unsigned int SPGRAM(_get_nfft)(SPGRAM() _q); \
|
|
\
|
|
/* Get window length */ \
|
|
unsigned int SPGRAM(_get_window_len)(SPGRAM() _q); \
|
|
\
|
|
/* Get delay between transforms */ \
|
|
unsigned int SPGRAM(_get_delay)(SPGRAM() _q); \
|
|
\
|
|
/* Get number of samples processed since reset */ \
|
|
unsigned long long int SPGRAM(_get_num_samples)(SPGRAM() _q); \
|
|
\
|
|
/* Get number of samples processed since object was created */ \
|
|
unsigned long long int SPGRAM(_get_num_samples_total)(SPGRAM() _q); \
|
|
\
|
|
/* Get number of transforms processed since reset */ \
|
|
unsigned long long int SPGRAM(_get_num_transforms)(SPGRAM() _q); \
|
|
\
|
|
/* Get number of transforms processed since object was created */ \
|
|
unsigned long long int SPGRAM(_get_num_transforms_total)(SPGRAM() _q); \
|
|
\
|
|
/* Get forgetting factor (filter bandwidth) */ \
|
|
float SPGRAM(_get_alpha)(SPGRAM() _q); \
|
|
\
|
|
/* Push a single sample into the object, executing internal transform */ \
|
|
/* as necessary. */ \
|
|
/* _q : spgram object */ \
|
|
/* _x : input sample */ \
|
|
void SPGRAM(_push)(SPGRAM() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write a block of samples to the object, executing internal */ \
|
|
/* transform as necessary. */ \
|
|
/* _q : spgram object */ \
|
|
/* _x : input buffer [size: _n x 1] */ \
|
|
/* _n : input buffer length */ \
|
|
void SPGRAM(_write)(SPGRAM() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Compute spectral periodogram output (fft-shifted values in dB) from */ \
|
|
/* current buffer contents */ \
|
|
/* _q : spgram object */ \
|
|
/* _X : output spectrum (dB), [size: _nfft x 1] */ \
|
|
void SPGRAM(_get_psd)(SPGRAM() _q, \
|
|
T * _X); \
|
|
\
|
|
/* Export stand-alone gnuplot file for plotting output spectrum, */ \
|
|
/* returning 0 on sucess, anything other than 0 for failure */ \
|
|
/* _q : spgram object */ \
|
|
/* _filename : input buffer [size: _n x 1] */ \
|
|
int SPGRAM(_export_gnuplot)(SPGRAM() _q, \
|
|
const char * _filename); \
|
|
\
|
|
/* Estimate spectrum on input signal (create temporary object for */ \
|
|
/* convenience */ \
|
|
/* _nfft : FFT size */ \
|
|
/* _x : input signal [size: _n x 1] */ \
|
|
/* _n : input signal length */ \
|
|
/* _psd : output spectrum, [size: _nfft x 1] */ \
|
|
void SPGRAM(_estimate_psd)(unsigned int _nfft, \
|
|
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)
|
|
|
|
//
|
|
// asgram : ascii spectral periodogram
|
|
//
|
|
|
|
#define LIQUID_ASGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(asgramcf,name)
|
|
#define LIQUID_ASGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(asgramf, name)
|
|
|
|
// Macro : ASGRAM
|
|
// ASGRAM : name-mangling macro
|
|
// T : primitive data type
|
|
// TC : primitive data type (complex)
|
|
// TI : primitive data type (input)
|
|
#define LIQUID_ASGRAM_DEFINE_API(ASGRAM,T,TC,TI) \
|
|
\
|
|
/* ASCII spectral periodogram for computing and displaying an estimate */ \
|
|
/* of a signal's power spectrum with ASCII characters */ \
|
|
typedef struct ASGRAM(_s) * ASGRAM(); \
|
|
\
|
|
/* Create asgram object with size _nfft */ \
|
|
/* _nfft : size of FFT taken for each transform (character width) */ \
|
|
ASGRAM() ASGRAM(_create)(unsigned int _nfft); \
|
|
\
|
|
/* Destroy asgram object, freeing all internally-allocated memory */ \
|
|
void ASGRAM(_destroy)(ASGRAM() _q); \
|
|
\
|
|
/* Reset the internal state of the asgram object */ \
|
|
void ASGRAM(_reset)(ASGRAM() _q); \
|
|
\
|
|
/* Set the scale and offset for spectrogram in terms of dB for display */ \
|
|
/* purposes */ \
|
|
/* _q : asgram object */ \
|
|
/* _ref : signal reference level [dB] */ \
|
|
/* _div : signal division [dB] */ \
|
|
void ASGRAM(_set_scale)(ASGRAM() _q, \
|
|
float _ref, \
|
|
float _div); \
|
|
\
|
|
/* Set the display's 10 characters for output string starting from the */ \
|
|
/* weakest and ending with the strongest */ \
|
|
/* _q : asgram object */ \
|
|
/* _ascii : 10-character display, default: " .,-+*&NM#" */ \
|
|
void ASGRAM(_set_display)(ASGRAM() _q, \
|
|
const char * _ascii); \
|
|
\
|
|
/* Push a single sample into the asgram object, executing internal */ \
|
|
/* transform as necessary. */ \
|
|
/* _q : asgram object */ \
|
|
/* _x : input sample */ \
|
|
void ASGRAM(_push)(ASGRAM() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write a block of samples to the asgram object, executing internal */ \
|
|
/* transforms as necessary. */ \
|
|
/* _q : asgram object */ \
|
|
/* _x : input buffer [size: _n x 1] */ \
|
|
/* _n : input buffer length */ \
|
|
void ASGRAM(_write)(ASGRAM() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Compute spectral periodogram output from current buffer contents */ \
|
|
/* and return the ascii character string to display along with the peak */ \
|
|
/* value and its frequency location */ \
|
|
/* _q : asgram object */ \
|
|
/* _ascii : output ASCII string [size: _nfft x 1] */ \
|
|
/* _peakval : peak power spectral density value [dB] */ \
|
|
/* _peakfreq : peak power spectral density frequency */ \
|
|
void ASGRAM(_execute)(ASGRAM() _q, \
|
|
char * _ascii, \
|
|
float * _peakval, \
|
|
float * _peakfreq); \
|
|
\
|
|
/* Compute spectral periodogram output from current buffer contents and */ \
|
|
/* print standard format to stdout */ \
|
|
void ASGRAM(_print)(ASGRAM() _q); \
|
|
|
|
LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_CFLOAT,
|
|
float,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_FLOAT,
|
|
float,
|
|
liquid_float_complex,
|
|
float)
|
|
|
|
//
|
|
// spectral periodogram waterfall
|
|
//
|
|
|
|
#define LIQUID_SPWATERFALL_MANGLE_CFLOAT(name) LIQUID_CONCAT(spwaterfallcf,name)
|
|
#define LIQUID_SPWATERFALL_MANGLE_FLOAT(name) LIQUID_CONCAT(spwaterfallf, name)
|
|
|
|
// Macro : SPWATERFALL
|
|
// SPWATERFALL : name-mangling macro
|
|
// T : primitive data type
|
|
// TC : primitive data type (complex)
|
|
// TI : primitive data type (input)
|
|
#define LIQUID_SPWATERFALL_DEFINE_API(SPWATERFALL,T,TC,TI) \
|
|
\
|
|
/* Spectral periodogram waterfall object for computing time-varying */ \
|
|
/* power spectral density estimates */ \
|
|
typedef struct SPWATERFALL(_s) * SPWATERFALL(); \
|
|
\
|
|
/* Create spwaterfall object, fully defined */ \
|
|
/* _nfft : transform (FFT) size, _nfft >= 2 */ \
|
|
/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \
|
|
/* _window_len : window length, 1 <= _window_len <= _nfft */ \
|
|
/* _delay : delay between transforms, _delay > 0 */ \
|
|
/* _time : number of aggregated transforms, _time > 0 */ \
|
|
SPWATERFALL() SPWATERFALL(_create)(unsigned int _nfft, \
|
|
int _wtype, \
|
|
unsigned int _window_len, \
|
|
unsigned int _delay, \
|
|
unsigned int _time); \
|
|
\
|
|
/* Create default spwatefall object (Kaiser-Bessel window) */ \
|
|
/* _nfft : transform size, _nfft >= 2 */ \
|
|
/* _time : delay between transforms, _delay > 0 */ \
|
|
SPWATERFALL() SPWATERFALL(_create_default)(unsigned int _nfft, \
|
|
unsigned int _time); \
|
|
\
|
|
/* Destroy spwaterfall object, freeing all internally-allocated memory */ \
|
|
void SPWATERFALL(_destroy)(SPWATERFALL() _q); \
|
|
\
|
|
/* Clears the internal state of the object, but not the internal buffer */ \
|
|
void SPWATERFALL(_clear)(SPWATERFALL() _q); \
|
|
\
|
|
/* Reset the object to its original state completely. This effectively */ \
|
|
/* executes the clear() method and then resets the internal buffer */ \
|
|
void SPWATERFALL(_reset)(SPWATERFALL() _q); \
|
|
\
|
|
/* Print internal state of the object to stdout */ \
|
|
void SPWATERFALL(_print)(SPWATERFALL() _q); \
|
|
\
|
|
/* Get number of samples processed since object was created */ \
|
|
uint64_t SPWATERFALL(_get_num_samples_total)(SPWATERFALL() _q); \
|
|
\
|
|
/* Get FFT size (columns in PSD output) */ \
|
|
unsigned int SPWATERFALL(_get_num_freq)(SPWATERFALL() _q); \
|
|
\
|
|
/* Get number of accumulated FFTs (rows in PSD output) */ \
|
|
unsigned int SPWATERFALL(_get_num_time)(SPWATERFALL() _q); \
|
|
\
|
|
/* Get power spectral density (PSD), size: nfft x time */ \
|
|
const T * SPWATERFALL(_get_psd)(SPWATERFALL() _q); \
|
|
\
|
|
/* Set the center frequency of the received signal. */ \
|
|
/* This is for display purposes only when generating the output image. */ \
|
|
/* _q : spectral periodogram waterfall object */ \
|
|
/* _freq : center frequency [Hz] */ \
|
|
int SPWATERFALL(_set_freq)(SPWATERFALL() _q, \
|
|
float _freq); \
|
|
\
|
|
/* Set the sample rate (frequency) of the received signal. */ \
|
|
/* This is for display purposes only when generating the output image. */ \
|
|
/* _q : spectral periodogram waterfall object */ \
|
|
/* _rate : sample rate [Hz] */ \
|
|
int SPWATERFALL(_set_rate)(SPWATERFALL() _q, \
|
|
float _rate); \
|
|
\
|
|
/* Set the canvas size. */ \
|
|
/* This is for display purposes only when generating the output image. */ \
|
|
/* _q : spectral periodogram waterfall object */ \
|
|
/* _width : image width [pixels] */ \
|
|
/* _height : image height [pixels] */ \
|
|
int SPWATERFALL(_set_dims)(SPWATERFALL() _q, \
|
|
unsigned int _width, \
|
|
unsigned int _height); \
|
|
\
|
|
/* Set commands for executing directly before 'plot' statement. */ \
|
|
/* _q : spectral periodogram waterfall object */ \
|
|
/* _commands : gnuplot commands separated by semicolons */ \
|
|
int SPWATERFALL(_set_commands)(SPWATERFALL() _q, \
|
|
const char * _commands); \
|
|
\
|
|
/* Push a single sample into the object, executing internal transform */ \
|
|
/* as necessary. */ \
|
|
/* _q : spwaterfall object */ \
|
|
/* _x : input sample */ \
|
|
void SPWATERFALL(_push)(SPWATERFALL() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write a block of samples to the object, executing internal */ \
|
|
/* transform as necessary. */ \
|
|
/* _q : spwaterfall object */ \
|
|
/* _x : input buffer, [size: _n x 1] */ \
|
|
/* _n : input buffer length */ \
|
|
void SPWATERFALL(_write)(SPWATERFALL() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Export set of files for plotting */ \
|
|
/* _q : spwaterfall object */ \
|
|
/* _base : base filename (will export .gnu, .bin, and .png files) */ \
|
|
int SPWATERFALL(_export)(SPWATERFALL() _q, \
|
|
const char * _base); \
|
|
|
|
|
|
LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_CFLOAT,
|
|
float,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_FLOAT,
|
|
float,
|
|
liquid_float_complex,
|
|
float)
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
// Design (root-)Nyquist filter from prototype
|
|
// _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_prototype(liquid_firfilt_type _type,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta,
|
|
float _dt,
|
|
float * _h);
|
|
|
|
// 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 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);
|
|
|
|
// run filter design for basic low-pass filter
|
|
// _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 [ignored]
|
|
// _h : output coefficient buffer, [size: _n x 1]
|
|
void firdespm_lowpass(unsigned int _n,
|
|
float _fc,
|
|
float _As,
|
|
float _mu,
|
|
float * _h);
|
|
|
|
// firdespm response callback function
|
|
// _frequency : normalized frequency
|
|
// _userdata : pointer to userdata
|
|
// _desired : (return) desired response
|
|
// _weight : (return) weight
|
|
typedef int (*firdespm_callback)(double _frequency,
|
|
void * _userdata,
|
|
double * _desired,
|
|
double * _weight);
|
|
|
|
// 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);
|
|
|
|
// create firdespm object with user-defined callback
|
|
// _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]
|
|
// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS)
|
|
// _callback : user-defined callback for specifying desired response & weights
|
|
// _userdata : user-defined data structure for callback function
|
|
firdespm firdespm_create_callback(unsigned int _h_len,
|
|
unsigned int _num_bands,
|
|
float * _bands,
|
|
liquid_firdespm_btype _btype,
|
|
firdespm_callback _callback,
|
|
void * _userdata);
|
|
|
|
// 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 finite impulse response notch filter
|
|
// _m : filter semi-length, m in [1,1000]
|
|
// _f0 : filter notch frequency (normalized), -0.5 <= _fc <= 0.5
|
|
// _As : stop-band attenuation [dB], _As > 0
|
|
// _h : output coefficient buffer, [size: 2*_m+1 x 1]
|
|
void liquid_firdes_notch(unsigned int _m,
|
|
float _f0,
|
|
float _As,
|
|
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 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 LIQUID_AUTOCORR_MANGLE_CCCF(name) LIQUID_CONCAT(autocorr_cccf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Computes auto-correlation with a fixed lag on input signals */ \
|
|
typedef struct AUTOCORR(_s) * AUTOCORR(); \
|
|
\
|
|
/* Create auto-correlator object with a particular window length and */ \
|
|
/* delay */ \
|
|
/* _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 */ \
|
|
/* _q : auto-correlator object */ \
|
|
/* _x : single input sample */ \
|
|
void AUTOCORR(_push)(AUTOCORR() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write block of samples to auto-correlator object */ \
|
|
/* _q : auto-correlation object */ \
|
|
/* _x : input array [size: _n x 1] */ \
|
|
/* _n : number of input samples */ \
|
|
void AUTOCORR(_write)(AUTOCORR() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Compute single auto-correlation output */ \
|
|
/* _q : auto-correlator object */ \
|
|
/* _rxx : auto-correlated 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(LIQUID_AUTOCORR_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
|
|
//
|
|
// Finite impulse response filter
|
|
//
|
|
|
|
#define LIQUID_FIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(firfilt_rrrf,name)
|
|
#define LIQUID_FIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(firfilt_crcf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Finite impulse response (FIR) filter */ \
|
|
typedef struct FIRFILT(_s) * FIRFILT(); \
|
|
\
|
|
/* Create a finite impulse response filter (firfilt) object by directly */ \
|
|
/* specifying the filter coefficients in an array */ \
|
|
/* _h : filter coefficients [size: _n x 1] */ \
|
|
/* _n : number of filter coefficients, _n > 0 */ \
|
|
FIRFILT() FIRFILT(_create)(TC * _h, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Create object using Kaiser-Bessel windowed sinc method */ \
|
|
/* _n : filter length, _n > 0 */ \
|
|
/* _fc : filter normalized 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 object from square-root Nyquist prototype */ \
|
|
/* The filter length will be \(2 k m + 1 \) samples long with a delay */ \
|
|
/* of \( k m + 1 \) samples. */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _k : nominal samples per symbol, _k > 1 */ \
|
|
/* _m : filter delay [symbols], _m > 0 */ \
|
|
/* _beta : rolloff factor, 0 < beta <= 1 */ \
|
|
/* _mu : fractional sample offset [samples], -0.5 < _mu < 0.5 */ \
|
|
FIRFILT() FIRFILT(_create_rnyquist)(int _type, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta, \
|
|
float _mu); \
|
|
\
|
|
/* Create rectangular filter prototype; that is */ \
|
|
/* \( \vec{h} = \{ 1, 1, 1, \ldots 1 \} \) */ \
|
|
/* _n : length of filter [samples], 0 < _n <= 1024 */ \
|
|
FIRFILT() FIRFILT(_create_rect)(unsigned int _n); \
|
|
\
|
|
/* Create DC blocking filter from prototype */ \
|
|
/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \
|
|
/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \
|
|
FIRFILT() FIRFILT(_create_dc_blocker)(unsigned int _m, \
|
|
float _As); \
|
|
\
|
|
/* Create notch filter from prototype */ \
|
|
/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \
|
|
/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \
|
|
/* _f0 : center frequency for notch, _fc in [-0.5, 0.5] */ \
|
|
FIRFILT() FIRFILT(_create_notch)(unsigned int _m, \
|
|
float _As, \
|
|
float _f0); \
|
|
\
|
|
/* Re-create filter object of potentially a different length with */ \
|
|
/* different coefficients. If the length of the filter does not change, */ \
|
|
/* not memory reallocation is invoked. */ \
|
|
/* _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 to stdout */ \
|
|
void FIRFILT(_print)(FIRFILT() _q); \
|
|
\
|
|
/* Set output scaling for filter */ \
|
|
/* _q : filter object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRFILT(_set_scale)(FIRFILT() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for filter */ \
|
|
/* _q : filter object */ \
|
|
/* _scale : scaling factor applied to each output sample */ \
|
|
void FIRFILT(_get_scale)(FIRFILT() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* Push sample into filter object's internal buffer */ \
|
|
/* _q : filter object */ \
|
|
/* _x : single input sample */ \
|
|
void FIRFILT(_push)(FIRFILT() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write block of samples into filter object's internal buffer */ \
|
|
/* _q : filter object */ \
|
|
/* _x : buffer of input samples, [size: _n x 1] */ \
|
|
/* _n : number of input samples */ \
|
|
void FIRFILT(_write)(FIRFILT() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Execute vector dot product on the filter's 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; in-place operation */ \
|
|
/* is permitted (_x and _y may point to the same place in memory) */ \
|
|
/* _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); \
|
|
\
|
|
/* Get length of filter object (number of internal coefficients) */ \
|
|
unsigned int FIRFILT(_get_length)(FIRFILT() _q); \
|
|
\
|
|
/* Compute complex frequency response of filter object */ \
|
|
/* _q : filter object */ \
|
|
/* _fc : normalized frequency for evaluation */ \
|
|
/* _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(LIQUID_FIRFILT_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FIRFILT_DEFINE_API(LIQUID_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 LIQUID_FIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(firhilbf, name)
|
|
//#define LIQUID_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) \
|
|
\
|
|
/* Finite impulse response (FIR) Hilbert transform */ \
|
|
typedef struct FIRHILB(_s) * FIRHILB(); \
|
|
\
|
|
/* Create a firhilb object with a particular filter semi-length and */ \
|
|
/* desired stop-band attenuation. */ \
|
|
/* Internally the object designs a half-band filter based on applying */ \
|
|
/* a Kaiser-Bessel window to a sinc function to guarantee zeros at all */ \
|
|
/* off-center odd indexed samples. */ \
|
|
/* _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 response Hilbert transform, freeing all */ \
|
|
/* internally-allocted memory and objects. */ \
|
|
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 */ \
|
|
/* _y0 : real-valued output sample, lower side-band retained */ \
|
|
/* _y1 : real-valued output sample, upper side-band retained */ \
|
|
void FIRHILB(_c2r_execute)(FIRHILB() _q, \
|
|
TC _x, \
|
|
T * _y0, \
|
|
T * _y1); \
|
|
\
|
|
/* 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 decimator (real to complex) on a block of */ \
|
|
/* samples */ \
|
|
/* _q : Hilbert transform object */ \
|
|
/* _x : real-valued input array, [size: 2*_n x 1] */ \
|
|
/* _n : number of output samples */ \
|
|
/* _y : complex-valued output array, [size: _n x 1] */ \
|
|
void FIRHILB(_decim_execute_block)(FIRHILB() _q, \
|
|
T * _x, \
|
|
unsigned int _n, \
|
|
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); \
|
|
\
|
|
/* Execute Hilbert transform interpolator (complex to real) on a block */ \
|
|
/* of samples */ \
|
|
/* _q : Hilbert transform object */ \
|
|
/* _x : complex-valued input array, [size: _n x 1] */ \
|
|
/* _n : number of *input* samples */ \
|
|
/* _y : real-valued output array, [size: 2*_n x 1] */ \
|
|
void FIRHILB(_interp_execute_block)(FIRHILB() _q, \
|
|
TC * _x, \
|
|
unsigned int _n, \
|
|
T * _y); \
|
|
|
|
LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_FLOAT, float, liquid_float_complex)
|
|
//LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_DOUBLE, double, liquid_double_complex)
|
|
|
|
|
|
//
|
|
// Infinite impulse response (IIR) Hilbert transform
|
|
// 2:1 real-to-complex decimator
|
|
// 1:2 complex-to-real interpolator
|
|
//
|
|
|
|
#define LIQUID_IIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(iirhilbf, name)
|
|
//#define LIQUID_IIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(iirhilb, name)
|
|
|
|
// NOTES:
|
|
// Although iirhilb is a placeholder for both decimation and
|
|
// interpolation, separate objects should be used for each task.
|
|
#define LIQUID_IIRHILB_DEFINE_API(IIRHILB,T,TC) \
|
|
\
|
|
/* Infinite impulse response (IIR) Hilbert transform */ \
|
|
typedef struct IIRHILB(_s) * IIRHILB(); \
|
|
\
|
|
/* Create a iirhilb object with a particular filter type, order, and */ \
|
|
/* desired pass- and stop-band attenuation. */ \
|
|
/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \
|
|
/* _n : filter order, _n > 0 */ \
|
|
/* _Ap : pass-band ripple [dB], _Ap > 0 */ \
|
|
/* _As : stop-band ripple [dB], _Ap > 0 */ \
|
|
IIRHILB() IIRHILB(_create)(liquid_iirdes_filtertype _ftype, \
|
|
unsigned int _n, \
|
|
float _Ap, \
|
|
float _As); \
|
|
\
|
|
/* Create a default iirhilb object with a particular filter order. */ \
|
|
/* _n : filter order, _n > 0 */ \
|
|
IIRHILB() IIRHILB(_create_default)(unsigned int _n); \
|
|
\
|
|
/* Destroy finite impulse response Hilbert transform, freeing all */ \
|
|
/* internally-allocted memory and objects. */ \
|
|
void IIRHILB(_destroy)(IIRHILB() _q); \
|
|
\
|
|
/* Print iirhilb object internals to stdout */ \
|
|
void IIRHILB(_print)(IIRHILB() _q); \
|
|
\
|
|
/* Reset iirhilb object internal state */ \
|
|
void IIRHILB(_reset)(IIRHILB() _q); \
|
|
\
|
|
/* Execute Hilbert transform (real to complex) */ \
|
|
/* _q : Hilbert transform object */ \
|
|
/* _x : real-valued input sample */ \
|
|
/* _y : complex-valued output sample */ \
|
|
void IIRHILB(_r2c_execute)(IIRHILB() _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 IIRHILB(_c2r_execute)(IIRHILB() _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 IIRHILB(_decim_execute)(IIRHILB() _q, \
|
|
T * _x, \
|
|
TC * _y); \
|
|
\
|
|
/* Execute Hilbert transform decimator (real to complex) on a block of */ \
|
|
/* samples */ \
|
|
/* _q : Hilbert transform object */ \
|
|
/* _x : real-valued input array, [size: 2*_n x 1] */ \
|
|
/* _n : number of output samples */ \
|
|
/* _y : complex-valued output array, [size: _n x 1] */ \
|
|
void IIRHILB(_decim_execute_block)(IIRHILB() _q, \
|
|
T * _x, \
|
|
unsigned int _n, \
|
|
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 IIRHILB(_interp_execute)(IIRHILB() _q, \
|
|
TC _x, \
|
|
T * _y); \
|
|
\
|
|
/* Execute Hilbert transform interpolator (complex to real) on a block */ \
|
|
/* of samples */ \
|
|
/* _q : Hilbert transform object */ \
|
|
/* _x : complex-valued input array, [size: _n x 1] */ \
|
|
/* _n : number of *input* samples */ \
|
|
/* _y : real-valued output array, [size: 2*_n x 1] */ \
|
|
void IIRHILB(_interp_execute_block)(IIRHILB() _q, \
|
|
TC * _x, \
|
|
unsigned int _n, \
|
|
T * _y); \
|
|
|
|
LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_FLOAT, float, liquid_float_complex)
|
|
//LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_DOUBLE, double, liquid_double_complex)
|
|
|
|
|
|
//
|
|
// FFT-based finite impulse response filter
|
|
//
|
|
|
|
#define LIQUID_FFTFILT_MANGLE_RRRF(name) LIQUID_CONCAT(fftfilt_rrrf,name)
|
|
#define LIQUID_FFTFILT_MANGLE_CRCF(name) LIQUID_CONCAT(fftfilt_crcf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Fast Fourier transform (FFT) finite impulse response filter */ \
|
|
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, _n >= _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 to stdout */ \
|
|
void FFTFILT(_print)(FFTFILT() _q); \
|
|
\
|
|
/* Set output scaling for filter */ \
|
|
void FFTFILT(_set_scale)(FFTFILT() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for filter */ \
|
|
void FFTFILT(_get_scale)(FFTFILT() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* Execute the filter on internal buffer and coefficients given a block */ \
|
|
/* of input samples; in-place operation is permitted (_x and _y may */ \
|
|
/* point to the same place in memory) */ \
|
|
/* _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); \
|
|
\
|
|
/* Get length of filter object's internal coefficients */ \
|
|
unsigned int FFTFILT(_get_length)(FFTFILT() _q); \
|
|
|
|
LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Infinite impulse response filter
|
|
//
|
|
|
|
#define LIQUID_IIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(iirfilt_rrrf,name)
|
|
#define LIQUID_IIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(iirfilt_crcf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Infinite impulse response (IIR) filter */ \
|
|
typedef struct IIRFILT(_s) * IIRFILT(); \
|
|
\
|
|
/* Create infinite impulse response filter from external coefficients. */ \
|
|
/* Note that the number of feed-forward and feed-back coefficients do */ \
|
|
/* not need to be equal, but they do need to be non-zero. */ \
|
|
/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \
|
|
/* equal to zero, otherwise the filter will be invalid as this value is */ \
|
|
/* factored out from all coefficients. */ \
|
|
/* For stability reasons the number of coefficients should reasonably */ \
|
|
/* not exceed about 8 for single-precision floating-point. */ \
|
|
/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \
|
|
/* _nb : number of feed-forward coefficients, _nb > 0 */ \
|
|
/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \
|
|
/* _na : number of feed-back coefficients, _na > 0 */ \
|
|
IIRFILT() IIRFILT(_create)(TC * _b, \
|
|
unsigned int _nb, \
|
|
TC * _a, \
|
|
unsigned int _na); \
|
|
\
|
|
/* Create IIR filter using 2nd-order secitons from external */ \
|
|
/* coefficients. */ \
|
|
/* _B : feed-forward coefficients [size: _nsos x 3] */ \
|
|
/* _A : feed-back coefficients [size: _nsos x 3] */ \
|
|
/* _nsos : number of second-order sections (sos), _nsos > 0 */ \
|
|
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) */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \
|
|
/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \
|
|
/* _Ap : pass-band ripple in dB, _Ap > 0 */ \
|
|
/* _As : stop-band ripple in dB, _As > 0 */ \
|
|
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 simplified low-pass Butterworth IIR filter */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
/* _fc : low-pass prototype cut-off frequency */ \
|
|
IIRFILT() IIRFILT(_create_lowpass)(unsigned int _order, \
|
|
float _fc); \
|
|
\
|
|
/* Create 8th-order integrator filter */ \
|
|
IIRFILT() IIRFILT(_create_integrator)(void); \
|
|
\
|
|
/* Create 8th-order differentiator filter */ \
|
|
IIRFILT() IIRFILT(_create_differentiator)(void); \
|
|
\
|
|
/* Create simple first-order DC-blocking filter with transfer function */ \
|
|
/* \( H(z) = \frac{1 - z^{-1}}{1 - (1-\alpha)z^{-1}} \) */ \
|
|
/* _alpha : normalized filter bandwidth, _alpha > 0 */ \
|
|
IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha); \
|
|
\
|
|
/* Create filter to operate as second-order integrating phase-locked */ \
|
|
/* loop (active lag design) */ \
|
|
/* _w : filter bandwidth, 0 < _w < 1 */ \
|
|
/* _zeta : damping factor, \( 1/\sqrt{2} \) suggested, 0 < _zeta < 1 */ \
|
|
/* _K : loop gain, 1000 suggested, _K > 0 */ \
|
|
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); \
|
|
\
|
|
/* Reset iirfilt object internals */ \
|
|
void IIRFILT(_reset)(IIRFILT() _q); \
|
|
\
|
|
/* Compute filter output given a signle input sample */ \
|
|
/* _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; */ \
|
|
/* in-place operation is permitted (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, _n > 0 */ \
|
|
/* _y : pointer to output array, [size: _n x 1] */ \
|
|
void IIRFILT(_execute_block)(IIRFILT() _q, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
\
|
|
/* Return number of coefficients for iirfilt object (maximum between */ \
|
|
/* the feed-forward and feed-back coefficients). Note that the filter */ \
|
|
/* length = filter order + 1 */ \
|
|
unsigned int IIRFILT(_get_length)(IIRFILT() _q); \
|
|
\
|
|
/* Compute complex frequency response of filter object */ \
|
|
/* _q : filter object */ \
|
|
/* _fc : normalized frequency for evaluation */ \
|
|
/* _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(LIQUID_IIRFILT_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// FIR Polyphase filter bank
|
|
//
|
|
#define LIQUID_FIRPFB_MANGLE_RRRF(name) LIQUID_CONCAT(firpfb_rrrf,name)
|
|
#define LIQUID_FIRPFB_MANGLE_CRCF(name) LIQUID_CONCAT(firpfb_crcf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Finite impulse response (FIR) polyphase filter bank (PFB) */ \
|
|
typedef struct FIRPFB(_s) * FIRPFB(); \
|
|
\
|
|
/* Create firpfb object with _M sub-filter each of length _h_len/_M */ \
|
|
/* from an external array of coefficients */ \
|
|
/* _M : number of filters in the bank, _M > 1 */ \
|
|
/* _h : coefficients, [size: _h_len x 1] */ \
|
|
/* _h_len : filter length (multiple of _M), _h_len >= _M */ \
|
|
FIRPFB() FIRPFB(_create)(unsigned int _M, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \
|
|
/* method */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
/* _m : filter semi-length [samples], _m > 0 */ \
|
|
/* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \
|
|
/* _As : filter stop-band suppression [dB], _As > 0 */ \
|
|
FIRPFB() FIRPFB(_create_kaiser)(unsigned int _M, \
|
|
unsigned int _m, \
|
|
float _fc, \
|
|
float _As); \
|
|
\
|
|
/* Create firpfb from square-root Nyquist prototype */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
/* _k : nominal samples/symbol, _k > 1 */ \
|
|
/* _m : filter delay [symbols], _m > 0 */ \
|
|
/* _beta : rolloff factor, 0 < _beta <= 1 */ \
|
|
FIRPFB() FIRPFB(_create_rnyquist)(int _type, \
|
|
unsigned int _M, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta); \
|
|
\
|
|
/* Create from square-root derivative Nyquist prototype */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
/* _k : nominal samples/symbol, _k > 1 */ \
|
|
/* _m : filter delay [symbols], _m > 0 */ \
|
|
/* _beta : rolloff factor, 0 < _beta <= 1 */ \
|
|
FIRPFB() FIRPFB(_create_drnyquist)(int _type, \
|
|
unsigned int _M, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta); \
|
|
\
|
|
/* Re-create firpfb object of potentially a different length with */ \
|
|
/* different coefficients. If the length of the filter does not change, */ \
|
|
/* not memory reallocation is invoked. */ \
|
|
/* _q : original firpfb object */ \
|
|
/* _M : number of filters in the bank, _M > 1 */ \
|
|
/* _h : coefficients, [size: _h_len x 1] */ \
|
|
/* _h_len : filter length (multiple of _M), _h_len >= _M */ \
|
|
FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, \
|
|
unsigned int _M, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Destroy firpfb object, freeing all internal memory and destroying */ \
|
|
/* all internal objects */ \
|
|
void FIRPFB(_destroy)(FIRPFB() _q); \
|
|
\
|
|
/* Print firpfb object's parameters to stdout */ \
|
|
void FIRPFB(_print)(FIRPFB() _q); \
|
|
\
|
|
/* Set output scaling for filter */ \
|
|
/* _q : filter object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRPFB(_set_scale)(FIRPFB() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for filter */ \
|
|
/* _q : filter object */ \
|
|
/* _scale : scaling factor applied to each output sample */ \
|
|
void FIRPFB(_get_scale)(FIRPFB() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* Reset firpfb object's internal buffer */ \
|
|
void FIRPFB(_reset)(FIRPFB() _q); \
|
|
\
|
|
/* Push sample into filter object's internal buffer */ \
|
|
/* _q : filter object */ \
|
|
/* _x : single input sample */ \
|
|
void FIRPFB(_push)(FIRPFB() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Execute vector dot product on the filter's internal buffer and */ \
|
|
/* coefficients using the coefficients from sub-filter at index _i */ \
|
|
/* _q : firpfb object */ \
|
|
/* _i : index of filter to use */ \
|
|
/* _y : pointer to output sample */ \
|
|
void FIRPFB(_execute)(FIRPFB() _q, \
|
|
unsigned int _i, \
|
|
TO * _y); \
|
|
\
|
|
/* Execute the filter on a block of input samples, all using index _i. */ \
|
|
/* In-place operation is permitted (_x and _y may point to the same */ \
|
|
/* place in memory) */ \
|
|
/* _q : firpfb object */ \
|
|
/* _i : index of filter to use */ \
|
|
/* _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 FIRPFB(_execute_block)(FIRPFB() _q, \
|
|
unsigned int _i, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
|
|
LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
//
|
|
// Interpolators
|
|
//
|
|
|
|
// firinterp : finite impulse response interpolator
|
|
#define LIQUID_FIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(firinterp_rrrf,name)
|
|
#define LIQUID_FIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(firinterp_crcf,name)
|
|
#define LIQUID_FIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(firinterp_cccf,name)
|
|
|
|
#define LIQUID_FIRINTERP_DEFINE_API(FIRINTERP,TO,TC,TI) \
|
|
\
|
|
/* Finite impulse response (FIR) interpolator */ \
|
|
typedef struct FIRINTERP(_s) * FIRINTERP(); \
|
|
\
|
|
/* Create interpolator from external coefficients. Internally the */ \
|
|
/* interpolator creates a polyphase filter bank to efficiently realize */ \
|
|
/* resampling of the input signal. */ \
|
|
/* If the input filter length is not a multiple of the interpolation */ \
|
|
/* factor, the object internally pads the coefficients with zeros to */ \
|
|
/* compensate. */ \
|
|
/* _M : interpolation factor, _M >= 2 */ \
|
|
/* _h : filter coefficients, [size: _h_len x 1] */ \
|
|
/* _h_len : filter length, _h_len >= _M */ \
|
|
FIRINTERP() FIRINTERP(_create)(unsigned int _M, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Create interpolator from filter prototype prototype (Kaiser-Bessel */ \
|
|
/* windowed-sinc function) */ \
|
|
/* _M : interpolation factor, _M >= 2 */ \
|
|
/* _m : filter delay [symbols], _m >= 1 */ \
|
|
/* _As : stop-band attenuation [dB], _As >= 0 */ \
|
|
FIRINTERP() FIRINTERP(_create_kaiser)(unsigned int _M, \
|
|
unsigned int _m, \
|
|
float _As); \
|
|
\
|
|
/* Create interpolator object from filter prototype */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \
|
|
/* _M : interpolation factor, _M > 1 */ \
|
|
/* _m : filter delay (symbols), _m > 0 */ \
|
|
/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \
|
|
/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \
|
|
FIRINTERP() FIRINTERP(_create_prototype)(int _type, \
|
|
unsigned int _M, \
|
|
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); \
|
|
\
|
|
/* Set output scaling for interpolator */ \
|
|
/* _q : interpolator object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRINTERP(_set_scale)(FIRINTERP() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for interpolator */ \
|
|
/* _q : interpolator object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRINTERP(_get_scale)(FIRINTERP() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* Execute interpolation on single input sample and write \(M\) output */ \
|
|
/* samples (\(M\) is the interpolation factor) */ \
|
|
/* _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(LIQUID_FIRINTERP_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
// iirinterp : infinite impulse response interpolator
|
|
#define LIQUID_IIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(iirinterp_rrrf,name)
|
|
#define LIQUID_IIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(iirinterp_crcf,name)
|
|
#define LIQUID_IIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(iirinterp_cccf,name)
|
|
|
|
#define LIQUID_IIRINTERP_DEFINE_API(IIRINTERP,TO,TC,TI) \
|
|
\
|
|
/* Infinite impulse response (IIR) interpolator */ \
|
|
typedef struct IIRINTERP(_s) * IIRINTERP(); \
|
|
\
|
|
/* Create infinite impulse response interpolator from external */ \
|
|
/* coefficients. */ \
|
|
/* Note that the number of feed-forward and feed-back coefficients do */ \
|
|
/* not need to be equal, but they do need to be non-zero. */ \
|
|
/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \
|
|
/* equal to zero, otherwise the filter will be invalid as this value is */ \
|
|
/* factored out from all coefficients. */ \
|
|
/* For stability reasons the number of coefficients should reasonably */ \
|
|
/* not exceed about 8 for single-precision floating-point. */ \
|
|
/* _M : interpolation factor, _M >= 2 */ \
|
|
/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \
|
|
/* _nb : number of feed-forward coefficients, _nb > 0 */ \
|
|
/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \
|
|
/* _na : number of feed-back coefficients, _na > 0 */ \
|
|
IIRINTERP() IIRINTERP(_create)(unsigned int _M, \
|
|
TC * _b, \
|
|
unsigned int _nb, \
|
|
TC * _a, \
|
|
unsigned int _na); \
|
|
\
|
|
/* Create interpolator object with default Butterworth prototype */ \
|
|
/* _M : interpolation factor, _M >= 2 */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, \
|
|
unsigned int _order); \
|
|
\
|
|
/* Create IIR interpolator from prototype */ \
|
|
/* _M : interpolation factor, _M >= 2 */ \
|
|
/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \
|
|
/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \
|
|
/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \
|
|
/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \
|
|
/* _Ap : pass-band ripple in dB, _Ap > 0 */ \
|
|
/* _As : stop-band ripple in dB, _As > 0 */ \
|
|
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 to stdout */ \
|
|
void IIRINTERP(_print)(IIRINTERP() _q); \
|
|
\
|
|
/* Reset interpolator object */ \
|
|
void IIRINTERP(_reset)(IIRINTERP() _q); \
|
|
\
|
|
/* Execute interpolation on single input sample and write \(M\) output */ \
|
|
/* samples (\(M\) is the interpolation factor) */ \
|
|
/* _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); \
|
|
\
|
|
/* Compute and return group delay of object */ \
|
|
/* _q : filter object */ \
|
|
/* _fc : frequency to evaluate */ \
|
|
float IIRINTERP(_groupdelay)(IIRINTERP() _q, \
|
|
float _fc); \
|
|
|
|
LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
//
|
|
// Decimators
|
|
//
|
|
|
|
// firdecim : finite impulse response decimator
|
|
#define LIQUID_FIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(firdecim_rrrf,name)
|
|
#define LIQUID_FIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(firdecim_crcf,name)
|
|
#define LIQUID_FIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(firdecim_cccf,name)
|
|
|
|
#define LIQUID_FIRDECIM_DEFINE_API(FIRDECIM,TO,TC,TI) \
|
|
\
|
|
/* Finite impulse response (FIR) decimator */ \
|
|
typedef struct FIRDECIM(_s) * FIRDECIM(); \
|
|
\
|
|
/* Create decimator from external coefficients */ \
|
|
/* _M : decimation factor, _M >= 2 */ \
|
|
/* _h : filter coefficients, [size: _h_len x 1] */ \
|
|
/* _h_len : filter length, _h_len >= _M */ \
|
|
FIRDECIM() FIRDECIM(_create)(unsigned int _M, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Create decimator from filter prototype prototype (Kaiser-Bessel */ \
|
|
/* windowed-sinc function) */ \
|
|
/* _M : decimation factor, _M >= 2 */ \
|
|
/* _m : filter delay [symbols], _m >= 1 */ \
|
|
/* _As : stop-band attenuation [dB], _As >= 0 */ \
|
|
FIRDECIM() FIRDECIM(_create_kaiser)(unsigned int _M, \
|
|
unsigned int _m, \
|
|
float _As); \
|
|
\
|
|
/* Create decimator object from filter prototype */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \
|
|
/* _M : interpolation factor, _M > 1 */ \
|
|
/* _m : filter delay (symbols), _m > 0 */ \
|
|
/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \
|
|
/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \
|
|
FIRDECIM() FIRDECIM(_create_prototype)(int _type, \
|
|
unsigned int _M, \
|
|
unsigned int _m, \
|
|
float _beta, \
|
|
float _dt); \
|
|
\
|
|
/* Destroy decimator object, freeing all internal memory */ \
|
|
void FIRDECIM(_destroy)(FIRDECIM() _q); \
|
|
\
|
|
/* Print decimator object propreties to stdout */ \
|
|
void FIRDECIM(_print)(FIRDECIM() _q); \
|
|
\
|
|
/* Reset decimator object internal state */ \
|
|
void FIRDECIM(_reset)(FIRDECIM() _q); \
|
|
\
|
|
/* Set output scaling for decimator */ \
|
|
/* _q : decimator object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRDECIM(_set_scale)(FIRDECIM() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for decimator */ \
|
|
/* _q : decimator object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void FIRDECIM(_get_scale)(FIRDECIM() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* 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, [_size: _n x 1] */ \
|
|
void FIRDECIM(_execute_block)(FIRDECIM() _q, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
|
|
LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
// iirdecim : infinite impulse response decimator
|
|
#define LIQUID_IIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(iirdecim_rrrf,name)
|
|
#define LIQUID_IIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(iirdecim_crcf,name)
|
|
#define LIQUID_IIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(iirdecim_cccf,name)
|
|
|
|
#define LIQUID_IIRDECIM_DEFINE_API(IIRDECIM,TO,TC,TI) \
|
|
\
|
|
/* Infinite impulse response (IIR) decimator */ \
|
|
typedef struct IIRDECIM(_s) * IIRDECIM(); \
|
|
\
|
|
/* Create infinite impulse response decimator from external */ \
|
|
/* coefficients. */ \
|
|
/* Note that the number of feed-forward and feed-back coefficients do */ \
|
|
/* not need to be equal, but they do need to be non-zero. */ \
|
|
/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \
|
|
/* equal to zero, otherwise the filter will be invalid as this value is */ \
|
|
/* factored out from all coefficients. */ \
|
|
/* For stability reasons the number of coefficients should reasonably */ \
|
|
/* not exceed about 8 for single-precision floating-point. */ \
|
|
/* _M : decimation factor, _M >= 2 */ \
|
|
/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \
|
|
/* _nb : number of feed-forward coefficients, _nb > 0 */ \
|
|
/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \
|
|
/* _na : number of feed-back coefficients, _na > 0 */ \
|
|
IIRDECIM() IIRDECIM(_create)(unsigned int _M, \
|
|
TC * _b, \
|
|
unsigned int _nb, \
|
|
TC * _a, \
|
|
unsigned int _na); \
|
|
\
|
|
/* Create decimator object with default Butterworth prototype */ \
|
|
/* _M : decimation factor, _M >= 2 */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
IIRDECIM() IIRDECIM(_create_default)(unsigned int _M, \
|
|
unsigned int _order); \
|
|
\
|
|
/* Create IIR decimator from prototype */ \
|
|
/* _M : decimation factor, _M >= 2 */ \
|
|
/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \
|
|
/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \
|
|
/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \
|
|
/* _order : filter order, _order > 0 */ \
|
|
/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \
|
|
/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \
|
|
/* _Ap : pass-band ripple in dB, _Ap > 0 */ \
|
|
/* _As : stop-band ripple in dB, _As > 0 */ \
|
|
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); \
|
|
\
|
|
/* Compute and return group delay of object */ \
|
|
/* _q : filter object */ \
|
|
/* _fc : frequency to evaluate */ \
|
|
float IIRDECIM(_groupdelay)(IIRDECIM() _q, \
|
|
float _fc); \
|
|
|
|
LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
|
|
//
|
|
// Half-band resampler
|
|
//
|
|
#define LIQUID_RESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(resamp2_rrrf,name)
|
|
#define LIQUID_RESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(resamp2_crcf,name)
|
|
#define LIQUID_RESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(resamp2_cccf,name)
|
|
|
|
#define LIQUID_RESAMP2_DEFINE_API(RESAMP2,TO,TC,TI) \
|
|
\
|
|
/* Half-band resampler, implemented as a dyadic (half-band) polyphase */ \
|
|
/* filter bank for interpolation, decimation, synthesis, and analysis. */ \
|
|
typedef struct RESAMP2(_s) * RESAMP2(); \
|
|
\
|
|
/* Create half-band resampler from design prototype. */ \
|
|
/* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \
|
|
/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \
|
|
/* _As : stop-band attenuation [dB], _As > 0 */ \
|
|
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), _m >= 2 */ \
|
|
/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \
|
|
/* _As : stop-band attenuation [dB], _As > 0 */ \
|
|
RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \
|
|
unsigned int _m, \
|
|
float _f0, \
|
|
float _As); \
|
|
\
|
|
/* Destroy resampler, freeing all internally-allocated memory */ \
|
|
void RESAMP2(_destroy)(RESAMP2() _q); \
|
|
\
|
|
/* print resampler object's internals to stdout */ \
|
|
void RESAMP2(_print)(RESAMP2() _q); \
|
|
\
|
|
/* Reset internal buffer */ \
|
|
void RESAMP2(_reset)(RESAMP2() _q); \
|
|
\
|
|
/* Get resampler filter delay (semi-length m) */ \
|
|
unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \
|
|
\
|
|
/* Execute resampler as half-band filter for a single input sample */ \
|
|
/* \(x\) where \(y_0\) is the output of the effective low-pass filter, */ \
|
|
/* and \(y_1\) is the output of the effective high-pass filter. */ \
|
|
/* _q : resampler 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 resampler as half-band analysis filterbank on a pair of */ \
|
|
/* sequential time-domain input samples. */ \
|
|
/* The decimated outputs of the low- and high-pass equivalent filters */ \
|
|
/* are stored in \(y_0\) and \(y_1\), respectively. */ \
|
|
/* _q : resampler 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 resampler as half-band synthesis filterbank on a pair of */ \
|
|
/* input samples. The low- and high-pass input samples are provided by */ \
|
|
/* \(x_0\) and \(x_1\), respectively. The sequential time-domain output */ \
|
|
/* samples are stored in \(y_0\) and \(y_1\). */ \
|
|
/* _q : resampler 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 resampler as half-band decimator on a pair of sequential */ \
|
|
/* time-domain input samples. */ \
|
|
/* _q : resampler object */ \
|
|
/* _x : input array [size: 2 x 1] */ \
|
|
/* _y : output sample pointer */ \
|
|
void RESAMP2(_decim_execute)(RESAMP2() _q, \
|
|
TI * _x, \
|
|
TO * _y); \
|
|
\
|
|
/* Execute resampler as half-band interpolator on a single input sample */ \
|
|
/* _q : resampler 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(LIQUID_RESAMP2_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Rational resampler
|
|
//
|
|
#define LIQUID_RRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(rresamp_rrrf,name)
|
|
#define LIQUID_RRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(rresamp_crcf,name)
|
|
#define LIQUID_RRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(rresamp_cccf,name)
|
|
|
|
#define LIQUID_RRESAMP_DEFINE_API(RRESAMP,TO,TC,TI) \
|
|
\
|
|
/* Rational rate resampler, implemented as a polyphase filterbank */ \
|
|
typedef struct RRESAMP(_s) * RRESAMP(); \
|
|
\
|
|
/* Create rational-rate resampler object from external coeffcients to */ \
|
|
/* resample at an exact rate P/Q. */ \
|
|
/* Note that to preserve the input filter coefficients, the greatest */ \
|
|
/* common divisor (gcd) is not removed internally from _P and _Q when */ \
|
|
/* this method is called. */ \
|
|
/* _P : interpolation factor, P > 0 */ \
|
|
/* _Q : decimation factor, Q > 0 */ \
|
|
/* _m : filter semi-length (delay), 0 < _m */ \
|
|
/* _h : filter coefficients, [size: 2*_P*_m x 1] */ \
|
|
RRESAMP() RRESAMP(_create)(unsigned int _P, \
|
|
unsigned int _Q, \
|
|
unsigned int _m, \
|
|
TC * _h); \
|
|
\
|
|
/* Create rational-rate resampler object from filter prototype to */ \
|
|
/* resample at an exact rate P/Q. */ \
|
|
/* Note that because the filter coefficients are computed internally */ \
|
|
/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \
|
|
/* removed to improve speed. */ \
|
|
/* _P : interpolation factor, P > 0 */ \
|
|
/* _Q : decimation factor, Q > 0 */ \
|
|
/* _m : filter semi-length (delay), 0 < _m */ \
|
|
/* _bw : filter bandwidth relative to sample rate, 0 < _bw <= 0.5 */ \
|
|
/* _As : filter stop-band attenuation [dB], 0 < _As */ \
|
|
RRESAMP() RRESAMP(_create_kaiser)(unsigned int _P, \
|
|
unsigned int _Q, \
|
|
unsigned int _m, \
|
|
float _bw, \
|
|
float _As); \
|
|
\
|
|
/* Create rational-rate resampler object from filter prototype to */ \
|
|
/* resample at an exact rate P/Q. */ \
|
|
/* Note that because the filter coefficients are computed internally */ \
|
|
/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \
|
|
/* removed to improve speed. */ \
|
|
RRESAMP() RRESAMP(_create_prototype)(int _type, \
|
|
unsigned int _P, \
|
|
unsigned int _Q, \
|
|
unsigned int _m, \
|
|
float _beta); \
|
|
\
|
|
/* Create rational resampler object with a specified resampling rate of */ \
|
|
/* exactly P/Q with default parameters. This is a simplified method to */ \
|
|
/* provide a basic resampler with a baseline set of parameters, */ \
|
|
/* abstracting away some of the complexities with the filterbank */ \
|
|
/* design. */ \
|
|
/* The default parameters are */ \
|
|
/* m = 12 (filter semi-length), */ \
|
|
/* bw = 0.5 (filter bandwidth), and */ \
|
|
/* As = 60 dB (filter stop-band attenuation) */ \
|
|
/* _P : interpolation factor, P > 0 */ \
|
|
/* _Q : decimation factor, Q > 0 */ \
|
|
RRESAMP() RRESAMP(_create_default)(unsigned int _P, \
|
|
unsigned int _Q); \
|
|
\
|
|
/* Destroy resampler object, freeing all internal memory */ \
|
|
void RRESAMP(_destroy)(RRESAMP() _q); \
|
|
\
|
|
/* Print resampler object internals to stdout */ \
|
|
void RRESAMP(_print)(RRESAMP() _q); \
|
|
\
|
|
/* Reset resampler object internals */ \
|
|
void RRESAMP(_reset)(RRESAMP() _q); \
|
|
\
|
|
/* Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) */ \
|
|
/* _q : resampler object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void RRESAMP(_set_scale)(RRESAMP() _q, \
|
|
TC _scale); \
|
|
\
|
|
/* Get output scaling for filter */ \
|
|
/* _q : resampler object */ \
|
|
/* _scale : scaling factor to apply to each output sample */ \
|
|
void RRESAMP(_get_scale)(RRESAMP() _q, \
|
|
TC * _scale); \
|
|
\
|
|
/* Get resampler delay (filter semi-length \(m\)) */ \
|
|
unsigned int RRESAMP(_get_delay)(RRESAMP() _q); \
|
|
\
|
|
/* Get original interpolation factor \(P\) when object was created */ \
|
|
/* before removing greatest common divisor */ \
|
|
unsigned int RRESAMP(_get_P)(RRESAMP() _q); \
|
|
\
|
|
/* Get internal interpolation factor of resampler, \(P\), after */ \
|
|
/* removing greatest common divisor */ \
|
|
unsigned int RRESAMP(_get_interp)(RRESAMP() _q); \
|
|
\
|
|
/* Get original decimation factor \(Q\) when object was created */ \
|
|
/* before removing greatest common divisor */ \
|
|
unsigned int RRESAMP(_get_Q)(RRESAMP() _q); \
|
|
\
|
|
/* Get internal decimation factor of resampler, \(Q\), after removing */ \
|
|
/* greatest common divisor */ \
|
|
unsigned int RRESAMP(_get_decim)(RRESAMP() _q); \
|
|
\
|
|
/* Get block length (e.g. greatest common divisor) between original P */ \
|
|
/* and Q values */ \
|
|
unsigned int RRESAMP(_get_block_len)(RRESAMP() _q); \
|
|
\
|
|
/* Get rate of resampler, \(r = P/Q\) */ \
|
|
float RRESAMP(_get_rate)(RRESAMP() _q); \
|
|
\
|
|
/* Execute rational-rate resampler on a block of input samples and */ \
|
|
/* store the resulting samples in the output array. */ \
|
|
/* Note that the size of the input and output buffers correspond to the */ \
|
|
/* values of P and Q passed when the object was created, even if they */ \
|
|
/* share a common divisor. Internally the rational resampler reduces P */ \
|
|
/* and Q by their greatest commmon denominator to reduce processing; */ \
|
|
/* however sometimes it is convenienct to create the object based on */ \
|
|
/* expected output/input block sizes. This expectation is preserved. So */ \
|
|
/* if an object is created with P=80 and Q=72, the object will */ \
|
|
/* internally set P=10 and Q=9 (with a g.c.d of 8); however when */ \
|
|
/* "execute" is called the resampler will still expect an input buffer */ \
|
|
/* of 72 and an output buffer of 80. */ \
|
|
/* _q : resamp object */ \
|
|
/* _x : input sample array, [size: Q x 1] */ \
|
|
/* _y : output sample array [size: P x 1] */ \
|
|
void RRESAMP(_execute)(RRESAMP() _q, \
|
|
TI * _x, \
|
|
TO * _y); \
|
|
|
|
LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Arbitrary resampler
|
|
//
|
|
#define LIQUID_RESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(resamp_rrrf,name)
|
|
#define LIQUID_RESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(resamp_crcf,name)
|
|
#define LIQUID_RESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(resamp_cccf,name)
|
|
|
|
#define LIQUID_RESAMP_DEFINE_API(RESAMP,TO,TC,TI) \
|
|
\
|
|
/* Arbitrary rate resampler, implemented as a polyphase filterbank */ \
|
|
typedef struct RESAMP(_s) * RESAMP(); \
|
|
\
|
|
/* Create arbitrary resampler object from filter prototype */ \
|
|
/* _rate : arbitrary resampling rate, 0 < _rate */ \
|
|
/* _m : filter semi-length (delay), 0 < _m */ \
|
|
/* _fc : filter cutoff frequency, 0 < _fc < 0.5 */ \
|
|
/* _As : filter stop-band attenuation [dB], 0 < _As */ \
|
|
/* _npfb : number of filters in the bank, 0 < _npfb */ \
|
|
RESAMP() RESAMP(_create)(float _rate, \
|
|
unsigned int _m, \
|
|
float _fc, \
|
|
float _As, \
|
|
unsigned int _npfb); \
|
|
\
|
|
/* Create arbitrary resampler object with a specified input resampling */ \
|
|
/* rate and default parameters. This is a simplified method to provide */ \
|
|
/* a basic resampler with a baseline set of parameters, abstracting */ \
|
|
/* away some of the complexities with the filterbank design. */ \
|
|
/* The default parameters are */ \
|
|
/* m = 7 (filter semi-length), */ \
|
|
/* fc = min(0.49,_rate/2) (filter cutoff frequency), */ \
|
|
/* As = 60 dB (filter stop-band attenuation), and */ \
|
|
/* npfb = 64 (number of filters in the bank). */ \
|
|
/* _rate : arbitrary resampling rate, 0 < _rate */ \
|
|
RESAMP() RESAMP(_create_default)(float _rate); \
|
|
\
|
|
/* Destroy arbitrary resampler object, freeing all internal memory */ \
|
|
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 (filter semi-length \(m\)) */ \
|
|
unsigned int RESAMP(_get_delay)(RESAMP() _q); \
|
|
\
|
|
/* Set rate of arbitrary resampler */ \
|
|
/* _q : resampling object */ \
|
|
/* _rate : new sampling rate, _rate > 0 */ \
|
|
void RESAMP(_set_rate)(RESAMP() _q, \
|
|
float _rate); \
|
|
\
|
|
/* Get rate of arbitrary resampler */ \
|
|
float RESAMP(_get_rate)(RESAMP() _q); \
|
|
\
|
|
/* adjust rate of arbitrary resampler */ \
|
|
/* _q : resampling object */ \
|
|
/* _gamma : rate adjustment factor: rate <- rate * gamma, _gamma > 0 */ \
|
|
void RESAMP(_adjust_rate)(RESAMP() _q, \
|
|
float _gamma); \
|
|
\
|
|
/* Set resampling timing phase */ \
|
|
/* _q : resampling object */ \
|
|
/* _tau : sample timing phase, -1 <= _tau <= 1 */ \
|
|
void RESAMP(_set_timing_phase)(RESAMP() _q, \
|
|
float _tau); \
|
|
\
|
|
/* Adjust resampling timing phase */ \
|
|
/* _q : resampling object */ \
|
|
/* _delta : sample timing adjustment, -1 <= _delta <= 1 */ \
|
|
void RESAMP(_adjust_timing_phase)(RESAMP() _q, \
|
|
float _delta); \
|
|
\
|
|
/* Execute arbitrary resampler on a single input sample and store the */ \
|
|
/* resulting samples in the output array. The number of output samples */ \
|
|
/* is depenent upon the resampling rate but will be at most */ \
|
|
/* \( \lceil{ r \rceil} \) samples. */ \
|
|
/* _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 input samples and store */ \
|
|
/* the resulting samples in the output array. The number of output */ \
|
|
/* samples is depenent upon the resampling rate and the number of input */ \
|
|
/* samples but will be at most \( \lceil{ r n_x \rceil} \) 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(LIQUID_RESAMP_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_RESAMP_DEFINE_API(LIQUID_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 LIQUID_MSRESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp2_rrrf,name)
|
|
#define LIQUID_MSRESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp2_crcf,name)
|
|
#define LIQUID_MSRESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp2_cccf,name)
|
|
|
|
#define LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2,TO,TC,TI) \
|
|
\
|
|
/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \
|
|
/* (half-band) polyphase filter banks for interpolation and decimation. */ \
|
|
typedef struct MSRESAMP2(_s) * MSRESAMP2(); \
|
|
\
|
|
/* Create multi-stage half-band resampler as either decimator or */ \
|
|
/* interpolator. */ \
|
|
/* _type : resampler type (e.g. LIQUID_RESAMP_DECIM) */ \
|
|
/* _num_stages : number of resampling stages, _num_stages <= 16 */ \
|
|
/* _fc : filter cut-off frequency, 0 < _fc < 0.5 */ \
|
|
/* _f0 : filter center frequency (set to zero) */ \
|
|
/* _As : stop-band attenuation [dB], _As > 0 */ \
|
|
MSRESAMP2() MSRESAMP2(_create)(int _type, \
|
|
unsigned int _num_stages, \
|
|
float _fc, \
|
|
float _f0, \
|
|
float _As); \
|
|
\
|
|
/* Destroy multi-stage half-band resampler, freeing all internal memory */ \
|
|
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 multi-stage half-band resampling rate */ \
|
|
float MSRESAMP2(_get_rate)(MSRESAMP2() _q); \
|
|
\
|
|
/* Get number of half-band resampling stages in object */ \
|
|
unsigned int MSRESAMP2(_get_num_stages)(MSRESAMP2() _q); \
|
|
\
|
|
/* Get resampling type (LIQUID_RESAMP_DECIM, LIQUID_RESAMP_INTERP) */ \
|
|
int MSRESAMP2(_get_type)(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(LIQUID_MSRESAMP2_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Multi-stage arbitrary resampler
|
|
//
|
|
#define LIQUID_MSRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp_rrrf,name)
|
|
#define LIQUID_MSRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp_crcf,name)
|
|
#define LIQUID_MSRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp_cccf,name)
|
|
|
|
#define LIQUID_MSRESAMP_DEFINE_API(MSRESAMP,TO,TC,TI) \
|
|
\
|
|
/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \
|
|
/* (half-band) polyphase filter banks followed by an arbitrary rate */ \
|
|
/* resampler for interpolation and decimation. */ \
|
|
typedef struct MSRESAMP(_s) * MSRESAMP(); \
|
|
\
|
|
/* Create multi-stage arbitrary resampler */ \
|
|
/* _r : resampling rate (output/input), _r > 0 */ \
|
|
/* _As : stop-band attenuation [dB], _As > 0 */ \
|
|
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); \
|
|
\
|
|
/* get overall resampling rate */ \
|
|
float MSRESAMP(_get_rate)(MSRESAMP() _q); \
|
|
\
|
|
/* Execute multi-stage resampler on one or more input samples. */ \
|
|
/* The number of output samples is dependent upon the resampling rate */ \
|
|
/* and the number of input samples. In general it is good practice to */ \
|
|
/* allocate at least \( \lceil{ 1 + 2 r n_x \rceil} \) samples in the */ \
|
|
/* output array to avoid overflows. */ \
|
|
/* _q : msresamp object */ \
|
|
/* _x : input sample array, [size: _nx x 1] */ \
|
|
/* _nx : input sample array size */ \
|
|
/* _y : pointer to output array for storing result */ \
|
|
/* _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(LIQUID_MSRESAMP_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Symbol timing recovery (symbol synchronizer)
|
|
//
|
|
#define LIQUID_SYMSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(symsync_rrrf,name)
|
|
#define LIQUID_SYMSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(symsync_crcf,name)
|
|
|
|
#define LIQUID_SYMSYNC_DEFINE_API(SYMSYNC,TO,TC,TI) \
|
|
\
|
|
/* Multi-rate symbol synchronizer for symbol timing recovery. */ \
|
|
typedef struct SYMSYNC(_s) * SYMSYNC(); \
|
|
\
|
|
/* Create synchronizer object from external coefficients */ \
|
|
/* _k : samples per symbol, _k >= 2 */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
/* _h : matched filter coefficients, [size: _h_len x 1] */ \
|
|
/* _h_len : length of matched filter; \( h_{len} = 2 k m + 1 \) */ \
|
|
SYMSYNC() SYMSYNC(_create)(unsigned int _k, \
|
|
unsigned int _M, \
|
|
TC * _h, \
|
|
unsigned int _h_len); \
|
|
\
|
|
/* Create square-root Nyquist symbol synchronizer from prototype */ \
|
|
/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _k : samples/symbol, _k >= 2 */ \
|
|
/* _m : symbol delay, _m > 0 */ \
|
|
/* _beta : rolloff factor, 0 <= _beta <= 1 */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta, \
|
|
unsigned int _M); \
|
|
\
|
|
/* Create symsync using Kaiser filter interpolator. This is useful when */ \
|
|
/* the input signal has its matched filter applied already. */ \
|
|
/* _k : input samples/symbol, _k >= 2 */ \
|
|
/* _m : symbol delay, _m > 0 */ \
|
|
/* _beta : rolloff factor, 0<= _beta <= 1 */ \
|
|
/* _M : number of filters in the bank, _M > 0 */ \
|
|
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 to stdout */ \
|
|
void SYMSYNC(_print)(SYMSYNC() _q); \
|
|
\
|
|
/* Reset symsync internal state */ \
|
|
void SYMSYNC(_reset)(SYMSYNC() _q); \
|
|
\
|
|
/* Lock the symbol synchronizer's loop control */ \
|
|
void SYMSYNC(_lock)(SYMSYNC() _q); \
|
|
\
|
|
/* Unlock the symbol synchronizer's loop control */ \
|
|
void SYMSYNC(_unlock)(SYMSYNC() _q); \
|
|
\
|
|
/* Set synchronizer output rate (samples/symbol) */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _k_out : output samples/symbol, _k_out > 0 */ \
|
|
void SYMSYNC(_set_output_rate)(SYMSYNC() _q, \
|
|
unsigned int _k_out); \
|
|
\
|
|
/* Set loop-filter bandwidth */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _bt : loop bandwidth, 0 <= _bt <= 1 */ \
|
|
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, [size: _nx x 1] */ \
|
|
/* _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(LIQUID_SYMSYNC_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Finite impulse response Farrow filter
|
|
//
|
|
|
|
#define LIQUID_FIRFARROW_MANGLE_RRRF(name) LIQUID_CONCAT(firfarrow_rrrf,name)
|
|
#define LIQUID_FIRFARROW_MANGLE_CRCF(name) LIQUID_CONCAT(firfarrow_crcf,name)
|
|
//#define LIQUID_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) \
|
|
\
|
|
/* Finite impulse response (FIR) Farrow filter for timing delay */ \
|
|
typedef struct FIRFARROW(_s) * FIRFARROW(); \
|
|
\
|
|
/* Create firfarrow object */ \
|
|
/* _h_len : filter length, _h_len >= 2 */ \
|
|
/* _p : polynomial order, _p >= 1 */ \
|
|
/* _fc : filter cutoff frequency, 0 <= _fc <= 0.5 */ \
|
|
/* _As : stopband attenuation [dB], _As > 0 */ \
|
|
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, -1 <= _mu <= 1 */ \
|
|
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); \
|
|
\
|
|
/* Execute firfarrow filter on block of samples. */ \
|
|
/* In-place operation is permitted (the input and output arrays may */ \
|
|
/* share 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, [size: _h_len x 1] */ \
|
|
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(LIQUID_FIRFARROW_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Order-statistic filter
|
|
//
|
|
|
|
#define LIQUID_ORDFILT_MANGLE_RRRF(name) LIQUID_CONCAT(ordfilt_rrrf,name)
|
|
|
|
// Macro:
|
|
// ORDFILT : name-mangling macro
|
|
// TO : output data type
|
|
// TC : coefficients data type
|
|
// TI : input data type
|
|
#define LIQUID_ORDFILT_DEFINE_API(ORDFILT,TO,TC,TI) \
|
|
\
|
|
/* Finite impulse response (FIR) filter */ \
|
|
typedef struct ORDFILT(_s) * ORDFILT(); \
|
|
\
|
|
/* Create a order-statistic filter (ordfilt) object by specifying */ \
|
|
/* the buffer size and appropriate sample index of order statistic. */ \
|
|
/* _n : buffer size, _n > 0 */ \
|
|
/* _k : sample index for order statistic, 0 <= _k < _n */ \
|
|
ORDFILT() ORDFILT(_create)(unsigned int _n, \
|
|
unsigned int _k); \
|
|
\
|
|
/* Create a median filter by specifying buffer semi-length. */ \
|
|
/* _m : buffer semi-length */ \
|
|
ORDFILT() ORDFILT(_create_medfilt)(unsigned int _m); \
|
|
\
|
|
/* Destroy filter object and free all internal memory */ \
|
|
void ORDFILT(_destroy)(ORDFILT() _q); \
|
|
\
|
|
/* Reset filter object's internal buffer */ \
|
|
void ORDFILT(_reset)(ORDFILT() _q); \
|
|
\
|
|
/* Print filter object information to stdout */ \
|
|
void ORDFILT(_print)(ORDFILT() _q); \
|
|
\
|
|
/* Push sample into filter object's internal buffer */ \
|
|
/* _q : filter object */ \
|
|
/* _x : single input sample */ \
|
|
void ORDFILT(_push)(ORDFILT() _q, \
|
|
TI _x); \
|
|
\
|
|
/* Write block of samples into object's internal buffer */ \
|
|
/* _q : filter object */ \
|
|
/* _x : array of input samples, [size: _n x 1] */ \
|
|
/* _n : number of input elements */ \
|
|
void ORDFILT(_write)(ORDFILT() _q, \
|
|
TI * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Execute vector dot product on the filter's internal buffer and */ \
|
|
/* coefficients */ \
|
|
/* _q : filter object */ \
|
|
/* _y : pointer to single output sample */ \
|
|
void ORDFILT(_execute)(ORDFILT() _q, \
|
|
TO * _y); \
|
|
\
|
|
/* Execute the filter on a block of input samples; in-place operation */ \
|
|
/* is permitted (_x and _y may point to the same place in memory) */ \
|
|
/* _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 ORDFILT(_execute_block)(ORDFILT() _q, \
|
|
TI * _x, \
|
|
unsigned int _n, \
|
|
TO * _y); \
|
|
|
|
LIQUID_ORDFILT_DEFINE_API(LIQUID_ORDFILT_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
|
|
// framedatastats : gather frame data
|
|
typedef struct {
|
|
unsigned int num_frames_detected;
|
|
unsigned int num_headers_valid;
|
|
unsigned int num_payloads_valid;
|
|
unsigned long int num_bytes_received;
|
|
} framedatastats_s;
|
|
|
|
// reset framedatastats object
|
|
void framedatastats_reset(framedatastats_s * _stats);
|
|
|
|
// print framedatastats object
|
|
void framedatastats_print(framedatastats_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);
|
|
|
|
//
|
|
// packet encoder/decoder
|
|
//
|
|
|
|
typedef struct qpacketmodem_s * qpacketmodem;
|
|
|
|
// create packet encoder
|
|
qpacketmodem qpacketmodem_create ();
|
|
void qpacketmodem_destroy(qpacketmodem _q);
|
|
void qpacketmodem_reset (qpacketmodem _q);
|
|
void qpacketmodem_print (qpacketmodem _q);
|
|
|
|
int qpacketmodem_configure(qpacketmodem _q,
|
|
unsigned int _payload_len,
|
|
crc_scheme _check,
|
|
fec_scheme _fec0,
|
|
fec_scheme _fec1,
|
|
int _ms);
|
|
|
|
// get length of encoded frame in symbols
|
|
unsigned int qpacketmodem_get_frame_len(qpacketmodem _q);
|
|
|
|
// get unencoded/decoded payload length (bytes)
|
|
unsigned int qpacketmodem_get_payload_len(qpacketmodem _q);
|
|
|
|
// regular access methods
|
|
unsigned int qpacketmodem_get_crc (qpacketmodem _q);
|
|
unsigned int qpacketmodem_get_fec0 (qpacketmodem _q);
|
|
unsigned int qpacketmodem_get_fec1 (qpacketmodem _q);
|
|
unsigned int qpacketmodem_get_modscheme(qpacketmodem _q);
|
|
|
|
float qpacketmodem_get_demodulator_phase_error(qpacketmodem _q);
|
|
float qpacketmodem_get_demodulator_evm(qpacketmodem _q);
|
|
|
|
// encode packet into un-modulated frame symbol indices
|
|
// _q : qpacketmodem object
|
|
// _payload : unencoded payload bytes
|
|
// _syms : encoded but un-modulated payload symbol indices
|
|
void qpacketmodem_encode_syms(qpacketmodem _q,
|
|
const unsigned char * _payload,
|
|
unsigned char * _syms);
|
|
|
|
// decode packet from demodulated frame symbol indices (hard-decision decoding)
|
|
// _q : qpacketmodem object
|
|
// _syms : received hard-decision symbol indices [size: frame_len x 1]
|
|
// _payload : recovered decoded payload bytes
|
|
int qpacketmodem_decode_syms(qpacketmodem _q,
|
|
unsigned char * _syms,
|
|
unsigned char * _payload);
|
|
|
|
// decode packet from demodulated frame bits (soft-decision decoding)
|
|
// _q : qpacketmodem object
|
|
// _bits : received soft-decision bits, [size: bps*frame_len x 1]
|
|
// _payload : recovered decoded payload bytes
|
|
int qpacketmodem_decode_bits(qpacketmodem _q,
|
|
unsigned char * _bits,
|
|
unsigned char * _payload);
|
|
|
|
// encode and modulate packet into modulated frame samples
|
|
// _q : qpacketmodem object
|
|
// _payload : unencoded payload bytes
|
|
// _frame : encoded/modulated payload symbols
|
|
void qpacketmodem_encode(qpacketmodem _q,
|
|
const unsigned char * _payload,
|
|
liquid_float_complex * _frame);
|
|
|
|
// decode packet from modulated frame samples, returning flag if CRC passed
|
|
// NOTE: hard-decision decoding
|
|
// _q : qpacketmodem object
|
|
// _frame : encoded/modulated payload symbols
|
|
// _payload : recovered decoded payload bytes
|
|
int qpacketmodem_decode(qpacketmodem _q,
|
|
liquid_float_complex * _frame,
|
|
unsigned char * _payload);
|
|
|
|
// decode packet from modulated frame samples, returning flag if CRC passed
|
|
// NOTE: soft-decision decoding
|
|
// _q : qpacketmodem object
|
|
// _frame : encoded/modulated payload symbols
|
|
// _payload : recovered decoded payload bytes
|
|
int qpacketmodem_decode_soft(qpacketmodem _q,
|
|
liquid_float_complex * _frame,
|
|
unsigned char * _payload);
|
|
|
|
int qpacketmodem_decode_soft_sym(qpacketmodem _q,
|
|
liquid_float_complex _symbol);
|
|
|
|
int qpacketmodem_decode_soft_payload(qpacketmodem _q,
|
|
unsigned char * _payload);
|
|
|
|
//
|
|
// pilot generator/synchronizer for packet burst recovery
|
|
//
|
|
|
|
// get number of pilots in frame
|
|
unsigned int qpilot_num_pilots(unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
// get length of frame with a particular payload length and pilot spacing
|
|
unsigned int qpilot_frame_len(unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
//
|
|
// pilot generator for packet burst recovery
|
|
//
|
|
|
|
typedef struct qpilotgen_s * qpilotgen;
|
|
|
|
// create packet encoder
|
|
qpilotgen qpilotgen_create(unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
qpilotgen qpilotgen_recreate(qpilotgen _q,
|
|
unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
void qpilotgen_destroy(qpilotgen _q);
|
|
void qpilotgen_reset( qpilotgen _q);
|
|
void qpilotgen_print( qpilotgen _q);
|
|
|
|
unsigned int qpilotgen_get_frame_len(qpilotgen _q);
|
|
|
|
// insert pilot symbols
|
|
void qpilotgen_execute(qpilotgen _q,
|
|
liquid_float_complex * _payload,
|
|
liquid_float_complex * _frame);
|
|
|
|
//
|
|
// pilot synchronizer for packet burst recovery
|
|
//
|
|
typedef struct qpilotsync_s * qpilotsync;
|
|
|
|
// create packet encoder
|
|
qpilotsync qpilotsync_create(unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
qpilotsync qpilotsync_recreate(qpilotsync _q,
|
|
unsigned int _payload_len,
|
|
unsigned int _pilot_spacing);
|
|
|
|
void qpilotsync_destroy(qpilotsync _q);
|
|
void qpilotsync_reset( qpilotsync _q);
|
|
void qpilotsync_print( qpilotsync _q);
|
|
|
|
unsigned int qpilotsync_get_frame_len(qpilotsync _q);
|
|
|
|
// recover frame symbols from received frame
|
|
void qpilotsync_execute(qpilotsync _q,
|
|
liquid_float_complex * _frame,
|
|
liquid_float_complex * _payload);
|
|
|
|
// get estimates
|
|
float qpilotsync_get_dphi(qpilotsync _q);
|
|
float qpilotsync_get_phi (qpilotsync _q);
|
|
float qpilotsync_get_gain(qpilotsync _q);
|
|
|
|
|
|
//
|
|
// Basic frame generator (64 bytes data payload)
|
|
//
|
|
|
|
// frame length in samples
|
|
#define LIQUID_FRAME64_LEN (1440)
|
|
|
|
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
|
|
int flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props);
|
|
|
|
// set length of user-defined portion of header
|
|
void flexframegen_set_header_len(flexframegen _q, unsigned int _len);
|
|
|
|
// set properties for header section
|
|
int flexframegen_set_header_props(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,
|
|
const unsigned char * _header,
|
|
const 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. Zeros will be written
|
|
// to the buffer if the frame is not assembled
|
|
// _q : frame generator object
|
|
// _buffer : output buffer [size: _buffer_len x 1]
|
|
// _buffer_len : output buffer length
|
|
int flexframegen_write_samples(flexframegen _q,
|
|
liquid_float_complex * _buffer,
|
|
unsigned int _buffer_len);
|
|
|
|
// 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);
|
|
|
|
// has frame been detected?
|
|
int flexframesync_is_frame_open(flexframesync _q);
|
|
|
|
// change length of user-defined region in header
|
|
void flexframesync_set_header_len(flexframesync _q,
|
|
unsigned int _len);
|
|
|
|
// enable or disable soft decoding of header
|
|
void flexframesync_decode_header_soft(flexframesync _q,
|
|
int _soft);
|
|
|
|
// enable or disable soft decoding of payload
|
|
void flexframesync_decode_payload_soft(flexframesync _q,
|
|
int _soft);
|
|
|
|
// set properties for header section
|
|
int flexframesync_set_header_props(flexframesync _q,
|
|
flexframegenprops_s * _props);
|
|
|
|
// 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);
|
|
|
|
// frame data statistics
|
|
void flexframesync_reset_framedatastats(flexframesync _q);
|
|
framedatastats_s flexframesync_get_framedatastats (flexframesync _q);
|
|
|
|
// enable/disable debugging
|
|
void flexframesync_debug_enable(flexframesync _q);
|
|
void flexframesync_debug_disable(flexframesync _q);
|
|
void flexframesync_debug_print(flexframesync _q,
|
|
const char * _filename);
|
|
|
|
//
|
|
// 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);
|
|
|
|
//
|
|
// M-FSK frame generator
|
|
//
|
|
|
|
typedef struct fskframegen_s * fskframegen;
|
|
|
|
// create M-FSK frame generator
|
|
fskframegen fskframegen_create();
|
|
void fskframegen_destroy (fskframegen _fg);
|
|
void fskframegen_print (fskframegen _fg);
|
|
void fskframegen_reset (fskframegen _fg);
|
|
void fskframegen_assemble(fskframegen _fg,
|
|
unsigned char * _header,
|
|
unsigned char * _payload,
|
|
unsigned int _payload_len,
|
|
crc_scheme _check,
|
|
fec_scheme _fec0,
|
|
fec_scheme _fec1);
|
|
unsigned int fskframegen_getframelen(fskframegen _q);
|
|
int fskframegen_write_samples(fskframegen _fg,
|
|
liquid_float_complex * _buf,
|
|
unsigned int _buf_len);
|
|
|
|
|
|
//
|
|
// M-FSK frame synchronizer
|
|
//
|
|
|
|
typedef struct fskframesync_s * fskframesync;
|
|
|
|
// create M-FSK frame synchronizer
|
|
// _callback : callback function
|
|
// _userdata : user data pointer passed to callback function
|
|
fskframesync fskframesync_create(framesync_callback _callback,
|
|
void * _userdata);
|
|
void fskframesync_destroy(fskframesync _q);
|
|
void fskframesync_print (fskframesync _q);
|
|
void fskframesync_reset (fskframesync _q);
|
|
void fskframesync_execute(fskframesync _q,
|
|
liquid_float_complex _x);
|
|
void fskframesync_execute_block(fskframesync _q,
|
|
liquid_float_complex * _x,
|
|
unsigned int _n);
|
|
|
|
// debugging
|
|
void fskframesync_debug_enable (fskframesync _q);
|
|
void fskframesync_debug_disable(fskframesync _q);
|
|
void fskframesync_debug_export (fskframesync _q, const char * _filename);
|
|
|
|
|
|
//
|
|
// GMSK frame generator
|
|
//
|
|
|
|
typedef struct gmskframegen_s * gmskframegen;
|
|
|
|
// create GMSK frame generator
|
|
gmskframegen gmskframegen_create();
|
|
void gmskframegen_destroy (gmskframegen _q);
|
|
int gmskframegen_is_assembled (gmskframegen _q);
|
|
void gmskframegen_print (gmskframegen _q);
|
|
void gmskframegen_set_header_len(gmskframegen _q, unsigned int _len);
|
|
void gmskframegen_reset (gmskframegen _q);
|
|
void gmskframegen_assemble (gmskframegen _q,
|
|
const unsigned char * _header,
|
|
const 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 _q,
|
|
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_set_header_len(gmskframesync _q, unsigned int _len);
|
|
void gmskframesync_reset(gmskframesync _q);
|
|
int gmskframesync_is_frame_open(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);
|
|
|
|
|
|
//
|
|
// DSSS frame generator
|
|
//
|
|
|
|
typedef struct {
|
|
unsigned int check;
|
|
unsigned int fec0;
|
|
unsigned int fec1;
|
|
} dsssframegenprops_s;
|
|
|
|
typedef struct dsssframegen_s * dsssframegen;
|
|
|
|
dsssframegen dsssframegen_create(dsssframegenprops_s * _props);
|
|
void dsssframegen_destroy(dsssframegen _q);
|
|
void dsssframegen_reset(dsssframegen _q);
|
|
int dsssframegen_is_assembled(dsssframegen _q);
|
|
void dsssframegen_getprops(dsssframegen _q, dsssframegenprops_s * _props);
|
|
int dsssframegen_setprops(dsssframegen _q, dsssframegenprops_s * _props);
|
|
void dsssframegen_set_header_len(dsssframegen _q, unsigned int _len);
|
|
int dsssframegen_set_header_props(dsssframegen _q,
|
|
dsssframegenprops_s * _props);
|
|
unsigned int dsssframegen_getframelen(dsssframegen _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 dsssframegen_assemble(dsssframegen _q,
|
|
const unsigned char * _header,
|
|
const unsigned char * _payload,
|
|
unsigned int _payload_len);
|
|
|
|
int dsssframegen_write_samples(dsssframegen _q,
|
|
liquid_float_complex * _buffer,
|
|
unsigned int _buffer_len);
|
|
|
|
|
|
//
|
|
// DSSS frame synchronizer
|
|
//
|
|
|
|
typedef struct dsssframesync_s * dsssframesync;
|
|
|
|
dsssframesync dsssframesync_create(framesync_callback _callback, void * _userdata);
|
|
void dsssframesync_destroy(dsssframesync _q);
|
|
void dsssframesync_print(dsssframesync _q);
|
|
void dsssframesync_reset(dsssframesync _q);
|
|
int dsssframesync_is_frame_open(dsssframesync _q);
|
|
void dsssframesync_set_header_len(dsssframesync _q,
|
|
unsigned int _len);
|
|
void dsssframesync_decode_header_soft(dsssframesync _q,
|
|
int _soft);
|
|
void dsssframesync_decode_payload_soft(dsssframesync _q,
|
|
int _soft);
|
|
int dsssframesync_set_header_props(dsssframesync _q,
|
|
dsssframegenprops_s * _props);
|
|
void dsssframesync_execute(dsssframesync _q,
|
|
liquid_float_complex * _x,
|
|
unsigned int _n);
|
|
void dsssframesync_reset_framedatastats(dsssframesync _q);
|
|
framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q);
|
|
|
|
void dsssframesync_debug_enable(dsssframesync _q);
|
|
void dsssframesync_debug_disable(dsssframesync _q);
|
|
void dsssframesync_debug_print(dsssframesync _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);
|
|
|
|
// set user-defined header length
|
|
void ofdmflexframegen_set_header_len(ofdmflexframegen _q,
|
|
unsigned int _len);
|
|
|
|
void ofdmflexframegen_set_header_props(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 (NULL pointers will use random 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,
|
|
const unsigned char * _header,
|
|
const unsigned char * _payload,
|
|
unsigned int _payload_len);
|
|
|
|
// write samples of assembled frame
|
|
// _q : OFDM frame generator object
|
|
// _buf : output buffer [size: _buf_len x 1]
|
|
// _buf_len : output buffer length
|
|
int ofdmflexframegen_write(ofdmflexframegen _q,
|
|
liquid_float_complex * _buf,
|
|
unsigned int _buf_len);
|
|
|
|
//
|
|
// 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);
|
|
// set user-defined header length
|
|
void ofdmflexframesync_set_header_len(ofdmflexframesync _q,
|
|
unsigned int _len);
|
|
|
|
void ofdmflexframesync_decode_header_soft(ofdmflexframesync _q,
|
|
int _soft);
|
|
|
|
void ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q,
|
|
int _soft);
|
|
|
|
void ofdmflexframesync_set_header_props(ofdmflexframesync _q,
|
|
ofdmflexframegenprops_s * _props);
|
|
|
|
void ofdmflexframesync_reset(ofdmflexframesync _q);
|
|
int ofdmflexframesync_is_frame_open(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);
|
|
|
|
// set the received carrier offset estimate
|
|
void ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo);
|
|
|
|
// 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 LIQUID_BSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(bsync_rrrf,name)
|
|
#define LIQUID_BSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(bsync_crcf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Binary P/N synchronizer */ \
|
|
typedef struct BSYNC(_s) * BSYNC(); \
|
|
\
|
|
/* Create bsync object */ \
|
|
/* _n : sequence length */ \
|
|
/* _v : correlation sequence [size: _n x 1] */ \
|
|
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); \
|
|
\
|
|
/* Destroy binary synchronizer object, freeing all internal memory */ \
|
|
/* _q : bsync object */ \
|
|
void BSYNC(_destroy)(BSYNC() _q); \
|
|
\
|
|
/* Print object internals to stdout */ \
|
|
/* _q : bsync object */ \
|
|
void BSYNC(_print)(BSYNC() _q); \
|
|
\
|
|
/* Correlate input signal against internal sequence */ \
|
|
/* _q : bsync object */ \
|
|
/* _x : input sample */ \
|
|
/* _y : pointer to output sample */ \
|
|
void BSYNC(_correlate)(BSYNC() _q, \
|
|
TI _x, \
|
|
TO * _y); \
|
|
|
|
LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
//
|
|
// Pre-demodulation synchronizers (binary and otherwise)
|
|
//
|
|
#define LIQUID_PRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT( presync_cccf,name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Pre-demodulation signal synchronizer */ \
|
|
typedef struct PRESYNC(_s) * PRESYNC(); \
|
|
\
|
|
/* Create pre-demod synchronizer from external sequence */ \
|
|
/* _v : baseband sequence, [size: _n x 1] */ \
|
|
/* _n : baseband sequence length, _n > 0 */ \
|
|
/* _dphi_max : maximum absolute frequency deviation for detection */ \
|
|
/* _m : number of correlators, _m > 0 */ \
|
|
PRESYNC() PRESYNC(_create)(TC * _v, \
|
|
unsigned int _n, \
|
|
float _dphi_max, \
|
|
unsigned int _m); \
|
|
\
|
|
/* Destroy pre-demod synchronizer, freeing all internal memory */ \
|
|
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 original sequence with internal input buffer */ \
|
|
/* _q : pre-demod synchronizer object */ \
|
|
/* _rxy : output cross correlation */ \
|
|
/* _dphi_hat : output frequency offset estimate */ \
|
|
void PRESYNC(_execute)(PRESYNC() _q, \
|
|
TO * _rxy, \
|
|
float * _dphi_hat); \
|
|
|
|
// non-binary pre-demodulation synchronizer
|
|
LIQUID_PRESYNC_DEFINE_API(LIQUID_PRESYNC_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
// binary pre-demodulation synchronizer
|
|
LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
//
|
|
// Frame detector
|
|
//
|
|
|
|
typedef struct qdetector_cccf_s * qdetector_cccf;
|
|
|
|
// create detector with generic sequence
|
|
// _s : sample sequence
|
|
// _s_len : length of sample sequence
|
|
qdetector_cccf qdetector_cccf_create(liquid_float_complex * _s,
|
|
unsigned int _s_len);
|
|
|
|
// create detector from sequence of symbols using internal linear interpolator
|
|
// _sequence : symbol sequence
|
|
// _sequence_len : length of symbol sequence
|
|
// _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC)
|
|
// _k : samples/symbol
|
|
// _m : filter delay
|
|
// _beta : excess bandwidth factor
|
|
qdetector_cccf qdetector_cccf_create_linear(liquid_float_complex * _sequence,
|
|
unsigned int _sequence_len,
|
|
int _ftype,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta);
|
|
|
|
// create detector from sequence of GMSK symbols
|
|
// _sequence : bit sequence
|
|
// _sequence_len : length of bit sequence
|
|
// _k : samples/symbol
|
|
// _m : filter delay
|
|
// _beta : excess bandwidth factor
|
|
qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence,
|
|
unsigned int _sequence_len,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta);
|
|
|
|
// create detector from sequence of CP-FSK symbols (assuming one bit/symbol)
|
|
// _sequence : bit sequence
|
|
// _sequence_len : length of bit sequence
|
|
// _bps : bits per symbol, 0 < _bps <= 8
|
|
// _h : modulation index, _h > 0
|
|
// _k : samples/symbol
|
|
// _m : filter delay
|
|
// _beta : filter bandwidth parameter, _beta > 0
|
|
// _type : filter type (e.g. LIQUID_CPFSK_SQUARE)
|
|
qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence,
|
|
unsigned int _sequence_len,
|
|
unsigned int _bps,
|
|
float _h,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta,
|
|
int _type);
|
|
|
|
void qdetector_cccf_destroy(qdetector_cccf _q);
|
|
void qdetector_cccf_print (qdetector_cccf _q);
|
|
void qdetector_cccf_reset (qdetector_cccf _q);
|
|
|
|
// run detector, looking for sequence; return pointer to aligned, buffered samples
|
|
void * qdetector_cccf_execute(qdetector_cccf _q,
|
|
liquid_float_complex _x);
|
|
|
|
// set detection threshold (should be between 0 and 1, good starting point is 0.5)
|
|
void qdetector_cccf_set_threshold(qdetector_cccf _q,
|
|
float _threshold);
|
|
|
|
// set carrier offset search range
|
|
void qdetector_cccf_set_range(qdetector_cccf _q,
|
|
float _dphi_max);
|
|
|
|
// access methods
|
|
unsigned int qdetector_cccf_get_seq_len (qdetector_cccf _q); // sequence length
|
|
const void * qdetector_cccf_get_sequence(qdetector_cccf _q); // pointer to sequence
|
|
unsigned int qdetector_cccf_get_buf_len (qdetector_cccf _q); // buffer length
|
|
float qdetector_cccf_get_rxy (qdetector_cccf _q); // correlator output
|
|
float qdetector_cccf_get_tau (qdetector_cccf _q); // fractional timing offset estimate
|
|
float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain
|
|
float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate
|
|
float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate
|
|
|
|
//
|
|
// 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);
|
|
|
|
|
|
//
|
|
// symbol streaming for testing (no meaningful data, just symbols)
|
|
//
|
|
#define LIQUID_SYMSTREAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(symstreamcf,name)
|
|
|
|
#define LIQUID_SYMSTREAM_DEFINE_API(SYMSTREAM,TO) \
|
|
\
|
|
/* Symbol streaming generator object */ \
|
|
typedef struct SYMSTREAM(_s) * SYMSTREAM(); \
|
|
\
|
|
/* Create symstream object with default parameters. */ \
|
|
/* This is equivalent to invoking the create_linear() method */ \
|
|
/* with _ftype=LIQUID_FIRFILT_ARKAISER, _k=2, _m=7, _beta=0.3, and */ \
|
|
/* with _ms=LIQUID_MODEM_QPSK */ \
|
|
SYMSTREAM() SYMSTREAM(_create)(void); \
|
|
\
|
|
/* Create symstream object with linear modulation */ \
|
|
/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _k : samples per symbol, _k >= 2 */ \
|
|
/* _m : filter delay (symbols), _m > 0 */ \
|
|
/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \
|
|
/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \
|
|
SYMSTREAM() SYMSTREAM(_create_linear)(int _ftype, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta, \
|
|
int _ms); \
|
|
\
|
|
/* Destroy symstream object, freeing all internal memory */ \
|
|
void SYMSTREAM(_destroy)(SYMSTREAM() _q); \
|
|
\
|
|
/* Print symstream object's parameters */ \
|
|
void SYMSTREAM(_print)(SYMSTREAM() _q); \
|
|
\
|
|
/* Reset symstream internal state */ \
|
|
void SYMSTREAM(_reset)(SYMSTREAM() _q); \
|
|
\
|
|
/* Set internal linear modulation scheme, leaving the filter parameters */ \
|
|
/* (interpolator) unmodified */ \
|
|
void SYMSTREAM(_set_scheme)(SYMSTREAM() _q, \
|
|
int _ms); \
|
|
\
|
|
/* Get internal linear modulation scheme */ \
|
|
int SYMSTREAM(_get_scheme)(SYMSTREAM() _q); \
|
|
\
|
|
/* Set internal linear gain (before interpolation) */ \
|
|
void SYMSTREAM(_set_gain)(SYMSTREAM() _q, \
|
|
float _gain); \
|
|
\
|
|
/* Get internal linear gain (before interpolation) */ \
|
|
float SYMSTREAM(_get_gain)(SYMSTREAM() _q); \
|
|
\
|
|
/* Write block of samples to output buffer */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _buf : output buffer [size: _buf_len x 1] */ \
|
|
/* _buf_len: output buffer size */ \
|
|
void SYMSTREAM(_write_samples)(SYMSTREAM() _q, \
|
|
TO * _buf, \
|
|
unsigned int _buf_len); \
|
|
|
|
LIQUID_SYMSTREAM_DEFINE_API(LIQUID_SYMSTREAM_MANGLE_CFLOAT, liquid_float_complex)
|
|
|
|
|
|
|
|
//
|
|
// multi-signal source for testing (no meaningful data, just signals)
|
|
//
|
|
|
|
#define LIQUID_MSOURCE_MANGLE_CFLOAT(name) LIQUID_CONCAT(msourcecf,name)
|
|
|
|
#define LIQUID_MSOURCE_DEFINE_API(MSOURCE,TO) \
|
|
\
|
|
/* Multi-signal source generator object */ \
|
|
typedef struct MSOURCE(_s) * MSOURCE(); \
|
|
\
|
|
/* Create msource object by specifying channelizer parameters */ \
|
|
/* _M : number of channels in analysis channelizer object */ \
|
|
/* _m : prototype channelizer filter semi-length */ \
|
|
/* _As : prototype channelizer filter stop-band suppression (dB) */ \
|
|
MSOURCE() MSOURCE(_create)(unsigned int _M, \
|
|
unsigned int _m, \
|
|
float _As); \
|
|
\
|
|
/* Create default msource object with default parameters: */ \
|
|
/* M = 1200, m = 4, As = 60 */ \
|
|
MSOURCE() MSOURCE(_create_default)(void); \
|
|
\
|
|
/* Destroy msource object */ \
|
|
void MSOURCE(_destroy)(MSOURCE() _q); \
|
|
\
|
|
/* Print msource object */ \
|
|
void MSOURCE(_print)(MSOURCE() _q); \
|
|
\
|
|
/* Reset msource object */ \
|
|
void MSOURCE(_reset)(MSOURCE() _q); \
|
|
\
|
|
/* user-defined callback for generating samples */ \
|
|
typedef int (*MSOURCE(_callback))(void * _userdata, \
|
|
TO * _v, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Add user-defined signal generator */ \
|
|
int MSOURCE(_add_user)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain, \
|
|
void * _userdata, \
|
|
MSOURCE(_callback) _callback); \
|
|
\
|
|
/* Add tone to signal generator, returning id of signal */ \
|
|
int MSOURCE(_add_tone)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain); \
|
|
\
|
|
/* Add chirp to signal generator, returning id of signal */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _duration : duration of chirp [samples] */ \
|
|
/* _negate : negate frequency direction */ \
|
|
/* _single : run single chirp? or repeatedly */ \
|
|
int MSOURCE(_add_chirp)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain, \
|
|
float _duration, \
|
|
int _negate, \
|
|
int _repeat); \
|
|
\
|
|
/* Add noise source to signal generator, returning id of signal */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _fc : ... */ \
|
|
/* _bw : ... */ \
|
|
/* _nstd : ... */ \
|
|
int MSOURCE(_add_noise)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain); \
|
|
\
|
|
/* Add modem signal source, returning id of signal */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \
|
|
/* _m : filter delay (symbols), _m > 0 */ \
|
|
/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \
|
|
int MSOURCE(_add_modem)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain, \
|
|
int _ms, \
|
|
unsigned int _m, \
|
|
float _beta); \
|
|
\
|
|
/* Add frequency-shift keying modem signal source, returning id of */ \
|
|
/* signal */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _m : bits per symbol, _bps > 0 */ \
|
|
/* _k : samples/symbol, _k >= 2^_m */ \
|
|
int MSOURCE(_add_fsk)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain, \
|
|
unsigned int _m, \
|
|
unsigned int _k); \
|
|
\
|
|
/* Add GMSK modem signal source, returning id of signal */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _m : filter delay (symbols), _m > 0 */ \
|
|
/* _bt : filter bandwidth-time factor, 0 < _bt <= 1 */ \
|
|
int MSOURCE(_add_gmsk)(MSOURCE() _q, \
|
|
float _fc, \
|
|
float _bw, \
|
|
float _gain, \
|
|
unsigned int _m, \
|
|
float _bt); \
|
|
\
|
|
/* Remove signal with a particular id, returning 0 upon success */ \
|
|
/* _q : multi-signal source object */ \
|
|
/* _id : signal source id */ \
|
|
int MSOURCE(_remove)(MSOURCE() _q, \
|
|
int _id); \
|
|
\
|
|
/* Enable signal source with a particular id */ \
|
|
int MSOURCE(_enable)(MSOURCE() _q, \
|
|
int _id); \
|
|
\
|
|
/* Disable signal source with a particular id */ \
|
|
int MSOURCE(_disable)(MSOURCE() _q, \
|
|
int _id); \
|
|
\
|
|
/* Set gain in decibels on signal */ \
|
|
/* _q : msource object */ \
|
|
/* _id : source id */ \
|
|
/* _gain : signal gain [dB] */ \
|
|
int MSOURCE(_set_gain)(MSOURCE() _q, \
|
|
int _id, \
|
|
float _gain); \
|
|
\
|
|
/* Get gain in decibels on signal */ \
|
|
/* _q : msource object */ \
|
|
/* _id : source id */ \
|
|
/* _gain : signal gain output [dB] */ \
|
|
int MSOURCE(_get_gain)(MSOURCE() _q, \
|
|
int _id, \
|
|
float * _gain); \
|
|
\
|
|
/* Get number of samples generated by the object so far */ \
|
|
/* _q : msource object */ \
|
|
/* _return : number of time-domain samples generated */ \
|
|
unsigned long long int MSOURCE(_get_num_samples)(MSOURCE() _q); \
|
|
\
|
|
/* Set carrier offset to signal */ \
|
|
/* _q : msource object */ \
|
|
/* _id : source id */ \
|
|
/* _fc : normalized carrier frequency offset, -0.5 <= _fc <= 0.5 */ \
|
|
int MSOURCE(_set_frequency)(MSOURCE() _q, \
|
|
int _id, \
|
|
float _dphi); \
|
|
\
|
|
/* Get carrier offset to signal */ \
|
|
/* _q : msource object */ \
|
|
/* _id : source id */ \
|
|
/* _fc : normalized carrier frequency offset */ \
|
|
int MSOURCE(_get_frequency)(MSOURCE() _q, \
|
|
int _id, \
|
|
float * _dphi); \
|
|
\
|
|
/* Write block of samples to output buffer */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _buf : output buffer, [size: _buf_len x 1] */ \
|
|
/* _buf_len: output buffer size */ \
|
|
void MSOURCE(_write_samples)(MSOURCE() _q, \
|
|
TO * _buf, \
|
|
unsigned int _buf_len); \
|
|
|
|
LIQUID_MSOURCE_DEFINE_API(LIQUID_MSOURCE_MANGLE_CFLOAT, liquid_float_complex)
|
|
|
|
|
|
|
|
|
|
//
|
|
// Symbol tracking: AGC > symsync > EQ > carrier recovery
|
|
//
|
|
#define LIQUID_SYMTRACK_MANGLE_RRRF(name) LIQUID_CONCAT(symtrack_rrrf,name)
|
|
#define LIQUID_SYMTRACK_MANGLE_CCCF(name) LIQUID_CONCAT(symtrack_cccf,name)
|
|
|
|
// large macro
|
|
// SYMTRACK : name-mangling macro
|
|
// T : data type, primitive
|
|
// TO : data type, output
|
|
// TC : data type, coefficients
|
|
// TI : data type, input
|
|
#define LIQUID_SYMTRACK_DEFINE_API(SYMTRACK,T,TO,TC,TI) \
|
|
\
|
|
/* Symbol synchronizer and tracking object */ \
|
|
typedef struct SYMTRACK(_s) * SYMTRACK(); \
|
|
\
|
|
/* Create symtrack object, specifying parameters for operation */ \
|
|
/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \
|
|
/* _k : samples per symbol, _k >= 2 */ \
|
|
/* _m : filter delay [symbols], _m > 0 */ \
|
|
/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \
|
|
/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \
|
|
SYMTRACK() SYMTRACK(_create)(int _ftype, \
|
|
unsigned int _k, \
|
|
unsigned int _m, \
|
|
float _beta, \
|
|
int _ms); \
|
|
\
|
|
/* Create symtrack object using default parameters. */ \
|
|
/* The default parameters are */ \
|
|
/* ftype = LIQUID_FIRFILT_ARKAISER (filter type), */ \
|
|
/* k = 2 (samples per symbol), */ \
|
|
/* m = 7 (filter delay), */ \
|
|
/* beta = 0.3 (excess bandwidth factor), and */ \
|
|
/* ms = LIQUID_MODEM_QPSK (modulation scheme) */ \
|
|
SYMTRACK() SYMTRACK(_create_default)(); \
|
|
\
|
|
/* Destroy symtrack object, freeing all internal memory */ \
|
|
void SYMTRACK(_destroy)(SYMTRACK() _q); \
|
|
\
|
|
/* Print symtrack object's parameters */ \
|
|
void SYMTRACK(_print)(SYMTRACK() _q); \
|
|
\
|
|
/* Reset symtrack internal state */ \
|
|
void SYMTRACK(_reset)(SYMTRACK() _q); \
|
|
\
|
|
/* Set symtrack modulation scheme */ \
|
|
/* _q : symtrack object */ \
|
|
/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \
|
|
void SYMTRACK(_set_modscheme)(SYMTRACK() _q, \
|
|
int _ms); \
|
|
\
|
|
/* Set symtrack internal bandwidth */ \
|
|
/* _q : symtrack object */ \
|
|
/* _bw : tracking bandwidth, _bw > 0 */ \
|
|
void SYMTRACK(_set_bandwidth)(SYMTRACK() _q, \
|
|
float _bw); \
|
|
\
|
|
/* Adjust internal NCO by requested phase */ \
|
|
/* _q : symtrack object */ \
|
|
/* _dphi : NCO phase adjustment [radians] */ \
|
|
void SYMTRACK(_adjust_phase)(SYMTRACK() _q, \
|
|
T _dphi); \
|
|
\
|
|
/* Execute synchronizer on single input sample */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _x : input data sample */ \
|
|
/* _y : output data array, [size: 2 x 1] */ \
|
|
/* _ny : number of samples written to output buffer (0, 1, or 2) */ \
|
|
void SYMTRACK(_execute)(SYMTRACK() _q, \
|
|
TI _x, \
|
|
TO * _y, \
|
|
unsigned int * _ny); \
|
|
\
|
|
/* execute synchronizer on input data array */ \
|
|
/* _q : synchronizer object */ \
|
|
/* _x : input data array */ \
|
|
/* _nx : number of input samples */ \
|
|
/* _y : output data array, [size: 2 _nx x 1] */ \
|
|
/* _ny : number of samples written to output buffer */ \
|
|
void SYMTRACK(_execute_block)(SYMTRACK() _q, \
|
|
TI * _x, \
|
|
unsigned int _nx, \
|
|
TO * _y, \
|
|
unsigned int * _ny); \
|
|
|
|
LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_RRRF,
|
|
float,
|
|
float,
|
|
float,
|
|
float)
|
|
|
|
LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_CCCF,
|
|
float,
|
|
liquid_float_complex,
|
|
liquid_float_complex,
|
|
liquid_float_complex)
|
|
|
|
|
|
|
|
//
|
|
// 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
|
|
//
|
|
|
|
// Modulation schemes available
|
|
#define LIQUID_WINDOW_NUM_FUNCTIONS (10)
|
|
|
|
// prototypes
|
|
typedef enum {
|
|
LIQUID_WINDOW_UNKNOWN=0, // unknown/unsupported scheme
|
|
|
|
LIQUID_WINDOW_HAMMING, // Hamming
|
|
LIQUID_WINDOW_HANN, // Hann
|
|
LIQUID_WINDOW_BLACKMANHARRIS, // Blackman-harris (4-term)
|
|
LIQUID_WINDOW_BLACKMANHARRIS7, // Blackman-harris (7-term)
|
|
LIQUID_WINDOW_KAISER, // Kaiser (beta factor unspecified)
|
|
LIQUID_WINDOW_FLATTOP, // flat top (includes negative values)
|
|
LIQUID_WINDOW_TRIANGULAR, // triangular
|
|
LIQUID_WINDOW_RCOSTAPER, // raised-cosine taper (taper size unspecified)
|
|
LIQUID_WINDOW_KBD, // Kaiser-Bessel derived window (beta factor unspecified)
|
|
} liquid_window_type;
|
|
|
|
// pretty names for window
|
|
extern const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2];
|
|
|
|
// Print compact list of existing and available windowing functions
|
|
void liquid_print_windows();
|
|
|
|
// returns window type based on input string
|
|
liquid_window_type liquid_getopt_str2window(const char * _str);
|
|
|
|
// 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);
|
|
|
|
// 7th order Blackman-harris window
|
|
// _n : window index
|
|
// _N : full window length
|
|
float blackmanharris7(unsigned int _n,
|
|
unsigned int _N);
|
|
|
|
// Flat-top window
|
|
// _n : window index
|
|
// _N : full window length
|
|
float flattop(unsigned int _n,
|
|
unsigned int _N);
|
|
|
|
// Triangular window
|
|
// _n : window index
|
|
// _N : full window length
|
|
// _L : triangle length, _L in {_N, _N+1, _N-1}
|
|
float triangular(unsigned int _n,
|
|
unsigned int _N,
|
|
unsigned int _L);
|
|
|
|
// raised-cosine tapering window
|
|
// _n : window index
|
|
// _t : taper length
|
|
// _N : full window length
|
|
float liquid_rcostaper_windowf(unsigned int _n,
|
|
unsigned int _t,
|
|
unsigned int _N);
|
|
|
|
|
|
// polynomials
|
|
|
|
|
|
#define LIQUID_POLY_MANGLE_DOUBLE(name) LIQUID_CONCAT(poly, name)
|
|
#define LIQUID_POLY_MANGLE_FLOAT(name) LIQUID_CONCAT(polyf, name)
|
|
|
|
#define LIQUID_POLY_MANGLE_CDOUBLE(name) LIQUID_CONCAT(polyc, name)
|
|
#define LIQUID_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 at value _x */ \
|
|
/* _p : polynomial coefficients [size _k x 1] */ \
|
|
/* _k : polynomial coefficients length, order is _k - 1 */ \
|
|
/* _x : input to evaluate polynomial */ \
|
|
T POLY(_val)(T * _p, \
|
|
unsigned int _k, \
|
|
T _x); \
|
|
\
|
|
/* Perform least-squares polynomial fit on data set */ \
|
|
/* _x : x-value sample set [size: _n x 1] */ \
|
|
/* _y : y-value sample set [size: _n x 1] */ \
|
|
/* _n : number of samples in _x and _y */ \
|
|
/* _p : polynomial coefficients output [size _k x 1] */ \
|
|
/* _k : polynomial coefficients length, order is _k - 1 */ \
|
|
void POLY(_fit)(T * _x, \
|
|
T * _y, \
|
|
unsigned int _n, \
|
|
T * _p, \
|
|
unsigned int _k); \
|
|
\
|
|
/* Perform Lagrange polynomial exact fit on data set */ \
|
|
/* _x : x-value sample set, size [_n x 1] */ \
|
|
/* _y : y-value sample set, size [_n x 1] */ \
|
|
/* _n : number of samples in _x and _y */ \
|
|
/* _p : polynomial coefficients output [size _n x 1] */ \
|
|
void POLY(_fit_lagrange)(T * _x, \
|
|
T * _y, \
|
|
unsigned int _n, \
|
|
T * _p); \
|
|
\
|
|
/* Perform Lagrange polynomial interpolation on data set without */ \
|
|
/* computing coefficients as an intermediate step. */ \
|
|
/* _x : x-value sample set [size: _n x 1] */ \
|
|
/* _y : y-value sample set [size: _n x 1] */ \
|
|
/* _n : number of samples in _x and _y */ \
|
|
/* _x0 : x-value to evaluate and compute interpolant */ \
|
|
T POLY(_interp_lagrange)(T * _x, \
|
|
T * _y, \
|
|
unsigned int _n, \
|
|
T _x0); \
|
|
\
|
|
/* Compute Lagrange polynomial fit in the barycentric form. */ \
|
|
/* _x : x-value sample set, size [_n x 1] */ \
|
|
/* _n : number of samples in _x */ \
|
|
/* _w : barycentric weights normalized so _w[0]=1, size [_n x 1] */ \
|
|
void POLY(_fit_lagrange_barycentric)(T * _x, \
|
|
unsigned int _n, \
|
|
T * _w); \
|
|
\
|
|
/* Perform Lagrange polynomial interpolation using the barycentric form */ \
|
|
/* of the weights. */ \
|
|
/* _x : x-value sample set [size: _n x 1] */ \
|
|
/* _y : y-value sample set [size: _n x 1] */ \
|
|
/* _w : barycentric weights [size: _n x 1] */ \
|
|
/* _x0 : x-value to evaluate and compute interpolant */ \
|
|
/* _n : number of samples in _x, _y, and _w */ \
|
|
T POLY(_val_lagrange_barycentric)(T * _x, \
|
|
T * _y, \
|
|
T * _w, \
|
|
T _x0, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Perform binomial expansion on 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 (coefficients has length n+1) */ \
|
|
/* _n : polynomial order */ \
|
|
/* _p : polynomial coefficients [size: _n+1 x 1] */ \
|
|
void POLY(_expandbinomial)(unsigned int _n, \
|
|
T * _p); \
|
|
\
|
|
/* Perform positive/negative binomial expansion on 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) */ \
|
|
/* _m : number of '1+x' terms */ \
|
|
/* _k : number of '1-x' terms */ \
|
|
/* _p : polynomial coefficients [size: _m+_k+1 x 1] */ \
|
|
void POLY(_expandbinomial_pm)(unsigned int _m, \
|
|
unsigned int _k, \
|
|
T * _p); \
|
|
\
|
|
/* Perform root expansion on the polynomial */ \
|
|
/* \( P_n(x) = (x-r[0]) (x-r[1]) ... (x-r[n-1]) \) */ \
|
|
/* as */ \
|
|
/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \
|
|
/* where \( r[0],r[1],...,r[n-1]\) are the roots of \( P_n(x) \). */ \
|
|
/* NOTE: _p has order _n (array is length _n+1) */ \
|
|
/* _r : roots of polynomial [size: _n x 1] */ \
|
|
/* _n : number of roots in polynomial */ \
|
|
/* _p : polynomial coefficients [size: _n+1 x 1] */ \
|
|
void POLY(_expandroots)(T * _r, \
|
|
unsigned int _n, \
|
|
T * _p); \
|
|
\
|
|
/* Perform root expansion on the polynomial */ \
|
|
/* \( P_n(x) = (xb[0]-a[0]) (xb[1]-a[1])...(xb[n-1]-a[n-1]) \) */ \
|
|
/* as */ \
|
|
/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \
|
|
/* NOTE: _p has order _n (array is length _n+1) */ \
|
|
/* _a : subtractant of polynomial rotos [size: _n x 1] */ \
|
|
/* _b : multiplicant of polynomial roots [size: _n x 1] */ \
|
|
/* _n : number of roots in polynomial */ \
|
|
/* _p : polynomial coefficients [size: _n+1 x 1] */ \
|
|
void POLY(_expandroots2)(T * _a, \
|
|
T * _b, \
|
|
unsigned int _n, \
|
|
T * _p); \
|
|
\
|
|
/* Find the complex roots of a polynomial. */ \
|
|
/* _p : polynomial coefficients [size: _n x 1] */ \
|
|
/* _k : polynomial length */ \
|
|
/* _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 */ \
|
|
/* _p : polynomial coefficients [size: _n x 1] */ \
|
|
/* _k : polynomial length */ \
|
|
/* _roots : resulting complex roots [size: _k-1 x 1] */ \
|
|
void POLY(_findroots_durandkerner)(T * _p, \
|
|
unsigned int _k, \
|
|
TC * _roots); \
|
|
\
|
|
/* Find the complex roots of the polynomial using Bairstow's method. */ \
|
|
/* _p : polynomial coefficients [size: _n x 1] */ \
|
|
/* _k : polynomial length */ \
|
|
/* _roots : resulting complex roots [size: _k-1 x 1] */ \
|
|
void POLY(_findroots_bairstow)(T * _p, \
|
|
unsigned int _k, \
|
|
TC * _roots); \
|
|
\
|
|
/* Expand the multiplication of two polynomials */ \
|
|
/* \( ( a[0] + a[1]x + a[2]x^2 + ...) (b[0] + b[1]x + b[]x^2 + ...) \) */ \
|
|
/* as */ \
|
|
/* \( c[0] + c[1]x + c[2]x^2 + ... + c[n]x^n \) */ \
|
|
/* where order(c) = order(a) + order(b) + 1 */ \
|
|
/* and therefore length(c) = length(a) + length(b) - 1 */ \
|
|
/* _a : 1st polynomial coefficients (length is _order_a+1) */ \
|
|
/* _order_a : 1st polynomial order */ \
|
|
/* _b : 2nd polynomial coefficients (length is _order_b+1) */ \
|
|
/* _order_b : 2nd polynomial order */ \
|
|
/* _c : output polynomial [size: _order_a+_order_b+1 x 1] */ \
|
|
void POLY(_mul)(T * _a, \
|
|
unsigned int _order_a, \
|
|
T * _b, \
|
|
unsigned int _order_b, \
|
|
T * _c); \
|
|
|
|
LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_DOUBLE,
|
|
double,
|
|
liquid_double_complex)
|
|
|
|
LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_FLOAT,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CDOUBLE,
|
|
liquid_double_complex,
|
|
liquid_double_complex)
|
|
|
|
LIQUID_POLY_DEFINE_API(LIQUID_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 greatest common divisor between to numbers P and Q
|
|
unsigned int liquid_gcd(unsigned int _P,
|
|
unsigned int _Q);
|
|
|
|
// 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 LIQUID_MATRIX_MANGLE_DOUBLE(name) LIQUID_CONCAT(matrix, name)
|
|
#define LIQUID_MATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(matrixf, name)
|
|
|
|
#define LIQUID_MATRIX_MANGLE_CDOUBLE(name) LIQUID_CONCAT(matrixc, name)
|
|
#define LIQUID_MATRIX_MANGLE_CFLOAT(name) LIQUID_CONCAT(matrixcf, name)
|
|
|
|
// large macro
|
|
// MATRIX : name-mangling macro
|
|
// T : data type
|
|
#define LIQUID_MATRIX_DEFINE_API(MATRIX,T) \
|
|
\
|
|
/* Print array as matrix to stdout */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _r : rows in matrix */ \
|
|
/* _c : columns in matrix */ \
|
|
void MATRIX(_print)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Perform point-wise addition between two matrices \(\vec{X}\) */ \
|
|
/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\). */ \
|
|
/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}+\vec{Y}_{i,j} \), */ \
|
|
/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _y : input matrix, [size: _r x _c] */ \
|
|
/* _z : output matrix, [size: _r x _c] */ \
|
|
/* _r : number of rows in each matrix */ \
|
|
/* _c : number of columns in each matrix */ \
|
|
void MATRIX(_add)(T * _x, \
|
|
T * _y, \
|
|
T * _z, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Perform point-wise subtraction between two matrices \(\vec{X}\) */ \
|
|
/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \
|
|
/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}-\vec{Y}_{i,j} \), */ \
|
|
/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _y : input matrix, [size: _r x _c] */ \
|
|
/* _z : output matrix, [size: _r x _c] */ \
|
|
/* _r : number of rows in each matrix */ \
|
|
/* _c : number of columns in each matrix */ \
|
|
void MATRIX(_sub)(T * _x, \
|
|
T * _y, \
|
|
T * _z, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Perform point-wise multiplication between two matrices \(\vec{X}\) */ \
|
|
/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \
|
|
/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j} \vec{Y}_{i,j} \), */ \
|
|
/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _y : input matrix, [size: _r x _c] */ \
|
|
/* _z : output matrix, [size: _r x _c] */ \
|
|
/* _r : number of rows in each matrix */ \
|
|
/* _c : number of columns in each matrix */ \
|
|
void MATRIX(_pmul)(T * _x, \
|
|
T * _y, \
|
|
T * _z, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Perform point-wise division between two matrices \(\vec{X}\) */ \
|
|
/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \
|
|
/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}/\vec{Y}_{i,j} \), */ \
|
|
/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _y : input matrix, [size: _r x _c] */ \
|
|
/* _z : output matrix, [size: _r x _c] */ \
|
|
/* _r : number of rows in each matrix */ \
|
|
/* _c : number of columns in each matrix */ \
|
|
void MATRIX(_pdiv)(T * _x, \
|
|
T * _y, \
|
|
T * _z, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Multiply two matrices \(\vec{X}\) and \(\vec{Y}\), storing the */ \
|
|
/* result in \(\vec{Z}\). */ \
|
|
/* NOTE: _rz = _rx, _cz = _cy, and _cx = _ry */ \
|
|
/* _x : input matrix, [size: _rx x _cx] */ \
|
|
/* _rx : number of rows in _x */ \
|
|
/* _cx : number of columns in _x */ \
|
|
/* _y : input matrix, [size: _ry x _cy] */ \
|
|
/* _ry : number of rows in _y */ \
|
|
/* _cy : number of columns in _y */ \
|
|
/* _z : output matrix, [size: _rz x _cz] */ \
|
|
/* _rz : number of rows in _z */ \
|
|
/* _cz : number of columns in _z */ \
|
|
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); \
|
|
\
|
|
/* Solve \(\vec{X} = \vec{Y} \vec{Z}\) for \(\vec{Z}\) for square */ \
|
|
/* matrices of size \(n\) */ \
|
|
/* _x : input matrix, [size: _n x _n] */ \
|
|
/* _y : input matrix, [size: _n x _n] */ \
|
|
/* _z : output matrix, [size: _n x _n] */ \
|
|
/* _n : number of rows and columns in each matrix */ \
|
|
void MATRIX(_div)(T * _x, \
|
|
T * _y, \
|
|
T * _z, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Compute the determinant of a square matrix \(\vec{X}\) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
T MATRIX(_det)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Compute the in-place transpose of the matrix \(\vec{X}\) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_trans)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Compute the in-place Hermitian transpose of the matrix \(\vec{X}\) */ \
|
|
/* _x : input matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_hermitian)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Compute \(\vec{X}\vec{X}^T\) on a \(m \times n\) matrix. */ \
|
|
/* The result is a \(m \times m\) matrix. */ \
|
|
/* _x : input matrix, [size: _m x _n] */ \
|
|
/* _m : input rows */ \
|
|
/* _n : input columns */ \
|
|
/* _xxT : output matrix, [size: _m x _m] */ \
|
|
void MATRIX(_mul_transpose)(T * _x, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T * _xxT); \
|
|
\
|
|
/* Compute \(\vec{X}^T\vec{X}\) on a \(m \times n\) matrix. */ \
|
|
/* The result is a \(n \times n\) matrix. */ \
|
|
/* _x : input matrix, [size: _m x _n] */ \
|
|
/* _m : input rows */ \
|
|
/* _n : input columns */ \
|
|
/* _xTx : output matrix, [size: _n x _n] */ \
|
|
void MATRIX(_transpose_mul)(T * _x, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T * _xTx); \
|
|
\
|
|
/* Compute \(\vec{X}\vec{X}^H\) on a \(m \times n\) matrix. */ \
|
|
/* The result is a \(m \times m\) matrix. */ \
|
|
/* _x : input matrix, [size: _m x _n] */ \
|
|
/* _m : input rows */ \
|
|
/* _n : input columns */ \
|
|
/* _xxH : output matrix, [size: _m x _m] */ \
|
|
void MATRIX(_mul_hermitian)(T * _x, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T * _xxH); \
|
|
\
|
|
/* Compute \(\vec{X}^H\vec{X}\) on a \(m \times n\) matrix. */ \
|
|
/* The result is a \(n \times n\) matrix. */ \
|
|
/* _x : input matrix, [size: _m x _n] */ \
|
|
/* _m : input rows */ \
|
|
/* _n : input columns */ \
|
|
/* _xHx : output matrix, [size: _n x _n] */ \
|
|
void MATRIX(_hermitian_mul)(T * _x, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T * _xHx); \
|
|
\
|
|
\
|
|
/* Augment two matrices \(\vec{X}\) and \(\vec{Y}\), storing the result */ \
|
|
/* in \(\vec{Z}\) */ \
|
|
/* NOTE: _rz = _rx = _ry, _rx = _ry, and _cz = _cx + _cy */ \
|
|
/* _x : input matrix, [size: _rx x _cx] */ \
|
|
/* _rx : number of rows in _x */ \
|
|
/* _cx : number of columns in _x */ \
|
|
/* _y : input matrix, [size: _ry x _cy] */ \
|
|
/* _ry : number of rows in _y */ \
|
|
/* _cy : number of columns in _y */ \
|
|
/* _z : output matrix, [size: _rz x _cz] */ \
|
|
/* _rz : number of rows in _z */ \
|
|
/* _cz : number of columns in _z */ \
|
|
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); \
|
|
\
|
|
/* Compute the inverse of a square matrix \(\vec{X}\) */ \
|
|
/* _x : input/output matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_inv)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Generate the identity square matrix of size \(n\) */ \
|
|
/* _x : output matrix, [size: _n x _n] */ \
|
|
/* _n : dimensions of _x */ \
|
|
void MATRIX(_eye)(T * _x, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Generate the all-ones matrix of size \(n\) */ \
|
|
/* _x : output matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_ones)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Generate the all-zeros matrix of size \(n\) */ \
|
|
/* _x : output matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_zeros)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Perform Gauss-Jordan elimination on matrix \(\vec{X}\) */ \
|
|
/* _x : input/output matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
void MATRIX(_gjelim)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c); \
|
|
\
|
|
/* Pivot on element \(\vec{X}_{i,j}\) */ \
|
|
/* _x : output matrix, [size: _r x _c] */ \
|
|
/* _r : rows of _x */ \
|
|
/* _c : columns of _x */ \
|
|
/* _i : pivot row */ \
|
|
/* _j : pivot column */ \
|
|
void MATRIX(_pivot)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c, \
|
|
unsigned int _i, \
|
|
unsigned int _j); \
|
|
\
|
|
/* Swap rows _r1 and _r2 of matrix \(\vec{X}\) */ \
|
|
/* _x : input/output matrix, [size: _r x _c] */ \
|
|
/* _r : rows of _x */ \
|
|
/* _c : columns of _x */ \
|
|
/* _r1 : first row to swap */ \
|
|
/* _r2 : second row to swap */ \
|
|
void MATRIX(_swaprows)(T * _x, \
|
|
unsigned int _r, \
|
|
unsigned int _c, \
|
|
unsigned int _r1, \
|
|
unsigned int _r2); \
|
|
\
|
|
/* Solve linear system of \(n\) equations: \(\vec{A}\vec{x} = \vec{b}\) */ \
|
|
/* _A : system matrix, [size: _n x _n] */ \
|
|
/* _n : system size */ \
|
|
/* _b : equality vector, [size: _n x 1] */ \
|
|
/* _x : solution vector, [size: _n x 1] */ \
|
|
/* _opts : options (ignored for now) */ \
|
|
void MATRIX(_linsolve)(T * _A, \
|
|
unsigned int _n, \
|
|
T * _b, \
|
|
T * _x, \
|
|
void * _opts); \
|
|
\
|
|
/* Solve linear system of equations using conjugate gradient method. */ \
|
|
/* _A : symmetric positive definite square matrix */ \
|
|
/* _n : system dimension */ \
|
|
/* _b : equality, [size: _n x 1] */ \
|
|
/* _x : solution estimate, [size: _n x 1] */ \
|
|
/* _opts : options (ignored for now) */ \
|
|
void MATRIX(_cgsolve)(T * _A, \
|
|
unsigned int _n, \
|
|
T * _b, \
|
|
T * _x, \
|
|
void * _opts); \
|
|
\
|
|
/* Perform L/U/P decomposition using Crout's method */ \
|
|
/* _x : input/output matrix, [size: _rx x _cx] */ \
|
|
/* _rx : rows of _x */ \
|
|
/* _cx : columns of _x */ \
|
|
/* _L : first row to swap */ \
|
|
/* _U : first row to swap */ \
|
|
/* _P : first row to swap */ \
|
|
void MATRIX(_ludecomp_crout)(T * _x, \
|
|
unsigned int _rx, \
|
|
unsigned int _cx, \
|
|
T * _L, \
|
|
T * _U, \
|
|
T * _P); \
|
|
\
|
|
/* Perform L/U/P decomposition, Doolittle's method */ \
|
|
/* _x : input/output matrix, [size: _rx x _cx] */ \
|
|
/* _rx : rows of _x */ \
|
|
/* _cx : columns of _x */ \
|
|
/* _L : first row to swap */ \
|
|
/* _U : first row to swap */ \
|
|
/* _P : first row to swap */ \
|
|
void MATRIX(_ludecomp_doolittle)(T * _x, \
|
|
unsigned int _rx, \
|
|
unsigned int _cx, \
|
|
T * _L, \
|
|
T * _U, \
|
|
T * _P); \
|
|
\
|
|
/* Perform orthnormalization using the Gram-Schmidt algorithm */ \
|
|
/* _A : input matrix, [size: _r x _c] */ \
|
|
/* _r : rows */ \
|
|
/* _c : columns */ \
|
|
/* _v : output matrix */ \
|
|
void MATRIX(_gramschmidt)(T * _A, \
|
|
unsigned int _r, \
|
|
unsigned int _c, \
|
|
T * _v); \
|
|
\
|
|
/* Perform Q/R decomposition using the Gram-Schmidt algorithm such that */ \
|
|
/* \( \vec{A} = \vec{Q} \vec{R} \) */ \
|
|
/* and \( \vec{Q}^T \vec{Q} = \vec{I}_n \) */ \
|
|
/* and \(\vec{R\}\) is a diagonal \(m \times m\) matrix */ \
|
|
/* NOTE: all matrices are square */ \
|
|
/* _A : input matrix, [size: _m x _m] */ \
|
|
/* _m : rows */ \
|
|
/* _n : columns (same as cols) */ \
|
|
/* _Q : output matrix, [size: _m x _m] */ \
|
|
/* _R : output matrix, [size: _m x _m] */ \
|
|
void MATRIX(_qrdecomp_gramschmidt)(T * _A, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T * _Q, \
|
|
T * _R); \
|
|
\
|
|
/* Compute Cholesky decomposition of a symmetric/Hermitian */ \
|
|
/* positive-definite matrix as \( \vec{A} = \vec{L}\vec{L}^T \) */ \
|
|
/* _A : input square matrix, [size: _n x _n] */ \
|
|
/* _n : input matrix dimension */ \
|
|
/* _L : output lower-triangular matrix */ \
|
|
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(LIQUID_MATRIX_MANGLE_FLOAT, float)
|
|
LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_DOUBLE, double)
|
|
|
|
LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CFLOAT, liquid_float_complex)
|
|
LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CDOUBLE, liquid_double_complex)
|
|
|
|
|
|
#define LIQUID_SMATRIX_MANGLE_BOOL(name) LIQUID_CONCAT(smatrixb, name)
|
|
#define LIQUID_SMATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(smatrixf, name)
|
|
#define LIQUID_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) \
|
|
\
|
|
/* Sparse matrix object (similar to MacKay, Davey, Lafferty convention) */ \
|
|
typedef struct SMATRIX(_s) * SMATRIX(); \
|
|
\
|
|
/* Create _M x _N sparse matrix, initialized with zeros */ \
|
|
SMATRIX() SMATRIX(_create)(unsigned int _M, \
|
|
unsigned int _N); \
|
|
\
|
|
/* Create _M x _N sparse matrix, initialized on array */ \
|
|
/* _x : input matrix, [size: _m x _n] */ \
|
|
/* _m : number of rows in input matrix */ \
|
|
/* _n : number of columns in input matrix */ \
|
|
SMATRIX() SMATRIX(_create_array)(T * _x, \
|
|
unsigned int _m, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Destroy object, freeing all internal memory */ \
|
|
void SMATRIX(_destroy)(SMATRIX() _q); \
|
|
\
|
|
/* Print sparse matrix in compact form to stdout */ \
|
|
void SMATRIX(_print)(SMATRIX() _q); \
|
|
\
|
|
/* Print sparse matrix in expanded form to stdout */ \
|
|
void SMATRIX(_print_expanded)(SMATRIX() _q); \
|
|
\
|
|
/* Get size of sparse matrix (number of rows and columns) */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : number of rows in matrix */ \
|
|
/* _n : number of columns in matrix */ \
|
|
void SMATRIX(_size)(SMATRIX() _q, \
|
|
unsigned int * _m, \
|
|
unsigned int * _n); \
|
|
\
|
|
/* Zero all elements and retain allocated memory */ \
|
|
void SMATRIX(_clear)(SMATRIX() _q); \
|
|
\
|
|
/* Zero all elements and clear memory */ \
|
|
void SMATRIX(_reset)(SMATRIX() _q); \
|
|
\
|
|
/* Determine if value has been set (allocated memory) */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : row index of value to query */ \
|
|
/* _n : column index of value to query */ \
|
|
int SMATRIX(_isset)(SMATRIX() _q, \
|
|
unsigned int _m, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Insert an element at index, allocating memory as necessary */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : row index of value to insert */ \
|
|
/* _n : column index of value to insert */ \
|
|
/* _v : value to insert */ \
|
|
void SMATRIX(_insert)(SMATRIX() _q, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T _v); \
|
|
\
|
|
/* Delete an element at index, freeing memory */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : row index of value to delete */ \
|
|
/* _n : column index of value to delete */ \
|
|
void SMATRIX(_delete)(SMATRIX() _q, \
|
|
unsigned int _m, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Set the value in matrix at specified row and column, allocating */ \
|
|
/* memory if needed */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : row index of value to set */ \
|
|
/* _n : column index of value to set */ \
|
|
/* _v : value to set in matrix */ \
|
|
void SMATRIX(_set)(SMATRIX() _q, \
|
|
unsigned int _m, \
|
|
unsigned int _n, \
|
|
T _v); \
|
|
\
|
|
/* Get the value from matrix at specified row and column */ \
|
|
/* _q : sparse matrix object */ \
|
|
/* _m : row index of value to get */ \
|
|
/* _n : column index of value to get */ \
|
|
T SMATRIX(_get)(SMATRIX() _q, \
|
|
unsigned int _m, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Initialize to identity matrix; set all diagonal elements to 1, all */ \
|
|
/* others to 0. This is done with both square and non-square matrices. */ \
|
|
void SMATRIX(_eye)(SMATRIX() _q); \
|
|
\
|
|
/* Multiply two sparse matrices, \( \vec{Z} = \vec{X} \vec{Y} \) */ \
|
|
/* _x : sparse matrix object (input) */ \
|
|
/* _y : sparse matrix object (input) */ \
|
|
/* _z : sparse matrix object (output) */ \
|
|
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(LIQUID_SMATRIX_MANGLE_BOOL, unsigned char)
|
|
LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_FLOAT, float)
|
|
LIQUID_SMATRIX_DEFINE_API(LIQUID_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) \
|
|
\
|
|
/* Linear modulator/demodulator (modem) object */ \
|
|
typedef struct MODEM(_s) * MODEM(); \
|
|
\
|
|
/* Create digital modem object with a particular scheme */ \
|
|
/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \
|
|
MODEM() MODEM(_create)(modulation_scheme _scheme); \
|
|
\
|
|
/* Create linear digital modem object with arbitrary constellation */ \
|
|
/* points defined by an external table of symbols. */ \
|
|
/* _table : array of complex constellation points, [size: _M x 1] */ \
|
|
/* _M : modulation order and table size, _M must be power of 2 */ \
|
|
MODEM() MODEM(_create_arbitrary)(TC * _table, \
|
|
unsigned int _M); \
|
|
\
|
|
/* Recreate modulation scheme, re-allocating memory as necessary */ \
|
|
/* _q : modem object */ \
|
|
/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \
|
|
MODEM() MODEM(_recreate)(MODEM() _q, \
|
|
modulation_scheme _scheme); \
|
|
\
|
|
/* Destroy modem object, freeing all allocated memory */ \
|
|
void MODEM(_destroy)(MODEM() _q); \
|
|
\
|
|
/* Print modem status to stdout */ \
|
|
void MODEM(_print)(MODEM() _q); \
|
|
\
|
|
/* Reset internal state of modem object; note that this is only */ \
|
|
/* relevant for modulation types that retain an internal state such as */ \
|
|
/* LIQUID_MODEM_DPSK4 as most linear modulation types are stateless */ \
|
|
void MODEM(_reset)(MODEM() _q); \
|
|
\
|
|
/* Generate random symbol for modulation */ \
|
|
unsigned int MODEM(_gen_rand_sym)(MODEM() _q); \
|
|
\
|
|
/* Get number of bits per symbol (bps) of modem object */ \
|
|
unsigned int MODEM(_get_bps)(MODEM() _q); \
|
|
\
|
|
/* Get modulation scheme of modem object */ \
|
|
modulation_scheme MODEM(_get_scheme)(MODEM() _q); \
|
|
\
|
|
/* Modulate input symbol (bits) and generate output complex sample */ \
|
|
/* _q : modem object */ \
|
|
/* _s : input symbol, 0 <= _s <= M-1 */ \
|
|
/* _y : output complex sample */ \
|
|
void MODEM(_modulate)(MODEM() _q, \
|
|
unsigned int _s, \
|
|
TC * _y); \
|
|
\
|
|
/* Demodulate input sample and provide maximum-likelihood estimate of */ \
|
|
/* symbol that would have generated it. */ \
|
|
/* The output is a hard decision value on the input sample. */ \
|
|
/* This is performed efficiently by taking advantage of symmetry on */ \
|
|
/* most modulation types. */ \
|
|
/* For example, square and rectangular quadrature amplitude modulation */ \
|
|
/* with gray coding can use a bisection search indepdently on its */ \
|
|
/* in-phase and quadrature channels. */ \
|
|
/* Arbitrary modulation schemes are relatively slow, however, for large */ \
|
|
/* modulation types as the demodulator must compute the distance */ \
|
|
/* between the received sample and all possible symbols to derive the */ \
|
|
/* optimal symbol. */ \
|
|
/* _q : modem object */ \
|
|
/* _x : input sample */ \
|
|
/* _s : output hard symbol, 0 <= _s <= M-1 */ \
|
|
void MODEM(_demodulate)(MODEM() _q, \
|
|
TC _x, \
|
|
unsigned int * _s); \
|
|
\
|
|
/* Demodulate input sample and provide (approximate) log-likelihood */ \
|
|
/* ratio (LLR, soft bits) as an output. */ \
|
|
/* Similarly to the hard-decision demodulation method, this is computed */ \
|
|
/* efficiently for most modulation types. */ \
|
|
/* _q : modem object */ \
|
|
/* _x : input sample */ \
|
|
/* _s : output hard symbol, 0 <= _s <= M-1 */ \
|
|
/* _soft_bits : output soft bits, [size: log2(M) x 1] */ \
|
|
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);
|
|
|
|
//
|
|
// continuous phase frequency-shift keying (CP-FSK) modems
|
|
//
|
|
|
|
// CP-FSK filter prototypes
|
|
typedef enum {
|
|
LIQUID_CPFSK_SQUARE=0, // square pulse
|
|
LIQUID_CPFSK_RCOS_FULL, // raised-cosine (full response)
|
|
LIQUID_CPFSK_RCOS_PARTIAL, // raised-cosine (partial response)
|
|
LIQUID_CPFSK_GMSK, // Gauss minimum-shift keying pulse
|
|
} liquid_cpfsk_filter;
|
|
|
|
// CP-FSK modulator
|
|
typedef struct cpfskmod_s * cpfskmod;
|
|
|
|
// create cpfskmod object (frequency modulator)
|
|
// _bps : bits per symbol, _bps > 0
|
|
// _h : modulation index, _h > 0
|
|
// _k : samples/symbol, _k > 1, _k even
|
|
// _m : filter delay (symbols), _m > 0
|
|
// _beta : filter bandwidth parameter, _beta > 0
|
|
// _type : filter type (e.g. LIQUID_CPFSK_SQUARE)
|
|
cpfskmod cpfskmod_create(unsigned int _bps,
|
|
float _h,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta,
|
|
int _type);
|
|
//cpfskmod cpfskmod_create_msk(unsigned int _k);
|
|
//cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT);
|
|
|
|
// destroy cpfskmod object
|
|
void cpfskmod_destroy(cpfskmod _q);
|
|
|
|
// print cpfskmod object internals
|
|
void cpfskmod_print(cpfskmod _q);
|
|
|
|
// reset state
|
|
void cpfskmod_reset(cpfskmod _q);
|
|
|
|
// get transmit delay [symbols]
|
|
unsigned int cpfskmod_get_delay(cpfskmod _q);
|
|
|
|
// modulate sample
|
|
// _q : frequency modulator object
|
|
// _s : input symbol
|
|
// _y : output sample array [size: _k x 1]
|
|
void cpfskmod_modulate(cpfskmod _q,
|
|
unsigned int _s,
|
|
liquid_float_complex * _y);
|
|
|
|
|
|
|
|
// CP-FSK demodulator
|
|
typedef struct cpfskdem_s * cpfskdem;
|
|
|
|
// create cpfskdem object (frequency modulator)
|
|
// _bps : bits per symbol, _bps > 0
|
|
// _h : modulation index, _h > 0
|
|
// _k : samples/symbol, _k > 1, _k even
|
|
// _m : filter delay (symbols), _m > 0
|
|
// _beta : filter bandwidth parameter, _beta > 0
|
|
// _type : filter type (e.g. LIQUID_CPFSK_SQUARE)
|
|
cpfskdem cpfskdem_create(unsigned int _bps,
|
|
float _h,
|
|
unsigned int _k,
|
|
unsigned int _m,
|
|
float _beta,
|
|
int _type);
|
|
//cpfskdem cpfskdem_create_msk(unsigned int _k);
|
|
//cpfskdem cpfskdem_create_gmsk(unsigned int _k, float _BT);
|
|
|
|
// destroy cpfskdem object
|
|
void cpfskdem_destroy(cpfskdem _q);
|
|
|
|
// print cpfskdem object internals
|
|
void cpfskdem_print(cpfskdem _q);
|
|
|
|
// reset state
|
|
void cpfskdem_reset(cpfskdem _q);
|
|
|
|
// get receive delay [symbols]
|
|
unsigned int cpfskdem_get_delay(cpfskdem _q);
|
|
|
|
#if 0
|
|
// demodulate array of samples
|
|
// _q : continuous-phase frequency demodulator object
|
|
// _y : input sample array [size: _n x 1]
|
|
// _n : input sample array length
|
|
// _s : output symbol array
|
|
// _nw : number of output symbols written
|
|
void cpfskdem_demodulate(cpfskdem _q,
|
|
liquid_float_complex * _y,
|
|
unsigned int _n,
|
|
unsigned int * _s,
|
|
unsigned int * _nw);
|
|
#else
|
|
// demodulate array of samples, assuming perfect timing
|
|
// _q : continuous-phase frequency demodulator object
|
|
// _y : input sample array [size: _k x 1]
|
|
unsigned int cpfskdem_demodulate(cpfskdem _q,
|
|
liquid_float_complex * _y);
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// M-ary frequency-shift keying (MFSK) modems
|
|
//
|
|
|
|
// FSK modulator
|
|
typedef struct fskmod_s * fskmod;
|
|
|
|
// create fskmod object (frequency modulator)
|
|
// _m : bits per symbol, _bps > 0
|
|
// _k : samples/symbol, _k >= 2^_m
|
|
// _bandwidth : total signal bandwidth, (0,0.5)
|
|
fskmod fskmod_create(unsigned int _m,
|
|
unsigned int _k,
|
|
float _bandwidth);
|
|
|
|
// destroy fskmod object
|
|
void fskmod_destroy(fskmod _q);
|
|
|
|
// print fskmod object internals
|
|
void fskmod_print(fskmod _q);
|
|
|
|
// reset state
|
|
void fskmod_reset(fskmod _q);
|
|
|
|
// modulate sample
|
|
// _q : frequency modulator object
|
|
// _s : input symbol
|
|
// _y : output sample array [size: _k x 1]
|
|
void fskmod_modulate(fskmod _q,
|
|
unsigned int _s,
|
|
liquid_float_complex * _y);
|
|
|
|
|
|
|
|
// FSK demodulator
|
|
typedef struct fskdem_s * fskdem;
|
|
|
|
// create fskdem object (frequency demodulator)
|
|
// _m : bits per symbol, _bps > 0
|
|
// _k : samples/symbol, _k >= 2^_m
|
|
// _bandwidth : total signal bandwidth, (0,0.5)
|
|
fskdem fskdem_create(unsigned int _m,
|
|
unsigned int _k,
|
|
float _bandwidth);
|
|
|
|
// destroy fskdem object
|
|
void fskdem_destroy(fskdem _q);
|
|
|
|
// print fskdem object internals
|
|
void fskdem_print(fskdem _q);
|
|
|
|
// reset state
|
|
void fskdem_reset(fskdem _q);
|
|
|
|
// demodulate symbol, assuming perfect symbol timing
|
|
// _q : fskdem object
|
|
// _y : input sample array [size: _k x 1]
|
|
unsigned int fskdem_demodulate(fskdem _q,
|
|
liquid_float_complex * _y);
|
|
|
|
// get demodulator frequency error
|
|
float fskdem_get_frequency_error(fskdem _q);
|
|
|
|
// get energy for a particular symbol within a certain range
|
|
float fskdem_get_symbol_energy(fskdem _q,
|
|
unsigned int _s,
|
|
unsigned int _range);
|
|
|
|
|
|
//
|
|
// 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) \
|
|
\
|
|
/* Analog frequency modulation object */ \
|
|
typedef struct FREQMOD(_s) * FREQMOD(); \
|
|
\
|
|
/* Create freqmod object with a particular modulation factor */ \
|
|
/* _kf : modulation factor */ \
|
|
FREQMOD() FREQMOD(_create)(float _kf); \
|
|
\
|
|
/* Destroy freqmod object, freeing all internal memory */ \
|
|
void FREQMOD(_destroy)(FREQMOD() _q); \
|
|
\
|
|
/* Print freqmod object internals to stdout */ \
|
|
void FREQMOD(_print)(FREQMOD() _q); \
|
|
\
|
|
/* Reset state */ \
|
|
void FREQMOD(_reset)(FREQMOD() _q); \
|
|
\
|
|
/* Modulate single sample, producing single output sample at complex */ \
|
|
/* baseband. */ \
|
|
/* _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) \
|
|
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
|
|
// _type : AM type (e.g. LIQUID_AMPMODEM_DSB)
|
|
// _suppressed_carrier : carrier suppression flag
|
|
ampmodem ampmodem_create(float _mod_index,
|
|
liquid_ampmodem_type _type,
|
|
int _suppressed_carrier);
|
|
|
|
// destroy ampmodem object
|
|
void ampmodem_destroy(ampmodem _q);
|
|
|
|
// print ampmodem object internals
|
|
void ampmodem_print(ampmodem _q);
|
|
|
|
// reset ampmodem object state
|
|
void ampmodem_reset(ampmodem _q);
|
|
|
|
// accessor methods
|
|
unsigned int ampmodem_get_delay_mod (ampmodem _q);
|
|
unsigned int ampmodem_get_delay_demod(ampmodem _q);
|
|
|
|
// modulate sample
|
|
void ampmodem_modulate(ampmodem _q,
|
|
float _x,
|
|
liquid_float_complex * _y);
|
|
|
|
void ampmodem_modulate_block(ampmodem _q,
|
|
float * _m,
|
|
unsigned int _n,
|
|
liquid_float_complex * _s);
|
|
|
|
// demodulate sample
|
|
void ampmodem_demodulate(ampmodem _q,
|
|
liquid_float_complex _y,
|
|
float * _x);
|
|
|
|
void ampmodem_demodulate_block(ampmodem _q,
|
|
liquid_float_complex * _r,
|
|
unsigned int _n,
|
|
float * _m);
|
|
|
|
//
|
|
// 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 LIQUID_FIRPFBCH_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch_crcf,name)
|
|
#define LIQUID_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(LIQUID_FIRPFBCH_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
LIQUID_FIRPFBCH_DEFINE_API(LIQUID_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 LIQUID_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-length, 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-length, 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(LIQUID_FIRPFBCH2_MANGLE_CRCF,
|
|
liquid_float_complex,
|
|
float,
|
|
liquid_float_complex)
|
|
|
|
//
|
|
// Finite impulse response polyphase filterbank channelizer
|
|
// with output rate Fs * P / M
|
|
//
|
|
|
|
#define LIQUID_FIRPFBCHR_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbchr_crcf,name)
|
|
|
|
#define LIQUID_FIRPFBCHR_DEFINE_API(FIRPFBCHR,TO,TC,TI) \
|
|
typedef struct FIRPFBCHR(_s) * FIRPFBCHR(); \
|
|
\
|
|
/* create rational rate resampling channelizer (firpfbchr) object by */ \
|
|
/* specifying filter coefficients directly */ \
|
|
/* _M : number of output channels in chanelizer */ \
|
|
/* _P : output decimation factor (output rate is 1/P the input) */ \
|
|
/* _m : prototype filter semi-length, length=2*M*m */ \
|
|
/* _h : prototype filter coefficient array, [size: 2*M*m x 1] */ \
|
|
FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _M, \
|
|
unsigned int _P, \
|
|
unsigned int _m, \
|
|
TC * _h); \
|
|
\
|
|
/* create rational rate resampling channelizer (firpfbchr) object by */ \
|
|
/* specifying filter design parameters for Kaiser prototype */ \
|
|
/* _M : number of output channels in chanelizer */ \
|
|
/* _P : output decimation factor (output rate is 1/P the input) */ \
|
|
/* _m : prototype filter semi-length, length=2*M*m */ \
|
|
/* _As : filter stop-band attenuation [dB] */ \
|
|
FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _M, \
|
|
unsigned int _P, \
|
|
unsigned int _m, \
|
|
float _As); \
|
|
\
|
|
/* destroy firpfbchr object, freeing internal memory */ \
|
|
void FIRPFBCHR(_destroy)(FIRPFBCHR() _q); \
|
|
\
|
|
/* reset firpfbchr object internal state and buffers */ \
|
|
void FIRPFBCHR(_reset)(FIRPFBCHR() _q); \
|
|
\
|
|
/* print firpfbchr object internals to stdout */ \
|
|
void FIRPFBCHR(_print)(FIRPFBCHR() _q); \
|
|
\
|
|
/* get number of output channels to channelizer */ \
|
|
unsigned int FIRPFBCHR(_get_M)(FIRPFBCHR() _q); \
|
|
\
|
|
/* get decimation factor for channelizer */ \
|
|
unsigned int FIRPFBCHR(_get_P)(FIRPFBCHR() _q); \
|
|
\
|
|
/* get semi-length to channelizer filter prototype */ \
|
|
unsigned int FIRPFBCHR(_get_m)(FIRPFBCHR() _q); \
|
|
\
|
|
/* push buffer of samples into filter bank */ \
|
|
/* _q : channelizer object */ \
|
|
/* _x : channelizer input [size: P x 1] */ \
|
|
void FIRPFBCHR(_push)(FIRPFBCHR() _q, \
|
|
TI * _x); \
|
|
\
|
|
/* execute filterbank channelizer, writing complex baseband samples for */ \
|
|
/* each channel into output array */ \
|
|
/* _q : channelizer object */ \
|
|
/* _y : channelizer output [size: _M x 1] */ \
|
|
void FIRPFBCHR(_execute)(FIRPFBCHR() _q, \
|
|
TO * _y); \
|
|
|
|
|
|
LIQUID_FIRPFBCHR_DEFINE_API(LIQUID_FIRPFBCHR_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);
|
|
|
|
// initialize default subcarrier allocation
|
|
// _M : number of subcarriers
|
|
// _f0 : lower frequency band, _f0 in [-0.5,0.5]
|
|
// _f1 : upper frequency band, _f1 in [-0.5,0.5]
|
|
// _p : output subcarrier allocation array, [size: _M x 1]
|
|
void ofdmframe_init_sctype_range(unsigned int _M,
|
|
float _f0,
|
|
float _f1,
|
|
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);
|
|
int ofdmframesync_is_frame_open(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
|
|
|
|
// set methods
|
|
void ofdmframesync_set_cfo(ofdmframesync _q, float _cfo); // set 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 LIQUID_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) \
|
|
\
|
|
/* Numerically-controlled oscillator object */ \
|
|
typedef struct NCO(_s) * NCO(); \
|
|
\
|
|
/* Create nco object with either fixed-point or floating-point phase */ \
|
|
/* _type : oscillator type, _type in {LIQUID_NCO, LIQUID_VCO} */ \
|
|
NCO() NCO(_create)(liquid_ncotype _type); \
|
|
\
|
|
/* Destroy nco object, freeing all internally allocated memory */ \
|
|
void NCO(_destroy)(NCO() _q); \
|
|
\
|
|
/* Print nco object internals to stdout */ \
|
|
void NCO(_print)(NCO() _q); \
|
|
\
|
|
/* Set phase/frequency to zero and reset the phase-locked loop filter */ \
|
|
/* state */ \
|
|
void NCO(_reset)(NCO() _q); \
|
|
\
|
|
/* Get frequency of nco object in radians per sample */ \
|
|
T NCO(_get_frequency)(NCO() _q); \
|
|
\
|
|
/* Set frequency of nco object in radians per sample */ \
|
|
/* _q : nco object */ \
|
|
/* _dtheta : input frequency [radians/sample] */ \
|
|
void NCO(_set_frequency)(NCO() _q, \
|
|
T _dtheta); \
|
|
\
|
|
/* Adjust frequency of nco object by a step size in radians per sample */ \
|
|
/* _q : nco object */ \
|
|
/* _step : input frequency step [radians/sample] */ \
|
|
void NCO(_adjust_frequency)(NCO() _q, \
|
|
T _step); \
|
|
\
|
|
/* Get phase of nco object in radians */ \
|
|
T NCO(_get_phase)(NCO() _q); \
|
|
\
|
|
/* Set phase of nco object in radians */ \
|
|
/* _q : nco object */ \
|
|
/* _phi : input phase of nco object [radians] */ \
|
|
void NCO(_set_phase)(NCO() _q, \
|
|
T _phi); \
|
|
\
|
|
/* Adjust phase of nco object by a step of \(\Delta \phi\) radians */ \
|
|
/* _q : nco object */ \
|
|
/* _dphi : input nco object phase adjustment [radians] */ \
|
|
void NCO(_adjust_phase)(NCO() _q, \
|
|
T _dphi); \
|
|
\
|
|
/* Increment phase by internal phase step (frequency) */ \
|
|
void NCO(_step)(NCO() _q); \
|
|
\
|
|
/* Compute sine output given internal phase */ \
|
|
T NCO(_sin)(NCO() _q); \
|
|
\
|
|
/* Compute cosine output given internal phase */ \
|
|
T NCO(_cos)(NCO() _q); \
|
|
\
|
|
/* Compute sine and cosine outputs given internal phase */ \
|
|
/* _q : nco object */ \
|
|
/* _s : output sine component of phase */ \
|
|
/* _c : output cosine component of phase */ \
|
|
void NCO(_sincos)(NCO() _q, \
|
|
T * _s, \
|
|
T * _c); \
|
|
\
|
|
/* Compute complex exponential output given internal phase */ \
|
|
/* _q : nco object */ \
|
|
/* _y : output complex exponential */ \
|
|
void NCO(_cexpf)(NCO() _q, \
|
|
TC * _y); \
|
|
\
|
|
/* Set bandwidth of internal phase-locked loop */ \
|
|
/* _q : nco object */ \
|
|
/* _bw : input phase-locked loop bandwidth, _bw >= 0 */ \
|
|
void NCO(_pll_set_bandwidth)(NCO() _q, \
|
|
T _bw); \
|
|
\
|
|
/* Step internal phase-locked loop given input phase error, adjusting */ \
|
|
/* internal phase and frequency proportional to coefficients defined by */ \
|
|
/* internal PLL bandwidth */ \
|
|
/* _q : nco object */ \
|
|
/* _dphi : input phase-locked loop phase error */ \
|
|
void NCO(_pll_step)(NCO() _q, \
|
|
T _dphi); \
|
|
\
|
|
/* Rotate input sample up by nco angle. */ \
|
|
/* Note that this does not adjust the internal phase or frequency. */ \
|
|
/* _q : nco object */ \
|
|
/* _x : input complex sample */ \
|
|
/* _y : pointer to output sample location */ \
|
|
void NCO(_mix_up)(NCO() _q, \
|
|
TC _x, \
|
|
TC * _y); \
|
|
\
|
|
/* Rotate input sample down by nco angle. */ \
|
|
/* Note that this does not adjust the internal phase or frequency. */ \
|
|
/* _q : nco object */ \
|
|
/* _x : input complex sample */ \
|
|
/* _y : pointer to output sample location */ \
|
|
void NCO(_mix_down)(NCO() _q, \
|
|
TC _x, \
|
|
TC * _y); \
|
|
\
|
|
/* Rotate input vector up by NCO angle (stepping) */ \
|
|
/* Note that this *does* adjust the internal phase as the signal steps */ \
|
|
/* through each input sample. */ \
|
|
/* _q : nco object */ \
|
|
/* _x : array of input samples, [size: _n x 1] */ \
|
|
/* _y : array of output samples, [size: _n x 1] */ \
|
|
/* _n : number of input (and output) samples */ \
|
|
void NCO(_mix_block_up)(NCO() _q, \
|
|
TC * _x, \
|
|
TC * _y, \
|
|
unsigned int _n); \
|
|
\
|
|
/* Rotate input vector down by NCO angle (stepping) */ \
|
|
/* Note that this *does* adjust the internal phase as the signal steps */ \
|
|
/* through each input sample. */ \
|
|
/* _q : nco object */ \
|
|
/* _x : array of input samples, [size: _n x 1] */ \
|
|
/* _y : array of output samples, [size: _n x 1] */ \
|
|
/* _n : number of input (and output) samples */ \
|
|
void NCO(_mix_block_down)(NCO() _q, \
|
|
TC * _x, \
|
|
TC * _y, \
|
|
unsigned int _n); \
|
|
|
|
// Define nco APIs
|
|
LIQUID_NCO_DEFINE_API(LIQUID_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);
|
|
|
|
#define SYNTH_MANGLE_FLOAT(name) LIQUID_CONCAT(synth_crcf, name)
|
|
|
|
// large macro
|
|
// SYNTH : name-mangling macro
|
|
// T : primitive data type
|
|
// TC : input/output data type
|
|
#define LIQUID_SYNTH_DEFINE_API(SYNTH,T,TC) \
|
|
typedef struct SYNTH(_s) * SYNTH(); \
|
|
\
|
|
SYNTH() SYNTH(_create)(const TC *_table, unsigned int _length); \
|
|
void SYNTH(_destroy)(SYNTH() _q); \
|
|
\
|
|
void SYNTH(_reset)(SYNTH() _q); \
|
|
\
|
|
/* get/set/adjust internal frequency/phase */ \
|
|
T SYNTH(_get_frequency)( SYNTH() _q); \
|
|
void SYNTH(_set_frequency)( SYNTH() _q, T _f); \
|
|
void SYNTH(_adjust_frequency)(SYNTH() _q, T _df); \
|
|
T SYNTH(_get_phase)( SYNTH() _q); \
|
|
void SYNTH(_set_phase)( SYNTH() _q, T _phi); \
|
|
void SYNTH(_adjust_phase)( SYNTH() _q, T _dphi); \
|
|
\
|
|
unsigned int SYNTH(_get_length)(SYNTH() _q); \
|
|
TC SYNTH(_get_current)(SYNTH() _q); \
|
|
TC SYNTH(_get_half_previous)(SYNTH() _q); \
|
|
TC SYNTH(_get_half_next)(SYNTH() _q); \
|
|
\
|
|
void SYNTH(_step)(SYNTH() _q); \
|
|
\
|
|
/* pll : phase-locked loop */ \
|
|
void SYNTH(_pll_set_bandwidth)(SYNTH() _q, T _bandwidth); \
|
|
void SYNTH(_pll_step)(SYNTH() _q, T _dphi); \
|
|
\
|
|
/* Rotate input sample up by SYNTH angle (no stepping) */ \
|
|
void SYNTH(_mix_up)(SYNTH() _q, TC _x, TC *_y); \
|
|
\
|
|
/* Rotate input sample down by SYNTH angle (no stepping) */ \
|
|
void SYNTH(_mix_down)(SYNTH() _q, TC _x, TC *_y); \
|
|
\
|
|
/* Rotate input vector up by SYNTH angle (stepping) */ \
|
|
void SYNTH(_mix_block_up)(SYNTH() _q, \
|
|
TC *_x, \
|
|
TC *_y, \
|
|
unsigned int _N); \
|
|
\
|
|
/* Rotate input vector down by SYNTH angle (stepping) */ \
|
|
void SYNTH(_mix_block_down)(SYNTH() _q, \
|
|
TC *_x, \
|
|
TC *_y, \
|
|
unsigned int _N); \
|
|
\
|
|
void SYNTH(_spread)(SYNTH() _q, \
|
|
TC _x, \
|
|
TC *_y); \
|
|
\
|
|
void SYNTH(_despread)(SYNTH() _q, \
|
|
TC *_x, \
|
|
TC *_y); \
|
|
\
|
|
void SYNTH(_despread_triple)(SYNTH() _q, \
|
|
TC *_x, \
|
|
TC *_early, \
|
|
TC *_punctual, \
|
|
TC *_late); \
|
|
|
|
// Define synth APIs
|
|
LIQUID_SYNTH_DEFINE_API(SYNTH_MANGLE_FLOAT, float, liquid_float_complex)
|
|
|
|
|
|
|
|
//
|
|
// 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_reset(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 LIQUID_QUANTIZER_MANGLE_FLOAT(name) LIQUID_CONCAT(quantizerf, name)
|
|
#define LIQUID_QUANTIZER_MANGLE_CFLOAT(name) LIQUID_CONCAT(quantizercf, name)
|
|
|
|
// large macro
|
|
// QUANTIZER : name-mangling macro
|
|
// T : data type
|
|
#define LIQUID_QUANTIZER_DEFINE_API(QUANTIZER,T) \
|
|
\
|
|
/* Amplitude quantization object */ \
|
|
typedef struct QUANTIZER(_s) * QUANTIZER(); \
|
|
\
|
|
/* Create quantizer object given compander type, input range, and the */ \
|
|
/* number of bits to represent the output */ \
|
|
/* _ctype : compander type (linear, mulaw, alaw) */ \
|
|
/* _range : maximum abosolute input range (ignored for now) */ \
|
|
/* _num_bits : number of bits per sample */ \
|
|
QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, \
|
|
float _range, \
|
|
unsigned int _num_bits); \
|
|
\
|
|
/* Destroy object, freeing all internally-allocated memory. */ \
|
|
void QUANTIZER(_destroy)(QUANTIZER() _q); \
|
|
\
|
|
/* Print object properties to stdout, including compander type and */ \
|
|
/* number of bits per sample */ \
|
|
void QUANTIZER(_print)(QUANTIZER() _q); \
|
|
\
|
|
/* Execute quantizer as analog-to-digital converter, accepting input */ \
|
|
/* sample and returning digitized output bits */ \
|
|
/* _q : quantizer object */ \
|
|
/* _x : input sample */ \
|
|
/* _s : output bits */ \
|
|
void QUANTIZER(_execute_adc)(QUANTIZER() _q, \
|
|
T _x, \
|
|
unsigned int * _s); \
|
|
\
|
|
/* Execute quantizer as digital-to-analog converter, accepting input */ \
|
|
/* bits and returning representation of original input sample */ \
|
|
/* _q : quantizer object */ \
|
|
/* _s : input bits */ \
|
|
/* _x : output sample */ \
|
|
void QUANTIZER(_execute_dac)(QUANTIZER() _q, \
|
|
unsigned int _s, \
|
|
T * _x); \
|
|
|
|
LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_FLOAT, float)
|
|
LIQUID_QUANTIZER_DEFINE_API(LIQUID_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);
|
|
|
|
// Uniform random number generator with arbitrary bounds, [a,b)
|
|
float randuf(float _a, float _b);
|
|
float randuf_pdf(float _x, float _a, float _b);
|
|
float randuf_cdf(float _x, float _a, float _b);
|
|
|
|
// 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_reset(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);
|
|
|
|
// get scale for constant, particularly for plotting purposes
|
|
// _val : input value (e.g. 100e6)
|
|
// _unit : output unit character (e.g. 'M')
|
|
// _scale : output scale (e.g. 1e-6)
|
|
void liquid_get_scale(float _val,
|
|
char * _unit,
|
|
float * _scale);
|
|
|
|
//
|
|
// MODULE : vector
|
|
//
|
|
|
|
#define LIQUID_VECTOR_MANGLE_RF(name) LIQUID_CONCAT(liquid_vectorf, name)
|
|
#define LIQUID_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 pointwise: 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 pointwise: 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(LIQUID_VECTOR_MANGLE_RF, float, float)
|
|
LIQUID_VECTOR_DEFINE_API(LIQUID_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__
|
|
|