go-comtrade/binary_data.go

113 lines
3.4 KiB
Go
Raw Permalink Normal View History

package comtrade
import (
"encoding/binary"
"math"
"os"
)
// BinaryData is the binary data of a comtrade data file
func init() {
Add(TypeBinary, func() Parser {
return &BinaryData{}
})
}
// 读取数据文件
// 1、采样序号和时标均以四字节无符号二进制格式存储
// 2、模拟通道采样数据binary两个字节binary32四个字节二进制补码形式存储
// 3、每16个状态通道以两个字节一组存储字的最低为对应该组16个状态通道中最小编号通道
// 4、每次采样字节数=(模拟通道数 * 每个采样数据占据字节数)+(状态通道数 / 16 * 2 + 4 + 4
// 5、每个采样数据占据字节数=2或4取决于数据格式2表示binary4表示binary32
// 05667-76012747261-140-502000011
// 05 00 00 00
// 9B 02 00 00 667
// 08 FD -760
// FA 04 1274
// 48 00 72
// 3D 00 61
// 74 FF -140
// 0A FE -502
// 30 00 000011
type BinaryData struct{}
func (b *BinaryData) Parse(filePath string, analogNum, digitalNum, endSamp uint32) (*Data, error) {
comtradeData := &Data{}
// 打开文件
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
comtradeData.AnalogData = make([]AnalogData, int(endSamp))
comtradeData.DigitalData = make([]DigitalData, int(endSamp))
for i := 0; i < int(endSamp); i++ {
comtradeData.AnalogData[i].Data = make([]int32, analogNum)
comtradeData.DigitalData[i].Data = make([]uint8, digitalNum)
}
// 计算状态通道组数
digitalCount := int(math.Ceil(float64(digitalNum) / 16.0))
remainder := int(digitalNum % 16)
for i := 0; i < int(endSamp); i++ {
var (
sampleIndex uint32
timestamp uint32
)
// 解析采样序号
if err := binary.Read(file, binary.LittleEndian, &sampleIndex); err != nil {
return nil, err
}
comtradeData.AnalogData[i].N = sampleIndex
comtradeData.DigitalData[i].N = sampleIndex
// 解析采样时标
if err = binary.Read(file, binary.LittleEndian, &timestamp); err != nil {
return nil, err
}
comtradeData.AnalogData[i].Timestamp = timestamp
comtradeData.DigitalData[i].Timestamp = timestamp
// 解析模拟通道采样数据
for m := 0; m < int(analogNum); m++ {
var tmp int16
if err := binary.Read(file, binary.LittleEndian, &tmp); err != nil {
return nil, err
} else {
comtradeData.AnalogData[i].Data[m] = int32(tmp)
}
}
// 3、每16个状态通道以两个字节一组存储字的最低为对应该组16个状态通道中最小编号通道
// 4、每次采样字节数=(模拟通道数 * 每个采样数据占据字节数)+(状态通道数 / 16 * 2 + 4 + 4
// 5、每个采样数据占据字节数=2或4取决于数据格式2表示binary4表示binary32
stateData := make([]uint16, digitalCount)
for n, datum := range stateData {
data := datum
if err := binary.Read(file, binary.LittleEndian, &data); err != nil {
return nil, err
}
stateData[n] = data
}
for h, datum := range stateData {
if remainder != 0 && h == digitalCount-1 {
for j := 0; j < remainder; j++ {
comtradeData.DigitalData[i].Data[(h*16)+j] = uint8(uint((datum >> uint(j)) & 0x0001))
}
break
}
for k := 0; k < 16; k++ {
comtradeData.DigitalData[i].Data[(h*16)+k] = uint8(uint((datum >> uint(k)) & 0x0001))
}
}
}
return comtradeData, nil
}