root/SigProc/trunk/SigProc/SigProc.h @ 4184

Revision 4184, 27.0 KB (checked in by hvolos, 6 years ago)

Added some throws to ensure sanity

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