SignalProcessingブロックの作成:C++

「SignalProcessingブロックの作成:C++」の編集履歴(バックアップ)一覧はこちら

SignalProcessingブロックの作成:C++」(2011/06/18 (土) 15:27:03) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*Pythonとの切り分けは? From the Python point of view, GNU Radio provides a data flow abstraction. パイソンはデータフロウの概要を提供する。 From the high level point-of-view, infinite streams of data flow through the ports. At the C++ level, streams are dealt with in convenient sized pieces, represented as contiguous arrays of the underlying type. C++ブロックは潜在に潜む配列によって切り分けられたストリームが扱われる。 *3つのファイルが必要 -xxx.h, xxx.cc #新しいクラスを定義するのに必要。 -xxx.i, SwigにどうやってクラスをPythonにインポートさせるかを教えるのに必要。 *型の指定 入力出力という順で以下のpreffix定義の元クラス名に慣例的に使われる。 -f - single precision floating point -c - complex<float> -s - short (16-bit integer) -i - integer (32-bit integer) *データの流れはgr_vector_XXX(配列)が基本! gr.vector_source_f :source of float's that gets its data from a vector floatのソースをベクトルから取得する。 gr.vector_source_b :source of unsined char's that gets its data from a vector unsined char'sのベクトルをソースから取得する。 14 def test_001_square_ff (self): 15 src_data = (-3, 4, -5.5, 2, 3) 16 expected_result = (9, 16, 30.25, 4, 9) 17 src = gr.vector_source_f (src_data) 18 sqr = howto.square_ff () 19 dst = gr.vector_sink_f () 20 self.fg.connect (src, sqr) 21 self.fg.connect (sqr, dst) 22 self.fg.run () 23 result_data = dst.data () 24 self.assertFloatTuplesAlmostEqual (expected_result, result_data, 6) 79 int howto_square_ff::general_work (int noutput_items, 80 gr_vector_int &ninput_items, 81 gr_vector_const_void_star &input_items, //input_items(gr_vector_const_void_star)はポインタのポインタ 82 gr_vector_void_star &output_items) 83 { 84 const float *in = (const float *) input_items[0]; //gr_vector_const_void_starを(const float *)にキャスト 85 float *out = (float *) output_items[0]; //gr_vector_void_starを(float *)にキャスト 86 87 for (int i = 0; i < noutput_items; i++){ //noutput_itemsの数だけ配列に格納 88 out[i] = in[i] * in[i]; 89 } 90 91 // Tell runtime system how many input items we consumed on 92 // each input stream. 93 94 consume_each (noutput_items); 95 96 // Tell runtime system how many output items we produced. 97 return noutput_items; 98 } gr_vector_XXXは配列のポインタのポインタ? *ブロックが止まるのはEOF gr.vector_source_f(src_data) will source the elements of src_data and then say that it's finished. The returned value of general_work() is the number of items actually written to each output stream, or -1 on EOF. *[[How to make a signal processing block>http://www.gnu.org/software/gnuradio/doc/howto-write-a-block.html#qa_howto_1.py]]、[[こっち>http://www.snowymtn.ca/GNURadio/GNURAdioDoc-10.pdf]]はより詳しく -noutput_items is the number of output items to write on each output stream. -ninput_items gives the number of input items available on each input stream. -A block may have x input streams and y output streams. -ninput_items is an integer `vector' of length x, the ith element of which gives the number of available items on the ith input stream. -input_items is a vector of pointers to the input items, one entry per input stream. -output_items is a vector of pointers to the output items, one entry per output stream. -gr_make_XXXは、そのクラスをインスタンス化して、そのスマートポインタ(の中のshared pointer)を返してくれえる。これはrawポインタを間違っていじってしまうのを防ぐためらしい。 *gr_block.ccを見れば何やってんのか分かる!? // stub implementation: 1:1 void gr_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) { unsigned ninputs = ninput_items_required.size (); for (unsigned i = 0; i < ninputs; i++) //入力ベクトルの数(ストリームの数)だけループ ninput_items_required[i] = noutput_items + history() - 1; //出力ストリームのエレメント数をそのまま入力ストリームの数にしている。 } 入出力の間おいて、各ストリームのエレメント数が違う場合に、forcastでそれを予測するようにしなくてはだめ。 上のサンプルはデフォルトで1:1の場合はこれでよい。 void consume_each (int how_many_items); consume_eachはhow_many_itemsの数だけ各入力ストリームのアイテムがいくつ消費されかをスケジューラに教える。 それに応じて、スケジューラはアップストリームのバッファや関連ポインタをアレンジする。 *[[すべこべ言わずにコンパイルしよう>http://www35.atwiki.jp/space_escalator/pages/45.html]] *howto_print_ccの作成 複素信号を出力する。 以下、gr_complex.h及びgr_type.hに宣言されている、Gnuradioの型 //gr_complex.h #include <complex> typedef std::complex<float> gr_complex; typedef std::complex<double> gr_complexd; //gr_type.h typedef std::vector<int> gr_vector_int; typedef std::vector<float> gr_vector_float; typedef std::vector<double> gr_vector_double; typedef std::vector<void *> gr_vector_void_star; typedef std::vector<const void *> gr_vector_const_void_star; 以下、howto_print_cc.ccの一部 int howto_print_cc::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const float complex *in = (const float complex *) input_items[0]; float complex *out = (float complex *) output_items[0]; printf("noutput_items = %d\n", noutput_items); for (int i = 0; i < noutput_items; i++){ out[i] = in[i]; printf("in[%d]=%g+%gj, out[%d]=%g+%gj\n", i, crealf(in[i]), cimagf(in[i]), i, crealf(out[i]), cimagf(out[i])); } // Tell runtime system how many input items we consumed on // each input stream. consume_each (noutput_items); // Tell runtime system how many output items we produced. return noutput_items; } *同期型ブロックと非同期型のブロック gr_blockをそのまま継承したブロックはforcastやconsumeメンバを使って入出力を異なるデータレートで器用に扱うことができる。 でも、大体の入力と出力の関係は固定的なものが要求されるよね?だから入出力さえ事前に分かっていれば、簡便化ができる。それをしてくれたのが同期ブロック。 例えば、間引きも補間も行わない(入出力の数が同じ)FIRフィルタは、それぞれの出力サンプルを作るためにそれぞれNタップ分の過去の入力が必要だよね? でも実際の入力数と出力数の比は1:1だから、Gnuradoiではこの概念のことを履歴(history)とか予知(look-ahead)って呼ぶんだ。 -gr_sync_block これはそのhistoryを使える入出力比が1:1のブロックで、ninput_itemsやそれを入力にするeach_consume()が省略されているworkメソッドを呼ぶんだ。 historyを使いたいときはコンストラクタでset_historyメソッドを呼ぶだけさ!さらにここで実装されているforcastはhistoryに関する要求を操作できるようにパワーアップしているのさ。 -gr_sync_decimator これはN:1のgr_sync_block版だよ。 -gr_sync_interpolator これも1:Nのgr_sync_block版だよ。 ----
*Pythonとの切り分けは? From the Python point of view, GNU Radio provides a data flow abstraction. パイソンはデータフロウの概要を提供する。 From the high level point-of-view, infinite streams of data flow through the ports. At the C++ level, streams are dealt with in convenient sized pieces, represented as contiguous arrays of the underlying type. C++ブロックは潜在に潜む配列によって切り分けられたストリームが扱われる。 *3つのファイルが必要 -xxx.h, xxx.cc #新しいクラスを定義するのに必要。 -xxx.i, SwigにどうやってクラスをPythonにインポートさせるかを教えるのに必要。 *型の指定 入力出力という順で以下のpreffix定義の元クラス名に慣例的に使われる。 -f - single precision floating point -c - complex<float> -s - short (16-bit integer) -i - integer (32-bit integer) *データの流れはgr_vector_XXX(配列)が基本! gr.vector_source_f :source of float's that gets its data from a vector floatのソースをベクトルから取得する。 gr.vector_source_b :source of unsined char's that gets its data from a vector unsined char'sのベクトルをソースから取得する。 14 def test_001_square_ff (self): 15 src_data = (-3, 4, -5.5, 2, 3) 16 expected_result = (9, 16, 30.25, 4, 9) 17 src = gr.vector_source_f (src_data) 18 sqr = howto.square_ff () 19 dst = gr.vector_sink_f () 20 self.fg.connect (src, sqr) 21 self.fg.connect (sqr, dst) 22 self.fg.run () 23 result_data = dst.data () 24 self.assertFloatTuplesAlmostEqual (expected_result, result_data, 6) 79 int howto_square_ff::general_work (int noutput_items, 80 gr_vector_int &ninput_items, 81 gr_vector_const_void_star &input_items, //input_items(gr_vector_const_void_star)はポインタのポインタ 82 gr_vector_void_star &output_items) 83 { 84 const float *in = (const float *) input_items[0]; //gr_vector_const_void_starを(const float *)にキャスト 85 float *out = (float *) output_items[0]; //gr_vector_void_starを(float *)にキャスト 86 87 for (int i = 0; i < noutput_items; i++){ //noutput_itemsの数だけ配列に格納 88 out[i] = in[i] * in[i]; 89 } 90 91 // Tell runtime system how many input items we consumed on 92 // each input stream. 93 94 consume_each (noutput_items); 95 96 // Tell runtime system how many output items we produced. 97 return noutput_items; 98 } gr_vector_XXXは配列のポインタのポインタ? *ブロックが止まるのはEOF gr.vector_source_f(src_data) will source the elements of src_data and then say that it's finished. The returned value of general_work() is the number of items actually written to each output stream, or -1 on EOF. *[[How to make a signal processing block>http://www.gnu.org/software/gnuradio/doc/howto-write-a-block.html#qa_howto_1.py]]、[[こっち>http://www.snowymtn.ca/GNURadio/GNURAdioDoc-10.pdf]]はより詳しく -noutput_items is the number of output items to write on each output stream. -ninput_items gives the number of input items available on each input stream. -A block may have x input streams and y output streams. -ninput_items is an integer `vector' of length x, the ith element of which gives the number of available items on the ith input stream. -input_items is a vector of pointers to the input items, one entry per input stream. -output_items is a vector of pointers to the output items, one entry per output stream. -gr_make_XXXは、そのクラスをインスタンス化して、そのスマートポインタ(の中のshared pointer)を返してくれえる。これはrawポインタを間違っていじってしまうのを防ぐためらしい。 *gr_block.ccを見れば何やってんのか分かる!? // stub implementation: 1:1 void gr_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) { unsigned ninputs = ninput_items_required.size (); for (unsigned i = 0; i < ninputs; i++) //入力ベクトルの数(ストリームの数)だけループ ninput_items_required[i] = noutput_items + history() - 1; //出力ストリームのエレメント数をそのまま入力ストリームの数にしている。 } 入出力の間おいて、各ストリームのエレメント数が違う場合に、forcastでそれを予測するようにしなくてはだめ。 上のサンプルはデフォルトで1:1の場合はこれでよい。 void consume_each (int how_many_items); consume_eachはhow_many_itemsの数だけ各入力ストリームのアイテムがいくつ消費されかをスケジューラに教える。 それに応じて、スケジューラはアップストリームのバッファや関連ポインタをアレンジする。 *gr_io_signature class gr_io_signature { public: ~gr_io_signature (); int min_streams () const { return d_min_streams; } int max_streams () const { return d_max_streams; } size_t sizeof_stream_item (int index) const { return d_sizeof_stream_item; } private: int d_min_streams; int d_max_streams; size_t d_sizeof_stream_item; gr_io_signature (int min_streams, int max_streams, size_t sizeof_stream_item); friend gr_io_signature_sptr gr_make_io_signature ( int min_streams, //ここではストリームの数の最大最小を記述(入力端子の数!?) int max_streams, size_t sizeof_stream_item); }; 入力端子が二つあるブロックを作りたい場合はmax_streamsを2にすればいいのか? *[[すべこべ言わずにコンパイルしよう>http://www35.atwiki.jp/space_escalator/pages/45.html]] *howto_print_ccの作成 複素信号を出力する。 以下、gr_complex.h及びgr_type.hに宣言されている、Gnuradioの型 //gr_complex.h #include <complex> typedef std::complex<float> gr_complex; typedef std::complex<double> gr_complexd; //gr_type.h typedef std::vector<int> gr_vector_int; typedef std::vector<float> gr_vector_float; typedef std::vector<double> gr_vector_double; typedef std::vector<void *> gr_vector_void_star; typedef std::vector<const void *> gr_vector_const_void_star; 以下、howto_print_cc.ccの一部 int howto_print_cc::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const float complex *in = (const float complex *) input_items[0]; float complex *out = (float complex *) output_items[0]; printf("noutput_items = %d\n", noutput_items); for (int i = 0; i < noutput_items; i++){ out[i] = in[i]; printf("in[%d]=%g+%gj, out[%d]=%g+%gj\n", i, crealf(in[i]), cimagf(in[i]), i, crealf(out[i]), cimagf(out[i])); } // Tell runtime system how many input items we consumed on // each input stream. consume_each (noutput_items); // Tell runtime system how many output items we produced. return noutput_items; } *同期型ブロックと非同期型のブロック gr_blockをそのまま継承したブロックはforcastやconsumeメンバを使って入出力を異なるデータレートで器用に扱うことができる。 でも、大体の入力と出力の関係は固定的なものが要求されるよね?だから入出力さえ事前に分かっていれば、簡便化ができる。それをしてくれたのが同期ブロック。 例えば、間引きも補間も行わない(入出力の数が同じ)FIRフィルタは、それぞれの出力サンプルを作るためにそれぞれNタップ分の過去の入力が必要だよね? でも実際の入力数と出力数の比は1:1だから、Gnuradoiではこの概念のことを履歴(history)とか予知(look-ahead)って呼ぶんだ。 -gr_sync_block これはそのhistoryを使える入出力比が1:1のブロックで、ninput_itemsやそれを入力にするeach_consume()が省略されているworkメソッドを呼ぶんだ。 historyを使いたいときはコンストラクタでset_historyメソッドを呼ぶだけさ!さらにここで実装されているforcastはhistoryに関する要求を操作できるようにパワーアップしているのさ。 -gr_sync_decimator これはN:1のgr_sync_block版だよ。 -gr_sync_interpolator これも1:Nのgr_sync_block版だよ。 ----

表示オプション

横に並べて表示:
変化行の前後のみ表示: