/* file: rrgen.c Entry number : 171 Authors : Dragan Gamberger, Ivan Maric, Tomislav Smuc, Gordan Bosanac, Nikola Bogunovic, Goran Krstacic Organization : Rudjer Boskovic Institute, Institute for Cardiovascular Prevention and Rehabilitation Zagreb, Croatia email address : dragan.gamberger at irb.hr 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 rr27 and rr43 of the challenge dataset. */ #include #include #include #define SPS 128 /* sampling frequency (determines quantization of RR intervals; see main()) */ #define STACK 20 /* stack daepth for mean value computation */ #define def_load 0.35 /* default load during the day */ float val[STACK]; /* previous interval values stack*/ float ip[STACK]; /* integral power values stack */ float val_mean; /* mean value of interval values in stack */ float ip_mean; /* mean value of integral power in stack */ float rr_high; /* expected interval value for load 0.0*/ float rr_low; /* expected interval value for load 1.0*/ float abs_max; /* absolut maximal interval value */ float abs_min; /* absolut minimal interval value */ float heart_load; /* present heart load 0.0 - 1.0 */ float int_pow; /* integral power (needed by the body) */ float int_pow_change; /* change of power */ float mem_prev; /* previous disorder */ int aux_counter; /* auxilliary counter */ /* load variables */ float load0; /* long term load */ float load00; /* intended long term load */ float load1; /* permanent load, steps */ int load1c; /* permanent load counter */ float load2; /* permanent load, continuous */ float load2p; /* positive step */ float load2m; /* negative step */ int load2cp; /* positive step counter */ int load2cm; /* negative step counter */ float load3; /* long term load, continuous */ float load3p; /* positive step */ float load3m; /* negative step */ int load3cp; /* positive step counter */ int load3cm; /* negative step counter */ float load4; /* medium term load, continuous */ float load4p; /* positive step */ float load4m; /* negative step */ int load4cp; /* positive step counter */ int load4cm; /* negative step counter */ float load5; /* medium term load, steps */ int load5c; /* counter */ float load6; /* short term load, steps */ int load6c; /* counter */ /* global time constants */ float start_ss,per_ss1,per_ss2; /* basic sleep period */ float incr1,incr2; /* increments for sleep */ float start_wk1,per_wk1; /* basic work period */ float start_wk2,per_wk2; /* intensive work period */ /* main random generating routine */ float randn(void) { return(((float)rand())/((float)RAND_MAX)); } float distri(xa,xbl,xbh,xcl,xch) float xa,xbl,xbh,xcl,xch; { float x,y; double base,exp,res; x=randn(); if(x>.5) { /* increase interval */ x=2.0*(x-0.5); exp=x; /* x = 0,1 */ base=2.0; /* select distribution slope 2=flat, 25 steep */ if(xch/xbh > 2.65) base=4.0; if(xch/xbh > 3.30) base=8.0; if(xch/xbh > 4.10) base=12.0; if(xch/xbh > 4.70) base=16.0; if(xch/xbh > 5.50) base=25.0; res=pow(base,exp); y=xa+xch*((float) res -1.0)/((float) base -1.0); } else { /* decrease interval */ exp=2.0*x; /* x = 0,1 */ base=2.0; /* select distribution slope 2=flat, 25 steep */ if(xcl/xbl > 2.65) base=4.0; /* both xbl xcl MUST be negative */ if(xcl/xbl > 3.30) base=8.0; if(xcl/xbl > 4.10) base=12.0; if(xcl/xbl > 4.70) base=16.0; if(xcl/xbl > 5.50) base=25.0; res=pow(base,exp); y=xa+xcl*((float) res -1.0)/((float) base -1.0); /* xcl is negative */ } return(y); } /* This function is called once, before generate() is called. See main() for a description of its arguments. */ void initialize(long seed, long tmax) { int j,jj; /* auxilliary counters */ srand((unsigned int)seed); /* initialize random generator */ for (j=0;;) { j =(int) (randn()*3000) -2000; /* do not use few first random numbers */ if(j>0) break; } for(jj=0;jj0.35 && abs_min82000) start_ss = 82000- per_ss2; per_ss1=per_ss2*(0.7+0.2*randn()); /* duration of the first sleep part */ per_ss2 -= per_ss1; /* duratio of the second part */ incr1 = (def_load*100)/ per_ss1; incr2 = (def_load*100)/ per_ss2; start_wk1=7000+1000*randn(); /* start increased load during the day */ per_wk1=start_ss-start_wk1-10000-1000*randn(); start_wk2=start_wk1+10000+1000*randn(); /* start second increased load during the day */ per_wk2=start_wk1+per_wk1-start_wk2-10000-1000*randn(); aux_counter=0; return; } /* This function is called once per RR interval. It should return the length of the next (simulated) RR interval in seconds. The example code generates samples of a noisy sine wave. */ float generate(void) { float rr; /* new interval value */ static float t; float xa,xbl,xbh,xcl,xch; /* distribution constants */ int j; /* auxilliary counter */ float tt; /* auxilliary time */ float corr1,corr2; /* correction values for rr*/ float change; /* statistical instabilities of rr */ /* compute load */ /* long term */ tt=t; for(;;) { /* ajust for more than 24 hours */ if(tt<=86400) break; else tt-=86400; } /* medium load is default value during the day*/ if(ttstart_ss+per_ss1+per_ss2) load0=def_load + 0.05*sin(tt*7.26/100000); else { if(aux_counter>0) aux_counter--; else { aux_counter=100; if(tt>start_ss && ttstart_ss+per_ss1 && ttdef_load) load0=def_load + 0.05*sin(tt*7.26/100000); } } if(tt>start_wk1 && ttstart_wk2 && ttstart_ss-10000 && tt0) load1c--; if(load1c==0) { load1c= (int) (1000*randn()); /* duration of the new offset */ if(load00) { /* first increase load */ load2-=load2p; load2cp--; } else if(load2cm>0) { /* after that decrese it */ load2+=load2m; load2cm--; } if(load2cp==0 && load2cm==0) { /* determine new period */ load2=0; load2cp= (int) (10+100*randn()); /* up and down times */ load2cm= (int) (load2cp*randn()); load2cp -= load2cm; if(load00) { /* first increase load */ load3-=load3p; load3cp--; } else if(load3cm>0) { /* after that decrease it */ load3+=load3m; load3cm--; } if(load3cp==0 && load3cm==0) { /* determine new period */ load3=0; if(load0>def_load-0.05 && randn()<0.3) if(randn()<0.001) { load3=0.1; load3cp= (int) (4500+4000*randn()); /* total up and down times */ load3cm= (int) (load3cp*randn()); /* decrease time */ load3cp -= load3cm; /* increase time */ load3p= 0.1*randn()+0.1; /* peak value */ load3m= load3p/((float) (load3cm)); /* decrease value */ load3p= load3p/((float) (load3cp)); /* increase value */ } } /* medium term load during the work, continuous */ if(load4cp>0) { /* first increase load */ load4-=load4p; load4cp--; } else if(load4cm>0) { /* after that decrese it */ load4+=load4m; load4cm--; } if(load4cp==0 && load4cm==0) { /* determine new period */ load4=0; if(load0>def_load-0.05 && randn()<0.1) if(randn()<0.001) { load4=0.1; load4cp= (int) (4500+4000*randn()); /* total up and down times */ load4cm= (int) (load4cp*randn()); /* decrease time */ load4cp -= load4cm; /* increase time */ load4p= 0.1*randn()+ 0.1; /* peak value */ if(randn()<0.1) load4p=load4p*(-2.0); if(load0+load1+load2+load3>0.7) load4p= 0.1*randn(); load4m= load4p/((float) (load4cm)); /* decrease value */ load4p= load4p/((float) (load4cp)); /* increase value */ } } /* medium term load during the whole day, steps*/ if(load5c>0) { load5c--; } else{ load5=0.0; if(randn()<0.0005*(load0+load1+load2+load3+load4+0.1)) { load5c= (int) (2500+5000*randn()); load5=0.15*randn()+0.1; if(load0+load1+load2+load3+load4>0.7) load5=load5/4.0; if(load00) { load6c--; } else{ load6=0.0; if(randn()<0.005*(load0+load1+load2+load3+load4+load5+0.1)) { load6c= (int) (10+50*randn()); load6=0.1*randn()+0.05; if(load0+load1+load2+load3+load4+load5>0.9) load6=load6/4; if(val[0]<0.5) load6=0.0; } } heart_load=load0+load1+load2+load3+load4+load5+load6; /* total heart load */ if(heart_load>1.0) heart_load=1.0; /* normalization */ if(heart_load<0.0) heart_load=0.0; /* compute changes in integral power of the body */ int_pow_change=heart_load+1.0-2*(rr_high-rr_low)/(val[0]+rr_high-2*rr_low); /* integral power correction, long term stability */ /* ** increse second constant if global oscilations are too high */ /* maximal oscilation depression with C=0.015 */ if(int_pow>0) corr1=-.002; else corr1=.002; if(int_pow>0 && int_pow>ip_mean && int_pow_change>0) corr1-=0.015*randn(); if(int_pow<0 && int_powip_mean && int_pow_change>0) corr1-=0.015*randn(); if(int_pow0) corr1-=0.003; if(int_pow_change<0) corr1+=0.003; /* recent history correction, use it only in stable situation */ corr2=0; if(int_pow>-0.25 && int_pow<0.25 ) { /* stable condition */ corr2+=(val_mean-val[0])*(0.0+1.0*randn())*1.2*val[0]; corr2+=(val_mean-val[1])*(0.0+1.0*randn())*1.4*val[0]; } /* introduce instabilities */ /* basic algorithm, use distribution to determine rr changes */ xa=0.000; xbl=-0.010*val[0]; xbh=0.010*val[0]; xcl=-0.020*(1.0+val[0]); xch=0.030*(1.0+val[0]); change=distri(xa,xbl,xbh,xcl,xch); /* use distribution to compute difference */ /* asimetric instabilities */ if(randn()<0.005 && val[0]>0.7) change+=0.4*randn()*val[0]; /*predicted interval value is previous + corrections + instabilities */ rr=val[0]+corr1+corr2+change; /* suprises */ if(mem_prev>0.001 || mem_prev<-0.001) { if(randn()<0.5) { rr-=mem_prev*(0.5+0.5*randn()); mem_prev=0.0; } } else if(randn() < 0.002) { if(val[0]> 0.8 && randn()<0.1) mem_prev=(-1.0)*(0.1+0.1*randn()); else{ if(val[0]<1.0 && val[0]>0.6 && randn()<0.5) rr+=.2; else mem_prev=0.05+.1*randn(); } rr+=mem_prev; } /* prevent this rr to be too short or too long*/ for(;;) { /* prevent this rr to be too short */ if(rr>abs_min) break; if(int_pow>1.0) rr+=0.05*randn(); else rr+=0.25*randn(); } for(;;) { /* prevent this rr to be too long */ if(rr0;j--) val[j]=val[j-1]; val[0]=rr; for(j=STACK-1;j>0;j--) ip[j]=ip[j-1]; ip[0]=int_pow; t += rr; return (rr); } 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); }