PLL(2)

この間の日曜日は決戦もとえ選挙の日だった。

昼間行くと暑くてかなわんので、朝一番の涼しい時に行ったよ。一番乗りかと思ったら、 五番乗りぐらいだった。7時前、珍しい光景に出くわした。

投票箱の蓋が開けられ、さーさーお立会い、何も入っていませんねと、担当者が、 オイラーとか投票に来た人達に確認を求めた。続いて、立会い人(何となく、知ってる 人だと思ったら、地区の顔役だった)にも、同意を求めた。

そして、南京錠2個で、蓋をロック。この儀式が完了して、7時丁度から、投函開始。 長年生きてるけど、こういう場面に遭遇したのは初めてだな。

この儀式は法律で決まっていて、零票確認(れいひょうかくにん)またはゼロ票確認(ぜろひょう-) と言うそうな。マニアが居て一番乗り競争が有るそうだ。 次回は、正式な一番乗りを狙ってみようかな。

投票箱って、よく外国だと透明なやつとかがあるけど、日本はジュラルミンのやつっぽい。 ちゃんと法律で決まってるそうだ。ついでに幾らぐらいか調べてみたら、いろいろな 会社が作ってるのね。アルミのむかいだ とかが、入札箱もやってる。目安箱はどうかな? 目安箱って言わずに、現代なら、 ご意見箱って言え。こりゃま、失礼しました。

立会い人って、投票会場をじっと監視してるけど、つまんないだろうな。まさか13時間の 勤務は無いだろうけど(飛行機なら余裕でヨーロッパ各地に行ける時間です)、尻痛く なりませんかね。

パイプ椅子にじっと座らせられて! エコノミー症候群で、よれよれじいさんが生まれる 可能性だって有るだろうに。途中で交代するんだろな、3交代ぐらい。年寄りは気が短いから、 5交代ぐらいのローテを組まないと、発狂したりして。

選管な人が立会人を指名するんですかね? それとも、地域の顔役に人選を依頼して、 よきに計らってもらっているんですかね? 今度、顔役に会ったら聞いてみよう。

帰り道、いつもと違った道を歩いてみたら、一家に一台じゃなくて、一人一台が標準の この地方で、4台止まっている家があった。軽トラから始まってワゴン車まで。 泥棒でなくても、家族構成と職業が推測出来ますなあ。

そこまではいいんだけど、、 全車両のナンバープレートが、8番に統一されてた。 これは、入札で手に入れた番号かな?

末広がりの八を選ぶって、凝った一家だ事。おじいちゃんの趣味と言うか家訓でも あるのか。

PLLの評価ボード

前回は、OpenBSDでもngspiceって事で、入れてみた。けど、xspiceの部分が完全に サポートされていないようで、そんなデバイス無いぞエラーを喰らう事があった。

Circuit: * test frequency-phase detector similar to 12040

Error on line 12 : abridgev1 [1 2 3] [d_sig1 d_sig2 d_d0] adc_vbuf
   MIF-ERROR - unable to find definition of model adc_vbuf
Warning: Model issue on line 13 : .model adc_vbuf adc_bridge(in_low=    1.6499999999999999 ...
  Unknown model type adc_bridge - ignored
    :

しょうがないので、ウブでやる。


.subckt f-p-det d_R d_V d_U d_U_ d_D d_D_

aa1 [d_U d_D] d_rset and1
.model and1 d_and(rise_delay = 1e-10 fall_delay = 0.1e-9
+ input_load = 0.5e-12)

ad1 d_d1 d_R d_d0 d_rset d_U d_U_ flop1
ad2 d_d1 d_V d_d0 d_rset d_D d_D_ flop1
.model flop1 d_dff(clk_delay = 1.0e-10 set_delay = 1.0e-10
+ reset_delay = 1.0e-10 ic = 2 rise_delay = 1.0e-10
+ fall_delay = 1e-10)

.ends f-p-det

前回取り上げた、周波数・位相検出器。読み解いてみるか。

aa1は、2入力のANDゲート。rise_delay ってのは、Tplhの事だな。fall_delayはTphlか。 そして、input_loadは、入力寄生容量とでも言うのかな。

ad1(2)は、セット・リセット端子付きのDタイプFF。回路構成は、DFFの出力のANDを 取って、リセット端子へ入力。位相信号は、クロックとして入力。そうすると、D入力 端子は、d_d1 ってなってるけど、これはロジックレベルの1を意味するんだな。 その伝で行くと、セット端子はロジックレベル0にして、機能を殺してる。

ああ、殺すとか物騒な言葉は、業界の隠語? 無効にするって意味ね。言葉使いで お里が知れる。サッカー選手で有名だったベッカムさんも、女房に、そんなロンドンの 下町言葉、下品だから使わないでって、常に矯正されてたとか。

次は、この周波数・位相検出器孫ボードの、評価ボードです。test-f-p-det.cir

.param vcc=3.3
.global d_d0 d_d1

*PULSE(V1 V2 TD TR TF PW PER)
v1 1 0 dc 0 pulse(0 'vcc' 10n 1n 1n 10n 20n)
v2 2 0 dc 0 pulse(0 'vcc' 8n 1n 1n 10n 20n)

*digital zero
v3 3 0 dc 0
abridgev1 [1 2 3] [d_sig1 d_sig2 d_d0] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 'vcc*0.5' in_high = 'vcc*0.5')
*digital one
ainv1 d_d0 d_d1 invd1
.model invd1 d_inverter(rise_delay = 1e-10 fall_delay = 1e-10)

