mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
137 lines
No EOL
4.7 KiB
C++
137 lines
No EOL
4.7 KiB
C++
#include "fft_pan.h"
|
|
#include "common/dsp/block.h"
|
|
#include "common/dsp/window/window.h"
|
|
#include "logger.h"
|
|
|
|
namespace satdump
|
|
{
|
|
namespace ndsp
|
|
{
|
|
FFTPanBlock::FFTPanBlock() : Block("fft_pan_cc", {{"in", DSP_SAMPLE_TYPE_CF32}}, {})
|
|
{
|
|
output_fft_buff = new float[dsp::STREAM_BUFFER_SIZE]; // TODOREWORK
|
|
init();
|
|
}
|
|
|
|
FFTPanBlock::~FFTPanBlock()
|
|
{
|
|
if (fft_output_buffer != nullptr)
|
|
destroy_fft();
|
|
delete[] output_fft_buff;
|
|
}
|
|
|
|
void FFTPanBlock::set_fft_settings(int size, uint64_t samplerate, int rate)
|
|
{
|
|
fft_mutex.lock();
|
|
|
|
if (rate < 1)
|
|
rate = 1;
|
|
|
|
p_size = size;
|
|
p_samplerate = samplerate;
|
|
p_rate = rate;
|
|
|
|
fft_size = size;
|
|
|
|
if (fft_output_buffer != nullptr)
|
|
destroy_fft();
|
|
|
|
// Compute FFT settings
|
|
rbuffer_rate = (samplerate / rate);
|
|
rbuffer_size = std::min<int>(rbuffer_rate, fft_size);
|
|
rbuffer_skip = rbuffer_rate - rbuffer_size;
|
|
logger->trace("FFT Rate %d, Samplerate %d, Final Size %d, Skip %d", rbuffer_rate, samplerate, rbuffer_size, rbuffer_skip);
|
|
|
|
// Init taps, rectangular window
|
|
fft_taps.resize(rbuffer_size);
|
|
for (int i = 0; i < rbuffer_size; i++)
|
|
fft_taps[i] = dsp::window::nuttall(i, rbuffer_size - 1) * ((i % 2) ? 1.0f : -1.0f);
|
|
|
|
// Init FFTW
|
|
fftw_in = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
|
fftw_out = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * fft_size);
|
|
fftw_plan = fftwf_plan_dft_1d(fft_size, fftw_in, fftw_out, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
|
|
memset(fftw_in, 0, sizeof(fftwf_complex) * fft_size);
|
|
memset(fftw_out, 0, sizeof(fftwf_complex) * fft_size);
|
|
|
|
// Output buffer
|
|
fft_input_buffer = dsp::create_volk_buffer<complex_t>(fft_size);
|
|
fft_output_buffer = dsp::create_volk_buffer<float>(fft_size);
|
|
|
|
reshape_buffer_size = std::max<int>(dsp::STREAM_BUFFER_SIZE, rbuffer_rate * 10); // TODOREWORK
|
|
fft_reshape_buffer = dsp::create_volk_buffer<complex_t>(reshape_buffer_size);
|
|
in_reshape_buffer = 0;
|
|
|
|
fft_mutex.unlock();
|
|
}
|
|
|
|
void FFTPanBlock::destroy_fft()
|
|
{
|
|
fftwf_free(fftw_in);
|
|
fftwf_free(fftw_out);
|
|
fftwf_destroy_plan(fftw_plan);
|
|
volk_free(fft_input_buffer);
|
|
volk_free(fft_output_buffer);
|
|
volk_free(fft_reshape_buffer);
|
|
}
|
|
|
|
bool FFTPanBlock::work()
|
|
{
|
|
DSPBuffer iblk = inputs[0].fifo->wait_dequeue();
|
|
|
|
if (iblk.isTerminator())
|
|
{
|
|
inputs[0].fifo->free(iblk);
|
|
return true;
|
|
}
|
|
|
|
int nsamples = iblk.size;
|
|
|
|
fft_mutex.lock();
|
|
|
|
if (in_reshape_buffer + nsamples < reshape_buffer_size)
|
|
{
|
|
memcpy(&fft_reshape_buffer[in_reshape_buffer], iblk.getSamples<complex_t>(), nsamples * sizeof(complex_t));
|
|
in_reshape_buffer += nsamples;
|
|
}
|
|
inputs[0].fifo->free(iblk);
|
|
|
|
if (in_reshape_buffer > rbuffer_rate)
|
|
{
|
|
int pos_in_buffer = 0;
|
|
while (in_reshape_buffer - pos_in_buffer > rbuffer_rate)
|
|
{
|
|
memcpy(fft_input_buffer, &fft_reshape_buffer[pos_in_buffer], rbuffer_size * sizeof(complex_t));
|
|
pos_in_buffer += rbuffer_rate;
|
|
|
|
complex_t *buffer_ptr = fft_input_buffer;
|
|
|
|
volk_32fc_32f_multiply_32fc((lv_32fc_t *)fftw_in, (lv_32fc_t *)buffer_ptr, fft_taps.data(), rbuffer_size);
|
|
|
|
fftwf_execute(fftw_plan);
|
|
|
|
volk_32fc_s32f_power_spectrum_32f(fft_output_buffer, (lv_32fc_t *)fftw_out, fft_size, fft_size);
|
|
|
|
if (avg_num < 1)
|
|
avg_num = 1;
|
|
float avg_rate = 1.0 / avg_num;
|
|
|
|
for (int i = 0; i < fft_size; i++)
|
|
output_fft_buff[i] = output_fft_buff[i] * (1.0f - avg_rate) + fft_output_buffer[i] * avg_rate;
|
|
|
|
on_fft(output_fft_buff, fft_size);
|
|
}
|
|
|
|
if (pos_in_buffer < in_reshape_buffer)
|
|
{
|
|
memmove(fft_reshape_buffer, &fft_reshape_buffer[pos_in_buffer], (in_reshape_buffer - pos_in_buffer) * sizeof(complex_t));
|
|
in_reshape_buffer -= pos_in_buffer;
|
|
}
|
|
}
|
|
|
|
fft_mutex.unlock();
|
|
return false;
|
|
}
|
|
} // namespace ndsp
|
|
} // namespace satdump
|