2023-11-19 00:43:20 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
|
|
|
// written by Christian Daniel //
|
|
|
|
// Copyright (C) 2014-2015 John Greb <hexameron@spam.no> //
|
|
|
|
// Copyright (C) 2015-2018, 2022-2023 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
|
|
|
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
|
|
|
|
// //
|
|
|
|
// This program 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 as version 3 of the License, or //
|
|
|
|
// (at your option) any later version. //
|
|
|
|
// //
|
|
|
|
// This program 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 V3 for more details. //
|
|
|
|
// //
|
|
|
|
// You should have received a copy of the GNU General Public License //
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
2014-06-27 12:36:13 -04:00
|
|
|
/*
|
2017-03-15 21:45:51 -04:00
|
|
|
* Filters from Fldigi.
|
2014-06-27 12:36:13 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _FFTFILT_H
|
|
|
|
#define _FFTFILT_H
|
|
|
|
|
2015-05-15 05:29:41 -04:00
|
|
|
#include <complex>
|
2020-11-03 07:52:12 -05:00
|
|
|
#include <cmath>
|
|
|
|
|
2014-06-27 12:36:13 -04:00
|
|
|
#include "gfft.h"
|
2022-05-17 19:30:32 -04:00
|
|
|
#include "fftwindow.h"
|
2023-11-05 04:33:27 -05:00
|
|
|
#include "fftnr.h"
|
2018-03-20 08:49:21 -04:00
|
|
|
#include "export.h"
|
2014-06-27 12:36:13 -04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2018-03-03 14:23:38 -05:00
|
|
|
class SDRBASE_API fftfilt {
|
2014-06-27 12:36:13 -04:00
|
|
|
enum {NONE, BLACKMAN, HAMMING, HANNING};
|
|
|
|
|
2015-05-15 05:29:41 -04:00
|
|
|
public:
|
|
|
|
typedef std::complex<float> cmplx;
|
|
|
|
|
2020-11-05 12:55:39 -05:00
|
|
|
fftfilt(int len);
|
2015-05-15 05:29:41 -04:00
|
|
|
fftfilt(float f1, float f2, int len);
|
2015-06-21 06:46:47 -04:00
|
|
|
fftfilt(float f2, int len);
|
2015-05-15 05:29:41 -04:00
|
|
|
~fftfilt();
|
|
|
|
// f1 < f2 ==> bandpass
|
|
|
|
// f1 > f2 ==> band reject
|
2022-05-17 19:30:32 -04:00
|
|
|
void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
2022-12-10 13:02:38 -05:00
|
|
|
void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true, FFTWindow::Function wf = FFTWindow::Blackman);
|
2022-12-12 01:50:35 -05:00
|
|
|
void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true); //!< Windowless version
|
2022-05-17 19:30:32 -04:00
|
|
|
void create_dsb_filter(float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
|
|
|
void create_asym_filter(float fopp, float fin, FFTWindow::Function wf = FFTWindow::Blackman); //!< two different filters for in band and opposite band
|
2018-05-21 18:10:56 -04:00
|
|
|
void create_rrc_filter(float fb, float a); //!< root raised cosine. fb is half the band pass
|
2015-05-15 05:29:41 -04:00
|
|
|
|
2015-06-21 06:46:47 -04:00
|
|
|
int noFilt(const cmplx& in, cmplx **out);
|
2015-05-15 05:29:41 -04:00
|
|
|
int runFilt(const cmplx& in, cmplx **out);
|
2017-03-15 10:37:51 -04:00
|
|
|
int runSSB(const cmplx& in, cmplx **out, bool usb, bool getDC = true);
|
2018-05-13 11:27:24 -04:00
|
|
|
int runDSB(const cmplx& in, cmplx **out, bool getDC = true);
|
2024-07-10 16:37:52 -04:00
|
|
|
int runAsym(const cmplx & in, cmplx **out, bool usb); //!< Asymmetrical filtering can be used for vestigial sideband
|
2015-05-15 05:29:41 -04:00
|
|
|
|
2023-11-05 04:33:27 -05:00
|
|
|
void setDNR(bool dnr) { m_dnr = dnr; }
|
|
|
|
void setDNRScheme(FFTNoiseReduction::Scheme scheme) { m_dnrScheme = scheme; }
|
|
|
|
void setDNRAboveAvgFactor(float aboveAvgFactor) { m_dnrAboveAvgFactor = aboveAvgFactor; }
|
|
|
|
void setDNRSigmaFactor(float sigmaFactor) { m_dnrSigmaFactor = sigmaFactor; }
|
|
|
|
void setDNRNbPeaks(int nbPeaks) { m_dnrNbPeaks = nbPeaks; }
|
|
|
|
void setDNRAlpha(float alpha) { m_noiseReduction.setAlpha(alpha); }
|
|
|
|
|
2014-06-27 12:36:13 -04:00
|
|
|
protected:
|
2023-11-05 04:33:27 -05:00
|
|
|
// helper class for FFT based noise reduction
|
2014-06-27 12:36:13 -04:00
|
|
|
int flen;
|
|
|
|
int flen2;
|
|
|
|
g_fft<float> *fft;
|
|
|
|
cmplx *filter;
|
2017-03-16 05:11:03 -04:00
|
|
|
cmplx *filterOpp;
|
2014-12-25 16:24:03 -05:00
|
|
|
cmplx *data;
|
2014-06-27 12:36:13 -04:00
|
|
|
cmplx *ovlbuf;
|
|
|
|
cmplx *output;
|
|
|
|
int inptr;
|
|
|
|
int pass;
|
|
|
|
int window;
|
2023-11-05 04:33:27 -05:00
|
|
|
bool m_dnr;
|
|
|
|
FFTNoiseReduction::Scheme m_dnrScheme;
|
|
|
|
float m_dnrAboveAvgFactor; //!< above average factor
|
|
|
|
float m_dnrSigmaFactor; //!< sigma multiplicator for average + std deviation
|
|
|
|
int m_dnrNbPeaks; //!< number of peaks (peaks scheme)
|
|
|
|
FFTNoiseReduction m_noiseReduction;
|
2014-06-27 12:36:13 -04:00
|
|
|
|
2018-05-21 18:10:56 -04:00
|
|
|
inline float fsinc(float fc, int i, int len)
|
|
|
|
{
|
2018-02-24 04:29:27 -05:00
|
|
|
int len2 = len/2;
|
|
|
|
return (i == len2) ? 2.0 * fc:
|
|
|
|
sin(2 * M_PI * fc * (i - len2)) / (M_PI * (i - len2));
|
2014-06-27 12:36:13 -04:00
|
|
|
}
|
2015-06-21 06:46:47 -04:00
|
|
|
|
2018-05-21 18:10:56 -04:00
|
|
|
inline float _blackman(int i, int len)
|
|
|
|
{
|
2017-03-15 21:45:51 -04:00
|
|
|
return (0.42 -
|
|
|
|
0.50 * cos(2.0 * M_PI * i / len) +
|
2014-06-27 12:36:13 -04:00
|
|
|
0.08 * cos(4.0 * M_PI * i / len));
|
|
|
|
}
|
2015-06-21 06:46:47 -04:00
|
|
|
|
2018-05-21 18:10:56 -04:00
|
|
|
/** RRC function in the frequency domain. Zero frequency is on the sides with first half in positive frequencies
|
|
|
|
* and second half in negative frequencies */
|
|
|
|
inline cmplx frrc(float fb, float a, int i, int len)
|
|
|
|
{
|
|
|
|
float x = i/(float)len; // normalize to [0..1]
|
|
|
|
x = 0.5-fabs(x-0.5); // apply symmetry: now both halves overlap near 0
|
2018-05-21 20:20:36 -04:00
|
|
|
float tr = fb*a; // half the transition zone
|
2018-05-21 18:10:56 -04:00
|
|
|
|
|
|
|
if (x < fb-tr)
|
|
|
|
{
|
|
|
|
return 1.0; // in band
|
|
|
|
}
|
|
|
|
else if (x < fb+tr) // transition
|
|
|
|
{
|
|
|
|
float y = ((x-(fb-tr)) / (2.0*tr))*M_PI;
|
|
|
|
return (cos(y) + 1.0f)/2.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0.0; // out of band
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 12:36:13 -04:00
|
|
|
void init_filter();
|
2015-06-21 06:46:47 -04:00
|
|
|
void init_dsb_filter();
|
2014-06-27 12:36:13 -04:00
|
|
|
};
|
|
|
|
|
2015-01-11 14:30:48 -05:00
|
|
|
|
|
|
|
|
|
|
|
/* Sliding FFT filter from Fldigi */
|
2018-03-03 14:23:38 -05:00
|
|
|
class SDRBASE_API sfft {
|
2015-01-11 14:30:48 -05:00
|
|
|
#define K1 0.99999
|
2015-05-15 05:29:41 -04:00
|
|
|
public:
|
|
|
|
typedef std::complex<float> cmplx;
|
|
|
|
sfft(int len);
|
|
|
|
~sfft();
|
|
|
|
void run(const cmplx& input);
|
|
|
|
void fetch(float *result);
|
2015-01-11 14:30:48 -05:00
|
|
|
private:
|
|
|
|
int fftlen;
|
|
|
|
int first;
|
|
|
|
int last;
|
|
|
|
int ptr;
|
|
|
|
struct vrot_bins_pair;
|
|
|
|
vrot_bins_pair *vrot_bins;
|
|
|
|
cmplx *delay;
|
|
|
|
float k2;
|
|
|
|
};
|
|
|
|
|
2014-06-27 12:36:13 -04:00
|
|
|
#endif
|