gqrx/dsp/rx_fft.cc

199 lines
4.9 KiB
C++
Raw Normal View History

2011-06-13 10:00:05 +00:00
/* -*- c++ -*- */
/*
* Copyright 2011 Alexandru Csete OZ9AEC.
*
* Gqrx 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.
*
* Gqrx 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 Gqrx; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include <gr_io_signature.h>
#include <gr_firdes.h>
#include <gr_complex.h>
#include <gri_fft.h>
2011-06-13 10:00:05 +00:00
#include <dsp/rx_fft.h>
rx_fft_c_sptr make_rx_fft_c (int fftsize, int wintype, bool use_avg)
{
return gnuradio::get_initial_sptr(new rx_fft_c (fftsize, wintype, use_avg));
}
/*! \brief Create receiver FFT object.
* \param fftsize The FFT size.
* \param wintype The window type (see gr_firdes::win_type).
* \param use_avg Whether to use averaging.
*
* \bug Implement use_avg.
*/
2011-06-13 10:00:05 +00:00
rx_fft_c::rx_fft_c(int fftsize, int wintype, bool use_avg)
: gr_sync_block ("rx_fft_c",
gr_make_io_signature(1, 1, sizeof(gr_complex)),
gr_make_io_signature(0, 0, 0)),
d_fftsize(fftsize),
d_wintype(-1),
2011-06-13 10:00:05 +00:00
d_use_avg(use_avg)
{
/* create FFT object */
d_fft = new gri_fft_complex (d_fftsize, true);
/* allocate circular buffer */
d_cbuf.set_capacity(d_fftsize);
/* create FFT window */
set_window_type(wintype);
2011-06-13 10:00:05 +00:00
}
rx_fft_c::~rx_fft_c()
{
delete d_fft;
2011-06-13 10:00:05 +00:00
}
/*! \brief Receiver FFT work method.
* \param mooutput_items
* \param input_items
* \param output_items
*
* This method does nothing except throwing the incoming samples into the
* circular buffer.
* FFT is only executed when the GUI asks for new FFT data via get_fft_data().
*/
int rx_fft_c::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
2011-06-13 10:00:05 +00:00
{
int i,j = 0;
const gr_complex *in = (const gr_complex*)input_items[0];
/* just throw new samples into the buffer */
boost::mutex::scoped_lock lock(d_mutex);
for (i = 0; i < noutput_items; i++) {
d_cbuf.push_back(in[i]);
}
return noutput_items;
}
/*! \brief Get FFT data.
* \param fftPoint Buffer to copy FFT data
* \param fftSize Current FFt size (output).
*/
void rx_fft_c::get_fft_data(std::complex<float>* fftPoints, int &fftSize)
{
boost::mutex::scoped_lock lock(d_mutex);
if (d_cbuf.size() < d_fftsize) {
// not enough samples in the buffer
fftSize = 0;
return;
}
/* perform FFT */
do_fft(d_cbuf.linearize(), d_cbuf.size()); // FIXME: array_one() and two() may be faster
d_cbuf.clear();
/* get FFT data */
memcpy(fftPoints, d_fft->get_outbuf(), sizeof(gr_complex)*d_fftsize);
fftSize = d_fftsize;
}
/*! \brief Compute FFT on the available input data.
* \param data_in The data to compute FFt on.
* \param size The size of data_in.
*
* Note that this function does not lock the mutex since the caller, get_fft_data()
* has alrady locked it.
*/
void rx_fft_c::do_fft(const gr_complex *data_in, int size)
{
/* apply window, if any */
if (d_window.size()) {
gr_complex *dst = d_fft->get_inbuf();
int i;
for (i = 0; i < size; i++)
dst[i] = data_in[i] * d_window[i];
}
else {
memcpy(d_fft->get_inbuf(), data_in, sizeof(gr_complex)*size);
}
/* compute FFT */
d_fft->execute();
}
/*! \brief Set new FFT size. */
void rx_fft_c::set_fft_size(int fftsize)
{
if (fftsize != d_fftsize) {
boost::mutex::scoped_lock lock(d_mutex);
d_fftsize = fftsize;
/* clear and resize circular buffer */
d_cbuf.clear();
d_cbuf.set_capacity(d_fftsize);
/* reset window */
d_wintype = -1;
set_window_type(d_wintype);
/* reset FFT object (also reset FFTW plan) */
delete d_fft;
d_fft = new gri_fft_complex (d_fftsize, true);
}
}
/*! \brief Get currently used FFT size. */
int rx_fft_c::get_fft_size()
{
return d_fftsize;
}
2011-06-13 10:00:05 +00:00
/*! \brief Set new window type. */
void rx_fft_c::set_window_type(int wintype)
{
if (wintype == d_wintype) {
/* nothing to do */
return;
2011-06-13 10:00:05 +00:00
}
d_wintype = wintype;
if ((d_wintype < gr_firdes::WIN_HAMMING) || (d_wintype > gr_firdes::WIN_BLACKMAN_hARRIS)) {
d_wintype = gr_firdes::WIN_HAMMING;
}
d_window.clear();
d_window = gr_firdes::window((gr_firdes::win_type)d_wintype, d_fftsize, 6.76);
2011-06-13 10:00:05 +00:00
}
/*! \brief Get currently used window type. */
int rx_fft_c::get_window_type()
{
return d_wintype;
}