Xfpdet d_sig1 d_sig2 d_U d_Un d_D d_Dn  f-p-det

*.include f-p-det-sub.cir
.include f-p-det-d-sub.cir

d_d0とかは、グローバルに使うよ宣言してるな。

位相器に与える信号源をv1,v2って事で用意してます。直流オフセット0v、パルス振幅、0-3.3V。 20nS周期のヂューティー50%。位相差が2nSあるって事だな。

次はv3で0Vの電圧を発生。以上、3種の信号源は、アナログの世界。これをadc_bridgeを 使って、デジタル世界にレベル変換します。スレッショルドは、Vccの半値って事ですね。

次にデジタル系のインバータをかませて、デジタル世界のロジック1をつくり出しています。

そこまで用意出来たら、メインボード側の孫ボード受けを用意し、includeで孫ボードを 差込ます。

* d to a for plotting
abridge-w1 [d_sig1 d_sig2 d_U d_D] [s1 s2 u1 d1] dac1
.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0.5
+ input_load = 5.0e-12 t_rise = 1e-10
+ t_fall = 1e-10)

.control
set xtrtol=2
tran 0.1n 1000n
plot s1 s2+1.2 u1+2.4 d1+3.6 xlimit 140n 200n
.endc

次のdac_bridgeは、アナログデータしか表示出来ない画面に、無理してデジタルデータを 表示するための苦肉の策。デジタルレベルをアナログレベルに変換。ロジックの1,0が、 アナログ電圧1V、0Vに変換される。

こういう仕組みを用意しておいて、トランジェント解析。結果表示は、オフセット電圧を 変えて、マルチデータを表示される。どうもご苦労さんですとしか、言い様がないな。

なお、set xtrtolは、xspiceのシュミレーションスピードを変えるもので、通常は2に 設定するらしい。

Windowsに入れたngspiceで試してみると adc_bridgeが見つからないという、OpenBSDと 同じエラーを吐いて、実行出来なかった。ちゃんと手が入っていないんだな。残念至極。

めげずに、次のブロック行ってみよー。次は、loop-filter.cir。

.subckt loopfe d_U d_D vout

.param loadcur=5m
.param initcond=2.5

v1 vtop 0 1
v2 vbot 0 -1

abridge-f1 [d_U d_D] [u1 d1] dac1
.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0.5
+ input_load = 5.0e-12 t_rise = 1e-10
+ t_fall = 1e-10)

*top switched current source
Gtop vtop vout cur='loadcur*v(u1)'
*bottom switched current source
Gbot vout vbot cur='loadcur*v(d1)'

*passive filter elements
.ic v(vout)='initcond' v(c1)='initcond'
R2 vout c1 200
C1 c1 0 5n
C2 vout 0 5n
Rshunt vout 0 10000k

.ends

位相検出器からの2つの出力を平滑するって機能を実現。5mAの定電流源を2つ用意し、 それを±1Vの電源に接続。一つはコンデンサ群を充電、もう片方は放電に割り当て。

どちらがonになるかは、入力信号によって決定。on/offと言うより、5mA/0mAって リアルタイムに設定を切り替えるって使い方だな。なかなか参考になるな。

コンデンサ群は、5000pFが電流源に もろに取り付け。もう一つの5000pFは、200オームのダンピング抵抗をかませたもの。 これで、フィルターの特性をなだらかにしてる。

