c++gnuradiognuradio-companion

AttributeError: module 'Kurtosis' has no attribute 'Kurtosis_c'


I am trying to build a sink block with FFT and Kurtosis capability using gr_modtool.

The code itself can be compiled without error.

But when I run the flow graph in GRC, it produces following error message.

Generating: '/home/nomo/gr-Kurtosis/kurtosis.py'

Executing: /usr/bin/python3 -u /home/nomo/gr-Kurtosis/kurtosis.py

Traceback (most recent call last):
  File "/home/nomo/gr-Kurtosis/kurtosis.py", line 134, in <module>
    main()
  File "/home/nomo/gr-Kurtosis/kurtosis.py", line 112, in main
    tb = top_block_cls()
  File "/home/nomo/gr-Kurtosis/kurtosis.py", line 81, in __init__
    self.Kurtosis_Kurtosis_c_0 = Kurtosis.Kurtosis_c(1024)
AttributeError: module 'Kurtosis' has no attribute 'Kurtosis_c'

Below is the implmentation source file:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "Kurtosis_c_impl.h"

namespace gr {
  namespace Kurtosis {

    Kurtosis_c::sptr
    Kurtosis_c::make(int fftsize)
    {
      return gnuradio::get_initial_sptr
        (new Kurtosis_c_impl(fftsize));
    }


    /*
     * The private constructor
     */
    Kurtosis_c_impl::Kurtosis_c_impl(int fftsize)
      : gr::sync_block("Kurtosis_c",
              gr::io_signature::make(1, 1, sizeof(gr_complex)),
              gr::io_signature::make(0, 0, 0)),
              d_N(fftsize)
    {
      d_input = (fftw_complex*)fftw_malloc(sizeof(gr_complex) * d_N);
      K = (fftw_complex*)fftw_malloc(sizeof(gr_complex) * d_N);
      d_plan = fftw_plan_dft_1d(d_N, d_input, d_input, FFTW_BACKWARD, FFTW_ESTIMATE);
    }

    /*
     * Our virtual destructor.
     */
    Kurtosis_c_impl::~Kurtosis_c_impl()
    {
    }

    int
    Kurtosis_c_impl::work(int noutput_items,
        gr_vector_const_void_star &input_items,
        gr_vector_void_star &output_items)
    {
      const gr_complex *in = (const gr_complex*) input_items[0];

      for(int i = 0; i < noutput_items; i++)
      {
        d_input[i][0] = in[i].real();
        d_input[i][1] = in[i].imag();
      }
      
      fftw_execute(d_plan);
      
      for(int i = 0; i < noutput_items ;i++)
      {   
        S1[i][0] = S1[i][0] + d_input[i][0];
        S1[i][1] = S1[i][1] + d_input[i][1];
        
        S2[i][0] = S2[i][0] + d_input[i][0] * d_input[i][0];
        S2[i][1] = S2[i][1] + d_input[i][1] * d_input[i][1];
        
        S3[i][0] = S3[i][0] + d_input[i][0] * d_input[i][0] * d_input[i][0];
        S3[i][1] = S3[i][1] + d_input[i][1] * d_input[i][1] * d_input[i][1];
        
        S4[i][0] = S4[i][0] + d_input[i][0] * d_input[i][0] * d_input[i][0] * d_input[i][0];
        S4[i][1] = S4[i][1] + d_input[i][1] * d_input[i][1] * d_input[i][1] * d_input[i][1];
        
        dc[i][0] = dc[i][0] + 1;
        dc[i][1] = dc[i][1] + 1;
      }
    
      for(int i = 0; i < noutput_items; i++)
      {
        Myu1[i][0] = S1[i][0] / dc[i][0];
        Myu1[i][1] = S1[i][1] / dc[i][1];
      
        Myu2[i][0] = S2[i][0] / dc[i][0];
        Myu2[i][1] = S2[i][1] / dc[i][1];
      
        Myu3[i][0] = S3[i][0] / dc[i][0];
        Myu3[i][1] = S3[i][1] / dc[i][1];
      
        Myu4[i][0] = S4[i][0] / dc[i][0];
        Myu4[i][1] = S4[i][1] / dc[i][1];
      }

    

      for(int i = 0; i < noutput_items; i++)
      {
        K[i][0] = (Myu4[i][0] - 4 * Myu3[i][0] * Myu1[i][0] + 6 * Myu2[i][0] * Myu1[i][0] 
                   * Myu1[i][0] - 3 * Myu1[i][0] * Myu1[i][0] * Myu1[i][0] * Myu1[i][0]) / 
                    ((Myu2[i][0] - Myu1[i][0] * Myu1[i][0]) * (Myu2[i][0] - Myu1[i][0] 
                      * Myu1[i][0]));
      
        K[i][1] = (Myu4[i][1] - 4 * Myu3[i][1] * Myu1[i][1] + 6 * Myu2[i][1] * Myu1[i][1] 
                   * Myu1[i][1] - 3 * Myu1[i][1] * Myu1[i][1] * Myu1[i][1] * Myu1[i][1]) / 
                    ((Myu2[i][1] - Myu1[i][1] * Myu1[i][1]) * (Myu2[i][1] - Myu1[i][1] 
                      * Myu1[i][1]));
      }

      // Tell runtime system how many output items we produced.
      return noutput_items;
    }

  } /* namespace Kurtosis1 */
} /* namespace gr */

The implementation header file is as below:

