ExamplePidAdvisor#

  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}