private static void PreprocessParsedWaveforms(XElement root, Version schemaVersion) { // Retrieve parsedwaveforms element and check if the data is encoded var parsedWaveforms = root.Descendants(XEParsedWaveforms) .SingleOrDefault(); if (parsedWaveforms != null) { object decoded = null; //SierraECGSchema_1_04_01: // @dataencoding: how the data is encoded: eg., "Base64". // Use "Plain" for sample values in ascii: "10 20 35...." . var encoding = (string)parsedWaveforms.Attribute("dataencoding"); switch (encoding) { case "Plain": decoded = parsedWaveforms.Value; break; case "Base64": decoded = Convert.FromBase64String(parsedWaveforms.Value); parsedWaveforms.SetAttributeValue("dataencoding", "Plain"); break; default: // no can decode boss man throw new InvalidOperationException("Unknown data encoding: " + encoding); } bool isCompressed; string compression; if (schemaVersion < new Version("1.04")) { isCompressed = (bool)parsedWaveforms.Attribute("compressflag"); compression = (string)parsedWaveforms.Attribute("compressmethod"); } else { compression = (string)parsedWaveforms.Attribute("compression"); isCompressed = compression == "XLI"; } if (isCompressed) { var signalCharacteristics = root.Element(ns + "dataacquisition") .Element(ns + "signalcharacteristics"); var leadsUsed = (string)signalCharacteristics.Element(ns + "acquisitiontype"); var goodChannels = (int)signalCharacteristics.Element(ns + "numberchannelsallocated"); if (compression == "XLI" && decoded is byte[]) { List <DecodedLead> leads; using (var xli = new XliDecompressor((byte[])decoded)) { var decodedData = new List <int[]>(); int[] payload; while (null != (payload = xli.ReadLeadPayload())) { decodedData.Add(payload); // the DXL algorithm can interpret 16 channels, so often all 16 // will be in the file, but the last 4 will be 0's besides // their calibration marks at the end. This is a quick check to skip // what we don't care about. if (decodedData.Count >= goodChannels) { break; } } leads = DecodedLead.ReinterpretLeads(leadsUsed, decodedData).ToList(); } if (schemaVersion < new Version("1.04")) { // CAW: "False" must be used as the "false" is not recognized by many of the tools parsedWaveforms.SetAttributeValue("compressflag", "False"); } else { //SierraECGSchema_1_04_01: // @compression: name the type of compression if the data is compressed // (e.g., "XLI" for standard Philips cardiograph compression; if not compressed, omit this attribute). parsedWaveforms.SetAttributeValue("compression", null); } // CAW: the default is 25 data points per line decoded = String.Join( Environment.NewLine, leads.SelectMany( lead => lead.Select((vv, ix) => new { I = ix, V = vv }) .GroupBy(xx => xx.I / 25) .Select(gg => String.Join(" ", gg.Select(xx => xx.V))))); } else { // no can decompress boss man throw new InvalidOperationException("Unknown compression method: " + compression); } } // handle the case where we've decoded Base64 only data if (decoded is byte[]) { var bytes = (byte[])decoded; var lead = new short[bytes.Length / 2]; Buffer.BlockCopy(bytes, 0, lead, 0, bytes.Length); decoded = String.Join( Environment.NewLine, lead.Select((vv, ix) => new { I = ix, V = vv }) .GroupBy(xx => xx.I / 25) .Select(gg => String.Join(" ", gg.Select(xx => xx.V)))); } parsedWaveforms.SetValue(decoded); } }
private static DecodedLead[] ExtractLeads(XElement root) { Debug.Assert(root != null); // Retrieve parsedwaveforms element and check if the data is encoded var parsedWaveforms = root.Descendants(XEParsedWaveforms) .SingleOrDefault(); if (parsedWaveforms != null) { var signalCharacteristics = root.Element(ns + "dataacquisition") .Element(ns + "signalcharacteristics"); var leadsUsed = (string)signalCharacteristics.Element(ns + "acquisitiontype"); var goodChannels = (int)signalCharacteristics.Element(ns + "numberchannelsallocated"); var sampleRate = (int)signalCharacteristics.Element(ns + "samplerate"); var duration = (int)parsedWaveforms.Element(ns + "durationperchannel"); var samples = duration * (sampleRate / 1000); object decoded = null; var encoding = (string)parsedWaveforms.Attribute("dataencoding"); switch (encoding) { case "Plain": return(parsedWaveforms.Value .Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select((vv, ix) => new { I = ix, V = Int32.Parse(vv) }) .GroupBy(xx => xx.I / samples) .Select(gg => new DecodedLead(gg.Key + 1, gg.Select(xx => xx.V).ToArray())) .ToArray()); case "Base64": decoded = Convert.FromBase64String(parsedWaveforms.Value); break; default: // no can decode boss man throw new InvalidOperationException("Unknown data encoding: " + encoding); } var isCompressed = (bool)parsedWaveforms.Attribute("compressflag"); var compression = (string)parsedWaveforms.Attribute("compressmethod"); if (isCompressed) { if (compression == "XLI" && decoded is byte[]) { using (var xli = new XliDecompressor((byte[])decoded)) { var decodedData = new List <int[]>(); int[] payload; while (null != (payload = xli.ReadLeadPayload())) { decodedData.Add(payload); // the DXL algorithm can interpret 16 channels, so often all 16 // will be in the file, but the last 4 will be 0's besides // their calibration marks at the end. This is a quick check to skip // what we don't care about. if (decodedData.Count >= goodChannels) { break; } } return(DecodedLead.ReinterpretLeads(leadsUsed, decodedData).ToArray()); } } else { // no can decompress boss man throw new InvalidOperationException("Unknown compression method: " + compression); } } // handle the case where we've decoded Base64 only data if (decoded is byte[]) { var bytes = (byte[])decoded; var leads = new List <DecodedLead>(); for (int offset = 0, lead = 0; offset < bytes.Length; offset += samples * 2) { var data = new short[samples]; Buffer.BlockCopy(bytes, offset, data, 0, samples * 2); leads.Add(new DecodedLead(++lead, data.Select(dd => (int)dd).ToArray())); } return(leads.ToArray()); } } throw new NotSupportedException("For whatever reason this format was not supported"); }