package comtrade import ( "bytes" "fmt" "io" "os" "strconv" "strings" "time" ) func ParseComtradeCfg(filePath string) (*ComtradeCfg, error) { cfgFile, err := os.Open(filePath) if err != nil { return nil, err } defer cfgFile.Close() comtradeCfg := &ComtradeCfg{} var tempList [][]byte content, err := io.ReadAll(cfgFile) if err != nil { return nil, err } lines := bytes.Split(content, []byte("\n")) // read first line tempList = bytes.Split(lines[0], []byte(",")) if len(tempList) < 3 { return nil, ErrReadFirstLine } // station_name, rec_dev_id, rev_year comtradeCfg.StationName = ByteToString(tempList[0]) comtradeCfg.RecDevID = ByteToString(tempList[1]) if value, err := strconv.ParseUint(ByteToString(tempList[2]), 10, 16); err != nil { return nil, err } else { comtradeCfg.RevYear = uint16(value) } // read second line tempList = bytes.Split(lines[1], []byte(",")) if len(tempList) < 3 { return nil, ErrReadSecondLine } // total channel number if value, err := strconv.ParseUint(ByteToString(tempList[0]), 10, 16); err != nil { return nil, err } else { comtradeCfg.Total = uint32(value) } if !bytes.Contains(tempList[1], []byte("A")) || !bytes.Contains(tempList[2], []byte("D")) { return nil, ErrReadADChannel } // analog channel total number if value, err := strconv.ParseUint(string(bytes.TrimSuffix(bytes.TrimSpace(tempList[1]), []byte("A"))), 10, 64); err != nil { return nil, err } else { comtradeCfg.AnalogNum = uint32(value) } // digit channel total number if value, err := strconv.ParseUint(string(bytes.TrimSuffix(bytes.TrimSpace(tempList[2]), []byte("D"))), 10, 64); err != nil { return nil, err } else { comtradeCfg.DigitalNum = uint32(value) } // initialize analog and digital channels comtradeCfg.Analog = make([]AnalogChan, comtradeCfg.AnalogNum) comtradeCfg.Digital = make([]DigitalChan, comtradeCfg.DigitalNum) // 读取模拟通道 read analog channels for i := 0; i < int(comtradeCfg.AnalogNum); i++ { tempList = bytes.Split(lines[2+i], []byte(",")) if len(tempList) < 10 { return nil, ErrReadAnalogChannel } // 通道索引号 An if num, err := strconv.ParseInt(ByteToString(tempList[0]), 10, 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].An = uint32(num) } // 通道标识 ch_id,通道相标识 ph comtradeCfg.Analog[i].ChId = ByteToString(tempList[1]) comtradeCfg.Analog[i].Ph = ByteToString(tempList[2]) // 被监视的电路元件 ccbm, 通道单位 uu comtradeCfg.Analog[i].Ccbm = ByteToString(tempList[3]) comtradeCfg.Analog[i].Uu = ByteToString(tempList[4]) // 通道增益系数 a if num, err := strconv.ParseFloat(ByteToString(tempList[5]), 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].A = float32(num) } // 通道偏移量 b if num, err := strconv.ParseFloat(ByteToString(tempList[6]), 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].B = float32(num) } // 从采样时刻开始的通道时滞 skew if num, err := strconv.ParseFloat(ByteToString(tempList[7]), 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].Skew = float32(num) } // Min Value at current channel if num, err := strconv.ParseFloat(ByteToString(tempList[8]), 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].Min = float32(num) } // Max Value at current channel if num, err := strconv.ParseFloat(ByteToString(tempList[9]), 64); err != nil { return nil, err } else { comtradeCfg.Analog[i].Max = float32(num) } if len(tempList) > 10 { if num, err := strconv.ParseFloat(ByteToString(tempList[10]), 64); err == nil { comtradeCfg.Analog[i].Primary = float32(num) } } if len(tempList) > 11 { if num, err := strconv.ParseFloat(ByteToString(tempList[11]), 64); err == nil { comtradeCfg.Analog[i].Secondary = float32(num) } } } // read digit channels for i := 0; i < int(comtradeCfg.DigitalNum); i++ { tempList = bytes.Split(lines[2+int(comtradeCfg.AnalogNum)+i], []byte(",")) if len(tempList) < 3 { return nil, ErrReadDigitalChannel } if num, err := strconv.Atoi(ByteToString(tempList[0])); err != nil { return nil, err } else { comtradeCfg.Digital[i].Dn = uint32(num) } comtradeCfg.Digital[i].ChId = ByteToString(tempList[1]) comtradeCfg.Digital[i].Ph = ByteToString(tempList[2]) // checking vector length to avoid IndexError if len(tempList) > 3 { // channel element (usually null) comtradeCfg.Digital[i].Ccbm = ByteToString(tempList[3]) } if len(tempList) > 4 { if num, err := strconv.ParseUint(ByteToString(tempList[4]), 10, 64); err != nil { return nil, err } else { comtradeCfg.Digital[i].Y = uint8(num) } } } // read frequency var line uint32 = 2 tempList = bytes.Split(lines[line+comtradeCfg.Total], []byte(",")) if num, err := strconv.ParseFloat(ByteToString(tempList[0]), 64); err != nil { return nil, err } else { comtradeCfg.Lf = float32(num) line++ } // read sampling rate num tempList = bytes.Split(lines[line+comtradeCfg.Total], []byte(",")) if num, err := strconv.ParseUint(ByteToString(tempList[0]), 10, 64); err != nil { return nil, err } else { comtradeCfg.Nrates = uint16(num) line++ } // read Sample and endSample for i := 0; i < int(comtradeCfg.Nrates); i++ { tempList = bytes.Split(lines[line+uint32(i)+comtradeCfg.Total], []byte(",")) if len(tempList) < 2 { return nil, ErrReadSample } if num, err := strconv.ParseFloat(ByteToString(tempList[0]), 64); err != nil { return nil, err } else { comtradeCfg.Samp = append(comtradeCfg.Samp, float32(num)) } if num, err := strconv.ParseFloat(ByteToString(tempList[1]), 64); err != nil { return nil, err } else { comtradeCfg.EndSamp = append(comtradeCfg.EndSamp, uint32(num)) } } line += uint32(comtradeCfg.Nrates) // read first data time (dd/mm/yyyy,hh:mm:ss.ssssss) if start, err := time.Parse(DateTimeLayout, ByteToString(lines[line+comtradeCfg.Total])); err != nil { if strings.Contains(err.Error(), MonthOutOfRange) { // try to parse date reverse month and day: mm/dd/yyyy if start, err = time.Parse(DateTimeLayout2, ByteToString(lines[line+comtradeCfg.Total])); err != nil { return nil, err } else { comtradeCfg.FirstDataTime = start line++ } } if err != nil { return nil, err } } else { comtradeCfg.FirstDataTime = start line++ } // read trigger time (dd/mm/yyyy,hh:mm:ss.ssssss) tempList = bytes.Split(lines[line+comtradeCfg.Total], []byte(",")) if trigger, err := time.Parse(DateTimeLayout, ByteToString(bytes.Join(tempList, []byte(",")))); err != nil { if strings.Contains(err.Error(), MonthOutOfRange) { // try to parse date reverse month and day if trigger, err = time.Parse(DateTimeLayout2, ByteToString(bytes.Join(tempList, []byte(",")))); err != nil { return nil, err } else { comtradeCfg.TriggerTime = trigger line++ } } if err != nil { return nil, err } } else { comtradeCfg.TriggerTime = trigger line++ } // read data file type tempList = bytes.Split(lines[line+comtradeCfg.Total], []byte(",")) // convert ft value to upper style comtradeCfg.Ft = strings.ToUpper(ByteToString(tempList[0])) fmt.Printf("ft vavlue:%v\n", comtradeCfg.Ft) // read time multiplication factor line++ tempList = bytes.Split(lines[line+comtradeCfg.Total], []byte(",")) if !bytes.Equal(tempList[0], []byte("")) { num, err := strconv.ParseFloat(ByteToString(tempList[0]), 64) if err != nil { return nil, err } comtradeCfg.TimeMult = float32(num) } else { comtradeCfg.TimeMult = 1 line++ } return comtradeCfg, nil } func ByteToString(b []byte) string { return strings.TrimSpace(string(b)) }