Files
ACP/DeviceCommand/Devices/Chroma61800.cs
T
2026-10-21 16:44:15 +08:00

753 lines
34 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// 交流源 一拖三 (Chroma 61800系列)
/// <para>SCPI 命令与参数范围按新手册 (61809/61812/61815, 新chromascpi.pdf) 校准:
/// 波形参数 SINE/SQUA/TRIAN/CSIN/DST01~30/USR01~30,Vac 0.0~350.0V,Vdc -495.0~495.0V,FREQ 30.00~100.00Hz</para>
/// </summary>
[ACPCommand]
public class Chroma61800 : Tcp
{
// Chroma SCPI 默认使用 \n 作为结束符
private const string ScpiDelimiter = "\n";
public Chroma61800(TcpConfig config) : base(config)
{
}
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取全部数值并按顺序转换为 double 数组。
/// 用于解析形如 "1.2,3.4,5.6" 的多值响应(如谐波振幅数组 MEAS:HARM:ARR?)。
/// 兼容逗号/分号/空格分隔及科学计数法。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>按出现顺序排列的数值数组,无有效数值时返回空数组</returns>
private static double[] ExtractDoubleArray(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return Array.Empty<double>();
var values = new List<double>();
foreach (Match m in Regex.Matches(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?"))
{
if (double.TryParse(m.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double v))
values.Add(v);
}
return values.ToArray();
}
#region 1. 基础系统与公共指令
/// <summary>
/// 清除错误队列 (*CLS)
/// </summary>
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 重设仪器为初始状态 (*RST)
/// </summary>
public virtual async Task 复位Async(CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询仪器识别码 (*IDN?)
/// </summary>
public virtual async Task<string> 查询设备信息Async(CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 命令流延时 (*D)
/// <para>在 SCPI 命令流中插入一段延时(单位: ms),常用于 LIST 参数下发完成后、切换 OUTP:MODE 之前等待仪器就绪</para>
/// </summary>
/// <param name="milliseconds">延时时长 (ms)</param>
public virtual async Task 延时Async(double milliseconds, CancellationToken ct = default)
{
string valStr = milliseconds.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"*D {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 退出远程状态、回到本地 (SYST:LOC,即 SYSTem:LOCal)
/// <para>设定后仪器回到 LOCAL 状态,前面板恢复可用。手册注明本命令僅可用於 RS-232 控制之下,
/// 经 Ethernet/USB 发送时仪器可能不响应</para>
/// </summary>
public virtual async Task 退出远程Async(CancellationToken ct = default)
{
await SendAsync($"SYST:LOC{ScpiDelimiter}", ct);
}
/// <summary>
/// 进入远程状态 (SYST:REM,即 SYSTem:REMote)
/// <para>设定后除 LOCAL/REMOTE 键外前面板其他键皆无效。手册注明本命令僅可用於 RS-232 控制之下</para>
/// </summary>
public virtual async Task 进入远程Async(CancellationToken ct = default)
{
await SendAsync($"SYST:REM{ScpiDelimiter}", ct);
}
#endregion
#region 2. 基础输出与耦合控制 (OUTPut 子系统)
/// <summary>
/// 设置输出开关状态 (OUTP ON / OFF)
/// </summary>
/// <param name="isOn">true: 开启输出, false: 关闭输出</param>
public virtual async Task 设置输出开关Async(bool isOn, CancellationToken ct = default)
{
string state = isOn ? "ON" : "OFF";
await SendAsync($"OUTP {state}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)
/// </summary>
public virtual async Task 设置耦合模式Async(string couplingMode, CancellationToken ct = default)
{
// 有效参数: AC, DC, ACDC
await SendAsync($"OUTP:COUP {couplingMode}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置输出继电器状态 (OUTP:REL ON | OFF)
/// </summary>
public virtual async Task 设置输出继电器Async(bool isOn, CancellationToken ct = default)
{
string state = isOn ? "ON" : "OFF";
await SendAsync($"OUTP:REL {state}{ScpiDelimiter}", ct);
}
#endregion
#region 3. 电源核心参数设置 (SOURCE 子系统)
/// <summary>
/// 设置交流电压 (VOLT:AC)
/// </summary>
/// <param name="voltage">电压值 (0.0 ~ 350.0V)</param>
public virtual async Task 设置交流电压Async(double voltage, CancellationToken ct = default)
{
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"VOLT:AC {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置直流电压 (VOLT:DC)
/// </summary>
/// <param name="voltage">电压值 (-495.0 ~ 495.0V)</param>
public virtual async Task 设置直流电压Async(double voltage, CancellationToken ct = default)
{
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"VOLT:DC {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置输出频率 (FREQ)
/// </summary>
/// <param name="frequency">频率值 (30.00 ~ 100.00 Hz)</param>
public virtual async Task 设置频率Async(double frequency, CancellationToken ct = default)
{
string valStr = frequency.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"FREQ {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置波形 A 组形状 (FUNC:SHAP:A)
/// <para>冒号后的 A 是波形组别(仪器有 A/B 两组波形寄存器),不是波形形状;
/// 三角波拼写为 TRIAN(TRIA/TRI 均非法,仪器只接受精确的 TRIAN)</para>
/// </summary>
/// <param name="shape">SINE | SQUA | TRIAN | CSIN | DST01~DST30(内建)| USR01~USR30(用户自定义)</param>
public virtual async Task 设置波形Async(string shape, CancellationToken ct = default)
{
await SendAsync($"FUNC:SHAP:A {shape}{ScpiDelimiter}", ct);
}
#endregion
#region 4. 相位与多相模式控制 (INST & PHASE 子系统)
/// <summary>
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE / SPLIT)
/// </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)
/// </summary>
public virtual async Task 设置三相关系Async(string relation, CancellationToken ct = default)
{
// 有效参数: INDEPEND, SAMEFREQ, BALANCE
await SendAsync($"PHASE:THREE {relation}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置相位耦合模式 (INST:COUP)
/// <para>ALL: 后续命令发送至所有相位; NONE: 仅发送至 NSEL 选定的相位</para>
/// </summary>
/// <param name="coupling">耦合模式: ALL | NONE</param>
public virtual async Task 设置相位耦合Async(string coupling, CancellationToken ct = default)
{
await SendAsync($"INST:COUP {coupling}{ScpiDelimiter}", ct);
}
/// <summary>
/// 按编号选择输出相位 (INST:NSEL)
/// <para>仅在 INST:COUP NONE 时生效,后续 SOURCE 命令将作用于选定相位</para>
/// </summary>
/// <param name="phase">相位编号: 1(A相) | 2(B相) | 3(C相)</param>
public virtual async Task 选择相位Async(int phase, CancellationToken ct = default)
{
await SendAsync($"INST:NSEL {phase}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置参数编辑方式 (INST:EDIT)
/// <para>EACH: 逐相独立编辑,配合 <see cref="选择相位Async"/> 分别为 A/B/C 三相下发各自的 LIST/参数;
/// ALL: 三相统一编辑,一次下发同时作用于三相</para>
/// </summary>
/// <param name="mode">编辑方式: EACH | ALL</param>
public virtual async Task 设置编辑方式Async(string mode, CancellationToken ct = default)
{
await SendAsync($"INST:EDIT {mode}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置输出开启相位角 (PHASE:ON)
/// </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)
/// </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 子系统)
/// <summary>
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>交流电压均方根值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> 读取交流电压Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:VOLT:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询交流电流均方根值 (MEAS:CURR:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>交流电流均方根值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> 读取交流电流Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:CURR:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询输出频率 (MEAS:FREQ?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>输出频率值 (单位: Hz,保留两位小数)</returns>
public virtual async Task<double> 读取频率Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询真实输出功率 (MEAS:POW:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>真实输出功率值 (单位: W,保留两位小数)</returns>
public virtual async Task<double> 读取真实功率Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:POW:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
#endregion
#region 6. LIST 模式子系统 (LIST 子系统)
/// <summary>
/// 设定列表功能的模态 (SOUR:LIST:COUP)
/// </summary>
/// <param name="coupling">耦合模态: ALL | NONE</param>
public virtual async Task 设置列表耦合模态Async(string coupling, CancellationToken ct = default)
{
await SendAsync($"SOUR:LIST:COUP {coupling}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定列表功能的触发形态 (SOUR:LIST:TRIG)
/// </summary>
/// <param name="triggerMode">触发形态: AUTO | MANUAL | EXCITE</param>
public virtual async Task 设置列表触发形态Async(string triggerMode, CancellationToken ct = default)
{
await SendAsync($"SOUR:LIST:TRIG {triggerMode}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询列表功能的有效序列数 (SOUR:LIST:POIN?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>有效序列数 (0 ~ 100)</returns>
public virtual async Task<int> 查询列表有效序列数Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:LIST:POIN?{ScpiDelimiter}", ScpiDelimiter, ct);
return int.TryParse(resp.Trim(), out int val) ? val : 0;
}
/// <summary>
/// 设定列表执行完成前的执行次数 (SOUR:LIST:COUN)
/// </summary>
/// <param name="count">执行次数 (0 ~ 65535)</param>
public virtual async Task 设置列表执行次数Async(int count, CancellationToken ct = default)
{
await SendAsync($"SOUR:LIST:COUN {count}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询当前相位上下文的列表执行次数 (SOUR:LIST:COUN?),用于下发后回读校验
/// </summary>
/// <returns>执行次数 (0 = 无限循环);解析失败返回 -1</returns>
public virtual async Task<int> 查询列表执行次数Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:LIST:COUN?{ScpiDelimiter}", ScpiDelimiter, ct);
return int.TryParse(resp.Trim(), out int val) ? val : -1;
}
/// <summary>
/// 设定列表点的静止时间顺序 (SOUR:LIST:DWEL)
/// </summary>
/// <param name="dwellTimes">静止时间序列 (单位: ms,每个值 0 ~ 99999999.9)</param>
public virtual async Task 设置列表静止时间顺序Async(double[] dwellTimes, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(dwellTimes, v => v.ToString("0.#", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:DWEL {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定波形缓冲区列表点数的顺序 (SOUR:LIST:SHAP)
/// </summary>
/// <param name="shapes">各点波形: A | B | SINE | SQUA | TRIAN | CSIN | DST01~DST30 | USR01~USR30(可直接写形状名,也可引用 A/B 波形组)</param>
public virtual async Task 设置列表波形顺序Async(string[] shapes, CancellationToken ct = default)
{
string valStr = string.Join(",", shapes);
await SendAsync($"SOUR:LIST:SHAP {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定列表的时间基础 (SOUR:LIST:BASE)
/// </summary>
/// <param name="timeBase">时间基础: TIME | CYCLE</param>
public virtual async Task 设置列表时间基础Async(string timeBase, CancellationToken ct = default)
{
await SendAsync($"SOUR:LIST:BASE {timeBase}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定列表功能的相位连续功能 (SOUR:LIST:PHAS:CONT)
/// </summary>
/// <param name="state">DISABLE | ENABLE</param>
public virtual async Task 设置列表相位连续Async(string state, CancellationToken ct = default)
{
await SendAsync($"SOUR:LIST:PHAS:CONT {state}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询列表功能的相位连续功能 (SOUR:LIST:PHAS:CONT?),返回 DISABLE 或 ENABLE
/// </summary>
public virtual async Task<string> 查询列表相位连续Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:LIST:PHAS:CONT?{ScpiDelimiter}", ScpiDelimiter, ct);
return resp?.Trim() ?? string.Empty;
}
/// <summary>
/// 设定 AC 起始电压列表点数的顺序 (SOUR:LIST:VOLT:AC:STAR)
/// </summary>
/// <param name="voltages">AC 起始电压序列 (单位: V,每个值 0.0 ~ 350.0)</param>
public virtual async Task 设置列表AC起始电压顺序Async(double[] voltages, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(voltages, v => v.ToString("0.###", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:VOLT:AC:STAR {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 AC 结束电压列表点数的顺序 (SOUR:LIST:VOLT:AC:END)
/// </summary>
/// <param name="voltages">AC 结束电压序列 (单位: V,每个值 0.0 ~ 350.0)</param>
public virtual async Task 设置列表AC结束电压顺序Async(double[] voltages, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(voltages, v => v.ToString("0.###", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:VOLT:AC:END {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 DC 起始电压列表点数的顺序 (SOUR:LIST:VOLT:DC:STAR)
/// </summary>
/// <param name="voltages">DC 起始电压序列 (单位: V,每个值 -495.0 ~ 495.0)</param>
public virtual async Task 设置列表DC起始电压顺序Async(double[] voltages, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(voltages, v => v.ToString("0.###", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:VOLT:DC:STAR {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 DC 结束电压列表点数的顺序 (SOUR:LIST:VOLT:DC:END)
/// </summary>
/// <param name="voltages">DC 结束电压序列 (单位: V,每个值 -495.0 ~ 495.0)</param>
public virtual async Task 设置列表DC结束电压顺序Async(double[] voltages, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(voltages, v => v.ToString("0.###", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:VOLT:DC:END {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定起始频率列表点数的顺序 (SOUR:LIST:FREQ:STAR)
/// </summary>
/// <param name="frequencies">起始频率序列 (单位: Hz,每个值 30.00 ~ 100.00)</param>
public virtual async Task 设置列表起始频率顺序Async(double[] frequencies, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(frequencies, v => v.ToString("0.##", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:FREQ:STAR {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定结束频率列表点数的顺序 (SOUR:LIST:FREQ:END)
/// </summary>
/// <param name="frequencies">结束频率序列 (单位: Hz,每个值 30.00 ~ 100.00)</param>
public virtual async Task 设置列表结束频率顺序Async(double[] frequencies, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(frequencies, v => v.ToString("0.##", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:FREQ:END {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定相位角度列表点数的顺序 (SOUR:LIST:DEGR)
/// </summary>
/// <param name="degrees">相位角度序列 (单位: °,每个值 0.0 ~ 359.9)</param>
public virtual async Task 设置列表相位角度顺序Async(double[] degrees, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(degrees, v => v.ToString("0.#", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:LIST:DEGR {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定操作模态 (OUTP:MODE)
/// </summary>
/// <param name="mode">操作模态: FIXED | LIST | PULSE | STEP | SYNTH | INTERHAR</param>
public virtual async Task 设置操作模态Async(string mode, CancellationToken ct = default)
{
await SendAsync($"OUTP:MODE {mode}{ScpiDelimiter}", ct);
}
/// <summary>
/// 在 LIST 模态下设定执行状态 (TRIG)
/// <para>需先通过 <see cref="设置操作模态Async"/> 将 OUTP:MODE 设为 LIST</para>
/// </summary>
/// <param name="isOn">true: 开始执行 LIST, false: 停止 LIST</param>
public virtual async Task 触发列表执行Async(bool isOn, CancellationToken ct = default)
{
string state = isOn ? "ON" : "OFF";
await SendAsync($"TRIG {state}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询列表触发执行状态 (TRIG:STATE?)
/// <para>返回 ON 表示 LIST 正在执行,OFF 表示已执行完毕;
/// 重新下发 LIST 参数前应先轮询本命令等待其变为 OFF,避免执行中被改写</para>
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>true: 正在执行(ON); false: 已结束(OFF)</returns>
public virtual async Task<bool> 查询触发状态Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"TRIG:STATE?{ScpiDelimiter}", ScpiDelimiter, ct);
return resp != null && resp.Trim().StartsWith("ON", StringComparison.OrdinalIgnoreCase);
}
#endregion
#region 7. 谐波量测 (Harmonic Sense 子系统)
/// <summary>
/// 设置谐波分析的测量来源 (CONFigure:HARMonic:SOURce)
/// </summary>
/// <param name="source">VOLT: 输出电压; CURR: 输出电流</param>
public virtual async Task 设置谐波量测源Async(string source, CancellationToken ct = default)
{
// 有效参数: VOLT, CURR
await SendAsync($"CONF:HARM:SOUR {source}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置谐波量测结果显示方式 (CONFigure:HARMonic:TIMES)
/// <para>SINGLE: 保留单次测量结果,约需 3 秒; CONTINUE: 持续更新,约需 10 秒稳定</para>
/// </summary>
/// <param name="times">显示方式: SINGLE | CONTINUE</param>
public virtual async Task 设置谐波量测方式Async(string times, CancellationToken ct = default)
{
// 有效参数: SINGLE, CONTINUE
await SendAsync($"CONF:HARM:TIM {times}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置每个谐波阶的数据格式 (CONFigure:HARMonic:PARameter)
/// </summary>
/// <param name="parameter">VALUE: 绝对值; PERCENT: 基频百分率</param>
public virtual async Task 设置谐波数据格式Async(string parameter, CancellationToken ct = default)
{
// 有效参数: VALUE, PERCENT
await SendAsync($"CONF:HARM:PAR {parameter}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置谐波分析的原始波形基频 (CONFigure:HARMonic:FREQuency)
/// </summary>
/// <param name="frequency">基频: 50 或 60 (Hz)</param>
public virtual async Task 设置谐波基频Async(int frequency, CancellationToken ct = default)
{
await SendAsync($"CONF:HARM:FREQ {frequency}{ScpiDelimiter}", ct);
}
/// <summary>
/// 开启/关闭谐波量测 (SENSe:HARMonic)
/// <para>每次新的 Fetch
/// ./Measure 前必须先 ON,约需 3 秒得到结果;
/// 若要量测其他数据,须先设回 OFF。分相量测配合 INST:COUP NONE + INST:NSEL 逐相进行</para>
/// </summary>
/// <param name="isOn">true: 开启谐波量测(ON); false: 关闭(OFF)</param>
public virtual async Task 设置谐波量测开关Async(bool isOn, CancellationToken ct = default)
{
string state = isOn ? "ON" : "OFF";
await SendAsync($"SENS:HARM {state}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询总谐波失真 (MEASure:HARMonic:THD?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>总谐波失真 THD (单位: %,保留两位小数)</returns>
public virtual async Task<double> 查询谐波总失真Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:HARM:THD?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询输出电压/电流的基频幅值 (MEASure:HARMonic:FUNDamental?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>基频幅值 (单位依 CONF:HARM:PAR 为 V/A 绝对值或百分率)</returns>
public virtual async Task<double> 查询谐波基频幅值Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:HARM:FUND?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询所有谐波阶的振幅数组 (MEASure:HARMonic:ARRay?)
/// <para>手册 5.7 谐波测量:可量测 2~50 阶谐波,来源可选输出电压(VOLT)或电流(CURR)。
/// 注意:仅返回各阶振幅,不含各阶相位角,故据此重构的波形形状为"同相叠加"近似</para>
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>各次谐波振幅数组(按阶次升序;单位依 CONF:HARM:PAR)</returns>
public virtual async Task<double[]> 查询谐波振幅数组Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:HARM:ARR?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDoubleArray(resp);
}
#endregion
#region 8. SYNTHESIS 波形合成子系统 (SYNThesis 子系统 · 自定义谐波波形输出)
/// <summary>
/// 设定每个谐波阶的数据格式 (SOUR:SYNT:COMP)
/// <para>VALUE: 绝对值; PERCENT: 基频电压的百分率。后缀 1/2/3 对应三段可编程波形</para>
/// </summary>
/// <param name="compose">数据格式: VALUE1 | VALUE2 | VALUE3 | PERCENT1 | PERCENT2 | PERCENT3</param>
public virtual async Task 设置合成数据格式Async(string compose, CancellationToken ct = default)
{
await SendAsync($"SOUR:SYNT:COMP {compose}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定每个谐波阶的振幅 (SOUR:SYNT:AMPL)
/// <para>最大位阶数为 50;各阶取值上限随阶次递减(2~10 阶 0~90.0,11~20 阶 0~60.0,
/// 21~30 阶 0~30.0,31~40 阶 0~30.0,41~50 阶 0~15.0;PERCENT 格式对应减半)</para>
/// </summary>
/// <param name="amplitudes">各次谐波振幅序列(按阶次升序,逗号下发)</param>
public virtual async Task 设置合成谐波振幅Async(double[] amplitudes, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(amplitudes, v => v.ToString("0.###", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:SYNT:AMPL {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定每个谐波阶的相位角 (SOUR:SYNT:PHAS)
/// </summary>
/// <param name="phases">各次谐波相位角序列(单位: °,每个值 0.0 ~ 359.9)</param>
public virtual async Task 设置合成谐波相位Async(double[] phases, CancellationToken ct = default)
{
string valStr = string.Join(",", Array.ConvertAll(phases, v => v.ToString("0.#", CultureInfo.InvariantCulture)));
await SendAsync($"SOUR:SYNT:PHAS {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 SYNTHESIS 模式的基波交流电压 (SOUR:SYNT:FUND)
/// </summary>
/// <param name="voltage">基波交流电压 (单位: V,0.0 ~ 350.0)</param>
public virtual async Task 设置合成基波电压Async(double voltage, CancellationToken ct = default)
{
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"SOUR:SYNT:FUND {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定叠加于 SYNTHESIS 波形的直流电压 (SOUR:SYNT:DC)
/// </summary>
/// <param name="voltage">直流电压 (单位: V,-495.0 ~ 495.0)</param>
public virtual async Task 设置合成直流电压Async(double voltage, CancellationToken ct = default)
{
string valStr = voltage.ToString("0.###", CultureInfo.InvariantCulture);
await SendAsync($"SOUR:SYNT:DC {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 SYNTHESIS 模式的基频 (SOUR:SYNT:FREQ)
/// </summary>
/// <param name="frequency">基频: 50 或 60 (Hz)</param>
public virtual async Task 设置合成基频Async(int frequency, CancellationToken ct = default)
{
await SendAsync($"SOUR:SYNT:FREQ {frequency}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设定 SYNTHESIS 模式的起始相位角 (SOUR:SYNT:SPH)
/// </summary>
/// <param name="degree">起始相位角 (单位: °,0.0 ~ 359.9)</param>
public virtual async Task 设置合成起始相位Async(double degree, CancellationToken ct = default)
{
string valStr = degree.ToString("0.#", CultureInfo.InvariantCulture);
await SendAsync($"SOUR:SYNT:SPH {valStr}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询当前合成数据格式 (SOUR:SYNT:COMP?),用于下发后回读校验
/// </summary>
/// <returns>VALUE1|2|3 / PERCENT1|2|3</returns>
public virtual async Task<string> 查询合成数据格式Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:COMP?{ScpiDelimiter}", ScpiDelimiter, ct);
return resp?.Trim() ?? string.Empty;
}
/// <summary>
/// 查询 SYNTHESIS 基波交流电压 (SOUR:SYNT:FUND?),用于下发后回读校验
/// </summary>
public virtual async Task<double> 查询合成基波电压Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:FUND?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询 SYNTHESIS 基频 (SOUR:SYNT:FREQ?),返回 50 或 60
/// </summary>
public virtual async Task<int> 查询合成基频Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
return (int)ExtractDouble(resp);
}
/// <summary>
/// 查询 SYNTHESIS 叠加直流电压 (SOUR:SYNT:DC?)
/// </summary>
public virtual async Task<double> 查询合成直流电压Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:DC?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询 SYNTHESIS 起始相位角 (SOUR:SYNT:SPH?)
/// </summary>
public virtual async Task<double> 查询合成起始相位Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:SPH?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 查询各谐波阶振幅数组 (SOUR:SYNT:AMPL?),首值对应 2 次谐波
/// </summary>
public virtual async Task<double[]> 查询合成谐波振幅Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:AMPL?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDoubleArray(resp);
}
/// <summary>
/// 查询各谐波阶相位角数组 (SOUR:SYNT:PHAS?),首值对应 2 次谐波
/// </summary>
public virtual async Task<double[]> 查询合成谐波相位Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"SOUR:SYNT:PHAS?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDoubleArray(resp);
}
#endregion
}
}