RCCフィルタについて

「RCCフィルタについて」の編集履歴(バックアップ)一覧に戻る

RCCフィルタについて - (2011/07/11 (月) 18:44:04) のソース

一次変調信号を拡散させた信号を伝送する際に、最適にRCCフィルタを設定しなければならない。
指定された帯域内で信号を送信するため、パルス整形フィルタでデータビットが成形される。
その信号はキャリア変調部と無線周波数(RF)変換部を通過してアンテナを通して空気中に送信される。
(参考資料:[[altera>http://www.altera.co.jp/literature/an/an129_j.pdf]],[[fujitsu>http://img.jp.fujitsu.com/downloads/jp/jmag/vol51-1/paper05.pdf]],[[慶応>http://www.google.co.jp/url?sa=t&source=web&cd=2&ved=0CB8QFjAB&url=http%3A%2F%2Fwww.mos.ics.keio.ac.jp%2Flecture%2Fmedia%2FW-CDMA.ppt&rct=j&q=%E3%83%81%E3%83%A3%E3%83%8D%E3%83%A9%E3%82%A4%E3%82%BC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%AF&ei=icMBTrGuAoaOuQOtwaiJDg&usg=AFQjCNF7-kFwEoW4T-VdttKUwuZ0d9SB7Q&cad=rja]])
W-CDMAではチャネライゼーションとスクランブルという拡散が行われており、
前者が同セル内でユーザ間を識別したり、マルチコード伝送(1ユーザが複数チャネルを使うこと?)を実現するのに使われている。
後者はセル間の識別に用いられている。
一般的にはチャネライゼーションに直行符号、スクランブルにGold符号が用いられている。
alteraの仕様書ではどちらの拡散もQPSK変調する前に行っている。
一方fujitsuの仕様書ではチャネライゼーションをQPSK変調前に、スクランブルをその後に行っている。
[[この>http://www.mobile.ecei.tohoku.ac.jp/paper/pdf/rcs_2008/19_rcs_2008_obara.pdf]]参考ではScrambleした後にナイキストフィルタにかけて送信している。
*ナイキストフィルタ
T秒ごとに標本化された標本(ディジタル信号)をフィルタを通したとき、出力波形のT秒ごとの標本値が元の値と完全に等しくなるようなLPFをナイキストフィルタという。
パラメータはサンプリング周波数fsで1/2fsに帯域を制限することができる。
BPSKはマッピングと帯域制限のコンポーネントで構成されていて、入力ビットに対して複素信号を出力する。
[[参考>http://www.mobile.ecei.tohoku.ac.jp/intro/pdf/07_digital.pdf]]

*RRCフィルタ
よく使われるナイキストフィルタの一つ。
dbpsk.pyでは以下のように使っている。
        # pulse shaping filter
        ntaps = 11 * self._samples_per_symbol //22タップ数分(sps=2の場合)、一度のフィルタ出力に影響を与える。
	self.rrc_taps = gr.firdes.root_raised_cosine(
	    self._samples_per_symbol,   # gain (samples_per_symbol since we're
                                        # interpolating by samples_per_symbol)
	    self._samples_per_symbol,   # sampling rate ここの値はbenchmarkではよく2になっている!
	    1.0,		        # symbol rate
	    self._excess_bw,            # excess bandwidth (roll-off factor)
            ntaps)
	self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol,
                                                   self.rrc_taps)
サンプリングレート及びシンボルレートを引数に指定するが、これは1シンボル(bpskの場合ビット)送るのに何サンプルを使うかを
求めたいだけだから、ディジタルフィルタの場合、上に示すようにして引数を指定してもよい。第2引数は作成したフィルタタップを指定
以下、gr_firdes.h及びccの定義(RCCフィルタタップの作成)
  /*!
   * \brief design a Root Cosine FIR Filter (do we need a window?)
   *
   * \p gain:			overall gain of filter (typically 1.0)
   * \p sampling_freq:		sampling freq (Hz)
   * \p symbol rate:		symbol rate, must be a factor of sample rate
   * \p alpha:		        excess bandwidth factor
   * \p ntaps:		        number of taps
   */
 static std::vector<float>
 root_raised_cosine (double gain,
		      double sampling_freq,
		      double symbol_rate,       // Symbol rate, NOT bitrate (unless BPSK)
		      double alpha,             // Excess Bandwidth Factor
		      int ntaps);
 
 vector<float>
 gr_firdes::root_raised_cosine (double gain,
 			       double sampling_freq,
 			       double symbol_rate,
 			       double alpha,
 			       int ntaps)
 {
   ntaps |= 1;	// ensure that ntaps is odd
 
   double spb = sampling_freq/symbol_rate; // samples per bit/symbol  1シンボル(bpskの場合ビット)送るのに何サンプルを使うか。(spb = 1)
   vector<float> taps(ntaps);
   double scale = 0;
   for(int i=0;i<ntaps;i++) //全タップ数22
     {
       double x1,x2,x3,num,den;
       double xindx = i - ntaps/2; //-10から10の整数値
       x1 = M_PI * xindx/spb; //常に2π×n
       x2 = 4 * alpha * xindx / spb; //-10から10倍
       x3 = x2*x2 - 1; //99から-1から99
       if( fabs(x3) >= 0.000001 )  // Avoid Rounding errors...
 	{
 	  if( i != ntaps/2 )
 	    num = cos((1+alpha)*x1) + sin((1-alpha)*x1)/(4*alpha*xindx/spb);
 	  else
 	    num = cos((1+alpha)*x1) + (1-alpha) * M_PI / (4*alpha);
 	  den = x3 * M_PI;
 	}
       else
 	{
 	if(alpha==1)
 	    {
 	      taps[i] = -1;
 	      continue;
 	    }
 	 x3 = (1-alpha)*x1;
 	 x2 = (1+alpha)*x1;
 	 num = (sin(x2)*(1+alpha)*M_PI
 		 - cos(x3)*((1-alpha)*M_PI*spb)/(4*alpha*xindx)
 		 + sin(x3)*spb*spb/(4*alpha*xindx*xindx)); //この辺でSinc関数っぽくなっている。(denで割ると)
 	 den = -32 * M_PI * alpha * alpha * xindx/spb;
       }
       taps[i] = 4 * alpha * num / den;
       scale += taps[i];
     }
 
   for(int i=0;i<ntaps;i++)
     taps[i] = taps[i] * gain / scale; //正規化してタップ完成
 
   return taps;
 }
LPFの実装(gr_interp_fir_filter_ccf.cc)
 //コンストラクタ。第一引数に1サンプルをいくつに増やすか決めている。
 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);
 }
 //ワーク
 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 (); //2(samples/symbol)
   int ni = noutput_items / interpolation (); //22/2=11:補間を除いたタップすう。
   
   for (int i = 0; i < ni; i++){ //11
     for (int nf = 0; nf < nfilters; nf++) //2
       out[nf] = d_firs[nf]->filter (&in[i]); //d_firsが同じ入力in[i]に対して別のタップ(nfilters(=2)回は同じ値のタップ)を掛けている。
     out += nfilters;
   }
 
   return noutput_items;
 } 
 //タップをセット!
 void
 gr_interp_fir_filter_ccf::set_taps (const std::vector<float> &taps)
 {
   d_new_taps = taps;
   d_updated = true;
 
   // round up length to a multiple of the interpolation factor
   int n = taps.size () % interpolation ();
   if (n > 0){
     n = interpolation () - n;
     while (n-- > 0)
       d_new_taps.insert(d_new_taps.begin(), 0);
   }
 
   assert (d_new_taps.size () % interpolation () == 0);//なぜ補間数で割りきれるとエラーがでるのか??分からん。。→いやこれが偽の場合assert!!
 }
 
 //d_fir(2次元)にtapsをインストール
 void
 gr_interp_fir_filter_ccf::install_taps (const std::vector<float> &taps)
 {
   int nfilters = interpolation (); //2(samples / symbol)だとする。
   int nt = taps.size () / nfilters; //補間を除いたタップ数11(=22/2:default)。
 
   assert (nt * nfilters == (int) taps.size ()); //11*2=22
 
   std::vector< std::vector <float> > xtaps (nfilters); //vectorのアドレスを入れる。
 
   for (int n = 0; n < nfilters; n++)
     xtaps[n].resize (nt);  //22個から11個の配列にresizeする。
 
   for (int i = 0; i < (int) taps.size(); i++)
     xtaps[i % nfilters][i / nfilters] = taps[i]; //taps[i]を順番にxtaps(i,0)とxtaps(i+1,1)にどんどん入れてく。(つまり、補完を取り除いたタップが一列に並ぶ)
 
   for (int n = 0; n < nfilters; n++)
     d_firs[n]->set_taps (xtaps[n]); //補間を取り除いたタップをd_firs(二次元配列)にセット。
   
   set_history (nt); //11個をヒストリーにセットする。
   d_updated = false;
 
 #if 0
   for (int i = 0; i < nfilters; i++){
     std::cout << "filter[" << i << "] = "; //
     for (int j = 0; j < nt; j++)
       std::cout << xtaps[i][j] << " "; 
 
     std::cout << "\n";
   }
 #endif
 
 }

----