2024年12月17日火曜日

openEMSを再び(4)

 

以前ギブアップしていたopenEMSにもう一度チャレンジする。


ちゃんとSパラを出力する。
TutorialのPatch_Antenna_Phased_Array.mでSパラを出力していたのでよくよく見てみると、AddLumpedPortをするときにexciteするポートを替えながら、都度シミュレーションしているみたい。よくよく考えたらネットアナでの測定もそうやる(ていうか装置が勝手にそうやってる)よね。
で、コードはこうなる(計算時間を短くするために周波数範囲を狭くした)。
  1. % tutorial for hyp2mat - capacitor in a microstrip.
  2. %
  3. % run from openems matlab command prompt
  4. % See hyp2mat(1) - convert hyperlynx files to matlab scripts.
  5. % (C) 2011,2012 Thorsten Liebig <thorsten.liebig@gmx.de>
  6. % Copyright 2012 Koen De Vleeschauwer.
  7. %
  8. % This file is part of hyp2mat.
  9. %
  10. % This program is free software: you can redistribute it and/or modify
  11. % it under the terms of the GNU General Public License as published by
  12. % the Free Software Foundation, either version 3 of the License, or
  13. % (at your option) any later version.
  14. %
  15. % This program is distributed in the hope that it will be useful,
  16. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. % GNU General Public License for more details.
  19. %
  20. % You should have received a copy of the GNU General Public License
  21. % along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. close all
  23. clear
  24. clc
  25. function port_return=Execute_main(Sim_Path,f_max,show_structure,port_active)
  26.   % initialize
  27.   physical_constants;
  28.   %f_max = 1e9;
  29.   % Importing printed circuit board
  30.   CSX = InitCSX();
  31.   CSX = ImportHyperLynx(CSX, 'small_loop_antenna.hyp');
  32.   % Adding a component
  33.   [pad1_material, pad1_start, pad1_stop] = GetHyperLynxPort(CSX, 'C1.1');
  34.   [pad2_material, pad2_start, pad2_stop] = GetHyperLynxPort(CSX, 'C1.2');
  35.   c1_height = pad1_stop - pad1_start;
  36.   c1_start = [(pad1_start(1)+pad1_stop(1))/2, pad1_start(2), pad1_start(3)];
  37.   c1_stop = [(pad2_start(1)+pad2_stop(1))/2, pad2_stop(2), pad2_stop(3)+c1_height];
  38.   CSX = AddLumpedElement( CSX, 'Capacitor', 0, 'Caps', 1, 'C', 1e-12);
  39.   CSX = AddBox( CSX, 'Capacitor', 0, c1_start, c1_stop );
  40.   % Adding excitation and load
  41.   [port1_material, port1_start, port1_stop] = GetHyperLynxPort(CSX, 'TP1.1');
  42.   [gnd1_material, gnd1_start, gnd1_stop] = GetHyperLynxPort(CSX, 'TP3.1');
  43.   [port2_material, port2_start, port2_stop] = GetHyperLynxPort(CSX, 'TP2.1');
  44.   [gnd2_material, gnd2_start, gnd2_stop] = GetHyperLynxPort(CSX, 'TP4.1');
  45.   if(port_active==1)
  46.     [CSX, port{1}] = AddLumpedPort( CSX, 999, 1, 50, gnd1_start, port1_stop, [0 0 -1], true);
  47.     [CSX, port{2}] = AddLumpedPort( CSX, 999, 2, 50, gnd2_start, port2_stop, [0 0 -1]);
  48.   else
  49.     [CSX, port{1}] = AddLumpedPort( CSX, 999, 1, 50, gnd1_start, port1_stop, [0 0 -1]);
  50.     [CSX, port{2}] = AddLumpedPort( CSX, 999, 2, 50, gnd2_start, port2_stop, [0 0 -1], true);
  51.   endif
  52.   % Setting up a mesh
  53.   unit = GetUnits(CSX);
  54.   substrate_epr = GetEpsilon(CSX);
  55.   resolution = c0 / f_max / sqrt(substrate_epr) / unit / 25;
  56.   AirBox = c0 / f_max / unit / 25;
  57.   z_top = port1_start(3);
  58.   z_bottom = gnd1_start(3);
  59.   z_middle = (z_top+z_bottom)/2;
  60.   mesh.x = [];
  61.   mesh.y = [];
  62.   mesh.z = [ z_middle ];
  63.   mesh = DetectEdges(CSX, mesh);
  64.   mesh.x = [min(mesh.x)-AirBox max(mesh.x)+AirBox mesh.x];
  65.   mesh.y = [min(mesh.y)-AirBox max(mesh.y)+AirBox mesh.y];
  66.   mesh.z = [min(mesh.z)-AirBox max(mesh.z)+2*AirBox mesh.z];
  67.   %mesh = SmoothMesh(mesh, resolution);
  68.   mesh = SmoothMesh(mesh, resolution, 'algorithm', [ 1 ]);
  69.   % Setting boundary conditions
  70.   FDTD = InitFDTD();
  71.   FDTD = SetGaussExcite(FDTD, f_max/2, f_max/2);
  72.   BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'};
  73.   FDTD = SetBoundaryCond(FDTD, BC );
  74.   mesh = AddPML(mesh, 8);
  75.   CSX = DefineRectGrid(CSX, unit, mesh);
  76.   % Simulation
  77.   %Sim_Path = 'tmp';
  78.   Sim_CSX = 'msl.xml';
  79.   disp([ 'Estimated simulation runtime: 6500 timesteps' ]); % inform user this may take a while...
  80.   WriteOpenEMS([Sim_Path '/' Sim_CSX], FDTD, CSX);
  81.   if(show_structure>0)
  82.     CSXGeomPlot([Sim_Path '/' Sim_CSX]);
  83.   endif
  84.     RunOpenEMS(Sim_Path, Sim_CSX);
  85.   port_return=port;
  86. endfunction
  87. f_max = 1e9;
  88. Sim_Path1='tmp1'
  89. [status, message, messageid] = rmdir(Sim_Path1, 's'); % clear previous directory
  90. [status, message, messageid] = mkdir(Sim_Path1 ); % create empty simulation folder
  91. Sim_Path2='tmp2'
  92. [status, message, messageid] = rmdir(Sim_Path2, 's'); % clear previous directory
  93. [status, message, messageid] = mkdir(Sim_Path2 ); % create empty simulation folder
  94. port=Execute_main(Sim_Path1,f_max,1,1)
  95. % Calculating the s-parameters
  96. f = linspace( 100e6, f_max, 1601 );
  97. port = calcPort( port, Sim_Path1, f, 'RefImpedance', 50);
  98. s11 = port{1}.uf.ref./ port{1}.uf.inc;
  99. s21 = port{2}.uf.ref./ port{1}.uf.inc;
  100. port=Execute_main(Sim_Path2,f_max,0,2)
  101. % Calculating the s-parameters
  102. port = calcPort( port, Sim_Path2, f, 'RefImpedance', 50);
  103. s12 = port{1}.uf.ref./ port{2}.uf.inc;
  104. s22 = port{2}.uf.ref./ port{2}.uf.inc;
  105. s_param=[];
  106. s_param(1,1,:) = s11;
  107. s_param(1,2,:) = s12;
  108. s_param(2,1,:) = s21;
  109. s_param(2,2,:) = s22;
  110. write_touchstone('s',f,s_param,'out.s2p');
  111. close all
  112. semilogx(f/1e6,20*log10(abs(s11)),'k-','LineWidth',2);
  113. hold on;
  114. grid on;
  115. semilogx(f/1e6,20*log10(abs(s21)),'r--','LineWidth',2);
  116. legend('S_{11}','S_{21}');
  117. ylabel('S-Parameter (dB)','FontSize',12);
  118. xlabel('frequency (GHz) \rightarrow','FontSize',12);
  119. ylim([-80 10]);
  120. print('sparam.png', '-dpng');
  121. % not truncated
