Files
front_linux/LFtid1056/pqdif_thread_processor.h

769 lines
36 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.

#pragma once
#include <ctime>
#include <cstddef>
#include <complex>
#include <map>
#include <string>
#include <vector>
#include "pqdif/include/pqdif_ph.h"
// ============================
// 新版:完整 PQDIF 逻辑结构
// 说明:
// 1) 该结构尽量忠实表达 PQDIF 的“文件 -> 记录 -> 定义/实例 -> 数组值”关系;
// 2) 后续所有映射、归并、按时刻整合都应该基于这些结构做;
// 3) 对暂未显式建模的标签,统一进入 extra_tags避免丢失信息。
// ============================
using PqdifExtraTagMap = std::map<std::string, std::string>;
// GUID 及其可读名称
struct PqdifGuidValue
{
GUID value{}; // 原始 GUID 值
std::string symbolic_name; // 通过 PQDIF 信息表解析出的标准名,如 tagPhaseID / ID_QT_VALUELOG 等
};
// PQDIF 原始时间戳
struct PqdifTimestampValue
{
UINT4 day = 0; // 自 1900-01-01 起的天数PQDIF 原始 day 字段
double second = 0.0; // 当天起算的秒PQDIF 原始 sec 字段
time_t unix_time = 0; // 转换后的 Unix 时间戳,便于上层使用
std::string text; // 格式化后的本地时间文本,便于调试和日志输出
};
// 记录头信息
struct PqdifRecordHeaderInfo
{
long record_index = -1; // 本记录在文件中的顺序索引
long file_position = 0; // 记录头在文件中的偏移
PqdifGuidValue record_type; // 记录类型,如 tagContainer / tagRecDataSource / tagRecObservation
long header_size = 0; // 记录头字节数
long data_size = 0; // 记录体字节数
long next_record_position = 0; // 下一条记录偏移
unsigned int checksum = 0; // 记录校验值
};
// 通用数组值容器:用于保存 PQDIF 向量/序列的真正数组内容
struct PqdifValueArray
{
int physical_type = -1; // PQDIF 物理类型 ID例如 REAL8 / UINT4 / TIMESTAMPPQDIF
long count = 0; // 数组点数
std::vector<bool> bool_values; // 布尔数组
std::vector<long long> int_values; // 有符号整数数组
std::vector<unsigned long long> uint_values; // 无符号整数数组
std::vector<double> real_values; // 浮点数组,最常见的统计值/波形值
std::vector<std::complex<double>> complex_values; // 复数数组
std::vector<PqdifTimestampValue> timestamp_values; // 时间戳数组
std::vector<PqdifGuidValue> guid_values; // GUID 数组
std::vector<std::string> text_values; // 字符串数组CHAR1/CHAR2
};
// Container / General Record文件级元数据
struct PqdifContainerRecord
{
PqdifRecordHeaderInfo header; // 记录头
std::vector<unsigned int> version_info; // tagVersionInfo格式版本号数组
std::string file_name; // tagFileName原始文件名
PqdifTimestampValue creation_time; // tagCreation文件创建时间
PqdifTimestampValue last_saved_time; // tagLastSaved最后保存时间
unsigned int times_saved = 0; // tagTimesSaved保存次数
std::string language; // tagLanguage语言
std::string title; // tagTitle标题
std::string subject; // tagSubject主题
std::string author; // tagAuthor作者
std::string keywords; // tagKeywords关键字
std::string comments; // tagComments备注
std::string last_saved_by; // tagLastSavedBy最后保存者
std::string application; // tagApplication生成软件
PqdifGuidValue compression_style_id; // tagCompressionStyleID压缩风格
unsigned int compression_algorithm_id = 0; // tagCompressionAlgorithmID压缩算法
unsigned int compression_checksum = 0; // tagCompressionChecksum压缩校验值
std::string owner; // tagOwner所有者
std::string copyright; // tagCopyright版权
std::string trademarks; // tagTrademarks商标
std::string notes; // tagNotes附加说明
std::string address1; // tagAddress1地址行 1
std::string address2; // tagAddress2地址行 2
std::string city; // tagCity城市
std::string state; // tagState州/省
std::string postal_code; // tagPostalCode邮编
std::string country; // tagCountry国家
std::string phone_voice; // tagPhoneVoice电话
std::string phone_fax; // tagPhoneFAX传真
std::string email; // tagEmail邮箱
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Series Definition序列定义描述“这一列是什么”
struct PqdifSeriesDefinition
{
int series_def_index = -1; // 序列定义在所属通道定义中的顺序索引
unsigned int quantity_units_id = 0; // tagQuantityUnitsID单位 ID
PqdifGuidValue quantity_characteristic_id; // tagQuantityCharacteristicID特征量 ID
PqdifGuidValue value_type_id; // tagValueTypeID值类型 ID例如 TIME / AVG / MAX / MIN / VAL
unsigned int storage_method_id = 0; // tagStorageMethodID序列存储方式
unsigned int significant_digits_id = 0; // tagQuantitySignificantDigitsID有效位定义
double quantity_resolution = 0.0; // tagQuantityResolutionID / 解析出的分辨率
double nominal_quantity = 0.0; // tagSeriesNominalQuantity标称值
std::string value_type_name; // tagValueTypeName值类型显示名
unsigned int hint_greek_prefix_id = 0; // tagHintGreekPrefixID显示前缀提示
unsigned int hint_preferred_units_id = 0; // tagHintPreferredUnitsID优选单位提示
unsigned int hint_default_display_id = 0; // tagHintDefaultDisplayID默认显示方式提示
double prob_interval = 0.0; // tagProbInterval概率间隔
double prob_percentile = 0.0; // tagProbPercentile概率百分位
PqdifTimestampValue effective_time; // tagEffective定义生效时间
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Channel Definition通道定义描述“这个通道测什么”
struct PqdifChannelDefinition
{
int channel_def_index = -1; // 通道定义在数据源中的顺序索引
std::string channel_name; // tagChannelName通道名称
unsigned int phase_id = 0; // tagPhaseID相别
std::string other_channel_identifier; // tagOtherChannelIdentifier附加通道标识
std::string group_name; // tagGroupName组名称
PqdifGuidValue quantity_type_id; // tagQuantityTypeID量类型如 VALUELOG / PHASOR
unsigned int quantity_measured_id = 0; // tagQuantityMeasuredID被测量对象如电压/电流/频率)
unsigned int physical_channel = 0; // tagPhysicalChannel物理通道编号
std::string quantity_name; // tagQuantityName自定义量名称
int primary_series_index = -1; // tagPrimarySeriesIdx主序列索引
std::vector<PqdifSeriesDefinition> series_definitions; // 该通道下的全部序列定义
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Data Source Record数据源定义描述设备和通道体系
struct PqdifDataSourceRecord
{
PqdifRecordHeaderInfo header; // 记录头
int data_source_index = -1; // 在文件中解析出的数据源顺序索引
long record_index = -1; // 对应文件记录索引,便于关联 Observation
PqdifGuidValue data_source_type_id; // tagDataSourceTypeID数据源类型
PqdifGuidValue vendor_id; // tagVendorID厂商 ID
PqdifGuidValue equipment_id; // tagEquipmentID设备型号 ID
std::string custom_source_info; // tagCustomSourceInfo扩展来源信息
PqdifGuidValue instrument_type_id; // tagInstrumentTypeID仪器类型
std::string instrument_model_name; // tagInstrumentModelName仪器型号名称
std::string instrument_model_number; // tagInstrumentModelNumber仪器型号编号
std::string serial_number; // tagSerialNumberDS序列号
std::string version; // tagVersionDS版本号
std::string name; // tagNameDS设备名称
std::string owner; // tagOwnerDS设备归属
std::string location; // tagLocationDS安装位置
std::string time_zone; // tagTimeZoneDS时区文本
std::string coordinates; // tagCoordinatesDS坐标信息
std::vector<PqdifChannelDefinition> channel_definitions; // 数据源下的全部通道定义
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Monitor Settings 中单通道的配置
struct PqdifChannelSetting
{
int channel_setting_index = -1; // 通道设置在监测设置记录中的顺序索引
int channel_def_index = -1; // tagChannelDefnIdx关联的数据源通道定义索引
unsigned int trigger_type_id = 0; // tagTriggerTypeID触发类型
double full_scale = 0.0; // tagFullScale满量程
double noise_floor = 0.0; // tagNoiseFloor噪声底
PqdifValueArray trigger_shape_param; // tagTriggerShapeParam触发曲线/参数数组
unsigned int xd_transformer_type_id = 0; // tagXDTransformerTypeID互感器类型
double xd_system_side_ratio = 0.0; // tagXDSystemSideRatio一次侧变比
double xd_monitor_side_ratio = 0.0; // tagXDMonitorSideRatio监测侧变比
PqdifValueArray xd_frequency_response; // tagXDFrequencyResponse频率响应数组
double cal_time_skew = 0.0; // tagCalTimeSkew校准时延
double cal_offset = 0.0; // tagCalOffset校准偏移
double cal_ratio = 0.0; // tagCalRatio校准比例
bool cal_must_use_arcal = false; // tagCalMustUseARCal是否必须使用校准曲线
PqdifValueArray cal_applied; // tagCalApplied校准应用值数组
PqdifValueArray cal_recorded; // tagCalRecorded校准记录值数组
double trigger_high_high = 0.0; // tagTriggerHighHigh高高阈值
double trigger_high = 0.0; // tagTriggerHigh高阈值
double trigger_low = 0.0; // tagTriggerLow低阈值
double trigger_low_low = 0.0; // tagTriggerLowLow低低阈值
double trigger_deadband = 0.0; // tagTriggerDeadband死区
double trigger_rate = 0.0; // tagTriggerRate触发速率
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Monitor Settings Record监测装置配置
struct PqdifMonitorSettingsRecord
{
PqdifRecordHeaderInfo header; // 记录头
int settings_index = -1; // 在文件中解析出的监测设置顺序索引
long record_index = -1; // 对应文件记录索引,便于关联 Observation
PqdifTimestampValue effective_time; // tagEffective配置生效时间
PqdifTimestampValue time_installed; // tagTimeInstalled安装时间
PqdifTimestampValue time_removed; // tagTimeRemoved拆除时间
bool use_calibration = false; // tagUseCalibration是否使用校准
bool use_transducer = false; // tagUseTransducer是否使用传感器/互感器
double nominal_frequency = 0.0; // tagNominalFrequency额定频率
unsigned int physical_connection = 0; // tagSettingPhysicalConnection物理接线方式
double nominal_voltage = 0.0; // tagNominalVoltage额定电压
bool is_pcc = false; // tagIsPCC是否为 PCC 点
std::vector<PqdifChannelSetting> channel_settings; // 各通道的监测配置
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Observation 中单个序列实例:保存某一次观测里的一个真实数组
struct PqdifSeriesInstance
{
int series_instance_index = -1; // 序列实例在通道实例中的顺序索引
int series_def_index = -1; // 关联的数据源序列定义索引(通常与定义层顺序一致)
unsigned int quantity_units_id = 0; // tagQuantityUnitsID本实例对应的单位 ID
PqdifGuidValue quantity_characteristic_id; // tagQuantityCharacteristicID本实例特征量 ID
PqdifGuidValue value_type_id; // tagValueTypeID本实例值类型 ID
long series_base_type = -1; // 当前库暴露的底层序列物理类型
double series_base_quantity = 0.0; // tagSeriesBaseQuantity序列基值
double scale = 1.0; // tagSeriesScale缩放系数
double offset = 0.0; // tagSeriesOffset偏移量
double nominal_quantity = 0.0; // 关联定义层解析出的标称量
unsigned int significant_digits_id = 0; // 关联定义层解析出的有效位配置
double quantity_resolution = 0.0; // 关联定义层解析出的分辨率
int share_channel_index = -1; // tagSeriesShareChannelIdx共享通道索引
int share_series_index = -1; // tagSeriesShareSeriesIdx共享序列索引
PqdifValueArray values; // tagSeriesValues真正的数组值
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Observation 中单个通道实例:保存某一次观测里的一个真实通道块
struct PqdifChannelInstance
{
int channel_instance_index = -1; // 通道实例在观测中的顺序索引
int channel_def_index = -1; // 关联的数据源通道定义索引
std::string channel_name; // 从 Observation 读出的通道名
unsigned int phase_id = 0; // 相别
PqdifGuidValue quantity_type_id; // 量类型
unsigned int quantity_measured_id = 0; // 被测量对象
int primary_series_index = -1; // 主序列索引
double charact_duration = 0.0; // tagCharactDuration特征持续时间
double charact_magnitude = 0.0; // tagCharactMagnitude特征幅值
double charact_frequency = 0.0; // tagCharactFrequency特征频率
double channel_frequency = 0.0; // tagChannelFrequency通道频率
int channel_group_id = 0; // tagChannelGroupID通道分组
std::vector<PqdifSeriesInstance> series_instances; // 该通道实例下的所有序列实例
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// Observation Record一次真实观测
struct PqdifObservationRecord
{
PqdifRecordHeaderInfo header; // 记录头
int observation_index = -1; // 在文件中解析出的观测顺序索引
long record_index = -1; // 对应文件记录索引
int related_data_source_index = -1; // 该观测关联的数据源顺序索引
long related_data_source_record_index = -1; // 该观测关联的数据源记录索引
int related_settings_index = -1; // 该观测关联的监测设置顺序索引
long related_settings_record_index = -1; // 该观测关联的监测设置记录索引
std::string observation_name; // tagObservationName观测名称
PqdifTimestampValue time_create; // tagTimeCreate观测记录创建时间
PqdifTimestampValue time_start; // tagTimeStart观测起始时间
unsigned int trigger_method_id = 0; // tagTriggerMethodID触发方式
PqdifTimestampValue time_triggered; // tagTimeTriggered触发时刻
std::vector<int> channel_trigger_indexes; // tagChannelTriggerIdx触发通道索引数组
unsigned int observation_serial = 0; // tagObservationSerial观测序号
unsigned int observation_aggregation_serial = 0; // tagObservationAggregationSerial聚合序号
PqdifGuidValue disturbance_category_id; // tagDisturbanceCategoryID扰动分类
std::vector<PqdifChannelInstance> channel_instances; // 本次观测中的所有通道实例
PqdifExtraTagMap extra_tags; // 当前结构未单独建模但已读出的标签
};
// 文件级完整逻辑对象
struct PqdifLogicalFile
{
std::vector<PqdifRecordHeaderInfo> record_headers; // 文件中所有记录的头信息,保留顺序
std::vector<PqdifContainerRecord> containers; // Container / General 记录,一般只有一个
std::vector<PqdifDataSourceRecord> data_sources; // 全部数据源记录
std::vector<PqdifMonitorSettingsRecord> monitor_settings; // 全部监测设置记录
std::vector<PqdifObservationRecord> observations; // 全部观测记录
};
// ============================
// 统计识别与同一时间聚合层
// 说明:
// 1) 这一层只服务于“从完整 PQDIF 结构中识别目标统计指标并按时间聚合”;
// 2) 当前阶段先不做 tagPqData_Float 映射;
// 3) 当前阶段只处理“筛选出的统计类 observation”其他 observation 暂不参与识别。
// ============================
// 解析得到的接线方式
// 用于区分星型 / 角型 两套指标规则。
enum class ParsedConnectionKind
{
Unknown = 0, // 未知 / 无法确认
Wye, // 星型 / Y
Delta // 角型 / Δ
};
// 当前支持的业务指标 ID
// 后续如果新增指标,只需要继续往这里加枚举,并在 cpp 里的识别规则补充即可。
enum class StatMetricId
{
Unknown = 0,
// 相电压有效值
UaRms,
UbRms,
UcRms,
// 相电流有效值
IaRms,
IbRms,
IcRms,
// 线电压有效值
UabRms,
UbcRms,
UcaRms,
// 相电压偏差
UaDeviation,
UbDeviation,
UcDeviation,
// 线电压偏差
UabDeviation,
UbcDeviation,
UcaDeviation,
// 频率
Frequency,
// 频率偏差
FrequencyDeviation,
// 电压序分量
UZeroSeq, // 电压零序分量
UNegSeq, // 电压负序分量
UPosSeq, // 电压正序分量
// 电压负序不平衡,通常对应 S2/S1单位可能为 % 或 pu
UNegSeqUnbalance,
// 电流序分量
IZeroSeq, // 电流零序分量
INegSeq, // 电流负序分量
IPosSeq, // 电流正序分量
// 电流负序不平衡,通常对应 S2/S1单位可能为 % 或 pu
INegSeqUnbalance,
// 功率类:三相/总有功、无功、视在功率
PaPower,
PbPower,
PcPower,
PTotalPower,
QaPower,
QbPower,
QcPower,
QTotalPower,
SaPower,
SbPower,
ScPower,
STotalPower,
// 功率因数类:三相/总功率因数、三相/总基波功率因数
PFa,
PFb,
PFc,
PFTotal,
FundPFa,
FundPFb,
FundPFc,
FundPFTotal,
// 电压变动幅值 DVC/dV/V三相与线电压
UaDvc,
UbDvc,
UcDvc,
UabDvc,
UbcDvc,
UcaDvc,
// 闪变:三相和线电压短闪 Pst、长闪 Plt
UaPst,
UbPst,
UcPst,
UabPst,
UbcPst,
UcaPst,
UaPlt,
UbPlt,
UcPlt,
UabPlt,
UbcPlt,
UcaPlt,
// 基波功率:三相/总有功、无功、视在基波功率
PaFundPower,
PbFundPower,
PcFundPower,
PTotalFundPower,
QaFundPower,
QbFundPower,
QcFundPower,
QTotalFundPower,
SaFundPower,
SbFundPower,
ScFundPower,
STotalFundPower,
// 基波有效值与基波相角:三相电压、三相电流、线电压
UaFundRms,
UbFundRms,
UcFundRms,
UaFundAngle,
UbFundAngle,
UcFundAngle,
IaFundRms,
IbFundRms,
IcFundRms,
IaFundAngle,
IbFundAngle,
IcFundAngle,
UabFundRms,
UbcFundRms,
UcaFundRms,
UabFundAngle,
UbcFundAngle,
UcaFundAngle,
// 总谐波畸变率 THD三相电压、三相电流、线电压
UaThd,
UbThd,
UcThd,
IaThd,
IbThd,
IcThd,
UabThd,
UbcThd,
UcaThd,
// 谐波/间谐波类动态指标范围。
//
// 不再为 2-50 次谐波逐项声明 UaHarm02、UaHarm03 ... UcHarm50
// 而是用“指标族基址 + 相别 + 次数”的方式动态构造。这样后续新增
// 电流谐波、间谐波、谐波含有率等指标时,不需要继续堆大量 enum 项。
//
// 当前已启用:
// VoltageHarmonicUaBase + order => UaHarmXX, order=2..50
// VoltageHarmonicUbBase + order => UbHarmXX, order=2..50
// VoltageHarmonicUcBase + order => UcHarmXX, order=2..50
// 预留区间:
// CurrentHarmonic* 后续电流谐波
// VoltageInterharmonic* 后续电压间谐波
// CurrentInterharmonic* 后续电流间谐波
// 三相电压谐波 RMSorder=2..50
VoltageHarmonicUaBase = 10000,
VoltageHarmonicUbBase = 10100,
VoltageHarmonicUcBase = 10200,
// AB/BC/CA 线电压谐波 RMSorder=2..50
LineVoltageHarmonicUabBase = 10300,
LineVoltageHarmonicUbcBase = 10400,
LineVoltageHarmonicUcaBase = 10500,
// 三相电流谐波 RMSorder=2..50
CurrentHarmonicIaBase = 11000,
CurrentHarmonicIbBase = 11100,
CurrentHarmonicIcBase = 11200,
// 三相电压谐波相角order=2..50
VoltageHarmonicAngleUaBase = 12000,
VoltageHarmonicAngleUbBase = 12100,
VoltageHarmonicAngleUcBase = 12200,
// AB/BC/CA 线电压谐波相角order=2..50
LineVoltageHarmonicAngleUabBase = 12300,
LineVoltageHarmonicAngleUbcBase = 12400,
LineVoltageHarmonicAngleUcaBase = 12500,
// 三相电流谐波相角order=2..50
CurrentHarmonicAngleIaBase = 13000,
CurrentHarmonicAngleIbBase = 13100,
CurrentHarmonicAngleIcBase = 13200,
// 三相电压间谐波 RMSslot=0..49 表示 0.5..49.5 次
VoltageInterharmonicUaBase = 14000,
VoltageInterharmonicUbBase = 14100,
VoltageInterharmonicUcBase = 14200,
// AB/BC/CA 线电压间谐波 RMSslot=0..49 表示 0.5..49.5 次
LineVoltageInterharmonicUabBase = 14300,
LineVoltageInterharmonicUbcBase = 14400,
LineVoltageInterharmonicUcaBase = 14500,
// 三相电流间谐波 RMSslot=0..49 表示 0.5..49.5 次
CurrentInterharmonicIaBase = 15000,
CurrentInterharmonicIbBase = 15100,
CurrentInterharmonicIcBase = 15200,
// 谐波功率 2-50 次:三相/总 有功、无功、视在功率
HarmonicActivePowerPaBase = 16000,
HarmonicActivePowerPbBase = 16100,
HarmonicActivePowerPcBase = 16200,
HarmonicActivePowerTotalBase = 16300,
HarmonicReactivePowerQaBase = 16400,
HarmonicReactivePowerQbBase = 16500,
HarmonicReactivePowerQcBase = 16600,
HarmonicReactivePowerTotalBase = 16700,
HarmonicApparentPowerSaBase = 16800,
HarmonicApparentPowerSbBase = 16900,
HarmonicApparentPowerScBase = 17000,
HarmonicApparentPowerTotalBase = 17100,
// 谐波含有率 2-50 次:三相电压、三相电流、线电压
VoltageHarmonicRatioUaBase = 18000,
VoltageHarmonicRatioUbBase = 18100,
VoltageHarmonicRatioUcBase = 18200,
CurrentHarmonicRatioIaBase = 18300,
CurrentHarmonicRatioIbBase = 18400,
CurrentHarmonicRatioIcBase = 18500,
LineVoltageHarmonicRatioUabBase = 18600,
LineVoltageHarmonicRatioUbcBase = 18700,
LineVoltageHarmonicRatioUcaBase = 18800,
};
// 统计值类型:用于把 MIN / MAX / AVG / P95 装进同一时间桶。
enum class StatValueKind
{
Unknown = 0,
Min, // 最小值
Max, // 最大值
Avg, // 平均值
P95 // 95 值 / 百分位 95
};
// 指标质量状态。
// Normal 表示当前指标可正常使用;其他状态用于把“重复来源/全零/量程异常/缺失”显式暴露出来,
// 防止后续新增指标时继续出现静默覆盖或误识别。
enum class StatMetricQuality
{
Normal = 0,
AllZero,
DuplicateSource,
SuspiciousRange,
Missing
};
// 单个“已展开的统计样本点”
// 含义:某个统计 observation 中某个通道/某个序列/某个时间点的一条已还原工程值样本。
struct ExpandedStatPoint
{
time_t timestamp = 0; // 样本对应的绝对时刻
std::string timestamp_text; // 格式化后的时间文本,便于日志和调试
int observation_index = -1; // 来源 observation 索引
int channel_instance_index = -1; // 来源通道实例索引
int channel_def_index = -1; // 来源通道定义索引,便于排查同名/同相通道覆盖
int channel_group_id = 0; // 来源通道分组 ID部分厂家用它表示谐波次数
int channel_spectrum_order_hint = -1; // 当 group/base/nominal 缺失时,从同类通道实例顺序推导出的谐波次数 2..50
int channel_spectrum_block_offset = -1; // 同类通道实例块内偏移;用于排查厂家把谱线拆成多个通道但名称相同的情况
int channel_spectrum_block_size = 0; // 同类通道实例候选总数;用于日志确认是否是 2-50 次整组数据
int series_instance_index = -1; // 来源序列实例索引
int series_def_index = -1; // 来源序列定义索引,便于核查 MIN/MAX/AVG/P95 的定义来源
int sample_index = -1; // 序列内部样本点下标
std::string observation_name; // 来源 observation 名称
std::string channel_name; // 通道名称(如 V RMS A
std::string quantity_name; // 量名称(来自定义层)
unsigned int phase_id = 0; // 相别
PqdifGuidValue quantity_type_id; // 量类型VALUELOG 等)
unsigned int quantity_measured_id = 0; // 被测量对象Voltage / Current
unsigned int quantity_units_id = 0; // 单位 ID
PqdifGuidValue quantity_characteristic_id;// 特征量RMS / FREQUENCY
PqdifGuidValue value_type_id; // 值类型MIN / MAX / AVG / P95
double prob_percentile = 0.0; // 序列定义中的概率百分位(若有)
double series_base_quantity = 0.0; // 序列基值;部分 PQDIF 厂家会用它表达谐波次数
double nominal_quantity = 0.0; // 标称量;部分 PQDIF 厂家会用它表达谐波次数
double value = 0.0; // 工程值(已完成 scale/offset 还原)
ParsedConnectionKind connection_kind = ParsedConnectionKind::Unknown; // 当前文件识别出的接线方式
StatMetricId metric_id = StatMetricId::Unknown; // 该样本点识别出的业务指标
StatValueKind stat_kind = StatValueKind::Unknown; // 该样本点属于 MIN/MAX/AVG/P95 哪一种
bool matched_by_name_fallback = false; // 是否通过名称辅助规则匹配成功
};
// 某一个业务指标在某个时间点上的统计值集合
struct AggregatedStatValues
{
bool has_min = false; // 是否存在最小值
bool has_max = false; // 是否存在最大值
bool has_avg = false; // 是否存在平均值
bool has_p95 = false; // 是否存在 95 值
double min_value = 0.0; // 最小值
double max_value = 0.0; // 最大值
double avg_value = 0.0; // 平均值
double p95_value = 0.0; // 95 值
StatMetricQuality quality = StatMetricQuality::Normal; // 指标质量状态
std::string quality_reason; // 质量状态说明
int source_observation_index = -1; // 选中的来源 observation 索引
int source_channel_instance_index = -1; // 选中的来源通道实例索引
int source_series_instance_index = -1; // 最近一次写入该桶的来源序列实例索引
std::string source_channel_name; // 选中的来源通道名称
};
// 同一时刻聚合桶
// 含义:在“已筛选出的统计类 observation”内某个 timestamp 下所有已识别指标的统计值集合。
struct TimeAggregatedStatBucket
{
time_t timestamp = 0; // 聚合时刻
std::string timestamp_text; // 格式化时间文本
std::map<StatMetricId, AggregatedStatValues> metrics; // 当前时刻下各指标的统计值
};
// PQDIF 统计桶 Base64 子记录对象
// 对象用途:保存“一个 PQDIF 文件 + 一个时间点 + 一种统计类型”的最终 Base64 组装结果。
// 数据粒度:例如同一个时间点会有 Max、Min、Avg、P95 四条子记录。
// 注意v20 起它不再直接作为全局队列元素,而是作为
// PqdifStatBase64TimePointPacket.records 的子对象存在。
struct PqdifStatBase64Record
{
std::string pqdif_file_path; // 对象来源PQDIF 文件全路径,便于后续处理时追溯文件
StatValueKind value_kind = StatValueKind::Unknown; // 对象统计类型Max / Min / Avg / P95
std::string value_kind_name; // 对象统计类型文本:便于日志/外部队列直接查看
int value_kind_code = 0; // 对象统计类型编码兼容旧统计队列1=Max, 2=Min, 3=Avg, 4=P95
time_t timestamp = 0; // 对象时间戳:该 Base64 数据所属的桶时间点
std::string timestamp_text; // 对象时间文本:格式化时间点,便于日志、人眼核查
std::string base64_payload; // 对象数据主体float 按星型/角型顺序组装后整体转换成的 Base64 字符串
size_t float_count = 0; // 对象校验字段:本条记录实际组装的 float 数量
size_t placeholder_count = 0; // 对象校验字段:本条记录中使用 3.14159f 占位的数量
ParsedConnectionKind connection_kind = ParsedConnectionKind::Unknown; // 对象接线方式:星型/角型/未知
};
// PQDIF Base64 时间点包对象
// 对象用途:把同一个 PQDIF 文件、同一个时间点下的 Max/Min/Avg/P95 四类 Base64 子记录合并保存。
// 设计原因:后续处理时可以按时间点一次性拿到四种统计类型,避免散落成单条记录。
struct PqdifStatBase64TimePointPacket
{
time_t timestamp = 0; // 对象时间戳:该时间点包对应的桶时间点
std::string timestamp_text; // 对象时间文本:格式化时间点,便于日志、人眼核查
std::vector<PqdifStatBase64Record> records; // 对象子记录:同一时间点下的 Max/Min/Avg/P95 Base64 记录
size_t record_count = 0; // 对象统计字段records.size() 的冗余统计,便于日志核查
size_t total_float_count = 0; // 对象统计字段:当前时间点下所有子记录的 float 数量合计
size_t total_placeholder_count = 0;// 对象统计字段:当前时间点下所有子记录的占位数量合计
size_t total_base64_chars = 0; // 对象统计字段:当前时间点下所有子记录 base64 字符数合计
};
// PQDIF Base64 文件级批次对象
// 对象用途:保存“一个 PQDIF 文件解析完成后”的全部 Base64 时间点包。
// 数据粒度:全局队列中的一个元素就是一个 PqdifStatBase64FileBatch文件之间不会混合。
struct PqdifStatBase64FileBatch
{
std::string pqdif_file_path; // 对象来源PQDIF 文件全路径
std::string source_file; // 对象来源:原始文件路径,通常与 pqdif_file_path 一致或接近
std::string mac; // 对象来源:设备目录名/设备标识
time_t parsed_at = 0; // 对象生成时间戳:解析完成时间
std::string parsed_at_text; // 对象生成时间文本:格式化解析完成时间
ParsedConnectionKind connection_kind = ParsedConnectionKind::Unknown; // 对象接线方式:星型/角型/未知
std::vector<PqdifStatBase64TimePointPacket> time_points; // 对象主体:文件内所有时间点包
size_t time_point_count = 0; // 对象统计字段time_points.size() 的冗余统计,便于日志核查
size_t total_record_count = 0; // 对象统计字段:文件内全部 Max/Min/Avg/P95 子记录数量
size_t total_float_count = 0; // 对象统计字段:文件内全部 float 数量
size_t total_placeholder_count = 0;// 对象统计字段:文件内全部占位数量
size_t total_base64_chars = 0; // 对象统计字段:文件内全部 base64 字符数
};
// 一个 PQDIF 文件的暂存对象
struct ParsedPqdifFile
{
std::string mac; // 设备目录名
std::string source_file; // 原始文件路径
time_t parsed_at = 0; // 解析完成时间
// 新结构:完整 PQDIF 拆分结果
PqdifLogicalFile logical_file;
// 统计识别与聚合层结果
ParsedConnectionKind connection_kind = ParsedConnectionKind::Unknown; ///< 当前文件识别出的接线方式
int selected_observation_index = -1; ///< 当前阶段被选中的“统计类 observation”索引
std::string selected_observation_name; ///< 当前阶段被选中的“统计类 observation”名称
std::vector<ExpandedStatPoint> expanded_stat_points; ///< 从 PQDIF 展开的全部统计样本点
std::vector<TimeAggregatedStatBucket> aggregated_stat_buckets; ///< 按 timestamp 聚合后的时间桶
};
// 启动 PQDIF 扫描线程
void RunPqdifScanLoop();
// 缓存访问接口
bool PopOldestParsedPqdifFile(ParsedPqdifFile& out);
bool PeekOldestParsedPqdifFile(ParsedPqdifFile& out);
size_t GetParsedPqdifCacheSize();
void ClearParsedPqdifCache();
// PQDIF 统计桶 Base64 “生成队列”访问接口
// 对象用途该队列由解析流程写入RunPqdifScanLoop() 每轮循环末尾会尝试把其中一个文件批次
// 移动到“待后续处理队列”。如果外部仍需直接读取生成队列,可以继续使用以下旧接口。
// v20 起:队列元素 = 一个 PQDIF 文件批次。
bool PopOldestPqdifStatBase64FileBatch(PqdifStatBase64FileBatch& out);
bool PeekOldestPqdifStatBase64FileBatch(PqdifStatBase64FileBatch& out);
// 兼容旧接口:如旧代码仍按单条 Base64 子记录读取,会从文件批次队列的最早文件/最早时间点中拆出一条。
bool PopOldestPqdifStatBase64Record(PqdifStatBase64Record& out);
bool PeekOldestPqdifStatBase64Record(PqdifStatBase64Record& out);
// 返回当前生成队列文件级批次数量;如需查看内部子记录数量,使用 GetPqdifStatBase64RecordCountInQueue()。
size_t GetPqdifStatBase64QueueSize();
size_t GetPqdifStatBase64RecordCountInQueue();
void ClearPqdifStatBase64Queue();
// PQDIF 统计桶 Base64 “待后续处理队列”访问接口
// 对象用途RunPqdifScanLoop() 已经从生成队列取出、准备交给后续入库/上传/推送流程的数据会放在这里。
// 推荐后续业务优先调用 PopReadyPqdifStatBase64FileBatch(),一次取出一个完整 PQDIF 文件批次。
bool PopReadyPqdifStatBase64FileBatch(PqdifStatBase64FileBatch& out);
bool PeekReadyPqdifStatBase64FileBatch(PqdifStatBase64FileBatch& out);
size_t GetReadyPqdifStatBase64QueueSize();
size_t GetReadyPqdifStatBase64RecordCountInQueue();
void ClearReadyPqdifStatBase64Queue();