多通道波形文件存储
最近在做一个多通道信号数据采集的项目,遇到这样的问题“在一个文件中如何去存储多个通道的实时波形数据”,初步定义了如下方式:将“一定时间”内不同通道采样点数据集合划分为一个数据块,“一定时间”在文件头信息中有定义(即数据块持续时间),采样数据集合点数将在每个通道头中有定义,以上两要素可以直接被采样率所影响。如此便可在一个文件中存储不同采样率多通道的波形数据,也可以保证不同通道间的数据在时间序列上的同步。
文件结构
文件头和通道头定义
struct File_Head_Info {
char szTotal_Head_Size[8]; /// 文件头总字节数(文件头+通道头)
char szReserved_Data[44]; /// 保留的字节数
char szTotal_Data_Block[8]; /// 数据块总数
char szData_Block_Duration[8]; /// 以秒为单位的一个数据块持续时间
char szSignal_Number [4]; /// 数据块中的通道数
};
struct Channel_Info {
char szSamples_In_A_Record[8]; /// 一个数据记录块中的采样数据数
char szMaintain[32]; /// 保留值,共32字节,必须填为0
};
文件读取伪代码
short *Format::ReadChannelData(int channel, int &smpcount, int&samplerate)
{
smpcount = 0;
//通道数超过了存储的通道数
if(channel >= m__Head.lSignal_Number)
{
smpcount = 0;
samplerate = 0;
return NULL;
}
///1.------------------ 获取要使用到的基本信息. ----------------------------
int iSignal_Num = (int)m__Head.lSignal_Number; /// 信号数
int iTotal_Block = (int)m__Head.lTotal_Data_Block; /// 总的数据块数
int iHead_Size = (int)m__Head.lTotal_Head_Size; /// 文件头大小(基本信息头+通道信息头)
///1.1 ---------------- 计算1个数据块内所有通道的采样点总字节数. ------------
long lData_In_A_Record = 0;
for( int i=0; i<iSignal_Num; i++ )
{
lData_In_A_Record += m_Cha_Info[i].lSamples_In_A_Record * sizeof( short );
}
samplerate = m_Cha_Info[channel].fSample_Rate;
////开始解析数据的位置
char* pStart = m_DataSource + iHead_Size;
////分配一个通道的内存
long lTotleLen = m_Cha_Info[channel].lSamples_In_A_Record * iTotal_Block;
short* relBuff = new short[lTotleLen];
////读取所有的块数据
for ( int i=0; i<iTotal_Block; i++ )
{
for( int j=0; j<iSignal_Num; j++ )
{
///2.1 -------- 通道数相同,提取数据. -----------------------------
if( channel == j )
{
int size = (m_Cha_Info[j].lSamples_In_A_Record) * sizeof(short);
memcpy( (char*)( relBuff + smpcount), pStart, size );
smpcount += m_Cha_Info[j].lSamples_In_A_Record;
pStart += size;
}
///2.2 -------- 通道数不同跳过数据. -----------------------------
else
{
pStart += m_Cha_Info[j].lSamples_In_A_Record * sizeof( short );
}
}
}
return relBuff;
}
数据写入伪代码
int FormatPlat::Write2File(int chanle, short *data, int sampleCount)
{
//判断通道个数
if(chanle >= m__Head.lSignal_Number || sampleCount <= 0 )
{
return 0;
}
int iSignal_Num = (int)m__Head.lSignal_Number; /// 信号数
int iTotal_Block = (int)m__Head.lTotal_Data_Block; /// 总的数据块数
int iHead_Size = (int)m__Head.lTotal_Head_Size; /// 文件头大小(基本信息头+通道信息头)
///1.1 ---------------- 计算1个数据块内所有通道的采样点总字节数. ------------
long lData_In_A_Record = 0;
for( int i=0; i<iSignal_Num; i++ )
{
lData_In_A_Record += m_Cha_Info[i].lSamples_In_A_Record * sizeof( short );
}
//定位当前块
long long lCurBlock = m_iSeqSumNum[chanle] / m_Cha_Info[chanle].lSamples_In_A_Record;
//在当前block的偏移位置
long long lseek = m_iSeqSumNum[chanle] % m_Cha_Info[chanle].lSamples_In_A_Record;
//数据块内剩余的点数
long surplus = m_Cha_Info[chanle].lSamples_In_A_Record - lseek;
//偏移到对应的通道的起始位置
char* pStart = m_DataSource + iHead_Size;
pStart += lCurBlock * lData_In_A_Record;
for( int i=0; i<chanle; i++ )
{
pStart += m_Cha_Info[i].lSamples_In_A_Record * sizeof( short );
}
pStart += lseek * sizeof(short);
//剩余未写入的数据
long lSurCount = sampleCount;
while(lSurCount > 0)
{
//当块内部小于剩余数据的长度
if(surplus < lSurCount)
{
memcpy(pStart , data, sizeof(short) * surplus);
data += surplus;
//移动到下一数据块的起始位置
pStart += lData_In_A_Record - (m_Cha_Info[chanle].lSamples_In_A_Record -surplus) * sizeof(short);
lSurCount -= surplus;
surplus = m_Cha_Info[chanle].lSamples_In_A_Record;
}
else
{
memcpy(pStart, data, lSurCount * sizeof(short));
lSurCount = 0;
}
}
m_iSeqSumNum[chanle] += sampleCount;
}