最近给 地球物理勘探行业 (大地电磁方法)做了个文件格式转换工具。
将自有的明码时间域文件转换成加拿大凤凰(Phoenix)V8的TSn格式。
凤凰(Phoenix)的格式,24bits存放一组ADC采样码。这个和我们平时32/64bits存储由差异。主要是考虑到仪器原有的adc芯片的精度与存储效率问题。
无码无真相,首先是写header:
/* 写Phoenix记录头 */
void TSnWork::writeHeader()
{
fwrite(&goHeadPhoenix.uiSec,1, 1, pFile);
fwrite(&goHeadPhoenix.uiMin,1, 1, pFile);
fwrite(&goHeadPhoenix.uiHour,1, 1,pFile);
fwrite(&goHeadPhoenix.uiDay,1, 1, pFile);
fwrite(&goHeadPhoenix.uiMonth,1, 1, pFile);
fwrite(&goHeadPhoenix.uiYear,1, 1, pFile);
fwrite(&goHeadPhoenix.uiDayOfWeek,1, 1, pFile);
fwrite(&goHeadPhoenix.uiCentury,1, 1, pFile);
fwrite(&goHeadPhoenix.uiDevSN,2, 1, pFile);
fwrite(&goHeadPhoenix.uiSampleCntPerRecordPerCh,2, 1, pFile);
fwrite(&goHeadPhoenix.uiChCntPerScan,1, 1, pFile);
fwrite(&goHeadPhoenix.uiRecoedHeaderLength,1, 1, pFile);
fwrite(&goHeadPhoenix.uiRecStatus,1, 1, pFile);
fwrite(&goHeadPhoenix.uiBitSaturationCode,2, 1, pFile);
fwrite(&goHeadPhoenix.uiBitWidth,1, 1, pFile);
fwrite(&goHeadPhoenix.uiFS,2, 1, pFile);
fwrite(&goHeadPhoenix.uiFSUnit,1, 1, pFile);
fwrite(&goHeadPhoenix.uiClockStatus,1, 1, pFile);
fwrite(&goHeadPhoenix.iClockErr,4, 1, pFile);
fwrite(goHeadPhoenix.acReserved, 6, 1, pFile);
QString oStrPhoenixHeader = QString("%1世纪 %2/%3/%4/ %5:%6:%7 星期%8")
.arg(goHeadPhoenix.uiCentury)
.arg(goHeadPhoenix.uiYear)
.arg(goHeadPhoenix.uiMonth)
.arg(goHeadPhoenix.uiDay)
.arg(goHeadPhoenix.uiHour)
.arg(goHeadPhoenix.uiMin)
.arg(goHeadPhoenix.uiSec)
.arg(goHeadPhoenix.uiDayOfWeek);
emit sigMsg(MSG_Normal, "写Phoenix记录头时间: "+ oStrPhoenixHeader);
}
再是写数据(ADC采样码):
void TSnWork::writeADC(float number)
{
unsigned char high;
unsigned char middle;
unsigned char low;
unsigned char buffer[3];
unsigned int intNumber;
if(number >= 0)
{
intNumber = int(std::abs(floor(number)));
}
else
{
intNumber = ~int(std::abs(floor(number))) + 1;
}
high = intNumber/65536;
middle = (intNumber%65536)/256;
low = intNumber%256;
buffer[0] = low;
buffer[1] = middle;
buffer[2] = high;
fwrite(buffer, BIT_WIDTH, 1, pFile);
}
MT 的TS5 和 AMT的 TS4 连续采样简单,直接写就ok。
MT 间隔采样 TS3, TS4
AMT 间隔采样 TS2, TS3
相对来说要skip,同时要把header 里面的utc秒给skip对齐。
以下是AMT TS3 的流程代码:
/* 间隔采样, 第一个片段丢弃,第二个片段留着指定的 L3NS record个数 */
void TSnWork::writeAMT_TS3(quint32 uiHSMP, quint32 uiL3NS)
{
/* 区别对待自有设备连续采集和间隔采集 */
if(goHeaderWFEM.uiSlicBase == goHeaderWFEM.uiSliceSample)
{
uiSlicCnt = goHeaderWFEM.uiDataCnt/uiHSMP/goHeaderWFEM.uiFS/2;
uiSkipSecs = 2*uiHSMP - uiL3NS ;
uiAddSecs = 2*uiHSMP - uiL3NS;
}
else
{
uiSlicCnt = goHeaderWFEM.uiDataCnt/goHeaderWFEM.uiSliceSample/goHeaderWFEM.uiFS/2;
uiSkipSecs = 2*goHeaderWFEM.uiSliceSample - uiL3NS;
uiAddSecs = 2*goHeaderWFEM.uiSlicBase - uiL3NS ;
}
for(quint64 i = 0; i < uiSlicCnt; i++)
{
for(quint32 j = 0; j < uiL3NS; j++)
{
this->writeHeader();
this->writeScan( goHeaderWFEM.uiFS );
this->updateHeadPhoenix( 1 );
emit sigMsg(MSG_Normal, QString("AMT TS3 间隔采样,\u058E记录:%1/%2\u058E片段:%3/%4 \n")
.arg(j+1)
.arg(uiL3NS)
.arg(i+1)
.arg(uiSlicCnt));
}
this->skipRows( goHeaderWFEM.uiFS*uiSkipSecs );
this->updateHeadPhoenix( uiAddSecs );
}
fclose(pFile);
emit sigMsg(MSG_Over, "AMT TS3 间隔采样写入完毕!");
}