root/SigProc/trunk/SigProc/SigProc.h @ 5251

Revision 5251, 30.5 KB (checked in by jgaeddert, 6 years ago)

adding rotate function to sigproc

  • Property svn:eol-style set to native
Line 
1/****************************************************************************
2
3Copyright 2005,2006 Virginia Polytechnic Institute and State University
4
5This file is part of the OSSIE Signal Processing Library.
6
7OSSIE Signal Processing Library is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 2 of the License,
10or (at your option) any later version.
11
12OSSIE Signal Processing Library is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License along
18with OSSIE Signal Processing Library; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21
22****************************************************************************/
23
24#ifndef SIG_PROC_H
25#define SIG_PROC_H
26
27#include <iostream>
28#include <fstream>
29#include <string>
30#include <math.h>
31
32#ifdef FPM
33#include "fixed.h"
34#endif
35
36#define PI      3.14159265358979f
37#define TWO_PI  6.28318530717959f
38
39namespace SigProc {
40//-----------------------------------------------------------------------------
41//
42// Convolutional coding definitions
43//
44//-----------------------------------------------------------------------------
45
46/** \brief Defines the basic entry for building the trellis at the decoder
47*/
48class TrellisEntry{
49    public:
50        ///Contructor
51        TrellisEntry();
52        ///Destructor
53        ~TrellisEntry();       
54        unsigned int previousState; ///< The state prior to the current state, used for tracing back the trellis
55        unsigned short int symbolNo; ///< The symbol that caused the change of state to the currrent state
56        signed int distance; ///< The total distance of the current state
57};
58
59/** \brief Includes all the necessary information for encoding and decoding the symbols
60 *
61 * The contructor has to be ALWAYS be used. The generator polynomials for each code rate have to be specified in DECIMAL, not OCTAL format
62 *
63 * For more information for the meaning of the symbols used and for generator polynomials look at
64 * Proakis Digital Communications book 4th Edition, pages 471 & 492 respectively.
65*/
66class trellisTable{
67    public:
68        /// The contructor has to be always used
69        trellisTable(unsigned int * generatorPolynomials, unsigned short int k, unsigned short int n, unsigned short K);
70
71        /// =The destructor
72        ~trellisTable();
73
74        unsigned short int k;///<the input bits at a time
75        unsigned short int n;///< the output bits at a time
76        unsigned short int K;///<the contraint length
77        unsigned short int numberOfInputStates;///< Based on k, how many different input states exist
78        unsigned int numberOfTrellisStates;///<Number of different trellis states, defined by k & K
79
80        unsigned int **output; ///< The rows are the trellis states and the columns the symbols, gives the output given the current state and symbol.
81        unsigned int **nextState;///< The sane as output, gives the the next state given the current state and synbol
82
83    protected:
84        ///Generates the trellis table given the generator polynomials in DECIMAL not OCTAL
85        void GenerateTrellisTable(unsigned int * generatorPolynomials);
86
87        ///Performs modulo 2 addition to the bits of the input number (symbol)
88        unsigned short int Modulo2BitWiseAdd(unsigned short int inputNumber);
89};
90
91/** \brief Defines the basic functionality for the convolution encoding/decoding
92*/
93
94class fec_conv{
95    public:
96        /// It accepts the pointer to the trellis Table
97        void SetTrellisTable(trellisTable *theTrellisTableIn);
98
99    protected:
100        /// It converts a decimal numnber (symbol) into a vector of bits
101        void Dec2Bin(unsigned int decNumber,unsigned short int * outputData,unsigned short int numberOfBits);
102
103        trellisTable * theTrellisTable;///< It holds the trellis table used for encoding/decoding
104};
105
106/** \brief It defines the encoding functionality
107 *
108 * To use this class, first pass the trellis table pointer
109 *
110 * To encode: reset the state, feed data & get encoded data, repeat for the next packet.
111 *
112 * To make the encoder to return at the zero state during encoding, feed K 0 symbols after the encoding of the data is done.
113*/
114class fec_conv_encoder : public fec_conv{
115    public:
116        ///Default constructor
117        fec_conv_encoder();
118
119        ///Default destructor
120        ~fec_conv_encoder();
121
122        /// Resets the state of the encoder to the zero state
123        void ResetState();
124
125        ///It gets the current state of the encoder
126        unsigned int GetState();
127
128        ///It accepts a vector of k bits and returns a vector of n bits
129        void Encode(unsigned short int * inputData,unsigned short int * outputData);
130
131    protected:
132        unsigned int currentState;///<The current state of the encoder
133};
134
135/** \brief It defines the decoding functionality
136 *
137 * The following cycle should be followed to use this class:
138 *
139 * 1. Set the trellis table
140 *
141 * 2. Set the traceback length
142 *
143 * 3. Set mode
144 *
145 * 4. Feed symbols into the decoder
146 *
147 * 5. Trace back trellis
148 *
149 * 6. Get the decoded symbols
150 *
151 * 7. Reset and repeat from 4 for the next packet. If the decoding parameters change, might need to repeat from 1.
152*/
153class fec_conv_decoder:public fec_conv {
154    public:
155        ///Default contructor
156        fec_conv_decoder();
157
158        ///Default destructor
159        ~fec_conv_decoder();
160
161        /// Set the numbers of the input symbols to be decoded, this equals to the total bits on the output of the encoder divided by k
162        void SetNoOfSymbols2TraceBack(unsigned int tracebackLength);
163
164        /// Feeds a symbol (in a vector of n bits) at time for decoding
165        void Symbol2Decode(unsigned short int * inputData);
166
167        /// After all symbols were fed in the decoder, it will tracesback the trellis to the begining.
168        void TraceBackTrellis();
169
170        ///After the trellis was traced back, it returns a decoded symbol, starting from the beggining each time is called.
171        void GetDecodedSymbol(unsigned short int * outputData);
172
173        ///It resets the state of the decoder in order to be able to start a new decoding session
174        void Reset();
175
176        ///Sets the mode of the decoder 0: the encoded data start from zero state 1: the encoded data start from the the zero state and end at the zero state.
177        void SetMode(unsigned short int mode);
178
179    protected:
180        ///Calculates the distance between the input bits (symbol) to the current trellis symbol
181        signed int CalculateDistance(unsigned short int inBits, unsigned short int symbol);
182
183        unsigned int currentTrellisIndex;///<The current trellis stage used when building and tracing back the trellis.
184        unsigned int decodedSymbolIndex;///<The next symbol to be returned when the GetDecodedSymbol is called.
185        unsigned int noOfSymbols2TraceBack;///<Number of symbols to trace back, should be equal to the symbols used in the encoding process.
186        unsigned int mode;///<The mode of the encoder
187
188        unsigned int *tracedBackSymbols;///<A vector array with the symbols traced back
189        TrellisEntry **theTrellis; ///<A two dimensional array making the trellis, states are rows, and columns are each trellis stage.
190};
191
192//-----------------------------------------------------------------------------
193//
194// Design root raised-cosine filter
195//
196//-----------------------------------------------------------------------------
197void DesignRRCFilter(
198  unsigned int k,      // samples per symbol
199  unsigned int m,      // delay
200  float beta,          // rolloff factor ( 0 < beta <= 1 )
201  float * h            // pointer to filter coefficients
202);
203
204//-----------------------------------------------------------------------------
205//
206// Design Gaussian filter
207//
208//-----------------------------------------------------------------------------
209void DesignGaussianFilter(
210  unsigned int k,      // samples per symbol
211  unsigned int m,      // delay
212  float beta,          // rolloff factor ( 0 < beta <= 1 )
213  float *& h,          // pointer to filter coefficients
214  unsigned int & h_len // length of filter (len = 2*m*k+1)
215);
216
217//-----------------------------------------------------------------------------
218//
219// Circular buffer
220//
221//-----------------------------------------------------------------------------
222/** \brief Circlar buffer, template class
223 *
224 * \section CB_basic_description Basic Description
225 * The circular buffer template class implementation minimizes memory copies
226 * by wrapping the array around to its beginning.  Elements can be added
227 * and removed by invoking the Push() and Pop() methods, respectively.
228 *
229 * \section CB_creating Creating Buffers
230 * There are three ways to create a buffer...
231 * \code
232 * // 1. generate an empty buffer
233 * CircularBuffer <short> v1(100);
234 *
235 * // 2. wrap an existing array
236 * short * x = new short[100];
237 * for (unsigned int i=0; i<100; i++)
238 *     x[i] = i;
239 * CircularBuffer <short> v2(x, 100);
240 *
241 * // 3. copy from another CircularBuffer
242 * CircularBuffer <short> v3(v2);
243 * \endcode
244 *
245 * \section CB_resizing_buffers Resizing Buffers
246 * CircularBuffer supports dynamic memory allocation as well; if an instance
247 * of CircularBuffer is created of a particular size and then later it is
248 * determined that the size is too small, invoking SetBufferSize() can be used
249 * to increase the length without loss of data.  However, decreasing the buffer
250 * size beyond the number of elements in the buffer truncates the data.
251 *
252 * \section CB_wrapping Wrapping
253 * When the buffer is full and another element is pushed, the new element
254 * overwrites the last element in the buffer without warning.  Status of the
255 * buffer can be checked with the GetBufferSize() and GetNumElements()
256 * methods.
257 *
258 */
259template <class T>
260class CircularBuffer {
261  public:
262    /// Default constructor
263    CircularBuffer();
264
265    /// Initializing constructor (empty)
266    CircularBuffer(unsigned int _bufferSize);
267
268    /// Initializing constructor (array)
269    CircularBuffer(T * _v, unsigned int _bufferSize);
270
271    /// Copy constructor
272    CircularBuffer(CircularBuffer &);
273
274    /// destructor
275    ~CircularBuffer() { delete [] headPtr; }
276
277    /// \brief Overload the [] operator (indexing)
278    ///
279    /// Returns the value at the appropriate index as if the buffer were a
280    /// linear array
281    T operator[] (unsigned int i) {
282        return headPtr[(i_read + i) % bufferSize ];
283    }
284
285    /// Push value into the beginning of the buffer, overwrite existing element
286    /// if buffer is full
287    void Push(T _value) {
288
289        // OK to push value
290        headPtr[i_head++] = _value;
291
292        // Ensure head index does not equal or exceed bufferSize (wrap)
293        i_head = i_head % bufferSize;
294
295        // Check to see if buffer is full
296        if ( numElements < bufferSize )
297            numElements++;  // buffer not yet full
298        else
299            i_read++;       // overflow
300    }
301
302    /// Remove element from the end of the buffer
303    T Pop() {
304        if ( numElements == 0 ) {
305            std::cerr << "ERROR: SigProc::CircularBuffer::Pop() : buffer is empty!"
306                      << std::endl;
307            throw 0;
308        }
309
310        // read value
311        T retval = headPtr[i_read++];
312
313        // Ensure read index does not equal or exceed bufferSize (wrap)
314        i_read = i_read % bufferSize;
315
316        // Decrement number of elements
317        numElements--;
318
319        // RETURN value
320        return retval;
321    }
322
323    /// Releases entire buffer (resets values in buffer to zero)
324    void Release() {
325        i_head = 0;
326        i_read = 0;
327        numElements = 0;
328        memset(headPtr, 0, bufferSize*sizeof(T));
329    }
330
331    /// Releases _n elements from buffer
332    void Release( unsigned int _n ) {
333        if ( _n >= numElements ) {
334            Release();
335        } else {
336            numElements -= _n;
337            i_read = (i_read + _n) % bufferSize;
338        }
339    }
340
341    /// Return the number of memory slots allocated to the buffer
342    unsigned int GetBufferSize() { return bufferSize; }
343
344    /// Set the buffer size dynamically
345    void SetBufferSize(unsigned int _bufferSize);
346
347    /// Return the number of elements inside the buffer
348    unsigned int GetNumElements() { return numElements; }
349
350    /// \brief Get a pointer to the buffer
351    ///
352    /// This method actually shifts the elements inside the buffer so that instead
353    /// of being cyclical they are linear.
354    T * GetHeadPtr() {
355        Linearize();
356        return headPtr;
357    }
358
359    /// Prints buffer to screen
360    void Print() {
361        std::cout << " b : ";
362        for (unsigned int i=0; i<numElements; i++)
363            std::cout << " " << headPtr[(i_read+i) % bufferSize];
364        std::cout << std::endl;
365    }
366
367  protected:
368    /// Pointer to the beginning of the buffer
369    T * headPtr;
370
371    /// Head index
372    unsigned int i_head;
373
374    /// Read index
375    unsigned int i_read;
376
377    /// Memory slots allocated to the buffer
378    unsigned int bufferSize;
379
380    /// Number of elements currently in the buffer
381    unsigned int numElements;
382
383    /// \brief Linearize buffer array
384    ///
385    /// Shifts the elements in the buffer so that they are organized linearly
386    /// rather than circularly.  If the buffer is not empty, Linearize creates
387    /// a new array and copies the old values.
388    void Linearize();
389
390};
391
392//-----------------------------------------------------------------------------
393//
394// P/N Sequence
395//
396//-----------------------------------------------------------------------------
397
398/// P/N Sequence
399class PNSequence
400{
401  public:
402    /// initializing constructor
403    PNSequence(unsigned int _g, unsigned int _a);
404
405    /// destructor
406    ~PNSequence();
407
408    unsigned long m;    ///< shift register length
409    unsigned long n;    ///< output sequence length, \f$ n=2^m-1 \f$
410    char * g;           ///< generator polynomial
411    char * a;           ///< initial polynomial state
412    char * s;           ///< output sequence
413};
414
415//-----------------------------------------------------------------------------
416//
417// Automatic Gain Control class
418//
419//-----------------------------------------------------------------------------
420/** \brief Automatic gain control signal processor
421 *
422 * \cite  R. G. Lyons, Understanding Digital Signal Processing, 2nd ed. New Jersey:
423 * Prentice Hall, 2004.
424 */
425class AutomaticGainControl
426{
427  public:
428    /// default constructor
429    AutomaticGainControl();
430
431    /// Destructor
432    ~AutomaticGainControl();
433
434    /// Set signal processing values
435    void SetValues(
436            float _elo,
437            float _ehi,
438            float _ka,
439            float _kr,
440            float _gmin,
441            float _gmax);
442
443    /// Get signal processing values
444    void GetValues(
445            float & _elo,
446            float & _ehi,
447            float & _ka,
448            float & _kr,
449            float & _gmin,
450            float & _gmax);
451
452    /// Get status
453    void GetStatus(float & _gain, float & _energy);
454
455    /// track signal energy and apply gain (real)
456    void ApplyGain(short & I);
457
458    /// track signal energy and apply gain (complex)
459    void ApplyGain(short & I, short & Q);
460
461  private:
462    /// disallow copy constructor
463    AutomaticGainControl(AutomaticGainControl &);
464
465    /// compute necessary gain value from measured energy
466    void ComputeGain();
467
468    /// low energy threshold
469    float energy_lo;
470
471    /// high energy threshold
472    float energy_hi;
473
474    /// attack time constant
475    float ka;
476
477    /// release time constant
478    float kr;
479
480    /// minimum gain value
481    float gmin;
482
483    /// maximum gain value
484    float gmax;
485
486    /// actual tracking gain value
487    float gain;
488
489    /// actual tracking average energy value
490    float energy;
491
492    /// low-pass filter coefficient for estimating average energy
493    float zeta;
494
495    /// average energy threshold for smoother tracking
496    float energy_av;
497
498};
499
500class phase_detect {
501
502 public:
503    phase_detect(float scale_factor);
504
505    void do_work(short I_in, short Q_in, short I_nco, short Q_nco, short &out);
506
507 private:
508    phase_detect(const phase_detect &);
509
510    float scale_factor;
511};
512
513
514class nco {
515  public:
516    nco();
517    nco(unsigned int max_out);
518
519    void do_work(short control_voltage, short &sine, short &cosine);
520
521  private:
522    nco(const nco &);
523
524    int freq_index;
525    int max_out;
526};
527
528class gain {
529  public:
530    gain();
531
532    void do_work(float gain, short data_in, short &out);
533
534  private:
535    gain(const gain &);
536
537};
538
539class iir_filter {
540  public:
541    iir_filter(float a[], unsigned int len_a, float b[], unsigned int len_b);
542
543    void do_work(short x, short &y);
544
545    void ResetBuffer();
546
547  private:
548    iir_filter(const iir_filter &);
549
550    float *A;
551    float *B;
552    unsigned int len_A, len_B;
553
554    float *v;
555    unsigned int len_v;
556    unsigned int next_v;
557};
558
559
560//-----------------------------------------------------------------------------
561//
562// FIR polyphase filter bank
563//
564//-----------------------------------------------------------------------------
565/** \brief Finite impulse response (FIR) polyphase filter bank
566 *
567 * This class implementes a finite impulse response (FIR) polyphase filter
568 * bank useful for decimators that need to interpolate samples in digital
569 * receivers.
570 *
571 * The filter bank can automatically calculate filter coefficients for
572 * prototypes commonly used in communications systems. Currently, such
573 * supported filter prototypes are
574 *   - root raised-cosine
575 *
576 * Filter prototypes that will eventually be supported are
577 *   - raised-cosine
578 *   - gaussian
579 *   - triangular
580 *   - hamming
581 *
582 * The user can also load filter coefficients that have been calculated
583 * externally.
584 *
585 * \image latex polyphase_rcos_filter_k2_N4.eps "Example filter bank (1)"
586 * \image html polyphase_rcos_filter_k2_N4.png  "Example filter bank (1)"
587 *
588 * \image latex polyphase_rcos_filter_k4_N2.eps "Example filter bank (2)"
589 * \image html polyphase_rcos_filter_k4_N2.png  "Example filter bank (2)"
590 *
591 * \cite M. Rice and fred harris, "Polyphase Filterbanks for Symbol Timing
592 * Synchronization in Sampled Data Receivers," in MILCOMM Proceedings, vol.
593 * 2, October 2002, pp. 982--986.
594 *
595 */
596class FIRPolyphaseFilterBank {
597  public:
598    /// \brief Initializing constructor
599    ///
600    /// This constructor calculates the filter coefficients for several
601    /// different filter types using just a few parameters.  The filters
602    /// currently supported are:
603    ///   - 'rrcos'  : square-root raised-cosine (RRC)
604    ///   - 'drrcos' : derivative RRC
605    ///
606    FIRPolyphaseFilterBank(
607            char * _type,       // type of filter
608            unsigned int _k,    // samples per symbol
609            unsigned int _m,    // delay
610            float _beta,        // excess bandwidth factor
611            unsigned int _Npfb  // number of filters
612            );
613
614    /// \brief Initializing constructor
615    ///
616    /// This constructor loads filter bank coefficients which have
617    /// been generated externally.  The coefficients are copied from
618    /// the input array to a new buffer.
619    FIRPolyphaseFilterBank(
620            float * _H,         // filter bank coefficients
621            unsigned int _h_len,// length of each filter
622            unsigned int _Npfb  // number of filters
623            );
624
625    /// destructor
626    ~FIRPolyphaseFilterBank();
627
628    /// Push input value into buffer
629    void PushInput(short _x);
630
631    /// Compute filter output from current buffer state using specific
632    /// filter from filter bank matrix
633    void ComputeOutput(
634            short &y,           // output sample
635            unsigned int _b     // filter bank index
636            );
637
638    /// Compute filter output from current buffer state using specific
639    /// filter from filter bank matrix and an external memory buffer
640    void ComputeOutput(
641            short &y,           // output sample
642            unsigned int _b,    // filter bank index
643            short *_v           // external memory buffer array
644            );
645
646    /// Reset filter buffer
647    void ResetBuffer();
648
649    /// Print filter buffer
650    void PrintBuffer();
651
652    /// Prints filter bank coefficients to the screen
653    void PrintFilterBankCoefficients();
654
655    /// Get the length of each filter
656    unsigned int GetFilterLength() { return h_len; }
657
658    /// Get the number of filters in the bank
659    unsigned int GetNumFilters() { return Npfb; }
660
661    /// Return a pointer to the filter bank coefficients; this is intended
662    /// for debugging
663    float * GetFilterBankCoefficients() { return H; }
664
665  protected:
666
667    /// type of filter; can be one of the following
668    ///   - 'rrcos'
669    ///   - 'gaussian'
670    char * type;
671
672    /// samples per symbol
673    unsigned int k;
674
675    /// symbol delay
676    unsigned int m;
677
678    /// excess bandwidth factor
679    float beta;
680
681    /// number of filters in bank
682    unsigned int Npfb;
683
684    /// \brief filter bank coefficients matrix
685    ///
686    /// The coefficients are stored in a one-dimensional array which
687    /// is realized as a two-dimensional matrix.  The array is of
688    /// length Npfb*h_len (the number of filters in the bank times
689    /// the length of each filter).
690    float *H;
691
692    /// length of each filter
693    unsigned int h_len;
694
695    /// circular input buffer
696    CircularBuffer <short> v;
697
698    /// transpose filter bank coefficient matrix
699    void TransposeCoefficientMatrix();
700
701    // ----- calculate filter bank coefficients -----
702
703    /// Calculate root raised-cosine coefficients
704    void CalculateRRCFilterCoefficients();
705
706    /// Calculate Gaussian filter coefficients
707    void CalculateGaussianFilterCoefficients();
708
709    /// \brief Calculate derivative filter coefficients
710    ///
711    /// Approximates the derivative of the template filter
712    /// \f[ \dot{h}(nT) = \frac{\partial h(nT)}{\partial t} \f]
713    ///
714    /// using discrete samples, viz.
715    /// \f[ \dot{h}_m(nT)     = h_{m+1}(nT) - h_{m-1}(nT), \ \ m=1,2,\ldots,...M-2 \f]
716    /// \f[ \dot{h}_0(nT)     = h_{1}(nT) - h_{M-1}(nT)\f]
717    /// \f[ \dot{h}_{M-1}(nT) = h_{M-2}(nT) - h_{0}(nT)\f]
718    ///
719    void CalculateDerivativeFilterCoefficients();
720
721  private:
722
723    /// disallow copy constructor
724    FIRPolyphaseFilterBank(const FIRPolyphaseFilterBank&);
725
726};
727
728
729//-----------------------------------------------------------------------------
730//
731// Dot product definitions
732//
733//-----------------------------------------------------------------------------
734void dot_product(float *x, float *y, unsigned int N, float &z);
735void dot_product(short *x, short *y, unsigned int N, short &z);
736void dot_product(float *x, short *y, unsigned int N, short &z);
737void dot_product(float *x, short *y, unsigned int N, float &z);
738
739//-----------------------------------------------------------------------------
740//
741// Trigonometric functions
742//
743//-----------------------------------------------------------------------------
744void arctan(float &x, float &y, float &theta);
745
746/// Rotates a complex signal counter-clockwise by \f[\theta\f] radians
747/// \f[ \bar{y} = \bar{x} e^{j\theta} \f]
748void rotate(short I_in, short Q_in, float theta, short *I_out, short *Q_out);
749
750//-----------------------------------------------------------------------------
751//
752// Random number generators
753//
754//-----------------------------------------------------------------------------
755
756/// Uniform random number generator, (0,1]
757float randf();
758
759/// Gaussian random number generator, N(0,1)
760void randnf(float * i, float * q);
761
762
763
764
765class fir_filter {
766  public:
767    fir_filter(float a[], unsigned int len_a);
768
769    void do_work(bool run_filter, short in_sample, short &out_sample);
770    void reset();
771
772  private:
773    fir_filter(const fir_filter &);
774
775#ifdef FPM
776    mad_fixed_t *A;
777    mad_fixed_t *v;
778#else
779    float *A;
780    short *v;
781#endif
782    unsigned int len_A;
783
784    unsigned int len_v;
785    unsigned int next_v;
786};
787
788class dump_data {
789 public:
790  dump_data(const char *filename, long start_sample, long number_of_samples);
791  ~dump_data();
792
793  void write_data(float data, const char *msg = "");
794  void write_data(float a, float b, const char *msg = "");
795
796 private:
797  dump_data();
798  dump_data(const dump_data &);
799
800  std::ofstream *out_file;
801
802  long start_sample, stop_sample;
803  long current_sample;
804
805};
806
807class dc_block {
808  public:
809    dc_block(const float forget_factor);
810    ~dc_block();
811
812    void do_work(short in, short &out);
813
814  private:
815    dc_block();
816    dc_block(const dc_block &);
817
818    float forget_factor;
819    int prev_input, prev_output;
820
821};
822
823//-----------------------------------------------------------------------------
824//
825// Circular buffer definitions
826//
827//-----------------------------------------------------------------------------
828
829// Initializing constructor (empty)
830template <class T>
831CircularBuffer<T>::CircularBuffer()
832{
833    bufferSize = 1;
834    numElements = 0;
835    i_head = 0;
836    i_read = 0;
837    headPtr = new T[bufferSize];
838}
839
840// Initializing constructor (empty)
841template <class T>
842CircularBuffer<T>::CircularBuffer(unsigned int _bufferSize) {
843    bufferSize = _bufferSize;
844    numElements = 0;
845    i_head = 0;
846    i_read = 0;
847    headPtr = new T[bufferSize];
848}
849
850// Initializing constructor (array)
851template <class T>
852CircularBuffer<T>::CircularBuffer(T * _v, unsigned int _bufferSize) {
853    bufferSize = _bufferSize;
854    numElements = 0;
855    i_head = 0;
856    i_read = 0;
857    headPtr = new T[bufferSize];
858    for (unsigned int i=0; i<bufferSize; i++)
859        Push( _v[i] );
860}
861
862// Copy constructor
863template <class T>
864CircularBuffer<T>::CircularBuffer(CircularBuffer & _cb) {
865    bufferSize = _cb.bufferSize;
866    numElements = _cb.numElements;
867    i_head = _cb.i_head;
868    i_read = _cb.i_read;
869    headPtr = new T[bufferSize];
870    for (unsigned int i=0; i<bufferSize; i++)
871        headPtr[i] = _cb.headPtr[i];
872}
873
874// Set the buffer size dynamically
875template <class T>
876void CircularBuffer<T>::SetBufferSize(unsigned int _bufferSize) {
877    if ( _bufferSize < 1 ) {
878        std::cerr << "ERROR: SigProc::CircularBuffer::SetBufferSize()" << std::endl
879                  << "  => minimum buffer size is 1" << std::endl;
880        throw 0;
881    }
882
883    if ( _bufferSize == bufferSize ) {
884        // Nothing to do
885        return;
886    } else if ( _bufferSize < bufferSize && numElements > _bufferSize ) {
887        // New buffer is too small: copy only newest elements, discard oldest
888        i_read = ( i_read + numElements - _bufferSize ) % bufferSize;
889        numElements = _bufferSize;
890    } else {
891        // New buffer is sufficiently large: copy everything
892    }
893
894    // allocate new buffer memory
895    T * tmpHeadPtr = new T[_bufferSize];
896
897    for (unsigned int i=0; i<numElements; i++)
898        tmpHeadPtr[i] = headPtr[i_read++ % bufferSize];
899
900    // delete old buffer
901    delete [] headPtr;
902
903    headPtr = tmpHeadPtr;
904    i_head = numElements % bufferSize;
905    i_read = 0;
906
907    bufferSize = _bufferSize;
908}
909
910// Linearize buffer
911template <class T>
912void CircularBuffer<T>::Linearize() {
913    if ( numElements == 0 )
914        return;
915
916    T * tmpHeadPtr = new T[bufferSize];
917
918    for (unsigned int i=0; i<numElements; i++)
919        tmpHeadPtr[i] = headPtr[i_read++ % bufferSize];
920
921    delete [] headPtr;
922    headPtr = tmpHeadPtr;
923    i_head = numElements % bufferSize;
924    i_read = 0;
925}
926
927// enum DemodScheme {
928//     HARD = 0,
929//     SOFT_TRUE = 1,
930//     SOFT_STANDARD = 2,
931//     SOFT_HIGHSNR = 3
932// };
933
934// void DemodQAM(unsigned int M, signed short X, signed short Y, DemodScheme scheme, signed char *bitsOut);
935
936// void DemodPSK(unsigned int M, signed short X, signed short Y, DemodScheme scheme, signed char *bitsOut);
937
938
939///
940enum ModulationScheme {
941        UNKNOWN,                                // Unknown modulation scheme
942        BPSK,   QPSK,   PSK8,   PSK16,          // Phase shift keying
943        DBPSK,  DQPSK,  DPSK8,  DPSK16,         // Differential PSK
944        PAM4,   PAM8,   PAM16,  PAM32,          // Pulse amplitude modulation
945        BFSK,   FSK4,   FSK8,   FSK16,          // Frequency shift keying
946        QAM4, QAM16,  QAM32,  QAM64,  QAM128, QAM256  // Quadrature amplitude modulation
947        };
948
949#define BPSK_LEVEL      10000   ///< BPSK amplitude (RMS=10000)
950#define QPSK_LEVEL      10000   ///< QPSK amplitude (RMS=10000)
951#define QAM4_LEVEL      7071    ///< QAM4 amplitude (RMS=10000)
952#define PSK8_LEVEL_1    7071    ///< Low 8-PSK amplitude (RMS=10000)
953#define PSK8_LEVEL_2    10000   ///< High 8-PSK amplitude (RMS=10000)
954#define QAM16_LEVEL_1   3162    ///< Low 16-QAM amplitude (RMS=10000)
955#define QAM16_LEVEL_2   9487    ///< High 16-QAM amplitude (RMS=10000)
956#define PAM4_LEVEL_1    4472    ///< Low 4-PAM amplitude (RMS=10000)
957#define PAM4_LEVEL_2    13416   ///< High 4-PAM amplitude (RMS=10000)
958
959/// Modulates a symbol into an I/Q pair for binary phase shift keying
960///
961/// \image latex ConstellationBPSK.eps "BPSK constellation"
962/// \image html ConstellationBPSK.png "BPSK constellation"
963void ModulateBPSK(short symbol_in, short &I_out, short &Q_out);
964
965/// Modulates a symbol into an I/Q pair for quadrature phase shift keying
966///
967// \image latex ConstellationQPSK.eps "QPSK constellation"
968// \image html ConstellationQPSK.png "QPSK constellation"
969void ModulateQPSK(short symbol_in, short &I_out, short &Q_out);
970
971/// Modulates a symbol into an I/Q pair for quadrature amplitude shift keying
972///
973/// \image latex ConstellationQAM4.eps "QAM4 constellation"
974/// \image html ConstellationQAM4.png "QAM4 constellation"
975void ModulateQAM4(short symbol_in, short &I_out, short &Q_out);
976
977/// Modulates a symbol into an I/Q pair for 8-ary phase shift keying
978///
979/// \image latex Constellation8PSK.eps "8-PSK constellation"
980/// \image html Constellation8PSK.png "8-PSK constellation"
981void Modulate8PSK(short symbol_in, short &I_out, short &Q_out);
982
983/// Modulates a symbol into an I/Q pair for 16-point quadrature
984/// amplitude modulation
985///
986/// \image latex Constellation16QAM.eps "16-QAM constellation"
987/// \image html Constellation16QAM.png "16-QAM constellation"
988void Modulate16QAM(short symbol_in, short &I_out, short &Q_out);
989
990/// Modulates a symbol into an I/Q pair for 4-ary pulse amplitude
991/// modulation
992///
993/// \image latex Constellation4PAM.eps "4-PAM constellation"
994/// \image html Constellation4PAM.png "4-PAM constellation"
995void Modulate4PAM(short symbol_in, short &I_out, short &Q_out);
996
997
998#define DEMOD_COS_22_5 0.923879532511287
999#define DEMOD_SIN_22_5 0.382683432365090
1000
1001#define QAM16_THRESHOLD 6324    ///< 16-QAM threshold for RMS=10000 signal
1002#define PAM4_THRESHOLD  8944    ///< 4-PAM threshold for RMS=10000 signal
1003
1004///
1005void DemodulateBPSK(short I_in, short Q_in, short &symbol_out);
1006
1007///
1008void DemodulateQPSK(short I_in, short Q_in, short &symbol_out);
1009
1010///
1011void DemodulateQAM4(short I_in, short Q_in, short &symbol_out);
1012
1013///
1014void Demodulate8PSK(short I_in, short Q_in, short &symbol_out);
1015
1016///
1017void Demodulate16QAM(short I_in, short Q_in, short &symbol_out);
1018
1019///
1020void Demodulate4PAM(short I_in, short Q_in, short &symbol_out);
1021
1022}
1023#endif
1024
1025
Note: See TracBrowser for help on using the browser.