水橋 - Smith

4月は農作業の解禁日だろうと思う。そう、鮎の解禁日みたいなアレね。

4月1日はたまたま天気がよくて暖かかったからかも知れないけど、多数の農家の人が畑に出ていた。それ からの日はずっと農家の人が作業をしてるのを見るな。地震の影響で、プロ野球の開幕は少々遅れる みたいだけど、農業方面は自然が相手だから、そうも言っていられないのだろう。本番スタートです。

林檎畑を改めてみると、若い枝が赤っぽいのね。こんな事、今まで知らなかったよ。昔と種類が変わって いるのかな。それとも、子供時代はそこまで、観察眼が無かったからだろうか?

シーズンスタートでまず驚いたのが、農作業車が農免道路に多く見られる事。軽トラなんだけど、見ると消毒用の大きな タンクを積んで走ってる。若葉マークじゃなくて枯葉マーク(今は評判が悪いので4ツ葉のクローバーマークかな) をつけてる車がほとんど。農家は高齢化が着実に進んでる事が見てとれる。

軽トラの次に多いのがいわゆるトラクター、続いて多いのは林檎の樹の消毒車。大きなタンクの後ろに ファンが付いていて、それで消毒液を散布する仕組みのやつだ。こういう特殊車両の常として、運行スピードが 遅いんだなあ。一般道より整備された農免道路だと、すいっと追い越せるからいいけど。って、普通車が 農業道路を走っちゃいかんだろうに。

散歩の道すが、農家の庭先が見えるんだけど、タンクに水と農薬を入れて準備をしてる場面によく出会う。 農薬は白っぽかったけど、何と言うやつだろう? 昔は、林檎の樹の消毒と言ったら、確か硫酸銅を石灰で 溶かしたやつを使ってたな。硫酸銅のあの青さが特徴的で、樹を見るとすぐに消毒をしたなって分かって 良かったよ。

そうそう、硫酸銅と言えば、プリント板のエッチングに使ったな。薬局へ買いに行ったら、何に使うんか しつこく聞かれて、ちゃんと説明したけど未成年者には売れないと言われたな。そんで、母と一緒に 行って、やっと手に入れた記憶があるぞ。

エッチングした後の廃液はどうやって処理したかなあ。こっそり畑に捨てたんだったかなあ。今そんな 事をしたら(昔でも同様かも知れないけど)新聞を賑わす事になろう。

半田も鉛は環境を汚染すると言って、無鉛半田になっちゃったくらいだから、みんな神経使ってんのね。 超無神経なのは、原発だな。鉛の比じゃありませんぜ。

disる

前回ちらっとリンクを載せておいたけど、Pythonでもアセンブラが見られるのね。ああ、アセンブラと 言っても、あの方が設計したマシン用のアセンブラだけど。ちょいとどんな具合になってるか試して みる。

def td(x):
    if re.match(r"^\d.*", x):
        return x

前回、こんなのを書いた。逆アセンブルしてみると

>>> import dis as d
>>> d.dis(td)
  9           0 LOAD_GLOBAL              0 (re)
              3 LOAD_ATTR                1 (match)
              6 LOAD_CONST               1 ('^\\d.*')
              9 LOAD_FAST                0 (x)
             12 CALL_FUNCTION            2
             15 POP_JUMP_IF_FALSE       22

 10          18 LOAD_FAST                0 (x)
             21 RETURN_VALUE        
        >>   22 LOAD_CONST               0 (None)
             25 RETURN_VALUE        

もう一丁、行ってみるかな。

def getlog(csv_file):
    fd = open(csv_file)
    s = fd.readlines()
    fd.close()
    return filter(td, s)
>>> d.dis(getlog)
 13           0 LOAD_GLOBAL              0 (open)
              3 LOAD_FAST                0 (csv_file)
              6 CALL_FUNCTION            1
              9 STORE_FAST               1 (fd)

 14          12 LOAD_FAST                1 (fd)
             15 LOAD_ATTR                1 (readlines)
             18 CALL_FUNCTION            0
             21 STORE_FAST               2 (s)

 15          24 LOAD_FAST                1 (fd)
             27 LOAD_ATTR                2 (close)
             30 CALL_FUNCTION            0
             33 POP_TOP             

 16          34 LOAD_GLOBAL              3 (filter)
             37 LOAD_GLOBAL              4 (td)
             40 LOAD_FAST                2 (s)
             43 CALL_FUNCTION            2
             46 RETURN_VALUE        

上のデータの並びは左から、ソースの行番号、バイトカウンタ、命令、参照変数となっている。CALL_FUNCTION の引数は、アリティなんだなと思える。って、それしか分からんのか! 続きはwebで。そして、 インテルの糞石より優しいVMの仕様書

予備実験

AA-30で取得したデータを元に、スミスチャートを描こうと思う。その予備実験として、gnuplotに渡すデータファイルを一時ファイルで実現 するにはどうしたらいいか確認しておく。

