RR Interval Time Series Modeling: The PhysioNet/Computing in Cardiology Challenge 2002 1.0.0

File: <base>/generators/rrgen-161.c (9,391 bytes)
/* file: rrgen.c
     Entry number  : 161
     Authors       : Miguel A. García-González, Juan Ramos-Castro
     Organization  : Instrumentation and Bioengineering Division, 
				Electronic Engineering Department,
				Universitat Politècnica de Catalunya
				Barcelona, Spain
     email address : magarcia at eel.upc.es

   This program should compile without errors or warnings using:
	gcc -Wall rrgen.c -lm

   See http://www.physionet.org/challenge/2002/ for further information on
   the CinC Challenge 2002.

   This program was used to generate series rr32 and rr34 of the challenge
   dataset.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define	SPS	128	/* sampling frequency (determines quantization of
				RR intervals; see main()) */
#define PI 3.14159263
#define DIM 1024

void simcirc(int *, long, float *);
void sese(int, float , float *);
void moving(float *,int,int, float *);
void escalado(float *,float, float );
void fillmat(float [][5],float *,int , int);
float mean(float *,int);
float stdv(float *,int);
void prepro(float *,int);
float generate(void);
float bbv(float,float,float,float,float,float);
float sqsig(float, float);
void square(float *, float , int , float *);
float randn(void);
float randu(void); 

/**********************************/
/* GLOBAL VARIABLES             ***/
float lf1;
float f1;
float sd1;
float xrr[1024];
long tgmax;
/**********************************/


/* This function is called once, before generate() is called.  See main()
	for a description of its arguments.
*/

/***********************************************************************/






void initialize(long seed, long tmax)
{
	float mrr,ddn;
	int mat5[5]={33,10,5,2,1};
/* Initialize global variables */
	srand((unsigned int) seed);
   mrr=0.75+0.3*randu(); /* Mean rr */
   sd1=0.07*mrr+0.04*(randu()); /* generated signal standard deviation if mean rr equals 1 second */
   lf1=0.5+randu()/2.0; /* ratio related to lf/hf index */
   f1=2.0+18.0*randu(); /* ratio related to determistic no deterministic data */
	ddn=0.5*mrr+0.05*randu();
	tgmax=tmax;
	simcirc(mat5 , tmax, xrr);
	escalado(xrr,mrr,ddn);
	return;
}


/* This function is called once per RR interval.  It should return
 the length of the next (simulated) RR interval in seconds.
*/

float generate(void)
{
	static float rr,temp,dfr,fmod,bfp,bfd,bfm,dut,ph,ts,sdf;
	static float t,fr=0.15,kf,ss[512],ss2[512],bar[512];
	int index,k;
	static int lresp,kresp;
	index = (int) floor(t/( (long) tgmax)* ((int) DIM));
	if(index>(DIM-1)) index=DIM-1;
	if(t>=kf){
		kresp=0;
		if (fr > 0.35) fr=fr-0.01*randu();
		if (fr < 0.18) {fr=fr+0.03*randu();}
		else {fr=fr+0.02*(randu()-0.5);};
		lresp= (int) floor(250.0+100.0*randu());
		dfr=0.01*(1.0+fabs(xrr[index]-1))*randu();
		kf=t+xrr[index]*lresp;
      /*Fractal signal used for simulate complex behaviour */
		sese(512, 1.3+0.1*randu(),ss);
		moving(ss,512,100,ss2);
      fmod=0.000*randu();
      bfp=0.12*(1+0.3*(randu()-0.5));
      bfd=0.003*randu();
      bfm=0.07*randu();
      dut=80.0+10.0*randu();
      ph=PI/2.0*(1+0.1*randu());
      for (k=0;k<512;k++) {
			 ts=(t+xrr[index]*k);
	  bar[k]=sqsig(2.0*PI*bfp*(1.0+bfd/2.0*(sin(2.0*PI*bfm*ts)+1.0))*ts+ph,dut);
      }
		moving(bar,512,1,bar);
		prepro(bar,512);
		temp=mean(bar,512);
		for (k=0;k<512;k++) bar[k]=bar[k]-temp;
		sdf=0.05*randu()+0.1;
	}
    /* Simulate non chaotic data */
	temp=bbv(sd1,t,xrr[index],fr,dfr,fmod)*(3*ss2[kresp]+1);
	temp=temp+(pow(xrr[index],-1.5)+0.03*randu())*bar[kresp]*sd1/lf1;
	rr=temp*pow(xrr[index],1.5)+ss[kresp]*f1*sd1*sd1*pow(xrr[index],-1)/3+0.01*randn();
	rr=rr*pow(xrr[index],2)+xrr[index];
	if ((rr > 2) || (rr < 0.5)) rr=xrr[index];
	t += rr;
	kresp++;
   return (rr);
}


