package ua.stu.scplib.attribute; import java.io.IOException; import ua.stu.scplib.structure.SCPECG; import ua.stu.scplib.structure.Section3; /** * <p>A class that encapsulates the features and values from an SCP ECG source, * usually for the purpose of displaying it.</p> * * @author dclunie */ public class GraphicAttribute extends GraphicAttributeBase { /***/ //private static final String identString = "@(#) $Header: /userland/cvs/pixelmed/imgbook/com/pixelmed/displaywave/SCPSourceECG.java,v 1.7 2004/01/25 03:47:19 dclunie Exp $"; /** */ protected static String buildInstanceTitle(SCPECG scpecg) { StringBuffer buffer = new StringBuffer(); buffer.append(scpecg.getNamedField("LastName")); // NB. must not contain any embedded or trailing nulls buffer.append("^"); buffer.append(scpecg.getNamedField("FirstName")); buffer.append(" ["); buffer.append(scpecg.getNamedField("PatientIdentificationNumber")); buffer.append(" ] - "); buffer.append(scpecg.getNamedField("DateOfAcquisition")); buffer.append(" "); buffer.append(scpecg.getNamedField("TimeOfAcquisition")); buffer.append(" ["); buffer.append(scpecg.getNamedField("ECGSequenceNumber")); buffer.append("]"); return buffer.toString(); } /** * <p>Find the named lead in an array of SCP lead codes.</p> * * @param leadNumbers an array of the SCP codes used to designate leads * @param leadName the string name of the lead wanted * @return the index in leadNumbers of the requested lead if present, else -1 */ static private int findLead(int[] leadNumbers,String leadName) { int scpLeadNumber = Section3.getLeadNumber(leadName); for (int i=0; i<leadNumbers.length; ++i) { if (leadNumbers[i] == scpLeadNumber) { return i; } } return -1; } /** * <p>Derive additional unipolar leads if possible and necessary.</p> * * <p>Will replace values of samples, numberOfChannels, amplitudeScalingFactorInMilliVolts and channelNames * with longer arrays including the new channels.</p> * * @param leadNumbers an array of the SCP codes used to designate leads in the present SCPECG instance */ private void deriveAdditionalUnipolarLeads(int[] leadNumbers) { // could hard-code SCPECG numbers, or do string comparison against // lead names, but allow for the possibility that the lead names // in this.getLeadNames() may not be reliable, and depend on // leadNumbers, which is directly from the SCPECG dataset int indexOfLeadI = findLead(leadNumbers,"I"); int indexOfLeadII = findLead(leadNumbers,"II"); int indexOfLeadIII = findLead(leadNumbers,"III"); int indexOfLeadAVR = findLead(leadNumbers,"aVR"); int indexOfLeadAVL = findLead(leadNumbers,"aVL"); int indexOfLeadAVF = findLead(leadNumbers,"aVF"); if (indexOfLeadI >= 0 && indexOfLeadII >= 0 && indexOfLeadIII < 0 && indexOfLeadAVR < 0 && indexOfLeadAVL < 0 && indexOfLeadAVF < 0) { // derive everything from leads I and II // sanity check first ... int nSamples = samples[indexOfLeadI].length; float scalingFactor = amplitudeScalingFactorInMilliVolts[indexOfLeadI]; if (nSamples == samples[indexOfLeadII].length && scalingFactor == amplitudeScalingFactorInMilliVolts[indexOfLeadII]) { int nextIndex = numberOfChannels; numberOfChannels+=4; samples = ArrayCopyUtilities.expandArray(samples,4); amplitudeScalingFactorInMilliVolts = ArrayCopyUtilities.expandArray(amplitudeScalingFactorInMilliVolts,4); channelNames = ArrayCopyUtilities.expandArray(channelNames,4); for (int i=nextIndex; i<numberOfChannels; ++i) { amplitudeScalingFactorInMilliVolts[i] = scalingFactor; samples[i] = new short[nSamples]; } indexOfLeadIII = nextIndex++; indexOfLeadAVR = nextIndex++; indexOfLeadAVL = nextIndex++; indexOfLeadAVF = nextIndex; channelNames[indexOfLeadIII]="III"; channelNames[indexOfLeadAVR]="aVR"; channelNames[indexOfLeadAVL]="aVL"; channelNames[indexOfLeadAVF]="aVF"; for (int sample=0; sample<nSamples; ++sample) { int leadI = samples [indexOfLeadI][sample]; int leadII = samples[indexOfLeadII][sample]; int leadIII = leadII - leadI; samples[indexOfLeadIII][sample] = (short)(leadIII); samples[indexOfLeadAVR][sample] = (short)(-(leadI + leadII )/2); samples[indexOfLeadAVL][sample] = (short)( (leadI - leadIII)/2); samples[indexOfLeadAVF][sample] = (short)( (leadII + leadIII)/2); } } } } /** * <p>Construct an ECG source from SCP-ECG data an input stream (such as from a file or the network).</p> * * @param i the input stream * @param deriveAdditionalLeads if true, compute extra unipolar leads when necessary (i.e. make 12 from 8) * @exception IOException */ public GraphicAttribute(BinaryInputStream i,boolean deriveAdditionalLeads) throws IOException { super(); SCPECG scpecg = new SCPECG(i,false/*verbose*/); if(scpecg.getSection2()==null) flNonsection2=true; doCommonConstructorStuff(scpecg,deriveAdditionalLeads); } /** * <p>Construct an ECG source from an SCP-ECG instance.</p> * * @param scpecg the input stream * @param deriveAdditionalLeads if true, compute extra unipolar leads when necessary (i.e. make 12 from 8) * @exception IOException */ public GraphicAttribute(SCPECG scpecg,boolean deriveAdditionalLeads) throws IOException { super(); doCommonConstructorStuff(scpecg,deriveAdditionalLeads); } private void doCommonConstructorStuff(SCPECG scpecg,boolean deriveAdditionalLeads) { samples = scpecg.getDecompressedRhythmData(); numberOfChannels = scpecg.getNumberOfLeads(); nSamplesPerChannel = (int)(scpecg.getNumbersOfSamples()[0]); // assume all the same, and fits in int :( samplingIntervalInMilliSeconds=scpecg.getDecompressedRhythmDataSampleTimeInterval()/1000; // SCP ECG values is in microseconds amplitudeScalingFactorInMilliVolts = new float[numberOfChannels]; for (int channel=0; channel<numberOfChannels; ++channel) { amplitudeScalingFactorInMilliVolts[channel] = (float)0.001; // SCP ECG decompressed samples are in microvolts } channelNames = scpecg.getLeadNames(); if (deriveAdditionalLeads) { deriveAdditionalUnipolarLeads(scpecg.getLeadNumbers()); } buildPreferredDisplaySequence(channelNames); title=buildInstanceTitle(scpecg); } }