Wavelet analysis of the blood pressure and pulse frequency measuements with Maple
© -2013, Prof. Gennady P. Chuiko and Irina A. Danishewska,
Petro Mohyla BlackSea Satate University, Mykolayiv, Ukraine
gp47@mail.ru
1. Introduction and measurement details
A significant part of medical signals, or observations, is non-stationary, discrete time sequences. Thus, the computer methods analysis, as well as refinement and compression, are very helpful as for the problems of recognition and detection of their key diagnostic features. We are going to illustrate here this statement with examples of very common, and even routine medical measurements of blood pressure as well as pulse rate and with possibilities of Maple.
The package of Discrete Wavelet transforms (DWT) within Maple 16 [1] was recently added as new research software just for such tasks. The practical testing of this package was additional goal of present study.
Results of measurments of the blood pressure and the pulse frequency of the patient were obtained by automatic blood pressure monitor "Micrilife BP 3AG1" (Microlife AG, Switzerland, http://www.microlife.com.ua). The technical parameters of this device are presented in table 1 in accordance with the accompanying documentation.
Table 1. Technical parameters of device
Parameters
Measurment range
30. .280 mmHg
40-200 beats per minute
Static accuracy
(range 30 -280 mmHg)
±3 mmHg
Pulse accuracy
±5 %
Operating temperature
-20 .. +50 С / 50-104 F
The results of observations are presented as data tables and vectors below
restart;
Data_s:=convert(Data_s,Vector[row], datatype=float[8]): whattype(Data_s);# systolic blood pressures (mmHg)
Data_d:=convert(Data_d,Vector[row], datatype=float[8]):# systolic blood pressures (mmHg)
Data_p:=convert(Data_p,Vector[row], datatype=float[8]):# pulse frequences (beats per minute - bpm)
2. Primary results and their statistical characteristics
Let us show the prymary results grafically (table 2)
gs:=plots[listplot](Data_s,view=[0..80,125..185],thickness=2, gridlines=true,tickmarks=[15,16],color=black, title=`fig.1.Systola`,labeldirections=[horizontal,vertical],labels=[`counts`,`Blood pressure, mmHg.`],font=[helvetica,14]): gd:=plots[listplot](Data_d,view=[0..80,70..110],thickness=2, gridlines=true,tickmarks=[15,16],color=black, title=`fig.2.Diastola`,labeldirections=[horizontal,vertical],labels=[`counts`,`Blood pressure, mmHg.`],font=[helvetica,14]): gp:=plots[listplot](Data_p,view=[0..80,65..105],thickness=2, gridlines=true,tickmarks=[15,16],color=black, title=`fig.3.Pilse`,labeldirections=[horizontal,vertical],labels=[`counts`,`Pulse, bpm.`],font=[helvetica,14]):
Table 2
gs;
gd;
gp;
The next table shows the statistical characteristics of results
Table 3
Mean_value_s:=Statistics[Mean](Data_s); std_s:=sqrt(Statistics[Variance](Data_s)); accuracy_s:=100*%/%%;
Mean_value_d:=Statistics[Mean](Data_d); std_d:=sqrt(Statistics[Variance](Data_d)); accuracy_d:=100*%/%%;
Mean_value_p:=Statistics[Mean](Data_p); std_s:=sqrt(Statistics[Variance](Data_p)); accuracy_p:=100*%/%%;
The results of table 3 as for standard deviations and accuracies are in certain disagreements with values declared by table 1.
Other visual characteristics of primary measurements are statistical frequency plots (table 4).
Table 4
Statistics:-FrequencyPlot(Data_s,frequencyscale=relative,gridlines=true);# Systola
Statistics:-FrequencyPlot(Data_d,frequencyscale=relative,gridlines=true);# Diastola
Statistics:-FrequencyPlot(Data_p,frequencyscale=relative,gridlines=true);# Pulse
The readers can decide themself how convincing look the graphs of table 4 for the solving of question of closeness of these distributions of probabilities to the normal law.
A significant positive correlation coefficient has been observed only between systolic pressure and pulse frequency.
Statistics:-Correlation(Data_d,Data_s); Statistics:-Correlation(Data_d,Data_p); Statistics:-Correlation(Data_p,Data_s);
However, this correlation also looks not too compelling (see the scatter plot below).
Statistics:-ScatterPlot(Data_p,Data_s,title = "fig.7 Systola-Pulse correlation", legend = "Point data",view=[76..88,140..170],symbol=solidcircle,symbolsize=18,color=black,gridlines=true,font=[helvetica,16],tickmarks=[12,10],labeldirections=[horizontal,vertical],labels=[`Pulse, bpm`,` Systolic pressure, mmHg`], titlefont=[helvetica,16]);
The need to clean up the primary data from input noises is the main conclusion of this section. The package of Discrete Wavelet transforms (DWT) looks as suitable tool for this aim [1,2].
3. VectorDWT and InverseVectorDWT procedures
Write down the two procedures for direct Discrete Wavelet transformation (VectorDWT) and for inverse transforms with recovering of the original signal (InverseVectorDWT), using samples of [1]
with(DiscreteTransforms);
VectorDWT := proc (V, iters, w1, w2) local i, s, temp1, temp2; description `Direct wavelet transformation`;s := LinearAlgebra:-Dimensions(V); if modp(s, 2^iters) <> 0 then error "the length of V is not divisible by enough powers of 2" end if; temp1 := Vector(V); temp2 := Vector(V); for i to iters do DiscreteWaveletTransform(s/2^(i-1), temp1, w2, w1, storagetype = singlearray, temp2); ArrayTools:-Copy(temp2, temp1) end do; return temp1 end proc; # direct Discrete Wavelet transformation (VectorDWT)
InverseVectorDWT := proc (V, iters, w1, w2) local s, i, temp1, temp2;description `Inverse Wavelet Transformation`; s := LinearAlgebra:-Dimensions(V); if modp(s, 2^iters) <> 0 then error "the length of V is not divisible by enough powers of 2" end if; temp1 := Vector(V); temp2 := Vector(V); for i from iters by -1 to 1 do InverseDiscreteWaveletTransform(s/2^(i-1), temp1, w2, w1, storagetype = singlearray, temp2); ArrayTools:-Copy(temp2, temp1) end do; return temp1 end proc;# inverse Discrete Wavelet transformation (InverseVectorDWT)
The input parameters of both procedures (such as V, iters, w1, w2 etc.) will be explained below.
4. Wavelet analysis, de-noising , compressin and reconstruction of sygnals
Let us determine the number of scale levels for beginning. This number (SDlevels) does not exceed a maximal power of two, which is the divisor of counts number (80). Because and both are the divisors of counts number (80) we can choose SDlevels=3 or SDlevels=4. If we select SDlevels=4, the highest detail scale, as well as the scale of the approximation would be relatively narrow (only 5 counts, because =5). So it looks better to choose one level less
SDlevels:=3;
Now we can choose the wavelet family and the lenght (10) of both digital filters ( SDw1,SDw2) [1]:
SDw1,SDw2:=WaveletCoefficients(Symlet,10);
WaveletPlot(SDw1,SDw2,output=both);# wawelet digital filters
Let us transform all primary data by choosed wavelets:
SData_d := VectorDWT(Data_d, SDlevels, SDw1, SDw2): SData_s := VectorDWT(Data_s, SDlevels, SDw1, SDw2): SData_p := VectorDWT(Data_p, SDlevels, SDw1, SDw2):
Table 5.
plots[listplot](SData_s,thickness=3,color=red,gridlines=true,title=`fig.9 Wavelet transformation of Systola (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
plots[listplot](SData_d,thickness=3,color=red,gridlines=true,title=`fig.10 Wavelet transformation of Diastola (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
plots[listplot](SData_p,thickness=3,color=red,gridlines=true,title=`fig.11 Wavelet transformation of Pulse (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
It is noticeable from the graphs of table 5, that thewavelet coefficients (w-coeffs) differ significantly from zero only on a scale of approximation (first 10 counts). At the same time for all three scales of detail (11-20, 21-40, and 41-80 counts) the w-coeffs fluctuate around zero. We can then clear the images of signals from high-frequency noises, using the method of so-called "hard" threshold [3,4]. Let us find t first the noise levels at different scale counts, according to the recommendations of [3,4].
sigma1s:=(Statistics[Median](map(abs,(LinearAlgebra:-SubVector(SData_s,41..80))))-Statistics[Mean](LinearAlgebra:-SubVector(SData_s,41..80)))/0.6745; sigma2s:=(Statistics[Median](map(abs,(LinearAlgebra:-SubVector(SData_s,21..40))))-Statistics[Mean](LinearAlgebra:-SubVector(SData_s,21..40)))/0.6745; sigma3s:=(Statistics[Median](map(abs,(LinearAlgebra:-SubVector(SData_s,11..20))))-Statistics[Mean](LinearAlgebra:-SubVector(SData_s,11..20)))/0.6745;
Now these values would be corrected by numbers of counts [3,4]
SDthresh1s:=evalf(sigma1s*sqrt(2*ln(40))): SDthresh2s:=evalf(sigma2s*sqrt(2*ln(20))): SDthresh3s:=evalf(sigma3s*sqrt(2*ln(10))): T:=[SDthresh1s,SDthresh2s,SDthresh3s];
One can see that the thresholds (4,.4) are slightly differ for different scales. We are guaranteed to get zero w-coeffs on all three scales, choosing the highest of these thresholds
SDthresh_s:=max(T);
Thresholds for diastolic pressure an pulse frequencies were obtained in the same way
SDthresh_d := 22.2790061630243; SDthresh_p := %:
Previous cleaning from fluctuations with «hard threshold» method uses the obtained thresholds
SDRaf_1s:= Vector(map( z -> `if`(abs(z) <= SDthresh_s, 0, z),SData_s),datatype = float[8]): SDRaf_1d:= Vector(map( z -> `if`(abs(z) <= SDthresh_d, 0, z),SData_d),datatype = float[8]): SDRaf_1p:= Vector(map( z -> `if`(abs(z) <= SDthresh_p, 0, z),SData_p),datatype = float[8]):
About the same way we can de-noise w-coeffs on the approximation scale, using the statistical standard deviation as threshold and the mathematical expectation as a level for the w-coefficients on these scales (1-10 counts)
avs:=Statistics[Mean](LinearAlgebra:-SubVector(SDRaf_1s,1..10)); var_s:=sqrt(Statistics[Variance](LinearAlgebra:-SubVector(SDRaf_1s,1..10))); avd:=Statistics[Mean](LinearAlgebra:-SubVector(SDRaf_1d,1..10)); var_d:=sqrt(Statistics[Variance](LinearAlgebra:-SubVector(SDRaf_1d,1..10))); avp:=Statistics[Mean](LinearAlgebra:-SubVector(SDRaf_1p,1..10)); var_p:=sqrt(Statistics[Variance](LinearAlgebra:-SubVector(SDRaf_1p,1..10)));
SDRaf_s:= Vector(map( z -> `if`(abs(z-avs) <= var_s, avs, z),SDRaf_1s),datatype = float[8]): SDRaf_d:= Vector(map( z -> `if`(abs(z-avd) <= var_d, avd, z),SDRaf_1d),datatype = float[8]): SDRaf_p:= Vector(map( z -> `if`(abs(z-avp) <= var_p, avp, z),SDRaf_1p),datatype = float[8]):
Table 6 shows the de-noised wavelet-images of sygnals for a comparicon with table 5
Table 6
plots[listplot](SDRaf_s,thickness=3,color=red,gridlines=true,title=`fig.12 Wavelet transformation of Systola (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
plots[listplot](SDRaf_d,thickness=3,color=red,gridlines=true,title=`fig.13 Wavelet transformation of Diastola (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
plots[listplot](SDRaf_p,thickness=3,color=red,gridlines=true,title=`fig.14 Wavelet transformation of Pulse (Symlet,10)`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,-50..500],tickmarks=[8,20],labeldirections=[horizontal,vertical],labels=[`counts`,`w-coeffs`]);
Wavelet-images now are describing literally a few different from zero coefficients, i.e. they are effectively compressed and de-niised. Now we can reconstruct all sygnals by inverse transformations
SDataNew_s := InverseVectorDWT(SDRaf_s, SDlevels, SDw1, SDw2): SDataNew_d := InverseVectorDWT(SDRaf_d, SDlevels, SDw1, SDw2): SDataNew_p := InverseVectorDWT(SDRaf_p, SDlevels, SDw1, SDw2):
Let us present the results graphically
g2s:=plots[listplot](SDataNew_s,thickness=5,color=[red],gridlines=true,title=`Рис.15 Systolic pressure`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,125..185],tickmarks=[15,16],labeldirections=[horizontal,vertical],labels=[`counts`,`pressure, mm Hg`]): g2d:=plots[listplot](SDataNew_d,thickness=5,color=[red],gridlines=true,title=`Рис.15 Diastolic pressure`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,65..105],tickmarks=[15,16],labeldirections=[horizontal,vertical],labels=[`counts`,`pressure, mm Hg`]): g2p:=plots[listplot](SDataNew_p,thickness=5,color=[red],gridlines=true,title=`Рис.15 Pulse`,font=[helvetica,14],titlefont=[Arial,14],view=[0..80,65..105],tickmarks=[15,16],labeldirections=[horizontal,vertical],labels=[`counts`,`pulse, bpm`]):
Table 7
g2s;
g2d;
g2p;
All curves are characterized by minimum about count≈(46-52). This feature is associated with the course of treatment of the patient in a sanatorium (Truskvavec′, Ukraine). The effect looks quite short-living.
Comparison with the data of table 2 shows the efficiency of cleaning of small-scale fluctuations with high frequencies. De-noised and compressed sygnals of Table 7 include only changes with relative long periods. Such long periodical cyclical nature usually presents itself from autocorrelation functions (Table 8).
Statistics:-AutoCorrelation(SDataNew_s): acfs:=plots[listplot](%,gridlines=true,thickness=3,title=`fig17. Systolic pressure autocorrelation `, font=[helvetica,14],color=red): Statistics:-AutoCorrelation(SDataNew_d): acfd:=plots[listplot](%,gridlines=true,thickness=3,title=`fig.18 Diastolic pressure autocorrelation`, font=[helvetica,14],color=red): Statistics:-AutoCorrelation(SDataNew_p): acfp:=plots[listplot](%,gridlines=true,thickness=3,title=`fig.19 Pulse autocorrelation`, font=[helvetica,14],color=red):
Table 8
acfs;
acfd;
acfp;
These autocorrelations are quite expressive, very similar and demonstrating the main period about 12 counts.
5. Some comparisons and conclusions
Let us recalculate some statistical characteristics of de-noised sygnals
Table 9
Mean_value_s:=Statistics[Mean](SDataNew_s); std_s:=sqrt(Statistics[Variance](SDataNew_s)); accuracy_s:=100*%/%%;
Mean_value_d:=Statistics[Mean](SDataNew_d); std_d:=sqrt(Statistics[Variance](SDataNew_d)); accuracy_d:=100*%/%%;
Mean_value_p:=Statistics[Mean](SDataNew_p); std_s:=sqrt(Statistics[Variance](SDataNew_p)); accuracy_p:=100*%/%%;
It is easy to see that de-noising of primary signals has no influence on the mathematical expectations, but markedly increases the accuracy of the results, comparing the characteristics of table 3 and table 4.
The correlation coefficient between systolic pressure and the pulse frequency, which was essentially masked by noises within primary signals, also increased noticeably (almost twice)
Statistics:-Correlation(SDataNew_p,SDataNew_s);
Correlation between reconstructed data also looks much more convincing visually, as is demonstrated in table 10
Table 10
Statistics:-ScatterPlot(Data_p,Data_s,title = "fig. 20 Systola-Pulse correlation (primary data)", legend = "Point data",view=[76..88,140..170],symbol=solidcircle,symbolsize=18,color=black,gridlines=true,font=[helvetica,16],tickmarks=[12,10],labeldirections=[horizontal,vertical],labels=[`pulse, bpm`,`pressure, mmHg`]);
Statistics:-ScatterPlot(SDataNew_p,SDataNew_s,title = "fig. 21 Systola-Pulse correlation (reconstructed data)", legend = "Point data",view=[76..88,140..170],symbol=solidcircle,symbolsize=18,color=red,gridlines=true,font=[helvetica,16],tickmarks=[12,10],labeldirections=[horizontal,vertical],labels=[`pulse, bpm`,`pressure, mmHg`]);
The readers may experiment with different lengths of digital filters in the expression (4.2) and make sure that the selected length=10 is optimal in certain sense. Someone could even change the family of wavelets, since Maple offers a choice of four such families: Daubechies, Symlet, Coiflet, and Battle-Lemarie [1].
The general conclusion that we do here, this is the statement that the Maple package Discrete Wavelet Transforms (DWT) is a perfect tool for analyzing, cleaning and compression of medical signals, if you know how and where to use it.
Legal Notice: The copyright for this application is owned by the author(s). Neither Maplesoft nor the author are responsible for any errors contained within and are not liable for any damages resulting from the use of this material. This application is intended for non-commercial, non-profit use only. Contact the author for permission if you wish to use this application in for-profit activities.
6. References
[1] Wavelets Examples and Applications. © - 2012, Maplesoft
[2] Y. Jin, E. Angelini , and A. Laine. "Wavelets in Medical Image Processing: Denoising, Segmentation, and Registration," in Handbook of Biomedical Image Analysis Vol 1- Segmentation Models - Part a, Ed.: D. L. W. Jasjit Suri, Swamy Laximinarayan Kluwer Academic Plenum Publishers, pp. 305-358, (2005).
[3] D.Donoho, and I. Johnstone. Adapting to Unknown Smoothness via Wavelet Shrinkage., Journal of American Statistics Association, Vol. 90, No. 432, pp. 200-1224, (1995).
[4] R. Coifman and D. Donoho.Translation-invariant De-noising. in Wavelets and Statistics, Antoniadis, A. and Oppenheim, G., Eds. New York NY: Springer-Verlag, 1995.