【譯】GNU Radio How to write a block 【如何開發用戶模塊及編寫功能塊】


本文講解如何在GNU Radio中添加用戶開發的信號處理模塊,譯文如有不當之處可參考原文地址:http://gnuradio.microembedded.com/outoftreemodules

Out-of-tree modules

  利用用戶自定義的功能模塊擴展GNU Radio。

  This article borrows heavily from the original (but very outdated) "How to write a block?" written by Eric Blossom.

1. What is an out-of-tree module?

  外部模塊(Out-of-tree Module)是不存在與GNU Radio源代碼樹的GNU Radio組件。通常,用戶自己擴展GNU Radio的功能模塊,被稱作外部模塊。一般我們不會向實際的GNU Radio源代碼樹中添加東西,除非你是想把他上傳給發開者們整合使用。添加外部模塊既允許你維護你自己的代碼,並且延續主代碼的功能。

  很多這樣的外部模塊由CGRAN主持,這個一個關於GNU Radio的智囊團。如果你開發了非常nice的東西,請將他提交到CGRAN!

   spectral estimation toolbox是外部模塊的一個例子,它的譜估計功能擴展了GNU Radio。安裝之后,在GRC(GNU Radio Companion)中你會擁有更多的模塊(blocks)可以使用,其特性和原有的模塊一樣。然而,它是有很多開發者共同開發的。

2. Tools and resources at my disposal

  有很多工具,腳本和文檔可以作為第三方程序或者作為GNU Radio的一部分。

2.1 gr-how-to-write-a-block

  這里有一個已經實現了的外部模塊的例子,它作為GNU Radio源代碼樹的一部分。如果你跟隨本文的教程,你就會成功得到一個名為gr-howto-write-a-block的模塊。總之,如果你想知道你的模塊應該張什么樣子,這是一個很好的參考。

  因為經歷測試和維護之后,它會作為GNU Radio樹的一部分。GNU Radio的當前版本將需要更新模塊結構。

2.2 gr_modtool - The swiss army knife of module editing

  開發一個GNU Radio模塊的時候,涉及很多單調和枯燥的工作:樣板代碼,makefile文件編寫等。gr_modtool作為一個腳本,目的是使所有的文件都自動生成,如編寫makefile文件,使用模板等,並且盡可能的為開發者做很多工作,這樣開發者就只可以直接開始DSP的編程工作了。

  需要注意的是:gr_modtool在你看到的代碼上做了很多假設,越是你自己定制的,或者有特定變化的,gr_modtool使用的就變得越少,但是它可能是編寫一個新模塊最好的開端。

  gr_modtool 在GNU Radio代碼樹中是可用的,並且它是被默認安裝的。

2.3 Cmake, make. etc.

  在GNU Radio中使用cmake來作為系統的構建,因此build一個模塊需要你安裝cmake(最常見的是make,但是也可以使用Eclipse或者MS Visual Studio)。

3. Tutorial 1: Creating an out-of-tree module

  在下面的教程中,我們將使用名為howto的模塊。第一步是創建這個模塊。

  利用gr_modtool是一個非常簡單的方式。無論你想要在那里創建新模塊,只需要在命令行輸入命令(這應該是GNU Radio源代碼樹以外),然后繼續:

1 hao@hao:~$ gr_modtool newmod howto 2 Creating out-of-tree module in ./gr-howto... Done. 3 Use 'gr_modtool add' to add a new block to this currently empty module.

  如果一切順利,你會在主文件夾下得到一個名為gr-howto的文件目錄。

4. Structure of a module

  我們可以看看gr-howto文件目錄的組成。

1 hao@hao:~$ cd gr-howto/
2 hao@hao:~/gr-howto$ ls
3 apps  cmake  CMakeLists.txt  docs  examples  grc  include  lib  python  swig

  它由多個子目錄組成,凡是用C/C++(或者其他非python語言)寫的程序都將放在lib/文件夾中。對於C++文件我們通常只有頭文件放在include/文件夾中(如果它們是接口),或者放在lib/文件夾中(如果它們只有在編譯時用到,在安裝之后用不到,如*_impl.h文件,你會在接下來的教程中看到里面有些什么)。

  當然python寫的程序將進入python/文件夾下,這包括未安裝的測試單元和已安裝的python模塊。

  你可能已經知道,雖然GNU Radio的模塊是用C++寫的,但是它可以在python中調用。這是通過SWIG (the simplified wrapper and interface generator)的幫助,這是一個簡化包裝和接口生成器,它會自動創建鏈接代碼來實現這一點。SWIG需要一些指令來完成這些事情,這些指令在swig/的子目錄中。

  除非你為你的模塊做一些更好的事情,一般你將不需要去swig/的子目錄。gr_modtool將會為我們處理所有的這一切。

  如果你想讓你的模塊在GNU Radio companion(the graphical UI for GNU Radio)中也是可用的,你需要在grc/文件夾中添加.xml描述文件。

  docs/文件夾中包含一些說明,如何從C++文件和python文件中提取文件的說明(我們使用Doxygen和Sphinx來完成),並確保它們可以在python代碼中有效。當然,你可以添加自定義的文件在這里。

  最后,在apps/的子目錄中包含一些完整的安裝到系統的應用程序(包括在GRC中執行,和單獨的執行的文件)。

  一些模塊還包括文件夾examples/,作為文件的附錄,用來保存例子。其他開發者簡單直接的看例子里面的block如何使用。

  這個構建系統還帶來了一些其他的獨立的包:Cmakelist.txt文件(其中一個是存在於每一個子目錄)和cmake/的文件夾。你可以無視后者,因為它主要是用於cmake如何找到GNU Radio的庫等的一些說明。為了確保你的模塊構建正確,Cmakelist.txt這個文件需要做很多修改。

5. Tutorial 2: Writing a block (square_ff) in C++

  對於我們第一個例子,我們創建一個用於對浮點信號的求平方的模塊。此模塊將接受一個浮點輸入流並產生一個浮點輸出流。也就是說對於每個輸入的浮點信號,將其平方后輸出。

  下面的命名規則,我們將使用包名howto作為前綴,並命名這個模塊為howto_square_ff,因為他的輸入輸出都是float型。
  我們要整理這個模塊,把我們寫好的其他東西放到里面,最終放到howto Python中。這樣就可以用Python來訪問它。