/********************* Aqui pongo mi codigo ***************************/
float randn(void)  /* Generador de numeros aleatorios con dist. gaussiana */
{
	float x1,x2,z;
	x1=((float) rand())/RAND_MAX;
	x2=((float) rand())/RAND_MAX;
	x1=x1+1e-10;
	z=sqrt(-2*log(x1))*cos(2*PI*x2);
	return(z);
}

float randu(void)   /* Generador de numeros aleatorios con dist. uniforme (0-1) */
{
	return((float) rand()/RAND_MAX);

}

float mean( float *vector, int dim) /* Calcula la media del vector */
{
	int k;
	float med=0;
	for(k=0;k<dim;k++)
	{
		med=med+vector[k];
	}
	med=med/dim;
	return(med);
}

float stdv(float *vector, int dim)  /* Calcula la desv. estandar ajustada vector*/
{
	int k;
	float var=0.0;

	for(k=0;k<dim;k++)
	{
		var=var+vector[k]*vector[k];
	}
	var=sqrt((var/dim-pow(mean(vector,dim),2.0))*dim/(dim-1));
	return(var);
}

void square(float *ti, float duty, int dim, float *x)
{
	int k;
	float w,temp;
	w=2.0*PI*duty/100.0;
	for(k=0;k<dim;k++){
		temp=-2.0*PI*floor(ti[k]/(2.0*PI));
		x[k]=ti[k]+temp;
		if(x[k]<w) {x[k]=1.0;}
		else {x[k]=0.0;}
	}

}

float sqsig(float ti, float duty)
{
	float w,temp;

	w=2.0*PI*duty/100.0;
	temp=-2.0*PI*floor(ti/(2.0*PI));
	temp=ti+temp;
	if(temp<w) {return(1.0);}
	else {return(0.0);}
}

void fillmat(float mat[][5],float *x,int col, int dim)
{
	int k;
	for(k=0;k<dim;k++) mat[k][col]=x[k];
}

void moving(float *v,int dim,int wl, float *vf)
{
	int k,j;
	for(k=wl;k<(dim-wl);k++) {
		vf[k]=0;
		for(j=-wl;j<=wl;j++) vf[k]=vf[k]+v[k+j];
		vf[k]=vf[k]/(wl*2.0+1.0);
	}
	for(k=0;k<wl;k++) {
		vf[k]=vf[k+wl];
		vf[dim-k-1]=vf[dim-k-wl];
	}
}

void prepro(float *v, int dim)
{
	int k;
	float ma,mi;
	mi=1.0e10;
	ma=-1.0e10;
	for(k=0;k<dim;k++) {
		if(v[k]<mi) mi=v[k];
		if(v[k]>ma) ma=v[k];
	}
	for(k=0;k<dim;k++) v[k]=(v[k]-mi)/(ma-mi)-0.5;
}

void escalado(float *v,float mrr, float dnd)
{
	float m;
	int k;
	float vf[1024];
	prepro(v,1024);
	for(k=0;k<1024;k++) v[k]=(v[k]+1.5)*dnd;
	m=mean(v,1024);
	for(k=0;k<1024;k++){
	 vf[k]=v[k]-m+mrr;
	 }
	moving(vf,1024,2,v);
	for (k=1;k<1023;k++) {
		if (fabs(v[k+1]-v[k])>0.05) v[k]=(v[k-1]+v[k+1])/2.0;
		}
	v[1023]=v[1021];
	v[1022]=v[1020];
	
	return;
}

