a b/preprocessOfApneaECG/BioSigKit/@BioSigKit/BioSigKit.m
1
classdef BioSigKit < handle 
2
%% ============== BioSigKit ==================  
3
% BioSigKit is a set of useful signal processing tools that are either
4
% developed by me personally or others in different fields of biosignal
5
% processing. BioSigKit is a wrapper with a simple visual interface that
6
% gathers this tools under a simple easy to use platform. This tool might
7
% be only used for non-commercial, academic, research and learning
8
% purposes.
9
%
10
%% ============== How to start =================== 
11
% example:: obj = BioSigKit(Sig, Fs, Gr)
12
% Where:::
13
% Sig: is the signal
14
% Fs : Sample Rate
15
% Gr : Flag for showing the interface or not
16
% Then you can call any subroutine
17
%% ====List Of Subroutines that you can call for QRS detection ========= 
18
% ------- Algorithm -------------------- How to Call ---------------
19
% (1) Pan-Tompkins Algorithm :        obj.PanTompkins
20
% (2) Phase Space Reconstruction :    obj.PhaseSpaceAlg
21
% (3) RST State-Machine :             obj.StateMachine
22
% (4) Filter Bank:                    obj.FilterBankQRS
23
% (5) MTEO qrstAlg:                   obj.MTEO_qrstAlg 
24
% (6) AMPD:                           obj.AMPD_PAlg
25
%% ==== List of all subroutines for ACC, EMG and etc processing ======== 
26
% (7) Activity Detection Hilbert:     obj.Env_hilbert
27
            % ---------------- Inputs ------------------ %
28
            % Smooth_window : Length of smoothing window in nr of sample
29
            % threshold_style : Set 0 for Automatic, Set 1 for Manual
30
            % DURATION : The number of samples for signal to be above
31
            % threshold to be considered active
32
            % ---------------- Output ------------------ %
33
            % alarm :  Pattern of activities
34
            % ---------------- Demo -------------------- %
35
            % v = repmat([.1*ones(200,1);ones(100,1)],[10 1]);                    % generate true variance profile
36
            % obj.sig = sqrt(v).*randn(size(v));
37
            % obj.Env_hilbert;
38
%-----------------
39
% (8) Comp Mobility and Complexity:   obj.ComputeHjorthP
40
%-----------------
41
% (9) Posture detection 3 Chann ACC:  obj.ACC_Act
42
            % ------------- Inputs ----------------------- %
43
            % obj.sig : 3 axis Accelerometer signal where, each row is an axis
44
            % and each column a sample (e.g. (3,:))
45
            % obj.Fs : Sampling frequency of the Accelerometer 
46
            % ------------- Output ----------------------- %
47
            % output : adaptively filtered ACC channels based on activity
48
            % state : activity level (0:steady,1:walking,2:joggin)
49
            % EE : Energy Expenditure over 1 min (or length sig)
50
            % F : Bandpass filter in Hz
51
            % SMA : Signal Magnitude area
52
%------------------
53
% (10)PsuedoCorr template matching :  obj.TemplateMatch
54
            % ------------------- Inputs --------------------- %
55
            % template :  A template in the form of a vector, the length of
56
            % the template should be smaller than the signal.
57
            % lag : a lag in terms of nr of samples to move the template,
58
            % it should be smaller than the length of the template
59
            % ------------------- Outputs -------------------- %
60
            % PsC_s : template matching score in range [0,1]. 
61
            % best_lag: the lag that gave the highest correlation score.
62
%-----------------
63
% (11)ECG derived respiration :       obj.EDR_comp
64
%-----------------
65
% (12)ACC derived respiration :       obj.ADR_comp
66
%% ===== General Projective, linear and nonlinear filterings ============ %%
67
% (13)Real-time neural PCA:           obj.neural_pca
68
            % ----------------- Inputs ------------------- %
69
            % X : Multi-channel signal, each row represents a channel and
70
            % each column a sample. 
71
            % nPCA: Number of PCAs to extract