Rshuntは、定電流源が、直流的に閉ループを構成するようにしてる。これを入れて おかないと、シュミレーション時にエラーとなった。(以前、経験した事が、生きて いますな)

VCOモジュール

PLLを完成させる為に残るのは、VCOモジュール。 READMEによると、2種ある

** voltage controlled oscillator:
vco_sub.cir
   7 stage ring oscillator with gain cells, CMOS devices
or
vco_sub_new.cir
   vco made from code model d_osc, cntl_array/freq_array data
   are gained by running test-vco.cir with vco_sub.cir

PLLには、newの方が使われているので、先に見ておく。何といっても短いからね。

***** XSPICE digital controlled oscillator d_osc as vco ***************
* 150 MHz to 900 MHz
* name: d_osc_vco
* aout analog out
* dout digital out
* cont control voltage
* dd supply voltage

以上説明終わり、ってな具合に簡潔なコメントが入っている。コードを書く時は こういうコメントが期待されますなあ。vcoの評価ボードが用意されてて、それを 実行してみると分かるんだけど、制御電圧contによって発振する周波数が非線形 なってる。(どうだ、凄いだろうって見せびらかしたかっただけ?)

どうやって非線形な制御をやってるかが、観賞ポイントになります。

.subckt d_osc_vco aout dout cont dd
* curve fitting to ro_vco 'measured' data
Bfit fitted 0 v = (-58256685.71*v(cont)*v(cont) - 186386142.9*v(cont) + 988722980)/10.

非線形の種はこれ。部品名がBで始まるものは、非線形依存電源です。設定式が v = に なってるので、右辺の2次式に相当する電圧が発生されます。

* linear interpolation, input data from measured ro vco
a5 cont dout var_clock
.model var_clock d_osc(cntl_array = [0.5 1 1.5 2 2.5]
+ freq_array = [8.790820e+008 7.472197e+008 5.799500e+008 3.772727e+008 1.611650e+008]
+ duty_cycle = 0.5 init_phase = 180.0
+ rise_delay = 1e-10 fall_delay=1e-10)

そして、これが心臓部の発振器。指定された電圧に対する周波数が発生されます。 肝心の電圧に対する周波数の対応は、cntl_array と freq_arrayに要点を書いて おきます。指定されて点以外は、内部で直線補間が勝手に行われます。

これを読み解くと、0.5V入力で879MHz、2.5V入力で161MHzを発振するって事ですね。後は、デジタル な波形をアナログに変換する部分が付いているだけ。余り、面白みがありませんでした。

もう一つのvcoは、cmos回路をリングにした、お馴染みの発振器でした。MOSFETを 構成するパラメータがしっかり定義されてて、一瞬MOSを設計してる気分に浸れます。

このMOSで作ったのがオリジナル。d_oscを使ったのがnewバージョン。だから、特性を 旧バージョンに合わせるために、非線形な計算をやってるのね。互換性維持って大事。 どこかのソフトもちゃんと見習わないと、世代ギャップを生じるぞ。

xspiceが使えるようになって、石だけの世界から脱却。d_oscみたいに機能豊富なSSIと 言うかMSIと言うかLSIが使えるようになったのね。このICを割って、どういう風に なってるか調べてみるのも一興かと。

そのnewバージョンで採用された d_osc機能。こいつが有れば、簡単に、FM東京 とかが 出来るな。勿論、ゲリラ的に、コミュニティーFMでもいいけど。

設計はこうする。変調電圧を作り出すために、オペアンプを一つ使う。回路を、2入力の 加算器構成にし、一つはキャリアー周波数を決定するDC電圧。もう一方の入力は、非変調波(音声) 入力。出力をd_oscに与えれば、あーら不思議、FM変調器になりますよ。

d_oscの設定は、cntl_array = [1.0 5.0] freq_array = [76.0meg 90.0meg] こんな設定。 1V入力で76MHzを発振、5V入力で90MHzを発振ってな具合。これだと、最低周波数で波を 出した場合、変調がかかると周波数偏移で帯域が拡がるからオフバンドしちゃうな。 まあ、昔7Mでアンカバーやってた人が、何言ってるって言われそう。

なお、オペアンプの出力って、0V近辺はリニアリティーが悪いってのが相場ですから、 直線性のよいエリアを使ってます。そして、加算器のゲインは、周波数偏移を考慮して 決定する事は言うまでもない。オペアンプのドリフトは即、キャリアー周波数の ドリフトにつながるので、低ドリフトのアンプを使う事。

