Development of a software tool for processing phonocardiogram data
17. Elsukov D.A. Python – Programming language // Economy and Society. 2021. No. 11-1 (90). P. 982–985.
APPENDIX A
from matplotlib import pyplot
from numpy import median, short, mean, sqrt, var
import os
class Tone(object):
def __init__(self,left,right,peak):
self.LeftPoint = left
self.RightPoint = right
self.Peak = peak
# KAA: Нормализуем значение.
def normalize(x,avg):
shift = x - avg
if shift >= 0:
return shift
else :
return -shift
def cutOff(x, threshold):
if x >= threshold:
return x
else :
return 0
#находим левые и правые края по следующим условиям
# для левого края - слева определенное кол-во точек равны медианному, а следующая точка отличается
# для правого края - справа определенное кол-во точек равны медианному, а предыдущая точка отличается
def findEdges(array,avg,threshold):
LeftEdges = []
RightEdges = []
for i in range(threshold,len(array)-threshold):
if isLeftStraight(array,avg,i,threshold) and array[i+1] != avg:
LeftEdges.append(i)
if isRightStraight(array,avg,i,threshold) and array[i-1] != avg:
RightEdges.append(i)
return LeftEdges,RightEdges
#находим левые и правые края по следующим условиям
# для левого края - слева определенное кол-во точек равны 0, а следующая точка отличается
# для правого края - справа определенное кол-во точек равны 0, а предыдущая точка отличается
def findEdgesNormal(array, threshold):
LeftEdges = []
RightEdges = []
for i in range(threshold,len(array)-threshold):
if isLeftStraight(array,0,i,threshold) and array[i+1] != 0:
LeftEdges.append(i)
if isRightStraight(array,0,i,threshold) and array[i-1] != 0:
RightEdges.append(i)
return LeftEdges,RightEdges
def isLeftStraight(array,avg,index,threshold):
isleftStr = True
for i in range(threshold):
isleftStr = isleftStr and array[index-i] == avg
if not isleftStr:
return False
return isleftStr;
def isRightStraight(array,avg,index,threshold):
isrightStr = True
for i in range(threshold):
isrightStr = isrightStr and array[index+i] == avg
if not isrightStr:
return False
return isrightStr;
#находим индекс максимального значения в определенном промежутке
def findPeakIndex(array, start, end):
interval = array[start:end]
maxValue = max(interval)
return array.index(maxValue,start-1,end+1)
# оставляем только 1 тон
def first_tone(array, first_tones):
b= []
c = []
def split(arr, size):
arrs = []
while len(arr) > size:
pice = arr[:size]
arrs.append(pice)
arr = arr[size:]
arrs.append(arr)
return arrs
first_tones = split(first_tones, 3)
for i in range(1, len(first_tones)):
b.append(first_tones[i][0] - first_tones[i-1][2])
for i in range(1, len(first_tones)):
for j in range(1, len(b)):
if i == j:
if sum(array[first_tones[i][0]:first_tones[i][2]+1])>sum(array[first_tones[i-1][0]:first_tones[i-1][2]+1]) and b[j]<b[j-1]:
c.append(first_tones[i-1])
print(c)
return c
# собираем данные в класс Tone, упаковываем
def makeTones(leftEdges,rightEdges,minLenforTone):
tones = []
first_tones = []
if(rightEdges[0] < leftEdges[0]):# если у нас есть правый край, но у него нет парного левого края - удаляем его
rightEdges.pop(0)
if leftEdges[-1] > leftEdges[-1]: # если есть левый край, но нет парного правого - удаляем
leftEdges.pop(len(leftEdges)-1)
for i in range(min(len(leftEdges),len(rightEdges))): # для каждого левого и правого края создаем объект Tone, и в промежутке этих краев находим значение максимальной амплитуды
if(rightEdges[i] - leftEdges[i] > minLenforTone):
peak = findPeakIndex(array,leftEdges[i],rightEdges[i])
first_tones.append(leftEdges[i])
first_tones.append(peak)
first_tones.append(rightEdges[i])
first_tones = first_tone(array, first_tones)
for i in range(len(first_tones)):
tones.append(Tone(first_tones[i][0],first_tones[i][1],first_tones[i][2]))
return tones
# собираем данные в класс Tone, упаковываем
def makeTonesOld(leftEdges,rightEdges,minLenforTone):
tones = []
if(rightEdges[0] < leftEdges[0]):# если у нас есть правый край, но у него нет парного левого края - удаляем его
rightEdges.pop(0)
if leftEdges[-1] > leftEdges[-1]: # если есть левый край, но нет парного правого - удаляем
leftEdges.pop(len(leftEdges)-1)
for i in range(min(len(leftEdges),len(rightEdges))): # для каждого левого и правого края создаем объект Tone, и в промежутке этих краев находим значение максимальной амплитуды
if(rightEdges[i] - leftEdges[i] > minLenforTone):
peak = findPeakIndex(array,leftEdges[i],rightEdges[i])
tones.append(Tone(leftEdges[i],rightEdges[i],peak))
return tones
dir_name="C:\\Users\\Task\\"
test = os.listdir(dir_name)
test = list(test)
for i in test:
with open(dir_name+i, newline="") as data:
array = list(map(lambda x: int(x),data.read().split(";")))
#KAA:
med = mean(array)
threshold = 20 #сколько точек должны идти прямо, чтобы считаться началом или концом тона
toneMinLen = 5 #какая минимальная длина должна быть у реального тона(нужна чтобы отсечь фейковые всплески)
#KAA:
array = list(map(lambda x: normalize(x,med),array)) # нормализуем прочитанный массив
windowLength = 50
for idx in range(len(array)-windowLength): #усреднение по скользящему окну размера windowLength - убираем высокие частоты
array[idx] = sum(array[idx:idx+windowLength-1])/windowLength
maxVal = max(array)
med = mean(array)
st = sqrt(var(array)) # стандартное отклонение
cutoffValue = (med + st)/3.1 #уровень шумоподавления
array = list(map(lambda x: cutOff(x,cutoffValue),array)) # убираем фоновые шумы из нормализованного массива
LeftEdges, RightEdges = findEdgesNormal(array, threshold) # находим края
tones = makeTones(LeftEdges,RightEdges,toneMinLen) # по данным о краях создаем тоны
#рисуем основной график
pyplot.figure(figsize=(10,3))
pyplot.title(dir_name+i)
pyplot.plot(array,color="lightgray");
#добавляем вертикальные полосы, отображающие тон
pyplot.vlines(x=[l.LeftPoint for l in tones],color="green",ymin=0,ymax=cutoffValue) #начало тона
pyplot.vlines(x=[r.RightPoint for r in tones],color="red",ymin=0,ymax=cutoffValue) # конец тона
pyplot.vlines(x=[p.Peak for p in tones],color="blue",ymin=0,ymax = cutoffValue)# пик тона
pyplot.show()