いちおう、今回の解析に使ったレイアウトファイルも載せておく。
  1. {VERSION=2.14}
  2. {UNITS=ENGLISH LENGTH}
  3. {BOARD "small_loop_antenna.kicad_pcb"
  4.   (PERIMETER_SEGMENT X1=6.100000000 Y1=4.050000000 X2=4.900000000 Y2=4.050000000)
  5.   (PERIMETER_SEGMENT X1=4.900000000 Y1=4.050000000 X2=4.900000000 Y2=2.850000000)
  6.   (PERIMETER_SEGMENT X1=4.900000000 Y1=2.850000000 X2=6.100000000 Y2=2.850000000)
  7.   (PERIMETER_SEGMENT X1=6.100000000 Y1=2.850000000 X2=6.100000000 Y2=4.050000000)
  8. }
  9. {STACKUP
  10.   (SIGNAL T=0.00137795 P=0 C=1.724e-08 L="F.Cu" M=COPPER)
  11.   (DIELECTRIC T=0.03937 C=4.4 L="DE_F.Cu" M="FR4")
  12.   (SIGNAL T=0.00137795 P=0 C=1.724e-08 L="B.Cu" M=COPPER)
  13. }
  14. {DEVICES
  15.   (? REF="TP4" L="B.Cu")
  16.   (? REF="TP3" L="B.Cu")
  17.   (? REF="TP2" L="F.Cu")
  18.   (? REF="TP1" L="F.Cu")
  19.   (? REF="C1" L="F.Cu")
  20. }
  21. {PADSTACK=0, 0.000000000
  22.   ("B.Cu", 1, 0.039370079, 0.039370079, 0.0, M)
  23. }
  24. {PADSTACK=1, 0.000000000
  25.   ("F.Cu", 1, 0.039370079, 0.039370079, 180.0, M)
  26. }
  27. {PADSTACK=2, 0.000000000
  28.   ("F.Cu", 2, 0.022047244, 0.024409449, 180.0, M)
  29. }
  30. {NET="GND"
  31.   (PIN X=5.4500000000 Y=4.0000000000 R="TP4.1" P=0)
  32.   (PIN X=5.5500000000 Y=4.0000000000 R="TP3.1" P=0)
  33.   (SEG X1=5.4500000000 Y1=4.0000000000 X2=5.5500000000 Y2=4.0000000000 W=0.0393700787 L="B.Cu")
  34. }
  35. {NET="Net-(C1-Pad1)"
  36.   (PIN X=5.5500000000 Y=4.0000000000 R="TP1.1" P=1)
  37.   (PIN X=5.4122047244 Y=3.9000000000 R="C1.1" P=2)
  38.   (SEG X1=5.4122047244 Y1=3.8622047244 X2=5.4000000000 Y2=3.8500000000 W=0.0236220472 L="F.Cu")
  39.   (SEG X1=5.4122047244 Y1=3.9000000000 X2=5.4122047244 Y2=3.8622047244 W=0.0236220472 L="F.Cu")
  40.   (SEG X1=5.9000000000 Y1=3.7500000000 X2=5.6000000000 Y2=3.7500000000 W=0.0393700787 L="F.Cu")
  41.   (SEG X1=5.6000000000 Y1=3.7500000000 X2=5.5500000000 Y2=3.8000000000 W=0.0393700787 L="F.Cu")
  42.   (SEG X1=6.0000000000 Y1=3.6500000000 X2=5.9000000000 Y2=3.7500000000 W=0.0393700787 L="F.Cu")
  43.   (SEG X1=6.0000000000 Y1=3.1000000000 X2=6.0000000000 Y2=3.6500000000 W=0.0393700787 L="F.Cu")
  44.   (SEG X1=5.5500000000 Y1=3.8000000000 X2=5.5500000000 Y2=4.0000000000 W=0.0393700787 L="F.Cu")
  45.   (SEG X1=5.4000000000 Y1=3.8000000000 X2=5.4000000000 Y2=3.8500000000 W=0.0393700787 L="F.Cu")
  46.   (SEG X1=5.3500000000 Y1=3.7500000000 X2=5.4000000000 Y2=3.8000000000 W=0.0393700787 L="F.Cu")
  47.   (SEG X1=5.1000000000 Y1=3.7500000000 X2=5.3500000000 Y2=3.7500000000 W=0.0393700787 L="F.Cu")
  48.   (SEG X1=5.0000000000 Y1=3.1000000000 X2=5.0000000000 Y2=3.6500000000 W=0.0393700787 L="F.Cu")
  49.   (SEG X1=5.0000000000 Y1=3.6500000000 X2=5.1000000000 Y2=3.7500000000 W=0.0393700787 L="F.Cu")
  50.   (SEG X1=5.1000000000 Y1=3.0000000000 X2=5.0000000000 Y2=3.1000000000 W=0.0393700787 L="F.Cu")
  51.   (SEG X1=5.9000000000 Y1=3.0000000000 X2=5.1000000000 Y2=3.0000000000 W=0.0393700787 L="F.Cu")
  52.   (SEG X1=6.0000000000 Y1=3.1000000000 X2=5.9000000000 Y2=3.0000000000 W=0.0393700787 L="F.Cu")
  53. }
  54. {NET="Net-(C1-Pad2)"
  55.   (PIN X=5.4500000000 Y=4.0000000000 R="TP2.1" P=1)
  56.   (PIN X=5.4500000000 Y=3.9000000000 R="C1.2" P=2)
  57.   (SEG X1=5.4500000000 Y1=3.9000000000 X2=5.4500000000 Y2=4.0000000000 W=0.0236220472 L="F.Cu")
  58. }
