diff options
Diffstat (limited to 'gr-filter/lib/firdes.cc')
-rw-r--r-- | gr-filter/lib/firdes.cc | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/gr-filter/lib/firdes.cc b/gr-filter/lib/firdes.cc new file mode 100644 index 000000000..5c3320d71 --- /dev/null +++ b/gr-filter/lib/firdes.cc @@ -0,0 +1,855 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2008,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <filter/firdes.h> +#include <stdexcept> + +using std::vector; + +namespace gr { + namespace filter { + +#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ + + static double Izero(double x) + { + double sum, u, halfx, temp; + int n; + + sum = u = n = 1; + halfx = x/2.0; + do { + temp = halfx/(double)n; + n += 1; + temp *= temp; + u *= temp; + sum += u; + } while (u >= IzeroEPSILON*sum); + return(sum); + } + + + // + // === Low Pass === + // + + vector<float> + firdes::low_pass_2(double gain, + double sampling_freq, // Hz + double cutoff_freq, // Hz BEGINNING of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response + // [sin(x)/x for the low pass case] + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = fwT0 / M_PI * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For low-pass, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + vector<float> + firdes::low_pass(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response + // [sin(x)/x for the low pass case] + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = fwT0 / M_PI * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For low-pass, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + // + // === High Pass === + // + + vector<float> + firdes::high_pass_2(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response times the window function + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = (1 - (fwT0 / M_PI)) * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = -sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For high-pass, gain @ fs/2 freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * M_PI); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + vector<float> + firdes::high_pass(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = (1 - (fwT0 / M_PI)) * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = -sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For high-pass, gain @ fs/2 freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * M_PI); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // === Band Pass === + // + + vector<float> + firdes::band_pass_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = (fwT1 - fwT0) / M_PI * w[n + M]; + else { + taps[n + M] = (sin(n * fwT1) - sin(n * fwT0)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-pass, gain @ center freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * (fwT0 + fwT1) * 0.5); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + vector<float> + firdes::band_pass(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = (fwT1 - fwT0) / M_PI * w[n + M]; + else { + taps[n + M] = (sin(n * fwT1) - sin(n * fwT0)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-pass, gain @ center freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * (fwT0 + fwT1) * 0.5); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // === Complex Band Pass === + // + + vector<gr_complex> + firdes::complex_band_pass_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f_c(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + vector<gr_complex> taps(ntaps); + vector<float> lptaps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + lptaps = low_pass_2(gain, sampling_freq, + (high_cutoff_freq - low_cutoff_freq)/2, + transition_width, attenuation_dB, + window_type, beta); + + gr_complex *optr = &taps[0]; + float *iptr = &lptaps[0]; + float freq = M_PI * (high_cutoff_freq + low_cutoff_freq)/sampling_freq; + float phase = 0; + if (lptaps.size() & 01) { + phase = - freq * ( lptaps.size() >> 1 ); + } + else + phase = - freq/2.0 * ((1 + 2*lptaps.size()) >> 1); + + for(unsigned int i = 0; i < lptaps.size(); i++) { + *optr++ = gr_complex(*iptr * cos(phase), *iptr * sin(phase)); + iptr++, phase += freq; + } + + return taps; + } + + + vector<gr_complex> + firdes::complex_band_pass(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f_c (sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector<gr_complex> taps(ntaps); + vector<float> lptaps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + lptaps = low_pass(gain, sampling_freq, + (high_cutoff_freq - low_cutoff_freq)/2, + transition_width, window_type, beta); + + gr_complex *optr = &taps[0]; + float *iptr = &lptaps[0]; + float freq = M_PI * (high_cutoff_freq + low_cutoff_freq)/sampling_freq; + float phase = 0; + if(lptaps.size() & 01) { + phase = - freq * ( lptaps.size() >> 1 ); + } + else + phase = - freq/2.0 * ((1 + 2*lptaps.size()) >> 1); + + for(unsigned int i=0;i<lptaps.size();i++) { + *optr++ = gr_complex(*iptr * cos(phase), *iptr * sin(phase)); + iptr++, phase += freq; + } + + return taps; + } + + // + // === Band Reject === + // + + vector<float> + firdes::band_reject_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response times the window function + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = 1.0 + ((fwT0 - fwT1) / M_PI * w[n + M]); + else { + taps[n + M] = (sin(n * fwT0) - sin(n * fwT1)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-reject, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + vector<float> + firdes::band_reject(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector<float> taps(ntaps); + vector<float> w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = 1.0 + ((fwT0 - fwT1) / M_PI * w[n + M]); + else { + taps[n + M] = (sin(n * fwT0) - sin(n * fwT1)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-reject, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // Hilbert Transform + // + + vector<float> + firdes::hilbert(unsigned int ntaps, + win_type windowtype, + double beta) + { + if(!(ntaps & 1)) + throw std::out_of_range("Hilbert: Must have odd number of taps"); + + vector<float> taps(ntaps); + vector<float> w = window (windowtype, ntaps, beta); + unsigned int h = (ntaps-1)/2; + float gain=0; + for(unsigned int i = 1; i <= h; i++) { + if(i & 1) { + float x = 1/(float)i; + taps[h+i] = x * w[h+i]; + taps[h-i] = -x * w[h-i]; + gain = taps[h+i] - gain; + } + else + taps[h+i] = taps[h-i] = 0; + } + + gain = 2 * fabs(gain); + for(unsigned int i = 0; i < ntaps; i++) + taps[i] /= gain; + return taps; + } + + // + // Gaussian + // + + vector<float> + firdes::gaussian(double gain, + double spb, + double bt, + int ntaps) + { + vector<float> taps(ntaps); + double scale = 0; + double dt = 1.0/spb; + double s = 1.0/(sqrt(log(2.0)) / (2*M_PI*bt)); + double t0 = -0.5 * ntaps; + double ts; + for(int i=0;i<ntaps;i++) { + t0++; + ts = s*dt*t0; + taps[i] = exp(-0.5*ts*ts); + scale += taps[i]; + } + for(int i=0;i<ntaps;i++) + taps[i] = taps[i] / scale * gain; + + return taps; + } + + + // + // Root Raised Cosine + // + + vector<float> + firdes::root_raised_cosine(double gain, + double sampling_freq, + double symbol_rate, + double alpha, + int ntaps) + { + ntaps |= 1; // ensure that ntaps is odd + + double spb = sampling_freq/symbol_rate; // samples per bit/symbol + vector<float> taps(ntaps); + double scale = 0; + for(int i = 0; i < ntaps; i++) { + double x1,x2,x3,num,den; + double xindx = i - ntaps/2; + x1 = M_PI * xindx/spb; + x2 = 4 * alpha * xindx / spb; + x3 = x2*x2 - 1; + + if(fabs(x3) >= 0.000001) { // Avoid Rounding errors... + if(i != ntaps/2) + num = cos((1+alpha)*x1) + sin((1-alpha)*x1)/(4*alpha*xindx/spb); + else + num = cos((1+alpha)*x1) + (1-alpha) * M_PI / (4*alpha); + den = x3 * M_PI; + } + else { + if(alpha==1) { + taps[i] = -1; + continue; + } + x3 = (1-alpha)*x1; + x2 = (1+alpha)*x1; + num = (sin(x2)*(1+alpha)*M_PI + - cos(x3)*((1-alpha)*M_PI*spb)/(4*alpha*xindx) + + sin(x3)*spb*spb/(4*alpha*xindx*xindx)); + den = -32 * M_PI * alpha * alpha * xindx/spb; + } + taps[i] = 4 * alpha * num / den; + scale += taps[i]; + } + + for(int i = 0; i < ntaps; i++) + taps[i] = taps[i] * gain / scale; + + return taps; + } + + // + // === Utilities === + // + + // delta_f / width_factor gives number of taps required. + static const float width_factor[5] = { // indexed by win_type + 3.3, // WIN_HAMMING + 3.1, // WIN_HANN + 5.5, // WIN_BLACKMAN + 2.0, // WIN_RECTANGULAR + //5.0 // WIN_KAISER (guesstimate compromise) + //2.0 // WIN_KAISER (guesstimate compromise) + 10.0 // WIN_KAISER + }; + + int + firdes::compute_ntaps_windes(double sampling_freq, + double transition_width, // this is frequency, not relative frequency + double attenuation_dB) + { + // Based on formula from Multirate Signal Processing for + // Communications Systems, fredric j harris + int ntaps = (int)(attenuation_dB*sampling_freq/(22.0*transition_width)); + if ((ntaps & 1) == 0) // if even... + ntaps++; // ...make odd + return ntaps; + } + + int + firdes::compute_ntaps(double sampling_freq, + double transition_width, + win_type window_type, + double beta) + { + // normalized transition width + double delta_f = transition_width / sampling_freq; + + // compute number of taps required for given transition width + int ntaps = (int)(width_factor[window_type] / delta_f + 0.5); + if((ntaps & 1) == 0) // if even... + ntaps++; // ...make odd + + return ntaps; + } + + double + firdes::bessi0(double x) + { + double ax,ans; + double y; + + ax=fabs(x); + if (ax < 3.75) { + y=x/3.75; + y*=y; + ans=1.0+y*(3.5156229+y*(3.0899424+y*(1.2067492 + +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2))))); + } + else { + y=3.75/ax; + ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1 + +y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2 + +y*(-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1 + +y*0.392377e-2)))))))); + } + return ans; + } + + vector<float> + firdes::window (win_type type, int ntaps, double beta) + { + vector<float> taps(ntaps); + int M = ntaps - 1; // filter order + + switch (type) { + case WIN_RECTANGULAR: + for(int n = 0; n < ntaps; n++) + taps[n] = 1; + + case WIN_HAMMING: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.54 - 0.46 * cos((2 * M_PI * n) / M); + break; + + case WIN_HANN: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.5 - 0.5 * cos((2 * M_PI * n) / M); + break; + + case WIN_BLACKMAN: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.42 - 0.50 * cos((2*M_PI * n) / (M-1)) + - 0.08 * cos((4*M_PI * n) / (M-1)); + break; + + case WIN_BLACKMAN_hARRIS: + for(int n = -ntaps/2; n < ntaps/2; n++) + taps[n+ntaps/2] = 0.35875 + 0.48829*cos((2*M_PI * n) / (float)M) + + 0.14128*cos((4*M_PI * n) / (float)M) + 0.01168*cos((6*M_PI * n) / (float)M); + break; + + case WIN_KAISER: + { + double IBeta = 1.0/Izero(beta); + double inm1 = 1.0/((double)(ntaps)); + double temp; + //fprintf(stderr, "IBeta = %g; inm1 = %g\n", IBeta, inm1); + + for(int i=0; i<ntaps; i++) { + temp = i * inm1; + //fprintf(stderr, "temp = %g\n", temp); + taps[i] = Izero(beta*sqrt(1.0-temp*temp)) * IBeta; + //fprintf(stderr, "taps[%d] = %g\n", i, taps[i]); + } + } + break; + + default: + throw std::out_of_range("firdes:window: type out of range"); + } + + return taps; + } + + void + firdes::sanity_check_1f(double sampling_freq, + double fa, // cutoff freq + double transition_width) + { + if(sampling_freq <= 0.0) + throw std::out_of_range("firdes check failed: sampling_freq > 0"); + + if(fa <= 0.0 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if(transition_width <= 0) + throw std::out_of_range("gr_dirdes check failed: transition_width > 0"); + } + + void + firdes::sanity_check_2f(double sampling_freq, + double fa, // first cutoff freq + double fb, // second cutoff freq + double transition_width) + { + if (sampling_freq <= 0.0) + throw std::out_of_range("firdes check failed: sampling_freq > 0"); + + if (fa <= 0.0 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if (fb <= 0.0 || fb > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fb <= sampling_freq / 2"); + + if (fa > fb) + throw std::out_of_range("firdes check failed: fa <= fb"); + + if (transition_width <= 0) + throw std::out_of_range("firdes check failed: transition_width > 0"); + } + + void + firdes::sanity_check_2f_c(double sampling_freq, + double fa, // first cutoff freq + double fb, // second cutoff freq + double transition_width) + { + if(sampling_freq <= 0.0) + throw std::out_of_range("firdes check failed: sampling_freq > 0"); + + if(fa < -sampling_freq / 2 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if(fb < -sampling_freq / 2 || fb > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fb <= sampling_freq / 2"); + + if(fa > fb) + throw std::out_of_range("firdes check failed: fa <= fb"); + + if(transition_width <= 0) + throw std::out_of_range("firdes check failed: transition_width > 0"); + } + + } /* namespace filter */ +} /* namespace gr */ |