Giter Club home page Giter Club logo

bpplus-reservoir's Introduction

My research interests include haemodynamics, blood pressure and cardiometabolic health.

I mostly write code for Stata and Matlab.

bpplus-reservoir's People

Contributors

adh30 avatar doingnz avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

bpplus-reservoir's Issues

beta 5

Version beta5

[ ] Extend scope of calculated variables so they match key Sphygmocor variables. [in progress]
[x ] Improve detection of end of systole
[x] Fix bug in Wf1 and Wf2 peak identification
[ ] better identification of problems with fits
[x] Improve error traps
[x] Fix bugs in figures and cut number of figures to one per dataset
[x] Improve setting default folder (rather than hard coding it) using a json as configuration file
[ ] Minor bug fixes and tidy code including converting script components to function [in progress]
[ ] SBP2 definition
[ ] SV estimation (possible beta 6 feature)
[ ] EF1 analog (possible beta 6 feature)

Warning: Colon operands must be real scalars. This warning will become an error in a future release.

I have updated to 2024a version of MATLAB.

I now get the following warning

Warning: Colon operands must be real scalars. This warning will become an error in a future release. 
> In kreservoir_v14 (line 152)
In BPfitres_v1 (line 38)
%find crossover point
Nd=length(pd);
np=[2:Nd Nd];
prend=pr(nn:end);
k=find((prend-prd).*(prend(np)-prd(np))<=0);  

%% k =   3    15    40    82
%% nn =  55

prr=pr;
prr(nn+k:end)=prd(k+1:end);                        %% <- this is line 152.

Extract the code that reads BP+ XML files into a function

Would you be ok if I extract the code that reads BP+ XML files into a function?

Separation of concerns reduces the effort to maintain code by improving reuse and testability. I have created MATLAB code for comparing BP+ results to invasive recordings for a new validation paper against pressure tip cath recordings. I think it is helpful sharing code that overlaps.

For ease of use, I think it require a "rename" of variables where _ is replaced with . to group variables by the source waveforms.

  • ss_ai becomes ss.ai, etc. for other supra-systolic variables and waveforms
  • ba_sbp becomes ba.sbp, ba_p_all becomes ba.p_all, etc. for intra-arterial brachial variables and waveforms
  • aosbp becomes ao.sbp, ao_p_all becomes ao.p_all, etc. for intra-arterial aortic variables and waveforms
  • samplerate becomes metadata.samplerate, snr becomes metadata.snr etc for other measurement parameters that are not measured.

i.e. we end up with a function along the lines of the following that works for both XML formats.

I wanted to ask for your thoughts on this before doing the work and proposing a PR for you repository.

function  [data, metadata, ss, ba, ao]=read_BPplus(folder_name, filename)

if not (isfile([folder_name filename]))
    return;
end
[data] = xml2struct([folder_name filename]);

% do we extract the measurement ID number?
metadata.id = filename;