1 import howto 2 sqr = howto.square_ff()

5.1 Creating the files

  第一步是創建一個空文件,並且編輯Cmakelist.txt。gr_modtool會再次幫我們完成這個工作。運行:

 1 hao@hao:~/gr-howto$ gr_modtool add -t general square_ff  2 GNU Radio module name identified: howto  3 Language: C++
 4 Block/code identifier: square_ff  5 Enter valid argument list, including default arguments:  6 Add Python QA code? [Y/n]  7 Add C++ QA code? [y/N]  8 Adding file 'lib/square_ff_impl.h'...  9 Adding file 'lib/square_ff_impl.cc'... 10 Adding file 'include/howto/square_ff.h'... 11 Editing swig/howto_swig.i... 12 Adding file 'python/qa_square_ff.py'... 13 Editing python/CMakeLists.txt... 14 Adding file 'grc/howto_square_ff.xml'... 15 Editing grc/CMakeLists.txt...

  在命令行中我們指定要添加一個模塊,他的類型是general(但是我們也不知道模塊的類型是什么),並且它叫做square_ff。類型有一下幾種可選:'sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock'。然后gr_modtool會問你是否需要參數(這里不需要,所以令他為空)?是否添加Python 測試文件(默認為Yes)?是否添加C++測試文件(默認為no)?
  現在,你可以看看Cmakelist.txt的不同和gr_modtool做了些什么,你還可以看到添加了許多新文件,如果你想要你的模塊能夠工作,現在必須來編輯這些文件。

5.2 Test Driven Programming

  我們可以直接運行剛才寫的C++代碼,但是作為一個高度發展的程序我們必須要先編寫測試代碼,畢竟我們有一個良好的習慣。取一個的浮點流作為輸入,再取一個的浮點流作為輸出。輸出應該是輸入的平方。
  這很簡單,我們打開python文件夾下的qa_square_ff.py,我們將編寫這個文件如下:

 1 from gnuradio import gr, gr_unittest  2 from gnuradio import blocks  3 import howto_swig as howto  4 
 5 class qa_square_ff (gr_unittest.TestCase):  6     def setUp (self):  7         self.tb = gr.top_block ()  8     
 9     def tearDown (self): 10         self.tb = None 11     
12     def test_001_square_ff(self): 13         src_data = (-3, 4, -5.5, 2, 3) 14         expected_result = (9, 16, 30.25, 4, 9) 15         src = blocks.vector_source_f(src_data) 16         sqr = howto.square_ff() 17         dst = blocks.vector_sink_f() 18  self.tb.connect(src, sqr) 19  self.tb.connect(sqr, dst) 20  self.tb.run() 21         result_data = dst.data() 22         self.assertFloatTuplesAlmostEqual(expected_result, result_data, 6) 23 
24 if __name__ == '__main__': 25     gr_unittest.run(qa_square_ff, "qa_square_ff.xml")

  gr_unittest是一個擴展的標准Python模塊單元測試。gr_unittest增加了對檢查浮點和復數的元組的近似相等的支持。unittest使用Python的反射機制來發現所有運行的方法和運行它們。unittest包裝每次調用test_*來匹配建立和拆除的調用。

  當我們運行測試,在這種秩序中gr_unittest.main要調用setUP, test_001_square_ff, 和tearDown。

  test_001_square_ff構建了一個graph,包含三個節點(分別是:source, signal processing block, sink)。 blocks.vector_source_f(src_data)作為信號源。howto.square_ff是我們正在測試的模塊。blocks.vector_sink_f是howto.square_ff的輸出。

  在run()方法下運行graph,直到所有的模塊完成各自的工作。最后,我們檢查的src_data經過square_ff輸出的結果與我們所期望的結果是否一致。

  注意,這樣的測試通常稱為在安裝模塊之前的測試。這意味着我們需要一些類似的代碼,以能夠加載模塊時測試。cmake可以適當的改變PYTHONPATH。此外這個文件中的第3行的意思是導入howto_swig並給它起個別名叫howto

  為了讓CMake的實際知道這個測試存在,gr_modtool修改python文件夾的CMakeLists.txt如下:

1 ######################################################################## 2 # Handle the unit tests 3 ######################################################################## 4 include(GrTest) 5 
6 set(GR_TEST_TARGET_DEPS gnuradio-howto) 7 set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) 8 GR_ADD_TEST(qa_howto ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_howto.py)

5.3 Build Tree vs. Install Tree

  當您運行cmake的時候,你通常運行在一個單獨的目錄(如build/),這就是構建樹。安裝的路徑是$prefix/lib/$pythonversion/dist-packages,$prefix是無論你在哪里(通常是/usr/local/)進行cmake的配置和-DCMAKE_INSTALL_PREFIX的開關。
  在編譯過程中,該庫將被復制到build目錄,只有在安裝過程中,文件安裝到安裝目錄,從而使GNU Radio能夠應用我們提供的模塊。我們寫的應用程序,使它們在訪問安裝目錄中的代碼和庫。在另一方面,我們希望在構建樹(build tree)中運行測試程序,這樣可以在安裝之前發現問題。

5.4 The C++ code(part 1)

現在,我們已經有了一個測試案例(test case),讓我們寫的C++代碼。所有的信號處理塊都繼承自gr::block或者gr::block的子類。gr_modtool已經為我們提供了三個文件定義塊:

lib/square_ff_impl.h

lib/square_ff_impl.cc

include/howto/square_ff.h

我們要做的就是修改他們。

  首先,我們來看看我們的頭文件。因為我們正在編寫的塊就是這么簡單,所以我們沒有必要真正改變他們(在include文件夾加入頭文件往往是相當完整的運行gr_modtool后,除非我們需要添加一些公共方法,如賦值方法,即getter和setter)。並且我們需要在lib/square_ff_impl.cc中將頭文件中聲明的方法實現。

  自動生成的square_ff_impl.cc文件內容如下:

 1 /* -*- c++ -*- */
 2 /* 
 3  * Copyright 2016 <+YOU OR YOUR COMPANY+>.  4  *  5  * This is free software; you can redistribute it and/or modify  6  * it under the terms of the GNU General Public License as published by  7  * the Free Software Foundation; either version 3, or (at your option)  8  * any later version.  9  * 10  * This software is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU General Public License for more details. 14  * 15  * You should have received a copy of the GNU General Public License 16  * along with this software; see the file COPYING. If not, write to 17  * the Free Software Foundation, Inc., 51 Franklin Street, 18  * Boston, MA 02110-1301, USA. 19  */