import tempfile, os
import Gnuplot

def wtmp():
    fd = tempfile.NamedTemporaryFile(delete=False, suffix='.gnuplot')
    fd.write('1 2\n')
    fd.write('2 3\n')
    fd.write('3 1\n')
    fd.close()
    return fd

def rdtmp(fn):
    f = open(fn)
    dat = f.readlines()
    f.close()
    print(dat)
    print(fn)

x = wtmp()
tf = x.name
rdtmp(tf)
mk = 'plot "{0}" with lines lt 1 ti ""\n'
win = mk.format(tf)
cmd = win.replace('\\', '\\\\')
g = Gnuplot.Gnuplot(debug=1)
g(cmd)
raw_input('Hit returnKey to byebye')

色々調べて、動くようになったのが上記のコードだ。一時ファイルを作るのは何のひねりもない NamedTemporaryFileと言う手続き。deleteと言う名前付き引数にFalseを設定しておくと、ファイルをclose後も ファイルは残ったままになる。(その代わり、ファイルを消すのはユーザーの責任)

Windows特有な事ではまったのが、ファイルのセパレータ。

['1 2\n', '2 3\n', '3 1\n']
c:\users\foo\appdata\local\temp\tmphht6qc.gnuplot
gnuplot> set terminal windows
gnuplot> plot "c:\\users\\foo\\appdata\\local\\temp\\tmphht6qc.gnuplot" with lines lt 1 ti ""
>>> tf
'c:\\users\\foo\\appdata\\local\\temp\\tmphht6qc.gnuplot'

gnuplotへは、セパレータになるバックスラッシュを保護してから渡さないと、そんなファイル無いよと なってしまう。その為に、replaceしてるんだ。Windowsって面倒くせー、だっせーぜよ。

Smith Chart

import cmath
import re
import csv
from numpy import *
import Gnuplot, Gnuplot.funcutils
import subprocess
import tempfile
import os

sh = """plot ((0)*(0)+(t)*(t)-2500)/(((0)+50)*((0)+50)+(t)*(t)),\
100*(t)/(((0)+50)*((0)+50)+(t)*(t)) lt 9 ti ""  ,\
((0)*(0)+(t)*(t)-2500)/(((0)+50)*((0)+50)+(t)*(t)),\
-100*(t)/(((0)+50)*((0)+50)+(t)*(t)) lt 9 ti ""  ,\
((25)*(25)+(t)*(t)-2500)/(((25)+50)*((25)+50)+(t)*(t)),\
100*(t)/(((25)+50)*((25)+50)+(t)*(t)) lt 9 ti "" ,\
((25)*(25)+(t)*(t)-2500)/(((25)+50)*((25)+50)+(t)*(t)),\
-100*(t)/(((25)+50)*((25)+50)+(t)*(t)) lt 9 ti "" ,\
((50)*(50)+(t)*(t)-2500)/(((50)+50)*((50)+50)+(t)*(t)),\
100*(t)/(((50)+50)*((50)+50)+(t)*(t)) lt 9 ti "" ,\
((50)*(50)+(t)*(t)-2500)/(((50)+50)*((50)+50)+(t)*(t)),\
-100*(t)/(((50)+50)*((50)+50)+(t)*(t)) lt 9 ti "" ,\
((100)*(100)+(t)*(t)-2500)/(((100)+50)*((100)+50)+(t)*(t)),\
100*(t)/(((100)+50)*((100)+50)+(t)*(t)) lt 9 ti "" ,\
((100)*(100)+(t)*(t)-2500)/(((100)+50)*((100)+50)+(t)*(t)),\
-100*(t)/(((100)+50)*((100)+50)+(t)*(t)) lt 9 ti ""  ,\
(t*t+(0)*(0)-2500)/((t+50)*(t+50)+(0)*(0)),\
100*(0)/((t+50)*(t+50)+(0)*(0)) lt 9 ti "" ,\
(t*t+(0)*(0)-2500)/((t+50)*(t+50)+(0)*(0)),\
-100*(0)/((t+50)*(t+50)+(0)*(0)) lt 9 ti "" ,\
(t*t+(25)*(25)-2500)/((t+50)*(t+50)+(25)*(25)),\
100*(25)/((t+50)*(t+50)+(25)*(25)) lt 9 ti "" ,\
(t*t+(25)*(25)-2500)/((t+50)*(t+50)+(25)*(25)),\
-100*(25)/((t+50)*(t+50)+(25)*(25)) lt 9 ti "" ,\
(t*t+(50)*(50)-2500)/((t+50)*(t+50)+(50)*(50)),\
100*(50)/((t+50)*(t+50)+(50)*(50)) lt 9 ti "" ,\
(t*t+(50)*(50)-2500)/((t+50)*(t+50)+(50)*(50)),\
-100*(50)/((t+50)*(t+50)+(50)*(50)) lt 9 ti "" ,\
(t*t+(100)*(100)-2500)/((t+50)*(t+50)+(100)*(100)),\
100*(100)/((t+50)*(t+50)+(100)*(100)) lt 9 ti "" ,\
(t*t+(100)*(100)-2500)/((t+50)*(t+50)+(100)*(100)),\
-100*(100)/((t+50)*(t+50)+(100)*(100)) lt 9 ti "",\
"""
mk = '"{0}" with lines lt 1 ti ""\n'

