これはおそらくあなたを助けるには遅すぎると思います(あなたは結局何をしましたか?)が、次の人を助けるかもしれません.
以下は、C の 1 行で作成したばかりのソフトウェア フェーズロック ループの例です。
main(a,b){for(;;)a+=((b+=16+a/1024)&256?1:-1)*getchar()-a/512,putchar(b);}
ソフトウェア フェーズロック ループは実際には非常に単純であると納得してもらうために、この小さなゴルフ バージョンを最初に提示します。
標準入力で 8 ビットの線形サンプルを供給すると、標準出力で 1 オクターブ高いトラックを追跡しようとするノコギリ波の 8 ビット サンプルが生成されます。1 秒あたり 8000 サンプルで、中央の C のすぐ下の B のすぐ上にある 250Hz 付近の周波数を追跡します。Linux では、 と入力してこれを行うことができますarecord | ./pll | aplay
。の下位 9 ビットはb
オシレータ (ハードウェア実装では VCO のようなもの) で、方形波 (1 または -1) を生成し、入力波形 ( getchar()
) を乗算して位相検出器の出力を生成します。次に、その出力をローパス フィルタ処理して、平滑a
化された位相誤差信号を生成します。この信号は、 の発振周波数を調整して 0 に近づけるために使用されます。方形波の固有周波数は、b
a
a == 0
b
サンプルごとに 16 ずつインクリメントします。これは、32 サンプルごとに 512 (フル サイクル) ずつインクリメントします。毎秒 8000 サンプルでの 32 サンプルは 1/250 秒であり、これが固有振動数が 250Hz である理由です。
次に、500Hz 程度のノコギリ波を構成するputchar()
の下位 8 ビットを取り出し、出力オーディオ ストリームとして吐き出します。b
この単純な例にはいくつか欠けているものがあります。
lock を検出する良い方法がありません。無音、ノイズ、または純粋な 250Hz の強力な入力トーンがある場合、a はほぼゼロになり、b はデフォルトの周波数で振動します。アプリケーションによっては、シグナルを検出したかどうかを知りたい場合があります。Designing Analog Chipsの第 12 章での Camenzind の提案は、2 番目の「位相検出器」に実際の位相検出器から 90° 位相をずらして供給することです。その平滑化された出力は、理論的にロックした信号の振幅を提供します。
発振器の固有周波数は固定されており、スイープしません。PLLのキャプチャ範囲(現在ロックされていない場合に発振に気付く周波数の間隔) はかなり狭いです。そのロック範囲は、ロックされた信号を追跡するために範囲を超えますが、はるかに大きくなります。このため、信号が検出されると予想される範囲全体で PLL の周波数をスイープし、ロックが得られるまでスイープを停止するのが一般的です。
上記のゴルフ バージョンは、私が今日書いた C 言語のソフトウェア フェーズロック ループのはるかに読みやすい例から縮小したものです。これは、ロック検出は行いますが、スイープは行いません。私のネットブックの Atom CPU では、PLL ごとの入力サンプルごとに約 100 CPU サイクルが必要です。
私があなたの状況にあったとしたら、次のことを行うと思います (信号処理について私よりも詳しい人を探したり、テスト データを生成したりするなどの明白なことは別として)。すでに非常に低い周波数であるため、フロントエンドで信号をフィルタリングしてダウンコンバートすることはおそらくないでしょう。200Hz ~ 400Hz 帯域へのダウンコンバートはほとんど必要ないようです。信号の位相が突然 90° 以上シフトすると、位相ロックが失われるため、PSK はいくつかの新しい問題を引き起こすと思います。しかし、これらの問題は簡単に解決できると思いますし、未踏の領域ではありません。