%% Read Data from CardioScope legacy xml
if sum(strcmp(fieldnames(data), 'CardioScope')) == 1
    % meta data
    metadata.algo=data.CardioScope.Results.Result.Attributes.algorithm_revision;         % Software algorithm
    metadata.samplerate=str2double(data.CardioScope.MeasDataLogger.SampleRate.Text);     % sample rate, Hz
    metadata.datestring=data.CardioScope.MeasDataLogger.Attributes.datetime;             % Date as text string
    metadata.guid = data.CardioScope.MeasDataLogger.Attributes.guid;
    metadata.snr=str2double(data.CardioScope.Results.Result.SNR.Text);                   % Signal to noise ratio, dB
    metadata.patinet_id = '';
    metadata.notes = '';

    metadata.RawSuprasystolicPressure=data.CardioScope.MeasDataLogger.SSBuff.Text; % raw base 64 data

    % start of pulses.
    metadata.baTransitTime = 0.18;
    if (contains(data.CardioScope.MeasDataLogger.Attributes.software_version,"038"))
        metadata.baTransitTime = 0.06;
    end

    % extract CardioScope values
    % nibp brachial measurement
    ba.sbp=str2double(data.CardioScope.MeasDataLogger.Sys.Text);                % brachial systolic BP, mmHg
    ba.dbp=str2double(data.CardioScope.MeasDataLogger.Dia.Text);                % diastolic BP, mmHg
    ba.pp=ba.sbp-ba.dbp;                                                        % brachial pulse pressure, mmHg
    ba.map=str2double(data.CardioScope.MeasDataLogger.Mean.Text);               % mean arterial pressure, mmHg
    ba.hr=str2double(data.CardioScope.MeasDataLogger.Hr.Text);                  % heart rate, bpm

    % calculated aortic measurements
    ao.sbp=str2double(data.CardioScope.Results.Result.aoSys.Text);              % cSBP calculated by BP+, mmHg
    ao.dbp=str2double(data.CardioScope.Results.Result.aoDia.Text);              % cDBP calculated by BP+, mmHg
    ao.map=str2double(data.CardioScope.Results.Result.aoMap.Text);              % cMAP calculated by BP+, mmHg
    ao.pp=ao.sbp-ao.dbp;                                                        % cPP calculated by BP+, mmHg
    ao.ed = -1; % TODO Calcualte ED

    ss.prv=str2double(data.CardioScope.Results.Result.RMSSD.Text);              % RMSSD from suprasystolic signal
    ss.ai=str2double(data.CardioScope.Results.Result.ssAI.Text);                % AI from suprasystolic signal
    ss.dpdt=str2double(data.CardioScope.Results.Result.ssDpDtMax.Text);         % dp/dt from suprasystolic signal in uncorrected units
    ss.harm=str2double(data.CardioScope.Results.Result.ssHARM.Text);            % Normalized sAI
    ss.pp=str2double(data.CardioScope.Results.Result.ssPP.Text);                % Suprasystolic Pulse Pressure
    ss.ppv=str2double(data.CardioScope.Results.Result.ssPPV.Text);              % Suprasystolic Pulse Pressure Variation, %
    ss.RWTTFoot=str2double(data.CardioScope.Results.Result.ssRWTTFoot.Text);    % reflected wave transit time from foot of suprasystolic signal
    ss.RWTTPeak=str2double(data.CardioScope.Results.Result.ssRWTTPeak.Text);    % reflected wave transit time from peak of suprasystolic signal
    ss.sep=str2double(data.CardioScope.Results.Result.ssSEP.Text);              % Systolic ejection period, s
    ss.Tn=split(data.CardioScope.Results.Result.ssAverageBeatPointsIdxs.Text,','); % Times of characteristic points?

    %% brachial rhythm
    ba.p_all=str2double(split(data.CardioScope.Results.Result.baEstimate.Text,','));
    %% suprasystolic rhythm, average beat & start of pulses.
    ss.p_all=[];                                                                                                        % not scaled to arterial mmHg
    ss.pulseStartIndexes=str2double(split(data.CardioScope.Results.Result.ssBeatStartIdxs.Text,','));
    ss.p_av = str2double(split(data.CardioScope.Results.Result.ssAverageBeat.Text,','));                                % not scaled to arterial mmHg
    ss.averagePulsePointsIndexes=str2double(split(data.CardioScope.Results.Result.ssAverageBeatPointsIdxs.Text,','));
    %% aortic rhythm, average beat & start of pulses.
    ao.p_all=str2double(split(data.CardioScope.Results.Result.aoEstimate.Text,','));
    ao.pulseStartIndexes=str2double(split(data.CardioScope.Results.Result.cPulseStartIndexes.Text,','));
    ao.p_av = str2double(split(data.CardioScope.Results.Result.aoAverageBeat.Text,','));
    ao.averagePulsePointsIndexes=str2double(split(data.CardioScope.Results.Result.cAveragePulsePointsIndexes.Text,','));

    %% aortic average beat, ao_p_av
    a0=str2double(split(data.CardioScope.Results.Result.aoAverageBeat.Text,','));

    % create a double beat' to deal with the errors in definition of dbp
    a=[a0; a0];
    plot(a);
    % identify start and end of beat as minima
    [~, locmin1]=min(a);
    [~, locmin2]=min(a(locmin1+50:end));
    locmin2=locmin2+locmin1+50;
    %plot(a(locmin1:locmin2));

    % filter derivative of new beat with SG to get rid of kinks at or around join
    aa = sgolayfilt(diff(a),Npoly,Frame); % filter the derivative - order and framelen defined above
    a1=cumsum(aa)-min(cumsum(aa))+min(a);    % reconstruct
    ao.p_av =a1(locmin1:locmin2-1)';         % crop to cycle
    clear a0 a aa a1 locmin1 locmin2;


    ao.offset = round(baTransitTime * metadata.samplerate);
    ss.beatStartIdxs=str2double(split(data.CardioScope.Results.Result.ssBeatStartIdxs.Text,','));
    ao.pulseStartIndexes = ss.beatStartIdxs - ao.offset;
    for i = 1:length(ao.pulseStartIndexes)
        if ao.pulseStartIndexes(i)<0
              ao.pulseStartIndexes(i)=0;
        end
    end