72
            % nit: Number of iterations to go through the whole signal
73
            % T : Learning rate in range [0,1], default:0.9
74
            % ---------------- Outputs ------------------- %
75
            % EigVec: Eigen vectors
76
            % PC : PCs
77
            % Eigval : Eigenvalues
78
%-----------------
79
% (14)Adaptive Filtering:             obj.adaptive_filter
80
%                 * RLS : Recursive Least Squares Filter
81
%                 * ALE : Adaptive Line Enhancer (Delayed Filter)
82
%                 * VLALE : Variable Leaky Adaptive Line Enhancer
83
%                 * NLMS_ecg : Normalized Least Mean Squares filter for artficat
84
%                   removal in ECG based on 3 channel Accelerometer recordings  
85
%-------------------- Inputs ---------------------------%
86
           % type: type of the filter (numeric): 
87
           %       (1) RLS : Recursive Least Squares Filter
88
           %       (2) ALE : Adaptive Line Enhancer (Delayed Filter)
89
           %       (3) VLALE : Variable Leaky Adaptive Line Enhancer
90
           %       (4) NLMS_ecg : Normalized Least Mean Squares filter for
91
           %       artficat removal in ECG based on 3 channel Accelerometer
92
           %       recordings
93
           % ref: Reference signal:
94
           %        * For RLS filter it is single channel (1*N)
95
           %        * For NLMS_ECG filter it should be 3 Channel
96
           %        Accelerometer (3*N)
97
           % obj.Sig: input signal to clean (single channel vector)
98
           % order : order of the filter (for VLALE and ALE also delay)
99
           % lambda : learning rate(0<= lambda <=1, usually close to 1)
100
           %-------------------- Outputs --------------------------%
101
           % output: cleaned signal
102
           % error_sig : error signal 
103
%-----------------
104
% (15)Nonlinear phasespace filtering: obj.nonlinear_phase_filt
105
%-------------------- Method ---------------------------%
106
         % Employs nonlinear phasespace filter to clean up the signal. This
107
         % method is very strong and even able to extract foetal ecg from
108
         % single channel maternal recordings. Please refer to examples of
109
         % BioSigKit for further details.
110
         %-------------------- Inputs ----------------------------%
111
         % sig : Signal to be analyzed (single channel)
112
         % t : Number of samples for computing delayed phase space (def: 1)
113
         % d : Embedding dimension to consider (def: 50)
114
         % m : dimension of null space (def: 49)
115
         % r : number of nearest neighbors to consider
116
         % (normally a large number def: length(sig)/4)
117
         % --------------------- Output ------------------------ %
118
         % output : Cleaned Signal
119
         % --------------------- example ----------------------- %
120
         % output = projective(foetal_ecg(:,2), 1, round(Fs/5), round(Fs/6.25), 1500);
121
% (16)Teager-Keiser energy operator:  obj.TK_comp
122
123
%% ============== Licensce ========================================== %%
124
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
125
% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
126
% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
127
% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
128
% OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
129
% SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
130
% TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
131
% PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
132
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
133
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
134
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
135
% Author :
136
% Hooman Sedghamiz, Feb, 2018
137
% MSc. Biomedical Engineering, Linkoping University
138
% Email : Hooman.sedghamiz@gmail.com
139
%% ============== End Helper ================= %%
140
    %------------ Class Definition of BioSigKit Toolbox -------------- %
141
    properties(GetAccess = 'public', SetAccess = 'private')
142
        panel = [];                                                        % Main Visualization Panel
143
        SigView = [];                                                      % Signal View Axis
144
        FreqValHolder;                                                     % Holds SampFreq from interface
145
        Alg;                                                               % Alg type from interface
146
        Status;                                                            % Loader
147
        LoadedSig;                                                         % Loaded Sig
148
        path_alg = addpath(genpath(fileparts(fileparts(which(mfilename)))));% Path of Algorithm
