1// ExamplePidAdvisor shows the usage of the PID advisor
2public static void ExamplePidAdvisor(string dev = DEFAULT_DEVICE) // Timeout(40000)
3{
4 ziDotNET daq = connect(dev);
5 if (!hasOption(daq, dev, "PID"))
6 {
7 daq.disconnect();
8 Skip("Not supported by device.");
9 }
10
11 resetDeviceToDefault(daq, dev);
12
13 daq.setInt(String.Format("/{0}/demods/*/rate", dev), 0);
14 daq.setInt(String.Format("/{0}/demods/*/trigger", dev), 0);
15 daq.setInt(String.Format("/{0}/sigouts/*/enables/*", dev), 0);
16 daq.setInt(String.Format("/{0}/demods/*/enable", dev), 0);
17 daq.setInt(String.Format("/{0}/scopes/*/enable", dev), 0);
18
19 // now the settings relevant to this experiment
20 // PID configuration.
21 double target_bw = 10e3; // Target bandwidth (Hz).
22 int pid_input = 3; // PID input (3 = Demod phase).
23 int pid_input_channel = 0; // Demodulator number.
24 double setpoint = 0.0; // Phase setpoint.
25 int phase_unwrap = 1; //
26 int pid_output = 2; // PID output (2 = oscillator frequency).
27 int pid_output_channel = 0; // The index of the oscillator controlled by PID.
28 double pid_center_frequency = 500e3; // (Hz).
29 double pid_limits = 10e3; // (Hz).
30
31
32 if (!isDeviceFamily(daq, dev, "HF2"))
33 {
34 daq.setInt(String.Format("/{0}/pids/0/input", dev), pid_input);
35 daq.setInt(String.Format("/{0}/pids/0/inputchannel", dev), pid_input_channel);
36 daq.setDouble(String.Format("/{0}/pids/0/setpoint", dev), setpoint);
37 daq.setInt(String.Format("/{0}/pids/0/output", dev), pid_output);
38 daq.setInt(String.Format("/{0}/pids/0/outputchannel", dev), pid_output_channel);
39 daq.setDouble(String.Format("/{0}/pids/0/center", dev), pid_center_frequency);
40 daq.setInt(String.Format("/{0}/pids/0/enable", dev), 0);
41 daq.setInt(String.Format("/{0}/pids/0/phaseunwrap", dev), phase_unwrap);
42 daq.setDouble(String.Format("/{0}/pids/0/limitlower", dev), -pid_limits);
43 daq.setDouble(String.Format("/{0}/pids/0/limitupper", dev), pid_limits);
44 }
45 // Perform a global synchronisation between the device and the data server:
46 // Ensure that the settings have taken effect on the device before starting
47 // the pidAdvisor.
48 daq.sync();
49
50 // set up PID Advisor
51 ziModule pidAdvisor = daq.pidAdvisor();
52
53 // Turn off auto-calc on param change. Enabled
54 // auto calculation can be used to automatically
55 // update response data based on user input.
56 pidAdvisor.setInt("auto", 0);
57 pidAdvisor.setByte("device", dev);
58 pidAdvisor.setDouble("pid/targetbw", target_bw);
59
60 // PID advising mode (bit coded)
61 // bit 0: optimize/tune P
62 // bit 1: optimize/tune I
63 // bit 2: optimize/tune D
64 // Example: mode = 7: Optimize/tune PID
65 pidAdvisor.setInt("pid/mode", 7);
66
67 // PID index to use (first PID of device: 0)
68 pidAdvisor.setInt("index", 0);
69
70 // DUT model
71 // source = 1: Lowpass first order
72 // source = 2: Lowpass second order
73 // source = 3: Resonator frequency
74 // source = 4: Internal PLL
75 // source = 5: VCO
76 // source = 6: Resonator amplitude
77 pidAdvisor.setInt("dut/source", 4);
78
79 if (isDeviceFamily(daq, dev, "HF2"))
80 {
81 // Since the PLL and PID are 2 separate hardware units on the
82 // device, we need to additionally specify that the PID
83 // Advisor should model the HF2's PLL.
84 pidAdvisor.setByte("pid/type", "pll");
85 }
86
87 // IO Delay of the feedback system describing the earliest response
88 // for a step change. This parameter does not affect the shape of
89 // the DUT transfer function
90 pidAdvisor.setDouble("dut/delay", 0.0);
91
92 // Other DUT parameters (not required for the internal PLL model)
93 // pidAdvisor.setDouble('dut/gain', 1.0)
94 // pidAdvisor.setDouble('dut/bw', 1000)
95 // pidAdvisor.setDouble('dut/fcenter', 15e6)
96 // pidAdvisor.setDouble('dut/damping', 0.1)
97 // pidAdvisor.setDouble('dut/q', 10e3)
98
99 // Start values for the PID optimization. Zero
100 // values will imitate a guess. Other values can be
101 // used as hints for the optimization process.
102 pidAdvisor.setDouble("pid/p", 0);
103 pidAdvisor.setDouble("pid/i", 0);
104 pidAdvisor.setDouble("pid/d", 0);
105 pidAdvisor.setInt("calculate", 0);
106
107 // Start the module thread
108 pidAdvisor.execute();
109 System.Threading.Thread.Sleep(1000);
110
111 // Advise
112 pidAdvisor.setInt("calculate", 1);
113 System.Diagnostics.Trace.WriteLine(
114 "Starting advising. Optimization process may run up to a minute...");
115
116 var watch = System.Diagnostics.Stopwatch.StartNew();
117 while (true)
118 {
119 double progress = pidAdvisor.progress() * 100;
120 System.Diagnostics.Trace.WriteLine(progress, "Progress");
121 System.Threading.Thread.Sleep(1000);
122 Int64 calc = pidAdvisor.getInt("calculate");
123 if (calc == 0)
124 {
125 break;
126 }
127 }
128
129 watch.Stop();
130 var elapsedMs = watch.ElapsedMilliseconds;
131
132 System.Diagnostics.Trace.WriteLine(
133 String.Format("Advice took {0} s.", watch.ElapsedMilliseconds / 1000.0));
134
135 // Get the advised values
136 double p_adv = pidAdvisor.getDouble("pid/p");
137 double i_adv = pidAdvisor.getDouble("pid/i");
138 double d_adv = pidAdvisor.getDouble("pid/d");
139 double dlimittimeconstant_adv =
140 pidAdvisor.getDouble("pid/dlimittimeconstant");
141 double rate_adv = pidAdvisor.getDouble("pid/rate");
142 double bw_adv = pidAdvisor.getDouble("bw");
143
144 System.Diagnostics.Trace.WriteLine(p_adv, "P");
145 System.Diagnostics.Trace.WriteLine(i_adv, "I");
146 System.Diagnostics.Trace.WriteLine(d_adv, "D");
147 System.Diagnostics.Trace.WriteLine(dlimittimeconstant_adv, "D_tc");
148 System.Diagnostics.Trace.WriteLine(rate_adv, "rate");
149 System.Diagnostics.Trace.WriteLine(bw_adv, "bw");
150
151 // copy the values from the Advisor to the device
152 pidAdvisor.setInt("todevice", 1);
153
154 // Get all calculated parameters.
155 Lookup result = pidAdvisor.get("*");
156
157 // extract bode plot and step response
158 double[] grid = result["/bode"][0].advisorWaves[0].grid;
159 double[] x = result["/bode"][0].advisorWaves[0].x;
160 double[] y = result["/bode"][0].advisorWaves[0].y;
161 String fileName = Environment.CurrentDirectory + "/pidAdvisor.txt";
162 System.IO.StreamWriter file = new System.IO.StreamWriter(fileName);
163 for (int i = 0; i < grid.Length; ++i)
164 {
165 file.WriteLine("{0} {1} {2}", grid[i], x[i], y[i]);
166 }
167 file.Close();
168
169 AssertEqual(1.0, pidAdvisor.progress());
170 AssertNotEqual(0, grid.Length);
171
172 pidAdvisor.clear(); // Release module resources. Especially important if modules are created
173 // inside a loop to prevent excessive resource consumption.
174 daq.disconnect();
175}