VFO(6)

ディジタルVFOの場合,周波数ステップの切替えが必須かと思う.
ただ,実際操作してみるとステップ切替え操作はかなり煩わしいもので,なんとかしたいと思っていた.
切替え頻度を減らすにはパルス数の多いエンコーダを使えばよさそうだが,今一つスッキリ解決するような気がしない.それにエンコーダが高価.

そこで,特に目新しいものではないが回転速度を検出してそれに応じて連続的に周波数ステップを変化させるようにしてみた.ここに動画をUPしておく

今回試した方法は次のとおり.
ダイアル速度を vd,加速を始める速度しきい値を vth として,次式のように変数 L に積算していく.
(1) vd>vth のときのみ, L=L + (vd – vth);

また,速度 vdが 0 のときは,減速用の定数をRdec として,
(2) L=L – Rdec;   ただし,L<0 ならL=0;

次に,Lの値からRaccを加速率の定数として次式でステップ数を決める.

(3) ステップ=最小ステップ + Racc*L^n;

現状,n=2 としているが,他の定数も含め操作感に関わる値なので,いろいろと調整するといいと思う.また際限なくステップが大きくなるのを回避するためには,Lの上限を設定すればいい.

ダイアルの速度の検出は簡単で,エンコーダカウント値の絶対値が速度そのものなので,特に何か処理が必要なことはない.
公開しているソースで言えば,count という変数の絶対値が速度( vd=|count| ).
理由は,count はメインループの1回の処理時間当たりのカウント値なので,その絶対値はダイアルの速度に比例したものとなるため.

結局,メインループの処理1回で変化させる周波数Δfは,

(4)    Δf=count*( 最小ステップ + Racc*L^n );

動画は,
vth=2, Racc=0.002, Rdec=1.0, n=2, 最小ステップ=10[Hz]
で動作させたもの.

個人的には,ステップ切替えスイッチは無くてもいい,と思えるくらいの操作感になっていると思う.

VFO(5)

