Diff of /ppfunctions_1.py [000000] .. [a007e7]

Switch to unified view

a b/ppfunctions_1.py
1
# -*- coding: utf-8 -*-
2
"""
3
Personal Processing Functions 1 (ppfunctions_1)
4
Created on Mon Apr  9 11:48:37 2018
5
@author: Kevin MAchado
6
7
Module file containing Python definitions and statements
8
"""
9
10
# Libraries
11
import numpy as np
12
from scipy.signal import kaiserord, lfilter, firwin
13
from scipy.fftpack import fft
14
#import peakutils                                # Librery to help in peak detection
15
16
# Functions 
17
# Normal energy = np.sum(pcgFFT1**2)
18
# Normalized average Shannon Energy = sum((l**2)*np.log(l**2))/l.shape[0]
19
# Third Order Shannon Energy = sum((l**3)*np.log(l**3))/l.shape[0]
20
21
def vec_nor(x):
22
    """
23
    Normalize the amplitude of a vector from -1 to 1
24
    """
25
    lenght=np.size(x)               # Get the length of the vector  
26
    xMax=max(x);                       # Get the maximun value of the vector
27
    nVec=np.zeros(lenght);         # Initializate derivate vector
28
    nVec = np.divide(x, xMax)
29
    nVec=nVec-np.mean(nVec);
30
    nVec=np.divide(nVec,np.max(nVec));
31
        
32
    return nVec
33
34
def derivate (x):
35
    """
36
    Derivate of an input signal as y[n]= x[n+1]- x[n-1] 
37
    """
38
    lenght=x.shape[0]               # Get the length of the vector
39
    y=np.zeros(lenght);             # Initializate derivate vector
40
    for i in range(lenght-1):
41
        y[i]=x[i-1]-x[i];       
42
    return y
43
# -----------------------------------------------------------------------------
44
# Energy
45
# -----------------------------------------------------------------------------
46
def Energy_value (x):
47
    """
48
    Energy of an input signal  
49
    """
50
    y = np.sum(x**2)
51
    return y
52
53
def E_VS (pcgFFT1, vTfft1, on):
54
    """
55
    Energy of PCG Vibratory Spectrum
56
    (frequency components, frequency value vector, on = on percentage or not)
57
    According with [1] The total vibratory spectrum can be divided into 7 bands:
58
    1. 0-5Hz, 2. 5-25Hz; 3. 25-120Hz; 4. 120-240Hz; 5. 240-500Hz; 6. 500-1000Hz; 7. 1000-2000Hz
59
60
The PCG signal producess vibrations in the spectrum between 0-2k Hz. 
61
[1] Abbas, Abbas K. (Abbas Khudair), Bassam, Rasha and Morgan & Claypool Publishers Phonocardiography signal processing. Morgan & Claypool Publishers, San Rafael, Calif, 2009.
62
    """
63
    c1 = (np.abs(vTfft1-5)).argmin()
64
    c2 = (np.abs(vTfft1-25)).argmin()
65
    c3 = (np.abs(vTfft1-120)).argmin()
66
    c4 = (np.abs(vTfft1-240)).argmin()
67
    c5 = (np.abs(vTfft1-500)).argmin()
68
    c6 = (np.abs(vTfft1-1000)).argmin()
69
    c7 = (np.abs(vTfft1-2000)).argmin()
70
    
71
    # All vector energy
72
    xAll = Energy_value(pcgFFT1)
73
74
    # Procesando de 0.01-5 Hz
75
    pcgFFT_F1 = pcgFFT1[0:c1]
76
    x1 = Energy_value(pcgFFT_F1)
77
    
78
    # Procesando de 5-25 Hz
79
    pcgFFT_F2 = pcgFFT1[c1:c2]
80
    x2 = Energy_value(pcgFFT_F2)
81
    
82
    # Procesando de 25-120 Hz
83
    pcgFFT_F3 = pcgFFT1[c2:c3]
84
    x3 = Energy_value(pcgFFT_F3)
85
    
86
    # Procesando de 120-240 Hz
87
    pcgFFT_F4 = pcgFFT1[c3:c4]
88
    x4 = Energy_value(pcgFFT_F4)
89
    
90
    # Procesando de 240-500 Hz
91
    pcgFFT_F5 = pcgFFT1[c4:c5]
92
    x5 = Energy_value(pcgFFT_F5)
93
    
94
    # Procesando de 500-1000 Hz
95
    pcgFFT_F6 = pcgFFT1[c5:c6]
96
    x6 = Energy_value(pcgFFT_F6)
97
    
98
    # Procesando de 1000-2000 Hz
99
    pcgFFT_F7 = pcgFFT1[c6:c7]
100
    x7 = Energy_value(pcgFFT_F7)
101
    
102
    x = np.array([xAll, x1, x2, x3, x4, x5, x6, x7])
103
    
104
    if (on == 'percentage'):
105
        x = 100*(x/x[0])
106
107
    return x 
108
109
def shannonE_value (x):
110
    """
111
    Shannon energy of an input signal  
112
    """
113
    y = sum((x**2)*np.log(x**2))/x.shape[0]
114
    return y
115
116
def shannonE_vector (x):
117
    """
118
    Shannon energy of an input signal  
119
    """
120
    mu = -(x**2)*np.log(x**2)/x.shape[0]
121
    y = -(((x**2)*np.log(x**2)) - mu)/np.std(x)
122
    return y
123
124
# -----------------------------------------------------------------------------
125
# Filter Processes
126
# -----------------------------------------------------------------------------
127
def Fpass(X,lp):
128
    """
129
    Fpass is the function to pass the coefficients of a filter trough a signal'
130
    """
131
    llp=np.size(lp)             # Get the length of the lowpass vector      
132
133
    x=np.convolve(X,lp);                # Disrete convolution 
134
    x=x[int(llp/2):-int(llp/2)];
135
    x=x-(np.mean(x));
136
    x=x/np.max(x);
137
    
138
    y=vec_nor(x);               # Vector Normalizing
139
        
140
    return y
141
142
def FpassBand(X,hp,lp):
143
    """
144
    FpassBand is the function that develop a pass band filter of the signal 'x' through the
145
    discrete convolution of this 'x' first with the coeficients of a High Pass Filter 'hp' and then
146
    with the discrete convolution of this result with a Low Pass Filter 'lp'
147
    """
148
    llp=np.shape(lp)                # Get the length of the lowpass vector      
149
    llp=llp[0];                    # Get the value of the length
150
    lhp=np.shape(hp)                # Get the length of the highpass vector     
151
    lhp=lhp[0];                    # Get the value of the length    
152
153
    x=np.convolve(X,lp);                # Disrete convolution 
154
    x=x[int(llp/2):-int(llp/2)];
155
    x=x-(np.mean(x));
156
    x=x/np.max(x);
157
    
158
    y=np.convolve(x,hp);            # Disrete onvolution
159
    y=y[int(lhp/2):-int(lhp/2)];
160
    y=y-np.mean(y);
161
    y=y/np.max(y);
162
163
    x=np.convolve(y,lp);                # Disrete convolution 
164
    x=x[int(llp/2):-int(llp/2)];
165
    x=x-(np.mean(x));
166
    x=x/np.max(x);
167
    
168
    y=np.convolve(x,hp);            # Disrete onvolution
169
    y=y[int(lhp/2):-int(lhp/2)];
170
    y=y-np.mean(y);
171
    y=y/np.max(y);
172
        
173
    y=vec_nor(y);               # Vector Normalizing
174
        
175
    return y