20 
21 #ifdef HAVE_CONFIG_H 22 #include "config.h"
23 #endif
24 
25 #include <gnuradio/io_signature.h>
26 #include "square_ff_impl.h"
27 
28 namespace gr { 29   namespace howto { 30 
31  square_ff::sptr 32  square_ff::make() 33  { 34       return gnuradio::get_initial_sptr 35         (new square_ff_impl()); 36  } 37 
38     /*
39  * The private constructor 40      */
41  square_ff_impl::square_ff_impl() 42       : gr::block("square_ff", 43               gr::io_signature::make(<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>)), 44               gr::io_signature::make(<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>))) 45  {} 46 
47     /*
48  * Our virtual destructor. 49      */
50     square_ff_impl::~square_ff_impl() 51  { 52  } 53 
54     void
55     square_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) 56  { 57         /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */
58  } 59 
60     int
61     square_ff_impl::general_work (int noutput_items, 62                        gr_vector_int &ninput_items, 63                        gr_vector_const_void_star &input_items, 64                        gr_vector_void_star &output_items) 65  { 66         const <+ITYPE*> *in = (const <+ITYPE*> *) input_items[0]; 67         <+OTYPE*> *out = (<+OTYPE*> *) output_items[0]; 68 
69         // Do <+signal processing+> 70         // Tell runtime system how many input items we consumed on 71         // each input stream.
72  consume_each (noutput_items); 73 
74         // Tell runtime system how many output items we produced.
75         return noutput_items; 76  } 77 
78   } /* namespace howto */
79 } /* namespace gr */

  gr_modtool提示我們需要在<++>的地方添加我們需要的代碼,如43行44行。首先修改構造函數(41~45行)如下:構造函數本來就是空的,因為square求平方不需要構造函數初始化。唯一有興趣的部分是輸入和輸出簽名的定義:在輸入端,我們有1個端口,允許浮點數輸入。輸出端口同理。

1 square_ff_impl::square_ff_impl() 2 : gr::block("square_ff", 3       gr::io_signature::make(1, 1, sizeof(float)), 4       gr::io_signature::make(1, 1, sizeof(float))) 5 { 6     //empty constructor
7 }

  修改54~58行代碼如下:

1 square_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) 2 { 3     /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */
4     nintput_items_required[0] = noutput_items; 5 }

  forecast()是一個函數,它告訴調度器產生noutput_items個輸出items需要從輸入多少items。在本例中,輸入輸出的items數量是相同的。
  index 0表示這是用於第一端口(port),但是我們只有一個端口。當一個模塊有很多端口(port)時需要用下標指明端口(port)

  通常在大多數block中都有不同的forecast()函數,舉例來說,你可以看看gr::block, gr::sync_block, gr::sync_decimator和gr::sync_interpolator是怎么來定義默認的forecast()統計rate change和history。
  最后,還有general_work(),在頭文件中聲明它是純虛函數,所以我們一定要重寫。

 1 int
 2 square_ff_impl::general_work (int noutput_items,  3                    gr_vector_int &ninput_items,  4                    gr_vector_const_void_star &input_items,  5                    gr_vector_void_star &output_items)  6 {  7     const float *in = (const float *) input_items[0];  8     float *out = (float *) output_items[0];  9 
10     // Do <+signal processing+> 11     // Tell runtime system how many input items we consumed on 12     // each input stream.
13     for(int i = 0; i<noutput_items; ++i) { 14       out[i] = in[i] * in[i]; 15  } 16  consume_each (noutput_items); 17 
18     // Tell runtime system how many output items we produced.
19     return noutput_items; 20 }

  這里分別有一個指針指向輸入緩沖區和輸出緩沖區,for循環可以將輸入緩沖區的平方復制到輸出緩沖區。

5.5 Using CMake

  如果您以前從未使用CMake,這是很好的時間來進行嘗試。一個在命令行中看到的以CMake為基礎的項目的典型的工作流程是這樣的:

1 $ mkdir build 2 $ cd build/
3 $ cmake ../ #告訴CMake,它的所有配置文件為一目錄了 4 $ make        #start building(應該在前一節之后工作)

  在我們的模塊的目錄中有一個新的目錄build/。所有的編譯等在這里完成,所以實際的源代碼樹不是充斥着臨時文件。如果我們改變任何的CMakeLists.txt文件,我們應該重新運行cmake ../(不過當你下一次運行make,cmake的檢測這些變化並且自動返回)。具體運行過程如下:

 1 hao@hao:~/gr-howto$ mkdir build  2 hao@hao:~/gr-howto$ cd build/
 3 hao@hao:~/gr-howto/build$ cmake ../
 4 -- The CXX compiler identification is GNU 4.8.4
 5 -- The C compiler identification is GNU 4.8.4
 6 -- Check for working CXX compiler: /usr/bin/c++
 7 -- Check for working CXX compiler: /usr/bin/c++ -- works  8 -- Detecting CXX compiler ABI info
 9 -- Detecting CXX compiler ABI info - done
10 -- Check for working C compiler: /usr/bin/cc
11 -- Check for working C compiler: /usr/bin/cc -- works 12 -- Detecting C compiler ABI info
13 -- Detecting C compiler ABI info - done
14 -- Build type not specified: defaulting to release. 15 -- Boost version: 1.55.0
16 -- Found the following Boost libraries: 17 -- filesystem 18 -- system 19 -- Found PkgConfig: /usr/bin/pkg-config (found version "0.26") 20 -- checking for module 'cppunit'
21 --   found cppunit, version 1.13.1
22 -- Found CPPUNIT: /usr/lib/x86_64-linux-gnu/libcppunit.so;dl 23 -- Found Doxygen: /usr/bin/doxygen (found version "1.8.6") 24 Checking for GNU Radio Module: RUNTIME 25 -- checking for module 'gnuradio-runtime'
26 --   found gnuradio-runtime, version 3.7.5.1
27  * INCLUDES=/usr/local/include 28  * LIBS=/usr/local/lib/libgnuradio-runtime.so;/usr/local/lib/libgnuradio-pmt.so 29 -- Found GNURADIO_RUNTIME: /usr/local/lib/libgnuradio-runtime.so;/usr/local/lib/libgnuradio-pmt.so 30 GNURADIO_RUNTIME_FOUND = TRUE 31 -- Found SWIG: /usr/bin/swig2.0 (found version "2.0.11") 32 -- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython2.7.so (found suitable version "2.7.6", minimum required is "2") 33 -- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.6", minimum required is "2") 34 -- Looking for sys/types.h 35 -- Looking for sys/types.h - found 36 -- Looking for stdint.h 37 -- Looking for stdint.h - found 38 -- Looking for stddef.h 39 -- Looking for stddef.h - found 40 -- Check size of size_t 41 -- Check size of size_t - done
42 -- Check size of unsigned int
43 -- Check size of unsigned int - done
44 -- Performing Test HAVE_WNO_UNUSED_BUT_SET_VARIABLE 45 -- Performing Test HAVE_WNO_UNUSED_BUT_SET_VARIABLE - Success 46 -- Configuring done
47 -- Generating done
48 -- Build files have been written to: /home/hao/gr-howto/build 49 hao@hao:~/gr-howto/build$ make
50 Scanning dependencies of target gnuradio-howto 51 [  6%] Building CXX object lib/CMakeFiles/gnuradio-howto.dir/square_ff_impl.cc.o 52 Linking CXX shared library libgnuradio-howto.so 53 [  6%] Built target gnuradio-howto 54 Scanning dependencies of target test-howto 55 [ 13%] Building CXX object lib/CMakeFiles/test-howto.dir/test_howto.cc.o 56 [ 20%] Building CXX object lib/CMakeFiles/test-howto.dir/qa_howto.cc.o 57 Linking CXX executable test-howto 58 [ 20%] Built target test-howto 59 Scanning dependencies of target _howto_swig_doc_tag 60 [ 26%] Building CXX object swig/CMakeFiles/_howto_swig_doc_tag.dir/_howto_swig_doc_tag.cpp.o 61 Linking CXX executable _howto_swig_doc_tag 62 [ 26%] Built target _howto_swig_doc_tag 63 Scanning dependencies of target howto_swig_swig_doc 64 [ 33%] Generating doxygen xml for howto_swig_doc docs 65 [ 40%] Generating python docstrings for howto_swig_doc 66 [ 40%] Built target howto_swig_swig_doc 67 Scanning dependencies of target _howto_swig_swig_tag 68 [ 46%] Building CXX object swig/CMakeFiles/_howto_swig_swig_tag.dir/_howto_swig_swig_tag.cpp.o 69 Linking CXX executable _howto_swig_swig_tag 70 [ 46%] Built target _howto_swig_swig_tag 71 [ 53%] Generating howto_swig.tag 72 Scanning dependencies of target howto_swig_swig_2d0df 73 [ 60%] Building CXX object swig/CMakeFiles/howto_swig_swig_2d0df.dir/howto_swig_swig_2d0df.cpp.o 74 Linking CXX executable howto_swig_swig_2d0df 75 Swig source 76 [ 60%] Built target howto_swig_swig_2d0df 77 Scanning dependencies of target _howto_swig 78 [ 66%] Building CXX object swig/CMakeFiles/_howto_swig.dir/howto_swigPYTHON_wrap.cxx.o 79 Linking CXX shared module _howto_swig.so 80 [ 66%] Built target _howto_swig 81 Scanning dependencies of target pygen_swig_387be 82 [ 73%] Generating howto_swig.pyc 83 [ 80%] Generating howto_swig.pyo 84 [ 80%] Built target pygen_swig_387be 85 Scanning dependencies of target pygen_python_54f4d 86 [ 86%] Generating __init__.pyc 87 [ 93%] Generating __init__.pyo 88 [ 93%] Built target pygen_python_54f4d 89 Scanning dependencies of target pygen_apps_9a6dd 90 [ 93%] Built target pygen_apps_9a6dd 91 Scanning dependencies of target doxygen_target 92 [100%] Generating documentation with doxygen 93 [100%] Built target doxygen_target

5.6 Let's try that -- running make test

  因為我們的C++代碼之前寫過測試代碼(QA code),馬上就可以看到,如果我們編寫的模塊是正確的。
  我們用make test運行我們的測試(調用cmake和make之后,在build/目錄中運行此命令)。這將調用一個shell腳本設置PYTHONPATH環境變量,以便我們的測試使用我們的代碼和庫的構建樹版本。然后運行其中的文件名格式為qa_*.py名稱的所有文件,並報告這些文件的成功或失敗。

  在后面有很多操作來使用我們沒有安裝的代碼版本(看cmake/目錄中一個簡單的動作。)
  如果你完成了square_ff模塊,這應該能正常運行:

 1 hao@hao:~/gr-howto/build$ make test  2 Running tests...  3 Test project /home/hao/gr-howto/build  4     Start 1: test_howto  5 1/2 Test #1: test_howto .......................   Passed    0.00 sec  6     Start 2: qa_square_ff  7 2/2 Test #2: qa_square_ff .....................   Passed    0.11 sec  8 
 9 100% tests passed, 0 tests failed out of 2
10 
11 Total Test time (real) =   0.11 sec

  如果事情在測試期間出現故障,我們可以挖得更深一些。當我們運行make test,我們實際上調用CMake的程序ctest,其中有許多選項,我們可以傳遞給它的更詳細信息。比如我寫程序的時候,把assertFloatTuplesAlmostEqual錯誤拼寫成assertFloatTuplesAmostEqual,如果我們只是運行make test,甚至只是CTEST,我們會得到這樣的:

 1 hao@hao:~/gr-howto/build$ ctest  2 Test project /home/hao/gr-howto/build  3     Start 1: test_howto  4 1/2 Test #1: test_howto .......................   Passed    0.00 sec  5     Start 2: qa_square_ff  6 2/2 Test #2: qa_square_ff .....................***Failed    0.11 sec  7 
 8 50% tests passed, 1 tests failed out of 2
 9 
10 Total Test time (real) =   0.11 sec 11 
12 The following tests FAILED: 13       2 - qa_square_ff (Failed) 14 Errors while running CTest

  要了解我們qa_square_ff測試發生了什么事,我們運行cmake -V -R square。'-V'標志為我們提供了詳細的輸出和“-R”標志是一個正則表達式只運行那些匹配的測試。

 1 hao@hao:~/gr-howto/build$ ctest -V -R square  2 UpdateCTestConfiguration  from :/home/hao/gr-howto/build/DartConfiguration.tcl  3 UpdateCTestConfiguration  from :/home/hao/gr-howto/build/DartConfiguration.tcl  4 Test project /home/hao/gr-howto/build  5 Constructing a list of tests  6 Done constructing a list of tests  7 Checking test dependency graph...  8 Checking test dependency graph end  9 test 2
10     Start 2: qa_square_ff 11 
12 2: Test command: /bin/sh "/home/hao/gr-howto/build/python/qa_square_ff_test.sh"
13 2: Test timeout computed to be: 9.99988e+06
14 2: E 15 2: ======================================================================
16 2: ERROR: test_001_t (__main__.qa_square_ff) 17 2: ----------------------------------------------------------------------
18 2: Traceback (most recent call last): 19 2:   File "/home/hao/gr-howto/python/qa_square_ff.py", line 46, in test_001_t 20 2:     self.assertFloatTuplesAmostEqual( expected_result, result_data, 6 ) 21 2: AttributeError: 'qa_square_ff' object has no attribute 'assertFloatTuplesAmostEqual'
22 2: 23 2: ----------------------------------------------------------------------
24 2: Ran 1 test in 0.002s 25 2: 26 2: FAILED (errors=1) 27 1/1 Test #2: qa_square_ff .....................***Failed    0.11 sec 28 
29 0% tests passed, 1 tests failed out of 1
30 
31 Total Test time (real) =   0.11 sec 32 
33 The following tests FAILED: 34       2 - qa_square_ff (Failed) 35 Errors while running CTest

  第21行提示沒有assertFloatTuplesAmostEqual屬性,我們返回修改重新make test。這可以利用測試信息,反復修改我們的模塊和測試程序,直到測試通過。

我們也可以只用print 語句在可能出錯的地方輸出變量的值,如print expected_result和print result_data去比較他們是否相等,這更容易理解這個問題。

5.7 More C++ code (but better) - Subclasses for common patterns

  gr::block允許極大的靈活性,對於輸入流的消費和生產輸出流。熟練使用forecast()consume()來建立變速率的模塊(即輸入輸出的items不相等)。構造一個每個輸入端口以不同的速率消耗items並且每個輸出端口以不同的速率產生items的模塊是可以實現的。

  另一方面,信號處理模塊的輸入速率和輸出速率之間的具有固定的關系是很常見的。很多都是1:1,而另一些則1:N或N:1的關系。你一定會想到在前面的模塊的general_work()函數中存在這樣一個問題:如果消耗的items的數量等於產生的items的數量,為什么還需要我再次告訴GNU Radio他們是相等的?

  另一個常見的需求是需要檢查多個輸入樣本,以產生一個輸出樣本。這是正交的輸入和輸出速率之間的關系。例如,一個非抽取,非內插FIR濾波器需要檢查N個輸入樣本來產生每一個輸出樣本,其中N是抽頭的濾波器的數目。然而,它仍然是消耗一個輸入items以產生一個輸出items。我們稱這個概念history,但你也可以把它看成“look-ahead”。如下圖所示:每次移動一個寬度為N的窗口,用這個N個items產生一個items。

  gr::sync_block繼承自gr::block並實現了一個1:1的可選的history。既然我們知道了輸入到輸出的速度,某些簡化是可能的。從實現者的觀點看,主要的變化是,我們定義了一個work()方法,而不是general_work()。work()具有一個稍微不同的調用順序;它省略了不必要的ninput_items參數,並安排consume_each()被我們調用。

1 /*! 2  * \brief Just like gr_block::general_work, only this arranges to 3  * call consume_each for you. 4  * 5  * The user must override work to define the signal processing code 6  */
7 virtual int work (int noutput_items, 8                   gr_vector_const_void_star &input_items, 9                   gr_vector_void_star &output_items) = 0;

  讓我們來添加一個繼承gr::sync_block模塊square2_ff並調用它。首先,我們編輯qa_square_ff.py增加另一個測試:

 1 def test_002_square2_t (self):  2     # set up fg
 3     src_data = (-3, 4, -5.5, 2, 3)  4     expected_result = (9, 16, 30.25, 4, 9)  5     src = blocks.vector_source_f( src_data )  6     sqr = howto.square2_ff( )#注意此處的square2
 7     dst = blocks.vector_sink_f( )  8  self.tb.connect( src, sqr )  9  self.tb.connect( sqr, dst ) 10  self.tb.run () 11     # check data
12     result_data = dst.data( ) 13     self.assertFloatTuplesAlmostEqual( expected_result, result_data, 6 )

  你可以看到它和以前的測試完全一樣,只是此處換成了square2_ff。

  然后我們使用gr_modtool添加模塊文件,跳過QA代碼,因為剛才我們已經寫好測試函數了。

 1 hao@hao:~/gr-howto$ gr_modtool add -t sync square2_ff  2 GNU Radio module name identified: howto  3 Language: C++
 4 Block/code identifier: square2_ff  5 Enter valid argument list, including default arguments:  6 Add Python QA code? [Y/n] n  7 Add C++ QA code? [Y/n] n  8 Adding file 'lib/square2_ff_impl.h'...  9 Adding file 'lib/square2_ff_impl.cc'... 10 Adding file 'include/howto/square2_ff.h'... 11 Editing swig/howto_swig.i... 12 Adding file 'grc/howto_square2_ff.xml'... 13 Editing grc/CMakeLists.txt...

  在square2_ff_impl.cc構造函數中完成與前面相同的方法,除了父類被變為gr::sync_block。修改后的square2_ff_impl.cc如下:

 1 /* -*- c++ -*- */
 2 /* 
 3  * Copyright 2016 <+YOU OR YOUR COMPANY+>.  4  *  5  * This is free software; you can redistribute it and/or modify  6  * it under the terms of the GNU General Public License as published by  7  * the Free Software Foundation; either version 3, or (at your option)  8  * any later version.  9  * 10  * This software is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU General Public License for more details. 14  * 15  * You should have received a copy of the GNU General Public License 16  * along with this software; see the file COPYING. If not, write to 17  * the Free Software Foundation, Inc., 51 Franklin Street, 18  * Boston, MA 02110-1301, USA. 19  */
