|
|
|
@@ -2,16 +2,14 @@
|
|
|
|
|
using DeviceCommand.Base;
|
|
|
|
|
using Model.Models;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace DeviceCommand.Devices
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 交流源 一拖三
|
|
|
|
|
/// 交流源 一拖三 (Chroma 61800系列)
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ACPCommand]
|
|
|
|
|
public class Chroma61800 : Tcp
|
|
|
|
@@ -23,185 +21,187 @@ namespace DeviceCommand.Devices
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 1. 基础系统控制
|
|
|
|
|
#region 1. 基础系统与公共指令
|
|
|
|
|
|
|
|
|
|
public virtual async Task 清除错误队列(CancellationToken ct = default)
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 清除错误队列 (*CLS)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 2. LIST 模式初始化
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 重设仪器为初始状态 (*RST)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 复位Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
await SendAsync($"*RST{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化 LIST 模式的三相独立编辑环境
|
|
|
|
|
/// 查询仪器识别码 (*IDN?)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="loopCount">循环次数,0代表无限循环</param>
|
|
|
|
|
public virtual async Task 初始化三相List模式(int loopCount = 0, CancellationToken ct = default)
|
|
|
|
|
public virtual async Task<string> 查询设备信息Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
await SendAsync($"INST:PHAS THRE{ScpiDelimiter}", ct); // 选择三相模式
|
|
|
|
|
await SendAsync($"INST:EDIT EACH{ScpiDelimiter}", ct); // 选择编辑电压方式为分别编辑
|
|
|
|
|
await SendAsync($"LIST:COUN {loopCount}{ScpiDelimiter}", ct); // 循环次数设定
|
|
|
|
|
await SendAsync($"LIST:TRIG AUTO{ScpiDelimiter}", ct); // 设定触发方式
|
|
|
|
|
await SendAsync($"LIST:BASE TIME{ScpiDelimiter}", ct); // 选择执行时间类别
|
|
|
|
|
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 3. LIST 步阶参数配置 (独立发送版 - 三参数固定版)
|
|
|
|
|
#region 2. 基础输出与耦合控制 (OUTPut 子系统)[cite: 1]
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 切换目标相位并设置波形为正弦波
|
|
|
|
|
/// 建议在发送具体 LIST 参数前调用一次即可
|
|
|
|
|
/// 设置输出开关状态 (OUTP ON / OFF)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="phase">相位 (1: L1, 2: L2, 3: L3)</param>
|
|
|
|
|
public virtual async Task 切换相位Async(int phase, CancellationToken ct = default)
|
|
|
|
|
/// <param name="isOn">true: 开启输出, false: 关闭输出</param>
|
|
|
|
|
public virtual async Task 设置输出开关Async(bool isOn, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
if (phase < 1 || phase > 3)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(phase), "相位必须为 1, 2, 或 3");
|
|
|
|
|
|
|
|
|
|
await SendAsync($"INST:NSEL {phase}{ScpiDelimiter}", ct);
|
|
|
|
|
await SendAsync($"FUNC:SHAP:A SINE{ScpiDelimiter}", ct);
|
|
|
|
|
string state = isOn ? "ON" : "OFF";
|
|
|
|
|
await SendAsync($"OUTP {state}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步起始角度
|
|
|
|
|
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List起始角度Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
public virtual async Task 设置耦合模式Async(string couplingMode, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:DEGR {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
// 有效参数: AC, DC, ACDC
|
|
|
|
|
await SendAsync($"OUTP:COUP {couplingMode}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步交流起始电压
|
|
|
|
|
/// 设置输出继电器状态 (OUTP:REL ON | OFF)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List交流起始电压Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
public virtual async Task 设置输出继电器Async(bool isOn, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:VOLT:AC:STAR {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步交流结束电压
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List交流结束电压Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:VOLT:AC:END {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步直流起始电压
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List直流起始电压Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:VOLT:DC:STAR {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步直流结束电压
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List直流结束电压Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:VOLT:DC:END {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步起始频率
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List起始频率Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:FREQ:STAR {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步结束频率
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List结束频率Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:FREQ:END {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 配置 LIST 各步执行时间 (单位: 毫秒)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 配置List执行时间Async(double step1, double step2, double step3, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string strValues = JoinParameters(step1, step2, step3);
|
|
|
|
|
await SendAsync($"LIST:DWEL {strValues}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 辅助方法:将三个 double 值转换为逗号分隔的字符串,确保小数点格式正确
|
|
|
|
|
/// </summary>
|
|
|
|
|
private string JoinParameters(double val1, double val2, double val3)
|
|
|
|
|
{
|
|
|
|
|
return $"{val1.ToString("0.###", CultureInfo.InvariantCulture)}," +
|
|
|
|
|
$"{val2.ToString("0.###", CultureInfo.InvariantCulture)}," +
|
|
|
|
|
$"{val3.ToString("0.###", CultureInfo.InvariantCulture)}";
|
|
|
|
|
string state = isOn ? "ON" : "OFF";
|
|
|
|
|
await SendAsync($"OUTP:REL {state}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 4. LIST 触发与状态监控
|
|
|
|
|
#region 3. 电源核心参数设置 (SOURCE 子系统)[cite: 1]
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 切换到 LIST 模式并触发输出
|
|
|
|
|
/// 设置交流电压 (VOLT:AC)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 启动List输出(CancellationToken ct = default)
|
|
|
|
|
/// <param name="voltage">电压值 (0 ~ 300V 或高压选配范围)</param>
|
|
|
|
|
public virtual async Task 设置交流电压Async(double voltage, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
await SendAsync($"OUTP:MODE LIST{ScpiDelimiter}", ct);
|
|
|
|
|
await SendAsync($"TRIG ON{ScpiDelimiter}", ct);
|
|
|
|
|
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
await SendAsync($"VOLT:AC {valStr}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询 LIST 序列是否正在运行
|
|
|
|
|
/// 设置直流电压 (VOLT:DC)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task<bool> 查询List是否运行中(CancellationToken ct = default)
|
|
|
|
|
public virtual async Task 设置直流电压Async(double voltage, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string state = await WriteReadAsync($"TRIG:STATE?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
state = state?.Trim().ToUpper();
|
|
|
|
|
return state == "ON" || state == "1";
|
|
|
|
|
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
await SendAsync($"VOLT:DC {valStr}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 阻塞异步等待直到 LIST 序列执行完毕 (带安全超时保护)
|
|
|
|
|
/// 设置输出频率 (FREQ)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="timeoutMs">最大等待超时时间(建议比实际LIST总时长多5-10秒)</param>
|
|
|
|
|
public virtual async Task 等待List执行结束(int timeoutMs = 60000, CancellationToken ct = default)
|
|
|
|
|
/// <param name="frequency">频率值 (Hz)</param>
|
|
|
|
|
public virtual async Task 设置频率Async(double frequency, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
// 给仪器留出响应触发的时间
|
|
|
|
|
await Task.Delay(500, ct);
|
|
|
|
|
string valStr = frequency.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
await SendAsync($"FREQ {valStr}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
bool isRunning = true;
|
|
|
|
|
|
|
|
|
|
while (isRunning)
|
|
|
|
|
{
|
|
|
|
|
ct.ThrowIfCancellationRequested();
|
|
|
|
|
|
|
|
|
|
if (sw.ElapsedMilliseconds > timeoutMs)
|
|
|
|
|
{
|
|
|
|
|
throw new TimeoutException($"等待 LIST 执行结束超时 ({timeoutMs} ms)。");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取当前状态
|
|
|
|
|
isRunning = await 查询List是否运行中(ct);
|
|
|
|
|
|
|
|
|
|
if (isRunning)
|
|
|
|
|
{
|
|
|
|
|
// 还在运行,适当休眠后继续轮询,避免总线阻塞
|
|
|
|
|
await Task.Delay(500, ct);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置波形选择 (FUNC:SHAP:A SINE / SQUA / CSIN 等)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 设置波形Async(string shape, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
await SendAsync($"FUNC:SHAP:A {shape}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 4. 相位与多相模式控制 (INST & PHASE 子系统)[cite: 1]
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isThreePhase">true: 三相模式, false: 单相模式</param>
|
|
|
|
|
public virtual async Task 设置单三相模式Async(bool isThreePhase, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string mode = isThreePhase ? "THREE" : "SINGLE";
|
|
|
|
|
await SendAsync($"INST:PHAS {mode}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置三相模式下的相互关系 (PHASE:THREE INDEPEND / SAMEFREQ / BALANCE)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 设置三相关系Async(string relation, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
// 有效参数: INDEPEND, SAMEFREQ, BALANCE
|
|
|
|
|
await SendAsync($"PHASE:THREE {relation}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置输出开启相位角 (PHASE:ON)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 设置开机角度Async(double degree, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string valStr = degree.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
await SendAsync($"PHASE:ON {valStr}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置输出关闭相位角 (PHASE:OFF)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task 设置关机角度Async(double degree, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string valStr = degree.ToString("0.###", CultureInfo.InvariantCulture);
|
|
|
|
|
await SendAsync($"PHASE:OFF {valStr}{ScpiDelimiter}", ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 5. 参数测量查询 (MEASure 子系统)[cite: 1]
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task<double> 读取交流电压Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string resp = await WriteReadAsync($"MEAS:VOLT:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询交流电流均方根值 (MEAS:CURR:AC?)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task<double> 读取交流电流Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string resp = await WriteReadAsync($"MEAS:CURR:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询输出频率 (MEAS:FREQ?)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task<double> 读取频率Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询真实输出功率 (MEAS:POW:AC?)[cite: 1]
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual async Task<double> 读取真实功率Async(CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
string resp = await WriteReadAsync($"MEAS:POW:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
|
|
|
|
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|