176
177
def FpassBand_1(X,Fs,H_cutoff_hz, L_cutoff_hz):
178
    """
179
    Ref: http://scipy-cookbook.readthedocs.io/items/FIRFilter.html
180
    http://lagrange.univ-lyon1.fr/docs/scipy/0.17.1/generated/scipy.signal.firwin.html
181
    FpassBand_1 is a function to develop a passband filter using 'firwin'
182
    and 'lfilter' functions from the "Scipy" library
183
    """
184
185
    # The Nyquist rate of the signal.
186
    nyq_rate = Fs / 2.0
187
    # The desired width of the transition from pass to stop,
188
    # relative to the Nyquist rate.  We'll design the filter
189
    # with a 5 Hz transition width.
190
    width = 5.0/nyq_rate
191
    # The desired attenuation in the stop band, in dB.
192
    ripple_db = 60.0
193
    # Compute the order and Kaiser parameter for the FIR filter.
194
    N, beta = kaiserord(ripple_db, width)
195
    # Use firwin with a Kaiser window to create a lowpass FIR filter.
196
    taps = firwin(N, L_cutoff_hz/nyq_rate, window=('kaiser', beta))
197
    taps_2 = firwin(N, H_cutoff_hz/nyq_rate, pass_zero=False)
198
    # Use lfilter to filter x with the FIR filter.
199
    X_l= lfilter(taps, 1.0, X)
200
    X_pb= lfilter(taps_2, 1.0, X_l)
201
    
202
    return X_pb[N-1:]
203
204
def FhighPass(X, Fs, H_cutoff_hz):
205
    """
206
    Ref: http://scipy-cookbook.readthedocs.io/items/FIRFilter.html
207
    http://lagrange.univ-lyon1.fr/docs/scipy/0.17.1/generated/scipy.signal.firwin.html
208
    FhighPass is a function to develop a highpass filter using 'firwin'
209
    and 'lfilter' functions from the "Scipy" library
210
    """
211
    # The Nyquist rate of the signal.
212
    nyq_rate = Fs / 2.0
213
    # The desired width of the transition from pass to stop,
214
    # relative to the Nyquist rate.  We'll design the filter
215
    # with a 5 Hz transition width.
216
    width = 5.0/nyq_rate
217
    # The desired attenuation in the stop band, in dB.
218
    ripple_db = 60.0
219
    # Compute the order and Kaiser parameter for the FIR filter.
220
    N, beta = kaiserord(ripple_db, width)
221
    # Use firwin with a Kaiser window to create a lowpass FIR filter.
222
    taps_2 = firwin(N, H_cutoff_hz/nyq_rate, pass_zero=False)
223
    # Use lfilter to filter x with the FIR filter.
224
    X_h= lfilter(taps_2, 1.0, X)
225
    
226
    return X_h[N-1:]
227
    
228
def FlowPass(X, Fs, L_cutoff_hz):
229
    """
230
    Ref: http://scipy-cookbook.readthedocs.io/items/FIRFilter.html
231
    http://lagrange.univ-lyon1.fr/docs/scipy/0.17.1/generated/scipy.signal.firwin.html
232
    FlowPass is a function to develop a lowpass filter using 'firwin'
233
    and 'lfilter' functions from the "Scipy" library
234
    """
235
    # The Nyquist rate of the signal.
236
    nyq_rate = Fs / 2.0
237
    # The desired width of the transition from pass to stop,
238
    # relative to the Nyquist rate.  We'll design the filter
239
    # with a 5 Hz transition width.
240
    width = 5.0/nyq_rate
241
    # The desired attenuation in the stop band, in dB.
242
    ripple_db = 60.0
243
    # Compute the order and Kaiser parameter for the FIR filter.
244
    N, beta = kaiserord(ripple_db, width)
245
    # Use firwin with a Kaiser window to create a lowpass FIR filter.
246
    taps = firwin(N, L_cutoff_hz/nyq_rate, window=('kaiser', beta))
247
    # Use lfilter to filter x with the FIR filter.
248
    X_l= lfilter(taps, 1.0, X)
