ワンセグ生データをOFDM復調(1)

前回、GNU RadioとADALM PLUTOを使って、 ワンセグの生データを取得してファイルに保存しました。

いきなり余談(Jupyterを使うまで)

現在、Pythonにて上記のデータをデコードできるかを実験しています。 最初はCでプログラムを作成し始めました。でも、実装していると、 途中途中までで、思い通りに処理ができているかを確認したくなります。 そのために、グラフを作成する必要が出てきました。CImgなど、 C++で比較的に簡単に使えるライブラリも試しました。これは画像生成は簡単ですが、 グラフ生成は面倒に感じました。

それで、結局Jupyter Notebookを使ったほうが簡単だということで、Pythonに移行しました。アルゴリズムが固まったら、データを一気に処理するためにC,C++に戻る予定ですが。

ここから本題

キャプチャした生データをソフトウェアで処理して、MPEG TSを得るところまで持っていきたいと考えています。そのためには、まずなによりも、OFDMの復調処理が必要です。 ここがクリアできれば、残りはそれほど難しくないと予想しています。

以下、Notebookの画像を貼り付けていきます。

“相関値算出まで”

上記In [1]は、各種ライブラリを使用することを宣言しています。[2]でcapture.rawという、GNU Radioで保存したファイルを開いて、dataという変数に読み込みます。 ファイルの一番先頭は少し飛ばしています。

[3]はガードインターバルとシンボル長の定義です。 ADALM PLUTOでは、64/63MHzでサンプリングしています。1シンボルは1008[us]なので、 計算してみると、ちょうど1024というキリの良い個数になります(そうなるようにサンプリング周波数を設定している)。

(少なくとも日本の)ワンセグのガードインターバルはシンボル長の1/8なので、128になります。

[4]は、シンボルの境界を検出するための相関値を求める関数correlateの定義です。 この方法については、 “An Open and Free ISDB-T Full_Seg Receiver Implemented in GNU Radio” Federico Larroca et al.で最初に知りましたが、 “ML Estimation of Time and Frequency Offset in OFDM Systems” Van De Beek et al.がオリジナルのようです。

最初の論文の(1)式の計算になります。ざっくり説明すると、シンボル長だけ離れた、ガードインターバル長サンプルの相関(積和, 上記gamma)を計算しています。また、RHOは本来であればSNR/(1+SNR)で定義されるのですが、今回は定数としています。十分SNRが大きければ1に近づく値なので、 ひとまずこのように置いても問題なさそうです。

“極大計算”

[5]では、実際に先頭をずらしながら相関値を計算していき、配列corに入れます。 correlateが返すのはタプルなので、[6]で分解してそれぞれの配列を得ます。 配列corrsの値が極大になっているところが、OFDMシンボルの区切りです。

[7]はグラフを見やすくするためのサイズ調整です(横幅を伸ばしている)。

[8]で相関値とガンマの値を時系列のグラフにしています。結果が次です。

“correlation”

上記Van De Beekの論文のFigure 4と同じような結果です。横軸はサンプルの番号です。赤い線が左の縦軸に対応しており、相関値を表します。青い線が右の縦軸に対応しており、ガンマの偏角を表します。

相関値がおよそ1024+128サンプル(OFDMシンボル長+ガードインターバル長)間隔で極大値を取り、 その時にガンマの偏角は大体同じ値(-2.0近辺)を示しています。

“derotate”

[9]は、シンボルごとの相関値の極大値(配列maxes)、 極大値を与える配列インデックス(配列indices)、その際のガンマの偏角を求めています。

ここまで、OFDMシンボル境界検出は上手く行っていますが、[10]以降はまだ試行錯誤しています。 [10]は、ガンマの偏角を用いて、サンプルデータを回転させてからFFTで周波数領域に移しています。 これは送信機と受信機のOFDMキャリア周波数の偏差(小数部のみ)を補正することに相当するはずです。

“FFT on one symbol”

[11]では試しに、1つの相関のピーク(インデックス5530)を先頭として、 1OFDMシンボルをFFTしています。これを虚数平面にプロットしたのが次の画像です。

“constellation”

なんだかバラバラです。キャリア周波数の補正ができていれば、 あとはキャリアの位相差だけしか残らないと考えていました。 そうであれば、パイロット信号(Scatterd Pilot: BPSK, TMCC: DBPSK)を除くワンセグのデータはQPSKのため、 GNU Radioで上手く行っているときのコンステレーション画像:

“Good constellation”

を回転したような結果が得られるかと期待したのですが、全くうまく行っていないようです。

[12]は、FFTした結果の最大値を見つけています。計算が正しければ、これがパイロット信号になっているはずなのですが…

ひとまずここまでです。

  • FFTで戻すデータの取り出し部分が間違っている?
  • (OFDMシンボル期間をまたぐ)時間方向でパイロット信号と相関を取ってチャンネル補正なりをしないと(コンステレーションとしても)データが取り出せない?
  • キャリア周波数が整数倍でずれていて、その補正が必要?

原因まで理解できていません。もう少し調査してみたいと思います。

2019/2/12追記

上記[10]が間違っていたようです。

rots = np.exp([-1j*arg*k/SYMBOL_LEN for k in range(SYMBOL_LEN)])

ではなく、

rots = np.exp([1j*arg*k/SYMBOL_LEN for k in range(SYMBOL_LEN)])

に直したところ(補正の回転方向が逆)、

“constellation”

上記程度にはなりました。少しはQPSKらしく見えてきました。これでTMCC検出やSP検出を行って等価処理をすれば、それなりの結果が得られそうです。

comments powered by Disqus