howto_scrambler_cc

PN系列で直接拡散させるブロックを作る。入力対出力レートは1:N(Nは拡散符号の周期)
まず、拡散符号を取り扱うクラスを調べる。

gr_lfsr.h

フィボナッチ線形帰還シフトレジスタで多項式マスクを指定することで、拡散符号を生成する。

詳細

  • コンストラクタ: gri_lfsr(int mask, int seed, int reg_len);
  • mask
次の次数のビットを作る(シフトする)ときに、帰還をかけるタップの場所を指定する多項式の係数。そこはxor演算される。例えば以下のようなマスクがある。
             x^4 + x^3 + x^0 = 0x19 (周期:15)
             x^5 + x^3 + x^0 = 0x29 (周期:31)
             x^6 + x^5 + x^0 = 0x61 (周期:63)
  • seed
各レジスタにセットされる初期値。LSBがx^0(最初に出力される値)に対応している。
  • reg_len
レジスタの長さ。通常はmask+1に指定する。
この長さのところにくるまで、各イタレーションに1ビットづつ右シフトする。
  • next_bit()
通常の線形帰還シフトレジスタの操作。
これでLFSRの1サイクルが処理される。
LFSRのLSBのビットが出力される。
MSBにはマスクされたレジスタの合計値を2で割った余り(要はxorされた結果)が格納される。
  • next_bit_scramble(unsigned char input)
入力ストリームを拡散する。
出力はnext_bit()と同じ。
ただし、MSBに格納されるビットは、入力のLSBとマスクされたレジスタの合計値をxorした結果である。
つまり、CDMAのような直接拡散を実現したい場合は、同じ入力サンプルを周期Nの間スクランブルしてもらえばOK!
ただここで、1or-1に拡散するように編集する必要がある。
以下ソースコード
 unsigned char next_bit_scramble(unsigned char input) {
   unsigned char output = d_shift_register & 1; //シフトレジスタのLSBをunsigned charとして出力
   unsigned char newbit = (popCount( d_shift_register & d_mask )%2)^(input & 1); //入力はunsigned charでその1バイトのLSBをLFSRに入力
   d_shift_register = ((d_shift_register>>1) | (newbit<<d_shift_register_length));
   return output;
 }
ここでは入力をunsigned charでかつ1or0の出力しか得られないので、入出力がfloatのscramblerを自作する必要がある。
  • next_bit_descramble(unsigned char input)
入力ストリームを逆拡散する。
出力ビットはマスクされたレジスタと入力サンプルのLSBの値の合計をxorしたもの。
MSBには入力のLSBが格納される。
CDMAのような逆拡散を実現したい場合は、gr_sync_decimatorを使って過去の拡散ビットを用いる必要がる。
もしかして、逆拡散ブロックの中でシンボル同期をとれるようにしちゃった方が早い??
というか、チップ周期でサンプリングして、その出力をいちいちチェックすれば結果だけでも得られる?
例えば逆拡散ブロックの出力は以下のようになる?
0.01, 0.001, ..(タップ数分).., -1.24, -0.05,..(タップ数分)..,1.34, 0.03,....
この1や-1に近い値を閾値処理してやれば、送信シンボルが得られる?
でもgr_pn_correlator_ccが使えるかもしれないので、チェックしといた方がよい。
あと、フローグラフ内だけでCDMA実験ができることも頭に入れといた方が良い、数値実験だけど。

gr_interp_fir_filter_ccf.h&.cc

1:Nのブロックを実現するためには、gr_sync_interpolator.hを継承する必要があるため、参考にこのブロックを調査する。
  • コードリーディング
gr_interp_fir_filter_ccf.hの一部
class gr_interp_fir_filter_ccf : public gr_sync_interpolator
{
 private:
  friend gr_interp_fir_filter_ccf_sptr gr_make_interp_fir_filter_ccf (unsigned interpolation, const std::vector<float> &taps);

  std::vector<float>	d_new_taps;
  bool			d_updated;
  std::vector<gr_fir_ccf *> d_firs;

  /*!
   * Construct a FIR filter with the given taps
   */
  gr_interp_fir_filter_ccf (unsigned interpolation, const std::vector<float> &taps);//コンストラクタ

  void install_taps (const std::vector<float> &taps);

 public:
  ~gr_interp_fir_filter_ccf ();

  void set_taps (const std::vector<float> &taps);

  int work (int noutput_items,
    gr_vector_const_void_star &input_items,
    gr_vector_void_star &output_items);
};

