Resonant frequency of a circular patch antenna
Using Femtet’s electromagnetic wave analysis solver, we explain an example of setting the resonant frequency of a circular patch antenna to a specific value.
Sample File
Note
Keep the sample project
open in Femtet, and double-click on the sample code
to execute it.
Note
For details on the FEM problem, please refer to FemtetHelp / Examples / Electromagnetic Wave Analysis / Example 40.
Design Variables
Appearance of the Model
Variable Name |
Description |
|---|---|
ant_r |
Radius of the circular antenna |
sx |
Size of the substrate |
xf |
Power port location |
Objective Function
Resonant frequency giving the first peak of S(1,1)
Sample Code
1"""Single-objective optimization: Resonant frequency of a circular patch antenna
2
3Using Femtet’s electromagnetic wave analysis solver,
4we explain an example of setting the resonant frequency
5of a circular patch antenna to a specific value.
6
7Corresponding project: her_ex40_parametric.femprj
8"""
9from time import sleep
10
11import numpy as np
12from scipy.signal import find_peaks
13from tqdm import tqdm
14
15from pyfemtet.opt.exceptions import SolveError
16from pyfemtet.opt import FemtetInterface, OptunaOptimizer, FEMOpt
17from pyfemtet.opt.optimizer import PoFBoTorchSampler, PartialOptimizeACQFConfig
18
19
20class SParameterCalculator:
21 """Calculating S-parameters and resonance frequencies."""
22
23 def __init__(self):
24 self.freq = []
25 self.S = []
26 self.interpolated_function = None
27 self.resonance_frequency = None
28 self.minimum_S = None
29
30 def _get_freq_and_S_parameter(self, Femtet):
31 """Obtain the relationship between frequency and S-parameter"""
32
33 Gogh = Femtet.Gogh
34
35 freq_list = []
36 dB_S_list = []
37 for mode in tqdm(range(Gogh.Hertz.nMode), 'Obtain frequency and S-parameter.'):
38 # mode setting
39 Gogh.Hertz.Mode = mode
40 sleep(0.1)
41
42 # Obtain frequency
43 freq = Gogh.Hertz.GetFreq().Real
44
45 # Obtain S(1, 1)
46 comp_S = Gogh.Hertz.GetSMatrix(0, 0)
47 norm = np.linalg.norm((comp_S.Real, comp_S.Imag))
48 dB_S = 20 * np.log10(norm)
49
50 # Save them
51 freq_list.append(freq)
52 dB_S_list.append(dB_S)
53
54 self.freq = freq_list
55 self.S = dB_S_list
56
57 def _calc_resonance_frequency(self):
58 """Compute the frequency that gives the first peak for S-parameter."""
59 peaks, _ = find_peaks(-np.array(self.S), height=None, threshold=None, distance=None, prominence=0.5, width=None, wlen=None, rel_height=0.5, plateau_size=None)
60 if len(peaks) == 0:
61 raise SolveError('No S(1,1) peaks detected.')
62 self.resonance_frequency = self.freq[peaks[0]]
63 self.minimum_S = self.S[peaks[0]]
64
65 def get_resonance_frequency(self, Femtet):
66 """Calculate the resonant frequency.
67
68 Note:
69 The objective or constraint function should take Femtet
70 as its first argument and return a float as the output.
71
72 Params:
73 Femtet: This is an instance for manipulating Femtet with macros. For detailed information, please refer to "Femtet Macro Help".
74
75 Returns:
76 float: A resonance frequency of the antenna.
77 """
78 self._get_freq_and_S_parameter(Femtet)
79 self._calc_resonance_frequency()
80 return self.resonance_frequency # unit: Hz
81
82
83def antenna_is_smaller_than_substrate(Femtet, opt):
84 """Calculate the relationship between antenna size and board size.
85
86 This function is used to constrain the model
87 from breaking down while changing parameters.
88
89 Returns:
90 float: Difference between the substrate size and antenna size. Must be equal to or grater than 1 mm.
91 """
92 params = opt.get_parameter()
93 r = params['antenna_radius']
94 w = params['substrate_w']
95 return w / 2 - r # unit: mm
96
97
98def port_is_inside_antenna(Femtet, opt):
99 """Calculate the relationship between the feed port location and antenna size."""
100 params = opt.get_parameter()
101 r = params['antenna_radius']
102 x = params['port_x']
103 return r - x # unit: mm. Must be equal to or grater than 1 mm.
104
105
106if __name__ == '__main__':
107 # Initialize the object for calculating frequency characteristics.
108 s = SParameterCalculator()
109
110 # Initialize the numerical optimization problem.
111 # (determine the optimization method)
112 opt = OptunaOptimizer(
113 sampler_class=PoFBoTorchSampler,
114 sampler_kwargs=dict(
115 n_startup_trials=4,
116 partial_optimize_acqf_kwargs=PartialOptimizeACQFConfig(
117 timeout_sec=30.,
118 ),
119 )
120 )
121
122 # Connect to Femtet (Disable GUI result to reduce the rendering load when switching modes.)
123 fem = FemtetInterface(
124 open_result_with_gui=False
125 )
126
127 # Initialize the FEMOpt object.
128 # (establish connection between the optimization problem and Femtet)
129 femopt = FEMOpt(fem=fem, opt=opt)
130
131 # Add design variables to the optimization problem.
132 # (Specify the variables registered in the femprj file.)
133 femopt.add_parameter('antenna_radius', 10, 5, 20)
134 femopt.add_parameter('substrate_w', 50, 40, 60)
135 femopt.add_parameter('port_x', 5, 1, 20)
136
137 # Add the constraint function to the optimization problem.
138 femopt.add_constraint(fun=antenna_is_smaller_than_substrate, name='antenna and substrate clearance', lower_bound=1, args=(opt,))
139 femopt.add_constraint(fun=port_is_inside_antenna, name='antenna and port clearance', lower_bound=1, args=(opt,))
140
141 # Add the objective function to the optimization problem.
142 # The target frequency is 3.3 GHz.
143 femopt.add_objective(fun=s.get_resonance_frequency, name='first resonant frequency(Hz)', direction=3.3 * 1e9)
144
145 femopt.set_random_seed(42)
146 femopt.optimize(n_trials=10)
Execution Result of the Sample Code
Execution result of her_ex40_parametric.py. The horizontal axis is the number of iterations, and the vertical axis is the resonant frequency.
After 10 iterations, the the best frequency was calculated to be 3.29 GHz.
Note
Results may vary slightly depending on the versions of Femtet, PyFemtet, and the optimization engine it depends on.