###Prepare edf table file
###################-
### Recode events based on RLs specifications
###################-
edf_event_recode<-function(d1,...){
#####Helper function, not foreseen to be called by the user
#####Based on the specified annotations in RLs, creates numeric codes for all events
##### that will ensure that the following scoring routines always have the same imput
#####-
##### required input:
##### d1 - annotation from edf plus file
##### optional input:
##### none
##### output:
##### an updated data table that will contain two new columns
##### T = code domain area
##### 1 = Sleep stage
##### 2 = leg movements
##### 3 = respiratory events
##### 4 = SaO2
##### 5 = Arousal
##### 6 = other, including start/stop events
##### 7 = Position
##### T2 = codes within domain area
##### 0,1,2,3,4 = wake, N1, N2, N3, REM
##### 10, 11 = left, right leg movement (at a later stage 12 will be added for bilateral LM)
##### 20,21,22,23, 25 = Hypopnea, obstructive, mixed, central apnea, RERA, 29 unknown apnea
##### 30 = Desaturation
##### 50 = Arousal
##### 301, 302 = lights off/start, lights on/stop
##### 0,1,2,3,4 = wake, N1, N2, N3, REM
##### 201=supine, 202=left, 203 = right, 204 = prone, 209 = unknown
#T: 1 = sleep stage; 2 = LM; 3 = Resp; 4 = SaO2; 5 = Arousal; 6 = Other; 7 = Position
#Sleep: 0wake, 1,2,3, 4REM, 9 = unscored
#LM 10 left, 11 right, 109,119 = Artefact on left/right leg
#Arousal = 50, RERA = 51
#Resp 20 hypopnea, 21 obst apnea, 23 central apnea, 22 mixed apnea, 28 = Inspiration, 27 = FlowLimitation?,
# 26=paradox. b, 25=RMI respiratory mechanics instability, 24=no resp. mov , 29 = Flow artifact
#SpO2 30 desaturation, 39 artifact
#Other: 301=Lights off, 302 = Lights on, 303=Device connect, 304 = device disconnect, 309 = other artifacts(Pulse.Averaged-Probe)
#Position: 201=supine, 202=left, 203 = right, 204 = prone, 209 = unknown
d1$T<-NA; d1$T2<-NA
#LM
d1$T[d1$Event=="Limb movement"]<-2
d1$T2[d1$Event=="Limb movement" & d1$Loc=="EMG RAT"]<-11
d1$T2[d1$Event=="Limb movement" & d1$Loc=="EMG LAT"]<-10
d1$T2[d1$Event=="Limb movement" & d1$Loc=="RAT"]<-11
d1$T2[d1$Event=="Limb movement" & d1$Loc=="LAT"]<-10
#Sleep
d1$T[d1$Event=="Sleep stage W"]<-1; d1$T2[d1$Event=="Sleep stage W"]<-0
d1$T[d1$Event=="Sleep stage N1"]<-1; d1$T2[d1$Event=="Sleep stage N1"]<-1
d1$T[d1$Event=="Sleep stage N2"]<-1; d1$T2[d1$Event=="Sleep stage N2"]<-2
d1$T[d1$Event=="Sleep stage N3"]<-1; d1$T2[d1$Event=="Sleep stage N3"]<-3
d1$T[d1$Event=="Sleep stage R"]<-1; d1$T2[d1$Event=="Sleep stage R"]<-4
d1$T[d1$Event=="Sleep stage 1"]<-1; d1$T2[d1$Event=="Sleep stage 1"]<-1
d1$T[d1$Event=="Sleep stage 2"]<-1; d1$T2[d1$Event=="Sleep stage 2"]<-2
d1$T[d1$Event=="Sleep stage 3"]<-1; d1$T2[d1$Event=="Sleep stage 3"]<-3
#Arousal
d1$T[d1$Event=="EEG arousal"]<-4; d1$T2[d1$Event=="EEG arousal"]<-30
#Respiratory events
d1$T[d1$Event=="Hypopnea"]<-3; d1$T2[d1$Event=="Hypopnea"]<-20
d1$T[d1$Event=="Obstructive apnea"]<-3; d1$T2[d1$Event=="Obstructive apnea"]<-20
d1$T[d1$Event=="Central apnea"]<-3; d1$T2[d1$Event=="Central apnea"]<-20
d1$T[d1$Event=="Mixed apnea"]<-3; d1$T2[d1$Event=="Mixed apnea"]<-20
d1$T[d1$Event=="RERA"]<-3; d1$T2[d1$Event=="RERA"]<-25
d1$T[d1$Event=="Apnea"]<-3; d1$T2[d1$Event=="Apnea"]<-20
#Start/stop
d1$T[d1$Event=="Lights off"]<-5; d1$T2[d1$Event=="Lights off"]<-51
d1$T[d1$Event=="Lights on"]<-5; d1$T2[d1$Event=="Lights on"]<-52
#d1<-d1[!is.na(d1$T),]
return(d1)
}
###################-
### Determin start/stop of recording
###################-
determine_startstop_edf<-function(d1,...){
#####Helper function, not foreseen to be called by the user
#####Based on the specified annotations in RLs, searches for a start and stop signal
#####-
##### required input:
##### RLs - REMLogic specification file (maybe empty)
##### d1 - extracted data table from REMLogic txt file
##### optional input:
##### none
##### output:
##### updated RLs with two new entries for start and stop (in time)
##### updated d1 data table with:
##### - new column "Onset" where start times are expressed as seconds from start of registration
##### - with all events that end before the start and start after the stop removed
#####-
##### Determination of start, in preferred order
##### (1) if a start event is defined and that start event is present
##### this will be taken as the start of the TIB
##### [if more than 1 start event are present, the latest one will be taken]
##### (2) if no start event is present but sleep is scored,
##### the first scored wake/sleep epoch is taken as the start
##### (3) if no start event is present and no sleep is scored
##### it will be assumed that the registration started 30 s before the
##### first event (any of LM, arousal, respiration)
#####-
##### Determination of stop, in preferred order
##### (1) if a stop event is defined and that stop event is present
##### this will be taken as the start of the TIB
##### [if more than 1 stop event are present, the latest one will be taken]
##### (2) if no stop event is present but sleep is scored,
##### the last scored wake/sleep epoch is taken as the stop
##### (3) if no stop event is present and no sleep is scored
##### it will be assumed that the registration stopped 30 s after the
##### last event (any of LM, arousal, respiration)
d1<-d1[order(d1$Onset),] ###sort by time
##Start
start1<-NA #Lights on
start2<-NA #Wake/sleep
start3<-NA #30 s before 1st event
start<-NA
s1<-which(d1$T2==51)
if(length(s1)==1) {
start1<-d1$Onset[s1]
starty<-1
}
if(length(s1)>1){
start1<-d1$Onset[s1[length(s1)]]
message("!!!\t More than one start/lights off signal found,\n\t the latest one will be considered !!!\n")
}
s2<-which(d1$T==1)
if(length(s2)>0){
start2<-d1$Onset[s2[1]]
}
#if not lights off signal and no sleep scoring
if(is.na(start1) & is.na(start2)){
start3<-d1$Onset[!is.na(d1$T)][1]-30
start<-start3
message("!!!\t No start/lights off signal or sleep scoring found/defined,\n\t it will be assumed that the recording started 30s before\n\t the first found event (LM, arousal, respiratory event) !!!\n")
}
#if scoring starts after start, take scoring as start
if(is.na(start1) & !is.na(start2)){
message("!!!\tNo start/lights off signal found, it will be assumed that recording started with first scored wake/sleep epoch")
start<-start2
}
if(is.na(start2) & !is.na(start1)) start<-start1
if(!is.na(start1) & !is.na(start2)){
if(start1<start2) {
start<-start2
message("!!!\t Scoring started after start/lights off signal,\n\t the first wake/sleep epoch present will be considered !!!\n")
}
if(start1>=start2) {
start<-start1
message("!!!\t Scoring started before start/lights off signal,\n\t the start/lights off signal present will be considered !!!\n")
}
}
##stop
stop1<-NA
stop2<-NA
stop3<-NA
stop<-NA
st1<-which(d1$T2==52)
if(length(st1)==1) {
stop1<-d1$Onset[st1]
}
if(length(st1)>1){
stop1<-d1$Onset[st1[length(st1)]]
message("!!!\t More than one stop/lights on signal found,\n\t the latest one will be considered !!!\n")
}
st2<-which(d1$T==1)
if(length(st2)>0){
stop2<-d1$Onset[st2[length(st2)]]+d1$Dur[st2[length(st2)]]
#message("!!!\t No stop/lights on signal found/defined,\n\t the last wake/sleep epoch present will be considered !!!\n")
}
if(is.na(stop1) & is.na(stop2)){
stop<-d1$Onset[!is.na(d1$Onset)][length(d1$Onset[!is.na(d1$Onset)])]+d1$Dur[!is.na(d1$Onset)][length(d1$Onset[!is.na(d1$Onset)])]+30
message("!!!\t No stop/lights on signal or sleep scoring found/defined,\n\t it will be assumed that the recording stopped 30s after\n\t the last found event (LM, arousal, respiratory event) !!!\n")
}
#if scoring stops after stop, take scoring as start
if(is.na(stop1) & !is.na(stop2)){
message("!!!\tNo stop/lights on signal found, it will be assumed that recording stopped with last scored wake/sleep epoch")
stop<-stop2
}
if(is.na(stop2) & !is.na(stop1)) stop<-stop1
if(!is.na(stop1) & !is.na(stop2)){
if(stop1>stop2) {
stop<-stop2
message("!!!\t Scoring stopped before stop/lights on signal,\n\t the last wake/sleep epoch present will be considered !!!\n")
}
if(stop1<=stop2) {
stop<-stop1
message("!!!\t Scoring stopped after stop/lights on signal,\n\t the stop/lights on signal present will be considered !!!\n")
}
}
####transform time to sec from start
d1$Onset<-d1$Onset-start
#Create new variable offset
d1$Offset<-d1$Onset+d1$Dur
####remove everything before start
d1<-d1[(is.na(d1$Offset) & d1$Onset>=0) | (!is.na(d1$Offset) & d1$Offset>=0),]
####remove everything after stop
d1<-d1[d1$Onset<=(stop-start),]
####if sleep is scored and start/stop is within an epoch of sleep change respective on/offset
h1<-which(d1$Onset<0 & d1$Offset>0 & d1$T==1)
if(length(h1)==1) {d1$Onset[h1]<-0; d1$Dur[h1]<-d1$Offset[h1]-d1$Onset[h1]}
h2<-which(d1$Onset<stop-start & d1$Offset>stop-start & d1$T==1)
if(length(h2)==1) {d1$Offset[h2]<-stop-start; d1$Dur[h2]<-d1$Offset[h2]-d1$Onset[h2]}
####if no sleep scored add wake for complete period
d1<-d1[order(d1$Onset),]
h5<-which(d1$T==1)
if(length(h5)<1){
d1<-rbind(d1, rep(NA, 24))
d1$T[dim(d1)[1]]<-1; d1$T2[dim(d1)[1]]<-0;
d1$Onset[dim(d1)[1]]<-0;
d1$Offset[dim(d1)[1]]<-stop-start
d1$Dur[dim(d1)[1]]<-stop-start
d1<-d1[order(d1$Onset),]
}
##housekeeping
row.has.na <- rowSums(!is.na(d1))
if(length(which(row.has.na==0))>0) d1<-d1[-which(row.has.na==0),]
return(d1)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.