def getlog(csv_file):
    fd = open(csv_file)
    s = fd.readlines()
    fd.close()
    return [x for x in s if re.match(r"^\d.*", x)]

def to_fz(f):
    return float(f[0]), complex(float(f[1]), float(f[2]))

def xyloc(fz):
    z = fz[1]
    a = (z -50)/(z + 50)
    x = a.real
    y = a.imag
    return x,y

def savefor(dat):
    fd = tempfile.NamedTemporaryFile(delete=False, suffix='.dat')
    for x in dat:
        s = str(x[0]) + ' ' + str(x[1]) + '\n'
        fd.write(s)
    fd.close()
    return fd

def main():
    subprocess.call(['ttpmacro', 'sa.ttl'])  # sa.ttl must be in teraterm-dir
    c = csv.reader(getlog('AA30.log'))
    fz = map(to_fz,c)
    dat = map(xyloc, fz)
    fd = savefor(dat)
    win = mk.format(fd.name)
    cmd = sh + win.replace('\\', '\\\\')
    g = Gnuplot.Gnuplot(debug=1)
    g.title('AA-30 Smith')
    g('set para')
    g('set size square')
    g('set trange [0:3000]')
    g('set samples 601')
    g(cmd)
    raw_input('Please press return to end...\n')
    os.unlink(fd.name)

# when executed, just run main():
if __name__ == '__main__': main()

ちょっと長いけど、その大半はスミスチャートの目盛りを書くためのgnuplot用計算手続き。 後述します。

ほとんどが前回のSWRを書くスクリプトを使いまわしているけど、ちょっと変えたのがgetlog内に 有ったfilter手続きを無くした事。代わりに、Haskelでも採用されてた(はず)リストの内包表記 ってのを使ってみた。

上記では、一時ファイルをちゃんと消しているけど、最初、os.unlinkをg(cmd)のすぐ後ろに置いて いたんだ。そしたら、目盛りだけ表示されて、肝心のデータが描画されなかった。 可笑しいなあ、Windows特有の問題かと思ってウブで実行した所

Please press return to end...
         line 0: warning: Skipping unreadable file "/tmp/tmpOdoeAZ.dat"

こんな的確なメッセージを出してくれたよ。結局、Windows版のgnuplotでは、エラーデータをPython側に 返す事が出来ない仕様だから、エラーが起きていても表示出来なかったのね。これ、要注意だな。

目盛りについて

スミスチャート は、独自な目盛りを持っている。好き好んでこんな目盛りにしてる訳ではなく、有限な 2次平面上で無限の複素平面を表示可能にする工夫が凝らされているからだ。

スミスチャートの目盛りはどうやって描くんだろう? きっとgnuplotでもやっているスミス2世が居るに 違いない。gnuplot付属のdemoを漁ってみたら(いやになるほどデモが出てきます)、poldat.demに書き方 が出ていた。媒介変数と三角関数を使ったもので、目が三角になってしまったので、採用は諦めました。 でも、同ファイルにはアンテナパターンの例が載ってましたので、アマチュアの方は必見です。

代わりに採用させていただいたのが、スクリプト中で取り入れているものです。発表されてたものの 引き写しなので、50オームの正規化円に、25オーム、100オームを追加した図になってます。

 t = (z - 50) / (z + 50)    where  z = a + jb

     a**2 + b**2 - 2500                100b
 t = -------------------  + j * -------------------
     (a + 50)**2 + b**2          (a + 50)**2 + b**2

上記の実部をxに虚部をyに割り当てておき、bを50に固定しaをスイープすれば、j50の インピーダンス円が描けるという寸法だそうです。スイープの変数はtで与えていますが 正の範囲だけに限定したかったので、y<0の部分はyに-をつけて書いているそうです。

こういう図が、アマチュア無線家によって発明されるなんて面白いな。嗚呼、スミスさんより先に 水橋さんが同じ仕組みの図を考案されているじゃないですか。独創的な方だったんですね。

おまけ

とある方の好意により手に入れた、40m用アンテナをAA-54で計測した例を載せておきます。データの提供、 どうもありがとうございました。

生データを元にSWRを書いてみた。 そしてスミスさんの発明に便乗してみました。

なお、pngファイルの採取は、g('set terminal png') を追加した上で、ウブ上から

sakae@ubuntu:~/aa30$ python smith.py > smith.png

と、実行しました。目盛りが黄色になってしまいましたが、オリジナルは灰色です。

最後に歴史的文献をば。 四端子回路のインピーダンス変成と整合回路の理論