go-comtrade/ascii_config.go

265 lines
7.6 KiB
Go
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.

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))
}