void simcirc(int dcd[5], long tmax, float *x)
/* Genera el ritmo circadiano */
{
	float ct[1024][5];
	float ti[1024],xf[1024],ph,pes[5];
	int k,zc[5],zcp[5],pos[5],nzc=0;
	int i,n1,n2,j;

	ph=1.5*PI+PI*randu()*0.1;
	for(k=0;k<1024;k++) ti[k]=(PI*2.0*k*tmax/(3600.0*24.0))/1023+ph;
	square(ti,dcd[0]+randu(),1024,x);
	fillmat(ct,x,0,1024);
	nzc=0;
	for(k=0;k<1023;k++){
		if(x[k]!=x[k+1]) {
			zcp[nzc]=1023-k;

			nzc++;
		}
	}
	for(k=0;k<nzc;k++){
		zc[k]=zcp[nzc-k-1];

		}
	for(i=1;i<5;i++) {
		ph=(randu()-0.5)*PI/4;
		for(k=0;k<1024;k++) ti[k]=(PI*2.0*k*tmax/(3600.0*24.0))/1023.0+ph+(k+1)*PI/4;
		square(ti,dcd[i]+randn(),1024,x);
		fillmat(ct,x,i,1024);
		pes[i]=0.5*(randu()-0.5);
	}
	pes[0]=1.0;
	for(k=0;k<1024;k++) {
		x[k]=0;
		for(i=0;i<5;i++) x[k]=x[k]+ct[1023-k][i]*pes[i];
	}

	n1= (int) ceil(((43.0-7.11)*randu())/2*tmax/3600.0/24.0);
	n2= (int) floor((13.11*randu())/2*tmax/3600.0/24.0);
	zc[nzc]=1023;
	i=zc[0];
	for(k=0;k<nzc;k++){
		pos[k]= (int) ceil((i+zc[k+1])/2);
		i=zc[k+1];
	}
	i=0;
	for(j=0;j<nzc;j++){

		for(k=0;k<(pos[j]-i);k++) ti[k]=x[k+i];
		if(j%2 == 0) moving(ti,pos[j]-i,n1,xf);
		else moving(ti,pos[j]-i,n2,xf);
		for(k=0;k<(pos[j]-i);k++) x[k+i]=xf[k];
		i=pos[j];
		}
	sese(1024,1.5,ti);
	moving(ti,1024,40,xf);
	n1= (int) (3*randu()+2);
	moving(x,1024,n1,ti);
	for(k=0;k<1024;k++) x[k]=ti[k]+xf[k]*1.5;
	return;


}

void sese(int n, float d, float *x)
/* Genera serie fractal de longitud n y dimension d, la salida esta en x */
{
	static float h,b,ti[1024],q[1024],p[1024],a[1024],c[1024],temp,temp2;
	int k,n2,j;

	n2=n/2;
	h=2-d;
	b=1+2*h;
	for(k=0;k<n2;k++){
		ti[k]=k+1;
		if(k==0) p[k]=0;
		else p[k]=pow(k,-b/2)*randn();
		q[k]=2*PI*randu();
		a[k]=p[k]*cos(q[k]);
		c[k]=p[k]*sin(q[k]);
	}
	for(k=0;k<n;k++){
		temp=0;
		for(j=0;j<n2;j++){
			temp=temp+a[j]*cos(2*PI*ti[j]*k/n)+c[j]*sin(2*PI*ti[j]*k/n);
		}
		x[k]=temp;
	}
	for(k=0;k<(n-1);k++){
		x[k]=x[k+1]-x[k];
	}
	x[n]=x[n-1];
	temp=mean(x,n);
	temp2=stdv(x,n);
	for(k=0;k<n;k++) x[k]=(x[k]-temp)/temp2;
	return;

}

/* Beat to beat deterministic variatio due to respiration and baroreceptor */
float bbv(float gsd1,float t,float rm,float fr, float dfr, float fmod)
{
/* gsd1: generated signal standard deviation if mean rr equals 1 second */
/* rm:  mean rr */
/* blf1: ratio related to lf/hf index */
/* bf1: ratio related to determistic no deterministic data */
/* t: simulation time */
/* fr: mean respiratory frequency */


   float resp; /*  */


   resp=(1.0+sin(2.0*PI*fr/rm*(1.0+dfr*sin(2.0*PI*fmod*t))*t))/2.0-0.5;
	resp=resp*(pow(rm,1.5)+0.001*randn())*gsd1;

	return(resp);

}



/***********************************************************************/


int main(int argc, char **argv)
{
    float t = 0.0;	    /* sum of intervals since the beginning of the
			       simulation, in seconds */
    long ts = 0;	    /* t, in sample intervals */
    long tsp = 0;	    /* previous value of ts */
    long tmax = 24*60*60;   /* 24 hours, in seconds */
    long seed;		    /* a 32-bit random variable that can be used to
			       initialize the generator */
    long atol();

    if (argc < 2) {
	fprintf(stderr, "usage: %s seed [tmax]\n", argv[0]);
	exit(1);
    }
    seed = atol(argv[1]);
    if (argc > 2)
	tmax = atol(argv[2]);

    initialize(seed, tmax);
    while ((t += generate()) < tmax) {	/* add RR interval to running time */
	/* calculate and output a quantized RR interval */
	ts = (long)(SPS*t + 0.5);
	printf("%5.3f\n", (ts - tsp)/((float)SPS));
	tsp = ts;
    }

    exit(0);
}