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 | |
---|