static private List <ECGAnnotation> loadCustomAnnotations(String signalFileName, int channel) { if (!File.Exists(signalFileName)) { return(new List <ECGAnnotation>()); } FileStream fileStream = new FileStream(signalFileName, FileMode.Open); StreamReader streamReader = new StreamReader(fileStream); String line = streamReader.ReadLine(); List <ECGAnnotation> annotations = new List <ECGAnnotation>(); while (line != null) { List <String> list = line.Split(' ').ToList(); if (list[1] == channel.ToString()) { List <String> help = list.GetRange(3, list.Count - 3); ECGAnnotation annotation = new ECGAnnotation() { Type = (ANNOTATION_TYPE)Enum.Parse(typeof(ANNOTATION_TYPE), list[0].ToString()), TimeIndex = Convert.ToDouble(list[2]), Text = String.Join(" ", help) }; annotations.Add(annotation); } // read next line line = streamReader.ReadLine(); } streamReader.Close(); return(annotations); }
private void OnAnnotationInsertRequested(ECGAnnotation annotation) { if (annotationInsertRequested != null) { annotationInsertRequested(annotation); } }
private void OnAnnotationDeletionRequested(ECGAnnotation annotation) { if (annotationDeletionRequested != null) { annotationDeletionRequested(annotation); } }
private void Insert_Button_Click(object sender, RoutedEventArgs e) { ANNOTATION_TYPE selectedType = (ANNOTATION_TYPE)cb_annotationType.SelectedItem; String content = ""; if (selectedType == ANNOTATION_TYPE.PHYSIONET_STANDARD) { content = cb_standard_content.SelectedItem as String; } else { content = tb_content.Text; } String[] timestampStrings = tb_timestamp.Text.Split(':'); if (content.Length == 0) { MessageBox.Show("There must be some annotation content?"); } else if (timestampStrings.Length == 0 || timestampStrings.Length > 3) { MessageBox.Show("Timestamp must be specified correctly ([mm]:[ss]:msec)!"); } else { try { double[] timestampNumbers = timestampStrings.Select(timestampstring => { return(Double.Parse(timestampstring)); }).Reverse().ToArray(); // first milliseconds (divide by 1000) timestampNumbers[0] = timestampNumbers[0] / 1000; // second should be seconds, no division or multiplication neccessary // thrid should be minutes, multiply by 60 if (timestampNumbers.Length > 2) { timestampNumbers[2] = timestampNumbers[2] * 60; } // now sum for total seconds double timeIndex = 0; for (int i = 0; i < timestampNumbers.Length; i++) { timeIndex += timestampNumbers[i]; } ECGAnnotation annot = new ECGAnnotation() { Text = content, Type = selectedType, TimeIndex = timeIndex }; if (annot.Type == ANNOTATION_TYPE.PHYSIONET_STANDARD) { // set the MIT annotation specific values annot.Code = ECGAnnotation.getCodeFromStandardAnnotationText(annot.Text); annot.Aux = ""; } MessageBox.Show("Insertion successful!"); OnAnnotationInsertRequested(annot); } catch (Exception) { MessageBox.Show("Incorrect timestamp format!"); } } }
static private void saveStandardAnnotations(ECG ecg, String atrFileName) { int sampleTime = 0; int num = 0; int chan = 0; FileStream fs = new FileStream(atrFileName + ".atr", FileMode.Create); BinaryWriter writer = new BinaryWriter(fs); byte buf = Convert.ToByte(0x0); byte nul = Convert.ToByte(0x0); int previousSampleTime = 0; ecg.Annotations = ecg.Annotations.OrderBy(an => an.TimeIndex).ToList(); for (int i = 0; i < ecg.Annotations.Count; i++) { ECGAnnotation annotation = ecg.Annotations.ElementAt(i); if (annotation.Type == ANNOTATION_TYPE.PHYSIONET_STANDARD) { sampleTime = Convert.ToInt32(annotation.TimeIndex * Frequency) - previousSampleTime; previousSampleTime = Convert.ToInt32(annotation.TimeIndex * Frequency); buf = Convert.ToByte(sampleTime & 0xFF); writer.Write(buf); buf = Convert.ToByte(Convert.ToByte((annotation.Code << 2) & 0xFF) | (Convert.ToByte((sampleTime >> 8) & 0xFF) & 0x3)); writer.Write(buf); if (annotation.Aux != null && annotation.Aux.Length > 0) { buf = Convert.ToByte((annotation.Aux.Length + 1) & 0xFF); writer.Write(buf); buf = Convert.ToByte(Convert.ToByte((63 << 2) & 0xFF) | (Convert.ToByte(((annotation.Aux.Length + 1) >> 8) & 0xFF) & 0x3)); writer.Write(buf); // write down AUX for (int j = 0; j < annotation.Aux.Length; j++) { writer.Write(Convert.ToByte(annotation.Aux[j] & 0xFF)); } writer.Write(nul); // string termination... if (annotation.Aux.Length + 1 % 2 != 0) { writer.Write(nul); } } if (annotation.SubTyp != 0) { // write down SUB buf = Convert.ToByte(annotation.SubTyp & 0xFF); writer.Write(buf); buf = Convert.ToByte(Convert.ToByte((61 << 2) & 0xFF) | (Convert.ToByte((annotation.SubTyp >> 8) & 0xFF) & 0x3)); writer.Write(buf); } if ((ecg.Channel - 1) != chan) { chan = (ecg.Channel - 1); // write down new CHAN buf = Convert.ToByte(chan & 0xFF); writer.Write(buf); buf = Convert.ToByte(Convert.ToByte((62 << 2) & 0xFF) | (Convert.ToByte((chan >> 8) & 0xFF) & 0x3)); writer.Write(buf); } if (annotation.Num != num) { num = annotation.Num; // write down new NUM buf = Convert.ToByte(annotation.Num & 0xFF); writer.Write(buf); buf = Convert.ToByte(Convert.ToByte((60 << 2) & 0xFF) | (Convert.ToByte((annotation.Num >> 8) & 0xFF) & 0x3)); writer.Write(buf); } } } // write EOF writer.Write(nul); writer.Write(nul); writer.Close(); }
static private List <ECGAnnotation> loadStandardAnnotations(String atrFileName, int channelToLoad = 1) { List <ECGAnnotation> standardAnnotations = new List <ECGAnnotation>(); byte[] bytes = File.ReadAllBytes(atrFileName); int sampleTime = 0; int num = 0; int subtyp = 0; int chan = 0; bool increaseSampleTime = true; ECGAnnotation annotation = null; String aux = ""; for (int i = 0; i < bytes.Length; i += 2) { aux = ""; subtyp = 0; increaseSampleTime = true; int A = bytes[i + 1] >> 2; int I = (((bytes[i + 1] & 0x3) << 8) | bytes[i]); switch (A) { // SKIP case 59: if (I == 0) { // if I is 0, we should skip the next 4 bytes i += 4; } else { // otherwise we have to skip next I bytes i += I; } increaseSampleTime = false; break; // NUM case 60: num = I; annotation.Num = num; increaseSampleTime = false; break; // SUB case 61: subtyp = I; annotation.SubTyp = subtyp; increaseSampleTime = false; break; // CHAN case 62: chan = I; annotation.Chan = chan; increaseSampleTime = false; break; // AUX case 63: for (int j = 0; j < I; j++) { // next I bytes are the aux string letters. // since we are reading two bytes at a time in main for loop, the aux string starts at (i+1)+1 position hence the: i+2+offset formula char c = Convert.ToChar(bytes[i + 2 + j]); if (c == '\0') { continue; } aux += c; } // if I is odd, there is a null byte pad appended to make the byte count even, but the null byte is not included in the byte count represented by I i += I + (I % 2 == 0 ? 0 : 1); annotation.Aux = aux; increaseSampleTime = false; break; // EOF case 0: if (I == 0) { return(standardAnnotations); } break; } if (increaseSampleTime) { sampleTime += I; annotation = new ECGAnnotation(); annotation.Type = ANNOTATION_TYPE.PHYSIONET_STANDARD; annotation.TimeIndex = sampleTime * (1.0 / Frequency); annotation.Text = ECGAnnotation.getStandardAnnotationTextFromCode(A); annotation.Code = A; annotation.Aux = aux; annotation.Chan = chan; annotation.Num = num; annotation.SubTyp = subtyp; if (annotation.Chan == (channelToLoad - 1)) { standardAnnotations.Add(annotation); } } else { if (aux.Length > 0) { annotation.Text += " " + aux; } } } return(standardAnnotations); }
void annotationInsertWindow_annotationInsertRequested(ECGAnnotation annotation) { signal.Annotations.Add(annotation); ecgView.refresh(); }
void annotationDeleteWindow_annotationDeletionRequested(ECGAnnotation annotation) { signal.Annotations.Remove(annotation); ecgView.refresh(); }