gr_interp_fir_filter_ccf.ccの一部
//コンストラクタ
gr_interp_fir_filter_ccf::gr_interp_fir_filter_ccf (unsigned interpolation, const std::vector<float> &taps)
 : gr_sync_interpolator ("interp_fir_filter_ccf",
			  gr_make_io_signature (1, 1, sizeof (gr_complex)),
			  gr_make_io_signature (1, 1, sizeof (gr_complex)),
			  interpolation),
    d_updated (false), d_firs (interpolation)
{
  if (interpolation == 0)
    throw std::out_of_range ("interpolation must be > 0");

  std::vector<float>	dummy_taps;
  
  for (unsigned i = 0; i < interpolation; i++)
    d_firs[i] = gr_fir_util::create_gr_fir_ccf (dummy_taps); 

  set_taps (taps);
  install_taps(d_new_taps);
}
//Work部
int gr_interp_fir_filter_ccf::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]; //入力ベクトルの先頭アドレスを格納
  gr_complex *out = (gr_complex *) output_items[0]; //出力ベクトルの先頭アドレスを格納

  if (d_updated) {
    install_taps (d_new_taps);
    return 0;		     // history requirements may have changed.
  }

  int nfilters = interpolation ();
  int ni = noutput_items / interpolation (); //入力の数は出力の数をd_interpolationで割った数
  
  for (int i = 0; i < ni; i++){ //このループは複数の入力ストリームを処理してくれる
    for (int nf = 0; nf < nfilters; nf++) //このループでタップ数分のフィルタ処理値をoutベクトルに格納!!!!
      out[nf] = d_firs[nf]->filter (&in[i]);
    out += nfilters; //フィルタのタップ数分だけoutベクトルの先頭ポインタを進めて次のループへ
  }

  return noutput_items;//出力データ数を返す
}
引数であるinterpolationはgr_interp_fir_filter_ccf引いてはgr_sync_interpolationが実体化する瞬間に初期化される。

gr_sync_interpolation.h&cc

  • gr_sync_interpolation.ccの一部
//forcast()内で入力の数を予測するのに用いられる。
int gr_sync_interpolator::fixed_rate_noutput_to_ninput(int noutput_items)
{
  return noutput_items / interpolation() + history() - 1;//interpolation()はd_interpolationを返す
}

//general_work内のconsume_eachで少ない入力数スケジューラに教え、出力の数が入力の数に対して大きくなるようにする。
int gr_sync_interpolator::general_work (int noutput_items,
				    gr_vector_int &ninput_items, 
				    gr_vector_const_void_star &input_items,
				    gr_vector_void_star &output_items)
{
  int	r = work (noutput_items, input_items, output_items);
  if (r > 0)
    consume_each (r / interpolation ()); //出力の数をd_interpolationで割った数が入力で消費される。
  return r;
}

//出力から入力の数を予測する。※でもなぜか誰もforecast使ってな~い
void gr_sync_interpolator::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] = fixed_rate_noutput_to_ninput(noutput_items);//出力と入力の数の関係を決定する。
}
やはりinterpolationの値で入力出力の比を決めている。
つまり、interpolationに拡散符号の周期を指定してやればいい!

出力結果

こんな感じ
in[0]=3+1j, out[0]=3+1j
in[1]=3+1j, out[1]=3+1j
in[2]=3+1j, out[2]=3+1j
in[3]=-3+1j, out[3]=-3+1j
in[4]=-3+1j, out[4]=-3+1j
in[5]=-3+1j, out[5]=-3+1j
in[6]=-3+1j, out[6]=-3+1j
in[7]=3+1j, out[7]=3+1j
in[8]=-3+1j, out[8]=-3+1j
in[9]=3+1j, out[9]=3+1j
in[10]=-3+1j, out[10]=-3+1j
in[11]=-3+1j, out[11]=-3+1j
in[12]=3+1j, out[12]=3+1j
in[13]=3+1j, out[13]=3+1j
in[14]=-3+1j, out[14]=-3+1j
in[15]=-4+2j, out[15]=-4+2j
in[16]=-4+2j, out[16]=-4+2j
in[17]=-4+2j, out[17]=-4+2j
in[18]=4+2j, out[18]=4+2j
in[19]=4+2j, out[19]=4+2j
in[20]=4+2j, out[20]=4+2j
in[21]=4+2j, out[21]=4+2j
in[22]=-4+2j, out[22]=-4+2j 
in[23]=4+2j, out[23]=4+2j
in[24]=-4+2j, out[24]=-4+2j
in[25]=4+2j, out[25]=4+2j
in[26]=4+2j, out[26]=4+2j
in[27]=-4+2j, out[27]=-4+2j
in[28]=-4+2j, out[28]=-4+2j
in[29]=4+2j, out[29]=4+2j
タップ数15及び31のM系列を発生させるパラメータ
//タップ数15
//interpotion = 15
//mask = 25   #2^4 + 2^3 + 2^0 = 25 ,ntaps = 15
//seed = 8
//reg_len = 3
//シフトレジスタの状態遷移(下位4ビットが有効)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 

//タップ数31
//interpotion = 31
//mask = 41   #x^5 + x^3 + x^0 = 41 ,ntaps = 31
//seed = 1
//reg_len = 4
//シフトレジスタの状態遷移(下位4ビットが有効)
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 
シフトレジスタは32ビットで今のところ実装されているから、最大で2^32-1周期のM系列を発生させることができる。

ソースコード



最終更新:2011年06月17日 00:37