2014年8月30日土曜日

WSPRコード生成手順を探る(訂正あり)

Weak Signal Propagation Reporter ; WSPRはK1JT Joe Taylor氏が開発した低電力ビーコン送受信プログラムで、数Hz帯域幅でSNR-28dBの信号までデコード可能な136kHz帯でもよく使われるデジタルモードのひとつです。

WSPRコードの生成はPCのソフトで行いますが、PCをつかわず送信機単体か外部コントローラーのPIC内で生成できないものか模索中です。

幸いなことにWSPRのソースコードは公開されておりユーザーマニュアルにWSPRコード生成の概要が記されていますが、ソースコードやマニュアルを見ても拘束長?畳み込み?などなど素人の自分には最初なんのこっちゃわかりませんでした。

ネットで手がかりを探った結果、G4JNT Andy Talbot氏のサイトにWSPRコーディングに関する具体的な手順の解説を見つけました。あと、前方誤り訂正(Forward Error Correction ; FEC)も少し勉強してようやくつかんできました。

備忘録としてソースコードを読んで解説を訳しながらまとめてみることにします。

1.送出キャラクタの圧縮
基本様式は、コールサイン(原則6文字)、グリッドローケータ(4文字)、送出電力(2文字)の計12文字(=12バイト=96ビット)ですが、これらをまとめて50ビットに圧縮します。

1)コールサイン部の数値化
 ①文字の種類と対応する番号
  数字、アルファベット、スペース記号を0から36の数値に割り当てます。
 i)数字(0~9)⇒ 0~9
 ii)アルファベット(A~Z) ⇒ 10~35
 iii)スペース記号 ⇒ 36

 ②注意点
  コールサインの1文字目はスペースを含め全キャラクタ使用可能
  コールサインの2文字目はスペース記号のみ使用不可
  コールサインの3文字目は数字以外使用不可
  サフィックス(4~6文字目)はいずれも数字は使用不可

 ③ユニーク数
  37 x 36 x 10 x 27 x 27 x 27 = 262177560 < 268435456 = 2^28 = 28ビット

 ④各数値化キャラクタをCh1~Ch6とすると、数値化コールサインNは、
  N = ((((Ch1 x 36 + Ch2) x 10 + Ch3) x 27 + (Ch4 - 10)) x 27 + (Ch5 - 10)) x 27 + (Ch6  - 10)

2)グリッドローケータ部と送出電力部の数値化
 ①文字の種類と対応する番号
 i)数字(0~9)⇒ 0~9
 ii)アルファベット(A~R) ⇒ 0~17

 ②グリッドローケータ部の数値化
  ユニーク数は、
  AA00~RR99 ⇒ 18 x 18 x 10 x 10 = 32400通り < 32768 = 2^15 = 15ビット

 各数値化キャラクタをLoc1~Loc4とすると、数値化グリッドローケータM1は、
 M1 = (179 - (Loc1 x 10 + Loc3)) x 180 + Loc2 x 10 + Loc4
 (余談:素直にM1 = (((Loc1 x 18) + Loc2) x 18 + Loc3) x 10 +Loc4にしなかったのはなぜなのでしょう?^^;)

 ③送出電力部と数値化グリッドローケータ部の組み合わせ
 電力値Pwr(dBm) = 0~60 (ただし、一桁目が0,3,7のみソフトで認識されます)

 数値化グリッドローケータと電力部の組み合わせ値Mは、
 M = M1 x 128 + Pwr + 64
 で、最大値が4124287 < 4194304 = 2^22 = 22ビット となります。
 (余談:最後の「+ 64」は、拡張用の予備部分なのかもしれませんが未確認)

これで数値化コールサイン部と数値化グリッドローケータ・電力部で
 N28ビット + M22ビット = 50ビット
に圧縮されました。

2.1バイト値1元配列化
 後の前方誤り訂正処理(FEC)を行うため、圧縮した50ビットを1バイト値の1元配列として割り当てます。 FECに入力するデータの大きさは拘束長32、レート1/2から50 + 32 - 1 = 81ビットになります。したがって11バイト = 88ビットの器が必要になります。
 その器に上から数値化コールサインNと数値化グリッドローケータ・電力Mを隙間無く入れ、残りの器(7番目の3ビット目以降)はすべて0とします。

3.FECエンコード
 32ビット長のシフトレジスタを2つ用意して、データの最初のバイトのMSBから1ビットとりだして、各々のシフトレジスタを右に1シフトさせてからLSBに格納します。そして、一つ目のシフトレジスタと0xF2D05351とのANDをとり、ビット間のXORをとった結果を別のレジスタに格納。もうひとつのシフトレジスタと0xE4613C47とのANDをとって同様にビット間のXORをとった結果をレジスタに格納。この操作を81回繰り返すことによって162ビットのコードが生成されます。