#ifndef INCLUDED_KURTOSIS1_KURTOSIS_C1_IMPL_H
#define INCLUDED_KURTOSIS1_KURTOSIS_C1_IMPL_H

#include <Kurtosis/Kurtosis_c.h>
#include <fftw3.h>

namespace gr {
  namespace Kurtosis {

    class Kurtosis_c_impl : public Kurtosis_c
    {
     private:
       int d_N;
       
        
       fftw_complex *K;
       fftw_complex *S1;
       fftw_complex *S2;
       fftw_complex *S3; 
       fftw_complex *S4;
       fftw_complex *Myu1;
       fftw_complex *Myu2;
       fftw_complex *Myu3;
       fftw_complex *Myu4;
       fftw_complex *dc;
       
   
      
       fftw_complex *d_input;
       fftw_plan     d_plan;

     public:
      Kurtosis_c_impl(int fftsize);
      ~Kurtosis_c_impl();
     

      // Where all the action really happens
      int work(
              int noutput_items,
              gr_vector_const_void_star &input_items,
              gr_vector_void_star &output_items
      );
    };

  } // namespace Kurtosis1
} // namespace gr

#endif /* INCLUDED_KURTOSIS1_KURTOSIS_C1_IMPL_H */

The following python code is generated when a flow graph is run in GRC

from distutils.version import StrictVersion

if __name__ == '__main__':
    import ctypes
    import sys
    if sys.platform.startswith('linux'):
        try:
            x11 = ctypes.cdll.LoadLibrary('libX11.so')
            x11.XInitThreads()
        except:
            print("Warning: failed to XInitThreads()")

from gnuradio import blocks
import pmt
from gnuradio import gr
from gnuradio.filter import firdes
import sys
import signal
from PyQt5 import Qt
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
import Kurtosis
from gnuradio import qtgui

class kurtosis(gr.top_block, Qt.QWidget):

    def __init__(self):
        gr.top_block.__init__(self, "Not titled yet")
        Qt.QWidget.__init__(self)
        self.setWindowTitle("Not titled yet")
        qtgui.util.check_set_qss()
        try:
            self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
        except:
            pass
        self.top_scroll_layout = Qt.QVBoxLayout()
        self.setLayout(self.top_scroll_layout)
        self.top_scroll = Qt.QScrollArea()
        self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
        self.top_scroll_layout.addWidget(self.top_scroll)
        self.top_scroll.setWidgetResizable(True)
        self.top_widget = Qt.QWidget()
        self.top_scroll.setWidget(self.top_widget)
        self.top_layout = Qt.QVBoxLayout(self.top_widget)
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)

        self.settings = Qt.QSettings("GNU Radio", "kurtosis")

        try:
            if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"):
                self.restoreGeometry(self.settings.value("geometry").toByteArray())
            else:
                self.restoreGeometry(self.settings.value("geometry"))
        except:
            pass

        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate = 32000

        ##################################################
        # Blocks
        ##################################################
        self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True)
        self.blocks_file_source_0 = blocks.file_source(gr.sizeof_gr_complex*1, '/home/nomo/gr-Kurtosis/b200_220215_0718_30_40_6000_TEST.dat', True, 0, 0)
        self.blocks_file_source_0.set_begin_tag(pmt.PMT_NIL)
        self.Kurtosis_Kurtosis_c_0 = Kurtosis.Kurtosis_c(1024)



        ##################################################
        # Connections
        ##################################################
        self.connect((self.blocks_file_source_0, 0), (self.blocks_throttle_0, 0))
        self.connect((self.blocks_throttle_0, 0), (self.Kurtosis_Kurtosis_c_0, 0))

    def closeEvent(self, event):
        self.settings = Qt.QSettings("GNU Radio", "kurtosis")
        self.settings.setValue("geometry", self.saveGeometry())
        event.accept()

    def get_samp_rate(self):
        return self.samp_rate

    def set_samp_rate(self, samp_rate):
        self.samp_rate = samp_rate
        self.blocks_throttle_0.set_sample_rate(self.samp_rate)



def main(top_block_cls=kurtosis, options=None):

    if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"):
        style = gr.prefs().get_string('qtgui', 'style', 'raster')
        Qt.QApplication.setGraphicsSystem(style)
    qapp = Qt.QApplication(sys.argv)

    tb = top_block_cls()
    tb.start()
    tb.show()

    def sig_handler(sig=None, frame=None):
        Qt.QApplication.quit()

    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)

    timer = Qt.QTimer()
    timer.start(500)
    timer.timeout.connect(lambda: None)

    def quitting():
        tb.stop()
        tb.wait()
    qapp.aboutToQuit.connect(quitting)
    qapp.exec_()


if __name__ == '__main__':
    main()

Question: How to solve this error?

Thank you in advance for any guidance you may be able to provide.


Solution

  • There are two probable reasons:

    1. You don't have swig installed on your system and the python binding does not get generated.

    #include <fftw3.h>

    1. You don't link all external libraries - fftw3 in your case.

    Open your top-level CMakeLists.txt and add

    find_package(FFTW3)
    

    then open lib/CMakeLists.txt and add fftw3::fftw3 to target_link_libraries list, something like

    target_link_libraries(gnuradio-Kurtosis PUBLIC
      gnuradio::gnuradio-runtime fftw3::fftw3 
    )
    

    One more thing is to improve the error handling - open python/__init__.py and change ImportError to ModuleNotFoundError

    After all these changes you need to reinstall your OOT module.