Si5351単体で3MHz以下の直交信号を出力する

Si5351Aは Multisynth の delay パラメータを使って直交信号を出力することができるが,パラメータの設定範囲が最大127のため,直交信号を出力できる範囲はおよそ3MHz以上に限られる.(Si5351で直交信号) そこで 別の方法によって 3MHz以下の直交信号を得ることにした.

Si5351の構成は図通りで,Mutisynthの分周比M0, M1をある値で固定しておき,PLLのフィードバック分周比Nを変化させて周波数をコントロールするのが一般的.

si5351_01.png

今回のポイントは,M0, M1も分数分周比をとることができるので,M0, M1によって周波数を細かく制御することが可能という点.ただ,Mの値の制御ではスムーズな周波数制御はできないと思うのでMの制御は位相差π/2を得るためだけの手段とし,周波数の制御はPLLの分周比Nの制御で行う.

Mの制御で希望の位相差を得るには,M0,M1を時間差をつけて変化させればよい.
例えば,M0, M1 = m’ としておいてPLLリセットする(これで位相が0にそろう).
その後, M0 = m  (m<m’,  M1 = m’  はそのまま) とすれば  f I>f Q となり
周波数差 fd = f I – f Q  が生じる.
これによって,f I の位相が f Q に対して時間経過とともに進んでいく.
経過時間を Td  とすれば,位相の進み θd は次式で表される.

eq1

よって,θd = π/2 となる Td は,

eq2.png

となるので,この時間経過後に M1 = m にセットすれば,π/2の位相差を持った信号が得られる.この操作は一度行えばよい.それ以降,m の変更がなく,かつ,周波数の変更をPLLで行えば位相差は維持される.

例として,2.0MHzの直交信号を得る場合について手順を示す.
条件は,m = 300,  fd = 4Hz,  Multisynthのモードは fractional.

  1.   fvco = 300*2.0MHz = 600MHz となるよう  N =  600MHz/25MHz = 24  にセット
  2.  出力周波数 f I, fQ = 2.0MHz –  4Hz  となるよう,
    M0, M1=600MHz / ( 2MHz-4Hz ) = 300.0006 にセット
  3.  PLLリセット
  4.  M0 = 300 にセット
  5.  Td = 1/(4fd) = 62.5ms 経過後に M1 = 300 にセット

これで2MHzの直交信号が得られる.以降,周波数を変化させる場合,例えば1.99MHzに変更するには,Nのみ変更し,N = 1.99MHz*300 / 25MHz = 23.88 にセットする.
ここで重要なのはPLLリセットしないこと.
fd は任意だが小さい方が位相差の精度がよいかもしれない.ただしTdが大きくなり待ち時間が長くなる.

以下動作例

出力周波数=1.18MHz
20200827_193438

出力周波数=588kHz
20200827_193537.jpg

 

保証された動作ではないかもしれないが,いまのところ変な動作はしていない様子.

SDR using dsPIC for SSB MODE

FM,AMモードはまだ納得できる状態ではないが,SSBに関しては問題なさそうなので,ファームウェア(ソースコード)などを公開した.

Source code,  Circuit diagram

IIR, FIR フィルタの特性を変えるためのツールも置いてある.

dsPICの内部処理は以下のとおり.

SSB_demod.jpg

原理的にはこれまで通り,複素係数フィルタで正(または負)の周波数成分をカットするフィルタ式.
コードを書いていて思ったのだが実際の処理内容はPSNと酷似している.なので,複素係数フィルタをAF PSN とみなしてもよいと思う.
hilbert 変換自体が負の周波数をカットするハイパスフィルタだし,一方,複素係数フィルタの虚数部は hilbert 変換器と同じものになっていることを考えれば.本質的に PSN方式 もフィルタ方式も同じということだろう(もちろん実現手法の違いはある).

FM demodulation (SDR using dsPIC)

FMの復調機能の追加を行った.
AMの復調ができているので,それを少しモディファイするだけでOK.
つまりAMは振幅を求めるがFMは位相を求めて微分すればよいので,下図のような構成になる.

FM_demod.jpg

