| 1 | /**************************************************************************** |
|---|
| 2 | |
|---|
| 3 | Copyright 2007 Virginia Polytechnic Institute and State University |
|---|
| 4 | |
|---|
| 5 | This file is part of the OSSIE Signal Processing C Library. |
|---|
| 6 | |
|---|
| 7 | OSSIE Signal Processing C Library is free software; you can redistribute it |
|---|
| 8 | and/or modify it under the terms of the GNU General Public License as |
|---|
| 9 | published by the Free Software Foundation; either version 2 of the License, |
|---|
| 10 | or (at your option) any later version. |
|---|
| 11 | |
|---|
| 12 | OSSIE Signal Processing C Library is distributed in the hope that it will be |
|---|
| 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | GNU General Public License for more details. |
|---|
| 16 | |
|---|
| 17 | You should have received a copy of the GNU General Public License along |
|---|
| 18 | with OSSIE Signal Processing C Library; if not, write to the Free Software |
|---|
| 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | ****************************************************************************/ |
|---|
| 23 | |
|---|
| 24 | #ifndef __SIG_PROC_C_H__ |
|---|
| 25 | #define __SIG_PROC_C_H__ |
|---|
| 26 | |
|---|
| 27 | #include <stdio.h> |
|---|
| 28 | #include <stdlib.h> |
|---|
| 29 | #include <string.h> |
|---|
| 30 | #include <math.h> |
|---|
| 31 | |
|---|
| 32 | #ifdef __cplusplus |
|---|
| 33 | extern "C" |
|---|
| 34 | { |
|---|
| 35 | #endif /* __cplusplus */ |
|---|
| 36 | |
|---|
| 37 | #ifdef FPM |
|---|
| 38 | #include "fixed.h" |
|---|
| 39 | #endif |
|---|
| 40 | |
|---|
| 41 | #define PI 3.14159265358979f |
|---|
| 42 | #define TWO_PI 6.28318530717959f |
|---|
| 43 | |
|---|
| 44 | //----------------------------------------------------------------------------- |
|---|
| 45 | // |
|---|
| 46 | // Design root raised-cosine filter |
|---|
| 47 | // |
|---|
| 48 | //----------------------------------------------------------------------------- |
|---|
| 49 | void design_rrc_filter( |
|---|
| 50 | unsigned int k, // samples per symbol |
|---|
| 51 | unsigned int m, // delay |
|---|
| 52 | float beta, // rolloff factor ( 0 < beta <= 1 ) |
|---|
| 53 | float * h // pointer to filter coefficients |
|---|
| 54 | ); |
|---|
| 55 | |
|---|
| 56 | //----------------------------------------------------------------------------- |
|---|
| 57 | // |
|---|
| 58 | // Design Gaussian filter |
|---|
| 59 | // |
|---|
| 60 | //----------------------------------------------------------------------------- |
|---|
| 61 | void design_gaussian_filter( |
|---|
| 62 | unsigned int k, // samples per symbol |
|---|
| 63 | unsigned int m, // delay |
|---|
| 64 | float beta, // rolloff factor ( 0 < beta <= 1 ) |
|---|
| 65 | float * h // pointer to filter coefficients |
|---|
| 66 | ); |
|---|
| 67 | |
|---|
| 68 | //----------------------------------------------------------------------------- |
|---|
| 69 | // |
|---|
| 70 | // Design low-pass butterworth filter |
|---|
| 71 | // |
|---|
| 72 | //----------------------------------------------------------------------------- |
|---|
| 73 | void design_butter_lowpass_filter( |
|---|
| 74 | unsigned int order, // filter order |
|---|
| 75 | float wc, // cutoff frequency |
|---|
| 76 | float *b, // feedback |
|---|
| 77 | float *a // feedforward |
|---|
| 78 | ); |
|---|
| 79 | |
|---|
| 80 | //----------------------------------------------------------------------------- |
|---|
| 81 | // |
|---|
| 82 | // Circular buffer |
|---|
| 83 | // |
|---|
| 84 | //----------------------------------------------------------------------------- |
|---|
| 85 | /** \brief Circlar buffer structure |
|---|
| 86 | * |
|---|
| 87 | * \section CB_basic_description Basic Description |
|---|
| 88 | * The circular buffer template class implementation minimizes memory copies |
|---|
| 89 | * by wrapping the array around to its beginning. Elements can be added |
|---|
| 90 | * and removed by invoking the Push() and Pop() methods, respectively. |
|---|
| 91 | * |
|---|
| 92 | * \section CB_creating Creating Buffers |
|---|
| 93 | * There are three ways to create a buffer... |
|---|
| 94 | * \code |
|---|
| 95 | * // 1. generate an empty buffer |
|---|
| 96 | * CircularBuffer <short> v1(100); |
|---|
| 97 | * |
|---|
| 98 | * // 2. wrap an existing array |
|---|
| 99 | * short * x = new short[100]; |
|---|
| 100 | * for (unsigned int i=0; i<100; i++) |
|---|
| 101 | * x[i] = i; |
|---|
| 102 | * CircularBuffer <short> v2(x, 100); |
|---|
| 103 | * |
|---|
| 104 | * // 3. copy from another CircularBuffer |
|---|
| 105 | * CircularBuffer <short> v3(v2); |
|---|
| 106 | * \endcode |
|---|
| 107 | * |
|---|
| 108 | * \section CB_resizing_buffers Resizing Buffers |
|---|
| 109 | * CircularBuffer supports dynamic memory allocation as well; if an instance |
|---|
| 110 | * of CircularBuffer is created of a particular size and then later it is |
|---|
| 111 | * determined that the size is too small, invoking SetBufferSize() can be used |
|---|
| 112 | * to increase the length without loss of data. However, decreasing the buffer |
|---|
| 113 | * size beyond the number of elements in the buffer truncates the data. |
|---|
| 114 | * |
|---|
| 115 | * \section CB_wrapping Wrapping |
|---|
| 116 | * When the buffer is full and another element is pushed, the new element |
|---|
| 117 | * overwrites the last element in the buffer without warning. Status of the |
|---|
| 118 | * buffer can be checked with the GetBufferSize() and GetNumElements() |
|---|
| 119 | * methods. |
|---|
| 120 | * |
|---|
| 121 | */ |
|---|
| 122 | |
|---|
| 123 | struct circular_buffer { |
|---|
| 124 | float * v; |
|---|
| 125 | unsigned int len; |
|---|
| 126 | unsigned int head_index; |
|---|
| 127 | }; |
|---|
| 128 | |
|---|
| 129 | typedef struct circular_buffer circular_buffer_t; |
|---|
| 130 | |
|---|
| 131 | /// Create circular buffer object, including memory allocation |
|---|
| 132 | circular_buffer_t * circular_buffer_create(unsigned int buffer_lenth); |
|---|
| 133 | |
|---|
| 134 | /// Initialize circular buffer object |
|---|
| 135 | void circular_buffer_initialize(circular_buffer_t * c, float * _v, unsigned int buffer_length); |
|---|
| 136 | |
|---|
| 137 | /// Push value into buffer |
|---|
| 138 | void circular_buffer_push(circular_buffer_t * c, float x); |
|---|
| 139 | |
|---|
| 140 | /// Index value within buffer |
|---|
| 141 | float circular_buffer_value(circular_buffer_t * c, unsigned int i); |
|---|
| 142 | |
|---|
| 143 | /// Linearize a circular buffer object |
|---|
| 144 | void circular_buffer_linearize(circular_buffer_t * c); |
|---|
| 145 | |
|---|
| 146 | /// Get pointer to linearized buffer object |
|---|
| 147 | float * circular_buffer_getpointer(circular_buffer_t * c); |
|---|
| 148 | |
|---|
| 149 | /// Print buffer values to screen |
|---|
| 150 | void circular_buffer_print(circular_buffer_t * c); |
|---|
| 151 | |
|---|
| 152 | /// Destroy circular buffer object, free memory |
|---|
| 153 | void circular_buffer_destroy(circular_buffer_t * c); |
|---|
| 154 | |
|---|
| 155 | //----------------------------------------------------------------------------- |
|---|
| 156 | // |
|---|
| 157 | // P/N Sequence |
|---|
| 158 | // |
|---|
| 159 | //----------------------------------------------------------------------------- |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | //----------------------------------------------------------------------------- |
|---|
| 163 | // |
|---|
| 164 | // Automatic Gain Control class |
|---|
| 165 | // |
|---|
| 166 | //----------------------------------------------------------------------------- |
|---|
| 167 | /** \brief Automatic gain control signal processor |
|---|
| 168 | * |
|---|
| 169 | * \cite R. G. Lyons, Understanding Digital Signal Processing, 2nd ed. New Jersey: |
|---|
| 170 | * Prentice Hall, 2004. |
|---|
| 171 | */ |
|---|
| 172 | |
|---|
| 173 | //----------------------------------------------------------------------------- |
|---|
| 174 | // |
|---|
| 175 | // FIR polyphase filter bank |
|---|
| 176 | // |
|---|
| 177 | //----------------------------------------------------------------------------- |
|---|
| 178 | /** \brief Finite impulse response (FIR) polyphase filter bank |
|---|
| 179 | * |
|---|
| 180 | * This class implementes a finite impulse response (FIR) polyphase filter |
|---|
| 181 | * bank useful for decimators that need to interpolate samples in digital |
|---|
| 182 | * receivers. |
|---|
| 183 | * |
|---|
| 184 | * The filter bank can automatically calculate filter coefficients for |
|---|
| 185 | * prototypes commonly used in communications systems. Currently, such |
|---|
| 186 | * supported filter prototypes are |
|---|
| 187 | * - root raised-cosine |
|---|
| 188 | * |
|---|
| 189 | * Filter prototypes that will eventually be supported are |
|---|
| 190 | * - raised-cosine |
|---|
| 191 | * - gaussian |
|---|
| 192 | * - triangular |
|---|
| 193 | * - hamming |
|---|
| 194 | * |
|---|
| 195 | * The user can also load filter coefficients that have been calculated |
|---|
| 196 | * externally. |
|---|
| 197 | * |
|---|
| 198 | * \image latex polyphase_rcos_filter_k2_N4.eps "Example filter bank (1)" |
|---|
| 199 | * \image html polyphase_rcos_filter_k2_N4.png "Example filter bank (1)" |
|---|
| 200 | * |
|---|
| 201 | * \image latex polyphase_rcos_filter_k4_N2.eps "Example filter bank (2)" |
|---|
| 202 | * \image html polyphase_rcos_filter_k4_N2.png "Example filter bank (2)" |
|---|
| 203 | * |
|---|
| 204 | * \cite M. Rice and fred harris, "Polyphase Filterbanks for Symbol Timing |
|---|
| 205 | * Synchronization in Sampled Data Receivers," in MILCOMM Proceedings, vol. |
|---|
| 206 | * 2, October 2002, pp. 982--986. |
|---|
| 207 | * |
|---|
| 208 | */ |
|---|
| 209 | |
|---|
| 210 | struct polyphase_filterbank { |
|---|
| 211 | float * H; |
|---|
| 212 | unsigned int Npfb; |
|---|
| 213 | unsigned int h_len; |
|---|
| 214 | circular_buffer_t * v; |
|---|
| 215 | }; |
|---|
| 216 | |
|---|
| 217 | typedef struct polyphase_filterbank polyphase_filterbank_t; |
|---|
| 218 | |
|---|
| 219 | // |
|---|
| 220 | void polyphase_filterbank_initialize(); |
|---|
| 221 | |
|---|
| 222 | //----------------------------------------------------------------------------- |
|---|
| 223 | // |
|---|
| 224 | // Dot product definitions |
|---|
| 225 | // |
|---|
| 226 | //----------------------------------------------------------------------------- |
|---|
| 227 | float dot_product(float *x, float *y, unsigned int N); |
|---|
| 228 | //short dot_product(short *x, short *y, unsigned int N); |
|---|
| 229 | //short dot_product(float *x, short *y, unsigned int N); |
|---|
| 230 | //float dot_product(float *x, short *y, unsigned int N); |
|---|
| 231 | |
|---|
| 232 | //----------------------------------------------------------------------------- |
|---|
| 233 | // |
|---|
| 234 | // Misellany |
|---|
| 235 | // |
|---|
| 236 | //----------------------------------------------------------------------------- |
|---|
| 237 | |
|---|
| 238 | /// Uniform random number generator, (0,1] |
|---|
| 239 | float randf(); |
|---|
| 240 | |
|---|
| 241 | /// Gaussian random number generator, N(0,1) |
|---|
| 242 | void randnf(float * i, float * q); |
|---|
| 243 | |
|---|
| 244 | //----------------------------------------------------------------------------- |
|---|
| 245 | // |
|---|
| 246 | // Trigonometric functions |
|---|
| 247 | // |
|---|
| 248 | //----------------------------------------------------------------------------- |
|---|
| 249 | float arctan(float x, float y); |
|---|
| 250 | |
|---|
| 251 | |
|---|
| 252 | //----------------------------------------------------------------------------- |
|---|
| 253 | // |
|---|
| 254 | // Byte packing functions |
|---|
| 255 | // |
|---|
| 256 | //----------------------------------------------------------------------------- |
|---|
| 257 | void pack_bytes( |
|---|
| 258 | char * input, |
|---|
| 259 | unsigned int input_length, |
|---|
| 260 | char * output, |
|---|
| 261 | unsigned int output_length, |
|---|
| 262 | unsigned int *num_written); |
|---|
| 263 | |
|---|
| 264 | void unpack_bytes( |
|---|
| 265 | char * input, |
|---|
| 266 | unsigned int input_length, |
|---|
| 267 | char * output, |
|---|
| 268 | unsigned int output_length, |
|---|
| 269 | unsigned int *num_written); |
|---|
| 270 | |
|---|
| 271 | void repack_bytes( |
|---|
| 272 | char * input, |
|---|
| 273 | unsigned int input_sym_size, |
|---|
| 274 | unsigned int input_length, |
|---|
| 275 | char * output, |
|---|
| 276 | unsigned int output_sym_size, |
|---|
| 277 | unsigned int output_length, |
|---|
| 278 | unsigned int *num_written); |
|---|
| 279 | |
|---|
| 280 | |
|---|
| 281 | //----------------------------------------------------------------------------- |
|---|
| 282 | // |
|---|
| 283 | // Modulation functions |
|---|
| 284 | // |
|---|
| 285 | //----------------------------------------------------------------------------- |
|---|
| 286 | |
|---|
| 287 | /// |
|---|
| 288 | enum modulation_scheme { |
|---|
| 289 | UNKNOWN, // Unknown modulation scheme |
|---|
| 290 | BPSK, QPSK, PSK8, PSK16, // Phase shift keying |
|---|
| 291 | DBPSK, DQPSK, DPSK8, DPSK16, // Differential PSK |
|---|
| 292 | PAM4, PAM8, PAM16, PAM32, // Pulse amplitude modulation |
|---|
| 293 | BFSK, FSK4, FSK8, FSK16, // Frequency shift keying |
|---|
| 294 | QAM16, QAM32, QAM64, QAM128, QAM256 // Quadrature amplitude modulation |
|---|
| 295 | }; |
|---|
| 296 | |
|---|
| 297 | #define BPSK_ALPHA 1 |
|---|
| 298 | #define QPSK_ALPHA 1/sqrt(2) |
|---|
| 299 | |
|---|
| 300 | #define QAM16_ALPHA 1/sqrt(10) |
|---|
| 301 | #define QAM32_ALPHA 1/sqrt(20) |
|---|
| 302 | #define QAM64_ALPHA 1/sqrt(42) |
|---|
| 303 | #define QAM128_ALPHA 1/sqrt(82) |
|---|
| 304 | #define QAM256_ALPHA 1/sqrt(170) |
|---|
| 305 | |
|---|
| 306 | #define PAM4_ALPHA 1/sqrt(5) |
|---|
| 307 | #define PAM8_ALPHA 1/sqrt(21) |
|---|
| 308 | #define PAM16_ALPHA 1/sqrt(85) |
|---|
| 309 | |
|---|
| 310 | #define BPSK_LEVEL 10000 ///< BPSK amplitude (RMS=10000) |
|---|
| 311 | #define QPSK_LEVEL 7071 ///< QPSK amplitude (RMS=10000) |
|---|
| 312 | #define PSK8_LEVEL_1 7071 ///< Low 8-PSK amplitude (RMS=10000) |
|---|
| 313 | #define PSK8_LEVEL_2 10000 ///< High 8-PSK amplitude (RMS=10000) |
|---|
| 314 | #define QAM16_LEVEL_1 3162 ///< Low 16-QAM amplitude (RMS=10000) |
|---|
| 315 | #define QAM16_LEVEL_2 9487 ///< High 16-QAM amplitude (RMS=10000) |
|---|
| 316 | #define PAM4_LEVEL_1 4472 ///< Low 4-PAM amplitude (RMS=10000) |
|---|
| 317 | #define PAM4_LEVEL_2 13416 ///< High 4-PAM amplitude (RMS=10000) |
|---|
| 318 | |
|---|
| 319 | /// modulate_s a symbol into an I/Q pair for binary phase shift keying |
|---|
| 320 | /// |
|---|
| 321 | /// \image latex ConstellationBPSK.eps "BPSK constellation" |
|---|
| 322 | /// \image html ConstellationBPSK.png "BPSK constellation" |
|---|
| 323 | void modulate_bpsk(short symbol_in, short *I_out, short *Q_out); |
|---|
| 324 | |
|---|
| 325 | /// modulate_s a symbol into an I/Q pair for quadrature phase shift keying |
|---|
| 326 | /// |
|---|
| 327 | /// \image latex ConstellationQPSK.eps "QPSK constellation" |
|---|
| 328 | /// \image html ConstellationQPSK.png "QPSK constellation" |
|---|
| 329 | void modulate_qpsk(short symbol_in, short *I_out, short *Q_out); |
|---|
| 330 | |
|---|
| 331 | /// modulate_s a symbol into an I/Q pair for 8-ary phase shift keying |
|---|
| 332 | /// |
|---|
| 333 | /// \image latex Constellation8PSK.eps "8-PSK constellation" |
|---|
| 334 | /// \image html Constellation8PSK.png "8-PSK constellation" |
|---|
| 335 | void modulate_8psk(short symbol_in, short *I_out, short *Q_out); |
|---|
| 336 | |
|---|
| 337 | /// modulate_s a symbol into an I/Q pair for 16-point quadrature |
|---|
| 338 | /// amplitude modulation |
|---|
| 339 | /// |
|---|
| 340 | /// \image latex Constellation16QAM.eps "16-QAM constellation" |
|---|
| 341 | /// \image html Constellation16QAM.png "16-QAM constellation" |
|---|
| 342 | void modulate_16qam(short symbol_in, short *I_out, short *Q_out); |
|---|
| 343 | |
|---|
| 344 | /// modulate_s a symbol into an I/Q pair for 4-ary pulse amplitude |
|---|
| 345 | /// modulation |
|---|
| 346 | /// |
|---|
| 347 | /// \image latex Constellation4PAM.eps "4-PAM constellation" |
|---|
| 348 | /// \image html Constellation4PAM.png "4-PAM constellation" |
|---|
| 349 | void modulate_4pam(short symbol_in, short *I_out, short *Q_out); |
|---|
| 350 | |
|---|
| 351 | |
|---|
| 352 | #define DEMOD_COS_22_5 0.923879532511287 |
|---|
| 353 | #define DEMOD_SIN_22_5 0.382683432365090 |
|---|
| 354 | |
|---|
| 355 | #define QAM16_THRESHOLD 6324 ///< 16-QAM threshold for RMS=10000 signal |
|---|
| 356 | #define PAM4_THRESHOLD 8944 ///< 4-PAM threshold for RMS=10000 signal |
|---|
| 357 | |
|---|
| 358 | /// |
|---|
| 359 | void demodulate_bpsk(short I_in, short Q_in, short *symbol_out); |
|---|
| 360 | |
|---|
| 361 | /// |
|---|
| 362 | void demodulate_qpsk(short I_in, short Q_in, short *symbol_out); |
|---|
| 363 | |
|---|
| 364 | /// |
|---|
| 365 | void demodulate_8psk(short I_in, short Q_in, short *symbol_out); |
|---|
| 366 | |
|---|
| 367 | /// |
|---|
| 368 | void demodulate_16qam(short I_in, short Q_in, short *symbol_out); |
|---|
| 369 | |
|---|
| 370 | /// |
|---|
| 371 | void demodulate_4pam(short I_in, short Q_in, short *symbol_out); |
|---|
| 372 | |
|---|
| 373 | #ifdef __cplusplus |
|---|
| 374 | } /* extern "C" */ |
|---|
| 375 | #endif /* __cplusplus */ |
|---|
| 376 | |
|---|
| 377 | #endif /* __SIG_PROC_H__ */ |
|---|
| 378 | |
|---|
| 379 | |
|---|