1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-04-27 18:04:00 -04:00
sdrangel/sdrbase/dsp/fftfilterrrc.h
2026-02-12 23:23:27 +01:00

151 lines
6.0 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-2019, 2023 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2026 SDRangel contributors //
// //
// 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/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_DSP_FFTFILTERRRC_H
#define INCLUDE_DSP_FFTFILTERRRC_H
#include <complex>
#include <vector>
#include "gfft.h"
#include "export.h"
/**
* @brief FFT-based root raised cosine filter for complex signals
*
* Implements a frequency-domain root raised cosine (RRC) filter using overlap-add
* FFT convolution. The RRC filter is commonly used for pulse shaping in digital
* communications to minimize intersymbol interference (ISI) while satisfying
* the Nyquist criterion.
*
* The filter operates in the frequency domain for computational efficiency,
* applying the RRC frequency response directly to the FFT bins of the input signal.
*/
class SDRBASE_API FFTFilterRRC
{
public:
using Complex = std::complex<float>;
/**
* @brief Construct FFT-based root raised cosine filter
*
* @param len FFT length (should be power of 2 for efficiency)
*/
explicit FFTFilterRRC(int len);
/**
* @brief Destructor
*/
~FFTFilterRRC();
// Disable copy semantics (manages raw pointers)
FFTFilterRRC(const FFTFilterRRC&) = delete;
FFTFilterRRC& operator=(const FFTFilterRRC&) = delete;
/**
* @brief Create root raised cosine filter in frequency domain
*
* @param symbolRate Symbol rate in Hz (normalized to sample rate)
* @param rolloff Roll-off factor (beta) - typically 0.2 to 0.5
* 0 = rectangular, 1 = full cosine roll-off
*
* The filter bandwidth extends from -symbolRate*(1+rolloff)/2 to
* +symbolRate*(1+rolloff)/2 in normalized frequency (0 to 0.5 = Nyquist).
*
* Creates mathematically correct RRC frequency response for use in
* digital communications applications.
*/
void create(float symbolRate, float rolloff);
/**
* @brief Process one complex input sample through the filter
*
* Uses overlap-add FFT convolution. Accumulates input samples until
* a half-buffer is filled, then performs FFT, frequency-domain multiplication
* with the RRC filter, IFFT, and overlap-add to produce output samples.
*
* @param input Complex input sample
* @param output Pointer to output buffer (will point to internal buffer)
* @return Number of output samples available (0 or fftLen/2)
*/
int process(const Complex& input, Complex** output);
/**
* @brief Get FFT length
* @return FFT length in samples
*/
int getFFTLength() const { return m_fftLen; }
/**
* @brief Get current symbol rate
* @return Symbol rate (normalized)
*/
float getSymbolRate() const { return m_symbolRate; }
/**
* @brief Get current rolloff factor
* @return Rolloff factor (beta)
*/
float getRolloff() const { return m_rolloff; }
/**
* @brief Get pointer to frequency-domain filter coefficients
*
* The filter coefficients are in the frequency domain, corresponding to the FFT bins.
*
* @return Pointer to array of complex filter coefficients (length = FFT length)
*/
const Complex* getFilter() const { return m_filter; }
private:
/**
* @brief Initialize internal buffers and FFT engine
*/
void initFilter();
/**
* @brief Compute RRC frequency response for a given frequency bin
*
* Implements the RRC transfer function in frequency domain:
* - For |f| <= (1-beta)/(2T): H(f) = T
* - For (1-beta)/(2T) < |f| <= (1+beta)/(2T): H(f) = T/2 * [1 + cos(pi*T/beta * (|f| - (1-beta)/(2T)))]
* - For |f| > (1+beta)/(2T): H(f) = 0
*
* @param symbolRate Symbol rate (normalized to sample rate)
* @param rolloff Roll-off factor (beta)
* @param binIndex FFT bin index
* @param fftLen FFT length
* @return Complex frequency response at this bin
*/
Complex computeRRCResponse(float symbolRate, float rolloff, int binIndex, int fftLen) const;
int m_fftLen; //!< FFT length
int m_fftLen2; //!< Half FFT length
g_fft<float>* m_fft; //!< FFT engine
Complex* m_filter; //!< Frequency-domain filter coefficients
Complex* m_fftBuffer; //!< Time-domain input buffer for FFT
Complex* m_overlapBuffer; //!< Overlap buffer for overlap-add
Complex* m_outputBuffer; //!< Output buffer
int m_inputIndex; //!< Current input buffer index
float m_symbolRate; //!< Current symbol rate (normalized)
float m_rolloff; //!< Current rolloff factor
};
#endif // INCLUDE_DSP_FFTFILTERRRC_H