2018年2月21日水曜日

オフセットパラボラ


 自分自身の妨害が結構大きそうな気がするので、オフセットパラボラにしてみました。
 焦点距離10cm、開口20cmで、この数値だけを見ると前回と同様です。



 画像は障害物の有無で撮った状態です。以前のピクチャとは設置場所・画角が異なります。

 感覚的には、前回とそんなに変わらないかなぁ、という気がします。比較したわけじゃないですが。

 下の画像、赤矢印が本棚、緑矢印がパイプベッドのフレームかな、という気がします。本棚までの距離は1.5mですが、1.8m付近に見えています。焦点距離が10cmなので、パラボラで20cm分距離が伸びますから、実際には1.7mの距離に見えるはずです。ということは、大体そんなもんかな、という距離感です。

 本棚からフレームまでの距離はおよそ20cmで、十分に見分けられる距離なので、方位分解能は15cm/1.5m程度、約6度程度かな、という感じです。


***

 エコー反射の長さは10cmくらいでしょうか。この距離は0.6msecくらいに相当します。
 パルス条件はパルス幅(PW)10msec/ΔF4kHzなので、パルス圧縮比(PCR)40になります。ということで、圧縮後のパルス幅は0.25msecになります。が、実際は送受信機の特性が悪いので、もっと幅の広いパルス幅になるはずです。
 エコー0.6msecというのは、0.25msecの2.4倍ですから、多少特性が悪化したとすれば、これくらいの量になるはずです。

 距離分解能を改善するには、PCRを大きくすれば、圧縮後のパルス幅が短くなります。PCRはPWとΔFの積なので、PWかΔFを大きくすればPCRが大きくなります。とはいえ、PWを2倍にすると、PCRも2倍になりますが、元のパルス幅が2倍ですから、最終的に得られるエコー幅に変化はありません。
 ということで、距離分解能を改善するにはΔFを大きくする、という選択肢になります。一方で、送信機や受信機の帯域幅の問題が有るので、無闇矢鱈とΔFを大きくすればいい、という事でもありません。
 超音波の場合、ΔFは3-5kHz程度かな、と思います。ΔFの制限がある以上、圧縮後のパルス幅を大きく改善することはできません。リニアチャープを使った場合、距離分解能は10cm程度が限界のようです。パルス圧縮を行わない場合、例えば0.5msecの超音波パルスを使う場合は距離分解能10cm程度で、パルス圧縮を使っても使わなくても得られる距離分解能に変わりはありません。ただし、パルス圧縮を使った場合はより遠くの目標を検出できる、という利点があります。



 この図はパルス幅を変えて撮影したものです。2msecと10msec、25msecの3条件です。以前の画像はすべて10msecで撮影されています。
 基本的に、距離分解能に違いは見られません。ただし、方位分解能はパルス幅が長いほうが分解能が高いような傾向が見られる気がします。

 また、画像化の際はAGCで信号の強さを正規化していますが、実際にはパルス幅が長い方が大幅に信号が強くなります。
 エコーの強さは送信出力と送信時間の積に比例します。一方、目標が大きいほどエコーが大きく、小さいほどエコーが小さくなります。PWを大きくした場合、エコー幅に影響はありませんが、送信エネルギーが増える分、小さい目標からのエコーも強く受信できるようになります。


 ということで、パルス圧縮を使う場合、その他の条件を無視すれば、できるだけ長い時間、できるだけ広い周波数帯で送信するほど高性能になります。また、送信周波数を広げるには、中心周波が高いほど有利になります。


 なお、これはFMチャープの話で、符号拡散を使った場合はまた別の話になります。
 あと、いろいろ資料を見てるとなんとなく解釈が怪しい気がしてきたので、大幅に間違っている可能性もあります。あんまり信用しないよーに。

2018年2月20日火曜日

パラボラ


 AIM-120の時に作ったスクリプトを流用して、放物線リフレクタを厚紙で作ってみました。補強が一切入ってないので、自重でかなりたわみます。とりあえず下にスペーサーをおいて、極端に沈み込まないようにしています。




緑はリフレクタなし、紺はリフレクタありのときのスコープです。おおよそ同じ範囲を見ています。

 リフレクタ無しでは1つの目標が広い範囲に広がっていますが、リフレクタ有りでは狭い範囲に集中しています。正直、たかが20cmの放物線リフレクタでここまで効果があるとは思っていませんでした。



 ついでに、物体の有無のサンプルです。上は物体あり、下は物体なしで、赤丸の部分にエコーの違いが見られます。



 とりあえず、しばらくは地味なバグ取りとか細かい修正が続きそうです。
 何に使うか決めてないので、飽きたらその時点でやめると思います。元々パルス圧縮を試してみたい、という理由でしたから、すでにある程度の目標は達成しているわけですが。

PPI


 超音波距離計から寄り道して、PWM Outを追加してアジマススキャンをできるようにしました。PC側でそれを表示するソフトウェアを作って、PPIスコープっぽい表示にしてみました。イメージはパトリオットミサイルのレーダースクリーンです。ま、だいぶ違いますが。

 上の図はおよそ4mのレンジで表示しています。なんとなく部屋の配置と同じように見える気がしますが、実際の距離と3割くらい違うので、何か間違ってると思います。

 開口の指向性がかなり鈍いので、小さい目標でもかなり広い範囲に写り込んでしまっています。


 Aスコープ風、Bスコープ風、PPIスコープ風、と、とりあえずエポックメイキングなタイプはおおよそ作った気がします。あとは目標の捜索/追尾や、複数の超音波レーダーからのトラッキングデータをデータリンクに流して…とかでしょうか。

 前述したとおり、指向性がかなり鈍く、方位分解能がかなり悪いです。目標の捜索とかには使えないと思います。このあたりは素子を並列に並べて指向性を作ったり、皿をかぶせて指向性を作ったり、といったことができると思います。
 音波の40kHzは電磁波の35GHzに相当する波長です。衛星放送は12GHz程度ですから、衛星アンテナより小さい大きさで、同じくらいの指向性を得られます。かなり小さい反射器でも高い利得が得られそうな気がします。10cmくらいのディッシュでも十分な性能が出そうです。高精度な放物面をどうやって作るか、という問題はありますが、このくらいの大きさなら3Dプリントを外注してもそんなに高くないかもしれません。放物線のモデルを作るのはそれはそれで大変そうですが。あと、皿が2素子分必要というのもちょっと面倒。


 とりあえず、アジマススキャンができるようになったよ、という報告まで。

2018年2月18日日曜日

 前回から変化したところといえば、温度計を追加した事と、アナログ値の出力回数を10分の1に減らしたことでしょうか。
 温度計はADT7420を使いました。CubeでI2Cの初期化を追加して、レジスタを2バイト読むだけで温度を計測できます。恐ろしく簡単です。
 1-Wireの温度計の代わりにADT7420を使いました。ストリナのADT7420は時定数を下げるためか、0.1mmのリジット基板に実装されていて、ちょっと面倒な感じです。あと、昔I2Cでかなり苦労をしていて、I2Cセンサは嫌だなぁと思っていました。でも1-Wireで面倒なドライバを自分で実装することを考えると、それらのデメリットを補って余りあるかな、という気がします。



 広い部屋に行く用事が有ったので、ついでに超音波距離計の動作テストもやってきました。リファレンスの距離計が無いので正確性はわかりませんが、とりあえず約12m先からのピークが見えます。とはいえ、相関値はかなり低いですが。
 壁からの反射なので、これ以上大きなピークは出ないと思いますが、考えようによっては、大面積からの反射なので、反射位置によって様々な位相が含まれます。それによって相関値が低くなってしまっている、と考えることもできます。

 あと、距離分解能は思ったより低そうです。


 現在、相関器は16bit*16bitの乗算器で14bit*8bitの計算を行っていますが、相関処理だけならもっとビット数が低くても良さそうな気がします。ARMのSIMDの特性上、16bit*16bitより幅の狭い乗算器はありませんが。
 とはいえ、現状の方法よりは性能の良い相関器は色々な方式が有るはずで、もうちょっと改善の余地があります。

 他にも、受信段のオペアンプのゲインを増やして長距離からの信号を増幅する、と言った手段もあります。近距離からの信号は飽和してしまいますが、相関器はアナログ値の上下がクリップされていても動作しますし、近距離に特化したいならDACの出力を小さくすれば送信エネルギーを下げ、受信が飽和しないようにもできます。
 このあたりも一度考え直して見る必要があります。
 オペアンプの増幅率は3m程度の反射で飽和しないように、という狭い部屋の中で決めた値なので、実際にはもっと増幅率を稼いでも問題ないのかもしれません。ただ、すでにユニ基板に乗せてしまったので、今更リード抵抗を交換するのも面倒だなぁ、と思っています。プリント基板作りたい。。。


 またしばらくは狭い部屋でテストを繰り返すことになります。どうなることやら。

2018年2月16日金曜日

測距