20 
21 #ifdef HAVE_CONFIG_H 22 #include "config.h"
23 #endif
24 
25 #include <gnuradio/io_signature.h>
26 #include "square2_ff_impl.h"
27 
28 namespace gr { 29   namespace howto { 30 
31  square2_ff::sptr 32  square2_ff::make() 33  { 34       return gnuradio::get_initial_sptr 35         (new square2_ff_impl()); 36  } 37 
38     /*
39  * The private constructor 40      */
41  square2_ff_impl::square2_ff_impl() 42       : gr::sync_block("square2_ff", 43               gr::io_signature::make(1, 1, sizeof(float)), 44               gr::io_signature::make(1, 1, sizeof(float))) 45  {} 46 
47     /*
48  * Our virtual destructor. 49      */
50     square2_ff_impl::~square2_ff_impl() 51  { 52  } 53 
54     int
55     square2_ff_impl::work(int noutput_items, 56               gr_vector_const_void_star &input_items, 57               gr_vector_void_star &output_items) 58  { 59         const float *in = (const float *) input_items[0]; 60         float *out = (float *) output_items[0]; 61 
62         // Do <+signal processing+>
63         for(int i = 0; i<noutput_items; ++i) { 64             out[i] = in[i] * in[i]; 65  } 66         // Tell runtime system how many output items we produced.
67         return noutput_items; 68  } 69 
70   } /* namespace howto */
71 } /* namespace gr */

  work()函數是真正的區別(同時,我們沒有一個forecast()函數了)。下一節將更詳細的介紹它
  這給了我們一些東西讓我們少出錯少寫代碼,如果模塊history需要大於1,請在構造函數中調用set_history()或任何時間的要求的變化。
  gr::sync_block提供了一個forecast版本用來處理的history 要求。

  gr::sync_decimator是一個繼承gr::sync_block並且實現N:1帶有可選history的模塊。

  gr::sync_interpolator是一個繼承gr::sync_block並且實現1:N帶有可選history的模塊。

  有了這些知識,應當明確的是,howto_square_ff應該是一個沒有history的gr_sync_block。

  現在,返回build/目錄,並運行make,因為gr_modtool在CMakeList.txt中添加了square2_ff所需的代碼,cmake自動重新運行,接下來我們執行make。

  再次運行make test將產生與qa_square_ff.py一樣不會失敗的測試結果。

5.8 Inside the work() function

  如果您使用的是sync block(包括decimator和interpolator),這是怎樣由gr_modtool產生的代碼的框架:

 1 int
 2 my_block_name::work(int noutput_items,  3                     gr_vector_const_void_star &input_items,  4                     gr_vector_void_star &output_items)  5 {  6     const float *in = (const float *) input_items[0];  7     float *out = (float *) output_items[0];  8 
 9     // Do <+signal processing+> 10 
11     // Tell runtime system how many output items we produced.
12     return noutput_items; 13 }

  因此,鑒於history,vectors,multiple input ports等,然而這是真的你所需要的?是的!因為同步模塊有一個固定的輸出輸入速率,所有你需要知道的是輸出items的數量,從而可以計算需要使用多少輸入items。

5.9 Making your blocks available in GRC

  您現在可以安裝您的模塊,但它不會提供給GRC。這是因為gr_modtool無法在你寫一個模塊之前創建有效的xml文件。當你調用gr_modtool加載生成的xml代碼只是一些框架代碼。一旦你寫完模塊,gr_modtool有一個功能,以幫助您建立您的xml代碼。對於HOWTO例子,運行下面的兩條命令自動生成xml程序

 1 hao@hao:~/gr-howto$ gr_modtool makexml square_ff  2 GNU Radio module name identified: howto  3 Warning: This is an experimental feature. Don't expect any magic.
 4 Searching for matching files in lib/:  5 Making GRC bindings for lib/square_ff_impl.cc...  6 Overwrite existing GRC file? [y/N] y  7 hao@hao:~/gr-howto$ gr_modtool makexml square2_ff  8 GNU Radio module name identified: howto  9 Warning: This is an experimental feature. Don't expect any magic.
10 Searching for matching files in lib/: 11 Making GRC bindings for lib/square2_ff_impl.cc... 12 Overwrite existing GRC file? [y/N] y

  生成的xml文件如下(兩個文件除了name屬性不同,其他一樣,這里只給出一個):

 1 <block>
 2   <name>Square ff</name>
 3   <key>howto_square_ff</key>
 4   <category>HOWTO</category>
 5   <import>import howto</import>
 6   <make>howto.square_ff()</make>
 7   <sink>
 8     <name>in</name>
 9     <type>float</type>
10   </sink>
11   <source>
12     <name>out</name>
13     <type>float</type>
14   </source>
15 </block>

  當然還可以自己修改,如更改名字等。

  如果你這樣做從build/目錄用make install命令,您可以在GRC使用該模塊。如果GRC已經在運行,你可以點擊在GRC工具欄上的“刷新塊”按鈕;它是在右手邊一個藍色圓形箭頭。您現在應該看到在模塊樹中“HOWT
O”。

5.10 There's more: additional gr_block-methods

  如果你已經閱讀了gr_block documentation(你應該有)你就會注意到有大量方法配置你的block。

  下面是一些比較重要的:

  set_history()

  如果你的塊需要的history(即像FIR濾波器),在構造函數中調用set_history()。GNU Radio確保你有一個給定數量的'old itmes'可用。
  你可以有最小的history是1,也就是說,對於每一個輸出的item,則需要1個輸入item。如果你選擇一個較大的值N,這意味着你的輸出item是從當前輸入item加上之前的N-1個items計算得到的(即一個輸出item對應N個輸入items)。

  調度器采用這種方法照顧你。如果設置了history 長度為N,在輸入緩沖區中的前N個items(包括N-1以前的,即使你已經消耗掉他們)都是有效數據。

  forecast()

  為了確保正確,系統需要知道在每個輸入數組中有多少數據是必需的。如前所述,forecast()方法提供了這個信息,因此你寫一個gr::block子類必須重寫forecast()(對於sync blocks,這是隱式的)。

  默認實現的功能塊forecast()表明,輸出items的數量和輸入items的數量是1:1的關系。這些items的大小是由gr::block的構造函數中gr::io_signature::make定義。輸入和輸出item的大小,當然可以有所不同,這仍然是一個1:1的關系。當然,如果你有這種關系,你不會想用gr::block!

1 // default implementation: 1:1
2 void
3 gr_block::forecast (int noutput_items, 4                     gr_vector_int &ninput_items_required) 5 { 6     unsigned ninputs = ninput_items_required.size (); 7     for (unsigned i = 0; i < ninputs; i++) 8         ninput_items_required[i] = noutput_items; 9 }

  雖然在square_ff實施1:1的工作,但它不不適用於interpolators, decimators, 或者是輸出流與輸入流具有更為復雜關系的模塊。這說明繼承gr::sync_block, gr::sync_interpolator或者gr::sync_decimator,而不是繼承gr::block,你可以經常避免實現forecast。

  set_output_multiple()

  當實現你的general_work()例程,它會偶爾方便於運行時系統確保你只要求生產一組是某些特定的值的多個輸出項。如果你的算法應用於一個固定大小數據的模塊,這是可能需要使用這個函數。在構造函數中調用set_output_multiple()來指定這個要求。默認的output multiple為1。

5.11 Finalizing your work and installing

  首先,查看這個清單:

  1. 你已經寫好一個或者多個blocks,包括測試代碼?
  2. make test通過?
  3. 有可用的GRC綁定?

  滿足上面的條件,你可以繼續安裝模塊,在Linux計算機中意味着回到build/目錄中調用make install:

 1 hao@hao:~/gr-howto$ cd build  2 hao@hao:~/gr-howto/build$ sudo make install # or make install
 3 [sudo] password for hao:  4 [ 11%] Built target gnuradio-howto  5 [ 22%] Built target test-howto  6 [ 27%] Built target _howto_swig_doc_tag  7 [ 38%] Built target howto_swig_swig_doc  8 [ 44%] Built target _howto_swig_swig_tag  9 [ 66%] Built target howto_swig_swig_2d0df  10 [ 72%] Built target _howto_swig  11 [ 83%] Built target pygen_swig_387be  12 [ 94%] Built target pygen_python_54f4d  13 [ 94%] Built target pygen_apps_9a6dd  14 [100%] Built target doxygen_target  15 Install the project...  16 -- Install configuration: "Release"
 17 -- Installing: /usr/local/lib/cmake/howto/howtoConfig.cmake  18 -- Installing: /usr/local/include/howto/api.h  19 -- Installing: /usr/local/include/howto/square_ff.h  20 -- Installing: /usr/local/include/howto/square2_ff.h  21 -- Installing: /usr/local/lib/libgnuradio-howto.so  22 -- Removed runtime path from "/usr/local/lib/libgnuradio-howto.so"
 23 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/_howto_swig.so  24 -- Removed runtime path from "/usr/local/lib/python2.7/dist-packages/howto/_howto_swig.so"
 25 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/howto_swig.py  26 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/howto_swig.pyc  27 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/howto_swig.pyo  28 -- Installing: /usr/local/include/howto/howto/swig/howto_swig.i  29 -- Installing: /usr/local/include/howto/howto/swig/howto_swig_doc.i  30 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/__init__.py  31 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/__init__.pyc  32 -- Installing: /usr/local/lib/python2.7/dist-packages/howto/__init__.pyo  33 -- Installing: /usr/local/share/gnuradio/grc/blocks/howto_square_ff.xml  34 -- Installing: /usr/local/share/gnuradio/grc/blocks/howto_square2_ff.xml  35 -- Installing: /usr/local/share/doc/gr-howto/xml  36 -- Installing: /usr/local/share/doc/gr-howto/xml/namespacegr_1_1howto.xml  37 -- Installing: /usr/local/share/doc/gr-howto/xml/namespacegr.xml  38 -- Installing: /usr/local/share/doc/gr-howto/xml/dir_97aefd0d527b934f1d99a682da8fe6a9.xml  39 -- Installing: /usr/local/share/doc/gr-howto/xml/compound.xsd  40 -- Installing: /usr/local/share/doc/gr-howto/xml/index.xsd  41 -- Installing: /usr/local/share/doc/gr-howto/xml/dir_931aa87cbc005b1171acaaec17b62d81.xml  42 -- Installing: /usr/local/share/doc/gr-howto/xml/combine.xslt  43 -- Installing: /usr/local/share/doc/gr-howto/xml/indexpage.xml  44 -- Installing: /usr/local/share/doc/gr-howto/xml/square__ff__impl_8h.xml  45 -- Installing: /usr/local/share/doc/gr-howto/xml/group__defs_8dox.xml  46 -- Installing: /usr/local/share/doc/gr-howto/xml/group__block.xml  47 -- Installing: /usr/local/share/doc/gr-howto/xml/main__page_8dox.xml  48 -- Installing: /usr/local/share/doc/gr-howto/xml/dir_d44c64559bbebec7f509842c48db8b23.xml  49 -- Installing: /usr/local/share/doc/gr-howto/xml/api_8h.xml  50 -- Installing: /usr/local/share/doc/gr-howto/xml/classgr_1_1howto_1_1square__ff.xml  51 -- Installing: /usr/local/share/doc/gr-howto/xml/namespacestd.xml  52 -- Installing: /usr/local/share/doc/gr-howto/xml/classgr_1_1howto_1_1square__ff__impl.xml  53 -- Installing: /usr/local/share/doc/gr-howto/xml/index.xml  54 -- Installing: /usr/local/share/doc/gr-howto/xml/square__ff_8h.xml  55 -- Installing: /usr/local/share/doc/gr-howto/html  56 -- Installing: /usr/local/share/doc/gr-howto/html/hierarchy.html  57 -- Installing: /usr/local/share/doc/gr-howto/html/functions_func.html  58 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2pnode.png  59 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff__impl.html  60 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff.html  61 -- Installing: /usr/local/share/doc/gr-howto/html/api_8h.js  62 -- Installing: /usr/local/share/doc/gr-howto/html/functions.html  63 -- Installing: /usr/local/share/doc/gr-howto/html/tab_s.png  64 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2node.png  65 -- Installing: /usr/local/share/doc/gr-howto/html/namespacegr.html  66 -- Installing: /usr/local/share/doc/gr-howto/html/navtree.css  67 -- Installing: /usr/local/share/doc/gr-howto/html/open.png  68 -- Installing: /usr/local/share/doc/gr-howto/html/nav_f.png  69 -- Installing: /usr/local/share/doc/gr-howto/html/modules.html  70 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2ns.png  71 -- Installing: /usr/local/share/doc/gr-howto/html/square__ff__impl_8h_source.html  72 -- Installing: /usr/local/share/doc/gr-howto/html/sync_off.png  73 -- Installing: /usr/local/share/doc/gr-howto/html/navtreeindex0.js  74 -- Installing: /usr/local/share/doc/gr-howto/html/dynsections.js  75 -- Installing: /usr/local/share/doc/gr-howto/html/namespacegr_1_1howto.html  76 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff__impl-members.html  77 -- Installing: /usr/local/share/doc/gr-howto/html/square__ff__impl_8h.html  78 -- Installing: /usr/local/share/doc/gr-howto/html/square__ff_8h.html  79 -- Installing: /usr/local/share/doc/gr-howto/html/hierarchy.js  80 -- Installing: /usr/local/share/doc/gr-howto/html/group__block.html  81 -- Installing: /usr/local/share/doc/gr-howto/html/dir_97aefd0d527b934f1d99a682da8fe6a9.html  82 -- Installing: /usr/local/share/doc/gr-howto/html/files.html  83 -- Installing: /usr/local/share/doc/gr-howto/html/jquery.js  84 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff.js  85 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff__impl.js  86 -- Installing: /usr/local/share/doc/gr-howto/html/doxygen.css  87 -- Installing: /usr/local/share/doc/gr-howto/html/dir_931aa87cbc005b1171acaaec17b62d81.html  88 -- Installing: /usr/local/share/doc/gr-howto/html/resize.js  89 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2plastnode.png  90 -- Installing: /usr/local/share/doc/gr-howto/html/nav_h.png  91 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff-members.html  92 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2mo.png  93 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2link.png  94 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2vertline.png  95 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2mlastnode.png  96 -- Installing: /usr/local/share/doc/gr-howto/html/tab_b.png  97 -- Installing: /usr/local/share/doc/gr-howto/html/closed.png  98 -- Installing: /usr/local/share/doc/gr-howto/html/globals.html  99 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2doc.png 100 -- Installing: /usr/local/share/doc/gr-howto/html/bc_s.png 101 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff__impl.png 102 -- Installing: /usr/local/share/doc/gr-howto/html/sync_on.png 103 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2mnode.png 104 -- Installing: /usr/local/share/doc/gr-howto/html/globals_defs.html 105 -- Installing: /usr/local/share/doc/gr-howto/html/api_8h.html 106 -- Installing: /usr/local/share/doc/gr-howto/html/namespacegr.js 107 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2blank.png 108 -- Installing: /usr/local/share/doc/gr-howto/html/annotated.js 109 -- Installing: /usr/local/share/doc/gr-howto/html/tab_a.png 110 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2folderclosed.png 111 -- Installing: /usr/local/share/doc/gr-howto/html/index.html 112 -- Installing: /usr/local/share/doc/gr-howto/html/functions_type.html 113 -- Installing: /usr/local/share/doc/gr-howto/html/modules.js 114 -- Installing: /usr/local/share/doc/gr-howto/html/navtree.js 115 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2cl.png 116 -- Installing: /usr/local/share/doc/gr-howto/html/namespacegr_1_1howto.js 117 -- Installing: /usr/local/share/doc/gr-howto/html/annotated.html 118 -- Installing: /usr/local/share/doc/gr-howto/html/tabs.css 119 -- Installing: /usr/local/share/doc/gr-howto/html/api_8h_source.html 120 -- Installing: /usr/local/share/doc/gr-howto/html/dir_d44c64559bbebec7f509842c48db8b23.html 121 -- Installing: /usr/local/share/doc/gr-howto/html/bdwn.png 122 -- Installing: /usr/local/share/doc/gr-howto/html/nav_g.png 123 -- Installing: /usr/local/share/doc/gr-howto/html/main__page_8dox.html 124 -- Installing: /usr/local/share/doc/gr-howto/html/square__ff_8h_source.html 125 -- Installing: /usr/local/share/doc/gr-howto/html/classes.html 126 -- Installing: /usr/local/share/doc/gr-howto/html/classgr_1_1howto_1_1square__ff.png 127 -- Installing: /usr/local/share/doc/gr-howto/html/files.js 128 -- Installing: /usr/local/share/doc/gr-howto/html/group__defs_8dox.html 129 -- Installing: /usr/local/share/doc/gr-howto/html/tab_h.png 130 -- Installing: /usr/local/share/doc/gr-howto/html/doxygen.png 131 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2folderopen.png 132 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2lastnode.png 133 -- Installing: /usr/local/share/doc/gr-howto/html/ftv2splitbar.png

  使用Ubuntu你可能還需要調用lddonfig: Ubuntu系統加上這句命令,更新庫。否則你會得到無法找到你剛剛安裝的庫的錯誤信息。

  注意:如果出現類似錯誤提示 AttributeError: 'module' object has no attribute 'square_ff' 執行下面的命令即可解決問題。

1 $ sudo ldconfig

自此,用戶自定義的模塊已經成功安裝。

 

6. Calling your blocks in GRC

  打開GNU Radio,可以在右邊看到剛才創建的block,如圖:

          

  在GRC(GNU Radio companion)中調用剛才編寫的block,測試是否正確。信號流圖如下:

        

  運行信號流圖,得到如下波形,圖中正弦波的幅值滿足平方關系,且頻率加倍。從而驗證了模塊的正確性,並且在GRC中是可以使用的。

        

 

初學GNU Radio,文中有很多地方翻譯出錯或者理解出錯,懇請大家多多指正。

本文會不定期更新,轉載請保留本文鏈接,以便他人能夠看到最新內容,謝謝~

本文鏈接:http://www.cnblogs.com/moon1992/p/5424677.html 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM