ソフトウェア/OpenFDTD の変更点
更新- 追加された行はこの色です。
- 削除された行はこの色です。
- ソフトウェア/OpenFDTD へ行く。
- ソフトウェア/OpenFDTD の差分を削除
[[公開メモ]] &katex();
* OpenFDTD を使ってプリント基板上の高速信号の伝播を理解したい [#v3733737]
例えば4層基板上のマイクロストリップラインの周囲の電場をこんな風に計算するとか。
&ref(microstrip1.png,,50%);
&ref(microstrip2.png,,33%);
** 目次 [#taf6b842]
#contents
** OpenFDTD について [#ta0c33d3]
株式会社 EEM により開発&メンテナンスされていたオープンソースの FDTD シミュレーションソフト。
[[Wikipedia:FDTD法]] は主にマクスウェル方程式を数値的に解いて電磁波のシミュレーションを行う際に使われる数値計算手法の一種。
株式会社 EEM は2022年9月30日に解散したため、現在は大賀さんが個人的に (?) メンテナンスを続けてらっしゃるようです。
** OpenFDTD のダウンロード&説明 [#v73424f6]
以前は http://e-em.co.jp/OpenFDTD にあったのですが、
現在は http://emoss.starfree.jp/ で公開されています。
> 1.1 概要
>
> (1) 本ソフトウェアについて
> 本ソフトウェアOpenFDTDはFDTD法(Finite Difference Time Domain method)[1][2] を用いた汎用的な電磁界シミュレーターです。 電磁界の広い用途の解析に使用することができます。
>
> (2) オープンソース
> 本ソフトウェアOpenFDTDはオープンソースのフリーソフトです。 自由にダウンロードしてお使いください。
>
> (3) 動作環境
> 動作環境はWindowsまたはLinuxです。 Windows環境には簡易GUIと実行プログラムが付属しています。
GPU やクラスターマシン、スーパーコンピュータ用の高速演算コードまで含まれているすばらしいものです。
Windows 用には GUI も提供されていて、モデルの作成や計算結果のグラフ表示が可能です。
* 計算例 [#m6251b49]
- [[ソフトウェア/OpenFDTD/マイクロストリップライン]]
- [[ソフトウェア/OpenFDTD/解放端・固定端]]
- [[ソフトウェア/OpenFDTD/50Ω終端]]
- [[ソフトウェア/OpenFDTD/パッドを作って素子を載せる]]
* プリント基板 (PCB) のシミュレーションに使うことを想定した注意点 [#k7b22011]
プリント基板 (PCB) のシミュレーションでは各部のサイズを厳密に設定しなければならならず、セルの大きさ分の誤差が計算結果に影響する。
このため、FDTD 計算の基本を押さえておかないと計算結果が合わず困ったことになります。
** FDTD 計算の基本 [#t2a1160b]
FDTD では計算したい空間を「直方体のセル」に分割して計算する。
ここではセルの数を $N_x\times N_y\times N_z$ とする。
「セルの頂点」が格子点 $(x_i,y_j,z_k)$ にあたる。頂点数は $(N_x+1)\times (N_y+1)\times (N_z+1)$ である。
電場・電流はセルの辺に沿って計算され、その際には「辺の中心」が基準点となる。
たとえば $E_x$ を計算するには $(x_i+(x_{i+1}-x_i)/2,y_j,z_k)=((x_i+x_{i+1})/2,y_j,z_k)$ が基準点で、その数は $N_x\times (N_y+1)\times (N_z+1)$ である。
基準点の周りに「その電場が仮定される範囲」が取られる。
- $x_i<x<x_{i+1}$
- $y_j-(y_j-y_{j-1})/2<y<y_j+(y_{j+1}-y_j)/2$
- $z_k-(z_k-z_{k-1})/2<z<z_k+(z_{k+1}-z_k)/2$
がその範囲になるため、セルの範囲、$E_{x,i+1/2,j,k}$ の範囲、$E_{y,i,j+1/2,k}$ の範囲、$E_{z,i,j,k+1/2}$ の範囲はすべて異なることに注意が必要。さらに、隣り合うセルのサイズが異なる場合には「電場セル」の中心は「辺の中心」とも一致しない。
磁場・磁流はセルの面に垂直に計算され、面の中心が基準点となる。例えば $H_{z}$ は $(x_{i+1/2},y_{j+1/2},z_k)$ が基準点となる。
** マテリアルの範囲 [#j3fd261d]
誘電体や金属を配置する際、その範囲は「セル単位」ではなく「座標空間内に厳密に設定された範囲」になる。
どういうことかというと、電場や磁場を計算する際、その「基準点」の座標がどこかによって、どのマテリアルのパラメータを使って計算するかが決まる。
FDTD が基礎とする Maxwell 方程式の形は
$$
\frac{\epsilon_r}{c}\partial_t\bm E=\bm\nabla\times\eta\bm H-\underbrace{(\eta\sigma)\bm E}_\text{電流密度項}
$$
$$
\frac{\mu_r}c\partial_t\eta\bm H=-\bm\nabla\times\bm E-\underbrace{(\frac{\sigma_m}\eta)\eta\bm H}_\text{磁流密度項}
$$
で、特に材質によって大きく変わる誘電率 $\epsilon_r$ と伝導率 $\sigma$ は電場の方程式だけに含まれるので、「格子点」や「セルの中心」ではなくむしろ「『辺の中心位置』にどの材質が設定されているか」が結果に影響してくるという点に注意が必要なのだ。
FDTD における導体は「ジャングルジム」のようなもので、その辺にしか電流は流れない。
物体をおかしなところで切ると、片方の先がどこにもつながっていないような中途半端な辺がたくさん
生えた「毛深い」物体ができてしまう。「毛」はアンテナっぽく働くけれど、毛と毛の間で横方向に
電流が流れないので思ったのと違う動作をしかねない。
また「辺」は「仮想的な太さ」を持つので、全体としての伝導度や抵抗を設計値と合わせたい場合には
その「太さ」を正しく考慮しないと値が異なってしまう。
また OpenFDTD では、
- 設定したマテリアルの範囲の「境界上の点」は「マテリアルの内部」として考慮されること、
- 複数のマテリアルに含まれる点は「最後に指定したマテリアル」で上書きされること、
にも注意が必要だ。
** 具体例で考える [#kfb4e75b]
例えば厚さ 1.6 mm の両面基板を考え、裏のグランドプレーンを $z=-1.6\ \text{mm}$ に配置したいとする。
それには任意の $k$ に対して $z_k=-1.6\ \text{mm}$ となるよう格子点を配置して、$z=-1.6\ \text{mm}$ に「厚さゼロ」の完全導体を配置すればよい。
そこである $k$ に対して $z_k=-1.6\ \text{mm}$ となるよう格子点を配置して、$z=-1.6\ \text{mm}$ に「厚さゼロ」の完全導体を配置する。
これにより、この面内にメッシュ状に配置された長方形の「辺」が完全導体の特性を持つようになり、この面内で電流が自由に流れるようになる。
マテリアルを設定した領域の境界と一致する点にはそのマテリアルが適用されるので、これにより、この面内にメッシュ状に配置された長方形の「辺」が完全導体の特性を持つようになり、この面内で電流が自由に流れるようになる。
辺は「太さ」を持つため、ここに完全導体ではなく有限伝導度の金属を置くなら、その厚さにも注意が必要だ。
この時、導体の厚さは次の格子面の中点までとなるため、その値は $(z_{k+1}-z_{k-1})/2$ となる。この面が系の端にある場合、例えば $z_0$ にある場合は、$z_{-1}$ の格子面が存在しないため、代わりに反対側の格子面までの距離が使われて、$z_1-z_0$ がトータルの厚さになる。
この時、導体の厚さは次の格子面の中点までと定義されるから、その値は $(z_{k+1}-z_{k-1})/2$ となる。この面が系の端にある場合、例えば $z_0$ にある場合は、$z_{-1}$ の格子面が存在しないため、代わりに反対側の格子面までの距離が使われて、$z_1-z_0$ がトータルの厚さになる。これに伝導率を掛けてシート抵抗が得られる。
この電流による磁場は、本来太さを持つ辺を流れる電流が、あたかも辺の上に集中しているかのように考えて計算される。
同様に、パターン面を $z=0\ \text{mm}$ として、そこに厚さゼロの金属を配置すればそこに電流を流すことができる。
同様に、パターン面を $z=0\ \text{mm}$ として、そこに厚さゼロの金属を配置すればそこに電流を流せる。
この間を誘電体、例えば FR-4 で埋めるには、グランドプレーンやパターン面の金属を配置する「前に」 $\epsilon_r=4.3$ の材質を $-1.6\ \text{mm}\le z\le 0\ \text{mm}$ に配置すると良い。
この間を誘電体、例えば FR-4 で埋めるには、グランドプレーンやパターン面の金属を配置する「前に」 $\epsilon_r=4.3$ の材質を $-1.6\ \text{mm}\le z\le 0\ \text{mm}$ に配置すると良い。後で配置すると先に置いた金属が上書きされてしまう。
グランドプレーンやパターンには「辺の太さ」分だけの仮想的な厚みがあるが、誘電体内で $E_z$ を計算する際にはその金属板の厚みは考慮されない。例えば $z_{k+1/2}$ にある $z$ 方向に向く辺は正しく $z_k$ から $z_{k+1}$ までの長さを持つ。つまりグランドプレーンの仮想的な厚さを無視して $z_k$ まで突き刺さっていて、その計算に誘電体の誘電率と伝導率が使われるのだ。
だから、$z_k<z<z_{k+1/2}$ の範囲は面内の電場を計算するときには金属、面直の電場を計算するときには誘電体であるように扱われる不思議領域になる。そこが問題になるなら、金属面のすぐ隣の面までの面間隔を小さくすることで影響を最小化できるはず。
パターンの太さを考えるときも十分注意しなければならない。格子点から格子点までの長さをピッタリパターンの太さに合わせ、両端の格子点を含む形でパターンに対応する金属領域を設定するのが、金属の形状を定義してそのまわりの誘電体内の電場を計算するには最適と思われるが、そのときパターンの幅は辺の仮想的な太さ分だけ設定領域をはみ出すので、パターンに抵抗率を設定する場合にはその分だけ抵抗が下がってしまう。
影響を減らすにはやはり、パターンの外周のすぐ外の格子面までの距離を十分に小さくとるしかないのだと思う。とはいえパターンの厚さは 15 um とかしかないので、これを正しく計算できるほどメッシュを細かくするのは現実的ではなく、何かうまくごまかしながら計算していくしかない感じ???
影響を減らすにはやはり、パターンの外周のすぐ外の格子面までの距離を十分に小さくとるしかないのだと思う。とはいえ例えばパターンの厚さは 15 um とかしかないので、これを正しく計算できるほどメッシュを細かくするのは現実的ではなく、何かうまくごまかしながら計算していくしかない感じ???
* 結果表示用 Igor Pro スクリプト [#xca6dd8d]
計算結果を図にするのが大変なので、Igor Pro で直接読み込んで表示できるようにした。
いろいろ手抜きをしているので、今後も改善していかないと。
FDTD 計算結果は ofd.out というファイルにごそっと書き出されている。
グラフ化などのポストプロセスはこのデータを読み込んで、画像に加工している。
なので、ofd.out を Igor で読み込めば、好きなように表示可能!
- 電場を xy, yz, zx 面で切って表示するところまで書いた。
- Igor6 でも動くように少し直した。int64 に対応していないので、int32 で2回読んでつなぎ合わせる必要があった。あと、wave1[inf] のようなのがエラーになるので wave1[numpnts(wave1)-1] のように書き換えた。
- NPoint = 0 でおかしくならないよう書き換えた。
- Zin と Reflection を表示できるようにした。
- cEpx などの計算が間違ってた(cHpx は合ってるのか?)
- NFreq2 = 0 でも大丈夫にしようとしたのだけれど、これはゼロにはならないのかも。
- スミスチャートを表示できるようにした
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#include "SmithChart"
// load_ofd_out("C:Users:osamu:documents:OpenFDTD:ofd.out")
// のようにして読み込む。
Structure ofd_out_header
char title[256]
int32 Nx, Ny, Nz
int32 NExl, NExh, NEyl, NEyh, NEzl, NEzh
int32 NHxl, NHxh, NHyl, NHyh, NHzl, NHzh
int32 NFreq1, NFreq2, NFeed, NPoint, Niter, Ntime
int32 SolverMaxIter, SolverNOut
double Dt
int32 NGline
EndStructure
Structure odf_feed
char dir, dummy1, dummy2, dummy3 // 4 byte alignment
int32 i, j, k
double dx, dy, dz
double volt
double delay
double z0
EndStructure
function/t odf_feed2str(feed)
STRUCT odf_feed &feed
string s = ""
sprintf s, "dir:%d;i:%d;j:%d;k:%d", feed.dir, feed.i, feed.j, feed.k
sprintf s, "%s;dx:%g;dy:%g;dz:%g", s, feed.dx, feed.dy, feed.dz
sprintf s, "%s;volt:%g;delay:%g;z0:%g", s, feed.volt, feed.delay, feed.z0
return s
end
function load_ofd_out(path)
string path
variable f
open/r f as path
STRUCT ofd_out_header header
fbinread f, header
string/g title = header.title
variable/g Nx = header.Nx, Ny = header.Ny, Nz = header.Nz
variable/g NEx = header.NExl + header.NExh * 2^32
variable/g NEy = header.NEyl + header.NEyh * 2^32
variable/g NEz = header.NEzl + header.NEzh * 2^32
variable/g NHx = header.NHxl + header.NHxh * 2^32
variable/g NHy = header.NHyl + header.NHyh * 2^32
variable/g NHz = header.NHzl + header.NHzh * 2^32
variable/g NFreq1 = header.NFreq1, NFreq2 = header.NFreq2, NFeed = header.NFeed
variable/g NPoint = header.NPoint, Niter = header.Niter, Ntime = header.Ntime
variable/g SolverMaxIter = header.SolverMaxIter, SolverNOut = header.SolverNOut
variable/g Dt = header.Dt, NGline = header.NGline
if(nex!=nx*(ny+1)*(nz+1))
abort "unexpected NEx"
endif
if(ney!=(nx+1)*ny*(nz+1))
abort "unexpected NEx"
endif
if(nez!=(nx+1)*(ny+1)*nz)
abort "unexpected NEx"
endif
if(nhx!=(nx+1)*(ny+2)*(nz+2))
abort "unexpected NHx"
endif
if(nhy!=(nx+2)*(ny+1)*(nz+2))
abort "unexpected NHx"
endif
if(nhz!=(nx+2)*(ny+2)*(nz+1))
abort "unexpected NHx"
endif
make/O/N=(Nx+1) Xn; fbinread /B=3 /F=5 f, Xn
make/O/N=(Ny+1) Yn; fbinread /B=3 /F=5 f, Yn
make/O/N=(Nz+1) Zn; fbinread /B=3 /F=5 f, Zn
make/O/N=(Nx) Xc; fbinread /B=3 /F=5 f, Xc
make/O/N=(Ny) Yc; fbinread /B=3 /F=5 f, Yc
make/O/N=(Nz) Zc; fbinread /B=3 /F=5 f, Zc
make/O/N=(Niter) Eiter; fbinread /B=3 /F=5 f, Eiter
make/O/N=(Niter) Hiter; fbinread /B=3 /F=5 f, Hiter
make/O/N=(SolverMaxIter+1, NFeed) VFeed
make/O/N=(SolverMaxIter+1, NFeed) IFeed
if (NFeed > 0)
fbinread /B=3 /F=5 f, VFeed
fbinread /B=3 /F=5 f, IFeed
endif
make/O/N=(SolverMaxIter+1, NPoint) VPoint;
if (NPoint > 0)
fbinread /B=3 /F=5 f, VPoint
endif
make/O/N=(NFreq1) Freq1; fbinread /B=3 /F=5 f, Freq1
make/O/N=(NFreq2) Freq2;
if (NFreq2>0)
fbinread /B=3 /F=5 f, Freq2
endif
setscale d,0,1,"Hz",freq1,freq2
variable i
STRUCT odf_feed feedn
make/O/N=(NFeed)/T Feed
for(i=0; i<NFeed; i+=1)
fbinread/B=3 f, feedn
Feed[i] = odf_feed2str(feedn)
endfor
make/O/N=(NFeed, NFreq1)/C Zin
make/O/N=(NFeed, NFreq1) Ref
make/O/N=(NFeed, NFreq2) Pin0
make/O/N=(NFeed, NFreq2) Pin1
setscale d,0,1,"Ohm",Zin
if (NFeed > 0)
fbinread /B=3 /F=5 f, Zin
fbinread /B=3 /F=5 f, Ref
if (NFreq2>0)
fbinread /B=3 /F=5 f, Pin0
fbinread /B=3 /F=5 f, Pin1
endif
endif
make/O/N=(NFreq1, NPoint)/C Spara
if (NPoint > 0)
fbinread /B=3 /F=5 f, Spara
endif
make/O/N=(3, 2, NGline) Gline
if (NGline > 0)
fbinread /B=3 /F=5 f, Gline
endif
// CExyz, CHxyz のメモリ構造 from ofd.h
//
//#define NEX(i,j,k) ((i)*(Ny+1)*(Nz+1)+(j)*(Nz+1)+(k))
//#define NEY(i,j,k) ((j)*(Nz+1)*(Nx+1)+(k)*(Nx+1)+(i))
//#define NEZ(i,j,k) ((k)*(Nx+1)*(Ny+1)+(i)*(Ny+1)+(j))
//#define NHX(i,j,k) ((i)*(Ny+2)*(Nz+2)+(j+1)*(Nz+2)+(k+1))
//#define NHY(i,j,k) ((j)*(Nz+2)*(Nx+2)+(k+1)*(Nx+2)+(i+1))
//#define NHZ(i,j,k) ((k)*(Nx+2)*(Ny+2)+(i+1)*(Ny+2)+(j+1))
//
//#define CEX_r(f,i,j,k) cEx_r[(f*NEx)+NEX(i,j,k)]
//#define CEY_r(f,i,j,k) cEy_r[(f*NEy)+NEY(i,j,k)]
//#define CEZ_r(f,i,j,k) cEz_r[(f*NEz)+NEZ(i,j,k)]
//#define CHX_r(f,i,j,k) cHx_r[(f*NHx)+NHX(i,j,k)]
//#define CHY_r(f,i,j,k) cHy_r[(f*NHy)+NHY(i,j,k)]
//#define CHZ_r(f,i,j,k) cHz_r[(f*NHz)+NHZ(i,j,k)]
//#define CEX_i(f,i,j,k) cEx_i[(f*NEx)+NEX(i,j,k)]
//#define CEY_i(f,i,j,k) cEy_i[(f*NEy)+NEY(i,j,k)]
//#define CEZ_i(f,i,j,k) cEz_i[(f*NEz)+NEZ(i,j,k)]
//#define CHX_i(f,i,j,k) cHx_i[(f*NHx)+NHX(i,j,k)]
//#define CHY_i(f,i,j,k) cHy_i[(f*NHy)+NHY(i,j,k)]
//#define CHZ_i(f,i,j,k) cHz_i[(f*NHz)+NHZ(i,j,k)]
if (NFreq2 > 0)
make/O/N=(nx, ny, nz, NFreq2)/C cEx, cEy, cEz
make/O/N=(nz+1, ny+1, nx+0, NFreq2) cEx_r; fbinread /B=3 /F=4 f, cEx_r
make/O/N=(nz+1, ny+1, nx+0, NFreq2) cEx_i; fbinread /B=3 /F=4 f, cEx_i
cEx = (cmplx(cEx_r[r][q][p][s], cEx_i[r][q][p][s])+cmplx(cEx_r[r+1][q][p][s], cEx_i[r+1][q][p][s])+cmplx(cEx_r[r][q+1][p][s], cEx_i[r][q+1][p][s])+cmplx(cEx_r[r+1][q+1][p][s], cEx_i[r+1][q+1][p][s]))/4
killwaves cEx_r, cEx_i
make/O/N=(nx+1, nz+1, ny+0, NFreq2) cEy_r; fbinread /B=3 /F=4 f, cEy_r
make/O/N=(nx+1, nz+1, ny+0, NFreq2) cEy_i; fbinread /B=3 /F=4 f, cEy_i
cEy = (cmplx(cEy_r[p][r][q][s], cEy_i[p][r][q][s])+cmplx(cEy_r[p+1][r][q][s], cEy_i[p+1][r][q][s])+cmplx(cEy_r[p][r+1][q][s], cEy_i[p][r+1][q][s])+cmplx(cEy_r[p+1][r+1][q][s], cEy_i[p+1][r+1][q][s]))/4
killwaves cEy_r, cEy_i
make/O/N=(ny+1, nx+1, nz+0, NFreq2) cEz_r; fbinread /B=3 /F=4 f, cEz_r
make/O/N=(ny+1, nx+1, nz+0, NFreq2) cEz_i; fbinread /B=3 /F=4 f, cEz_i
cEz = (cmplx(cEz_r[q][p][r][s], cEz_i[q][p][r][s])+cmplx(cEz_r[q+1][p][r][s], cEz_i[q+1][p][r][s])+cmplx(cEz_r[q][p+1][r][s], cEz_i[q][p+1][r][s])+cmplx(cEz_r[q+1][p+1][r][s], cEz_i[q+1][p+1][r][s]))/4
killwaves cEz_r, cEz_i
make/O/N=(nx+1, ny+1, nz+1, NFreq2)/C cHx, cHy, cHz
make/O/N=(nz+2, ny+2, nx+1, NFreq2) cHx_r; fbinread /B=3 /F=4 f, cHx_r
make/O/N=(nz+2, ny+2, nx+1, NFreq2) cHx_i; fbinread /B=3 /F=4 f, cHx_i
cHx = (cmplx(cHx_r[r][q][p][s], cHx_i[r][q][p][s])+cmplx(cHx_r[r+1][q][p][s], cHx_i[r+1][q][p][s])+cmplx(cHx_r[r][q+1][p][s], cHx_i[r][q+1][p][s])+cmplx(cHx_r[r+1][q+1][p][s], cHx_i[r+1][q+1][p][s]))/4
killwaves cHx_r, cHx_i
make/O/N=(nx+2, nz+2, ny+1, NFreq2) cHy_r; fbinread /B=3 /F=4 f, cHy_r
make/O/N=(nx+2, nz+2, ny+1, NFreq2) cHy_i; fbinread /B=3 /F=4 f, cHy_i
cHy = (cmplx(cHy_r[p][r][q][s], cHy_i[p][r][q][s])+cmplx(cHy_r[p+1][r][q][s], cHy_i[p+1][r][q][s])+cmplx(cHy_r[p][r+1][q][s], cHy_i[p][r+1][q][s])+cmplx(cHy_r[p+1][r+1][q][s], cHy_i[p+1][r+1][q][s]))/4
killwaves cHy_r, cHy_i
make/O/N=(ny+2, nx+2, nz+1, NFreq2) cHz_r; fbinread /B=3 /F=4 f, cHz_r
make/O/N=(ny+2, nx+2, nz+1, NFreq2) cHz_i; fbinread /B=3 /F=4 f, cHz_i
cHz = (cmplx(cHz_r[q][p][r][s], cHz_i[q][p][r][s])+cmplx(cHz_r[q+1][p][r][s], cHz_i[q+1][p][r][s])+cmplx(cHz_r[q][p+1][r][s], cHz_i[q][p+1][r][s])+cmplx(cHz_r[q+1][p+1][r][s], cHz_i[q+1][p+1][r][s]))/4
killwaves cHz_r, cHz_i
endif
variable/g num
fbinread /B=3 /F=5 f, num
make/O/N=(nx+1) cEpx; cEpx = xn
make/O/N=(ny+1) cEpy; cEpy = yn
make/O/N=(nz+1) cEpz; cEpz = zn
setscale d,0,1,"m", cEpx, cEpy, cEpz
make/O/N=(nx+2) cHpx; cHpx = p == 0 ? xn[0]-(xn[1]-Xn[0])/2 : (p < nx ? (xn[p-1]+xn[p])/2 : xn[p-1] + (xn[p-1]-xn[p-2])/2)
make/O/N=(ny+2) cHpy; cHpy = p == 0 ? yn[0]-(yn[1]-yn[0])/2 : (p < ny ? (yn[p-1]+yn[p])/2 : yn[p-1] + (yn[p-1]-yn[p-2])/2)
make/O/N=(nz+2) cHpz; cHpz = p == 0 ? zn[0]-(zn[1]-zn[0])/2 : (p < nz ? (zn[p-1]+zn[p])/2 : zn[p-1] + (zn[p-1]-zn[p-2])/2)
setscale d,0,1,"m", cHpx, cHpy, cHpz
FStatus f
if(V_logEOF != V_filePos)
print "unexpected file length"
printf "logEOF = %f, filepos = %f\n", V_logEOF, V_filePos
endif
close f
show_ofd()
end
function show_ofd_sub(c1, c2, c3)
string c1, c2, c3
wave cEpx, cEpy, cEpz
wave/C cEx, cEy, cEz
nvar nx, ny, nz
make/O/N=(nx,ny) exy
make/O/N=(ny,nz) eyz
make/O/N=(nz,nx) ezx
NVAR NFreq2
wave Freq2
wave cEp1 = $("cEp"+c1)
wave cEp2 = $("cEp"+c2)
wave cEp3 = $("cEp"+c3)
string g="graph_e"+c1+c2+"_"+c3
dowindow $g
if(!v_flag)
variable/g $("Ep"+c3)=round(100*1000*(cEp3[0]+cEp3[inf])/2)/100
variable/g Ef = Freq2[0]/1e6
variable/g Efnowi = 0
variable/g Efnow = Freq2[0]/1e6
display
appendimage $("e"+c1+c2) vs {cEp1, cEp2}
dowindow/c $g
Label/w=$g bottom "Position "+c1+" / \\U"
Label/w=$g left "Position "+c2+" / \\U"
ModifyImage/w=$g $("e"+c1+c2) ctab= {0.2,*,Rainbow,1}, log=1
ControlBar/w=$g 20
CheckBox check0 title="log",proc=CheckLogProc,win=$g,value=1,side=1
SetVariable $("setFreq"+c3) title="freq (MHz):",win=$g,proc=SetSliceCoordinateProc,limits={(Freq2[0]/1e6),(Freq2[inf]/1e6),1},live=1,size={220,18},value=Ef
SetVariable $("setEp"+c3) title=(c3+" (mm):"),win=$g,proc=SetSliceCoordinateProc,limits={(1000*cEp3[0]),(1000*cEp3[inf]),0.01},live=1,size={200,18},value=$("Ep"+c3)
make/O/N=2 $("e"+c1+c2+"_cur1")
wave e12_cur1 = $("e"+c1+c2+"_cur1")
setscale/p x,(cEp1[0]),(cEp1[inf]-cEp1[0]),waveunits(cEp1,-1),e12_cur1
setscale d,0,1,waveunits(cEp2,-1),e12_cur1
appendtograph/w=$g e12_cur1
execute "e"+c1+c2+"_cur1:=ep"+c2+"/1000"
make/O/N=2 $("e"+c1+c2+"_cur2")
wave e12_cur2 = $("e"+c1+c2+"_cur2")
setscale/p x,(cEp2[0]),(cEp2[inf]-cEp2[0]),waveunits(cEp2,-1),e12_cur2
setscale d,0,1,waveunits(cEp1,-1),e12_cur2
appendtograph/w=$g/VERT e12_cur2
execute "e"+c1+c2+"_cur2:=ep"+c1+"/1000"
ModifyGraph rgb=(0,0,0), lstyle=2, lsize=0.1
ColorScale/C/N=text1/F=0/Z=1/A=RC/X=0.00/Y=0.00/E image=$("e"+c1+c2), heightPct=120, log=1
ColorScale/C/N=text1 logLTrip=0.1,minor=1
if(0==cmpstr(c1,"z"))
ModifyGraph/w=$g swapXY=1
endif
endif
end
Function SetSliceCoordinateProc(sva) : SetVariableControl
STRUCT WMSetVariableAction &sva
switch( sva.eventCode )
case 1: // mouse up
case 2: // Enter key
case 3: // Live update
string win = sva.win
// Variable dval = sva.dval
string c1 = win[7,7]
string c2 = win[8,8]
string c3 = win[10,10]
wave e12 = $("e"+c1+c2)
wave/C cEx, cEy, cEz
wave freq2
nvar Efnow, Efnowi, Ef
variable Efi
FindLevel/Q freq2, ef * 1e6
if(v_flag)
efi = Efnowi
else
efi = x2pnt(freq2, V_Levelx)
endif
if(Efnowi==efi)
if((ef < efnow) && (efi>0))
efi -= 1
elseif((ef > efnow) && (efi<numpnts(freq2)-1))
efi += 1
endif
endif
ef = freq2[efi]/1e6
Efnowi = efi
efnow = ef
show_e12("graph_exy_z")
show_e12("graph_eyz_x")
show_e12("graph_ezx_y")
break
case -1: // control being killed
break
endswitch
return 0
End
function show_e12(win)
string win
string c1 = win[7,7]
string c2 = win[8,8]
string c3 = win[10,10]
wave e12 = $("e"+c1+c2)
wave/C cEx, cEy, cEz
nvar ep3 = $("Ep"+c3)
wave cEp3 = $("cEp"+c3)
FindLevel/Q/Q cEp3, ep3/1000
variable ep3i = V_Levelx
nvar Efi = Efnowi
if(0==cmpstr(c3,"x"))
e12 = sqrt(cabs(cEx[ep3i][p][q][Efi])^2+cabs(cEy[ep3i][p][q][Efi])^2+cabs(cEz[ep3i][p][q][Efi])^2)
elseif(0==cmpstr(c3,"y"))
e12 = sqrt(cabs(cEx[q][ep3i][p][Efi])^2+cabs(cEy[q][ep3i][p][Efi])^2+cabs(cEz[q][ep3i][p][Efi])^2)
elseif(0==cmpstr(c3,"z"))
e12 = sqrt(cabs(cEx[p][q][ep3i][Efi])^2+cabs(cEy[p][q][ep3i][Efi])^2+cabs(cEz[p][q][ep3i][Efi])^2)
endif
wave freq2
variable ef = freq2[efi]
TextBox/w=$win/C/N=text0/F=0/X=0/Y=0/E=2 "freq = "+num2str(ef)+" MHz, "+c3+" = "+num2str(ep3)+" mm"
end
function show_ofd()
NVAR NFreq2
if(NFreq2>0)
variable/g Epx, Epy, Epz
show_ofd_sub("x", "y", "z")
show_ofd_sub("y", "z", "x")
show_ofd_sub("z", "x", "y")
show_e12("graph_exy_z")
show_e12("graph_eyz_x")
show_e12("graph_ezx_y")
endif
// STRUCT WMSetVariableAction sva
// sva.eventCode = 3
// sva.win = "graph_exy_z"
// SetSliceCoordinateProc(sva)
// sva.win = "graph_eyz_x"
// SetSliceCoordinateProc(sva)
// sva.win = "graph_ezx_y"
// SetSliceCoordinateProc(sva)
NVAR NFeed
if(NFeed>0)
show_zin()
endif
end
function show_zin()
NVAR NFreq1, NFeed
wave Freq1
wave/c Zin
make/O/N=(NFreq1)/C Zinp
setscale d,0,1,"Ohm",Zinp
DoWindow graph_zin
if(!V_Flag)
display Zinp vs Freq1
DoWindow/C graph_zin
appendtograph/w=graph_zin Zinp vs Freq1
appendtograph/w=graph_zin Zinp vs Freq1
ModifyGraph/w=graph_zin cmplxMode(Zinp)=1, cmplxMode(Zinp#1)=2, grid=1, rgb(Zinp#1)=(0,0,65535)
ModifyGraph/w=graph_zin rgb(Zinp#2)=(0,0,0),cmplxMode(Zinp#2)=3
Label/w=graph_zin left "Zin / \\U";DelayUpdate
Label/w=graph_zin bottom "Frequency / \\U"
ControlBar/w=graph_zin 20
variable/g feedi
SetVariable setvar0 proc=SetFeedProc,value=feedi,limits={0,0,1},win=graph_zin
make/N=2 zincsr
execute "zincsr:=Ef*1e6"
setscale x,0,100,"Ohm",zincsr
appendtograph/w=graph_zin/VERT zincsr
ModifyGraph/w=graph_zin lstyle(zincsr)=2,rgb(zincsr)=(0,0,0)
endif
DoWindow graph_ref
if(!V_Flag)
make/o Refp
display/N=graph_ref Refp vs Freq1
modifygraph/w=graph_ref grid=1, zero(left)=1
SetAxis/w=graph_ref/A/E=1 left
Label/w=graph_ref left "Reflection / \\U"
Label/w=graph_ref bottom "Frequency / \\U"
endif
DoWindow graph_smith
if(!V_Flag)
smith_chart()
DoWindow/C graph_smith
make/o zsx, zsy
appendtograph/w=graph_smith zsy vs zsx
ModifyGraph/w=graph_smith lsize(zsy)=2,rgb(zsy)=(0,0,0)
endif
show_zin_sub()
end
Function CheckLogProc(cba) : CheckBoxControl
STRUCT WMCheckboxAction &cba
switch( cba.eventCode )
case 2: // mouse up
string win = cba.win
Variable checked = cba.checked
ModifyImage/w=$(win) $(win[6,8]) log=(checked)
ColorScale/C/N=text1 log=(checked)
break
case -1: // control being killed
break
endswitch
return 0
End
function show_zin_sub()
ControlInfo/w=graph_zin setvar0
variable dval = V_Value
wave/t feed
TextBox/w=graph_zin/C/N=text0/F=0/X=0/Y=0/E=2 "Feed#"+num2str(dval)+" : "+feed[dval]
wave/c zinp, zin
Zinp = Zin[dval][p]
NVAR NFreq1
make/o/N=(NFreq1) Refp
setscale d,0,1,"dB",Refp
variable z0 = numberbykey("z0", feed[dval])
Refp=20*log(max(cabs((Zinp-z0)/(Zinp+z0)),1e-10))
variable zz0 = 50
make/o/N=(numpnts(zinp)) zsx = smith_x(real(zinp)/zz0, imag(zinp)/zz0)
make/o/N=(numpnts(zinp)) zsy = smith_y(real(zinp)/zz0, imag(zinp)/zz0)
end
Function SetFeedProc(sva) : SetVariableControl
STRUCT WMSetVariableAction &sva
switch( sva.eventCode )
case 1: // mouse up
case 2: // Enter key
case 3: // Live update
show_zin_sub()
break
case -1: // control being killed
break
endswitch
return 0
End
* スミスチャート表示用ライブラリ [#z2586223]
上記のプログラムから呼び出して使っている。
SmithChart.ipf
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
// ====================== スミスチャート(イミタンスチャート)
// 使い方:
// wave/C zc // プロットしたい複素ウェーブ
// variable z0 = 50 // 基準インピーダンス
// make/N=(numpnts(zc)) zsx = smith_x(real(zc)/z0, imag(zc)/z0) // 反射率に直す
// make/N=(numpnts(zc)) zsy = smith_y(real(zc)/z0, imag(zc)/z0) // 反射率に直す
// smith_chart() // グリッドを表示
// appendtograph zsy vs zsx // トレースを追加
// ModifyGraph lsize(zsy)=2,rgb(zsy)=(0,0,0)
//
// あるいは:
// smith_display(zc, 50)
function smith_display(zc, z0)
wave/c zc
variable z0
string wname = nameofwave(zc)+"_smith"
make/N=(numpnts(zc)) $(wname+"x"), $(wname+"y")
wave wx = $(wname+"x")
wave wy = $(wname+"y")
wx = smith_x(real(zc)/z0, imag(zc)/z0)
wy = smith_y(real(zc)/z0, imag(zc)/z0)
smith_chart()
appendtograph wy vs wx
ModifyGraph lsize($(wname+"y"))=2,rgb($(wname+"y"))=(0,0,0)
end
// インピーダンスから反射率へ
function smith_x(x, y)
variable x, y
return (x^2+y^2-1)/((x+1)^2+y^2)
end
function smith_y(x, y)
variable x, y
return 2*y/((x+1)^2+y^2)
end
// 反射率からインピーダンスへ
function smith_ix(x, y)
variable x, y
return -(x^2+y^2-1)/((x-1)^2+y^2)
end
function smith_iy(x, y)
variable x, y
return -2*y/((x-1)^2+y^2)
end
function smith_csr_moved(s)
STRUCT WMWinHookStruct &s
if(s.eventCode!=7)
return 0
endif
if(0==cmpstr(s.traceName, "smith_gridy") || strlen(s.traceName)==0)
TextBox/C/N=text0/A=LB/X=0/Y=0/E=2/F=0/B=1 ""
return 0
endif
string csr = s.cursorName
variable h = hcsr($csr, s.winName)
variable v = vcsr($csr, s.winName)
variable ix = smith_ix(h, v)
variable iy = smith_iy(h, v)
string str
sprintf str, "reflection = %.1g\n%.3f%+.3fi", sqrt(h^2+v^2), ix, iy
TextBox/C/N=text0/A=LB/X=0/Y=0/E=2/F=0/B=1 str
end
// イミタンスチャートウィンドウの作成
function smith_chart()
// グリッドウェーブの作成
smith_chart_grid()
// グリッドの表示
wave smith_gridy, smith_gridx
Display smith_gridy vs smith_gridx
AppendToGraph smith_gridy vs smith_gridx
ModifyGraph margin=20,height={Plan,1,left,bottom}
ModifyGraph rgb(smith_gridy)=(65535,32768,32768),rgb(smith_gridy#1)=(32768,40777,65535)
ModifyGraph muloffset(smith_gridy#1)={-1,0}
ModifyGraph tick=3, noLabel=2, standoff=0, axRGB=(65535,65535,65535,0)
setwindow kwTopWin, hook(smith_hook)=smith_csr_moved, hookevents=4
// テキスト表示
SetDrawLayer UserFront
variable i
make/o smithx={-1.08,-0.6544,-0.3162,0.011,0.283,0.614,1.022,-1.011,-0.6654,0.6508,0.9632,0.9484,0.636,-0.658,-1.0294}
make/o smithy={0,0,0,0,0,0,0,0.4192,0.8382,0.772,0.3346,-0.397,-0.8346,-0.908,-0.4742}
make/o/t smiths={"0","0.2","0.5","1","2","5","∞","0.2j","0.5j","2j","5j","-5j","-2j","-0.5j","-0.2j"}
for(i=0; i<numpnts(smithx); i+=1)
SetDrawEnv xcoord= bottom,ycoord= left,textrgb= (65535,32768,32768)
DrawText smithx[i],smithy[i],smiths[i]
endfor
SetDrawEnv textrgb= (65535,32768,32768),textxjust= 2
DrawText 1,0,"Impedance"
make/o smithx={-1.084,-0.6508,-0.3088,0.0074,1.022,0.2426,0.5734,-1.011,-0.6838,0.5698,0.9338,0.9154,0.5734,-0.6874,-1.0184}
make/o smithy={-0.08,-0.08,-0.08,-0.08,-0.08,-0.08,-0.08,0.342,0.772,0.8382,0.408,-0.478,-0.8934,-0.8492,-0.397}
make/o/t smiths={"∞","5","2","1","0","0.5","0.2","5j","2j","0.5j","0.2j","-0.2j","-0.5j","-2j","-5j"}
for(i=0; i<numpnts(smithx); i+=1)
SetDrawEnv xcoord= bottom,ycoord= left,textrgb= (32768,40777,65535)
DrawText smithx[i],smithy[i],smiths[i]
endfor
SetDrawEnv textrgb= (32768,40777,65535)
DrawText -0.0386,0,"Admittance"
SetDrawEnv xcoord= bottom,ycoord= left,textrgb= (44253,29492,58982)
DrawText -0.0074,1.0146,"j"
SetDrawEnv xcoord= bottom,ycoord= left,textrgb= (44253,29492,58982)
DrawText -0.0184,-1.0698,"-j"
killwaves smithx, smithy, smiths
end
function smith_chart_grid()
make/o/N=2000 smith_gridx = nan, smith_gridy = nan
wave gx = smith_gridx
wave gy = smith_gridy
variable i = 0, j
// 等抵抗線
make/o smith_zr = {0, 0.2, 0.5, 1, 2, 5}
for(j=0; j<numpnts(smith_zr); j+=1)
gx = (i<=p && p<=i+101) ? (1-smith_x(smith_zr[j],0))/2*cos(2*pi*p/100)+(1+smith_x(smith_zr[j],0))/2 : gx
gy = (i<=p && p<=i+101) ? (1-smith_x(smith_zr[j],0))/2*sin(2*pi*p/100) : gy
i+= 101
gx[i]=nan; gy[i]=nan ; i+= 1
endfor
// 等インダクタンス線
make/o smith_zi = {-5, -2, -1, -0.5, -0.2, 0, 0.2, 0.5, 1, 2, 5}
make/o/N=100 smith_zr = smith_ix((p-50)/50, 0)
for(j=0; j<numpnts(smith_zi); j+=1)
gx = (i<=p && p<i+100) ? smith_x(smith_zr[p-i], smith_zi[j]) : gx
gy = (i<=p && p<i+100) ? smith_y(smith_zr[p-i], smith_zi[j]) : gy
i+= 100
gx[i]=nan; gy[i]=nan ; i+= 1
endfor
killwaves smith_zr, smith_zi
redimension/N=(i) smith_gridx, smith_gridy
end
Counter: 12809 (from 2010/06/03),
today: 2,
yesterday: 8