149
        slashchar = char('/'*isunix + '\'*(~isunix));                      % OS dependent /
150
    end  
151
    %------------ Interface and private methods -------------%
152
    methods(Access = protected)
153
           BioSigKitPanel(obj);             % Setup the interface
154
    end
155
    %------------ Properties for BioSigKit ------------------%
156
    properties(GetAccess = 'public', SetAccess = 'public')
157
           Fs;                              % Sample Freq
158
           Sig;                             % Signal
159
           Gr = 0;                          % Flag for showing the interface
160
           Results;                         % Struct holding results
161
           statsC;                          % Holding Stats
162
           PlotResult = 0;                  % Verbose results of each algorithm
163
           PhasePeriod = 0.020;             % Phase Period Used for Phase Space
164
           ScalogramL;                      % Scalogram Length
165
           complexity;                      % Complexity based on Hjorth Param
166
           mobility;                        % mobility based on Hjorth
167
           ACC;                             % 3 channel ACC
168
    end
169
    %% ------------------ Methods ----------------------------- %%
170
    methods 
171
       %% --------------------- Constructor -------------------------- %%
172
       function obj = BioSigKit(Sig, Fs, Gr)
173
           % --------- Check Inputs -------------%
174
           if nargin < 3 
175
             Gr = 0;
176
             if nargin < 2
177
              Fs = 250; 
178
              if nargin < 1
179
                 BioSigKitPanel(obj);
180
                 return;
181
              end
182
              Gr = 1;
183
             end
184
           end
185
           %--------- Pack Necessary Parameters -------------%
186
           obj.Sig = Sig;
187
           obj.Gr = Gr;
188
           obj.Fs = Fs;
189
           obj.ScalogramL = ceil(length(Sig)/2) - 1;
190
           %--------- Create the interface of Flag is on ------------- %
191
           if obj.Gr
192
              %------ Initialize Figure------%
193
              BioSigKitPanel(obj);
194
              %------ Update Figure -----------%
195
              UpdateFig(obj);
196
           end
197
       end
198
      %% ----------------------Run Algorithms method-------------------- %%
199
      function RunAlg(obj)
200
          if isempty(obj.Sig)
201
              msgbox('First Load a Signal!'); 
202
              return;
203
          end
204
          [~,ind] = min(size(obj.Sig));
205
          if ind == 1
206
                  obj.Sig = obj.Sig(1,:);
207
          else
208
                  obj.Sig = obj.Sig(:,1);
209
          end
210
          % ------------------ Set the Values --------------------------%
211
          obj.Fs = str2double(obj.FreqValHolder.String);
212
          % ------------------ Start Loader ----------------------------%
213
          obj.Status.start;
214
          obj.Status.setBusyText('Processing...');
215
          pause(0.01);
216
          UpdateFig(obj);
217
          obj.Results = [];
218
          ResetStats(obj);
219
          % --------------- Run the appropriate method ------------------%
220
        try
221
          switch obj.Alg.Value
222
              % ----- Pan-Tompkins -------%
223
              case 1
224
                 PanTompkins(obj);
225
              % ----- Phase Space --------%
226
              case 2
227
                 PhaseSpaceAlg(obj);
228
              % ----- RST State-Machine ------%
229
              case 3
230
                 StateMachine(obj);
231
              % ----- QRS Filter-Bank -------- %
232
              case 4
233
                 FilterBankQRS(obj);
234
              % ---------- QRST MTEO ------------ %
235
              case 5
236
                 MTEO_qrstAlg(obj); 
237
              %----------- AMPD Peak Detector --------%
238
              case 6
239
                 AMPD_PAlg(obj);
240
              otherwise
241
                 return;
242
          end
243
         % -------------------- Update Figure --------------------- %
244
           visualizeResults(obj);    
245
        catch ME
246
           msgbox(ME.message);
247
        end
248
          % ------------------- Update Loader ---------------------- %
249
          obj.Status.setBusyText('Done!');
250
          pause(1);
251
          obj.Status.stop;
252
      end
253
      %% ---------------------- Import Sig ------------------------------ %%
254
      function ImportSig(obj)
255
          [FileName,Path] = uigetfile(fullfile(pwd,...
256
                '*.mat'),...
257
                'Select Your Signal');
258
          if ~FileName
259
              return;
260
          end
261
          data = load([Path,obj.slashchar,FileName]);
262
          FN = fields(data);
263
          if ~isempty(FN)
264
             obj.Sig = data.(FN{1}); 
265
          else
266
             msgbox('Bad Input Signal! Input should be a vector!');
267
             return;
268
          end
269
          if ~isempty(obj.LoadedSig)
270
             obj.LoadedSig.String = [Path,FileName];
271
             % ----------------- Update Figure ------------------ %
272
             UpdateFig(obj);
273
             obj.Results = [];
274
          end
275
          
276
      end
277
      %% ================= Phase Space ===================== %%
278
       %----- Employs Phase Space for QRS detection ------ %
279
       % Call : obj.PhaseSpaceAlg  OR PhaseSpaceAlg(obj)
280
       % Outputs :  
281
       % R : R Beats, 
282
       % V : Processed area computed from Phase Space
283
      function [R,V] = PhaseSpaceAlg(obj)
284
          obj.Results = [];
285
          [R,V] = PhaseSpaceQRS(obj.Sig,obj.Fs,obj.PhasePeriod,...
286
              obj.PlotResult);
287
          obj.Results.R(1,:) = R(:,1);
288
      end
289
      %% ================= MTEO QRST Delineation ============== %%
290
       %------ Emlpoys MultiValued MTEO to delineate ECG---------- %
291
       % Call : obj.MTEO_qrstAlg OR MTEO_qrstAlg(obj)
292
       % Outputs: Delineated Waves (QRSTP)
293
       function [R,Q,S,T,P_w] = MTEO_qrstAlg(obj)
294
           obj.Results = [];
295
           [R,Q,S,T,P_w] = MTEO_qrst(obj.Sig,obj.Fs,obj.PlotResult);
296
           obj.Results.R(1,:) = R(:,1);
297
           obj.Results.Q(1,:) = Q(:,1);
298
           obj.Results.S(1,:) = S(:,1);
299
           obj.Results.T(1,:) = T(:,1);
300
           obj.Results.P(1,:) = P_w(:,1);
301
       end
302
     %% =================== AMPD Peak Detection ================== %%
303
     % ------------- Employs AMPD Algorithm for Peak detection -----------%
304
     % Inputs : 
305
     % Sig
306
     % L : Max sample number for Scalogram computation(Leave free if have not idea)
307
       function R = AMPD_PAlg(obj)
308
          obj.Results = [];
309
          if isempty(obj.ScalogramL)
310
             obj.ScalogramL = ceil(length(obj.Sig)/2) - 1;
311
          end
312
          try
313
            R = AMPD_P(obj.Sig,obj.ScalogramL,obj.PlotResult); 
314
            obj.Results.R(1,:) = R(:,1);
315
          catch ME
316
             msgbox(ME.message); 
317
          end
318
            
319
       end
320
     %% ================== Filter Bank QRS Detector ================== %%
321
     function R = FilterBankQRS(obj)
322
          obj.Results = [];
323
          R = nqrsdetect(obj.Sig,obj.Fs);   
324
          obj.Results.R(1,:) = R(:);
325
     end
326
     %% ==================== Pan-Tompkins QRS Detector ================ %%
327
     function [R_amp,R_ind] = PanTompkins(obj)
328
         obj.Results = [];
329
         [R_amp,R_ind]=pan_tompkin(obj.Sig,obj.Fs,obj.PlotResult);
330
         obj.Results.R(1,:) = R_ind(:);
331
     end
332
     %% ===================== Simple State-Machine ===================== %%
333
     % Outputs : R_i : Index of R peaks, R_a : Amplitude
334
     function [R_i,R_a,S_i,S_a,T_i,T_a,Q_i,Q_a] = StateMachine(obj)
335
         [R_i,R_a,S_i,S_a,T_i,T_a,Q_i,Q_a] = SimpleRST(obj.Sig,obj.Fs,...
336
             obj.PlotResult);
337
         obj.Results.R(1,:) = R_i;
338
         obj.Results.Q(1,:) = Q_i;
339
         obj.Results.S(1,:) = S_i;
340
         obj.Results.T(1,:) = T_i;
341
     end
342
     %% ===============Update the plot in interface ========== %%
343
     function visualizeResults(obj)
344
         % --------------- First the Figure ------------------%
345
         if ~isempty(obj.Results)
346
             PP = fields(obj.Results);
347
             Index = [5,10,15;3,8,13;2,7,12;1,6,11;4,9,14];
348
             colors = distinguishable_colors(length(PP),{'k','y'});
349
             for i= 1: length(PP)
350
                 % ----------- Update Signal ------------------ %
351
                 line(repmat(obj.Results.(PP{i})(1,:),[2 1]),...
352
                      repmat([min(obj.Sig-mean(obj.Sig))/2; max(obj.Sig-mean(obj.Sig))/2],...
353
                      size(obj.Results.(PP{i})(1,:))),'LineWidth',1.5,...
354
                      'LineStyle','-.','color',colors(i,:),'Parent',obj.SigView);
355
                 % ----------- Update Stats -------------------- %
356
                 intervals = round((diff(obj.Results.(PP{i})(1,:)))./obj.Fs,3);
357
                 obj.statsC.Children(Index(i,1)).String = mat2str(max(intervals));
358
                 obj.statsC.Children(Index(i,2)).String = mat2str(round(mean(intervals),3));
359
                 obj.statsC.Children(Index(i,3)).String = mat2str(length(obj.Results.(PP{i})(1,:)));
360
             end
361
         end
362
     end
363
     %% ================= Update VisualInterface Axis ================= %%
364
     function UpdateFig(obj)
365
              cla(obj.SigView);
366
              plot(obj.Sig - mean(obj.Sig),'LineWidth',2,'Parent',obj.SigView,'color','yellow');
367
              set(obj.SigView,'XGrid','on',...
368
                 'YGrid','on','XMinorGrid','on','YMinorGrid','on',...
369
                 'Color',[0,0,0],'YColor',[1,1,1],'XColor',[1,1,1]);
370
              axis(obj.SigView,'tight');
371
     end
372
     %% ================ Update Stats ================================== %%
373
     function ResetStats(obj)
374
        for j = 1: 15
375
           obj.statsC.Children(j).String = '\bf --';
376
        end
377
     end
378
    end
379
    %% ============ Experimental Methods not in GUI Yet ================== %%
380
    methods
381
        %% ------ Use Hilber Tr to detect Activity in signals --------- %%
382
        function alarm = Env_hilbert(obj,Smooth_window,threshold_style,...
383
                DURATION)
384
            % ---------------- Inputs ------------------ %
385
            % Smooth_window : Length of smoothing window in nr of sample
386
            % threshold_style : Set 0 for Automatic, Set 1 for Manual
387
            % DURATION : The number of samples for signal to be above
388
            % threshold to be considered active
389
            % ---------------- Output ------------------ %
390
            % alarm :  Pattern of activities
391
            % ---------------- Demo -------------------- %
392
            % v = repmat([.1*ones(200,1);ones(100,1)],[10 1]);                    % generate true variance profile
393
            % obj.sig = sqrt(v).*randn(size(v));
394
            % obj.Env_hilbert;
395
            % ---------------- Input Handling ------------------%
396
            if nargin < 4
397
               DURATION = 20;                                                     % default
398
               if nargin < 3
399
                  threshold_style = 1;                                            % default 1 , means it is done automatic
400
                   if nargin < 2
401
                      Smooth_window = 20;                                         % default for smoothing length
402
                   end
403
                end
404
            end
405
            alarm = envelop_hilbert(obj.Sig,...
406
                Smooth_window,...
407
                threshold_style,DURATION,obj.PlotResult);
408
        end
409
        %% ------ Employ Hjorth Parameters to analyze a signal --------- %%
410
        function [mobility,complexity] = ComputeHjorthP(obj)
411
            % ---------------- Hjorth Parameters ------------------- %
412
            % ---------------- Output ----------------------%
413
            % mobility : Central frequency
414
            % complexity : bandwith of the signal
415
              [mobility,complexity] = simpleHjorth(obj.Sig,obj.Fs);
416
              obj.mobility = mobility;
417
              obj.complexity = complexity;
418
        end
419
        %% ------ Activity Detection in ACC signals ---------------- %%
420
        function [output,state,EE,F,SMA] = ACC_Act(obj)
421
            % ------------- Inputs ----------------------- %
422
            % obj.sig : 3 axis Accelerometer signal where, each row is an axis
423
            % and each column a sample (e.g. (3,:))
424
            % obj.Fs : Sampling frequency of the Accelerometer 
425
            % ------------- Output ----------------------- %
426
            % output : adaptively filtered ACC channels based on activity
427
            % state : activity level (0:steady,1:walking,2:joggin)
428
            % EE : Energy Expenditure over 1 min (or length sig)
429
            % F : Bandpass filter in Hz
430
            % SMA : Signal Magnitude area
431
             if isempty(obj.Sig)
432
                error('Please first load your ACC to obj.ACC!'); 
433
             end
434
             [output,state,EE,F,SMA] = ACC_Activity(obj.Sig,obj.Fs);
435
        end
436
 %% ------------- Template Matching with Psuedo Corr--------------------- %%
437
        function [PsC_s,best_lag] = TemplateMatch(obj,template,lag)
438
            % ------------------- Inputs --------------------- %
439
            % template :  A template in the form of a vector, the length of
440
            % the template should be smaller than the signal.
441
            % lag : a lag in terms of nr of samples to move the template,
442
            % it should be smaller than the length of the template
443
            % ------------------- Outputs -------------------- %
444
            % PsC_s : template matching score in range [0,1]. 
445
            % best_lag: the lag that gave the highest correlation score.
446
            if nargin < 3
447
               [PsC_s,best_lag] = PsC(template,obj.Sig);
448
            else
449
               [PsC_s,best_lag] = PsC(template,obj.Sig,lag);
450
            end
451
              
452
        end
453
      %% ---------------- Real time Neural PCA Filter ----------------- %%
454
        function  [EigVec,PC,Eigval] = neural_pca(obj,nPCA,nit)
455
            % ----------------- Inputs ------------------- %
456
            % X : Multi-channel signal, each row represents a channel and
457
            % each column a sample. 
458
            % nPCA: Number of PCAs to extract
459
            % nit: Number of iterations to go through the whole signal
460
            % T : Learning rate in range [0,1], default:0.9
461
            % ---------------- Outputs ------------------- %
462
            % EigVec: Eigen vectors
463
            % PC : PCs
464
            % Eigval : Eigenvalues
465
            % ---------------- Check Inputs -------------- %
466
            if size(obj.Sig,1) < 2 
467
                fprintf('|#| BioSigKit> Input signals should be channles*N.\n');
468
            end
469
            [EigVec,PC,Eigval] = RTpca(obj.Sig,nPCA,nit);
470
        end
471
       %% ----------------- Adaptive Filters --------------------- %%
472
       function [output,error_sig] = adaptive_filter(obj,type,ref,...
473
               order,lamda)
474
           %-------------------- Inputs ---------------------------%
475
           % type: type of the filter (numeric): 
476
           %       (1) RLS : Recursive Least Squares Filter
477
           %       (2) ALE : Adaptive Line Enhancer (Delayed Filter)
478
           %       (3) VLALE : Variable Leaky Adaptive Line Enhancer
479
           %       (4) NLMS_ecg : Normalized Least Mean Squares filter for
480
           %       artficat removal in ECG based on 3 channel Accelerometer
481
           %       recordings
482
           % ref: Reference signal:
483
           %        * For RLS filter it is single channel (1*N)
484
           %        * For NLMS_ECG filter it should be 3 Channel
485
           %        Accelerometer (3*N)
486
           % obj.Sig: input signal to clean (single channel vector)
487
           % order : order of the filter (for VLALE and ALE also delay)
488
           % lambda : learning rate(0<= lambda <=1, usually close to 1)
489
           %-------------------- Outputs --------------------------%
490
           % output: cleaned signal
491
           % error_sig : error signal 
492
           % ------------------- Process Inputs -------------------%
493
           output= [];
494
           error_sig = [];
495
           if nargin < 2
496
              fprintf('|#| BioSigKit> Please select a filter type! (1-4).\n'); 
497
              fprintf('|#| BioSigKit> Exiting.');
498
              return;
499
           end
500
           if nargin < 5
501
               lamda = 1;
502
               if nargin < 4
503
                   order = 1*obj.Fs;
504
                   if nargin < 3
505
                      ref= [];
506
                   end
507
               end
508
           end
509
           % ------------------- Run the Filters-------------------%
510
           switch type
511
               % ------ Recursive Least Squars (RLS) ------ %
512
               case 1 
513
                   if isempty(ref) || size(ref,1) > 1
514
                      fprintf('|#| BioSigKit> Ref signal should be 1*N!\n');
515
                      return;
516
                   end
517
                   fprintf('|#| BioSigKit> Adaptive RLS Filter...\n');
518
                   [output,error_sig] = RLS(ref,obj.Sig,order,lamda);
519
               % ------ Adaptive Line Enhancer (ADLE) ------ %
520
               case 2
521
                   fprintf('|#| BioSigKit> Adaptive Delayed Line Enhancer...\n');
522
                   [output,error_sig] = ALE_imp(obj.Sig,obj.Fs,order);
523
               % ------ Variable Leaky ALE (VLALE) ------ %
524
               case 3 
525
                   fprintf('|#| BioSigKit> Variable Leaky ALE Running...\n');
526
                   [output,error_sig] = VLALE_imp(obj.Sig,obj.Fs,order); 
527
               % ------ ECG artifact removal with 3 channel ACC ------ %
528
               case 4
529
                   if isempty(ref) || size(ref,1) < 3 || size(ref,1) > 3 
530
                      fprintf('|#| BioSigKit> Accelerometer signals should be 3*N!\n');
531
                      return;
532
                   end
533
                   fprintf('|#| BioSigKit> ECG Artifact removal with NLMS...\n');
534
                   output = NLMS_ecg(ref,obj.Sig,order,obj.PlotResult);
535
               otherwise 
536
                   fprintf('|#| BioSigKit> Filter type not recognized!\n');
537
           end
538
            fprintf('|#| Done!\n');
539
       end
540
       %% ----------------- Non-Linear PhaseSpace Filter -------------- %%
541
       function output = nonlinear_phase_filt(obj,t,d,m,r)
542
         %-------------------- Method ---------------------------%
543
         % Employs nonlinear phasespace filter to clean up the signal. This
544
         % method is very strong and even able to extract foetal ecg from
545
         % single channel maternal recordings. Please refer to examples of
546
         % BioSigKit for further details.
547
         %-------------------- Inputs ----------------------------%
548
         % sig : Signal to be analyzed (single channel)
549
         % t : Number of samples for computing delayed phase space (def: 1)
550
         % d : Embedding dimension to consider (def: 50)
551
         % m : dimension of null space (def: 49)
552
         % r : number of nearest neighbors to consider
553
         % (normally a large number def: length(sig)/4)
554
         % --------------------- Output ------------------------ %
555
         % output : Cleaned Signal
556
         % --------------------- example ----------------------- %
557
         % output = projective(foetal_ecg(:,2), 1, round(Fs/5), round(Fs/6.25), 1500);
558
         %---------------------- Input Handling ----------------------%
559
            if nargin < 5
560
             r = round(length(obj.Sig)/4); 
561
             if nargin < 4
562
               m = 49;          
563
               if nargin < 3
564
                     d = 50;
565
                   if nargin < 2 
566
                       t = 1; 
567
                   end
568
               end
569
             end
570
            end
571
            % ------------------- Run filter ------------------- %
572
            fprintf('|#| BioSigKit> Running Non-linear Filter...\n');
573
            output = projective (obj.Sig, t, d, m, r);
574
            fprintf('|#| Done!\n');
575
       end
576
       %% =================== ECG derived Respiration =============== %%
577
       function EDR = EDR_comp(obj)
578
           % --------------------- Method ------------------------ %
579
           % 1) Use Pan-tompkins for R peak detection