tan の逆関数は安直にテーブル参照にした.math ライブラリのatanやatan2関数は処理が重くて使えなかった.
今のところSGからのFM信号はうまく復調できている.リミッタを深く効かせた通常のFM復調と違ってノイズは多め.この方式はI,Q信号の瞬時値から位相を計算するため,リミッタが使えないから仕方ない.

もう少しテストが必要かもしれないが,とりあえず SSB(USB/LSB),CW,AM,FM モードの受信が可能になった.

AM demodulation (SDR using dsPIC) (2)

Direct Conversion 方式でAM復調がうまくいった… 確かにほぼうまくいったのだが,問題があることがわかった.
ローカル信号のリークが周波数によっては予想以上に大きくなるところがあり,アンプをDC結合したためにリークの直流成分でアンプが飽和してしまい,その周波数では受信不能となる.飽和しないレベルであれば動作はするが,ダイナミックレンジが狭くなる.
直前の記事で,「直交ミキサでベースバンドに変換するDC方式はなかなか難しい」と書いた通りになった.

まず,アンプをAC結合に戻し直流による飽和が起こらないようにした.

次に,ローカル発振(VFO)周波数 ωc を受信周波数 ωm より ωi  低くして,受信したAM信号の周波数を ωi に変換し,これを増幅した後AD変換してdsPIC に取り込むようにした.
今回 ωi = 2 π 12.5kHz としている.

AM_demod2.jpg

その後信号処理で,上図に示すようにベースバンドに変換している.
(乗算器が4個必要なのは,複素数同士の掛け算のため)
LPF以降は前回と同じ.

dsPIC33FJの能力の限界に近い処理量のようだが,AM受信自体は前回と同様問題なくできている様子.受信周波数を500kHzから54MHzまで変えてみたが,受信できなくなる周波数は無いようので,しばらくこれで動作確認をしてみる.

AM demodulation (SDR using dsPIC)

dsPICによるSDRでSSBやCWはうまく受信できている.これに加えてAMモードも実装したい.AM受信はSSBモードでもできるが,キャリア周波数を完全に合わせないと受信信号のピッチが変わってしまう.会話なら問題も少ないが音楽は不協和音になってしまって聞きづらいので,やはりAMモードが必要だと思う.

AMの復調をするには,下図のように,IchとQchをそれぞれ2乗して加算したあと平方根をとればよい.

AM_demod

理屈は簡単だが,直交ミキサでベースバンドに変換するDC方式だと,キャリア周波数が0Hz(直流)に変換されるので実際にはなかなか難しい.なので多くは,キャリア周波数を0Hzではなく10kHzなどに変換し,それを信号処理してAM復調をする.

ただ今回使用しているdsPICの性能にあまり余裕がないので,上図のとおりDC方式にする.

LPFの出力は次式となる.eq1_2

AMの場合,A + m(t) > 0 なので,

eq3

これの直流分 A/2 をカットすれば復調完了で,式(3)にはキャリア周波数とローカル周波数の差の要素は含まれないので,チューニングのずれで復調される信号ピッチが変わるということはない.

それはいいのだが,実際はミキサの出力にはローカル信号のリークに起因する直流成分が加算される.DBMにしてもリークを0にすることは現実的には困難で,また厄介なことにリークの量は一定ではなく,周波数によって変化する.

リークは直流として生じるので問題なさそうに思えるが,そうではない.
リーク成分を vi, vq として,それらを考慮した場合のLPFの出力を I’ , Q’ とすれば,

eq4_5

このとき,出力は,

eq6

となる.面倒なのでこれ以上の式の展開はしないが,明らかに出力に歪が生じてしまう.チューニングがあっている(ωc=ωm)のときは歪だけだが,チューニングがずれると式(6)の第3,4 項によってビート成分とその高調波も出てくる.

結局,リーク成分vi, vq を除去することが必須であることがわかる.ただ厳密にはそれは不可能なので,条件をつけて譲歩するしかない.

その条件は,「厳密にチューニングがあう(ωc=ωm)ことはない」ということ.

もし ωc=ωm だったら,

eq7_8

となるが,残念なことに第1項と第3項はどちらも直流で分離不可能.

仮に式(7),(8)から直流分を除去すると次式となり,

eq9_10

出力は次式となる.

eq11

元の信号を全波整流したものとなってしまって復調できない
(  m(t) が正負の値をとることに注意).
AMの場合,A+m(t)が常に>0.そうなるようにAが足されていることに大きな意味がある.

 

…ということで,ωc=ωmのときはあきらめて,厳密にそうなることは稀だということに期待する.

ωc≠ωmならば,式(1), (2)をみればわかるように,I, Q は,周波数差|ωc – ωm|に相当する周期をもつ交流となる.リーク込みのLPF出力は式(4), (5) だが,これの時間平均をとれば,I,Qはともに0に収束し最終的に vi, vq のみとなって,リークによる直流分が得られる.得られた値を信号処理時にI, Q信号から引けばよい.

今回,平均処理を2~3秒間の移動平均としてみる.例えば,平均時間2秒なら,1/2=0.5Hz以上周波数がずれていればよい.AMで0.5Hz以内にゼロインするのは難しいと思うので実用的にはOKだろう.たまたま合ってしまう可能性はゼロではないけど,受信信号とローカル信号は全く無相関なのでその状態が長く続くとも思えない…(と希望的観測しておこう).最終的に約2.6秒とした.

ここまで書いて気付いたが,これってカットオフ周波数の非常に低いHPFで直流をカットしているのと同じことだった.ただカットオフ周波数が0.5Hzとかになるので,容量がものすごく大きなCが要る(10000uFとか)し,カットオフ周波数の調整も面倒そうなので,信号処理でやる意味はありそう.

