モールス信号decoder(オプション追加)

昨日、車でちょいと出かけた時、前を走る軽がえらい調子よく飛ばしてるなあと思っていたら、 インターを降りた所にある一時停止で、ちょいとスピードを緩めただけで、そのまま行っちゃった。

その途端、もの影に隠れていた白バイ2台が出動ですよ。けたましくサイレンを鳴らして、前を 行く軽を追跡。距離を縮めた所で、「No. XXXの車両、ウィンカーを出して左車線に移ってください」 と、ご案内。丁度、信号が有って、止まった所で、「信号が青になったら、左折して止まってください」 と、指示。

こうして、軽のおばちゃんは、人通りの少ない路地に連れ込まれたのでした。

人の不幸は、蜜の味

この一部始終を、白バイの後から追跡して、つぶさに観察しましたよ。だって、こういうの 久しぶりに見るんだもの。(テレビでは、たまにやってるけど、あれはやらせ?) 頑張って逃げれば、カーチェイスも見られて、面白かったのに。

ああ、趣味悪いですね。ずっと、ゴールド免許でいられるように、自戒しなければ!

K3

また、ハムの話題です。Elecraftが出している、K3と言うリグを 羨望の眼差しで見ている自分がいます。

レビュー記事を読んでも、国内のオーナーの使用感レポートを読んでも、耳がなかなか良いと 評判です。組み立てキット(完成品もある)で、自分が組み立てたと言う達成感も、アマチュア 心をくすぐります。

欲しいなあと思って調べてみると、国内代理店が あるため、直接の輸入は出来ないようです。中間マージンをがっぽり取られて、高いものに なってしまうかと思うと、ちと残念。日本以外へは直接輸出するそうなので、海外に つてを持つ人は、迂回輸入が可能でしょう。だれか、そういう人いないかな。

オプション

このK3にも、いろいろな追加オプションがあって、夢を見るにはうってつけ。でも、かなわない。 このうさを何処で晴らそう。

そうだ、いま自分が以前から作っている、モールス信号デコーダーに、オプションでも追加して、 我慢する事にしよう。

一番欲しいオプションは、モールス信号のスピードへの自動追従。他のオプションは、発想力が 無いから、にわかには浮かんでこない。(まあ、畳上の水練だから、しょうがないけど)

本体の cwd.c は、オプションを付ける事などまるで考えていなかったから、オプション用の インターフェース等は、何もない。そこで、得意の本体改造ですよ。なるべく、改造部分を 少なくするのがこつ。失敗してもすぐに、元戻し出来ますから。

信号検出の基準となっているのは、main()中でかろうじて変数宣言しておいた、int dot = 5; dotの値を書き換えてあげるだけで、符号検出のタイミングを変更できる。

ドットの値を書き換える関数(仮に、tr()とでもしよう)が、用意出来たとしたら、この関数の 返値を使えばいい。改造部分は、以下のようになる。

   int yes;    // Option
 ......
             if ( mcnt && (scnt > 1) ){        // in char (Option: dot -> 1)
                 val[x++] = mcnt > dot * 2 ?  '3' : '1'; 
                 yes = tr(mcnt);               // Option
                 if (yes) { dot = yes; }       // Option 
                 mcnt = 0;
                 if (x == MAXELE){ exit(1); }    // fatal, broken morce code.
             }

Option と書いた部分が、スピード自動対応の場合の、本体改造箇所。tr(mcnt)は、最新の マークカウンターの値をtr関数に渡して、ドット間隔の値を更新するか、しないかを決めて もらうということだ。更新が必要ない時は、0が帰ってくるし、更新する場合は、その値が 帰ってくる。

オプションの方式検討

受信機でフィルターが欲しいと言われたら、クリスタルィルターでもいいしメカフィルターでも いいし、DSPでやっても、フィルターはフィルターだ。

今回は、どうする。最新のmcntの値が渡されたって、それが、果たして短点なのか長点なのかの 判別がつかない。

過去のデータを溜めておき、そのデータを元に、短点(長点)を決めるのがよさそうだ。溜める データが多い程、安定するだろうけど、溜めすぎると追従スピードが悪くなりそう。 ここは、カットアンドトライするしかないか。取りあえず、過去16個のデータを保存し、古いデータは 削除する事にしよう。

この16個のデータを昇順ソートすると、前半には短点が後半には長点のデータが集まってくる。 (短点と長点の出現頻度は、半々と仮定したけど、本当か)

後は、短点と長点の比率(1:3が正しいけど、本体では、尤度を持たせて1:2以上としてるので、 これに習う)が正しいか判定する事にする。

オプションを単独で評価したいので、main付きのソース tr.c を以下に掲げる。

// auto speed tracking

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#define KEEP 16                          // mcnt keep count

int rp = KEEP;                           // ring pointer for kp
int kp[KEEP] = {                         // history (init value)
      6,  6,  6,  6,  6,  6,  6,  6,
     18, 18, 18, 18, 18, 18, 18, 18
};

int int_cmp(const int *a, const int *b){
    if (*a == *b){ return 0; }
    if (*a < *b){ return -1; } else { return 1; }
}

int tr(int v){
    int i, work[KEEP];
    int dot  = 0;                           // sum of dot
    int dash = 0;                           // sum of dash

    if (rp == KEEP){ rp = 0; }
    kp[rp++] = v;                           // Update history 

    bcopy(&kp, &work, sizeof(int) * KEEP);  // copy to work
    qsort(work, KEEP, sizeof(int), (int(*)(const void*, const void*))int_cmp); 

    for(i = 0; i < KEEP; i++){ 
        printf(" %d", work[i] );                            // monitor
        if ( i < KEEP/2 ) { dot += work[i]; } else { dash += work[i]; }
    }

    printf(" -> %d %d ", dot / (KEEP/2), dash / (KEEP/2));  // monotor
    if (dash > dot * 2){ printf("OK\n"); } else { printf("ng\n"); }
}

main(){
  int dot_dash;   // simulate mcnt

  while(1){
     printf("Next dot/dash ==> ");
     scanf("%i", &dot_dash);
     tr(dot_dash);
  }
}

オプションの評価

まず、短点が6(約100ms)の遅い状態から、短点2の速い信号を受信した時、どのぐらいで 追従するか、シュミレートしてみる。長点の長さは、多少くずれていて5だったとします。

[sakae@nil ~/CW]$ ./a.out
Next dot/dash ==> 5
 5 6 6 6 6 6 6 6 18 18 18 18 18 18 18 18 -> 5 18 OK
Next dot/dash ==> 2
 2 5 6 6 6 6 6 6 18 18 18 18 18 18 18 18 -> 5 18 OK
Next dot/dash ==> 5
 2 5 5 6 6 6 6 6 18 18 18 18 18 18 18 18 -> 5 18 OK
Next dot/dash ==> 2 ;;-------------------------------------- C
 2 2 5 5 6 6 6 6 18 18 18 18 18 18 18 18 -> 4 18 OK
Next dot/dash ==> 5
 2 2 5 5 5 6 6 6 18 18 18 18 18 18 18 18 -> 4 18 OK
Next dot/dash ==> 5
 2 2 5 5 5 5 6 6 18 18 18 18 18 18 18 18 -> 4 18 OK
Next dot/dash ==> 2
 2 2 2 5 5 5 5 6 18 18 18 18 18 18 18 18 -> 4 18 OK
Next dot/dash ==> 5 ;;--------------------------------------- Q
 2 2 2 5 5 5 5 5 18 18 18 18 18 18 18 18 -> 3 18 OK
Next dot/dash ==> 5
 2 2 2 5 5 5 5 5 5 18 18 18 18 18 18 18 -> 3 16 OK
Next dot/dash ==> 2
 2 2 2 2 5 5 5 5 5 5 18 18 18 18 18 18 -> 3 14 OK
Next dot/dash ==> 2 ::--------------------------------------- D
 2 2 2 2 2 5 5 5 5 5 5 18 18 18 18 18 -> 3 13 OK
Next dot/dash ==> 2 ;;--------------------------------------- E
 2 2 2 2 2 2 5 5 5 5 5 5 18 18 18 18 -> 2 11 OK

