xlxs
This commit is contained in:
379
extract/aux.go
379
extract/aux.go
@@ -1,380 +1,45 @@
|
||||
package extract
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tealeg/xlsx"
|
||||
)
|
||||
|
||||
// 每行传感器数据帧头信息长度为24字节
|
||||
type AuxFrameHead struct {
|
||||
PkgHead [4]byte // 包头头标识符,固定为0xD15BD15B
|
||||
FillByte0 byte // 填充字节 0x00
|
||||
FrmHead [6]byte // 帧头标识符,固定为0xEB90EB90EB90
|
||||
// 图像模式
|
||||
// B7 模式标识 000:为线阵模式
|
||||
// B6
|
||||
// B5
|
||||
// B4 B4谱状态 0:不输出1:输出
|
||||
// B3 B3谱状态 0:不输出1:输出
|
||||
// B2 B2谱状态 0:不输出1:输出
|
||||
// B1 B1谱状态 0:不输出1:输出
|
||||
// B0 全色状态 0:不输出1:输出
|
||||
ImgMode byte
|
||||
SerialNo uint32 // 当前流水号
|
||||
TimeSec uint32 // 时间(秒)
|
||||
TimeSecFrac uint32 // 秒小数 量纲:1us/bit,十六进制无符号整型数
|
||||
FileNo uint8 // 文件号
|
||||
|
||||
IsValidFrmHead bool
|
||||
B0 bool
|
||||
B1 bool
|
||||
B2 bool
|
||||
B3 bool
|
||||
B4 bool
|
||||
IsLinerMatrix bool
|
||||
RowLength int
|
||||
}
|
||||
|
||||
func (afh *AuxFrameHead) Decode(data []byte) error {
|
||||
if len(data) < 24 {
|
||||
return errors.New("length of AuxFrameHead is not 24")
|
||||
}
|
||||
|
||||
afh.PkgHead = [4]byte{data[0], data[1], data[2], data[3]}
|
||||
afh.FillByte0 = data[4]
|
||||
afh.FrmHead = [6]byte{data[5], data[6], data[7], data[8], data[9], data[10]}
|
||||
afh.ImgMode = data[11]
|
||||
afh.B0 = (afh.ImgMode&(1<<0) != 0x0)
|
||||
afh.B1 = (afh.ImgMode&(1<<1) != 0x0)
|
||||
afh.B2 = (afh.ImgMode&(1<<2) != 0x0)
|
||||
afh.B3 = (afh.ImgMode&(1<<3) != 0x0)
|
||||
afh.B4 = (afh.ImgMode&(1<<4) != 0x0)
|
||||
afh.IsLinerMatrix = (afh.ImgMode&(1<<5) == 0x0 && afh.ImgMode&(1<<6) == 0x0 && afh.ImgMode&(1<<7) == 0x0)
|
||||
afh.SerialNo = binary.BigEndian.Uint32(data[12:16])
|
||||
afh.TimeSec = binary.BigEndian.Uint32(data[16:20])
|
||||
afh.TimeSecFrac = uint32(uint32(data[20])<<16 | uint32(data[21])<<8 | uint32(data[22]))
|
||||
afh.FileNo = data[23]
|
||||
|
||||
afh.RowLength = afh.LengthOfRow()
|
||||
afh.IsValidFrmHead = afh.CheckFrmHead()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 计算一行数据长度:帧头+辅助数据+图像数据
|
||||
func (afh AuxFrameHead) LengthOfRow() int {
|
||||
if !afh.IsLinerMatrix {
|
||||
return 14344
|
||||
}
|
||||
|
||||
length := 64 // 帧头+辅助数据长度
|
||||
if afh.B0 {
|
||||
length += 19040
|
||||
}
|
||||
if afh.B1 {
|
||||
length += 1192
|
||||
}
|
||||
if afh.B2 {
|
||||
length += 1192
|
||||
}
|
||||
if afh.B3 {
|
||||
length += 1192
|
||||
}
|
||||
if afh.B4 {
|
||||
length += 1192
|
||||
}
|
||||
|
||||
return length
|
||||
}
|
||||
|
||||
func (afh AuxFrameHead) CheckFrmHead() bool {
|
||||
if afh.FrmHead[0] == 0xEB && afh.FrmHead[1] == 0x90 &&
|
||||
afh.FrmHead[2] == 0xEB && afh.FrmHead[3] == 0x90 &&
|
||||
afh.FrmHead[4] == 0xEB && afh.FrmHead[5] == 0x90 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 从传输帧文件中分离辅助数据,分别存储到辅助数据文件 _AUX.dat 和图像数据文件 _IMG_{波谱}.dat 中
|
||||
func (e *Extractor) SeprateAuxAndImgData(dataFile string, segmentIndex int) error {
|
||||
// 打开传输帧文件 - 一次读入内存
|
||||
data, err := os.ReadFile(dataFile)
|
||||
if err != nil {
|
||||
log.Println("read data from", dataFile, "error:", err.Error())
|
||||
func (e Extractor) ExtractAux(auxfile, xlsxfile string) error {
|
||||
if err := createAuxXlxs(xlsxfile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("seprate aux and img data from", dataFile)
|
||||
|
||||
dataLen := len(data)
|
||||
log.Info("length of original data: ", dataLen)
|
||||
var firstFrmHead *AuxFrameHead
|
||||
data, firstFrmHead = e.trimImgRawData(data)
|
||||
dataLen = len(data)
|
||||
log.Info("after trim,length of data: ", dataLen)
|
||||
e.quanlityAnalysis(data)
|
||||
|
||||
outputDir := e.params.OutputPath
|
||||
name := strings.Join([]string{
|
||||
e.params.Satellite,
|
||||
"PMS",
|
||||
time.Unix(int64(firstFrmHead.TimeSec)+int64(ReferenceTime2000),
|
||||
int64(firstFrmHead.TimeSecFrac)*1000).
|
||||
Format("20060102_150405"),
|
||||
e.params.DataId,
|
||||
fmt.Sprintf("%03d", firstFrmHead.FileNo),
|
||||
}, "_")
|
||||
|
||||
lw := newL0Writer(outputDir, name)
|
||||
defer lw.Close()
|
||||
|
||||
var panEnviHdr, mssEnviHdr EnviHdr
|
||||
|
||||
var afh AuxFrameHead
|
||||
|
||||
msdata := make([][]byte, 4)
|
||||
var header []byte
|
||||
var ebAux []byte
|
||||
var platAux []byte
|
||||
|
||||
for i := 0; i < dataLen; {
|
||||
if i+4 > dataLen {
|
||||
logrus.Println("end of data, dataLen:", dataLen, "i:", i)
|
||||
break
|
||||
}
|
||||
|
||||
// 包头
|
||||
if data[i] == 0xD1 && data[i+1] == 0x5B && data[i+2] == 0xD1 && data[i+3] == 0x5B {
|
||||
log.Debug("find package head: 0xD15BD15B")
|
||||
} else {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析帧
|
||||
if i+24 > dataLen {
|
||||
log.Info("length of frame head is not engough for frame head")
|
||||
break
|
||||
}
|
||||
afh.Decode(data[i : i+24])
|
||||
|
||||
if !afh.IsValidFrmHead {
|
||||
log.Info("invalid frame head of original raw data")
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
|
||||
// 目前只支持线阵模式
|
||||
if !afh.IsLinerMatrix {
|
||||
log.Error("not liner matrix mode, only support liner matrix mode")
|
||||
break
|
||||
}
|
||||
|
||||
// 读取一行数据 data[i : i+afh.RowLength]
|
||||
if i+afh.RowLength > dataLen {
|
||||
log.Infof("length of image row data %v is not enough: %v", dataLen-i, afh.RowLength)
|
||||
break
|
||||
}
|
||||
|
||||
auxTime := binary.BigEndian.Uint32(data[i+32 : i+36])
|
||||
if math.Abs(float64(auxTime)-float64(afh.TimeSec)) < 30 {
|
||||
header = append(header, data[i:i+24]...)
|
||||
}
|
||||
// 存储辅助数据到临时文件
|
||||
dataIndex := i + 24
|
||||
// lw.ws[EB_AUX].w.Write(data[dataIndex : dataIndex+8]) // 8字节焦面电箱辅助数据
|
||||
ebAux = append(ebAux, data[dataIndex:dataIndex+8]...)
|
||||
dataIndex += 8
|
||||
// lw.ws[PLAT_AUX].w.Write(data[dataIndex : dataIndex+32]) // 32字节中心机辅助数据
|
||||
platAux = append(platAux, data[dataIndex:dataIndex+32]...)
|
||||
dataIndex += 32
|
||||
|
||||
// 存储图像数据到临时文件 - 以 ENVI BSQ 格式存储,同时提供 HDR 描述文件
|
||||
if afh.B0 {
|
||||
// wpan.Write(data[dataIndex : dataIndex+19040])
|
||||
write16bPixelLittleEndian(lw.ws[PAN_RAW].w, data[dataIndex:dataIndex+19040])
|
||||
dataIndex += 19040
|
||||
panEnviHdr.Lines += 1
|
||||
}
|
||||
|
||||
if afh.B1 {
|
||||
// write16bPixelLittleEndian(wmss, data[dataIndex:dataIndex+1192])
|
||||
msdata[0] = append(msdata[0], data[dataIndex:dataIndex+1192]...)
|
||||
dataIndex += 1192
|
||||
mssEnviHdr.Lines += 1
|
||||
}
|
||||
if afh.B2 {
|
||||
// write16bPixelLittleEndian(wmss, data[dataIndex:dataIndex+1192])
|
||||
msdata[1] = append(msdata[1], data[dataIndex:dataIndex+1192]...)
|
||||
dataIndex += 1192
|
||||
}
|
||||
if afh.B3 {
|
||||
// write16bPixelLittleEndian(wmss, data[dataIndex:dataIndex+1192])
|
||||
msdata[2] = append(msdata[2], data[dataIndex:dataIndex+1192]...)
|
||||
dataIndex += 1192
|
||||
}
|
||||
if afh.B4 {
|
||||
// write16bPixelLittleEndian(wmss, data[dataIndex:dataIndex+1192])
|
||||
msdata[3] = append(msdata[3], data[dataIndex:dataIndex+1192]...)
|
||||
dataIndex += 1192
|
||||
}
|
||||
i = dataIndex // 完成一行数据解析
|
||||
wb, err := xlsx.OpenFile(xlsxfile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// var bands = 0
|
||||
// for i := 0; i < 4; i++ {
|
||||
// if len(msdata[i]) > 0 {
|
||||
// log.Println("write mss data of band B", i+1)
|
||||
// _, err := write16bPixelLittleEndian(lw.ws[MSS_RAW].w, msdata[i])
|
||||
// if err != nil {
|
||||
// log.Error("write mss data error:", err.Error())
|
||||
// }
|
||||
// bands += 1
|
||||
// }
|
||||
// }
|
||||
sh := wb.Sheets[0]
|
||||
|
||||
if len(msdata[0]) != len(msdata[1]) || len(msdata[2]) != len(msdata[3]) {
|
||||
log.Error("mss data of bands B1-B4 are not equal")
|
||||
return errors.New("mss data of bands B1-B4 are not equal")
|
||||
data, err := os.ReadFile(auxfile)
|
||||
if err != nil {
|
||||
log.Println("read aux data from", auxfile, "error:", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
mssRowLen := 1192 * 4
|
||||
for i := 0; i < len(msdata[0]); i += mssRowLen {
|
||||
var err error
|
||||
_, err = write16bPixelLittleEndian(lw.ws[MSS_RAW].w, msdata[0][i:i+mssRowLen])
|
||||
if err != nil {
|
||||
log.Error("write mss 1 data error:", err.Error())
|
||||
}
|
||||
_, err = write16bPixelLittleEndian(lw.ws[MSS_RAW].w, msdata[1][i:i+mssRowLen])
|
||||
if err != nil {
|
||||
log.Error("write mss 2 data error:", err.Error())
|
||||
}
|
||||
_, err = write16bPixelLittleEndian(lw.ws[MSS_RAW].w, msdata[2][i:i+mssRowLen])
|
||||
if err != nil {
|
||||
log.Error("write mss 3 data error:", err.Error())
|
||||
}
|
||||
_, err = write16bPixelLittleEndian(lw.ws[MSS_RAW].w, msdata[3][i:i+mssRowLen])
|
||||
if err != nil {
|
||||
log.Error("write mss 4 data error:", err.Error())
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(data); i += 24 + 128 + 512 {
|
||||
row := sh.AddRow()
|
||||
|
||||
panEnviHdr.Samples = 9520
|
||||
panEnviHdr.Bands = 1
|
||||
lw.ws[PAN_HDR].w.Write([]byte(panEnviHdr.String()))
|
||||
var head AuxFrameHead
|
||||
head.Decode(data[i : i+24])
|
||||
head.SaveXlsx(row)
|
||||
|
||||
mssEnviHdr.Lines = mssEnviHdr.Lines / 4 // 多光谱波段分别在 4 行中传输
|
||||
mssEnviHdr.Samples = 2384 * 4
|
||||
mssEnviHdr.Bands = 1
|
||||
lw.ws[MSS_HDR].w.Write([]byte(mssEnviHdr.String()))
|
||||
var box AuxFocalBox
|
||||
box.Decode(data[i+24 : i+24+128])
|
||||
box.SaveXlsx(row)
|
||||
|
||||
// 帧头+辅助数据
|
||||
if len(header)/24 < len(ebAux)/128 || len(ebAux)/128 != len(platAux)/512 {
|
||||
fmt.Println("aux data length:", len(header)/24, len(ebAux)/128, len(platAux)/512)
|
||||
return errors.New("aux data length is not equal")
|
||||
}
|
||||
|
||||
auxRows := len(header) / 24
|
||||
for i := 0; i < auxRows; i++ {
|
||||
lw.ws[AUX].w.Write(header[i*24 : (i+1)*24])
|
||||
lw.ws[AUX].w.Write(ebAux[i*128 : (i+1)*128])
|
||||
lw.ws[AUX].w.Write(platAux[i*512 : (i+1)*512])
|
||||
var plat AuxPlatform
|
||||
plat.Decode(data[i+24+128 : i+24+128+512])
|
||||
box.SaveXlsx(row)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Extractor) quanlityAnalysis(data []byte) {
|
||||
// 数据质量分析
|
||||
fimg, _ := os.Create("demo/temp/" + e.params.DataId + "/aux.txt")
|
||||
defer fimg.Close()
|
||||
fimg.WriteString("字节数 帧头流水号 文件号 帧头时间 中心辅助数据前4字节(行33-36)\n")
|
||||
|
||||
var startAuxLine bool
|
||||
var preSN uint32
|
||||
for i := 0; i < len(data); {
|
||||
afh := &AuxFrameHead{}
|
||||
afh.Decode(data[i : i+24])
|
||||
|
||||
if !afh.IsValidFrmHead {
|
||||
log.Errorf("invalid frame head of original raw data i: %v, len: %v", i, len(data))
|
||||
return
|
||||
}
|
||||
|
||||
t := time.Unix(int64(afh.TimeSec+uint32(ReferenceTime2000)), int64(afh.TimeSecFrac)*1000)
|
||||
|
||||
utcTime := binary.BigEndian.Uint32(data[i+32 : i+36])
|
||||
tAux := time.Unix(int64(utcTime+uint32(ReferenceTime2000)), 0)
|
||||
|
||||
startAuxLine = math.Abs(float64(utcTime)-float64(afh.TimeSec)) < 30
|
||||
if startAuxLine {
|
||||
fimg.WriteString(fmt.Sprintf("%d %d %d %s %s\n",
|
||||
i,
|
||||
afh.SerialNo,
|
||||
afh.FileNo,
|
||||
t.String(),
|
||||
tAux.String(),
|
||||
))
|
||||
|
||||
if afh.SerialNo-preSN != 16 && preSN != 0 {
|
||||
log.Println("serial number not continuous", afh.SerialNo, preSN)
|
||||
}
|
||||
preSN = afh.SerialNo
|
||||
}
|
||||
|
||||
i += afh.RowLength
|
||||
}
|
||||
}
|
||||
|
||||
// 裁剪图像数据,只保留有效数据
|
||||
func (e *Extractor) trimImgRawData(data []byte) ([]byte, *AuxFrameHead) {
|
||||
var start, end int
|
||||
afh := &AuxFrameHead{}
|
||||
// 将中心辅助数据时间合理的帧作为第一帧
|
||||
var startAuxLine bool
|
||||
for i := 0; i < len(data); {
|
||||
// 解析帧
|
||||
if i+24 > len(data) {
|
||||
log.Info("length of original image frame head is not engough: ", len(data)-i)
|
||||
break
|
||||
}
|
||||
|
||||
if data[i] == 0xD1 && data[i+1] == 0x5B && data[i+2] == 0xD1 && data[i+3] == 0x5B {
|
||||
log.Debug("find package head: 0xD15BD15B")
|
||||
} else {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
afh.Decode(data[i : i+24])
|
||||
|
||||
if !afh.IsValidFrmHead {
|
||||
log.Debugf("invalid frame head of original raw data %v", i)
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
|
||||
utcTime := binary.BigEndian.Uint32(data[i+32 : i+36]) // 相对于2000年的秒数
|
||||
startAuxLine = math.Abs(float64(utcTime)-float64(afh.TimeSec)) < 30 // 时间差小于30秒认为是有效数据
|
||||
if !startAuxLine {
|
||||
i += afh.RowLength
|
||||
} else {
|
||||
start = i
|
||||
nLen := (len(data) - i - 1)
|
||||
nLen = nLen - nLen%(afh.RowLength*16)
|
||||
end = i + nLen
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return data[start:end], afh
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user