Model Optimization
ParamRF allows you to easily optimize model parameters to meet a given design goal. In this example, we design a simple low-pass filter using SciPy’s L-BFGS-B algorithm.
Defining the Model
Instead of passing unconstrained floats, we can pass Bounded parameters to specify interval constraints on our values:
import pmrf as prf
from pmrf.models import ShuntCapacitor, Inductor
C1 = ShuntCapacitor(C=prf.Bounded(1.0, 100.0, scale=1e-12))
L1 = Inductor(L=prf.Bounded(1.0, 100.0, scale=1e-9))
C2 = ShuntCapacitor(C=prf.Bounded(1.0, 100.0, scale=1e-12))
lpf = C1 ** L1 ** C2
It is best practice to apply a scaling factor to our values in order to keep the optimization numerically stable. To create fixed parameters and apply more complicated constraints, parameters re-exported from pmrf.parameters can be used e.g. pmrf.Fixed() and pmrf.Constrained().
Running the Optimizer
Next, we define our design goals. In this case, we want to ensure good matching (low reflection) across our passband. We can use the Goal evaluator and pass it to the minimize() function alongside our frequency range:
from pmrf.evaluators import Goal
from pmrf.optimize import minimize, ScipyMinimize
match_goal = Goal('s11_db', '<', -20)
passband = prf.Frequency(100, 500, 101, 'MHz')
result = minimize(match_goal, lpf, passband, solver=ScipyMinimize(method='L-BFGS-B'))
The minimize() function returns an OptimizeResult object containing the optimized model and solver metrics. We can extract this newly fitted model to verify our results and print its parameters:
import matplotlib.pyplot as plt
import numpy as np
optimized_lpf = result.model
print("Optimized Parameters:")
print(optimized_lpf.named_params())
plt.plot(passband.f, -20.0 * np.ones_like(passband.f), color='black', linestyle='--', label='target')
lpf.plot_s_db(passband, m=0, n=0, label='initial')
optimized_lpf.plot_s_db(passband, m=0, n=0, label='optimized')
plt.title('Initial vs. Optimized S11')
For more complex designs, the minimize() function can accept a list of multiple goals, and you can apply masks to evaluate different features across different frequency bands. Custom loss functions can also be specified in losses.
For even more complicated designs, AbstractEvaluator can be overridden directly.
Note that ParamRF also provides convenience functions for fitting models directly to data in fitting(). See the tutorial for a detailed guide.