| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- package faultRecordFile
- import (
- "encoding/binary"
- "fmt"
- proto "fwh-toolbox-server/function/FaultRecordProtocol"
- )
- const versionFieldSize = 64
- // FailureData failuredata(code=4 单一故障信息)
- type FailureData struct {
- DeclaredLength uint16 `json:"declaredLength"` // 样本中等于整个文件字节数(含填充),不作为有效长度使用
- Basic BasicInfo `json:"basic"`
- Index uint8 `json:"index"`
- Time string `json:"time"` // 设备时间
- TriggerSource uint16 `json:"triggerSource"`
- TriggerSourceName string `json:"triggerSourceName,omitempty"`
- DcdcVersion string `json:"dcdcVersion"`
- InvVersion string `json:"invVersion,omitempty"` // aGate 中为填充,不解析
- FpgaVersion string `json:"fpgaVersion,omitempty"` // aGate 中为填充,不解析
- ChannelGroups
- ParsedBytes int `json:"parsedBytes"` // 结构结束位置,之后为填充
- }
- // ParseFailureData 按结构逐项解析,结构结束后的内容(0xFF 填充)忽略
- func ParseFailureData(b []byte, deviceType string) (FailureData, error) {
- r := &byteReader{b: b}
- f := FailureData{
- DeclaredLength: r.u16("length"),
- Basic: readBasicInfo(r),
- Index: r.u8("index"),
- Time: r.time("time").String(),
- TriggerSource: r.u16("triggerSource"),
- }
- f.TriggerSourceName = proto.TriggerSourceName(f.TriggerSource)
- f.DcdcVersion = cString(r.take(versionFieldSize, "dcdcVersion"))
- inv := r.take(versionFieldSize, "invVersion")
- fpga := r.take(versionFieldSize, "fpgaVersion")
- if deviceType != proto.DeviceTypeAGate {
- f.InvVersion = cString(inv)
- f.FpgaVersion = cString(fpga)
- }
- f.ChannelGroups = readChannelGroups(r, true)
- f.ParsedBytes = r.p
- return f, r.err
- }
- // WaveformChannel 一个采样通道的全部点(原始 int16 值)
- type WaveformChannel struct {
- Number int `json:"number"` // 通道序号,从 0 开始
- Meaning uint16 `json:"meaning"` // 采样通道含义(可配通道处为类型码)
- // Configurable 采样通道列表末尾的通道对应可配采样通道(按样本推断)
- Configurable *ConfigurableChannel `json:"configurable,omitempty"`
- Values []int16 `json:"values"`
- }
- // Waveform waveformdata(code=5 单一故障波形数据)
- type Waveform struct {
- Points int `json:"points"`
- PrePoints int `json:"prePoints"`
- SampleFrequency int `json:"sampleFrequency"`
- Channels []WaveformChannel `json:"channels"`
- }
- // ParseWaveform 采样点优先排列:先排第 1 点的 n 个通道,再排第 2 点,依此类推。
- // 通道数取 failuredata 的“采样通道总数”,点数取基本信息的“采样点总数”;每点每通道 2 字节、大端、按 int16 解释。
- func ParseWaveform(b []byte, fd FailureData) (Waveform, error) {
- n := int(fd.SampleTotal)
- m := int(fd.Basic.TotalPoints)
- if n == 0 || m == 0 {
- return Waveform{}, fmt.Errorf("invalid waveform shape: %d channels × %d points", n, m)
- }
- if len(b) != n*m*2 {
- return Waveform{}, fmt.Errorf("waveform length %d does not match %d channels × %d points × 2", len(b), n, m)
- }
- w := Waveform{
- Points: m,
- PrePoints: int(fd.Basic.PrePoints),
- SampleFrequency: int(fd.Basic.SampleFrequency),
- Channels: make([]WaveformChannel, n),
- }
- cfgStart := n - int(fd.ConfigSampleTotal)
- for c := 0; c < n; c++ {
- ch := WaveformChannel{Number: c, Values: make([]int16, m)}
- if c < len(fd.SampleMeanings) {
- ch.Meaning = fd.SampleMeanings[c]
- }
- if cfgStart >= 0 && c >= cfgStart && c-cfgStart < len(fd.ConfigSamples) {
- cfg := fd.ConfigSamples[c-cfgStart]
- ch.Configurable = &cfg
- }
- w.Channels[c] = ch
- }
- for k := 0; k < m; k++ {
- for c := 0; c < n; c++ {
- off := (k*n + c) * 2
- w.Channels[c].Values[k] = int16(binary.BigEndian.Uint16(b[off:]))
- }
- }
- return w, nil
- }
- // TimeOffsetMs 第 k 个采样点相对故障时刻的毫秒数
- func (w Waveform) TimeOffsetMs(k int) float64 {
- if w.SampleFrequency == 0 {
- return 0
- }
- return float64(k-w.PrePoints) * 1000 / float64(w.SampleFrequency)
- }
- // Record 一条已解析的录波记录
- type Record struct {
- Batch string `json:"batch"`
- Sn string `json:"sn"`
- RecordIndex int `json:"recordIndex"`
- Failure FailureData `json:"failure"`
- Waveform Waveform `json:"waveform"`
- }
- // ParseRecordFiles 解析一条记录的两个文件(内容为十六进制文本)
- func ParseRecordFiles(f RecordFiles, deviceType string) (Record, error) {
- rec := Record{Batch: f.Batch, Sn: f.Sn, RecordIndex: f.Index}
- fdBytes, err := proto.DecodeHex(string(f.FailureData))
- if err != nil {
- return rec, fmt.Errorf("failuredata: %w", err)
- }
- if rec.Failure, err = ParseFailureData(fdBytes, deviceType); err != nil {
- return rec, fmt.Errorf("failuredata: %w", err)
- }
- wfBytes, err := proto.DecodeHex(string(f.WaveformData))
- if err != nil {
- return rec, fmt.Errorf("waveformdata: %w", err)
- }
- if rec.Waveform, err = ParseWaveform(wfBytes, rec.Failure); err != nil {
- return rec, fmt.Errorf("waveformdata: %w", err)
- }
- return rec, nil
- }
|