一応、上のデータの見方を説明します。==> 5 は、本体で検出した、最新のマーク値。 数字が16個並んでいるのは、ソート済みの16個のデータ。 -> の後のデータは、計算済みの 短点値、長点値 OKは、長点 > 短点 X 2 を満たしてる場合。

この例ですと、"CQDE" を受信した所で、短点が追従しました。

今度は、逆に、速い信号から、遅い信号に切り替わった場合です。

Next dot/dash ==> 18
 2 2 2 2 2 2 2 2 5 5 5 5 5 5 5 18 -> 2 6 OK
Next dot/dash ==> 6
 2 2 2 2 2 2 2 5 5 5 5 5 5 5 6 18 -> 2 6 OK
Next dot/dash ==> 18
 2 2 2 2 2 2 2 5 5 5 5 5 5 6 18 18 -> 2 8 OK
Next dot/dash ==> 6  ;;--------------------------------- C
 2 2 2 2 2 2 5 5 5 5 5 5 6 6 18 18 -> 2 8 OK
Next dot/dash ==> 18
 2 2 2 2 2 2 5 5 5 5 5 6 6 18 18 18 -> 2 10 OK
Next dot/dash ==> 18
 2 2 2 2 2 2 5 5 5 5 6 6 18 18 18 18 -> 2 11 OK
Next dot/dash ==> 6
 2 2 2 2 2 5 5 5 5 6 6 6 18 18 18 18 -> 3 11 OK
Next dot/dash ==> 18  ;;--------------------------------- Q
 2 2 2 2 2 5 5 5 6 6 6 18 18 18 18 18 -> 3 13 OK
Next dot/dash ==> 18
 2 2 2 2 2 5 5 6 6 6 18 18 18 18 18 18 -> 3 15 OK
Next dot/dash ==> 6
 2 2 2 2 5 5 6 6 6 6 18 18 18 18 18 18 -> 3 15 OK
Next dot/dash ==> 6  ;;---------------------------------- D
 2 2 2 5 5 6 6 6 6 6 18 18 18 18 18 18 -> 4 15 OK
Next dot/dash ==> 6  ;; --------------------------------- E
 2 2 5 5 6 6 6 6 6 6 18 18 18 18 18 18 -> 4 15 OK
Next dot/dash ==> 6
 2 5 5 6 6 6 6 6 6 6 18 18 18 18 18 18 -> 5 15 OK
Next dot/dash ==> 18
 2 5 6 6 6 6 6 6 6 18 18 18 18 18 18 18 -> 5 16 OK
Next dot/dash ==> 18
 5 6 6 6 6 6 6 6 18 18 18 18 18 18 18 18 -> 5 18 OK
Next dot/dash ==> 18 ;;----------------------------------- J
 6 6 6 6 6 6 6 18 18 18 18 18 18 18 18 18 -> 7 18 OK

こちらの場合は、若干追従が遅いようです。また、HHのような訂正符号を 受信すると

Next dot/dash ==> 6
 6 6 6 6 6 6 6 6 6 6 6 18 18 18 18 18 -> 6 13 OK
Next dot/dash ==> 6
 6 6 6 6 6 6 6 6 6 6 6 6 18 18 18 18 -> 6 12 ng
Next dot/dash ==> 6
 6 6 6 6 6 6 6 6 6 6 6 6 18 18 18 18 -> 6 12 ng

このように、短点データで、記録データが埋め尽くされる事態になり、短長点 比率が異常と言う事で、dot値の更新をロックします。

取りあえず、これを実戦投入してみるかなあ。

なお、このオプション設計にあたり、先人のJA3CLMさんに相談した所 スピードデータは、11msサンプリングしたデータを使い、16段階まで 自動追従するように、経験値データを内蔵してるとの事でした。 その節はありがとうございました。> JA3CLM

私のは、いい加減な作りですので、夢々、これでモールス符号の練習は しないようにお願いします。

どんな点がいい加減かというと、全てが・基準。長点比率や、文字間スペース ワード間スペースの確認がラフになっています。