/*************************************************************************
*
* ######### 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(',', '_');
}
}
}