マイコン内でLPFを通してピーク検出を行う、というところまで動きました。とりあえず横軸をExcelで音速から距離に計算してグラフ化しています。

 上のグラフはゲート全域のおよそ12m分、下のグラフは3mまでを拡大したものです。

 試しに130cmくらい離れた場所に30cmくらいの間隔でエアダスターの缶を置いてみました。1.35m、1.47m、1.64m、1.86mあたりに山があります。
 おそらく1.35mと1.64mがダスター缶じゃないかな、と思います。間隔は0.31mですから、缶の間隔と一致します。
 その他の山は、1.47mはダスター缶を置いた台の反射だと思います。その間も全体的に高いのは、台の壁面が見えているため、そこからの反射が有るのではないかな、と思います。1.86mは何が反射しているのかわかりません。壁にしては近いし、他のものは空のダンボールとかどれも有り得そうな感じです。


 距離分解能は10cmくらいかな、という感じでしょうか。LPFのCOFをもう少し上げれば距離分解能が稼げるかもしれませんが、それでも5cmくらいが限界だと思います。

 もっとも、パルス幅は10msecなので、パルス圧縮を行わなければ距離分解能は1.7mまで悪化してしまうので、15倍くらい性能が改善しているわけですが。
 パルス圧縮比は40なので、理論値で行けば4.25cm程度になるはずです。調整次第では、理論値に近い性能まで出るかもしれません。


 今のところ、計測を開始してからUARTの出力が終わるまでは20秒くらいかかっています。しかし、UARTを吐くforの中では計算は行っておらず、計測を開始してからUARTの出力が始まるまでは体感で1秒もありませんから、そのほとんどの時間をUARTで食っていることになります。
 データ数が1万4千行あり、1行あたりおよそ20文字近くのデータが有るので、全体では280kbyteくらいを転送していることになります。UARTの転送速度は12kbyte/secなので、280/12で23.33...秒が必要です。実際にはもう少し文字数が少ないので、ほぼ実測値と一致しています。
 ということで、現在でも115.2kbaudのUARTをフルに使っていることになります。また相関等の計算は0.5秒程度(デバッグ出力による)で、ピーク値の検出はほぼ無視できる程度であることがわかります。
 明らかにUARTに流すデータが多すぎるので、このあたりは気にならない程度までデータを飛ばすようにすれば、苛つかない程度には早くなると思います。


 とりあえず超音波距離計として必要な機能の大半は実装が終わりました。次の大きな目標としては温度計を動作させることでしょうか。
 パルス圧縮がおおよそ理論通りに動くようになってきて、そろそろ超音波距離計も飽きてきました。

メモ:undefined reference to `operator new(unsigned int)'

 undefined reference to `operator new(unsigned int)'
 undefined reference to `operator delete(void*)'
 というコンパイラエラーが出る場合、makefileのLDのgccをg++にすればok。

 ちょっと前にマイコンでC++を使おうと思ったことが有るんだけど、newを使おうとすると上記エラーが出て、結局newは使わずmallocを使っていた。
 コンパイラはg++に変えていたけど、リンカがgccのままだった、というオチ。


 これで動的メモリ確保がC++らしく書けるようになった。
 コンストラクタ/デストラクタが不要ならmallocで良いんだけど、mallocは、それはそれで危険なコードなので、使わないならそれに越したことはない。

2018年2月15日木曜日

測距


 6mくらいの距離で計ってみました。38msecあたりに強いピークがあり、これが壁からの反射波だと思います。途中のピークでも、おおよそその位置にモノがあるので、ちゃんと計測できているようです。

 距離が伸びでも、相関値に大きな影響は無いようです。この減り方を伸ばすと、10mくらいならちゃんとピークが出そうです。それ以上の距離はちょっと厳しい気がします。もうちょっと増幅率稼いでおけばよかったなぁ。

 計測幅は80msec、相関の計算には440msec程度です。
 最終的に、SIMDはスカラ演算と比べて2倍の処理速度になりました(forのオーバーヘッド含まず/命令数で計算)。32bitコアで16bit2組のベクトル演算ですから、ちょうど2倍になります。
 SIMDはコンパイラ最適化が少し弱くなるような気がします(インラインアセンブリと同じ書き方ですから、コンパイラ最適化が行われない?)。SIMDを使う場合は、可能な限りSIMD周りを一つの関数にまとめ、それ以外の処理は書かない、と言った工夫が必要なようです。これは関数を呼び出すことにより、レジスタをスタックに退避して、コンパイラが使用可能なレジスタを探すのを助ける、といった動きになりそうです。


 とりあえずAスコープ風の表示でいいなら、今の段階でも十分に使えますが、距離計として使うならピークを検出する処理が必要になります。次はこれを作る事になりそうです。