def interpolate(self, start, end, method='linear', register=True): if (end + 1) > len(self.data) or start < 0 or (end + 1) < start: print('Invalid interval') return nIntervals = end - start if nIntervals < 1: return if method == 'linear': deltaY = (self.data[end] - self.data[start]) / nIntervals for i in range(nIntervals): self.data[start + i] = self.data[start] + deltaY * i # register operation if register: xmlElement = ETree.Element('interpolate') tools.ETaddElement(parent=xmlElement, tag='frameStart', text=str(start)) tools.ETaddElement(parent=xmlElement, tag='frameEnd', text=str(end)) tools.ETaddElement(parent=xmlElement, tag='method', text=str(method)) self.registerOperation(xmlElement)
def resample(self, newSampleRate, method='linear', register=True): xData = np.arange(self.nPoints) / self.samplingRate_Hz f = scipyInterpolate.interp1d(xData, self.data, kind=method, fill_value=(self.data[0], self.data[-1]), assume_sorted=True) xNew = np.arange(xData[0], xData[-1], 1.0 / newSampleRate) self.data = f(xNew) self.samplingRate_Hz = float(newSampleRate) self.nPoints = self.data.shape[0] # register operation if register: xmlElement = ETree.Element('resample') tools.ETaddElement(parent=xmlElement, tag='sampleRate', attribList=[['unit', 'Hz']], text=str(newSampleRate)) tools.ETaddElement(parent=xmlElement, tag='method', text=str(method)) self.registerOperation(xmlElement)
def cropInterval(self, start, end, register=True, RemoveSegment=False, segmentIndexes=None): # register operation if register: xmlElement = ETree.Element('cropInterval') tools.ETaddElement(parent=xmlElement, tag='frameStart', text=str(start)) tools.ETaddElement(parent=xmlElement, tag='frameEnd', text=str(end)) tools.ETaddElement(parent=xmlElement, tag='RemoveSegment', text=str(RemoveSegment)) tools.ETaddElement(parent=xmlElement, tag='segmentIndexes', text=str(segmentIndexes)) self.registerOperation(xmlElement) if RemoveSegment: if len(segmentIndexes) > 0: end = segmentIndexes[np.searchsorted(segmentIndexes, end)] start = segmentIndexes[np.searchsorted(segmentIndexes, start) - 1] if (end + 1) > len(self.data) or start < 0 or (end + 1) < start: print('Invalid interval') return self.data = np.delete(self.data, range(start, end + 1)) self.nPoints = self.data.shape[0]
def setUnit(self, newUnit, register=True): self.unit = newUnit # register operation if register: xmlElement = ETree.Element('setUnit') tools.ETaddElement(parent=xmlElement, tag='unit', text=newUnit) self.registerOperation(xmlElement)
def setLabel(self, newLabel, register=True): self.label = newLabel # register operation if register: xmlElement = ETree.Element('setLabel') tools.ETaddElement(parent=xmlElement, tag='label', text=newLabel) self.registerOperation(xmlElement)
def setType(self, newType, register=True): self.sigType = newType # register operation if register: xmlElement = ETree.Element('setType') tools.ETaddElement(parent=xmlElement, tag='type', text=newType) self.registerOperation(xmlElement)
def LPfilter(self, method='movingAverage', nTaps=5, order=3, register=True): if nTaps % 2 == 0: print('nTaps is even. Must be odd number. Canceling LPfilter...') return if method == 'movingAverage': self.data = scipySignal.filtfilt([ 1.0 / nTaps, ] * nTaps, [1.0], self.data) if method == 'median': self.data = scipySignal.medfilt(self.data, kernel_size=nTaps) if method == 'butterworth': fNyquist = self.samplingRate_Hz / 2.0 fc_Hz = 20 # in Hertz wc_norm = fc_Hz / fNyquist # must be normalized from 0 to 1, where 1 is the Nyquist frequency [b, a] = scipySignal.butter(N=order, Wn=wc_norm, btype='low', analog=False, output='ba') self.data = scipySignal.filtfilt(b, a, self.data) # register operation if register: xmlElement = ETree.Element('LPfilter') tools.ETaddElement(parent=xmlElement, tag='method', text=str(method)) if method == 'movingAverage' or method == 'median': tools.ETaddElement(parent=xmlElement, tag='Ntaps', text=str(nTaps)) if method == 'butterworth': tools.ETaddElement(parent=xmlElement, tag='order', text=str(order)) self.registerOperation(xmlElement)
def calibrate(self, valMax, valMin, method='percentile', segmentIndexes=None, register=True): if valMax <= valMin: return # print(segmentIndexes) [x1, x2] = self.yLimits(method=method, detrend=False, segmentIndexes=segmentIndexes) y2 = valMax y1 = valMin # linear interpolation ang_coef = (y2 - y1) / float(x2 - x1) self.data = ang_coef * (self.data - x1) + y1 # register operation if register: xmlElement = ETree.Element('calibrate') tools.ETaddElement(parent=xmlElement, tag='valMin', text=str(valMin)) tools.ETaddElement(parent=xmlElement, tag='valMax', text=str(valMax)) tools.ETaddElement(parent=xmlElement, tag='method', text=str(method)) tools.ETaddElement(parent=xmlElement, tag='segmentIndexes', text=str(segmentIndexes).replace(',', '')) self.registerOperation(xmlElement)
def registerOperation(self, xmlElement): """add channel information to the element and add to the XML tree""" tools.ETaddElement(parent=xmlElement, tag='channel', text=str(self.channel)) self.operationsXML.append(xmlElement)
def findPeaks(self, method='ampd', findPeaks=True, findValleys=False, register=False): peakIdx = None peakVal = None valleyIdx = None valleyVal = None if method.lower() == 'ampd': if findPeaks: peakIdx = ampdLib.ampdFast(self.data, 10, LSMlimit=0.2) fmax_bpm = 250 DeltaTMin = int( 60.0 / float(fmax_bpm) * self.samplingRate_Hz ) # number of samples that represents a frequency of 250bpm temp = [] for i in range(len(peakIdx) - 1): if peakIdx[i + 1] - peakIdx[i] > DeltaTMin: # 5 samples appart temp.append(peakIdx[i]) else: temp.append(max(peakIdx[i], peakIdx[i + 1])) peakIdx = temp if findValleys: valleyIdx = ampdLib.ampdFast(-self.data, 10, LSMlimit=0.1) if method.lower() == 'md': fmax_bpm = 250 sMax = np.percentile(self.data, 90.0) smph = np.percentile(self.data, 60.0) sMin = np.percentile(self.data, 10.0) prominence = (sMax - sMin) * 0.2 DeltaTMin = int( 60.0 / float(fmax_bpm) * self.samplingRate_Hz ) # number of samples that represents a frequency of 250bpm peakIdx = tools.detect_peaks(self.data, mph=smph, mpd=DeltaTMin, threshold=0, edge='rising', kpsh=False, MinPeakProminence=prominence, MinPeakProminenceSide='left', valley=False) if findValleys: valleyIdx = [] for i in peakIdx: cumulativeProminence = 0 idx = i dx = self.data[idx] - self.data[idx - 1] while idx >= 0 and (dx > 0 or cumulativeProminence < (sMax - sMin) * 0.5): cumulativeProminence += dx idx -= 1 dx = self.data[idx] - self.data[idx - 1] valleyIdx.append(idx) valleyIdx = np.array(valleyIdx) if not findPeaks: peakIdx = None if findPeaks: peakIdx = np.unique(peakIdx) # removes eventual repeated indexes if findValleys: valleyIdx = np.unique( valleyIdx) # removes eventual repeated indexes if findPeaks: peakVal = self.data[peakIdx] if findValleys: valleyVal = self.data[valleyIdx] # register operation if register: xmlElement = ETree.Element('findPeaksSignal') tools.ETaddElement(parent=xmlElement, tag='findPeaks', text=str(findPeaks)) tools.ETaddElement(parent=xmlElement, tag='findValleys', text=str(findValleys)) tools.ETaddElement(parent=xmlElement, tag='method', text=method) self.registerOperation(xmlElement) return [peakIdx, peakVal, valleyIdx, valleyVal]