4.インターリーブ
 無線による信号伝送においてランダムエラーとバーストエラーに対してFECはランダムエラーには強いが、バーストエラーにはあまり強くないのでインターリーブを施します。
ビットの並びをある法則によってシャッフルして隣同士のビットを離すことによりバーストエラーに対抗する手法です。
 WSPRの場合は、162ビットのコードに順番にビットに番号を振って、その番号を8ビットであらわしてビットの並びを逆さにして並び替えます。
まず符号なし8ビット整数0から255まで順番にビット並びを反転します。
たとえば、"1"なら、b00000001 ⇒ b10000000 = "128"
     "18"なら、b00010010 ⇒ b01001000 = "72"
並び替えられた番号順にビットを並び替えます。
ビット並びを反転した整数が162未満の場合、その整数の番号の位置にFEC処理したコードを順番に1対1で割り当てていきます。
これをコード数である162回繰り返します。
 これで162ビットのデータシンボルが生成完了です。

5.同期シンボルとの連結
 最後にあらかじめ求められた擬似ランダム同期シンボルとデータシンボルを連結して1シンボル2ビット(4階調)の最終送出データが完成します。
 
 【162ビット同期シンボル】

1 1 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 0 0 1 1 0 1 0 0 0 1
1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 1 0 0 1 0 0 1 0 1 1 0 0 0 1
1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0 0 1 1
0 1 0 0 0 1 1 1 0 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0
1 0 1 1 0 0 0 1 1 0 0 0

 最終送出データシンボル(n) = 同期シンボル(n) + データシンボル(n) x 2

間違っているところがあるかもしれないので逐一修正しますが、この手順をCでコーディングしてみようと考えています。



追記:NとM1の式に間違いがあったので修正しました。(2014.9.3)
   インターリーブ手法訂正しました(2014.9.17)

4 件のコメント:

  1. お見事! 流石ですね。私は、なんのこっちゃと思っただけで、羅針盤(アルゴリズム解説)無しにあのフォートランサブルーチンの海を渡るのは無理と早々に諦めていました。

    QRSSなどもTX単体で考えておられるのでしょうか? 私はキーボードを繋ぐならPCを繋ぐのも大差ない、どっちにしても受信やネットでPCは必須なわけだし..と自分に言い訳しつつ、PC側のインタフェースプログラムに頼った実装をしてしまっています。

    でもやっぱりPCは面倒で、結局普段はWSQやJT9は立ち上げず仕舞いです。やはりスイッチ一つで立ち上がるAllInOne機が良いですね。

    返信削除
    返信
    1. MSOさんですよね、おはようございます!
      コメントありがとうございます。

      Andyさんの解説を見つけてなんとか理解できました。Thanks, Andy!
      136kHz(将来は476kHzも)帯は移動運用が主になるのでビーコンを出すだけならば、電気食い虫のPCは出来るだけ稼動したくないなぁというのが本音です。本当ならAndroidタブレットにArgoなどのソフトがあればいいのですが...(公開されているソースファイルで作るのもありですが、なかなか手が回りませんhi)

      JUMA TX-136やTX-500で使われているdsPICは比較的余裕がありそうなので本体にQRSS,DFCW, WSPR送信モードが実装できればいいなぁと思っています。

      まだまだ道のりは遠いです^^;

      削除
  2. 間違えました。お恥ずかしい。f^^

    トレースを試みたところ、Nの式でA-Zの+10に嵌って、M1で括弧の掛かり具合に悩んだのが関の山。FECからはちんぷんかんぷんで...、そうこうするうちに以下にwspr.cを見つけてしまいました。ご存知かも知れませんが。
    https://github.com/threeme3/WsprryPi

    あると思って探せば有るものですね。オランダのPE1NNZさん、GPL2、Andyさんの解説をまんまコーディングした雰囲気です。コピーして答え合わせしたところでは当然ながら問題なさそうです。賢くなる機会を逸しました。hi.

    返信削除
    返信
    1. MSOさん、こんばんは^^

      式を確かめたらおもいっきり間違えていました(汗
      混乱させてしまってすみません。

      wspr.cは知りませんでした。ご紹介ありがとうございます。
      斜め読みしましたが仰るようにAndyさんの解説手順のとおりのようですね。ソースはPICにもまんま利用できそうですhi

      でもせっかく手順が分かったのでとりあえず見なかったことにして(笑)コーディングしてみます。wspr.cのターゲットがRaspberry PiっぽいのでPICでも出来そうな気がしてきました!出来たらここで公開します。

      削除