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

../../_images/her_ex40_model.png

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

her_ex40_parametric.py
  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

../../_images/her_ex40_result.png

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.