Optimization of resonant system based on Gaussian fit
- Driver:
Download script: harmonic_oscillator_fit.m
The target of the study is to tune a resonant system. For simplicity, the resonant system is a harmonic oscillator with eigenfrequency \(\omega_0\) and damping \(\gamma\) driven with force \(F\) at frequency \(\omega\). The amplitude of the oscillator is
\[a_{\rm harm}(\omega) = \frac{F}{\sqrt{(2\omega\omega_0\gamma)^2 + (\omega_0^2 - \omega)^2}} .\]
We assume the system as a black box with unknown resonant behavior. To capture the resonant feature, it is fitted against a Gaussian plus a linear function
\[a_{\rm fit}(\omega) = A \exp\left(-\frac{1}{2}\frac{(\omega-\tau)^2}{\sigma^2}\right) + B\omega + C .\]
The target is to tune \(F, \omega_0, \gamma\) such that the fitted amplitude is \(A = 10\), the resonance frequency is \(\tau = 2\) and the resonance width \(\sigma\) is as small as possible.
1jcm_optimizer_path = '<JCM_OPTIMIZER_PATH>';
2addpath(fullfile(jcm_optimizer_path, 'interface', 'matlab'));
3
4server = jcmoptimizer.Server();
5client = jcmoptimizer.Client(server.port);
6
7%Amplitude of a driven harmonic oscillator.
8function a = amplitude(omega, F, omega0, gamma)
9 a = F/sqrt((2*omega*omega0*gamma)^2 + (omega0^2 - omega^2)^2);
10end
11
12% Definition of the search domain to tune the oscillator
13design_space = { ...
14 struct('name', 'F', 'type', 'continuous', 'domain', [0.1, 40.0]), ...
15 struct('name', 'omega0', 'type', 'continuous', 'domain', [1.0, 4.0]), ...
16 struct('name', 'gamma', 'type', 'continuous', 'domain', [0.03, 0.3]) ...
17};
18
19%The amplitude is scaned for 10 different driving frequencies
20omegas = linspace(1,3,10);
21
22%Since the system depends on the driving frequency which is not a design parameter,
23%it is defined as an environment parameter.
24environment = { ...
25 struct('name', 'omega', 'type', 'variable', 'domain', [omegas(1), omegas(end)]) ...
26};
27
28 % Creation of the study object with study_id 'harmonic_oscillator_fit'
29study = client.create_study( ...
30 'design_space', design_space, ...
31 'environment', environment, ...
32 'driver','ActiveLearning',...
33 'name','Optimization of resonant system based on Gaussian fit',...
34 'study_id', 'harmonic_oscillator_fit');
35
36%definition of variables
37
38%The single-output Gaussian process is scanned over all omegas
39scan = struct();
40scan.type = "Scan";
41scan.name = "amplitude_scan";
42scan.output_dim = length(omegas);
43scan.scan_parameters = {"omega"};
44scan.scan_values = omegas.';
45scan.input_surrogate = "amplitude";
46
47%The result of the omega-scan is fitted to a Gaussian + linear expression with
48%amplitude A, resonance frequency tau, linear gradient B, and constant offset C.
49%The output are the fitted values and the mean-squared error (MSE).
50fit = struct();
51fit.type = "Fit";
52fit.name = "fit";
53fit.input = "amplitude_scan";
54fit.expression = "A*exp(-0.5*(omega-tau)^2/sigma^2) + B*omega + C";
55fit.output_names = {"A", "B", "C", "tau", "sigma", "MSE"};
56fit.output_dim = 6;
57fit.model_variables = {"omega"};
58fit.variable_values = omegas.';
59fit.initial_parameters = [1.0, 0.0, 0.0, 1.0, 0.5];
60
61%The expression that defines the loss function:
62expression = struct();
63expression.type = "Expression";
64expression.name = "loss";
65expression.expression = "(A-20)^2 + (tau - 2)^2 + sigma^2 + 0.001*MSE";
66
67%configuration of study
68study.configure( ...
69 'max_iter', 30, ...
70 'surrogates', { ...
71 ...A single-output Gaussian process learns the dependence of the amplitude on the
72 ...design and environment parameters.
73 struct('type', "GP", 'name', "amplitude", 'output_dim', 1, 'tolerance', 1e-12) ...
74 }, ...
75 'variables', {scan, fit, expression}, ...
76 'objectives', { ...
77 ...The only objective of the study is to minimize the loss.
78 struct("type", "Minimizer", "variable", "loss"), ...
79 }, ...
80 'acquisition_optimizer', struct( ...
81 ...Sample computation based on fits is more expensive. In this case
82 ...advanced sample computation is usually too laborious.
83 'compute_suggestion_in_advance', false ...
84 ) ...
85);
86
87% Evaluation of the black-box function for specified design parameters
88function observation = evaluate(study, sample)
89
90 pause(2); % make objective expensive
91 observation = study.new_observation();
92 %The harmonic-oscillator amplitude is evaluated for all omega values and the
93 %observed values are used as training input for the Gaussian process "amplitude"
94 for i = 1:length(omegas)
95 observation.add(amplitude(omegas(i), sample.F, sample.omega0, sample.gamma), ...
96 'environment_value', {omegas(i)}, 'model_name', "amplitude");
97 end
98
99end
100
101% Run the minimization
102study.set_evaluator(@evaluate);
103study.run();
104
105
106% Print result
107best = study.get_state("driver.best_sample");
108fprintf("Best design parameters: F=%f, omega0=%f, gamma=%f\n", ...
109 best.F, best.omega0, best.gamma);
110fprintf(['Objective: (A-20)^2 + (tau - 2)^2 + sigma^2 + 0.001*MSE = ', ...
111 '%.3f\n'], study.get_state('driver.min_objective'));