root/SigProc/trunk/SigProc/SigProc.h @ 4147

Revision 4147, 26.4 KB (checked in by hvolos, 6 years ago)

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