で、実行すると、1portあたり約1時間の計2時間で終了。いちおう、出力はこうなる。
で、出来上がったSパラを見てみる。が、Octaveでうまいこと表示させりゃいいんだけど、ここで、なぜかPythonに戻って、scikit-rfで表示する。コードはこんな感じ。
  1. import numpy as np
  2. import skrf as rf
  3. import matplotlib.pyplot as plt
  4. import scipy
  5.  
  6. def main():
  7.         
  8.     ANT1 = rf.Network('out.s2p')
  9.     ANT1.name='ANT1'
  10.     freq=ANT1.frequency
  11.     tl_media = rf.DefinedGammaZ0(freq, z0=50)
  12.     gnd = rf.Circuit.Ground(freq, name='gnd')
  13.     port1 = rf.Circuit.Port(freq, name='port1', z0=50)
  14.     port2 = rf.Circuit.Port(freq, name='port2', z0=50)
  15.     cnx=[[(port1,0),(ANT1,0)],
  16.          [(ANT1,1),(port2,0)],
  17.          [(gnd,0)]]
  18.     cir=rf.Circuit(cnx)
  19.     ntw=cir.network
  20.     ntw.frequency.unit='MHz'
  21.     fig=plt.figure()
  22.     ax1=fig.add_subplot(2,2,1)
  23.     ntw.plot_s_smith(ax=ax1,m=0, n=0, lw=2)
  24.     ax2_1=fig.add_subplot(2,2,2)
  25.     ax2_2=ax2_1.twinx()
  26.     ntw.plot_s_db(ax=ax2_1,m=1, n=0, lw=2, show_legend=False)
  27.     ntw.plot_s_vswr(ax=ax2_2,m=0, n=0, lw=2, show_legend=False, color='orangered')
  28.     ax2_2.set_ylim(1,6)
  29.     handler1, label1 = ax2_1.get_legend_handles_labels()
  30.     handler2, label2 = ax2_2.get_legend_handles_labels()
  31.     ax2_1.legend(handler1 + handler2, label1 + label2, loc=2, borderaxespad=0.)
  32.     ax3=fig.add_subplot(2,2,3)
  33.     ntw.plot_s_db(ax=ax3,m=0, n=1, lw=2)
  34.     ax4=fig.add_subplot(2,2,4)
  35.     ntw.plot_s_smith(ax=ax4,m=1, n=1, lw=2)
  36.     fig.tight_layout()
  37.     plt.show()
  38. if __name__ == "__main__":
  39.     main()
で、実行すると、
たぶん、いけてるんじゃないかな。

0 件のコメント:

コメントを投稿