else
    %% Read Data from BPplus xml
    metadata.algo=data.BPplus.Results.Result.Attributes.algorithm_revision;              % Software algorithm
    metadata.samplerate=str2double(data.BPplus.MeasDataLogger.SampleRate.Text);          % sample rate, Hz
    metadata.datestring=data.BPplus.MeasDataLogger.Attributes.datetime;                  % Date as text string
    metadata.guid = data.BPplus.MeasDataLogger.Attributes.guid;
    metadata.snr=str2double(data.BPplus.Results.Result.SNR.Text);                        % Signal to noise ratio, dB

    metadata.RawSuprasystolicPressure=data.BPplus.MeasDataLogger.RawSuprasystolicPressure.Text; % raw base 64 data

    % extract BPplus values
    ba.sbp=str2double(data.BPplus.MeasDataLogger.Sys.Text);                     % brachial systolic BP, mmHg
    ba.dbp=str2double(data.BPplus.MeasDataLogger.Dia.Text);                     % diastolic BP, mmHg
    ba.pp=ba.sbp-ba.dbp;                                                        % brachial pulse pressure, mmHg
    ba.map=str2double(data.BPplus.MeasDataLogger.Map.Text);                     % mean arterial pressure, mmHg
    ba.hr=str2double(data.BPplus.MeasDataLogger.Pr.Text);                          % heart rate, bpm

    ao.sbp=str2double(data.BPplus.Results.Result.cSys.Text);                    % cSBP calculated by BP+, mmHg
    ao.dbp=str2double(data.BPplus.Results.Result.cDia.Text);                    % cDBP calculated by BP+, mmHg
    ao.map=str2double(data.BPplus.Results.Result.cMap.Text);                    % cDBP calculated by BP+, mmHg
    ao.pp=ao.sbp-ao.dbp;                                                        % cPP calculated by BP+, mmHg

    ao.ed=str2double(data.BPplus.Results.Result.cST.Text)/1000;                 % cST calculated by BP+, ms, duration of systole

    ss.prv=str2double(data.BPplus.Results.Result.sPRV.Text);                    % RMSSD from suprasystolic signal
    ss.ai=str2double(data.BPplus.Results.Result.sAI.Text);                      % AI from suprasystolic signal
    ss.dpdt=str2double(data.BPplus.Results.Result.sDpDtMax.Text);               % dp/dt from suprasystolic signal in uncorrected units
    %ssHARM= Can be calculated from sAI if needed
    ss.pp=str2double(data.BPplus.Results.Result.sPP.Text);                      % Suprasystolic Pulse Pressure in the Cuff, mmHg (PP in cuff is small)
    ss.ppv=str2double(data.BPplus.Results.Result.sPPV.Text);                    % Pulse pressure variation, % [?]
    ss.RWTTFoot=str2double(data.BPplus.Results.Result.sRWTTFoot.Text);          % reflected wave transit time from foot of suprasystolic signal
    ss.RWTTPeak=str2double(data.BPplus.Results.Result.sRWTTPeak.Text);          % reflected wave transit time from peak of suprasystolic signal
    ss.sep=str2double(data.BPplus.Results.Result.sSEP.Text)/1000;               % Systolic ejection period, s
    ss.Tn=split(data.BPplus.Results.Result.sAveragePulsePointsIndexes.Text,','); % Times of characteristic points?
    %% brachial rhythm
    ba.p_all=str2double(split(data.BPplus.Results.Result.baEstimate.Text,','));
    %% suprasystolic rhythm and average beat
    ss.p_all=str2double(split(data.BPplus.Results.Result.sBaseLined.Text,','));                                         % not scaled to arterial mmHg
    ss.pulseStartIndexes=str2double(split(data.BPplus.Results.Result.sPulseStartIndexes.Text,','));
    ss.SelectedPulseIndexes=str2double(split(data.BPplus.Results.Result.sSelectedPulseIndexes.Text,','));
    ss.p_av = split(data.BPplus.Results.Result.sAveragePulse.Text,',');                                                 % not scaled to arterial mmHg
    ss.averagePulsePointsIndexes=str2double(split(data.BPplus.Results.Result.sAveragePulsePointsIndexes.Text,','));
    %% aortic rhythm, average beat & start of pulses.
    ao.p_all=str2double(split(data.BPplus.Results.Result.cEstimate.Text,','));
    ao.pulseStartIndexes=str2double(split(data.BPplus.Results.Result.cPulseStartIndexes.Text,','));
    ao.p_av=str2double(split(data.BPplus.Results.Result.cAveragePulse.Text,','))';
    ao.averagePulsePointsIndexes=str2double(split(data.BPplus.Results.Result.cAveragePulsePointsIndexes.Text,','));
end
%% categorise quality based on SNR
if metadata.snr>=12
    metadata.quality='Excellent';
elseif metadata.snr>=9
    metadata.quality='Good';
elseif metadata.snr>=6
    metadata.quality='Acceptable';
elseif metadata.snr>0
    metadata.quality='Poor';
else
    metadata.quality='Unacceptable';
end

end

Version 1 beta 4

Version 1 (Beta 4)

  • Include estimates of 3-element Windkessel parameters and compliance using Liu's area method as standard.
  • include variables that are produced by Sphygmocor.
  • include options to fix Pinfinity at zero (or some other pre-specified value)
  • improve detection of end-systole and/or flag errors

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.