· 

Pythonで回路計算(6)

定数を、ちょこちょこ変えながら確認するのって大変です、、、1ポートだとあっち回してこっち回してが通用しますが、2ポートだとあっちをこっちに回すとこっちはあっちに動いて、、、ってなってもう無理ーってなります。いや実物で測定しながらやるのよりは全然いいですけど。まぁ最後は実物でちょこちょこやらんといかんのですが。

ここによると、scipyの最適化ライブラリで値を出すことが示されています。が、うちではexampleの通りでは動かなかったので、同じくscipyの最適化ライブラリの別のアルゴリズムだと動いたのでその記録、、、ていうかいつも通り結論だけ。

引数が(値を最適化したい)変数だけで、最適化状態と計算結果との差異を出す関数(ゴールに近いほど値が小さくなり、遠いほど値が大きくなるような関数)を定義します。うちではget_err(x)です。このget_errを最小化するような変数xを探索してくれます。

import numpy as np
import skrf as rf
import matplotlib.pyplot as plt
import scipy

def Calc_Network(FIL1,C1,C2,L1,L2,gnd,port1,port2):
    cnx = [
        [(port1, 0), (C1, 0)],
        [(C1, 1), (L1, 0), (FIL1, 0)],
        [(FIL1, 1), (L2, 0), (C2, 0)],
        [(port2, 0), (C2, 1)],
        [(gnd, 0), (L1, 1), (L2, 1)]
    ]
    cir = rf.Circuit(cnx)
    ntw = cir.network
    return ntw

FIL1 = rf.Network('out.s2p')
FIL1.name='FIL1'

freq=FIL1.frequency
tl_media = rf.DefinedGammaZ0(freq, z0=50)
gnd = rf.Circuit.Ground(freq, name='gnd')
port1 = rf.Circuit.Port(freq, name='port1', z0=50)
port2 = rf.Circuit.Port(freq, name='port2', z0=50)

C1_def=100e-12
C2_def=100e-12
L1_def=100e-9
L2_def=100e-9
#C1_def=9e-12
#C2_def=9e-12
#L1_def=25e-9
#L2_def=25e-9
x0=(C1_def,C2_def,L1_def,L2_def)

f_range_lower=314.8e6
f_range_upper=315.2e6
vswr_max=1.5

def matching_network(C1_val,C2_val,L1_val,L2_val):
    C1 = tl_media.capacitor(C1_val, name='C1')
    C2 = tl_media.capacitor(C2_val, name='C2')
    L1 = tl_media.inductor(L1_val, name='L1')
    L2 = tl_media.inductor(L2_val, name='L2')
    ntw=Calc_Network(FIL1,C1,C2,L1,L2,gnd,port1,port2)
    return ntw

def get_err(x):
    ntw=matching_network(*x)
    irange=np.where((ntw.f>=f_range_lower)&(ntw.f<=f_range_upper))
    vswr1=ntw.s_vswr[irange,0,0]
    vswr2=ntw.s_vswr[irange,1,1]
    tgt=np.ones_like(vswr1)*vswr_max
    eval1=vswr1-tgt
    eval2=vswr2-tgt
    err1=np.where(eval1<0,0,eval1)
    err2=np.where(eval2<0,0,eval2)
    return (np.sum(err1)+np.sum(err2))

res=scipy.optimize.fmin(get_err,x0)
print(res)
res=scipy.optimize.fmin(get_err,res)
print(res)

ntw=matching_network(*res)

fig=plt.figure()

ax1=fig.add_subplot(2,2,1)
ntw.plot_s_smith(ax=ax1,m=0, n=0, lw=2)

ax2_1=fig.add_subplot(2,2,2)
ax2_2=ax2_1.twinx()
ntw.plot_s_db(ax=ax2_1,m=1, n=0, lw=2, show_legend=False)
ntw.plot_s_vswr(ax=ax2_2,m=0, n=0, lw=2, show_legend=False, color='orangered')
ax2_2.set_ylim(1,6)
handler1, label1 = ax2_1.get_legend_handles_labels()
handler2, label2 = ax2_2.get_legend_handles_labels()
ax2_1.legend(handler1 + handler2, label1 + label2, loc=2, borderaxespad=0.)

ax3=fig.add_subplot(2,2,3)
ntw.plot_s_db(ax=ax3,m=0, n=1, lw=2)

ax4=fig.add_subplot(2,2,4)
ntw.plot_s_smith(ax=ax4,m=1, n=1, lw=2)

fig.tight_layout()
plt.show()

ちょっと雑然としていてかつ長いですが、たったこれだけで、最適化してくれるんだからいいですよね、、、

 

今回、ちょっと帯域幅に欲を出しています。ちょっとくらいミスマッチが出てもちょっと帯域を広げたいときってありますよね。

なんとなく1回では収束しなかったので、2回最適化しています。この辺の設定も決められるんだろうけど、後で調べるかもしれない。

出力はこんなのが出ます。

 

Optimization terminated successfully.

         Current function value: 244.303714

         Iterations: 210

         Function evaluations: 355

[2.62032969e-10 8.35302699e-12 5.23056775e-08 2.62671216e-08]

Optimization terminated successfully.

         Current function value: 70.789551

         Iterations: 341

         Function evaluations: 580

[1.09647196e-11 1.09630758e-11 2.69960441e-08 2.69959050e-08]

波形はいい感じです。まぁ、最適化しても実際の部品でその値そのものは実現できないし、実測するとちょっと違ったりするので、参考ですよね。

これだけのことをたったの89行でできるってのが、人類の進歩(大げさ)を感じるとともに、プログラミングが専門家のものではなくなった感じがする。ソフトとしての体裁なんか不要で、ひとりひとりが思いついたことをちょちょっと調べてすぐ実現できるのが今の時代にマッチしているんだろうなー。