| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package faultRecordFile
- import (
- "archive/zip"
- "bytes"
- "encoding/csv"
- "fmt"
- "io"
- "strconv"
- )
- var utf8Bom = []byte{0xEF, 0xBB, 0xBF} // 便于 Excel 识别中文
- // ChannelLabel 通道表头:序号 + 含义代码(可配通道附类型和地址)
- func ChannelLabel(ch WaveformChannel) string {
- if ch.Configurable != nil {
- return fmt.Sprintf("ch%d 可配%s", ch.Number, ConfigurableDesc(*ch.Configurable))
- }
- return fmt.Sprintf("ch%d 0x%04X", ch.Number, ch.Meaning)
- }
- // ConfigurableDesc 可配通道说明:默认方式为“类型@地址”,代码方式为“代码 0xXXXX”
- func ConfigurableDesc(c ConfigurableChannel) string {
- if c.Mode == 1 {
- return fmt.Sprintf("代码0x%04X", c.Address>>16)
- }
- return fmt.Sprintf("%s@0x%X", c.TypeName, c.Address)
- }
- // WriteWaveformCSV 每行一个采样点:点序号、相对故障时刻毫秒、各通道原始值
- func WriteWaveformCSV(w io.Writer, rec Record) error {
- if _, err := w.Write(utf8Bom); err != nil {
- return err
- }
- cw := csv.NewWriter(w)
- wf := rec.Waveform
- header := []string{"point", "time_ms"}
- for _, ch := range wf.Channels {
- header = append(header, ChannelLabel(ch))
- }
- if err := cw.Write(header); err != nil {
- return err
- }
- row := make([]string, len(header))
- for k := 0; k < wf.Points; k++ {
- row[0] = strconv.Itoa(k)
- row[1] = strconv.FormatFloat(wf.TimeOffsetMs(k), 'f', 3, 64)
- for c, ch := range wf.Channels {
- row[c+2] = strconv.Itoa(int(ch.Values[k]))
- }
- if err := cw.Write(row); err != nil {
- return err
- }
- }
- cw.Flush()
- return cw.Error()
- }
- // WriteSummaryCSV 基本信息、版本、触发源及各组通道
- func WriteSummaryCSV(w io.Writer, rec Record) error {
- if _, err := w.Write(utf8Bom); err != nil {
- return err
- }
- cw := csv.NewWriter(w)
- f := rec.Failure
- rows := [][]string{
- {"项目", "值"},
- {"批次", rec.Batch},
- {"设备 SN", rec.Sn},
- {"记录序号", strconv.Itoa(rec.RecordIndex)},
- {"发生时间(设备时间)", f.Time},
- {"触发源", fmt.Sprintf("0x%04X %s", f.TriggerSource, f.TriggerSourceName)},
- {"CAN 协议版本", strconv.Itoa(int(f.Basic.CanProtocolVersion))},
- {"存储格式版本", strconv.Itoa(int(f.Basic.StorageFormat))},
- {"参数列表版本", f.Basic.ParamListVersion},
- {"最大采样频率 Hz", strconv.Itoa(int(f.Basic.MaxSampleFrequency))},
- {"采样频率 Hz", strconv.Itoa(int(f.Basic.SampleFrequency))},
- {"采样点总数", strconv.Itoa(int(f.Basic.TotalPoints))},
- {"故障前采样点", strconv.Itoa(int(f.Basic.PrePoints))},
- {"故障后采样点", strconv.Itoa(int(f.Basic.PostPoints))},
- {"DCDC 版本", f.DcdcVersion},
- {"INV 版本", f.InvVersion},
- {"FPGA 版本", f.FpgaVersion},
- {},
- {"快照通道", "含义代码", "原始值"},
- }
- for i, s := range f.Snapshots {
- v := ""
- if s.Value != nil {
- v = strconv.Itoa(int(*s.Value))
- }
- rows = append(rows, []string{strconv.Itoa(i), fmt.Sprintf("0x%04X", s.Meaning), v})
- }
- rows = append(rows, []string{}, []string{"采样通道", "含义代码"})
- for i, m := range f.SampleMeanings {
- rows = append(rows, []string{strconv.Itoa(i), fmt.Sprintf("0x%04X", m)})
- }
- rows = append(rows, []string{}, []string{"可配快照通道", "配置"})
- for i, c := range f.ConfigSnapshots {
- rows = append(rows, []string{strconv.Itoa(i), ConfigurableDesc(c)})
- }
- rows = append(rows, []string{}, []string{"可配采样通道", "配置"})
- for i, c := range f.ConfigSamples {
- rows = append(rows, []string{strconv.Itoa(i), ConfigurableDesc(c)})
- }
- if err := cw.WriteAll(rows); err != nil {
- return err
- }
- return cw.Error()
- }
- // BuildCSVZip 每条记录生成 waveform 和 summary 两个 CSV,打包为 zip
- func BuildCSVZip(records []Record) ([]byte, error) {
- var buf bytes.Buffer
- zw := zip.NewWriter(&buf)
- for _, rec := range records {
- prefix := fmt.Sprintf("%s_%s_index%d", rec.Batch, rec.Sn, rec.RecordIndex)
- for _, item := range []struct {
- name string
- write func(io.Writer, Record) error
- }{
- {prefix + "_waveform.csv", WriteWaveformCSV},
- {prefix + "_summary.csv", WriteSummaryCSV},
- } {
- fw, err := zw.Create(item.name)
- if err != nil {
- return nil, err
- }
- if err := item.write(fw, rec); err != nil {
- return nil, err
- }
- }
- }
- if err := zw.Close(); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
|