フローグラフの作成:Python


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

ブロック間の情報は得られない

  • サンプリングレートは各ブロックで指定する必要がある
Gnuradio Tutorialより「GNU Radio cannot guess the correct sampling rate from the context, as it is not part of the information flow between blocks.」
digital_tone.pyより
13         src0 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 350, ampl)#ちゃんと各ブロックでsample_rateを指定している
14         src1 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 440, ampl)
15         dst = audio.sink (sample_rate, "")
16         self.connect (src0, (dst, 0))#selfはgr.top_blockを示している。
17         self.connect (src1, (dst, 1))

ということはサンプリングレートさえ指定すればブロック間の同期は可能?
これらはgr.top_blockに繋がっている。

ブロックの接尾辞はデータタイプを表す

   * f = float
   * c = complex float
   * i = int
   * s = short int
   * b = bits (actually an integer type) ←これはunsigned char型のことだった!!
These suffixes are used for all types of blocks, e.g. gr.fir_filter_ccf() will define an FIR filter with complex input, complex output and float taps, and gr.add_const_ss() will define a block which adds incoming short values with another, constant, short int.

全てのPythonブロックXXXはC++で記述されたgr_make_XXXを呼んでいる。このインターフェースがSwig!

Every block in C++ comes with a creating function, called gr_make_*** (gr_make_sig_source_f() in the example mentioned above). This function is always documented on the same page as the matching class, and this function is what gets exported to Python, so gr.sig_source_f() in Python calls gr_make_sig_source_f() in C++. For the same reason, it takes the same arguments - that's how you know how to initialise a block in Python.
つまり、Headerファイルに定義されているgr_make_XXXがgr.XXXとして同じ引数でPythonコードで呼び出せるということ!

connectの注意点

  • 入力と出力のデータタイプのチェックをデータサイズで行っているため、タイプが違ってもサイズが同じならエラーがでない。
  • ビット列を扱うときは気をつけろ!特に特定の数のビットを扱うときは。
When processing single bits, be careful. In some cases, you will work with binary data in a usual sense, in other cases you want to handle a specific number of bits at a time. Have a look at the packed_to_unpacked* and unpacked_to_packed* blocks for this.

USRPは16bitのダイナミックレンジ

Be careful with dynamic ranges. When you're using float or complex data types, you have a larger range than you'll ever need concerning the machine, but some sinks and sources have specific ranges you need to stick to. For example, audio sinks require samples within +-1 and will clip anything outside this interval. The USRP sink on the other hand needs samples in the +-32767 range (signed 16 bit values) because that's the dynamic range of the DAC.

Hierarchical blocksはブロックを包含するブロック

以下のように記述することでB1ブロックとB2ブロックを繋げてひとつのブロックとすることができる。
1 class HierBlock(gr.hier_block2):
2     def __init__(self, audio_rate, if_rate):
3         gr.hier_block2.__init__(self, "HierBlock",
4                        gr.io_signature(1, 1, gr.sizeof_float),#(ポート数の最小値, ポート数の最大値, 入出力のサイズ)
5                        gr.io_signature(1, 2, gr.sizeof_gr_complex))
6 
7         B1 = gr.block1(...) # Put in proper code here!
8         B2 = gr.block2(...)
9 
10         self.connect(self, B1, B2, self)#両端の入出力はHierarchical Blockであるselfで終わっている。

さらに親クラスは初期化の際に以下の4つのパラメータを必要とする。
  • self (which is always passed to the constructor as first argument),#Pythonではこれは常にコンストラクタの引数に必要
  • a string with an identifier for the hierarchical block (change at your convenience),#クラス名が文字列として必要
  • an input signature and an output signature.#入力信号および出力信号の型定義が必要
ちなみにgr.io_signature(0, 0, 0)はNULL IO signatuireと呼び、sourceやsinkをHierBlockに組み込みたい場合に終端入出力として用いる。

複数のflowグラフの実行(送信、受信パスの同時実行)

2008年6月現在、top_blockを複数同時に実行することはできない。しかし、以下のように記すことで別々のflowグラフを同時に実行できる。
25 class my_top_block(gr.top_block):
26     def __init__(self):
27         gr.top_block.__init__(self)
28 
29     tx_path = transmit_path()
30 
31     rx_path = receive_path()
32 
33     self.connect(tx_path)
34     self.connect(rx_path)
上プログラムにおいて各xx_pathはhier_block及びgr.io_signature(0, 0, 0)で入出力両端が閉じている。
この場合hier_block内のconnectにはselfを用いない。それはconnect内でsourceとsinkで既にflowグラフができているからである。
このプログラムが動作する場合、top_blockは各hier_block(tx_pathやrx_path)を呼ぶが、各hier_blockはそれ以降のブロックに繋がっていない。