VFOの回路図とArduino Sketch はこちらに公開しておいた.(動画
画像表示の際アンチエイリアス処理を施しているので,まずその違いを以下に.

アンチエイリアス処理なし

アンチなし.jpg

アンチエイリアス処理あり

20190212_234133.jpg

(数字のフォントが違うのはアンチエイリアス処理とは関係ありません…)

この違いが重要かどうかは人それぞれかと思うが,個人的には上のアンチエイリアス処理なしの表示だと気分がよくない.

次に,LCDとOLEDの比較を.

まず,LCD

20190212_220612.jpg

20190212_220500.jpg

入手できるほとんどのLCDは視野角が広くなく,見るべき方向が規定されている.
このLCDは向かって右から見ると非常にきれいだが,左からみると線は欠けるし色合いもおかしい.
アンチエイリアス処理による微妙な輝度を再現できていない感じ.

たぶん携帯電話用のLCDだと思うので,縦において少し下方から見るように作られているのだと思う.実際ほとんどのLCDのデータシートには,View angle : 6 o’clock と表記がある.

OLEDの場合.

20190212_224237.jpg

20190212_224229.jpg

当然ながら,どの角度から見ても見え方に変化はなくきれい.

OLEDが100%よさそうだが欠点もある.

20190209_021913.jpg

明るい色のベタはむらが出るし(写真ではわかりにくいが.縞が見えるのはスキャンによるもの),ドライブ電流が足りなくなるのか暗くなる.
「一部だけ白」などはきれいだか,「全面白」とかはあまりよくない.

結論としては,暗いバックグラウンド色で使うならOLED.
明るいバックグラウンド色にするなら見る角度限定でLCDか…

VFO(4)

LCDへの表示がうまくいったので,次はOLED(NHD-1.69-160128UGC3) に表示させてみる.
これのコントローラチップは,SEPS525
16bitごとにCSの区切りが必要なのかどうか読み切れなったが,なんとなく「当然必要でしょ」という雰囲気が感じられたので,LCDのときのようにはいかないかも… と思いながら,とりあえず同じ転送プログラムを試してみた.
やはりNG…
spi.write16() を使って1ピクセルずつ送るとOKだったので,16bitごとにCSの区切りが必要のようだ.
そこで転送プログラム以下のようにしてみた.

s2.png

ブロックサイズを16にしてやることで,16bitごとにCSがネゲートされうまくいった.

20190212_234133.jpg
しかし,CSが頻繁にネゲートされるのでその時間(1回あたり600ns程度)が加わり,転送時間が25ms程度になってしまった.
これにダイアルイメージ描画時間35msとあわせて,更新レートはおよそ60msとなった.
これくらいになると動きのスムーズさがいま一つと感じるのは否めない.
RX621のシステムでは8bitパラレル転送+描画時間20msで更新レートが約30ms程度だったので,それに比べるとかなり動きが悪く見える.

何とかしたいところだが,これ以上プログラムの最適化で何とかできるようにも思えないので,デュアルコアを活用し描画処理と転送を別のコアで行うことで速度UPを試みる.

こちらのサイトを参考にさせていただき,メインのLOOPとは別のコアで動作するもう一つのタスクを作った.

setup()内で,

xTaskCreatePinnedToCore(task0, “Task0”, 4096, NULL, 1, NULL, 0);

として,次の関数を用意すればいいようだ.

void task0(void* arg)
{
while (1)
{
//SPI転送処理
delay(1);
}
}

delay(1) がないとシステムリセットが繰り返し発生した.
よくわかっていないが,おそらくOSに処理を返す必要があるからだろうと推測.
また,同じディレイ時間にも関わらず delayMicroseconds(1000) ではNGだった.

とにかく,これでloop() とtask0() が別コアに割り当てられ同時に動く(と思う).
あとは,この2つの処理間でのデータの同期に気を付ければいい.

というわけで,
一時はあきらめて,IOピンがまだ余っているのでOLEDはパラレルでいこうか…,などと考えたが,OLEDでもSPIで更新レートを50ms以下になんとかすることができた.

もっと簡単にRX621からESP32に移行できると思っていたが,思いの外苦労してしまった.
とは言え,初めてESP32を使ったのにもかかわらず,短時間でそれなりのものが組めたのは,いろんな方がネットにUPしてくれている情報のおかげなのは間違いない.

感謝の意味を込めて今回作成したソース(VFOsys)をこちらに公開しておく(無保証,サポートなしで).
エンコーダを回せば,ダイアルが動き(動画)その周波数が出力されるだけのものなので,そこからはこのソースをベースに各々機能を追加していただければと思う.

とにかく,ようやくシステムがうまく動き出したので,次はLCDとOLEDの比較をしてみよう.

VFO(3)

RX621で開発を進めていたところESP32が気になってきて調べてみると,
さらに安価で動作クロックも速く,しかもデュアルコア…
これは乗り換えるしかない,ということで  ESP32-DevKitC  を入手.20190206_125309~2.jpg
Arduino環境で開発できるようで,こちらを参考にさせていただきセットアップ.

ESP32のIO数があまり多くないので,ディスプレイはSPIで制御することにする.
幸い,OLED(NHD-1.69-160128UGC3) は,シリアル/パラレルどちらの接続もできる.
同じ解像度(160 x 128)のシリアル接続のLCDも用意して比較することにした.

20190213_024447.jpg

回路は下記のとおり.
LCDとOLEDは排他利用となる.Si5351は秋月電子のモジュール.

VFO.PNG

20190212_233108.jpg 20190212_233146.jpg

ディスプレイのインターフェース信号の配置が気持ち悪いが,ESP32内蔵のSPIを使うには
こうなってしまうようだ.
任意のピンでSPIができるようだが,その場合ライブラリによるソフトウェアSPIになり,転送速度がかなり遅くなるらしい.
以前,ダイアル表示のカウンタを作ったとき経験だが,ダイアルイメージの更新レートがおおよそ50ms以上になってくるとダイアルの動きがスムーズに見えなくなってくる感じだったので,これ以下にはしたい.

SPIのレジスタを直接操作しないと無理だろうなと思い,いろいろ調べてみると,
こちらのサイトに手掛かりがあり参考になった.
ESP32のリファレンスマニュアルも読んでみると,SPIには32bit x 16 (512bit)のバッファがあって,そこにデータを貯めておき(例では,半分の256bit),これを1ブロックとして一機に送出する方法らしい.これを必要回数繰り返す.
今回は,16bit/pixelx128x160=327680 bit 転送しないといけないので,
バッファをフルに使えば,327680/512=640回 となる.

以下のようなプログラム(抜粋)を組んで動作を確認した.
配列GRAM65k[][](16bitカラーのイメージデータ)をすべてディスプレイに転送する.

s1.png

オシロで波形を見てみると,1ブロック転送中はCSはアサートされたままになるようだ.
16bitごとにCSを区切らないといけないのでは?と思ったが,どうやらST7735やILI93xxといったディスプレイコントローラはその必要はないようだ.

肝心の転送時間だが,SPIクロック周波数が27MHzでおよそ12ms だった.
クロック周波数がディスプレイコントローラの動作範囲を超えているが,
「実力的にOK」との情報が多数あったのでそれに期待.

結果としては,上手く動作した.
20190212_220612.jpg

ただ,転送時間は12msだがダイアルイメージの描画処理に35msほどかかっている.
RX621のときは20ms以下だったのでかなり遅くなってしまったのは予想外だった.
CPUクロックが2倍以上なのにどういうことだろう?
当然ながら,速くなることを期待してたのでかなりテンションが下がる…
バックグラウンドで動いているfreeRTOSのせいかもしれないし,
デュアルコアも活かせてないし仕方ないか…

でもまあ,CPU自体RXよりかなり安価でRAMが520KBもあるのは捨てがたい.
現状,更新レートは目標通り50ms以下(12ms+35ms)にはなっていて,視覚的にもあまり違和感はないのでこのまま進めることにしよう.

次は,OLEDで動作確認しないと.

VFO(2)

アナログダイアル表示のVFOシステムがようやく具体的になってきた.
以前つくったカウンタのハードはほぼそのままで,ファームだけを新しく作ろうと思っていたが,コスト下げるためにハードも新しくすることにする.

CPUにPIC32MZを使っていたが,高いのでRX621にする.
基板を起こすまでは秋月のボードでデバッグできるので,その辺りも選択理由.
ただし,RAMが96kBなのでカラーディスプレイの解像度を,160x128に落とさざるを得ない.ただ,それもコストダウンにつながるのでいいかと…
160x128だと画面が1.7~1.8インチ.小さすぎないか少々気になるが,機械のパネルに配置するには,むしろこれくらいの大きさがちょうといいかもしれない.

ところが,LCDを探していると同じ解像度と大きさのカラーOLEDが見つかった.

NHD-1.69-160128UGC3

3000円を超えるのでどうしようか迷ったが,一度使ってみることにした.
(コストダウンしようとしているのに本末転倒…)
LCDは,見る角度で色合いが変わったり,見にくくなるのが非常に気になっていたため
それが解消されるなら,ありかなと思う.

とりあえず表示だけさせて雰囲気を確認.

oled1.jpg
アンチエイリアス処理をしているので輪郭が少々ぼやけるが,画面が1.7インチと小さいので,目視ではあまり気にならない.
この解像度(160x128)では,アンチエイリアス処理をしないと微妙な角度の短い線などは,見るに堪えない形状になる.

こんな角度でも色合いや見やすさは変わらない.20190122_125705_Burst01.jpg20190122_125736.jpg

よさそうなので,もう少しファームを作り込んでみた.

oled5.jpg

あとは,Si5351AからLo 信号と,必要に応じてCar信号 を出すようにするのと,
カウンタと同様,周波数オフセット値の設定など自由にできるようにする機能を
追加していく.

スペアナ制御ツール

先日,アンリツのスペアナMS2661Aを中古で入手した.
9kHz~3GHzの帯域で,RBWの最小は30Hz(オプション付)と
性能的には納得して購入したが,測定データの保存方法で悩んでしまった.

20181010_061554

メモリインターフェースオプションが付いていて,
PCカードメモリにデータを保存できるようだが,
今時PCカードメモリなど入手困難なので,SD用PCカードアダプタを使ってみた.

結果は残念ながら,”メモリタイプが異なる”とのメッセージが出てNGだった.
このスペアナが作られた時代にはSDは無かったのかもしれない.

仕方がないので,GPIBかRS232Cポート経由で,
データをPCに転送して表示・保存することにした.
ただ,プログラムを作る必要があるので少々面倒だ.
(なので,できればメモリインターフェースを使いたかった)

測定器といえばGPIBというところだが,
PC側にもGPIBインターフェースが必要になり,面倒なのでRS232Cを使うことにした.
ただ,通信速度が9600bps と,今時としてはかなり遅い感じがするのは否めない.

簡単なプログラムを作って試したところ,うまい具合にデータの取得・表示ができた.

42641369_1386471288151860_1717727983411658752_n

42727699_1386471231485199_1732282193058725888_n

必要な人は他にはおそらくいないと思うが,Windows10で動作するMS2661A用の
データキャプチャソフトをこちらに置いておく (  MS2661A.exe ) 

センター,スパン,スタート,ストップ周波数に関しては,
このソフトからリモートコントロールできる.
通信速度が遅いので,データの取得には  3, 4秒かかる.
これが速ければ,リアルタイムでPCに波形表示ができるのだが・・・

FT817ND   433MHz とその第2高調波
FT817_430M

433MHz拡大
FT817_433.000MHz

 

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ソースファイルを更新しているので,日付を確認の上ご利用願います)