249
    
250
    return X_l[N-1:]
251
# -----------------------------------------------------------------------------
252
# Peak Detection
253
# -----------------------------------------------------------------------------
254
def PDP(Xf, samplerate):
255
    """
256
    Peak Detection Process
257
    """
258
    timeCut = samplerate*0.25                       # time to count another pulse
259
    vCorte = 0.6
260
    
261
    Xf = vec_nor(Xf)
262
    dX=derivate(Xf);                                      # Derivate of the signal
263
    dX=vec_nor(dX);                                  # Vector Normalizing
264
    
265
    size=np.shape(Xf)                                 # Rank or dimension of the array
266
    fil=size[0];                                         # Number of rows
267
 
268
    positive=np.zeros((1,fil+1));                   # Initializating Vector 
269
    positive=positive[0];                           # Getting the Vector
270
271
    points=np.zeros((1,fil));                       # Initializating the Peak Points Vector
272
    points=points[0];                               # Getting the point vector
273
274
    points1=np.zeros((1,fil));                      # Initializating the Peak Points Vector
275
    points1=points1[0];                             # Getting the point vector
276
    
277
    vCorte = 0.6
278
       
279
    '''
280
    FIRST! having the positives values of the slope as 1
281
    And the negative values of the slope as 0
282
    '''
283
    for i in range(0,fil):
284
        if dX[i]>0:
285
            positive[i]=1;
286
        else:
287
            positive[i]=0;
288
    '''
289
    SECOND! a peak will be found when the ith value is equal to 1 &&
290
    the ith+1 is equal to 0
291
    '''
292
    for i in range(0,fil):
293
        if (positive[i]==1 and positive[i+1]==0):
294
            points[i]=Xf[i];
295
        else:
296
            points[i]=0;
297
    '''
298
    THIRD! Define a minimun Peak Height
299
    '''
300
    p=0;
301
    for i in range(0,fil):
302
        if (points[i] > vCorte and p==0):
303
            p=i
304
            points1[i]=Xf[i]
305
            
306
        else:
307
            points1[i]=0;
308
            if (p+timeCut < i):
309
                p=0
310
                    
311
    return points1
312
# -----------------------------------------------------------------------------
313
# Fast Fourier Transform
314
# -----------------------------------------------------------------------------
315
def fft_k(data, samplerate, showFrequency):
316
    '''
317
    Fast Fourier Transform
318
    Ref: https://docs.scipy.org/doc/scipy/reference/tutorial/fftpack.html
319
    '''
320
    pcgFFT = fft(data)                                                    # FFT Full Vector
321
    short_pcgFFT = 2.0/np.size(data) * np.abs(pcgFFT[0:np.size(data)//2]) # FFT positives values
322
    vTfft = np.linspace(0.0, 1.0/(2.0*(1/samplerate)), np.size(data)//2)  # Vector of frequencies (X-axes)
323
       
324
    idx = (np.abs(vTfft-showFrequency)).argmin()             # find the value closest to a value
325
    
326
    return short_pcgFFT[0:idx], vTfft[0:idx]
327
328
def fft_k_N(data, samplerate, showFrequency):
329
    '''
330
    Normalized Fast Fourier Transform
331
    Ref: https://docs.scipy.org/doc/scipy/reference/tutorial/fftpack.html
332
    '''
333
    pcgFFT = fft(data)                                                    # FFT Full Vector
334
    short_pcgFFT = 2.0/np.size(data) * np.abs(pcgFFT[0:np.size(data)//2]) # FFT positives values
335
    vTfft = np.linspace(0.0, 1.0/(2.0*(1/samplerate)), np.size(data)//2)  # Vector of frequencies (X-axes)
336
       
337
    idx = (np.abs(vTfft-showFrequency)).argmin()             # find the value closest to a value
338
    
339
    return vec_nor(short_pcgFFT[0:idx]), vTfft[0:idx]