📄 biosig.c
字号:
/* $Id: biosig.c,v 1.46 2006/05/15 09:49:21 schloegl Exp $ Copyright (C) 2005,2006 Alois Schloegl <a.schloegl@ieee.org> This function is part of the "BioSig for C/C++" repository (biosig4c++) at http://biosig.sf.net/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* reading and writing of GDF files is demonstrated Features: - reading and writing of EDF, BDF and GDF2.0pre files - reading of GDF1.x, BKR, CFWB, CNT files implemented functions: - SOPEN, SREAD, SWRITE, SCLOSE, SEOF, SSEEK, STELL, SREWIND */#include <stdio.h>#include <stdlib.h>#include <string.h>//#include <libxml/xmlreader.h>#include "biosig.h"//#include "zlib.h"const int16_t GDFTYP_BYTE[] = { 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 0, 0, 0, 0, 0, /* 0 */ 4, 8,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 48 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, /* 256 */ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, /* 255+24 = bit24, 3 byte */ 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 384 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, /* 512 */ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,10 };/****************************************************************************//** **//** INTERNAL FUNCTIONS **//** **//****************************************************************************/ // greatest common divisor size_t gcd(size_t A,size_t B) { size_t t; while (!B) { t = B; B = A%B; A = t; } return(A);};// least common multiplesize_t lcm(size_t A,size_t B) { return(A*B/gcd(A,B));};#if __BYTE_ORDER == __BIG_ENDIANfloat l_endian_f32(float x) { union { float f32; uint32_t u32; } b1,b2; b1.f32 = x; b2 = b1; b2.u32 = bswap_32(b1.u32); return(b2.f32);}double l_endian_f64(double x) { union { double f64; uint32_t u32[2]; } b1,b2; b1.f64 = x; b2 = b1; b2.u32[0] = bswap_32(b1.u32[1]); b2.u32[1] = bswap_32(b1.u32[0]); return(b2.f64);}#endif/****************************************************************************//** **//** EXPORTED FUNCTIONS **//** **//****************************************************************************//****************************************************************************//** INIT HDR **//****************************************************************************/HDRTYPE* create_default_hdr(const unsigned NS, const unsigned N_EVENT){/* HDR is initialized, memory is allocated for NS channels and N_EVENT number of events. The purpose is to set the define all parameters at an initial step. No parameters must remain undefined. */ HDRTYPE* hdr = (HDRTYPE*)malloc(sizeof(HDRTYPE)); union { uint32_t testword; uint8_t testbyte[sizeof(uint32_t)]; } EndianTest; int k,k1; EndianTest.testword = 0x4a3b2c1d; hdr->FILE.LittleEndian = (EndianTest.testbyte[0]==0x1d); if ((hdr->FILE.LittleEndian) && (__BYTE_ORDER == __BIG_ENDIAN)) { fprintf(stderr,"Panic: mixed results on Endianity test.\n"); exit(-1); } if ((!hdr->FILE.LittleEndian) && (__BYTE_ORDER == __LITTLE_ENDIAN)) { fprintf(stderr,"Panic: mixed results on Endianity test.\n"); exit(-1); } hdr->FILE.OPEN = 0; hdr->FILE.FID = 0; hdr->AS.Header1 = NULL; hdr->TYPE = GDF; hdr->VERSION = 1.94; hdr->AS.rawdata = (uint8_t*) malloc(10); hdr->NRec = 0; hdr->NS = NS; hdr->SampleRate = 4321.5; memset(hdr->AS.PID,32,81); hdr->AS.RID = "GRAZ"; hdr->AS.bi = (uint32_t*)calloc(hdr->NS+1,sizeof(uint32_t)); hdr->data.size[0] = 0; // rows hdr->data.size[1] = 0; // columns hdr->data.block = (biosig_data_type*)malloc(410); hdr->T0 = t_time2gdf_time(time(NULL)); hdr->ID.Equipment = *(uint64_t*)&"b4c_0.35"; hdr->Patient.Name = "X"; hdr->Patient.Id = "X"; hdr->Patient.Birthday = (gdf_time)0; // Unknown; hdr->Patient.Medication = 0; // 0:Unknown, 1: NO, 2: YES hdr->Patient.DrugAbuse = 0; // 0:Unknown, 1: NO, 2: YES hdr->Patient.AlcoholAbuse= 0; // 0:Unknown, 1: NO, 2: YES hdr->Patient.Smoking = 0; // 0:Unknown, 1: NO, 2: YES hdr->Patient.Sex = 0; // 0:Unknown, 1: Male, 2: Female hdr->Patient.Handedness = 0; // 0:Unknown, 1: Right, 2: Left, 3: Equal hdr->Patient.Impairment.Visual = 0; // 0:Unknown, 1: NO, 2: YES, 3: Corrected hdr->Patient.Weight = 0; // 0:Unknown hdr->Patient.Height = 0; // 0:Unknown hdr->Dur[0] = 1; hdr->Dur[1] = 1; memset(&hdr->IPaddr,0,6); for (k1=0; k1<3; k1++) { hdr->Patient.Headsize[k1] = 0; // Unknown; hdr->ELEC.REF[k1] = 0.0; hdr->ELEC.GND[k1] = 0.0; } hdr->LOC[0] = 0x00292929; hdr->LOC[1] = 48*3600000+(1<<31); // latitude hdr->LOC[2] = 15*3600000+(1<<31); // longitude hdr->LOC[3] = 35000; //altitude in centimeter above sea level hdr->FLAG.UCAL = 0; // un-calibration OFF (auto-scaling ON) hdr->FLAG.OVERFLOWDETECTION = 1; // overflow detection ON // define variable header hdr->CHANNEL = (CHANNEL_TYPE*)calloc(hdr->NS,sizeof(CHANNEL_TYPE)); for (k=0;k<hdr->NS;k++) { hdr->CHANNEL[k].Label = "C4"; hdr->CHANNEL[k].Transducer= "EEG: Ag-AgCl electrodes"; hdr->CHANNEL[k].PhysDim = "uV"; hdr->CHANNEL[k].PhysDimCode = 19+4256; // uV hdr->CHANNEL[k].PhysMax = +100; hdr->CHANNEL[k].PhysMin = -100; hdr->CHANNEL[k].DigMax = +2047; hdr->CHANNEL[k].DigMin = -2048; hdr->CHANNEL[k].GDFTYP = 3; // int16 hdr->CHANNEL[k].SPR = 1; // one sample per block hdr->CHANNEL[k].HighPass = 0.16; hdr->CHANNEL[k].LowPass = 70.0; hdr->CHANNEL[k].Notch = 50; hdr->CHANNEL[k].Impedance = INF; for (k1=0; k1<3; hdr->CHANNEL[k].XYZ[k1++] = 0.0); } // define EVENT structure hdr->EVENT.N = N_EVENT; hdr->EVENT.SampleRate = hdr->SampleRate; hdr->EVENT.POS = (uint32_t*) calloc(hdr->EVENT.N,sizeof(*hdr->EVENT.POS)); hdr->EVENT.TYP = (uint16_t*) calloc(hdr->EVENT.N,sizeof(*hdr->EVENT.TYP)); hdr->EVENT.DUR = (uint32_t*) calloc(hdr->EVENT.N,sizeof(*hdr->EVENT.DUR)); hdr->EVENT.CHN = (uint16_t*) calloc(hdr->EVENT.N,sizeof(*hdr->EVENT.CHN)); // initialize "Annotated ECG structure" hdr->aECG = NULL; return(hdr);}/****************************************************************************//** SOPEN **//****************************************************************************/HDRTYPE* sopen(const char* FileName, const char* MODE, HDRTYPE* hdr)/* MODE="r" reads file and returns HDR MODE="w" writes HDR into file */{ const char* GENDER = "XMFX"; const uint16_t CFWB_GDFTYP[] = {17,16,3}; const float CNT_SETTINGS_NOTCH[] = {0.0, 50.0, 60.0}; const float CNT_SETTINGS_LOWPASS[] = {30, 40, 50, 70, 100, 200, 500, 1000, 1500, 2000, 2500, 3000}; const float CNT_SETTINGS_HIGHPASS[] = {NaN, 0, .05, .1, .15, .3, 1, 5, 10, 30, 100, 150, 300};#ifdef __XML_XMLREADER_H__ xmlTextReaderPtr reader; xmlDocPtr doc; /* the resulting document tree */ int ret;#endif int k,id; uint32_t k32u; size_t count,len,pos; uint8_t buf[81]; char tmp[81]; char cmd[256]; double Dur; char* Header1; char* Header2; char* ptr_str; struct tm tm_time; time_t tt; unsigned EventChannel = 0; struct { int number_of_sections; } SCP;if (!strcmp(MODE,"r")) { hdr = create_default_hdr(0,0); // initializes fields that may stay undefined during SOPEN #ifdef ZLIB_H hdr->FILE.FID = fopen(FileName,"rb");#else hdr->FILE.FID = fopen(FileName,"rb");#endif hdr->FileName = FileName; if (hdr->FILE.FID == NULL) { free(hdr); return(NULL); } /******** read 1st (fixed) header *******/ Header1 = (char*)malloc(256);/*#ifdef ZLIB_H count = gzread(hdr->FILE.FID,Header1,256);#else*/ count = fread(Header1,1,256,hdr->FILE.FID);//#endif if (0); else if (!memcmp(Header1+1,"BIOSEMI",7)) { hdr->TYPE = BDF; hdr->VERSION = -1; } else if ((Header1[0]==(char)207) & (!Header1[1]) & (!Header1[154]) & (!Header1[155])) hdr->TYPE = BKR; else if (!memcmp(Header1,"CFWB\1\0\0\0",8)) hdr->TYPE = CFWB; else if (!memcmp(Header1,"Version 3.0",11)) hdr->TYPE = CNT; else if (!memcmp(Header1,"DEMG",4)) hdr->TYPE = DEMG; else if (!memcmp(Header1,"0 ",8)) { hdr->TYPE = EDF; hdr->VERSION = 0; } else if (!memcmp(Header1,"fLaC",4)) hdr->TYPE = FLAC; else if (!memcmp(Header1,"GDF",3)) hdr->TYPE = GDF; else if (!memcmp(Header1,"@ MFER ",8)) hdr->TYPE = MFER; else if (!memcmp(Header1,"@ MFR ",6)) hdr->TYPE = MFER; else if (!memcmp(Header1,"NEX1",4)) hdr->TYPE = NEX1; else if (!memcmp(Header1,"PLEX",4)) hdr->TYPE = PLEXON; else if (!memcmp(Header1+16,"SCPECG",6)) hdr->TYPE = SCP_ECG; else { fclose(hdr->FILE.FID); free(Header1);#ifdef __XML_XMLREADER_H__ LIBXML_TEST_VERSION reader = xmlReaderForFile(hdr->FileName, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT); // XML_PARSE_DTDVALID cannot be used in aECG if (reader != NULL) { ret = xmlTextReaderRead(reader); while (ret == 1) {// processNode(reader);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -