113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
|
|
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表示binary,4表示binary32
|
|||
|
|
|
|||
|
|
// 05,667,-760,1274,72,61,-140,-502,0,0,0,0,1,1
|
|||
|
|
// 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 0,0,0,0,1,1
|
|||
|
|
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, ×tamp); 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表示binary,4表示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
|
|||
|
|
}
|