Files
sjy01-preprocessing/extract/aux.go
nuknal f609b2b023 aux
2024-05-18 16:34:10 +08:00

333 lines
8.7 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 extract
import (
"encoding/binary"
"errors"
"fmt"
"math"
"os"
"strings"
"time"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)
// 每行传感器数据帧头信息长度为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())
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)
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
}
// 存储辅助数据到临时文件
dataIndex := i + 24
lw.ws[EB_AUX].w.Write(data[dataIndex : dataIndex+8]) // 8字节焦面电箱辅助数据
dataIndex += 8
lw.ws[PLAT_AUX].w.Write(data[dataIndex : dataIndex+32]) // 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 // 完成一行数据解析
}
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
}
}
panEnviHdr.Samples = 9520
panEnviHdr.Bands = 1
lw.ws[PAN_HDR].w.Write([]byte(panEnviHdr.String()))
mssEnviHdr.Lines = mssEnviHdr.Lines / 4 // 多光谱波段分别在 4 行中传输
mssEnviHdr.Samples = 2384
mssEnviHdr.Bands = bands
lw.ws[MSS_HDR].w.Write([]byte(mssEnviHdr.String()))
return nil
}
func (e *Extractor) quanlityAnalysis(data []byte) {
// 数据质量分析
fimg, _ := os.Create("demo/temp/" + e.params.DataId + "_aux_img.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
}