580
           % 2) Extract templates
581
           % 3) Use neural PCA to extract the eigenvectors
582
           % 4) construct EDR signal.
583
           % ---------------- Compute R peaks --------------------- %
584
              obj.PanTompkins();
585
           % --------------- Segment window size ------------------ %
586
              Win = round(0.356*obj.Fs);
587
              if ~mod(Win,2)
588
                  L = Win/2;
589
                  Win = Win + 1;
590
              else
591
                  L = (Win-1)/2;
592
              end
593
           % --------------- Segment the signal --------------------- %
594
              R = zeros(Win,length(obj.Results.R));
595
              for i = 1 : length(obj.Results.R)   
596
                  if obj.Results.R(i)-L < 1
597
                     dummy = Win - length(obj.Sig(1:obj.Results.R(i)+L));
598
                     R(:,i) = [ones(dummy,1)*mean(obj.Sig(1:obj.Results.R(i)+L));...
599
                         obj.Sig(1:obj.Results.R(i)+L)]; 
600
                  elseif obj.Results.R(i)+L > length(obj.Sig)
601
                     dummy = Win - length(obj.Sig(obj.Results.R(i)-L:end));
602
                     R(:,i) = [obj.Sig(obj.Results.R(i)-L:end);...
603
                         ones(dummy,1)*mean(obj.Sig(obj.Results.R(i)-L:end))]; 
