benchmark_tx.py

パケット送信プログラムのサンプルコード。
受信に成功しやすいパラメータの例) ./benchmark_tx.py -f 2.45G -m dbpsk -s 10 -r 64k

ペイロードデータ

デフォルトではパケット番号+パケット番号下位1バイトのペイロードが作られる。
Pythonではバイト列を文字列として扱う
data = (pkt_size - 2) * chr(pktno & 0xff) #chr()は引数に対応するascii文字を返す。これを指定パケットサイズ-2個繋げてdataに格納。
payload = struct.pack('!H', pktno & 0xffff) + data #パケット番号の下位2バイト(複数バイトなのでネットワークバイトオーダーを指定)とdataを繋げてpayload完成。
send_pkt(payload)

パケットの作成:mod_pkts.send_pkt→packet_utils.make_packet

  • パディング
1パケットを512バイトで送るため、4 bytes/sample(DACのダイナミックレンジ) × 128 samples にする。
pkt = pkt + (_npadding_bytes(len(pkt), samples_per_symbol, bits_per_symbol) * '\x55') #'55'をパディング。
def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol):
   """
   Generate sufficient padding such that each packet ultimately ends
   up being a multiple of 512 bytes when sent across the USB.  We
   send 4-byte samples across the USB (16-bit I and 16-bit Q), thus
   we want to pad so that after modulation the resulting packet
   is a multiple of 128 samples.
   @param ptk_byte_len: len in bytes of packet, not including padding.
   @param samples_per_symbol: samples per bit (1 bit / symbolwidth GMSK) ※1シンボルで何回サンプルするか。dbpskの場合2
   @type samples_per_symbol: int
   @param bits_per_symbol: bits per symbol (log2(modulation order)) ※1シンボルで何ビット送れるか。dbpskの場合1(modulation order は2)
   @type bits_per_symbol: int
   @returns number of bytes of padding to append.
   """
   modulus = 128
   byte_modulus = gru.lcm(modulus/8, samples_per_symbol) * bits_per_symbol / samples_per_symbol #(16-byte/パケット)×(bits/sample)。dbpskの場合8-byte
   r = pkt_byte_len % byte_modulus #余っていて送らないといけないバイト数#bdpskでパケットサイズが1519bytesの場合7bytes
   if r == 0:
       return 0
   return byte_modulus - r #パディングするバイト数

変調ブロック:modulation_utils.type_1_mods()

バイトストリームを入力に複素数ベースバンド信号を出力する。
Type 1 modulators accept a stream of bytes on their input and produce complex baseband output
おそらくUSRPに直行変調器が実装されており、そこのIQの値を設定するブロックである。
呼び出しているクラスdbpsk_modでこの中で以下のものが呼び出されている。
  • bytes2chunks = gr.packed_to_unpacked_bb(bits_per_chunk, gr.GR_MSB_FIRST)
