root/SigProc/trunk/SigProc/filters.cpp @ 4146

Revision 4146, 14.7 KB (checked in by jgaeddert, 6 years ago)

Cleaning up documentation, adding Gaussian filter design (needs testing)

  • Property svn:eol-style set to native
Line 
1/****************************************************************************
2
3Copyright 2006, Virginia Polytechnic Institute and State University
4
5This file is part of the OSSIE Signal Processing Library.
6
7OSSIE Core Framework is free software; you can redistribute it and/or modify
8it under the terms of the Lesser GNU General Public License as published by
9the Free Software Foundation; either version 2.1 of the License, or
10(at your option) any later version.
11
12The OSSIE Signal Processing library 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
15Lesser GNU General Public License for more details.
16
17You should have received a copy of the Lesser GNU General Public License
18along with OSSIE Core Framework; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21****************************************************************************/
22
23#include "SigProc.h"
24
25#include <math.h>
26
27//-----------------------------------------------------------------------------
28//
29// Design root raised-cosine filter
30//
31//-----------------------------------------------------------------------------
32/** \brief Calculate square-root raised-cosine filter coefficients
33
34  DesignRRCFilter calculates the coefficients for a square-root raised-cosine
35  (RRC) finite impulse response (FIR) filter commonly used in digital
36  communications.  The input parameters are as follows
37
38    - \f$k\f$ : samples per symbol
39    - \f$m\f$ : sample delay
40    - \f$\beta\f$ : excess bandwidth (rolloff) factor
41
42  The function returns a pointer to the filter coefficients as well as an
43  integer value describing the length of the filter.  The length of the
44  filter is always
45
46  \f[
47    h_{len} = 2 k m + 1
48  \f]
49
50  The filter coefficients themselves are derived from the following equation
51
52  \f[
53    h\left[z\right] =
54      4\beta \frac{ \cos\left[(1+\beta)\pi z\right] +
55                    \sin\left[(1+\beta)\pi z\right] / (4\beta z) }
56                  { \pi \sqrt{T}\left[ 1-16\beta^2z^2\right] }
57  \f]
58
59  where \f$z=n/k-m\f$, and \f$T=1\f$ for most cases.
60
61  The function compensates for the two cases where \f$h[n]\f$ might be
62  undefined in the above equation, viz.
63
64  \f[
65    \mathop {\lim }\limits_{z \to 0 } h(z) =
66      \frac{ 4\beta \left[ 1 + \frac{1-\beta\pi }{ 4\beta } \right] }
67           { \pi\sqrt{T}\left( 1-16\beta^2 z^2 \right) }
68  \f]
69
70  and
71
72  \f[
73    \mathop {\lim }\limits_{z \to \pm \frac{1}{4\beta} } h(z) =
74        \frac{(1+\beta)}{2\pi}\sin\left[\frac{(1+\beta)\pi}{4\beta}\right]
75      - \frac{(1-\beta)}{2}\cos\left[\frac{(1-\beta)\pi}{4\beta}\right]
76      + \frac{2\beta}{\pi}\sin\left[\frac{(1-\beta)\pi}{4\beta}\right]
77
78  \f]
79
80  \param[in]  k         samples per symbol
81  \param[in]  m         symbol delay
82  \param[in]  beta      excess bandwidth/rolloff factor ( 0 < beta < 1 )
83  \param[out] h         pointer to filter coefficients
84  \param[out] h_len     length of filter, h_len = 2*m*k+1
85
86 */
87
88void SigProc::DesignRRCFilter(
89  unsigned int k,      // samples per symbol
90  unsigned int m,      // delay
91  float beta,          // rolloff factor ( 0 < beta <= 1 )
92  float *& h,          // pointer to filter coefficients
93  unsigned int & h_len // length of filter (len = 2*m*k+1)
94)
95{
96    h_len = 0;
97
98    if ( k < 1 ) {
99        std::cerr << "ERROR: SigProc::DesignRRCFilter: k must be greater than 0"
100                  << std::endl;
101        throw 0;
102    } else if ( m < 1 ) {
103        std::cerr << "ERROR: SigProc::DesignRRCFilter: m must be greater than 0"
104                  << std::endl;
105        throw 0;
106    } else if ( (beta < 0.0f) || (beta > 1.0f) ) {
107        std::cerr << "ERROR: SigProc::DesignRRCFilter: beta must be in [0,1]"
108                  << std::endl;
109        throw 0;
110    } else;
111
112    unsigned int n;
113    float z, t1, t2, t3, t4, T(1.0f);
114    float pi(3.14159265358979f);
115
116    h_len = 2*k*m+1;
117    h = new float[h_len];
118
119    // Calculate filter coefficients
120    for (n=0; n<h_len; n++) {
121
122        z = float(n)/float(k)-float(m);
123        t1 = cosf((1+beta)*pi*z);
124        t2 = sinf((1-beta)*pi*z);
125
126        // Check for special condition where z equals zero
127        if ( n == k*m ) {
128            t4 = 4*beta/(pi*sqrtf(T)*(1-(16*beta*beta*z*z)));
129            h[n] = t4*( 1 + (1-beta)*pi/(4*beta) );
130        } else {
131            t3 = 1/((4*beta*z));
132
133            float g = 1-16*beta*beta*z*z;
134            g *= g;
135
136            // Check for special condition where 16*beta^2*z^2 equals 1
137            if ( g < 1e-3 ) {
138                float g1, g2, g3, g4;
139                g1 = -(1+beta)*pi*sin((1+beta)*pi/(4*beta));
140                g2 = cos((1-beta)*pi/(4*beta))*(1-beta)*pi;
141                g3 = -sin((1-beta)*pi/(4*beta))*4*beta;
142                g4 = -2*pi;
143
144                h[n] = (g1+g2+g3)/g4;
145            } else {
146                t4 = 4*beta/(pi*sqrtf(T)*(1-(16*beta*beta*z*z)));
147                h[n] = t4*( t1 + (t2*t3) );
148            }
149        }
150    }
151}
152
153//-----------------------------------------------------------------------------
154//
155// Design Gaussian filter
156//
157//-----------------------------------------------------------------------------
158void SigProc::DesignGaussianFilter(
159  unsigned int k,      // samples per symbol
160  unsigned int m,      // delay
161  float beta,          // rolloff factor ( 0 < beta <= 1 )
162  float *& h,          // pointer to filter coefficients
163  unsigned int & h_len // length of filter (len = 2*m*k+1)
164) {
165    h_len = 0;
166
167    if ( k < 1 ) {
168        std::cerr << "ERROR: SigProc::DesignGaussianFilter: k must be greater than 0"
169                  << std::endl;
170        throw 0;
171    } else if ( m < 1 ) {
172        std::cerr << "ERROR: SigProc::DesignGaussianFilter: m must be greater than 0"
173                  << std::endl;
174        throw 0;
175    } else if ( beta < 0.0f) {
176        std::cerr << "ERROR: SigProc::DesignGaussianFilter: beta must be greater than 0"
177                  << std::endl;
178        throw 0;
179    } else;
180
181    h_len = 2*k*m + 1;
182    h = new float[h_len];
183    float sigma(beta);
184    float g( 2*sigma*sigma );
185    float z;
186
187    for (unsigned int n=0; n<h_len; n++) {
188        // Check for special condition where z equals zero
189        if ( n == k*m ) {
190            h[n] = 1.0f;
191        } else {
192            z = float(n)/float(k)-float(m);
193            h[n] = expf(-z*z/g);
194        }
195    }
196}
197
198//-----------------------------------------------------------------------------
199//
200// FIR polyphase filter bank
201//
202//-----------------------------------------------------------------------------
203
204// Initializing constructor
205SigProc::FIRPolyphaseFilterBank::FIRPolyphaseFilterBank(
206        char * _type,       // type of filter
207        unsigned int _k,    // samples per symbol
208        unsigned int _m,    // delay
209        float _beta,        // excess bandwidth factor
210        unsigned int _Npfb  // number of filters
211        )
212{
213    k = _k;
214    m = _m;
215    beta = _beta;
216    Npfb = _Npfb;
217
218    H = NULL;
219
220    if ( strcmp(_type,"rrcos")==0 ) {
221        // Square-root raised-cosine filter
222        CalculateRRCFilterCoefficients();
223        TransposeCoefficientMatrix();
224    } else if ( strcmp(_type,"drrcos")==0 ) {
225        // Derivative square-root raised-cosine filter
226        CalculateRRCFilterCoefficients();
227        CalculateDerivativeFilterCoefficients();
228        TransposeCoefficientMatrix();
229    } else if ( strcmp(_type,"gaussian")==0 ) {
230        // Gaussian filter
231        CalculateGaussianFilterCoefficients();
232        TransposeCoefficientMatrix();
233    } else if ( strcmp(_type,"dgaussian")==0 ) {
234        // Derivative gaussian filter
235        CalculateGaussianFilterCoefficients();
236        CalculateDerivativeFilterCoefficients();
237        TransposeCoefficientMatrix();
238    } else {
239        std::cerr << "ERROR: FIRPolyphaseFilterBank: unknown filter type : " << _type << std::endl;
240        throw 0;
241    }
242
243    // At this point, H should be initialized and h_len should store
244    // the correct length of each filter in the bank.
245    v.SetBufferSize(h_len);
246
247    // memset input buffer to zeros
248    ResetBuffer();
249}
250
251// Initializing constructor
252SigProc::FIRPolyphaseFilterBank::FIRPolyphaseFilterBank(
253        float * _H,         // filter bank coefficients
254        unsigned int _h_len,// length of each filter
255        unsigned int _Npfb  // number of filters
256        )
257{
258    /// \todo perform check on input?
259
260    h_len = _h_len;
261    Npfb = _Npfb;
262
263    // perform deep copy of memory
264    H = new float[Npfb*h_len];
265    for (unsigned int i=0; i<(Npfb*h_len); i++)
266        H[i] = _H[i];
267
268    v.SetBufferSize(h_len);
269
270    // memset input buffer to zeros
271    ResetBuffer();
272}
273
274// destructor
275SigProc::FIRPolyphaseFilterBank::~FIRPolyphaseFilterBank()
276{
277    // delete filter bank coefficients matrix
278    if ( H != NULL )
279        delete [] H;
280
281}
282
283// push input value into buffer
284void SigProc::FIRPolyphaseFilterBank::PushInput(short _x)
285{
286    // Add _x to input buffer
287    v.Push( _x );
288}
289
290// compute filter output from current buffer state using specific filter
291void SigProc::FIRPolyphaseFilterBank::ComputeOutput(
292        short &y,           // output sample
293        unsigned int _b     // filter bank index
294        )
295{
296    // Ensure the requested filter bank index does not exceed the number
297    // of filters actually in the bank
298    if ( _b >= Npfb )
299    {
300        std::cerr << "ERROR: SigProc::FIRPolyphaseFitlerBank::ComputeOutput, "
301                  << " index exceeds filter bank size ("
302                  << _b << " > " << Npfb << ")" << std::endl;
303        throw 0;
304    }
305
306    // Initialize floating point value for output
307    /// \todo make this compatable with FPM
308    float yf(0.0f);
309
310    // Set B to memory block in filter bank array
311    unsigned int B;
312    B = _b*h_len;
313
314    // Accumulate (apply filter)
315    for (unsigned int i=0; i<h_len; i++)
316        yf += float( v[i] ) * H[B+i];
317
318    // Ensure yf is within the scope of short int
319    if ( yf < SHRT_MIN ) {
320        y = SHRT_MIN;
321    } else if ( yf > SHRT_MAX ) {
322        y = SHRT_MAX;
323    } else {
324        y = (short) yf;
325    }
326
327}
328
329// Reset filter buffer
330void SigProc::FIRPolyphaseFilterBank::ResetBuffer()
331{
332    v.Release();
333
334    // Load buffer with zeros
335    for (unsigned int i=0; i<h_len; i++)
336        v.Push( 0 );
337}
338
339// Print filter buffer
340void SigProc::FIRPolyphaseFilterBank::PrintBuffer()
341{
342    v.Print();
343}
344
345// Print filter bank coefficients to the screen
346void SigProc::FIRPolyphaseFilterBank::PrintFilterBankCoefficients()
347{
348    if ( H == NULL )
349    {
350        std::cout << "ERROR: SigProc::FIRPolyphaseFilterBank: "
351                  << "cannot print filter coefficients (matrix empty)"
352                  << std::endl;
353        return;
354    }
355
356    unsigned int r, c, B;
357    std::cout << "H = [" << std::endl;
358    for (r=0; r<Npfb; r++ ) {
359        B = r*h_len;
360        printf("  ");
361
362        for (c=0; c<h_len; c++) {
363            printf("%0.3f ", H[B + c]);
364        }
365        printf(";\n");
366    }
367    std::cout << "   ]" << std::endl;
368
369}
370
371//
372void SigProc::FIRPolyphaseFilterBank::TransposeCoefficientMatrix()
373{
374    // create temporary pointer
375    float * H_tmp;
376    H_tmp = H;
377
378    // allocate new memory for filter bank coefficients
379    H = new float[h_len*Npfb];
380
381    // reshape matrix
382    unsigned int i(0), r, c;
383    for (r=0; r<Npfb; r++) {
384        for (c=0; c<h_len; c++)
385            H[i++] = H_tmp[c*Npfb + r];
386    }
387
388    delete [] H_tmp;
389}
390
391
392// Calculate root raised-cosine coefficients
393void SigProc::FIRPolyphaseFilterBank::CalculateRRCFilterCoefficients()
394{
395    if ( H != NULL )
396        delete [] H;
397
398    // create over-sampled pulse
399    SigProc::DesignRRCFilter(Npfb*k, m, beta, H, h_len);
400
401    // Apply scaling factor to filter coefficients
402    float h_scale = float(k);
403    for (unsigned int i=0; i<h_len; i++)
404        H[i] /= h_scale;
405
406    //
407    h_len = ( h_len - 1 ) / Npfb;
408
409}
410
411//
412void SigProc::FIRPolyphaseFilterBank::CalculateGaussianFilterCoefficients()
413{
414    if ( H != NULL )
415        delete [] H;
416
417}
418
419// Calculate derivative filter coefficients
420void SigProc::FIRPolyphaseFilterBank::CalculateDerivativeFilterCoefficients()
421{
422    unsigned int N = h_len*Npfb;
423
424    float * dH = new float[N];
425
426    for (unsigned int i=0; i<N; i++) {
427        if ( i==0 ) {
428            dH[0] = H[1] - H[N-1];
429        } else if ( i==N-1 ) {
430            dH[N-1] = H[0] - H[N-2];
431        } else {
432            dH[i] = H[i+1] - H[i-1];
433        }
434        dH[i] /= 2.0f;
435    }
436
437    delete [] H;
438    H = dH;
439}
440
441
442SigProc::iir_filter::iir_filter(float a_coeff[], unsigned int len_a, float b_coeff[], unsigned int len_b) : len_A(len_a), len_B(len_b), next_v(0)
443{
444
445    A = new float[len_a];
446    B = new float[len_b];
447
448    for (unsigned int i = 0; i < len_a; ++i)
449        A[i] = a_coeff[i];
450
451    for (unsigned int i = 0; i < len_b; ++i)
452        B[i] = b_coeff[i];
453
454    if (len_A > len_B)
455        len_v = len_A;
456    else
457        len_v = len_B;
458
459    v = new float[len_v];
460
461    for (unsigned int i = 0; i < len_v; ++i)
462        v[i] = 0;
463
464}
465
466void SigProc::iir_filter::ResetBuffer()
467{
468    for (unsigned int i = 0; i < len_v; ++i)
469        v[i] = 0;
470}
471
472void SigProc::iir_filter::do_work(short x, short &y)
473{
474    // calculate new v[n]
475    int v_idx = next_v;
476
477    v[next_v] = x;
478
479    for (unsigned int i = 1; i < len_A; ++i) {
480
481        --v_idx;
482        if (v_idx < 0)
483            v_idx += len_v;
484
485        v[next_v] -= (short) (A[i] * v[v_idx]);
486         
487    }
488
489    // Now calculate the output value
490    v_idx = next_v;
491    float out = 0;
492
493    for (unsigned int i = 0; i < len_B; ++i) {
494        out += (B[i] * v[v_idx]);
495
496        --v_idx;
497        if (v_idx < 0)
498            v_idx += len_v;
499    }
500
501    next_v = (++next_v) % len_v;
502
503    if (out < SHRT_MIN)
504        y = SHRT_MIN;
505    else if (out > SHRT_MAX)
506        y = SHRT_MAX;
507    else
508        y = (short) out;
509}
510
511
512SigProc::fir_filter::fir_filter(float a_coeff[], unsigned int len_a) : len_A(len_a), len_v(len_a),next_v(0)
513 {
514#ifdef FPM
515    A = new mad_fixed_t[len_a];
516    v = new mad_fixed_t[len_v];
517#else
518    A = new float[len_a];
519    v = new short[len_v];
520#endif
521
522    for (unsigned int i = 0; i < len_a; ++i)
523#ifdef FPM
524        A[i] = mad_f_tofixed(a_coeff[i]);
525#else
526        A[i] = a_coeff[i];
527#endif
528
529
530    for (unsigned int i = 0; i < len_v; ++i)
531        v[i] = 0;
532
533
534}
535
536void SigProc::fir_filter::do_work(bool run_filter, short x, short &y)
537{
538    // calculate new v[n]
539    int v_idx = next_v;
540
541    v[next_v] = x;
542    next_v = (++next_v) % len_v;
543
544    if (!run_filter) { // Do not create an output value
545        y = 0;
546        return;
547    }
548
549    // Now calculate the output value
550#ifdef FPM
551    mad_fixed_t out(0);
552#else
553    float out(0.0);
554#endif
555
556    for (unsigned int i = 0; i < len_A; ++i) {
557        if (v[v_idx]) {
558#ifdef FPM
559            out = mad_f_add(out, mad_f_mul(A[i], v[v_idx]));
560#else
561            out += (A[i] * v[v_idx]);
562#endif
563        }
564
565        --v_idx;
566        if (v_idx < 0)
567            v_idx += len_v;
568    }
569
570#ifdef FPM
571        y = (short) out;
572#else
573    if (out < SHRT_MIN)
574        y = SHRT_MIN;
575    else if (out > SHRT_MAX)
576        y = SHRT_MAX;
577    else
578        y = (short) out;
579#endif
580}
581
582void SigProc::fir_filter::reset()
583{
584
585    for (unsigned int i = 0; i < len_v; ++i)
586        v[i] = 0;
587
588    next_v = 0;
589}
Note: See TracBrowser for help on using the browser.