%% Code Generation for a Deep Learning Simulink Model to Classify ECG Signals
% This example demonstrates how you can use powerful signal processing
% techniques and Convolutional Neural Networks together to classify ECG
% signals. We will also showcase how CUDA(R) code can be generated from the
% Simulink(R) model. This example uses the pretrained CNN network from the
% _Classify Time Series Using Wavelet Analysis and Deep Learning_ example
% of the Wavelet Toolbox(TM)  to classify ECG signals based on images from
% the CWT of the time series data. For information on training, see
% <docid:wavelet_ug#mw_1972856e-c413-4b6d-bc0a-8fd006ec8b8e Classify Time
% Series Using Wavelet Analysis and Deep Learning>.
%
% For a video demonstration on how to perform software-in-the-loop (SIL),
% processor-in-the-loop (PIL) simulation, and deploying this example to
% NVIDIA Jetson(R) board, see
% <https://www.mathworks.com/videos/deep-learning-in-simulink-for-nvidia-gpus-classification-of-ecg-signals-1621401016961.html>.
%
% This example illustrates the following concepts:
%
% * Model the classification application in Simulink. Use |MATLAB Function|
% blocks to perform preprocessing and wavelet transforms of the ECG data.
% Use the |Image Classifier| block from the Deep Learning Toolbox(TM) for
% loading the pretrained network and performing the classification of the
% ECG data.
% * Configure the model for code generation.
% * Generate a CUDA executable for the Simulink model.
%

% Copyright 2020-2021 The MathWorks, Inc.

%% Third-Party Prerequisites
%
% * CUDA enabled NVIDIA GPU.
% * NVIDIA CUDA toolkit and driver.
% * NVIDIA cuDNN library.
% * Environment variables for the compilers and libraries. For more
% information, see
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff Third-party
% Products> and <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% Environment Variables>.
%
%% Verify GPU Environment
% To verify that the compilers and libraries necessary for running this
% example are set up correctly, use the
% <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278
% coder.checkGpuInstall> function.
envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%% ECG Data Description
% This example uses ECG data from <https://physionet.org/ PhysioNet>
% database. It contains data from three groups of people:
%
% # Persons with cardiac arrhythmia (ARR)
% # Persons with congestive heart failure (CHF)
% # Persons with normal sinus rhythms (NSR)
%
% It includes 96 recordings from persons with ARR, 30 recordings from
% persons with CHF, and 36 recordings from persons with NSR. The
% |ecg_signals| MAT-file contains the test ECG data in time series format.
% The image classifier in this example distinguishes between ARR, CHF, and
% NSR.
%% Algorithmic Workflow
% The block diagram for the algorithmic workflow of the Simulink model is
% shown.
%
% <<../ECGBlockDiagram.jpg>>
%
%% ECG Deep Learning Simulink Model
% The Simulink model for classifying the ECG signals is shown. When the
% model runs, the |Video Viewer| block displays the classified ECG signal.
open_system('ecg_dl_cwt');

%% ECG Preprocessing Subsystem
% The |ECG Preprocessing| subsystem contains a |MATLAB Function| block that
% performs CWT to obtain scalogram of the ECG signal and then processes the
% scalogram to obtain an image and an |Image Classifier| block that loads
% the pretrained network from |trainedNet.mat| and performs prediction for
% image classification based on SqueezeNet deep learning CNN.
open_system('ecg_dl_cwt/ECG Preprocessing');

%%
% The |ScalogramFromECG| function block defines a function called
% |ecg_to_scalogram| that:
%
% * Uses 65536 samples of double-precision ECG data as input.
% * Create time frequency representation from the ECG data by applying
% Wavelet transform.
% * Obtain scalogram from the wavelet coefficients.
% * Convert the scalogram to image of size (227x227x3).
%
% The function signature of |ecg_to_scalogram| is shown.
type ecg_to_scalogram

%% ECG Postprocessing
% The |ECG Postprocessing| MATLAB function block defines the
% |label_prob_image| function that finds the label for the scalogram image
% based on the highest score from the scores outputed by the image
% classifier. It outputs the scalogram image with the label and confidence
% printed on it.
type label_prob_image

%% Run the Simulation
% Open Configuration Parameters dialog box.
%
% In *Simulation Target* pane, select *GPU acceleration*. In the *Deep
% Learning* group, select the target library as *cuDNN*.
%
% <<../SimulationTargetSettings.JPG>>
%
% To verify the algorithm and display the labels and confidence score of
% the test ECG signal loaded in the workspace, run the simulation.
set_param('ecg_dl_cwt', 'SimulationMode', 'Normal');
sim('ecg_dl_cwt');

%% Generate and Build the Simulink Model
% In *Code Generation* pane, select the *Language* as *C++* and enable
% *Generate GPU code*.
%
% <<../CodeGenerationSettings.png>>
%
% Open *Code Generation > GPU Code* pane. In the subcategory *Libraries*,
% enable *cuBLAS*, *cuSOLVER* and *cuFFT*.
%
% <<../GPUCodeSettings.JPG>>
%
% Generate and build the Simulink model on the host GPU by using the
% |slbuild| command. The code generator places the files in a _build
% folder_, a subfolder named |ecg_dl_cwt_ert_rtw| under your current
% working folder.
status = evalc("slbuild('ecg_dl_cwt')");
%% Generated CUDA(R) Code
% The subfolder named |ecg_dl_cwt_ert_rtw| contains the generated C++ codes
% corresponding to the different blocks in the Simulink model and the
% specific operations being performed in those blocks. For example, the
% file |trainedNet0_ecg_dl_cwt0.h| contains the C++ class which contains
% certain attributes such as |numLayers| and member functions such as
% |getBatchSize()|, |predict()|. This class represents the pretrained
% |SqueezeNet| which has been loaded in the Simulink model.
%
% <<../CodeTrainedNet.JPG>>
%
%% Cleanup
% Close the Simulink model.
close_system('ecg_dl_cwt/ECG Preprocessing');
close_system('ecg_dl_cwt');