The bits in the bytes input stream are grouped into chunks of bits_per_chunk bits and each resulting chunk is written right-justified to the output stream of bytes.
入力する1バイトの中身をbits_per_chunkで指定した数の塊に分けて右揃えのバイト列を出力する。bits_per_chunk=1でbitのベクトルになる。
1バイトの中身はintegerで表現される。例えば、70('F')で表されるbit列は01000110であり、
bits_per_chunk=1にすると0,1,0,0,0,1,1,0の8bytesのバイト列となって出力される。
この時、gr.GR_MSB_FIRSTを指定すると左の0が先頭のバイト列なる。
QPSKの場合bits_per_chunk(= bits_per_simbol)は2となる。
この時、上の例と同じように1バイトの中身が70の場合、1,0,1,2の4bytesで出力バイトストリームが得られる。
仕様書の解釈
Convert a stream of packed bytes or shorts to stream of unpacked bytes or shorts.
input: stream of unsigned char; output: stream of unsigned char.←入出力の型であるbは1bytesのunsigned整数
This is the inverse of gr_unpacked_to_packed_XX.
The bits in the bytes or shorts input stream are grouped into chunks of bits_per_chunk bits and each resulting chunk is written right- justified to the output stream of bytes or shorts. All b or 16 bits of the each input bytes or short are processed.
The right thing is done if bits_per_chunk is not a power of two.
The combination of gr_packed_to_unpacked_XX_ followed by gr_chunks_to_symbols_Xf or gr_chunks_to_symbols_Xc handles the general case of mapping from a stream of bytes or shorts into arbitrary float or complex symbols.
gr.unpacked_to_packed_bbのコメント
Convert a stream of unpacked bytes or shorts into a stream of packed bytes or shorts.
input: stream of unsigned char; output: stream of unsigned char.←こっちはちゃんとunsigned char
This is the inverse of gr_packed_to_unpacked_XX.
The low bits_per_chunk bits are extracted from each input byte or short.←それぞれの入力バイトからbits_per_chunk分だけ抽出され、それが出力バイトにパックされる。
These bits are then packed densely into the output bytes or shorts, such that all 8 or 16 bits of the output bytes or shorts are filled with valid input bits.←出力される全てのビット列は有効な入力ビット列で満たされている。
The right thing is done if bits_per_chunk is not a power of two.←bits_per_chunkが2の乗数でなければうまくいく。
The combination of gr_packed_to_unpacked_XX followed by gr_chunks_to_symbols_Xf or gr_chunks_to_symbols_Xc handles the general case of mapping from a stream of bytes or shorts into arbitrary float or complex symbols.
packとunpackについてはここ(でもここではpackとunpackの意味が逆になっている。。)

  • symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]):arityはシンボルの種類数
ビット入力をマッピングして出力する。bpskの場合、0or1に、qpskの場合0or1or2or3にマッピングされる。
output[i] = psk.binary_to_ungray[input[i]]
  • diffenc = gr.diff_encoder_bb(arity:modulus):
y[0] = (x[0] + y[-1]) % M
Differential encoder
前の時間との差分で符号化する。
  • chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]:symbol_table)
シンボル列(ビット列:integer)をコンスタレーションにマッピングし、複素信号を生成。
Map a stream of symbol indexes (unpacked bytes or shorts) to stream of float or complex constellation points.in D dimensions (D = 1 by default)
input: stream of unsigned char; output: stream of gr_complex.
out[n D + k] = symbol_table[in[n] D + k], k=0,1,...,D-1
例えば、in[i] = {1, 0, 1, 1}, D = 1(dbpsk)の場合
out[0] = symbol_table[in[0]],
out[1] = symbol_table[in[1]],
....
この時のsymbol_tableは以下のm = 2 の場合
def make_constellation(m):
   return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
つまり、return [1, -1]
symobol_tableがm = 4(qpsk)の場合
return [1, j, -1, -j]
入力シンボルが0の場合、1を出力し、入力シンボルが1の場合、-1を出力する。
  • self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
最後にルートレイズドコサインフィルタにかけて、波形を滑らかにし、ナイキスト周波数にする。ここで初めてsamples/symbol(bpskの場合bit)を使う。
シンボルレートはこいつが決めている!?詳しくは神谷先生著の「MATLABによるディジタル無線通信技術」参照。
ナイキストフィルタのカットオフ周波数をf0とすると1/(2f0)の間隔で符号関干渉なくインパルスを伝送できる。
ゆえにシンボルレートは2f0[sps]となる。ただしこれはアナログフィルタの場合、ディジタルフィルタの場合は実時間ではなく、離散時間で表す。
ディジタルフィルタのロールオフフィルタの場合はシンボル間隔を何倍でサンプリングするかでどのように帯域制限されるかが決まるが、シンボルレートは決めることができない。
例えば、sinc(πkT'/T)においてT'/Tを1/2とする。これをD/A変換し、実時間にするときに初めて、シンボルレートが求まる。
USRPの処理能力は100M[samples/sec]で、1シンボルで2サンプル送るから50M[sps](ただ、これでは1Gを超えるので間引かれるが。。interpolation=4で12.5Mが最高)

増幅ブロック:gr.multiply_const_cc(1)

USRPシンクブロック:create_usrp_sink → generic_usrp.generic_usrp_sink_c → usrp2.cource_32fc

32ビットfloatの複素信号を入力にしたusrpのsink。

最終更新:2011年06月29日 01:14