最近は、バリキャップが入手難らしい。何故かと考えるに、その分野がPLLに置き換わって きて、需要が減ってしまったからだろうね。

次は、いよいよ今まで見てきたモジュールを組み合わせて、PLLに仕立て上げます。

PLLするぞ

メイン基盤は、pll-xspice.cirだ。

* pll circuit using xspice code models
* output frequency 400 MHz
* locked to a 1 or 10 MHz reference

.param vcc=3.3
.param divisor=40
.param fref=10e6
.csparam simtime=25u

.global d_d0 d_d1

vdd dd 0 dc 'vcc'
*vco cont 0 dc 1.9

*PULSE(V1 V2 TD TR TF PW PER)
* reference frequency selected by param fref
* PULSE(V1 V2 TD TR TF PW PER)
vref ref 0 dc 0 pulse(0 'vcc' 10n 1n 1n  '1/fref/2' '1/fref')
abridgeref [ref] [d_ref] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 0.5 in_high = 0.5)

冒頭部分。大事なパラメータの設定と基準周波数発振器の設定。この部分は、JJY(今はそんな波出てるのかな? 昔は、これだけが頼りだったよ) か、武蔵小金井にある、日本時間製造所から分けて貰ってきましょう。

たまに、CMOS用電池がへたったFreeBSDの入っているノーパソを立ち上げるんだけど、 時刻が飛んじゃってる。そんな時は、焦らず騒がず、黙って

ntpdate ntp.nict.jp

して、時刻を貰ってくるものなあ。

現代風なら、カーナビとかGPS付きスマホを分解して、空から降ってくる基準波を 引き出して使いましょう。あれ? 日本時間製造所もGPSも時刻を返すんじゃなかったっけ? 果たして、基準周波数なんて貰えるのか >教えて、エライ人。

基準波が10MHz、分周比が40との事ですから、VCOは、10Mhz X 40 = 400Mhz に、ひたすら 追従しようと、けなげに頑張る訳です。

.include vco_sub_new.cir
xvco buf d_digout cont dd d_osc_vco
 
* digital divider
adiv1 d_digout d_divout divider
.model divider d_fdiv(div_factor = 'divisor' high_cycles = 'divisor/2'
+ i_count = 4 rise_delay = 1e-10
+ fall_delay = 1e-10)

そのVCOがソケットに差し込まれ、次は、分周器が出てきました。分周比は、ここでは 固定の40を代入してます。これを、パソコン等から設定出来るようにすると、憧れの DDSチューニングのトランシーバーが実現出来る訳です。(誰も、10MHzステップで しか設定出来ない発振器なんて興味無いよ)

* frequency phase detector
.include f-p-det-d-sub.cir
Xfpdet d_divout d_ref d_U d_Un d_D d_Dn  f-p-det

* loop filters
*2nd or 3rd order, transistors as switches
.include loop-filter-2.cir
Xlf d_Un d_D cont loopf

残りの重要モジュールも装着されました。これで、PLL本体としては組み立て終了です。 (アナログーデジタル変換部分は、面白みもないので省略)

次からは、実運用のための手順書が書かれています。

.control
save cont s1 s2 u1n d1 v.xlf.vdd#branch; to save memory
iplot cont
tran 0.1n $&simtime uic
rusage
plot cont s1 s2+1.2 u1n+2.4 d1+3.6 xlimit 4u 5u
plot v.xlf.vdd#branch xlimit 4u 5u ylimit -8m 2m
*plot cont
.endc

保存すべきデータを決め、シュミレーションには長い時間がかかるので、ユーザーが 飽きないように結果のvcoの制御電圧contのグラフを表示しつつシュミレーションを進行。

終ったら、contの電圧安定具合を表示。周波数・位相検出器の入出力を表示、もう一枚 v.xlf.vddってのが表示される。(これは、今回のシュミレーションには、関係無さそう)

注目は、contが安定するまでの時間。すなわちループがロックされるに要する時間。 大体13uSぐらいで安定してる。最終結果は、下記のようになった。

ngspice 2 -> print cont
   :
401016  2.499994e-05    1.943966e+00
401017  2.499998e-05    1.943966e+00
401018  2.500000e-05    1.943966e+00

位相ジッタを生じさせるような、ばらつきも見えない。

上のPLLを使ったんでは、435MHzの呼び出しが出来ない。改造しよう。まずは、基準周波数を、 1MHzに変更。これを435回数えると、vcoの出力は435MHzに安定するはず。

やってみたら、位相ジッターが出てきたぞ。ループフィルターの時定数を変更すればいいのか。 要は、平滑回路だから、もっと時定数を大きくして平滑度を上げる。そうすると、 必然的に、安定するまでの時間がかかるようになる。これは、トレードオフの関係で、 旨く両立させる方法って無いんでしょ。>自動制御の偉い先生。

OpenBSD用ngspiceを作り直し、瓢箪から駒

上でやったOpenBSDのportsから入れたngspiceなんだけど、何となくxspiceが有効になって いないっぽい。その証拠は、config.logの冒頭付近にあった。そんな訳で、もう一度 configのやり直し

 ./configure --prefix=/usr/local --sysconfdir=/etc --mandir=/usr/local/man  \
 --infodir=/usr/local/info --localstatedir=/var --disable-silent-rules \
 --disable-gtk-doc --with-x --enable-xspice --disable-debug \
 --with-readline=yes --disable-openmp

そして、再インストールした。けど、同様に、xspiceがイネーブルになってないっぽい、 エラーが出てくる。

これはどうした事? 作業dirの上の階層に、fake-i386ってのが出来ていて、そこに パッケージングの元を集積するっぽい。中を覗いたら、それらしいのが出来てた。

[ob: ngspice]$ pwd
/usr/ports/pobj/ngspice-26/fake-i386/usr/local/lib/ngspice
[ob: ngspice]$ ls
analog.cm*      digital.cm*     spice2poly.cm*  xtradev.cm*     xtraevt.cm*

でも、これに相当するものが、実機ではインストールされていない。portsのパッケージング リストにも登場しない。おまえが勝手に入れたものなんて知るかいってOpenBSDの態度。

CONFIGURE_ARGS=         --enable-xspice \
                        --with-readline=yes

Makefileにちゃんとconfigオプションを指定しておくと、派生品もパッキングの 対象になるのかな。それとも、pkg/PLISTに手動で登録しておくのかな。全ての謎を 解く鍵は、includeされてる、bsd.port.mk に書いてあるはずだから、読んでミレ。

ならば、手動で入れてやるー。そしたら、リナちゃんと同じように動いた。

ほなら、OpenBSDで作った*.cmファイルをWindowsへ持って行ったら動くんじゃねぇ? やろうとしたら、先客で同じ名前のものが用意されてた。で、使い方の案内を見たら、 システムワイドな設定をspinitにしておけとな。面倒なんで、home-dirに、.spiceiitを 作り、そこに

 codemodel C:/app/spice/lib/ngspice/spice2poly.cm
 codemodel C:/app/spice/lib/ngspice/analog.cm
 codemodel C:/app/spice/lib/ngspice/digital.cm
 codemodel C:/app/spice/lib/ngspice/xtradev.cm
 codemodel C:/app/spice/lib/ngspice/xtraevt.cm
*set units=degrees
alias so source
set nomoremode
set width=132
set height=999999999

こんな設定を書いたら、Windowsでもxspice機能が使えるようになった。正式には、 scripts/spinitが入っている所をSPICE_LIB_DIRに設定する。Winの場合は、これの デフォがC:/Spice/share らしい。

ngspiceのパッケージャの人も、糞dirを嫌って、Cドライブ直下がSpiceの居場所だよ と、初期地を決めている。みんな、あそこの場所は縁起が悪い、トラブルを招くって 知ってて、避けているんだね。 あの糞dirにぶち込む輩は、根っからのWindows屋しか居ない。

なお、.spiceinitって頭にドットが付くファイルは、M$の嫌がらせにより作れない。 天下のRMSがemacs経由だと作れるように、M$の嫌がらせを跳ね除けてくれている。 大いに利用しよう。

また、spiceのインストール先も、間にスペースが入った、糞dir名な所は避けて、C:/appの 下にしてる。生活の知恵発動ですよ。

etc

友人が、パソコンを新調したいって事で、PCデポへ偵察に行ったらしい。 そしたら、ゲームコーナーが出来ていて、ネット対戦してる人がいたとか。 ソフトの進化にびっくりしたと言っていた。

ゲームと言えば、龍角散じゃなくて、 はじめてのUnityかな。どんなものか、 触ってみるか。