/************************************************************************* * * ######### Schweizerische Eidgenossenschaft * ### ### Confederation suisse * # # Confederazione Svizzera * ### ### Confederazione Svizzera * ##### * Federal Institute of Metrology METAS * * File : AgilentPna.cs * Class : Agilent_PNA_Series * Agilent_PNA_Series_Opt080 * Library : Metas.Instr.Driver.Vna * Version : 2.5.4.0 * Author : Michael Wollensack * Created : 07.08.2008 * Modified : 12.04.2022 * ************************************************************************/ using System.ComponentModel; using System.Collections.Generic; using System.Globalization; using Metas.Instr.VisaExtensions; using Metas.UncLib.Core; using Metas.Vna.Data; using DoubleHelper = Metas.UncLib.Core.Special.DoubleHelper; namespace Metas.Instr.Driver.Vna { /// /// Driver for Agilent PNA Series vector network analyzer. /// public class Agilent_PNA_Series : IVna { /// /// Visa session. /// public SrqMessageBasedSession visa; private VnaSetUpMode setupmode; internal VnaParameter[] parameters; internal bool version_0990 = false; internal bool version_1060 = false; internal bool Option_080 = false; internal int nTestPorts = 2; #region Constructor /// /// Creates a VNA session. /// public Agilent_PNA_Series() { this.parameters = new VnaParameter[0]; } /// /// Creates a VNA session to the specified resource. /// /// String that describes a unique VISA resource. /// String that describes the instrument identification. public Agilent_PNA_Series(string resourceName, string idName = null) { Open(resourceName, idName); } #endregion #region IDevice Members /// /// Opens a VNA session to the specified resource. /// /// String that describes a unique VISA resource. /// String that describes the instrument identification. public void Open(string resourceName, string idName = null) { this.setupmode = VnaSetUpMode.unknown; this.parameters = new VnaParameter[0]; this.parameterMatrix = null; this.visa = new SrqMessageBasedSession(resourceName); string idn = Identification; if (idn.IndexOf("Agilent Technologies,E836") >= 0 || idn.IndexOf("Agilent Technologies,N52") >= 0 || idn.IndexOf("Keysight Technologies,N52") >= 0 || idn.IndexOf("Keysight Technologies,E508") >= 0 || idn.IndexOf("Keysight Technologies,M937") >= 0 || // PXI over HiSLIP idn.IndexOf("Keysight Technologies,M948") >= 0 || // PXI over HiSLIP idn.IndexOf("Keysight Technologies,M980") >= 0 || // PXI over HiSLIP idn.IndexOf("Keysight Technologies,P937") >= 0 || // USB over HiSLIP idn.IndexOf("Keysight Technologies,P50") >= 0) // USB over HiSLIP { } else if (!string.IsNullOrEmpty(idName) && idn.Contains(idName)) { } else { throw new InstrumentIdentificationQueryFailedException(idn); } // Agilent\sTechnologies,N5225A,MY51451200,A.10.65.04\n try { string[] s = idn.Split(','); string firmware = s[3]; int d = int.Parse(firmware.Substring(2, 5).Replace(".", "")); version_0990 = d >= 990; version_1060 = d >= 1060; } catch { } string opt = this.visa.Query("*OPT?"); Option_080 = opt.Contains("080"); if (version_1060) { nTestPorts = VnaHelper.String2Int(this.visa.Query("SYST:CAP:HARD:PORT:COUN?")); } else { System.Text.RegularExpressions.Match m = System.Text.RegularExpressions.Regex.Match(opt, "P[0-9]+"); if (m.Success) { nTestPorts = int.Parse(m.Value.Substring(1)); } } if (nTestPorts == 0) nTestPorts = 2; this.visa.SrqMask = "*CLS;*ESE 1;*SRE 32"; this.visa.Timeout = 3000; this.visa.SrqTimeout = 3000; this.visa.SrqWrite("DISPLAY:WINDOW:TITLE:DATA '.net Driver VNA - Agilent PNA';*OPC"); this.visa.Write("FORM:DATA REAL,64;:FORM:BORD NORM"); _frequencyList = null; TurnSystemCorrectionOff(); } /// /// Closes the specified device session. /// public void Close() { this.TriggerCont(); this.visa.Write("*CLS;*ESE 0;*SRE 0"); this.visa.Dispose(); this.visa = null; } /// /// Instrument Identification /// public string Identification { get { return this.visa.Query("*IDN?").Split('\n')[0]; } } #endregion #region IVna Members /// /// Preset the VNA. /// public void Preset() { this.setupmode = VnaSetUpMode.unknown; this.parameters = new VnaParameter[0]; this.parameterMatrix = null; // user preset enabled? int state = VnaHelper.String2Int(this.visa.Query("SYSTEM:UPRESET:FPANEL:STATE?")); if (state == 1) { // User Preset this.visa.SrqWrite("SYSTEM:UPRESET;*OPC"); } else { // Factory Preset this.visa.SrqWrite("*RST;*OPC"); } // Set to stepped mode this.visa.SrqWrite("SENSE:SWEEP:GENERATION STEPPED;*OPC"); this.visa.SrqWrite("DISPLAY:WINDOW:TITLE:DATA '.net Driver VNA - Agilent PNA';*OPC"); this.visa.Write("FORM:DATA REAL,64;:FORM:BORD NORM"); _frequencyList = null; TurnSystemCorrectionOff(); } private void TurnSystemCorrectionOff() { // http://ena.support.keysight.com/e5080a/manuals/webhelp/eng/programming/gp-ib_command_finder/system.htm#systfcorchancoup // http://na.support.keysight.com/pxi/help/latest/Programming/GP-IB_Command_Finder/System.htm#SYSTem:FCORrection:CHANnel:COUPler:STATe string idn = Identification; if (idn.Contains("Keysight Technologies,E508") || idn.Contains("Keysight Technologies,M937") || idn.Contains("Keysight Technologies,M948") || idn.Contains("Keysight Technologies,M980") || idn.Contains("Keysight Technologies,P937") || idn.Contains("Keysight Technologies,P50")) { this.visa.SrqWrite("SYSTem:FCORrection:CHANnel:COUPler:STATe OFF;*OPC"); } // http://ena.support.keysight.com/e5080/manuals/webhelp/eng/index.htm#S1_Settings/Receiver_Gain.htm if (idn.Contains("Keysight Technologies,E5080B") || idn.Contains("Keysight Technologies,M980") || idn.Contains("Keysight Technologies,P50")) { this.visa.SrqWrite("SENSe:SOURce1:RECeiver1:GAIN:ALL 'Low';*OPC"); } } /// /// Set instrument state to VNA. /// /// Instrument state public void SetState(byte[] state) { this.setupmode = VnaSetUpMode.unknown; this.parameters = new VnaParameter[0]; this.parameterMatrix = null; int t = this.visa.SrqTimeout; this.visa.SrqTimeout = 30000; string l1 = state.Length.ToString(); string l2 = l1.Length.ToString(); this.visa.SendEndEnabled = false; this.visa.Write("MMEMORY:TRANSFER 'Driver VNA.cst',#" + l2 + l1); this.visa.SendEndEnabled = true; this.visa.Write(state); //this.visa.SrqWrite("*RST;" + // "MMEMORY:LOAD 'Driver VNA.cst';" + // ":MMEMORY:DELETE 'Driver VNA.cst';" + // "*OPC"); this.visa.SrqWrite("*RST;*OPC"); this.visa.SrqWrite("MMEMORY:LOAD 'Driver VNA.cst';*OPC"); this.visa.SrqWrite("MMEMORY:DELETE 'Driver VNA.cst';*OPC"); this.visa.SrqTimeout = t; this.visa.SrqWrite("DISPLAY:WINDOW:TITLE:DATA '.net Driver VNA - Agilent PNA';*OPC"); this.visa.Write("FORM:DATA REAL,64;:FORM:BORD NORM"); _frequencyList = null; TurnSystemCorrectionOff(); } /// /// Get instrument state from VNA. /// /// Instrument state public byte[] GetState() { this.visa.SrqWrite("MMEMORY:STORE 'Driver VNA.cst';*OPC"); // not working with SRQ and Agilent PNA Firmware Version A.07.50.13 // Utility / System / System Setup / Remote Interface / Enable Remote Drive Access string s2 = this.visa.Query("MMEMORY:TRANSFER? 'Driver VNA.cst'", 2); int l2 = 0; int.TryParse(s2.Substring(1, 1), out l2); string s1 = this.visa.ReadString(l2); int l1 = 0; int.TryParse(s1, out l1); byte[] state = this.visa.ReadByteArray(l1); // Dummy read this.visa.ReadByteArray(); this.visa.SrqWrite("MMEMORY:DELETE 'Driver VNA.cst';*OPC"); return state; } /// /// Set instrument state to VNA. /// /// Instrument State File Path (*.is) /// Canceled public bool SetState(string pathState) { return VnaHelper.SetState(this, pathState); } /// /// Get instrument state from VNA. /// /// Instrument State File Path (*.is) /// Canceled public bool GetState(string pathState) { return VnaHelper.GetState(this, pathState); } /// /// Set up VNA. /// /// VNA mode public void SetUp(VnaSetUpMode mode) { SetUp(VnaHelper.GetVnaParameterMatrix(mode)); } private void SetUp(VnaParameter[,] p) { if (p == null) throw new System.Exception("VNA SetUp Mode unknown not supported."); int n1 = p.GetLength(0); int n2 = p.GetLength(1); int n = n1 * n2; if (n == 0) throw new System.Exception("VNA SetUp Mode unknown not supported."); parameters = new VnaParameter[n]; int[] windows = new int[n]; int[] traces = new int[n]; int i = 1; for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { //parameters[n1 * i2 + i1] = p[i1, i2]; //windows[n1 * i2 + i1] = i; parameters[n2 * i1 + i2] = p[i1, i2]; windows[n2 * i1 + i2] = i; traces[n2 * i1 + i2] = (i - 1) % 24 + 1; // maximum number of traces per window 24 i++; } } this.setupmode = VnaHelper.GetVnaSetUpMode(p); SetUp(parameters, new List(windows), new List(traces)); } private void SetUp(VnaParameter[] parameters, List windows, List traces) { // display catalog //string s = this.visa.Query("DISPLAY:CATALOG?"); // not working with firmware A.11.xx.xx string s = this.visa.Query("DISPLAY:CATALOG?"); s = s.Split('"')[1]; int[] cw; if (s == "EMPTY") { cw = new int[0]; } else { string[] temp = s.Split(','); cw = new int[temp.Length]; for (int i = 0; i < cw.Length; i++) { cw[i] = VnaHelper.String2Int(temp[i]); } } int[] temp_windows = new int[windows.Count]; bool windows_dont_change = (cw.Length == temp_windows.Length); for (int i = 0; i < temp_windows.Length; i++) { temp_windows[i] = i + 1; if (windows_dont_change) { windows_dont_change = (cw[i] == temp_windows[i]); } } if (!windows_dont_change) { foreach (int cwi in cw) { this.visa.SrqWrite("DISPLAY:WINDOW" + cwi + " OFF;*OPC"); } foreach (int wi in temp_windows) { this.visa.SrqWrite("DISPLAY:WINDOW" + wi + " ON;*OPC"); } } // calculate parameter catalog //s = this.visa.Query("CALCULATE:PARAMETER:CATALOG?"); // not working with firmware A.11.xx.xx //s = this.visa.Query("CALCULATE:PARAMETER:CATALOG:EXTENDED?"); //s = s.Split('"')[1]; //string[] cp; //if (s == "NO CATALOG") //{ // cp = new string[0]; //} //else //{ // cp = s.Split(','); //} //// delete not used parameters //List temp_parameter = new List(AgilentPnaGlobal.parameter_pna); //foreach (VnaParameter p in parameters) //{ // temp_parameter.Add(AgilentPnaGlobal.parameter_name(p)); //} //foreach (string cpi in cp) //{ // if (!temp_parameter.Contains(cpi)) // { // this.visa.SrqWrite("CALCULATE:PARAMETER:DELETE '" + cpi + "';*OPC"); // } //} // delete all traces this.visa.SrqWrite("CALCULATE:PARAMETER:DELETE:ALL;*OPC"); // define parameter if not defined already //List temp_parameter2 = new List(cp); for (int i = 0; i < parameters.Length; i++) { //if (!temp_parameter2.Contains(AgilentPnaGlobal.parameter_name(parameters[i]))) //{ // not working with firmware A.11.xx.xx //this.visa.SrqWrite("CALCULATE:PARAMETER:DEFINE '" + // AgilentPnaGlobal.parameter_name(parameters[i]) + // "'," + AgilentPnaGlobal.parameter_dict(parameters[i]) + ";*OPC"); this.visa.SrqWrite("CALCULATE:PARAMETER:DEFINE:EXTENDED '" + AgilentPnaGlobal.parameter_name(parameters[i]) + "','" + AgilentPnaGlobal.parameter_dict(parameters[i]) + "';*OPC"); //} } // display window catalog List> display_window_catalog = new List>(); for (int i = 0; i < traces.Count; i++) { //s = this.visa.Query("DISPLAY:WINDOW" + windows[i] + ":CATALOG?"); // not working with firmware A.11.xx.xx s = this.visa.Query("DISPLAY:WINDOW" + windows[i] + ":CATALOG?"); s = s.Split('"')[1]; List dwci = new List(); if (s != "EMPTY") { string[] temp = s.Split(','); foreach (string tempi in temp) { dwci.Add(VnaHelper.String2Int(tempi)); } } display_window_catalog.Add(dwci); // delete not used traces for (int k = 1; k <= 8; k++) { if (dwci.Contains(k) && !traces.Contains(k)) { this.visa.SrqWrite("DISPLAY:WINDOW" + windows[i] + ":TRACE" + k + ":DELETE;*OPC"); } } } // create trace if not created already for (int i = 0; i < display_window_catalog.Count; i++) { List dwci = display_window_catalog[i]; if (dwci.Contains(traces[i]) == false) { this.visa.SrqWrite("DISPLAY:WINDOW" + windows[i] + ":TRACE" + traces[i] + ":FEED '" + AgilentPnaGlobal.parameter_name(parameters[i]) + "';*OPC"); this.visa.SrqWrite("DISPLAY:WINDOW" + windows[i] + ":TRACE" + traces[i] + ":Y:RPOSITION 9;*OPC"); } } } /// /// Set up VNA. /// /// VNA mode public void SetUp(string mode) { SetUp((VnaSetUpMode)System.Enum.Parse(typeof(VnaSetUpMode), mode)); } /// /// Set single frequency. /// /// Frequency / Hz public void SetSingleFrequency(double freq) { SweepMode = VnaSweepMode.LinearFrequency; FrequencyStart = freq; FrequencyStop = freq; } /// /// Set single frequency. /// /// Frequency list / Hz /// Index public void SetSingleFrequency(double[] freq, int index) { SetSingleFrequency(freq[index]); } /// /// VNA sweep mode: trigger hold. /// public void TriggerHold() { this.visa.SrqWrite("SENSE:SWEEP:MODE HOLD;*OPC"); } int srq_timeout; /// /// Triggers VNA. /// public void TriggerSingleStart() { TriggerHold(); int avg_n = this.IFAverageFactor; if (avg_n > 1) { this.visa.SrqWrite("SENSE:AVERAGE:CLEAR;*OPC"); } this.visa.SrqWrite("SENSE:SWEEP:GROUPS:COUNT " + avg_n.ToString() + ";*OPC"); srq_timeout = this.visa.SrqTimeout; this.visa.SrqMask = "*CLS;*ESE 1;*SRE 32"; this.visa.SrqTimeout = 7200000; this.visa.SrqBegin(); this.visa.Write("SENSE:SWEEP:MODE GROUPS;*OPC"); } /// /// Waits for sweep complete. /// /// Background Worker /// Do Work Event Arguments public void TriggerSingleWait(BackgroundWorker worker = null, DoWorkEventArgs e = null) { this.visa.SrqEnd(worker, e); this.visa.Clear(); //this.visa.Write("*CLS;*ESE 0;*SRE 0"); this.visa.SrqMask = "*CLS;*ESE 1;*SRE 32"; this.visa.SrqTimeout = srq_timeout; if (worker != null) if (worker.CancellationPending) this.TriggerHold(); } /// /// Triggers VNA and waits for sweep complete. /// /// Background Worker /// Do Work Event Arguments public void TriggerSingle(BackgroundWorker worker = null, DoWorkEventArgs e = null) { TriggerSingleStart(); TriggerSingleWait(worker, e); } /// /// VNA sweep mode: trigger continuous. /// public void TriggerCont() { this.visa.SrqWrite("SENSE:SWEEP:MODE CONTINUOUS;*OPC"); } /// /// Get data from VNA. All available parameters. /// /// VNA format /// Data public VnaData GetData(VnaFormat format) { return GetData(Parameters, format); } /// /// Get data from VNA. /// /// VNA parameters /// VNA format /// Data internal virtual VnaData GetData(VnaParameter[] parameters, VnaFormat format) { double[] temp; double[] flist = FrequencyList; var ports = VnaParameter.CommonPorts(parameters); double z0 = Z0; int n1 = flist.Length; int n2 = parameters.Length; VnaData data = new VnaData(); data.Frequency = flist; data.Ports = ports; data.PortZr = new Complex[ports.Length]; for (int i1 = 0; i1 < ports.Length; i1++) { data.PortZr[i1] = z0; } data.ParameterData = new VnaParameterData[n2]; if (format == VnaFormat.ErrorCorrectedData) { this.visa.Write("CALCULATE:CORRECTION ON"); } else { this.visa.Write("CALCULATE:CORRECTION OFF"); } string fast = version_0990 ? ",fast" : ""; for (int i2 = 0; i2 < n2; i2++) { this.visa.Write("CALCULATE:PARAMETER:SELECT '" + AgilentPnaGlobal.parameter_name(parameters[i2]) + "'" + fast + ";:CALCULATE:DATA? SDATA"); string s2 = this.visa.ReadString(2); int l2 = 0; int.TryParse(s2.Substring(1, 1), out l2); string s1 = this.visa.ReadString(l2); int l1 = 0; int.TryParse(s1, out l1); byte[] bindata = this.visa.ReadByteArray(l1); // Dummy read this.visa.ReadByteArray(); // real64 temp = VnaHelper.Real64ByteArray2DoubleArray(bindata); // VNA data data.ParameterData[i2] = new VnaParameterData(); data.ParameterData[i2].Parameter = parameters[i2]; data.ParameterData[i2].Data = new Complex[n1]; for (int i1 = 0; i1 < n1; i1++) { data.ParameterData[i2].Data[i1] = new Complex(temp[2 * i1], temp[2 * i1 + 1]); } } return data; } /// /// Triggers VNA, waits for sweep complete, gets and saves raw data. /// /// Data File Path (*.sdatb, *.vdatb) public void Measure(string pathRes) { VnaHelper.VnaMeasure(this, pathRes); } private string _rootPath = ""; /// /// Root Path /// public string RootPath { get { return _rootPath; } set { _rootPath = value; } } private double[] _frequencyList = null; /// /// Frequency List / Hz /// public double[] FrequencyList { get { if (_frequencyList == null) { _frequencyList = VnaHelper.GetFrequencyList(this); } return _frequencyList; } } /// /// Number of Test Ports /// public int NTestPorts { get { return nTestPorts; } } /// /// Settings /// public VnaSettings Settings { get { return VnaHelper.GetVnaSettings(this); } } /// /// Sweep Mode /// public VnaSweepMode SweepMode { get { VnaSweepMode value = VnaSweepMode.LinearFrequency; string mode = this.visa.Query("SENSE:SWEEP:TYPE?"); mode = mode.Split('\n')[0]; switch (mode) { case "LIN": value = VnaSweepMode.LinearFrequency; break; case "LOG": value = VnaSweepMode.LogFrequency; break; case "SEGM": value = VnaSweepMode.SegmentSweep; break; case "CW": value = VnaSweepMode.CWTime; break; } return value; } set { _frequencyList = null; string mode = ""; switch (value) { case VnaSweepMode.LinearFrequency: mode = "LIN"; break; case VnaSweepMode.LogFrequency: mode = "LOG"; break; case VnaSweepMode.SegmentSweep: mode = "SEGM"; break; case VnaSweepMode.CWTime: mode = "CW"; break; } this.visa.SrqWrite("SENSE:SWEEP:TYPE " + mode + ";*OPC"); } } /// /// Sweep Time / s /// public double SweepTime { get { return VnaHelper.String2Double(this.visa.Query("SENSE:SWEEP:TIME?")); } set { this.visa.SrqWrite("SENSE:SWEEP:TIME " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Dwell Time / s /// public double DwellTime { get { return VnaHelper.String2Double(this.visa.Query("SENSE:SWEEP:DWELL?")); } set { this.visa.SrqWrite("SENSE:SWEEP:DWELL " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Sweep Points /// public int SweepPoints { get { return VnaHelper.String2Int(this.visa.Query("SENSE:SWEEP:POINTS?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:SWEEP:POINTS " + value.ToString() + ";*OPC"); } } /// /// IF Bandwidth / Hz /// public double IFBandwidth { get { return VnaHelper.String2Double(this.visa.Query("SENSE:BANDWIDTH?")); } set { this.visa.SrqWrite("SENSE:BANDWIDTH:TRACK 0;*OPC"); this.visa.SrqWrite("SENSE:BANDWIDTH " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// IF Average Factor /// public int IFAverageFactor { get { int state = VnaHelper.String2Int(this.visa.Query("SENSE:AVERAGE?")); int value = 1; if (state == 1) { value = VnaHelper.String2Int(this.visa.Query("SENSE:AVERAGE:COUNT?")); } return value; } set { if (value <= 1) { this.visa.SrqWrite("SENSE:AVERAGE OFF;*OPC"); } else { this.visa.SrqWrite("SENSE:AVERAGE:COUNT " + value.ToString() + ";:SENSE:AVERAGE ON;*OPC"); } } } /// /// Start Frequency / Hz /// public double FrequencyStart { get { return VnaHelper.String2Double(this.visa.Query("SENSE:FREQ:START?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:FREQ:START " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Stop Frequency / Hz /// public double FrequencyStop { get { return VnaHelper.String2Double(this.visa.Query("SENSE:FREQ:STOP?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:FREQ:STOP " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Center Frequency / Hz /// public double FrequencyCenter { get { return VnaHelper.String2Double(this.visa.Query("SENSE:FREQ:CENTER?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:FREQ:CENTER " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Span Frequency / Hz /// public double FrequencySpan { get { return VnaHelper.String2Double(this.visa.Query("SENSE:FREQ:SPAN?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:FREQ:SPAN " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// CW Frequency / Hz /// public double FrequencyCW { get { return VnaHelper.String2Double(this.visa.Query("SENSE:FREQ:CW?")); } set { _frequencyList = null; this.visa.SrqWrite("SENSE:FREQ:CW " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// SegmentTable /// 1. Column : Start Frequency / Hz /// 2. Column : Stop Frequency / Hz /// 3. Column : Frequency Step / Hz /// 4. Column : IF Bandwidth / Hz /// public double[,] SegmentTable { get { int points; double start, stop, step, ifbw; int n = VnaHelper.String2Int(this.visa.Query("SENSE:SEGMENT:COUNT?")); double[,] value = new double[n, 4]; for (int i = 0; i < n; i++) { string temp = "SENSE:SEGM" + (i + 1).ToString(); points = VnaHelper.String2Int(this.visa.Query(temp + ":SWEEP:POINTS?")); start = VnaHelper.String2Double(this.visa.Query(temp + ":FREQ:START?")); stop = VnaHelper.String2Double(this.visa.Query(temp + ":FREQ:STOP?")); step = (stop - start) / (points - 1); ifbw = VnaHelper.String2Double(this.visa.Query(temp + ":BWIDTH?")); value[i, 0] = start; value[i, 1] = stop; value[i, 2] = step; value[i, 3] = ifbw; } return value; } set { _frequencyList = null; VnaSweepMode sweep_mode = this.SweepMode; this.visa.SrqWrite("SENSE:SEGMENT:DELETE:ALL;*OPC"); this.visa.SrqWrite("SENSE:SEGMENT:BWIDTH:CONTROL ON;*OPC"); int points; double start, stop, step, ifbw; int n = value.GetLength(0); for (int i = 0; i < n; i++) { string temp = "SENSE:SEGM" + (i + 1).ToString(); start = value[i, 0]; stop = value[i, 1]; step = value[i, 2]; ifbw = value[i, 3]; points = (int)System.Math.Floor((stop - start) / step + 1); this.visa.SrqWrite(temp + ":ADD;*OPC"); this.visa.SrqWrite(temp + ":FREQ:START " + start.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); this.visa.SrqWrite(temp + ":FREQ:STOP " + stop.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); this.visa.SrqWrite(temp + ":SWEEP:POINTS " + points.ToString() + ";*OPC"); this.visa.SrqWrite(temp + ":BWIDTH " + ifbw.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); this.visa.SrqWrite(temp + " ON;*OPC"); } this.SweepMode = sweep_mode; } } /// /// Source 1 Power / dBm /// public double Source1Power { get { return VnaHelper.String2Double(this.visa.Query("SOURCE:POWER1?")); } set { this.visa.SrqWrite("SOURCE:POWER1 " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Source 1 Power Slope / (dB/GHz) /// public double Source1PowerSlope { get { int slope_state = VnaHelper.String2Int(this.visa.Query("SOURCE:POWER:SLOPE:STATE?")); double slope = slope_state == 0 ? 0 : VnaHelper.String2Double(this.visa.Query("SOURCE:POWER:SLOPE?")); return slope; } set { string slope_state = value == 0 ? "OFF" : "ON"; this.visa.SrqWrite("SOURCE:POWER:SLOPE:STATE " + slope_state + ";*OPC"); this.visa.SrqWrite("SOURCE:POWER:SLOPE " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Port 1 Attenuator / dB /// public double Port1Attenuator { get { return VnaHelper.String2Double(this.visa.Query("SOURCE:POWER1:ATTENUATION?")); } set { this.visa.SrqWrite("SOURCE:POWER1:ATTENUATION " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Port 1 Extension / s /// public double Port1Extension { get { return VnaHelper.String2Double(this.visa.Query("SENSE:CORRECTION:EXTENSION:PORT1?")); } set { this.visa.SrqWrite("SENSE:CORRECTION:EXTENSION:PORT1 " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Source 2 Power / dBm /// public double Source2Power { get { return VnaHelper.String2Double(this.visa.Query("SOURCE:POWER2?")); } set { this.visa.SrqWrite("SOURCE:POWER2 " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Source 2 Power Slope / (dB/GHz) /// public double Source2PowerSlope { get { return this.Source1PowerSlope; } set { this.Source1PowerSlope = value; } } /// /// Port 2 Attenuator / dB /// public double Port2Attenuator { get { return VnaHelper.String2Double(this.visa.Query("SOURCE:POWER2:ATTENUATION?")); } set { this.visa.SrqWrite("SOURCE:POWER2:ATTENUATION " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Port 2 Extension / s /// public double Port2Extension { get { return VnaHelper.String2Double(this.visa.Query("SENSE:CORRECTION:EXTENSION:PORT2?")); } set { this.visa.SrqWrite("SENSE:CORRECTION:EXTENSION:PORT2 " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Source Port Settings /// public VnaSourcePortSettings[] SourcePorts { get { VnaSourcePortSettings[] s = new VnaSourcePortSettings[NTestPorts]; for (int i = 0; i < NTestPorts; i++) { VnaSourcePortState state = VnaSourcePortState.Auto; string s_state = this.visa.Query("SOURCE:POWER" + (i + 1) + ":MODE?"); if (s_state.StartsWith("ON")) state = VnaSourcePortState.On; else if (s_state.StartsWith("OFF")) state = VnaSourcePortState.Off; double power = VnaHelper.String2Double(this.visa.Query("SOURCE:POWER" + (i + 1) + "?")); int slope_state = VnaHelper.String2Int(this.visa.Query("SOURCE:POWER" + (i + 1) + ":SLOPE:STATE?")); double slope = slope_state == 0 ? 0 : VnaHelper.String2Double(this.visa.Query("SOURCE:POWER" + (i + 1) + ":SLOPE?")); double attenuator = VnaHelper.String2Double(this.visa.Query("SOURCE:POWER" + (i + 1) + ":ATTENUATION?")); s[i] = new VnaSourcePortSettings() { PortState = state, PortPower = power, PortSlope = slope, PortAttenuator = attenuator }; } return s; } set { int n = value != null ? value.Length : 0; bool samePower = true; for (int i = 1; i < n; i++) { samePower = samePower && DoubleHelper.IsApproximatelyEqual(value[0].PortPower, value[i].PortPower); } // coupled ports string couple = samePower ? "ON" : "OFF"; this.visa.SrqWrite("SOURCE:POWER:COUPLE " + couple + ";*OPC"); // global slope int slope_state = VnaHelper.String2Int(this.visa.Query("SOURCE:POWER:SLOPE:STATE?")); double slope = slope_state == 0 ? 0 : VnaHelper.String2Double(this.visa.Query("SOURCE:POWER:SLOPE?")); for (int i = 0; i < n; i++) { this.visa.SrqWrite("SOURCE:POWER" + (i + 1) + ":MODE " + value[i].PortState.ToString() + ";*OPC"); this.visa.SrqWrite("SOURCE:POWER" + (i + 1) + " " + value[i].PortPower.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); if (!DoubleHelper.IsApproximatelyEqual(slope, value[i].PortSlope)) { string slope_state_i = value[i].PortSlope == 0 ? "OFF" : "ON"; this.visa.SrqWrite("SOURCE:POWER" + (i + 1) + ":SLOPE:STATE " + slope_state_i + ";*OPC"); this.visa.SrqWrite("SOURCE:POWER" + (i + 1) + ":SLOPE " + value[i].PortSlope.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } this.visa.SrqWrite("SOURCE:POWER" + (i + 1) + ":ATTENUATION " + value[i].PortAttenuator.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } } private double _z0 = 0; /// /// Z0 / Ohm /// public double Z0 { get { if (_z0 == 0) _z0 = VnaHelper.String2Double(this.visa.Query("SENSE:CORRECTION:IMPEDANCE:INPUT:MAGNITUDE?")); return _z0; } set { _z0 = value; this.visa.SrqWrite("SENSE:CORRECTION:IMPEDANCE:INPUT:MAGNITUDE " + value.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } } /// /// Turns RF power from the source ON or OFF. /// public bool OutputState { get { int state = VnaHelper.String2Int(this.visa.Query("OUTPUT:STATE?")); return (state == 1); } set { if (value) this.visa.SrqWrite("OUTPUT:STATE ON;*OPC"); else this.visa.SrqWrite("OUTPUT:STATE OFF;*OPC"); } } private VnaParameter[,] parameterMatrix = null; /// /// VNA parameter matrix /// public VnaParameter[,] ParameterMatrix { get { return parameterMatrix; } set { parameterMatrix = null; SetUp(value); parameterMatrix = value; } } /// /// VNA Set up mode /// public VnaSetUpMode SetUpMode { get { return this.setupmode; } } /// /// List with available parameters /// public VnaParameter[] Parameters { get { return this.parameters; } } #endregion } /// /// Driver for Agilent PNA Series Option 080 (frequency conversion settings) vector network analyzer. /// public class Agilent_PNA_Series_Opt080 : Agilent_PNA_Series, IVna2 { #region Constructor /// /// Creates a VNA session. /// public Agilent_PNA_Series_Opt080() { this.parameters = new VnaParameter[0]; } /// /// Creates a VNA session to the specified resource. /// /// String that describes a unique VISA resource. /// String that describes the instrument identification. public Agilent_PNA_Series_Opt080(string resourceName, string idName = null) { Open(resourceName, idName); } #endregion #region IVna Members /// /// Get data from VNA. /// /// VNA parameters /// VNA format /// Data internal override VnaData GetData(VnaParameter[] parameters, VnaFormat format) { VnaData data = base.GetData(parameters, format); VnaPortDescription[] ports = data.Ports; if (SupportsFrequencyConversion && FrequencyConversionState) { data.FrequencyConversions = new FrequencyConversion[ports.Length]; for (int i1 = 0; i1 < ports.Length; i1++) { data.FrequencyConversions[i1] = GetFreqConv(ports[i1].Port - 1); } } return data; } #endregion #region IVna2 Members /// /// Frequency Conversion Settings /// public VnaFreqConvSettings FrequencyConversionSettings { get { return VnaHelper.GetVnaFrequencyConversionSettings(this); } } /// /// Supports Frequency Conversion /// public bool SupportsFrequencyConversion { get { return Option_080; } } /// /// Turns frequency conversion ON or OFF. /// public bool FrequencyConversionState { get { if (SupportsFrequencyConversion) { int state = VnaHelper.String2Int(this.visa.Query("SENS:FOM:STAT?")); return (state == 1); } return false; } set { if (SupportsFrequencyConversion) { string s = value ? "ON" : "OFF"; visa.SrqWrite("SENS:FOM:STAT " + s + ";*OPC"); } } } FrequencyConversion[] lastFrequencyConversions = null; /// /// Frequency Conversions /// public FrequencyConversion[] FrequencyConversions { get { FrequencyConversion[] freqConv = new FrequencyConversion[NTestPorts]; lastFrequencyConversions = new FrequencyConversion[NTestPorts]; for (int i = 0; i < NTestPorts; i++) { freqConv[i] = GetFreqConv(i); lastFrequencyConversions[i] = freqConv[i]; } return freqConv; } set { int n = value != null ? value.Length : 0; for (int i = 0; i < n; i++) { if (lastFrequencyConversions == null) { SetFreqConv(value[i], i); } else if (value[i] != lastFrequencyConversions[i]) { if (value[i].TestReceiver != lastFrequencyConversions[i].TestReceiver) SetFreqConv(new FrequencyConversion(value[i].TestReceiver, value[i].TestReceiver, value[i].Source), i); else if (value[i].ReferenceReceiver != lastFrequencyConversions[i].ReferenceReceiver) SetFreqConv(new FrequencyConversion(value[i].ReferenceReceiver, value[i].ReferenceReceiver, value[i].Source), i); else SetFreqConv(value[i], i); } } } } private FrequencyConversion GetFreqConv(int i) { FrequencyConversion freqConv; if (SupportsFrequencyConversion) { int rangeSrc = GetFreqOffsetRangeSource(i); int rangeRcv = GetFreqOffsetRangeReceivers(i); double sourceNumerator = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeSrc + ":FREQ:MULT?")); double sourceDenominator = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeSrc + ":FREQ:DIV?")); double sourceOffset = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeSrc + ":FREQ:OFFS?")); double rcvNumerator = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeRcv + ":FREQ:MULT?")); double rcvDenominator = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeRcv + ":FREQ:DIV?")); double rcvOffset = VnaHelper.String2Double(visa.Query("SENS:FOM:RANG" + rangeRcv + ":FREQ:OFFS?")); freqConv = new FrequencyConversion( new FrequencyConversionSub(rcvNumerator, rcvDenominator, rcvOffset), new FrequencyConversionSub(rcvNumerator, rcvDenominator, rcvOffset), new FrequencyConversionSub(sourceNumerator, sourceDenominator, sourceOffset)); } else { freqConv = FrequencyConversion.Default; } return freqConv; } private void SetFreqConv(FrequencyConversion freqConv, int i) { if (SupportsFrequencyConversion) { if (freqConv.TestReceiver == freqConv.ReferenceReceiver) { int rangeSrc = GetFreqOffsetRangeSource(i); int rangeRcv = GetFreqOffsetRangeReceivers(i); visa.SrqWrite("SENS:FOM:RANG" + rangeSrc + ":COUP ON;*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeSrc + ":FREQ:MULT " + freqConv.Source.Numerator.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeSrc + ":FREQ:DIV " + freqConv.Source.Denominator.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeSrc + ":FREQ:OFFS " + freqConv.Source.Offset.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeRcv + ":COUP ON;*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeRcv + ":FREQ:MULT " + freqConv.TestReceiver.Numerator.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeRcv + ":FREQ:DIV " + freqConv.TestReceiver.Denominator.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); visa.SrqWrite("SENS:FOM:RANG" + rangeRcv + ":FREQ:OFFS " + freqConv.TestReceiver.Offset.ToString("E15", CultureInfo.InvariantCulture) + ";*OPC"); } else { throw new System.Exception("Frequency conversion of the test receiver must be equal to the reference receiver."); } } } private int GetFreqOffsetRangeSource(int portindex) { string name = "Source" + (portindex / 2 + 1); int index = GetFreqOffsetRangeIndex(name); return index + 1; } private int GetFreqOffsetRangeReceivers(int portindex) { string name = "Receivers"; int index = GetFreqOffsetRangeIndex(name); return index + 1; } private int GetFreqOffsetRangeIndex(string name) { string[] cat = GetFreqOffsetCatalog(); int i = System.Array.FindIndex(cat, delegate (string c) { return c == name; }); if (i < 0) { // Remove number at the end if (name.StartsWith("Source") && name != "Source") { i = GetFreqOffsetRangeIndex("Source"); } else if (name.StartsWith("Receivers") && name != "Receivers") { i = GetFreqOffsetRangeIndex("Receivers"); } } return i; } private string[] fomCatalog = null; private string[] GetFreqOffsetCatalog() { if (fomCatalog == null) { string s = visa.Query("SENS:FOM:CAT?"); fomCatalog = s.Split(new char[] { ',', '"', '\n' }, System.StringSplitOptions.RemoveEmptyEntries); } return fomCatalog; } #endregion } internal static class AgilentPnaGlobal { public static List parameter_pna = new List { "S11", "S12", "S13", "S14", "R1", "A", "1", "R1/A", "A/B", "S21", "S22", "S23", "S24", "R2", "B", "2", "R2/B", "B/A", "S31", "S32", "S33", "S34", "R3", "C", "3", "R3/C", "C/D", "S41", "S42", "S43", "S44", "R4", "D", "4", "R4/D", "D/C" }; public static string parameter_dict(VnaParameter p) { string s = ""; if (p.IsSParameter) { s = "S" + p.NumPort.ToString() + "_" + p.DenPort.ToString(); } else { if (p.NumRcv == VnaReceiverType.one) s += "1"; else if (p.NumRcv == VnaReceiverType.a) s += "R" + p.NumPort.ToString(); else if (p.NumRcv == VnaReceiverType.b) s += (char)('A' + p.NumPort - 1); if (p.DenRcv == VnaReceiverType.a) s += "/R" + p.DenPort.ToString(); else if (p.DenRcv == VnaReceiverType.b) s += "/" + (char)('A' + p.DenPort - 1); s += "," + p.SrcPort.ToString(); } return s; } public static string parameter_name(VnaParameter p) { return p.Name.ToLower().Replace(',', '_'); } } }