実際の動作の様子はこちら( https://youtu.be/txrccQwB3Pc )

チューニングのずれによるピッチの変化がなくなりAMらしくなった.少しビートが残っている感じがするが,まあいいんじゃないかと思う.むしろチューニングの目安となっていいかもしれない.

ついでにAGC処理も追加しておいた.
ちなみにスピーカのすぐ上に見える回路はアナログでAGCをやろうとした残骸.
信号処理でAGCがうまくいったので使っていない.
また,直流分も通すためにミキサからAD変換までの回路をDC結合に変更した.

そろそろ基板におこせる段階かな.
その前にFMもやってみようか…

SDR using dsPIC33FJ64GP802 (2)

レシーバをテストしていて気づいたのだが,RF入力のレベルが小さくなっていくと,あるレベル(しきい値)でノイズゲートが掛かったようにいきなり無音となる.さらによく調べてみたら,しきい値付近のレベルだと信号やノイズがとぎれとぎれになってブツブツという音がする.どうもAD変換時の量子化が原因のようだ.しきい値はAD変換の量子化レベルであって,dsPICの場合,12bitなので,3.3V/4096=805 uV.
これ以下の変化は検知できず,一定値の信号として処理され結果として無音になる.また,これを超えるか超えないか微妙なレベルだと変なノイズが出る.

量子化レベル以下の変化を取り込む方法として,よく知られているものとしてはディザー信号を重畳させる方法がある.

つまり,量子化レベルより十分大きな振幅を持つ信号(ディザー信号)を目的信号に加え,量子化レベルを超えさせる.ディザー信号は,目的信号と周波数帯域が重ならないスペクトルを持つ信号とする(一般的には,目的信号より高い周波数領域に成分を持つノイズなど).

目的信号+ディザー信号をAD変換で取り込んだら,信号処理(フィルタ)でディザー信号の成分をカットすればよい.

数値計算で確認してみた結果を以下に.

入力信号は振幅0.1,周波数800Hzとする.

nodither
+/-0.5を量子化の区切りとする.
上段のグラフのように入力信号の振幅が0.1の場合,AD変換器で量子化されると中段のグラフのように一定値0となってしまい入力信号の情報は失われる.当然スペクトラムも下段のとおり全域で0となる.

次に,振幅50,周波数6.25kHzの正弦波をディザー信号として加えてみる.

dither

ディザー信号を入力信号に重畳すれば,量子化されても入力信号の情報は失われないことが
スペクトルをみればわかる.
不要な6.25kHzは,デシメーションフィルタがカットしてくれるので問題ない.

 

もう一つの例として,入力信号が量子化レベルをぎりぎり超える程度の振幅(0.55とした)を持つケースを以下に示す.

nodither2
入力信号は取り込めているが高調波成分が生じている.量子化された波形をみれば当然.

 

ディザー信号ありの場合.

dither2

こちらの方が,高調波成分が少なく,低ひずみで信号が取り込めているのがわかる.

 

実回路で確認.
下図のとおり,DACのLポートから6.25kHzを出力し,オペアンプの入力に加えた.

dither_circuit1

とりあえず,空中配線で…

20200620_225906

信号レベルが低くても無音となることはなく,変なノイズも発生しなくなった.

 

SDR using dsPIC33FJ64GP802

dsPICで受信用のAF PSN試作して動作確認まで行っていたが,それを使って実際に受信機を組んでみた.

Source code ,  Circuit diagram

動作の様子 Youtube

今のところ,AGCはもちろん,RFアンプも入力のフィルタもないが,それなりにうまく動作しているようなので,きちんとした受信機に仕上げてみようと思う.

AF PSN for DC Reciever

以前,SSB送信用のAF PSN をdsPICで製作した.
その後,受信用もできないかと気になりつつも,ずいぶん時間が経ってしまった.
もちろん,dsPIC33FJ64GP802にこだわらなければ何とでもなるが,
このdsPIC  1個でできれば面白いと思う.

よく知られているとおり,PSN受信機の構成は以下のようになる.

r01.jpg

AF PSNの部分をdsPIC33FJ64GP802 1個で構成したいのだが,
ADCが12bitであることと、2ch同時サンプルができないことが課題.
特に,12bitでは受信用としてダイナミックレンジが満足できない気がして,
いま一つやる気が起きなかったが,ようやく,「とりあえずやってみるか」
という気分になってきた.

受信用も,送信用のAF PSN同様,複素係数フィルタを使う.
r02.jpg

解析信号でブロック図を書くと以下のとおりで,送信用AF PSNもそうだが,
本質的にはフィルタ式と同じ.r03.jpg

 

結論から言えば,以下のような構成で,受信用AF PSNを実現できた.
r04.jpg

r06.jpg

r07b.jpg

r08b.jpg

一応設計通り動作している様子.
実際に受信機として使い物になるかどうかは,後日評価したい.

 

以下は詳細.

1.AD変換
送信用は,入力信号がほぼ話者の声だけと考えられるので,
アンチエイリアスフィルタが無くてもほぼ問題なかったが
受信用はそういうわけにはいかず,AD変換前にナイキスト周波数以上の成分を
十分に除去しなければならない.
カットオフ周波数がナイキスト周波数(1/2サンプリング周波数)に近い
シャープな切れ味のLPFを使って,
サンプリング周波数をあまり上げることなく十分な帯域をとりたいところだが,
そのようなフィルタは,カットオフ付近の移相量が大きく素子感度が高いため
温度変化など環境変化やその他様々な要因で特性が変化しやすい.
一番の問題は,そのようなフィルタが2個(I, Q)必要なことと,
それらが常に同じ特性でなければならないこと.
したがって,素子感度を下げ2個フィルタの特性のばらつきをできるだけ抑えたい.

そのためには,カットオフ付近で位相がなだらかに変化するフィルタが望ましいので,
ベッセルフィルタがよいと思う.
当然,カットオフ(振幅)特性もなだらかになり,シャープな切れ味にはならないので,
アンチエイリアスの能力は低下する.
そこでサンプリング周波数をできるだけ高くする.今回は100kHzとした.
また,dsPIC33FJ64GP802は48MHzのオーバークロックで動作させる.

I,Q 2ch同時サンプルはできず,2μs程度の遅延がありサンプリングタイミングがずれる.
2μsは,例えば3kHzにおいては,位相で 2.16deg に相当する.
これは無視できるレベルではないので,後段の複素係数FIRフィルタで
この遅延を補正することにした.

 

2.デシメーション用 IIRフィルタ
100kHzサンプリングですべて処理できればいいのだが,
dsPIC33FJ64GP802の性能では難しそうなので,
サンプリング周波数を1/8(12.5kHz)に下げる.
そのためには,後段の複素係数フィルタのナイキスト周波数(6.25kHz)以上の成分を
十分に除去しなければならない.
(このIIRフィルタのサンプリング周波数は100kHz)
I,Q 2chのフィルタが必要だが,ディジタルフィルタなので,
特性に違いが生じたり変化する心配はない.
できるだけシャープなカットオフ特性をもったLPFを使いたいので,
今回は,4次Elliptic LPF にしてみた.
IIRフィルタは設計が面倒だが,動作時はFIRより少ない計算量で済む.

2次IIRフィルタは以下のような構成になる.4次はこれを2段直列に接続する.

r05.jpg
kは本来不要なパラメータだが(k=1でよい),dsPICのように固定小数点演算の場合は,
計算途中で結果がオーバーフローしないようにk>1とする必要がある.
今回は k=4 とする.

IIRフィルタの設計には,GNU Octave (フリーウェア)を使った.
設計用のスクリプト ( IIR_ellip_LPF_design.m ) を実行すれば,
b0/k, b1/k, b2/k, a1/k, a2/k, k を定義するヘッダファイルが生成される.
signal パッケージを使うので,Octaveを起動したらコマンドラインで,

pkg load signal

とタイプしておく必要がある.

次に,dsPICでIIRフィルタを実行するソースコード(dsPIC33,DSPライブラリ使用)を
以下に記載しておく.

//— IIR ———————————–
//4th IIR Elliptic LPF coeff.
//fs=100000[Hz],  fc=3000[Hz]
//Ripple=1[dB],  Att=70[dB]

fractional _XDATA(2) IIR_coef0[] =
//{b0/k, b1/k, b2/k, a1/k, a2/k, log2(k) }
{ 53, -26, 53, 15311, -7199,  2};

fractional _XDATA(2) IIR_coef1[] =
//{b0/k, b1/k, b2/k, a1/k, a2/k, log2(k) }
{720, -1161, 720, 15706, -7794,  2};

fractional _YBSS(2) Z_Re_0[5];
fractional _YBSS(2) Z_Re_1[5];
fractional x, y;

void IIR_Ellip_LPF(void)
{
//– 1st stage——————————————
Z_Re_0[0]=x;
y=VectorDotProduct(5, &Z_Re_0[0], &IIR_coef0[0]);
y<<=IIR_coef0[5];
Z_Re_0[2]=Z_Re_0[1];  Z_Re_0[1]=Z_Re_0[0];
Z_Re_0[4]=Z_Re_0[3];  Z_Re_0[3]=y;

//– 2nd stage——————————————
Z_Re_1[0]=y;
y=VectorDotProduct(5, &Z_Re_1[0], &IIR_coef1[0]);
y<<=IIR_coef1[5];
Z_Re_1[2]=Z_Re_1[1];  Z_Re_1[1]=Z_Re_1[0];
Z_Re_1[4]=Z_Re_1[3];  Z_Re_1[3]=y;
//output:  y;
}

DSPライブラリ関数にはIIRフィルタもあるが,処理速度が遅かったので
VectorDotProduct 関数を使って自作してみた.
これはI chのみなので,もう一組IIRフィルタが必要となる.

伝達特性(設計値)は,以下のとおり
(横軸はナイキスト周波数50kHzで正規化)r09.jpg

 

3.複素係数FIRフィルタ(PSN)
サンプリング周波数とタップ数が違うだけで送信用と同じ.
今回128タップとしている(これが限界).

FIRの係数を求める際,AD変換の遅延を補正するよう考慮している.
具体的には,遅延をTとして Im側にのみ周波数特性にexp(- j2πf T) を掛けている.
 Source code,   Circuit diagram, and  Octave Script for filter design 

FIRフィルタ

前回AF PSNを複素係数のFIRフィルタで作成したが,その係数を変えれば任意の周波数特性を持ったフィルタが作れることはいうまでもなく,AF PSN はその一例にすぎない.

FIRフィルタの係数は,周波数特性を逆フーリエ変換すれば得られるので手間はかからない.とはいえ手計算できるものでもないので,AF PSN 作成の際に,係数を求めるために作ったツールをここにUPしておいた(Calc_Coeff_of_CPLXBPF.m).

これは,拡張子mが示すようにMATLAB,GNU Octave 上で動くスクリプトである.
GNU Octave はフリーウェアでこちらから入手でき,Windows の場合,octave-4.4.0-w64_1-installer.exe ならインストールは容易かと思う.

スクリプト内でパスバンドの周波数を書き換えて実行すれば,その特性を実現する係数を定義するヘッダファイルが自動生成される.
これをincludeしてコンパイルすれば,設定どおりのパスバンドを持ったBPFが実現できる.
複素係数フィルタであるが,実数部のみ使用すれば普通のフィルタと同じである.

 

さて,前回製作したAF PSNであるが,パスバンド内のリップルとパスバンド外の減衰特性が気になった.周波数特性を求めたところ下図のようになった.

Rect

理由は,窓関数を使用していなかった(=矩形窓)ためである.
そこで,フィルタ係数に窓関数を掛けてみた.
(窓関数はスクリプト内で指定できるようにしてある)

 

Hann 窓
han

Hamming 窓
hamming

Blackman 窓
blackman

Bartlett 窓
bartlett

使用する窓関数としては Hamming か Blackman になるだろう.
Blackman のほうが減衰特性がなだらかであるが,それでも十分急峻な減衰特性なのでこれがよいと思う.
(ヘッダファイルとCソースファイルを更新しているので,日付を確認の上ご利用願います)

音響ホーン

以前は40KHzのトランスデューサ(写真左)を使ってバットディテクターを製作していたが,
40KHz付近しか観測できない,という制約があった.
今回のバットディテクターでは,
広帯域で超音波を観測するためにMEMSマイク(写真右)を使っている.
ただ,トランスデューサは40KHz付近の感度は高く,
40KHzに限った感度の比較では,MEMSマイクは今一つな感じがする.

20180311_133045~2

写真を見ればわかるように,
MEMSマイクの音響ホールは直径0.5mmしかない.
トランスデューサの方は,内部の振動板らしきものは,直径8mmほどある.
開口面積がMEMSマイクの方が格段に小さいため,
感度が悪いのも無理はない.

そこで,音響ホーンを用いて開口面積を大きくし,感度の向上を試みた.

20180311_131230~2

3Dプリンタで作成した超音波用の音響ホーン.

定量的なデータはとっていないが,聞き比べた感じでは,
トランスデューサと同等以上の感度が得られているようだ.

バットディテクタ

知人からの相談がきっかけで,
新しい方式のバットディテクターを開発,試作した.

詳細はこちら

バットディテクターは,コウモリの出す超音波を可聴音に変換するもので,
主な方式として次の3種類のものが従来からある.

・ヘテロダイン式 (Heterodyne)
・フリークエンシーディビジョン式(Frequency Division:周波数分周式)
・タイムエキスパンション式(Time Expansion:時間軸延長式)
Wikiより.

これらの方式では,

・ヘテロダイン式
チューニング操作による探索が必須.周波数が大きく異なるものは同時観測できない.
・周波数分周式
レベルが最も高い信号しか観測できない.周波数以外の情報が失われる.
・時間軸延長式
リアルタイムで観測できない.

といった短所がある.

今回開発したのものは,
超音波領域の信号のスペクトルを周波数方向に圧縮し
全てを可聴音の領域に詰め込む方法.
「スペクトラム圧縮式」としておく.
この方式では,従来方式の上記欠点が改善される.
つまり,チューニング操作不要で,
周波数に関わらず同時に複数対象を
リアルタイムに観測できる.

sc01

信号処理方法としては,下記のように2種類考えられる.
今回は,下の方法で試作をしてみた.
20171212-2