summaryrefslogtreecommitdiff
path: root/gr-fft/lib/fft_v_fftw.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-fft/lib/fft_v_fftw.cc')
-rw-r--r--gr-fft/lib/fft_v_fftw.cc217
1 files changed, 217 insertions, 0 deletions
diff --git a/gr-fft/lib/fft_v_fftw.cc b/gr-fft/lib/fft_v_fftw.cc
new file mode 100644
index 0000000000..387e63b458
--- /dev/null
+++ b/gr-fft/lib/fft_v_fftw.cc
@@ -0,0 +1,217 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2007,2008,2010,2012,2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fft_v_fftw.h"
+#include <math.h>
+#include <string.h>
+#include <volk/volk.h>
+
+namespace gr {
+namespace fft {
+
+template <class T, bool forward>
+typename fft_v<T, forward>::sptr fft_v<T, forward>::make(int fft_size,
+ const std::vector<float>& window,
+ bool shift,
+ int nthreads)
+{
+ return gnuradio::get_initial_sptr(
+ new fft_v_fftw<T, forward>(fft_size, window, shift, nthreads));
+}
+
+template <class T, bool forward>
+fft_v_fftw<T, forward>::fft_v_fftw(int fft_size,
+ const std::vector<float>& window,
+ bool shift,
+ int nthreads)
+ : sync_block("fft_v_fftw",
+ io_signature::make(1, 1, fft_size * sizeof(T)),
+ io_signature::make(1, 1, fft_size * sizeof(gr_complex))),
+ d_fft_size(fft_size),
+ d_fft(fft_size, nthreads),
+ d_shift(shift)
+{
+ if (!set_window(window))
+ throw std::runtime_error("fft_v: window not the same length as fft_size");
+}
+
+template <class T, bool forward>
+void fft_v_fftw<T, forward>::set_nthreads(int n)
+{
+ d_fft.set_nthreads(n);
+}
+
+template <class T, bool forward>
+int fft_v_fftw<T, forward>::nthreads() const
+{
+ return d_fft.nthreads();
+}
+
+template <class T, bool forward>
+bool fft_v_fftw<T, forward>::set_window(const std::vector<float>& window)
+{
+ if (window.empty() || window.size() == d_fft_size) {
+ d_window = window;
+ return true;
+ } else
+ return false;
+}
+
+template <>
+void fft_v_fftw<gr_complex, true>::fft_and_shift(const gr_complex* in, gr_complex* out)
+{
+ if (!d_window.empty()) {
+ gr_complex* dst = d_fft.get_inbuf();
+ volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size);
+ } else {
+ memcpy(d_fft.get_inbuf(), in, sizeof(gr_complex) * d_fft_size);
+ }
+ d_fft.execute();
+ if (d_shift) {
+ unsigned int len = (unsigned int)(ceil(d_fft_size / 2.0));
+ memcpy(
+ &out[0], &d_fft.get_outbuf()[len], sizeof(gr_complex) * (d_fft_size - len));
+ memcpy(&out[d_fft_size - len], &d_fft.get_outbuf()[0], sizeof(gr_complex) * len);
+ } else {
+
+ memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size);
+ }
+}
+
+template <>
+void fft_v_fftw<gr_complex, false>::fft_and_shift(const gr_complex* in, gr_complex* out)
+{
+ if (!d_window.empty()) {
+ gr_complex* dst = d_fft.get_inbuf();
+ if (d_shift) {
+ unsigned int offset = d_fft_size / 2;
+ int fft_m_offset = d_fft_size - offset;
+ volk_32fc_32f_multiply_32fc(&dst[fft_m_offset], &in[0], &d_window[0], offset);
+ volk_32fc_32f_multiply_32fc(
+ &dst[0], &in[offset], &d_window[offset], d_fft_size - offset);
+ } else {
+ volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size);
+ }
+ } else {
+ if (d_shift) { // apply an ifft shift on the data
+ gr_complex* dst = d_fft.get_inbuf();
+ unsigned int len =
+ (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array
+ memcpy(&dst[0], &in[len], sizeof(gr_complex) * (d_fft_size - len));
+ memcpy(&dst[d_fft_size - len], &in[0], sizeof(gr_complex) * len);
+ } else {
+ memcpy(d_fft.get_inbuf(), in, sizeof(gr_complex) * d_fft_size);
+ }
+ }
+ d_fft.execute();
+ memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size);
+}
+
+template <>
+void fft_v_fftw<float, true>::fft_and_shift(const float* in, gr_complex* out)
+{
+ // copy input into optimally aligned buffer
+ if (!d_window.empty()) {
+ gr_complex* dst = d_fft.get_inbuf();
+ for (unsigned int i = 0; i < d_fft_size; i++) // apply window
+ dst[i] = in[i] * d_window[i];
+ } else {
+ gr_complex* dst = d_fft.get_inbuf();
+ for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion
+ dst[i] = in[i];
+ }
+
+ d_fft.execute();
+ if (d_shift) {
+ unsigned int len = (unsigned int)(ceil(d_fft_size / 2.0));
+ memcpy(
+ &out[0], &d_fft.get_outbuf()[len], sizeof(gr_complex) * (d_fft_size - len));
+ memcpy(&out[d_fft_size - len], &d_fft.get_outbuf()[0], sizeof(gr_complex) * len);
+ } else {
+
+ memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size);
+ }
+}
+
+template <>
+void fft_v_fftw<float, false>::fft_and_shift(const float* in, gr_complex* out)
+{
+ // copy input into optimally aligned buffer
+ if (!d_window.empty()) {
+ gr_complex* dst = d_fft.get_inbuf();
+ if (d_shift) {
+ unsigned int len =
+ (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array
+ for (unsigned int i = 0; i < len; i++) {
+ dst[i] = in[len + i] * d_window[len + i];
+ }
+ for (unsigned int i = len; i < d_fft_size; i++) {
+ dst[i] = in[i - len] * d_window[i - len];
+ }
+ } else {
+ for (unsigned int i = 0; i < d_fft_size; i++) // apply window
+ dst[i] = in[i] * d_window[i];
+ }
+
+ } else {
+ gr_complex* dst = d_fft.get_inbuf();
+ if (d_shift) {
+ unsigned int len =
+ (unsigned int)(floor(d_fft_size / 2.0)); // half length of complex array
+ for (unsigned int i = 0; i < len; i++) {
+ dst[i] = in[len + i];
+ }
+ for (unsigned int i = len; i < d_fft_size; i++) {
+ dst[i] = in[i - len];
+ }
+ } else {
+ for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion
+ dst[i] = in[i];
+ }
+ }
+
+ // compute the fft
+ d_fft.execute();
+
+ // copy result to output stream
+ memcpy(out, d_fft.get_outbuf(), sizeof(gr_complex) * d_fft_size);
+}
+
+template <class T, bool forward>
+int fft_v_fftw<T, forward>::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ auto in = reinterpret_cast<const T*>(input_items[0]);
+ auto out = reinterpret_cast<gr_complex*>(output_items[0]);
+
+ int count = 0;
+
+ while (count++ < noutput_items) {
+
+ fft_and_shift(in, out);
+
+ in += d_fft_size;
+ out += d_fft_size;
+ }
+
+ return noutput_items;
+}
+
+template class fft_v<gr_complex, true>;
+template class fft_v<gr_complex, false>;
+template class fft_v<float, true>;
+template class fft_v<float, false>;
+} /* namespace fft */
+} /* namespace gr */