604
                  else
605
                     R(:,i) = obj.Sig(obj.Results.R(i)-L:obj.Results.R(i) + L); 
606
                  end  
607
              end
608
           % ------------------- Real Time PCA ------------------------ %
609
              temp_ecg = obj.Sig;
610
              obj.Sig = R';
611
              PC = neural_pca(obj,size(R,2),2);
612
              obj.Sig = temp_ecg;
613
              PC = PC(:,1);
614
           % ------------------- Build EDR Signal --------------------- %
615
              xx = 1 : length(temp_ecg);
616
              interp1 = [0 obj.Results.R length(temp_ecg)];
617
              PC = [0 PC' 0];
618
              EDR = spline(interp1,PC,xx);
619
              EDR = detrend(EDR);
620
       end
621
       %% ================ 3 Channel ACC derived Respiration ========== %%
622
       function ADR = ADR_comp(obj)
623
            %------------ Method -----------------------------%
624
            % (1) Adaptively filter the ACC signals
625
            % (2) Real Time PCA
626
            % (3) Mix PCs and reconstruct the signal
627
            %------------------- Input handling ----------------%
628
            if size(obj.Sig,1) < 3
629
                fprintf('|#| BioSigKit> ACC signal should be 3*n!');
630
                return;
631
            end
632
            
633
            output = ACC_Activity(obj.Sig,obj.Fs);
634
            % ------------------- Real Time PCA ------------------------ %
635
            PC = neural_pca(obj,3,2);
636
            PC = PC(:,1);
637
            ADR = output'*PC;
638
            ADR = detrend(ADR);
639
       end
640
       %% =================== Teager-Keiser Energy Op =========== %%
641
       function [ey,ex] = TK_comp(obj)
642
           % --------------- Outputs ----------------%
643
           % ey: energy operator
644
           % ex: Teager operator
645
           [ey,ex]=energyop(obj.Sig,obj.PlotResult);
646
       end
647
    end
648
end