Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

ECG recording, storing, filtering and recognition

, 14 Apr 2004
Full open code project for making driver and application software for ECG medical measurements.
ecg_dsp_src.zip
drvECG_1
drvECG_1.clw
drvECG_1.def
drvECG_1.dsp
drvECG_1.dsw
drvECG_1.exp
drvECG_1.ilk
drvECG_1.lib
res
Ecg_1
ECG_1.clw
ECG_1.dsp
ECG_1.dsw
ECG_DRAW.obj
ECG_Statistic_View.lib
ECG_VIEW.exp
ECG_VIEW.ilk
ECG_VIEW.lib
TestOCX.ocx
drvECG_1.exp
drvECG_1.ilk
drvECG_1.lib
resource.hm
res
ECG_1.ico
bitmap1.bmp
bmp00001.bmp
setup.bmp
ECG_Statistic_View
ECG_Statistic_View.clw
ECG_Statistic_View.def
ECG_Statistic_View.dsp
ECG_Statistic_View.dsw
res
ECG_VIEW
ECG_DRAW.obj
ECG_VIEW.APS
ECG_VIEW.clw
ECG_VIEW.def
ECG_VIEW.dll
ECG_VIEW.dsp
ECG_VIEW.dsw
ECG_VIEW.exp
ECG_VIEW.lib
res
testrecord2.zip
test_file1.zip
// ECG_1Dlg.cpp : implementation file
//

#include "stdafx.h"
#include "ECG_1.h"
#include "ECG_1Dlg.h"
#include "MCP3002.h"
#include "DSP_Filter.h"
#include "Ecg_Draw.h"
#include "Statistic_View.h"
#include "ECG_Data.h"
#include "DlgVeloTest.h"
#include "DlgConfirm.h"
#include "DlgPulseMeter.h"
#include "DSP_ECG.h"
#include "Person.h"
#include "Ecg_Info.h"
#include "DlgDSPAll.h"

#include "DlgPersonal.h"
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

UINT SmplProcess(LPVOID param)
{
	CECG_1Dlg* dlg = (CECG_1Dlg*) param;
	int p_DX,p_DY = 0;
	
	CRect rcClient;
	CRect Progress;

	dlg->GetClientRect(rcClient);

	p_DX = 55 + rcClient.Width()/2;
	p_DY = 60 + rcClient.bottom/2;

	//Move the progres windoe to the center of the dialog
	//then recize it to be 300x40 points
	Progress.SetRect(p_DX-150,p_DY-20,
		p_DX+150,p_DY+20);
	dlg->m_ctlSampling.MoveWindow(Progress,TRUE);
	dlg->m_ctlSampling.SetPos(0);
	for(int i=1;i<21;i++)
	{
		dlg->m_ctlSampling.SetPos(i);
		Sleep(450);		
		//if start stop is =0 we must stop the procrs control
		if(dlg->b_start_stop==0)
		{
			i=21;
		}
	}
	dlg->m_ctlSampling.MoveWindow(0,0,0,0);
	return 0;
}

static void EndSampleNotification(void* obj,unsigned short *ch_0,unsigned short *ch_1,int lenght,CTime start,CTime end);


/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	afx_msg void OnBok();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)

	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}
void CAboutDlg::OnBok() 
{
	// TODO: Add your control notification handler code here
	CAboutDlg::OnOK();
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	ON_BN_CLICKED(IDC_BOK, OnBok)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CECG_1Dlg dialog

CECG_1Dlg::CECG_1Dlg(CWnd* pParent /*=NULL*/)
	: CDialog(CECG_1Dlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CECG_1Dlg)
	m_bmppos = 0;
	m_sComment = _T("");
	m_b50hz = FALSE;
	m_b60hz = FALSE;
	m_b40hzlol = FALSE;
	m_bw50noht = FALSE;
	m_bw45low = FALSE;
	m_bw067hz = FALSE;
	m_select_segment = -1;
	m_srecord = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CECG_1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CECG_1Dlg)
	DDX_Control(pDX, IDC_BCORECT, m_ctlcorect);
	DDX_Control(pDX, IDC_LDATA, m_ctldata);
	DDX_Control(pDX, IDC_BRECORD, m_ctlRecord);
	DDX_Control(pDX, IDC_SLIDBMP, m_ctlBmp);
	DDX_Control(pDX, IDC_PSAMPLING, m_ctlSampling);
	DDX_Slider(pDX, IDC_SLIDBMP, m_bmppos);
	DDX_Text(pDX, IDC_ECOMMENT, m_sComment);
	DDX_Check(pDX, IDC_C50HZ, m_b50hz);
	DDX_Check(pDX, IDC_C60HZ, m_b60hz);
	DDX_Check(pDX, IDC_C40LOL, m_b40hzlol);
	DDX_Check(pDX, IDC_CW50HZ, m_bw50noht);
	DDX_Check(pDX, IDC_CW40HZ, m_bw45low);
	DDX_Check(pDX, IDC_CW067, m_bw067hz);
	DDX_Radio(pDX, IDC_RADIO1, m_select_segment);
	DDX_Text(pDX, IDC_SRECORDS, m_srecord);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CECG_1Dlg, CDialog)
	//{{AFX_MSG_MAP(CECG_1Dlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BRECORD, OnBrecord)
	ON_WM_HSCROLL()
	ON_BN_CLICKED(IDC_BSHOWBMP, OnBshowbmp)
	ON_BN_CLICKED(IDC_BTEST, OnBtest)
	ON_BN_CLICKED(IDC_BINVERTECG, OnBinvertecg)
	ON_BN_CLICKED(IDC_BLOW, OnBlow)
	ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
	ON_BN_CLICKED(IDC_BPRINT, OnBprint)
	ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
	ON_BN_CLICKED(IDC_BDELTA, OnBdelta)
	ON_BN_CLICKED(IDC_BDELTA2, OnBdelta2)
	ON_BN_CLICKED(IDC_BDELTAREVERSE, OnBdeltareverse)
	ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
	ON_BN_CLICKED(IDC_BDELTAREVERSE2, OnBdeltareverse2)
	ON_LBN_SELCHANGE(IDC_LDATA, OnSelchangeLdata)
	ON_BN_CLICKED(IDC_BCORECT, OnBcorect)
	ON_COMMAND(ID_FILE_EXIT, OnFileExit)
	ON_COMMAND(ID_FILE_SAVE, OnFileSave)
	ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
	ON_COMMAND(ID_FILE_NEW, OnFileNew)
	ON_COMMAND(ID_INFO_ECG, OnInfoEcg)
	ON_COMMAND(ID_INFO_PERSONAL, OnInfoPersonal)
	ON_BN_CLICKED(IDC_BSAVEBMP, OnBsavebmp)
	ON_COMMAND(ID_INFO_CONFIRM, OnInfoConfirm)
	ON_WM_CONTEXTMENU()
	ON_BN_CLICKED(IDC_BRECALCALL, OnBrecalcall)
	ON_BN_CLICKED(IDC_BEXIT, OnBexit)
	ON_COMMAND(ID_HELP_ABOUTECG1, OnHelpAboutecg1)
	ON_BN_CLICKED(IDC_BWFLOW, OnBwflow)
	ON_BN_CLICKED(IDC_BWFNOHT50HZ, OnBwfnoht50hz)
	ON_BN_CLICKED(IDC_BWFLOW40HZ, OnBwflow40hz)
	ON_COMMAND(ID_DSP_NOHT50HZ, OnDspNoht50hz)
	ON_COMMAND(ID_DSP_LOW100HZ, OnDspLow100hz)
	ON_COMMAND(ID_DSP_HIGH0025HZ, OnDspHigh0025hz)
	ON_COMMAND(ID_DSP_ECGANALYSIS, OnDspEcganalysis)
	ON_COMMAND(ID_DSP_LOW40HZ, OnDspLow40hz)
	ON_BN_CLICKED(IDC_BSAVEBMP2, OnBsavebmp2)
	ON_BN_CLICKED(IDC_C50HZ, OnC50hz)
	ON_BN_CLICKED(IDC_C60HZ, OnC60hz)
	ON_BN_CLICKED(IDC_C40LOL, OnC40lol)
	ON_BN_CLICKED(IDC_CW50HZ, OnCw50hz)
	ON_BN_CLICKED(IDC_CW40HZ, OnCw40hz)
	ON_BN_CLICKED(IDC_CW067, OnCw067)
	ON_BN_CLICKED(IDC_BAMPL, OnBampl)
	ON_BN_CLICKED(IDC_BDSPALL, OnBdspall)
	ON_BN_CLICKED(IDC_RADIO1, OnRadio1)
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(ID_ECGINFO_PERSONAL, OnInfoPersonal)
	ON_BN_CLICKED(IDC_RADIO2, OnRadio1)
	ON_BN_CLICKED(IDC_RADIO3, OnRadio1)
	ON_BN_CLICKED(IDC_RADIO4, OnRadio1)
	ON_BN_CLICKED(IDC_BECGPRINT, OnBecgprint)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CECG_1Dlg message handlers

BOOL CECG_1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	//Make dlg_pulse_meter modless
	dlg_pulse_meter.Create(IDD_DPULSEMETER,this);
	//set bool variable to show our program that dlg_pulse_meter is closed
	b_dlgPulseMeter = 0;
	//
	dlg_pulse_meter.s_CurrPulse = "0";
	dlg_pulse_meter.s_PastPulse = "0";


	//Calculate win-syncc filter kernels
	//for sampling rate 500hz
	dsp_flf.LoadFilterKernels(500);
	i_fsmpl = 500;
	//////////////////////////////
	m_select_segment = 3;

	//Sets the filter defaut
	m_b50hz=1;
	m_b40hzlol=1;
	s_filter_input = "";
	//Set BMP view type to view ECG records
	i_bmp = 0;
	
	m_ctlSampling.SetRange(0,20);
	m_ctlBmp.SetRange(0,4);
	s_ECG_Info = "QRS ?";
	i_old_ctldata_index = 0;
	GetDlgItem(IDC_BCORECT)->EnableWindow(FALSE);
	//set the start stop variable to be stopped
	b_start_stop = 0;
	//Set the QRS measurement variables
	i_QRS_count=0;
	i_QRS_ms=0;
	i_PR_ms=0;
	i_QT_QTc_ms=0;
	hh = 0;
	mm = 0;
	//Must be done this initialization
	TStart = 0;
	///////////////////////////////////
	ZeroArr(AR_ECG,5000);
	ZeroArr(AR_REV,5000);
	m_sComment = "";
	//Unvisible sampling process control
	m_ctlSampling.MoveWindow(0,0,0,0);
	UpdateData(false);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CECG_1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CECG_1Dlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
		//redraw BMP with ECG
		if(i_bmp==0)
			OnButton1();
		//else draw statistical info
		if(i_bmp==1)
			OnButton3();

	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CECG_1Dlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CECG_1Dlg::OnBrecord() 
{
	// TODO: Add your control notification handler code here
	//Before starting sampling deletes previous AR_ECG and AR__REV
	//function is stopped
	UpdateData(true);
	if(b_start_stop == 0)
	{
		//Open dialog to show measured pulse

		ShowPulseDialog();
		//Start sampling process
		StartSampling();
	}
	//function is active
	else
	{
		StopSampling();
		//close pulse dialog if it was created
		HidePulseDialog();
	}

}

void EndSampleNotification(void* obj,unsigned short *ch_0,unsigned short *ch_1,int lenght,CTime start,CTime end)
{
	CECG_1Dlg* dlg = (CECG_1Dlg*) obj;
	dlg->TStart = start;
	dlg->s_ECG_Info.Format("%d:%d",start.GetHour(),
		start.GetMinute());
	dlg->hh = start.GetHour();
	dlg->mm = start.GetMinute();
	
	//filtering and copying
	dlg->CopyFromSample(ch_0,ch_1,lenght);
	//First we need to copy sampled arrays in to a program arrays
	//if start stop flag is =1 then after conversion set window text
	//to show that we can make a new conversion
	if(dlg->b_start_stop == 1)
	{
		//Copy sampled data in to the ECG_DATA class 
		dlg->SetData(dlg->AR_ECG,2500);
		
		dlg->m_ctldata.AddString(dlg->s_ECG_Info);
		//Show pulse on pulse meter dialog
		dlg->ShowCurrPulse(dlg->m_ctldata.GetCount());
		dlg->StartSampling();	
	}
	if(dlg->b_start_stop == 0)
	{
	//	dlg->b_start_stop = 0;
		dlg->m_ctlRecord.SetWindowText("Star Record");
		dlg->m_ctldata.AddString(dlg->s_ECG_Info);
	}
}

void CECG_1Dlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
	UpdateData(true);
	OnButton1();
	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CECG_1Dlg::CopyFromSample(unsigned short *ar0, unsigned short *ar1, int lenght)
{
	//memmove does not work!!!
	for(int i=0;i<lenght;i++)
	{
		AR_ECG[i] = double(*(ar0+i));
		AR_REV[i] = double(*(ar1+i));
	}
	//Calculate the signal mean
	//Normalize array
	dsp_flf.SetArrToNormalize(&AR_ECG[0],lenght);
	dsp_flf.SetArrToNormalize(&AR_REV[0],lenght);
	//Low filtr
//	dsp_flf.Filter_High(AR_ECG,AR_ECG,5000,1,500,0.000001);
	//If noht filter was selected use it 2 times
	s_filter_input = "";
	if(m_b50hz==1)
	{
		dsp_flf.RFilter_Noht(&AR_ECG[0],lenght,500,50,0.005);
		dsp_flf.RFilter_Noht(&AR_ECG[0],lenght,500,50,0.005);
		s_filter_input = s_filter_input + " 2x50Hz Rnoht/";
	}
	//if noht filter was selected use it 2 times
	if(m_b60hz==1)
	{
		dsp_flf.RFilter_Noht(&AR_ECG[0],lenght,500,60,0.01);
		dsp_flf.RFilter_Noht(&AR_ECG[0],lenght,500,60,0.01);
		s_filter_input = s_filter_input + " 2x60Hz Rnoht/";
	}
	//If lol filter was selected use it
	if(m_b40hzlol==1)
	{
		dsp_flf.RFilter_Low(&AR_ECG[0],lenght,500,0.51);	
		s_filter_input = s_filter_input + " 1x40Hz Rlow/";
	}
	if(m_bw45low==1)
	{
		dsp_flf.WFilter_Low40Hz(AR_ECG,AR_ECG,lenght,500,40);
	//	dsp_flf.WFilter_Low40Hz(AR_ECG,AR_ECG,lenght,500,40);
		s_filter_input = s_filter_input + " 1x40Hz Wlol/";
	}
	if(m_bw50noht==1)
	{
		dsp_flf.WFilter_Noht(AR_ECG,AR_ECG,lenght,500,50);
		dsp_flf.WFilter_Noht(AR_ECG,AR_ECG,lenght,500,50);
		s_filter_input = s_filter_input + " 2x50Hz Wnoht/";
	}
	if(m_bw067hz==1)
	{
		dsp_flf.WFilter_High(&AR_ECG[0],&AR_ECG[0],
			5000,-1,500,0.0001);
		s_filter_input = s_filter_input + " 1x>0.67Hz Whigh/";
	}

	if(s_filter_input=="")
		s_filter_input = " NO FILTER";
	//Resample signal from500Hz to 250Hz
	int k = Resample(&AR_ECG[0],&AR_ECG[0],lenght,500,250);
	//After this we can draw a bitmap with sampled arrays
	OnBtest();
	
}

void CECG_1Dlg::OnOK() 
{
	// TODO: Add extra validation here

}

void CECG_1Dlg::OnBshowbmp() 
{
	// TODO: Add your control notification handler code here
//	dsp_flf.Filter_Low(&AR_ECG[0],5000,500,0.05);
	dsp_flf.SetArrToNormalize(&AR_ECG[0],5000);	
	dsp_flf.RFilter_Noht(&AR_ECG[0],5000,250,50,0.017);
	
	OnBtest();
}

int CECG_1Dlg::Resample(double *dest, double *source, int lenght, int fold, int fnew)
{
	int k;
	k = fold/fnew;
	for(int i=0;i<lenght/k;i++)
	{
		*(dest+i) = *(source+i*k);
	}
	//Zero end of the array
	for(i=lenght/k;i<lenght;i++)
	{
		*(dest+i) = 0;
	}
	return k;
}

void CECG_1Dlg::SamplingProcess()
{
	//Begins a new thread to visualize sampling process
	AfxBeginThread(SmplProcess,this);
	SetThreadPriority(SmplProcess,THREAD_PRIORITY_NORMAL);
}

void CECG_1Dlg::OnBtest() 
{
	//Pass curr record throught the ECG_DSP
	dsp_ecg.SetECG(AR_ECG,2500,AR_REV,&i_QRS_count,&i_QRS_ms,
		&i_PR_ms,&i_QT_QTc_ms,m_select_segment);
	//Format the ECG record intervals info
	s_ECG_Info.Format("%d:%d Pulse-rate %d/min, QRSint.%dms, PRint.%dms, QTint.%dms",
		hh,mm,i_QRS_count,i_QRS_ms,i_PR_ms,i_QT_QTc_ms);
	
	OnButton1();
}

void CECG_1Dlg::OnBinvertecg() 
{
	// TODO: Add your control notification handler code here
	//Inverst the array ECG
	dsp_flf.InvertArr(&AR_ECG[0],&AR_ECG[0],5000);
	//Inverts the array REV
	dsp_flf.InvertArr(&AR_REV[0],&AR_REV[0],5000);
	OnBtest() ;
}

int CECG_1Dlg::CountQRS(double *ECG, int lenght)
{
	int D = 0;
/*	int Delta[5000];
	int Deltamin[5000];
	for(int i=0;i<lenght;i++)
	{
		*(AR_REV+i) = 0;
		Deltamin[i]= 0;
	}
	for(i=0;i<lenght-1;i++)
	{
		D = int(*(ECG+i+1) - *(ECG+i));
		Delta[i] = D;
		if(D>16)
		*(AR_REV+i) = 2;
		if(D<-16)
		*(AR_REV+i) = -2;
	}
	D = 0;
	int d_count;
	for(i=0;i<lenght-1;i++)
	{	
		d_count=0;
		if(*(AR_REV+i)==2)
		{	//*(AR_REV+i-1)=400;//find the delta begining
			
			do{	i++;d_count++;}
			while(*(AR_REV+i)==2);
			int max=i;
			do{max++;}
			while(*(AR_REV+max)==2);
			*(AR_REV+max) = *(AR_ECG+max);//fing max after delta+

			do{max++;}
			while(*(AR_REV+max)<0);
			*(AR_REV+max+1) = *(AR_ECG+max);//find min after max
	
			max = i;
			do{max--;}
			while(Delta[max]>0);
			*(AR_REV+max+2) = *(ECG+max+1);//find min after d-

			if(d_count>2)
			{D++;
			//*(AR_REV+i) = 400;//end of the delta+
			}
		}
	}
	//D contains QRS/10s to convert it in QRS/min
	//we must multiply it by 6, because 1 min contains 60 seconds
	i_QRS_count = D*6;
	//Format the QRS count in to text string
	s_ECG_Info.Format("%d:%d QRS %d/min",hh,mm,i_QRS_count);
*/	return D;
}

void CECG_1Dlg::OnBlow() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.RFilter_Low(&AR_ECG[0],5000,250,0.62);
	OnBtest();
}

void CECG_1Dlg::OnButton2() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.WFilter_High(&AR_ECG[0],&AR_ECG[0],
		5000,-1,250,0.0001);//255Hz*0.001 = 0.225
	OnBtest() ;
}

void CECG_1Dlg::OnBprint() 
{
	// TODO: Add your control notification handler code here
	CPrintDialog dlgPrint(FALSE,PD_ALLPAGES ,this);
	if(dlgPrint.DoModal()==IDOK)
	{
		CDC dcPrint;
		dcPrint.Attach(dlgPrint.GetPrinterDC());
	//	dcPrint.SetMapMode(MM_LOMETRIC);
		DOCINFO myPrintJob;
		myPrintJob.cbSize = sizeof(myPrintJob);
		myPrintJob.lpszDocName = "MyPrintJob";
		myPrintJob.lpszOutput = NULL;
		myPrintJob.lpszDatatype = NULL;
		myPrintJob.fwType = NULL;
		if(dcPrint.StartDoc(&myPrintJob)>=0)
		{
			dcPrint.StartPage();
			CString str;
			for(int i=1;i<10;i++)
			{
				str.Format("points %d lenght",100*i);
				dcPrint.MoveTo(10,100*i);
				dcPrint.TextOut(10,100*i,str);
				dcPrint.LineTo(100*i,100*i);
			}
			
				dcPrint.MoveTo(100,100);
				dcPrint.LineTo(1000,100);
			dcPrint.EndPage();
			dcPrint.EndDoc();
		}

		dcPrint.DeleteDC();
	}
}

void CECG_1Dlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	i_bmp = 0;
	CRect rcClient;
	GetClientRect(rcClient);
	CClientDC dc(this);
	int x,y;
	y = 100;
	x = 220;
	rcClient.SetRect(x,y,x+500,y+500);
	ecg_draw.SetArr(&AR_ECG[0],&AR_REV[0],5000);
	
	ecg_draw.SetEcgInfo(s_ECG_Info);
	ecg_draw.SetEcgDrawRect(&dc,rcClient,m_bmppos*500,m_bmppos*500+500);

	//Set the redraw type to be bmp_ecg
	if(i_bmp==1)
		i_bmp = 0;
}

void CECG_1Dlg::OnBdelta() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.RFilter_Low(AR_ECG,5000,250,0.1);
	dsp_flf.Delta1(AR_REV,AR_ECG,5000);
	OnButton1();
}

void CECG_1Dlg::OnBdelta2() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.RFilter_Low(AR_ECG,5000,250,0.1);
	dsp_flf.Delta2(AR_REV,AR_ECG,5000);
	OnButton1();
}

void CECG_1Dlg::OnBdeltareverse() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.DeltaReverse1(AR_REV,AR_REV,5000);
	OnButton1();
}

void CECG_1Dlg::StartSampling()
{
	cur_index=0;
	//Starts the sampling process
	//before this format the date
	SetTestdate();
	m_ctlRecord.SetWindowText("End Record");
	mcp3002.SetEndSampleNotification(this,EndSampleNotification);
	
	//Loads filter kernels for 500Hz
	dsp_flf.LoadFilterKernels(500);
	mcp3002.MMT_Start(0x378);
	//Visualize process with time bar
	SamplingProcess();
	b_start_stop = 1;

}

void CECG_1Dlg::StopSampling()
{
	//End the sampling process
	mcp3002.MMT_Stop();
	m_ctlRecord.SetWindowText("Star Record");
	//Loads filter kernels for 250Hz
	dsp_flf.LoadFilterKernels(250);
	b_start_stop = 0;
//	GetDlgItem(IDC_BRECORD)->EnableWindow(false);
}

void CECG_1Dlg::OnButton3() 
{
	// TODO: Add your control notification handler code here
	//Set the redraw type to be bmp_statistic
	if(i_bmp==0)
		i_bmp = 1;
	//Count all qrs min
	CountQRSmin();
//	CountAllQRS();
//	dsp_flf.Message(QRS_MIN_COUNT.GetSize());
	CRect rcClient;
	GetClientRect(rcClient);
	CClientDC dc(this);
	int x,y;
	y = 100;
	x = 220;
	double Qrscount[2500];
	double pwt[2500];
	for(int i=0;i<2500;i++)
	{
		Qrscount[i]=1;
		pwt[i]=10;
	}
	for(i=0;i<QRS_MIN_COUNT.GetSize();i++)
	{
		Qrscount[i] = QRS_MIN_COUNT.GetAt(i);
		pwt[i] = Qrscount[i] * 2 + rand()%50 - rand()%50;
		//pwt[i] = 100;//
	}
	dsp_flf.RFilter_Low(pwt,1000,100,0.45);
//	dsp_flf.Message(i);//OK
	rcClient.SetRect(x,y,x+500,y+200);
	statistic_draw.SetArr(Qrscount,pwt,2500);
	
	CString str;
	str = "      (Y=pulse & power rates, X=minutes)";
	str = "Test date "+
		ecg_data.ecg_info.velo_test_date.Format("%Y-%mm-%dd  Start at %H:%M")+
		str;
	statistic_draw.SetInfo(str);
	statistic_draw.SetEcgDrawRect(&dc,rcClient,m_bmppos*500,m_bmppos*500+500);
	
}

void CECG_1Dlg::OnBdeltareverse2() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.DeltaReverse2(AR_REV,AR_REV,5000);
	OnButton1();
}

void CECG_1Dlg::SetData(double *source, int lenght)
{
	//Adds new portion of sampled data to the ECG_DATA DATA
	//word array
	m_sComment = "Used filters:"+ s_filter_input;
	ecg_data.SetDataNew(source,lenght,m_sComment,i_QRS_count,
		i_QRS_ms,i_PR_ms,i_QT_QTc_ms,hh,mm);
}

void CECG_1Dlg::OnSelchangeLdata() 
{
	// TODO: Add your control notification handler code here
	int index = m_ctldata.GetCurSel();
	//If there are something in the list box
	//enable corect button
	if(index>=0)
	{
		GetDlgItem(IDC_BCORECT)->EnableWindow(TRUE);
		i_old_ctldata_index = index;
		
		m_srecord.Format("Record %d of %d",index,m_ctldata.GetCount()-1);
		UpdateData(false);

		GetDataFrom(AR_ECG,index,2500);
		dsp_flf.SetArrToNormalize(AR_ECG,2500);
		OnBtest();
	}
	
}

void CECG_1Dlg::GetDataFrom(double *dest,int start, int lenght)
{
	UpdateData(true);
	ecg_data.GetFrom(dest,start*lenght,lenght);
	//Gets the info about the recorded segment
	//GetInfoFrom returns the CString comment about the segment
	m_sComment = ecg_data.GetInfoFrom(start,&i_QRS_count,
		&i_QRS_ms,&i_PR_ms,&i_QT_QTc_ms,&hh,&mm);

	i_QRS_count = ecg_data.GetQRSCount(start);
	s_ECG_Info.Format("%d:%d QRS %d /m",hh,mm,i_QRS_count);
	UpdateData(false);
}

void CECG_1Dlg::SetDataAt(double* source,int start,int lenght)
{
	UpdateData(true);
	ecg_data.SetDataAt(source,start*lenght,lenght);
	//Sets the info about the ECG segment
	ecg_data.SetInfoAt(start,m_sComment,i_QRS_count,
		i_QRS_ms,i_PR_ms,i_QT_QTc_ms,hh,mm);
	UpdateData(false);
}

void CECG_1Dlg::OnBcorect() 
{
	// TODO: Add your control notification handler code here

	//This function sets data in to ecg_data class
	SetDataAt(AR_ECG,i_old_ctldata_index,2500);
	//Disable control correct, because the correction was done
	GetDlgItem(IDC_BCORECT)->EnableWindow(FALSE);
	//Gets the selected index string
	ecg_data.GetInfoFrom(i_old_ctldata_index,&i_QRS_count,&i_QRS_ms,
	&i_PR_ms,&i_QT_QTc_ms,&hh,&mm);

	CString str;
	str.Format("%d:%d  %d�/���",hh,mm,i_QRS_count);
	
	//delete the selected string
	m_ctldata.DeleteString(i_old_ctldata_index);
	//insert new value at his position
	m_ctldata.InsertString(i_old_ctldata_index,str);
	//after this remember the last selection 
	m_ctldata.SetCurSel(i_old_ctldata_index);

}

void CECG_1Dlg::OnFileExit() 
{
	// TODO: Add your command handler code here
	OnBexit();
}

void CECG_1Dlg::OnFileSave() 
{
	// TODO: Add your command handler code here
	//If sampling is active stop it now!
	StopSampling();
	//close pulse dialog if it is neaded
	HidePulseDialog();
	//Load variables to dlg_personal
	SetPersonal();
	//Opens the personal info dlg to confirm before saving
	int result = dlg_personal.DoModal();
	if(result == IDOK)
	{//If the info was confirmed  read 
	//confirmed info from dlg_personal
	//and set it in to ecg_data.personal
		GetPersonal();

		CString FileName;
		CFileDialog m_lFile(FALSE);

		m_lFile.m_ofn.lpstrFilter = "ECG\0*.ecg";
		m_lFile.m_ofn.lpstrDefExt = ".ecg";
		if(m_lFile.DoModal()==IDOK)
		{
			FileName = m_lFile.GetFileName();
			ecg_data.SaveData(FileName);
		}
	}
}

void CECG_1Dlg::OnFileOpen() 
{
	// TODO: Add your command handler code here
	//If sampling is active stop it now!
	StopSampling();

	CString FileName;
	CFileDialog m_lFile(TRUE);
	m_lFile.m_ofn.lpstrFilter = "ECG\0*.ecg";
	m_lFile.m_ofn.lpstrDefExt = ".ecg";
	if(m_lFile.DoModal()==IDOK)
	{
		FileName = m_lFile.GetFileName();
		ecg_data.OpenFile(FileName);
		//Confirm personal information
		SetPersonal();
		//open the dialog with personal data
		int result = dlg_personal.DoModal();	
		//If dialog was closed
		if(result == IDOK)
		{
			//read confirmed data and set it to ecg_data.person
			GetPersonal();
			//Full the list box with a new values
			OnBrecalcall();
			dsp_flf.LoadFilterKernels(250);
		//	char title[30];
		//	CECG_1Dlg::GetWindowText(title,30);
		//	CString sTitle = LPCSTR(title);
			CECG_1Dlg::SetWindowText("ECG_1 Test Version   File: "+FileName);
		//	EnableControls();
		}
	}
}

void CECG_1Dlg::OnFileNew() 
{
	//Stop sampling 
	StopSampling();
	//close pulse dialog if it is neaded
	HidePulseDialog();
	//Clear person values
	ClearPersonal();
	//clear ECG info section
	ClearECGInfo();
	// TODO: Add your command handler code here
	int result = dlg_personal.DoModal();
	if(result==IDOK)
	{
		GetPersonal();
		NewECG();
		//Reload filter kernels for sampling rate 500Hz
		dsp_flf.LoadFilterKernels(500);
	}
}

void CECG_1Dlg::NewECG()
{
	//Stops the sampling process
	StopSampling();
	//Clear ecg_data arrays
	ecg_data.RemoveAll();
	m_ctldata.ResetContent();
	s_ECG_Info = "?";
	//Clear the AR_ECG
	ZeroArr(AR_ECG,5000);
	ZeroArr(AR_REV,5000);
	//Do new drawing and calculations
	OnBtest();
}

void CECG_1Dlg::ZeroArr(double *dest, int lenght)
{
	for(int i=0;i<lenght;i++)
	{
		*(dest+i) = 0;
	}
}

void CECG_1Dlg::CountQRSmin()
{
	int min_count = 0;
	if(QRS_MIN_COUNT.GetSize()>0)
		QRS_MIN_COUNT.RemoveAll();

	int lenght = ecg_data.TIME.GetSize();
//	dsp_flf.Message(lenght);//OK
	if(lenght>0)
	{
		CWordArray min;
		CWordArray qrs_c;
		BYTE h,m=0;

		//Copy all QRS_counts in to rate_min
		for(int i=0;i<lenght;i++)
		{
			ecg_data.GetPosTime(i,&h,&m);
			min.Add(m);
			qrs_c.Add(ecg_data.GetQRSCount(i));
		}
		BYTE m_old;
		int count = 0;
		double mean=0;
		int pos=0;
		i=0;

		int corect=0;
		do
		{
			count=0;
			mean=0;
			m_old=min.GetAt(pos);
		//	dsp_flf.Message(m_old);
			do
			{
				mean = mean + qrs_c.GetAt(i);
				i++;
				count++;
				if(i>=min.GetSize())
					corect=-1;
			}
			while((m_old == min.GetAt(i+corect))&(i<min.GetSize()));
		//	dsp_flf.Message(i-pos);
			mean = mean/count;
		//	dsp_flf.Message(mean);
			QRS_MIN_COUNT.Add(int(mean));
			pos = i;//
		}
		while(pos<min.GetSize());
	}		
}

void CECG_1Dlg::GetPersonal()
{
	//reads the personel data from dlg_personal
	//and set it in to the ecg_data.person
	ecg_data.person.sEGN = dlg_personal.m_sEGN;
	ecg_data.person.Birth_Date = dlg_personal.m_birthdate;
	ecg_data.person.sName_1 = dlg_personal.m_sName1;
	ecg_data.person.sName_2 = dlg_personal.m_sName2;
	ecg_data.person.sName_3 = dlg_personal.m_sName3;
	ecg_data.person.Sex = dlg_personal.m_sSex;

	ecg_data.person.sAddress = dlg_personal.m_sAddress;
	ecg_data.person.sPhone = dlg_personal.m_sPhone;

}

void CECG_1Dlg::SetPersonal()
{
	//get the data from ecg_data.person
	//and set it in to the dlg_personal variables
	//to lett the user confirm it
	dlg_personal.m_sEGN = ecg_data.person.sEGN;
	//if birthdate == 0 set it to some value
	if(ecg_data.person.Birth_Date == 0)
		ecg_data.person.Birth_Date.SetDate(2000,01,01);

	dlg_personal.m_birthdate = ecg_data.person.Birth_Date;
	dlg_personal.m_sName1 = ecg_data.person.sName_1;
	dlg_personal.m_sName2 = ecg_data.person.sName_2;
	dlg_personal.m_sName3 = ecg_data.person.sName_3;
	dlg_personal.m_sSex = ecg_data.person.Sex;

	dlg_personal.m_sAddress = ecg_data.person.sAddress;
	dlg_personal.m_sPhone = ecg_data.person.sPhone ;

}

void CECG_1Dlg::ClearPersonal()
{
	dlg_personal.m_sEGN = "";
	dlg_personal.m_birthdate.SetDate(2000,01,01);
	dlg_personal.m_sName1 = "";
	dlg_personal.m_sName2 = "";
	dlg_personal.m_sName3 = "";
	dlg_personal.m_sSex = "";

	dlg_personal.m_sAddress = "";
	dlg_personal.m_sPhone = "" ;

}

void CECG_1Dlg::OnInfoEcg() 
{
	// TODO: Add your command handler code here
	//open a ECG statistical info dialog

	//calculate statistic meandevmaxmin
	ECG_Statistic();
	//Format the CString variables at velo_test dialog
	FormatTestDlg();
	////////////////////////////
	
	//open dialog
	int result = dlg_velo_test.DoModal();
	if(result == IDOK)
	{
		//Update the velo test info
		//Because we have no sensors for blood preasure put the values handly
		//temperature too
		ecg_data.ecg_info.BloodPreasure.iMean = 
			atoi(dlg_velo_test.m_sbloodpreaure);
		ecg_data.ecg_info.Temperature.iMean =
			atoi(dlg_velo_test.m_stemperature);
	}
}

void CECG_1Dlg::OnInfoPersonal() 
{
	// TODO: Add your command handler code here
	//Wieu the personal information to confirm
	SetPersonal();
	int result = dlg_personal.DoModal();
	if(result == IDOK)
	{
		//Update the personal info
		GetPersonal();
	}
}

int CECG_1Dlg::GetQRSmean()
{
	CWordArray QRScount;
	//Counts the mean QRS for all records
	double count = 0;
	int lenght = ecg_data.GetAllDataLenght()/2500;
	for(int i=0;i<lenght;i++)
	{
		QRScount.Add(ecg_data.GetQRSCount(i));
	}
	//calculate the mean
	for(i=0;i<lenght;i++)
	{
		count = count + QRScount.GetAt(i);
	}
	count = count/lenght;
	QRScount.RemoveAll();
//	dsp_flf.Message(count);
	return int(count);
}

void CECG_1Dlg::SetTestdate()
{
	//Sets current date when starts the measurement
	//if this is old measurement we do not need to set date
	if(ecg_data.ecg_info.velo_test_date==0)
	{
		//if tere are no any date set it
		ecg_data.ecg_info.velo_test_date=
			COleDateTime::GetCurrentTime();
	}
}

void CECG_1Dlg::OnBsavebmp() 
{
	// TODO: Add your control notification handler code here
	if(ecg_data.GetAllDataLenght()/2500>0)
	{
		//Set personal info for print form
		CPerson* lpPerson;
		lpPerson = &ecg_data.person;
		CEcg_Info* lpEcg_Info;
		lpEcg_Info = &ecg_data.ecg_info;

		ecg_draw.PrintBMP(lpPerson);
	}
}

void CECG_1Dlg::OnInfoConfirm() 
{
	// TODO: Add your command handler code here
	//Check for data in ecg_info section
	if(ecg_data.ecg_info.Confirm_By=="")
		//if there are no any name set something
		ecg_data.ecg_info.Confirm_By = "NO NAME";
	if(ecg_data.ecg_info.Conclusion=="")
		//if there are no conclusion set something
		ecg_data.ecg_info.Conclusion = "NOT CONFIRMED";
	//set dlg_confirm variables
	dlg_confirm.m_sName = ecg_data.ecg_info.Confirm_By;
	dlg_confirm.m_sConclusion = ecg_data.ecg_info.Conclusion;
	
	if(dlg_confirm.DoModal()==IDOK)
	{
		//read the values about name and conclusion
		ecg_data.ecg_info.Confirm_By = dlg_confirm.m_sName;
		ecg_data.ecg_info.Conclusion = dlg_confirm.m_sConclusion;
	}
}

void CECG_1Dlg::ClearECGInfo()
{
	//Clear section of data.ecg_info
	ecg_data.ecg_info.Confirm_By = "";
	ecg_data.ecg_info.Conclusion = "";
	//Clear all ecg_info
}

void CECG_1Dlg::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	// TODO: Add your message handler code here
	CMenu menu;
	menu.LoadMenu(IDR_CONTEXTMENU);
	CRect rect;
	m_ctldata.GetWindowRect(rect);
	int x = point.x;
	int y = point.y;
	//if mouse is on m_ctldata rect
	if(x>rect.left&x<rect.right&y>rect.top&y<rect.bottom)
	{
		CMenu* pContextMenu = menu.GetSubMenu(0);
	
		pContextMenu->TrackPopupMenu(TPM_CENTERALIGN+
			TPM_LEFTBUTTON,
			point.x,point.y,pWnd,NULL);
	}
	//if mous is on BMP rect
	if(x>251&x<750&y>196&y<449)
	{
		CMenu* pContextMenu = menu.GetSubMenu(1);
	
		pContextMenu->TrackPopupMenu(TPM_CENTERALIGN+
			TPM_LEFTBUTTON,
			point.x,point.y,pWnd,NULL);
	}
}

void CECG_1Dlg::OnBrecalcall() 
{
	// TODO: Add your control notification handler code here
	//This function recalculates all ECG data segment
	//to find the QRS count
	int count = ecg_data.GetAllDataLenght()/2500;
	if(count>0)
	{
		CString str;
		//because we will recalculate all data
		//we can remove it 
		m_ctldata.ResetContent();
		for(int i=0;i<count;i++)
		{
			//reads data from i*2500 to i*2500+2500
		//	GetDataFrom(AR_ECG,i,2500);
			ecg_data.GetInfoFrom(i,&i_QRS_count,&i_QRS_ms,
				&i_PR_ms,&i_QT_QTc_ms,&hh,&mm);
			//normalize array because it need or may be not normalized
		//	dsp_flf.SetArrToNormalize(AR_ECG,2500);
			//detect QRS
			//CountQRS(AR_ECG,2500);
		//	dsp_ecg.SetECG(AR_ECG,2500,AR_REV,&i_QRS_count,
		//		&i_QRS_ms,&i_PR_ms,&i_QT_QTc_ms);
		//	ecg_data.SetInfoAt(i,m_sComment,i_QRS_count,i_QRS_ms,
		//		i_PR_ms,i_QT_QTc_ms,hh,mm);
			//Format a string to be fitt in m_ctldata control
			str.Format("%d:%d  %d�/���",hh,mm,i_QRS_count);
			//inserts a string at current position
			m_ctldata.InsertString(i,str);
		}		
	}
	OnBtest();
}

void CECG_1Dlg::OnBexit() 
{
	// TODO: Add your control notification handler code here
	mcp3002.MMT_Stop();
	Sleep(10);
	//close pulse dialog if it is neaded
	HidePulseDialog();
	//Close the main program dialog
	CDialog::OnOK();
}

void CECG_1Dlg::OnHelpAboutecg1() 
{
	// TODO: Add your command handler code here
	CAboutDlg dlg;
	dlg.DoModal();
}

void CECG_1Dlg::OnBwflow() 
{
	// TODO: Add your control notification handler code here
	//window-cync filter low<100Hz
	dsp_flf.WFilter_Low100Hz(AR_ECG,AR_ECG,2500,250,100);
	OnBtest();
}

void CECG_1Dlg::OnBwfnoht50hz() 
{
	// TODO: Add your control notification handler code here
	//window-cync filter noht <47Hz >53Hz
	dsp_flf.WFilter_Noht(AR_ECG,AR_ECG,2500,250,50);
	OnBtest();
}

void CECG_1Dlg::OnBwflow40hz() 
{
	// TODO: Add your control notification handler code here
	//window-cync filter low<40Hz
	dsp_flf.WFilter_Low40Hz(AR_ECG,AR_ECG,2500,250,40);
	OnBtest();
}

void CECG_1Dlg::OnDspNoht50hz() 
{
	// TODO: Add your command handler code here
	OnBwfnoht50hz();
}

void CECG_1Dlg::OnDspLow100hz() 
{
	// TODO: Add your command handler code here
	OnBwflow();
}

void CECG_1Dlg::OnDspHigh0025hz() 
{
	// TODO: Add your command handler code here
	OnButton2();
}

void CECG_1Dlg::OnDspEcganalysis() 
{
	// TODO: Add your command handler code here
}

void CECG_1Dlg::OnDspLow40hz() 
{
	// TODO: Add your command handler code here
	OnBwflow40hz();
}

void CECG_1Dlg::ECG_Statistic()
{
	int mean,dev,max,min=0;
	double* arr;
	int lenght = ecg_data.QRS_COUNT.GetSize();
	if(lenght>0)
	{
		arr = new double [lenght];
	//	dsp_flf.Message(lenght); //test
		//Start calculating ecg statistic
		//QRS
		for(int i=0;i<lenght;i++)
		{
			//read qrs info and set it in arr
			*(arr+i) = ecg_data.GetQRSCount(i);
		}
		//calculate meandevmaxmin
		ecg_data.ecg_info.HeartRate.iMean = 
			dsp_flf.Mean(arr,lenght);
		ecg_data.ecg_info.HeartRate.iDev =
			dsp_flf.StandardDeviation(arr,lenght);
		ecg_data.ecg_info.HeartRate.iMax = 
			dsp_flf.FindMax(arr,lenght);
		ecg_data.ecg_info.HeartRate.iMin = 
			dsp_flf.FindMin(arr,lenght);


		//QRS_ms
		for( i=0;i<lenght;i++)
		{
			//read qrs info and set it in arr
			*(arr+i) = ecg_data.GetQRSms(i);
		}
		//calculate meandevmaxmin
		ecg_data.ecg_info.QRS_ms.iMean = 
			dsp_flf.Mean(arr,lenght);
		ecg_data.ecg_info.QRS_ms.iDev =
			dsp_flf.StandardDeviation(arr,lenght);
		ecg_data.ecg_info.QRS_ms.iMax = 
			dsp_flf.FindMax(arr,lenght);
		ecg_data.ecg_info.QRS_ms.iMin = 
			dsp_flf.FindMin(arr,lenght);

		//PR_ms
		for( i=0;i<lenght;i++)
		{
			//read qrs info and set it in arr
			*(arr+i) = ecg_data.GetPRms(i);
		}
		//calculate meandevmaxmin
		ecg_data.ecg_info.PR_ms.iMean = 
			dsp_flf.Mean(arr,lenght);
		ecg_data.ecg_info.PR_ms.iDev =
			dsp_flf.StandardDeviation(arr,lenght);
		ecg_data.ecg_info.PR_ms.iMax = 
			dsp_flf.FindMax(arr,lenght);
		ecg_data.ecg_info.PR_ms.iMin = 
			dsp_flf.FindMin(arr,lenght);

		//QT_QTc_ms
		for( i=0;i<lenght;i++)
		{
			//read qrs info and set it in arr
			*(arr+i) = ecg_data.GetQTQTcms(i);
		}
		//calculate meandevmaxmin]
		ecg_data.ecg_info.QT_QTc_ms.iMean = 
			dsp_flf.Mean(arr,lenght);
		ecg_data.ecg_info.QT_QTc_ms.iDev =
			dsp_flf.StandardDeviation(arr,lenght);
		ecg_data.ecg_info.QT_QTc_ms.iMax = 
			dsp_flf.FindMax(arr,lenght);
		ecg_data.ecg_info.QT_QTc_ms.iMin = 
			dsp_flf.FindMin(arr,lenght);

		//free memory from array
		delete arr;	
	}
	
}

void CECG_1Dlg::FormatTestDlg()
{
	CString str;
	int age=0;
	CString sage="";
	//Finding the patients ages
	COleDateTime this_year = COleDateTime::GetCurrentTime();
	age = int(this_year.GetYear()) -
		int(ecg_data.person.Birth_Date.GetYear());
	sage.Format(" %dy.",age);
	//Format the name control
	str = "Name: "+ecg_data.person.sName_1+" "+ecg_data.person.sName_2+" "+
		ecg_data.person.sName_3;
	str = str + sage;
	dlg_velo_test.m_sName = str;
	//Format the name of the trainer
	str = ecg_data.ecg_info.Confirm_By;
	dlg_velo_test.m_sTrainerName = "Confirmed by: "+str;
	////////////////////////////
	//Format the measured values
	////////////////////////////
	//Format the heart rate
	dlg_velo_test.m_sHeartRate.Format(
		"Mean heart rate - %d�/min +-%d�/min (maximum:%d�/min minimum:%d�/min)",
		ecg_data.ecg_info.HeartRate.iMean,
		ecg_data.ecg_info.HeartRate.iDev,
		ecg_data.ecg_info.HeartRate.iMax,
		ecg_data.ecg_info.HeartRate.iMin);
	//Format the QRSms
	dlg_velo_test.m_sQRSms.Format(
		"Mean QRS interval %dmsec. +-%dmsec. (maximum:%dmsec. minimum:%dmsec.)",
		ecg_data.ecg_info.QRS_ms.iMean,
		ecg_data.ecg_info.QRS_ms.iDev,
		ecg_data.ecg_info.QRS_ms.iMax,
		ecg_data.ecg_info.QRS_ms.iMin);
	//Format the PRms
	dlg_velo_test.m_sPRms.Format(
		"Mean PR interval %dmsec +-%dmsec. (maximum:%dmsec. minimum:%dmsec.)",
		ecg_data.ecg_info.PR_ms.iMean,
		ecg_data.ecg_info.PR_ms.iDev,
		ecg_data.ecg_info.PR_ms.iMax,
		ecg_data.ecg_info.PR_ms.iMin);
	//Format the QTQtcms
	dlg_velo_test.m_sQTQTcms.Format(
		"Mean QT_QTc interval %dmsec +-%dmsec. (maximum:%dmsec. minimum:%dmsec.)",
		ecg_data.ecg_info.QT_QTc_ms.iMean,
		ecg_data.ecg_info.QT_QTc_ms.iDev,
		ecg_data.ecg_info.QT_QTc_ms.iMax,
		ecg_data.ecg_info.QT_QTc_ms.iMin);
	//Format info about blood preasure
	dlg_velo_test.m_sbloodpreaure.Format("%d not used",
		ecg_data.ecg_info.BloodPreasure.iMean);
	//Format info about temperature
	dlg_velo_test.m_stemperature.Format("%d not used",
		ecg_data.ecg_info.Temperature.iMean);
	
	//Check for recorded date, if is no recorded date set curent time
	if(ecg_data.ecg_info.velo_test_date==0)
	{
		MessageBox("No ecg_test date! Now it will be set as system time!","No date",MB_OK);
		ecg_data.ecg_info.velo_test_date = COleDateTime::GetCurrentTime();
	}
	dlg_velo_test.m_dTestDate = (ecg_data.ecg_info.velo_test_date);
	/////////////////////////////

}

void CECG_1Dlg::OnBsavebmp2() 
{
	// TODO: Add your control notification handler code here
	if(ecg_data.GetAllDataLenght()/2500>0)
	{
		CPerson* lpPerson;
		lpPerson = &ecg_data.person;
		CEcg_Info* lpEcg_Info;
		lpEcg_Info = &ecg_data.ecg_info;

		statistic_draw.PrintBMP(lpPerson,lpEcg_Info);
	}
}

void CECG_1Dlg::ShowPulseDialog()
{
	//dialog_pulse_meter was done
	//in oninitdialog
	//dlg_pulse_meter.Create(IDD_DPULSEMETER,this);
	//So we can show it and continue working with program
	if(b_dlgPulseMeter==0)
	{
		dlg_pulse_meter.ShowWindow(SW_SHOW);
		dlg_pulse_meter.DrawPulse();
		b_dlgPulseMeter = 1;
	}
}

void CECG_1Dlg::HidePulseDialog()
{
	//if pulse_dialog is opened close it
	if(b_dlgPulseMeter==1)
	{
		dlg_pulse_meter.ShowWindow(SW_HIDE);
		b_dlgPulseMeter = 0;
	}

}

void CECG_1Dlg::ShowCurrPulse(int data_index)
{
	if(b_dlgPulseMeter==1)
	{
		dlg_pulse_meter.s_CurrPulse.Format("%d",
			i_QRS_count);

		int syze = ecg_data.QRS_COUNT.GetSize();
		if(syze > 0)
		{
		int pos=syze-1;
		int count = 0;
		int mean = 0;
		do
		{
			mean = mean + ecg_data.QRS_COUNT.GetAt(pos);
			pos--;
			count++;
		}
		while((count<3)&(pos>0));
		mean = mean/count;		

		dlg_pulse_meter.s_PastPulse.Format("%d",mean);
		}
		dlg_pulse_meter.DrawPulse();
	}
}

void CECG_1Dlg::OnC50hz() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);
}

void CECG_1Dlg::OnC60hz() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);
}

void CECG_1Dlg::OnC40lol() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);
}

void CECG_1Dlg::OnCw50hz() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);	
}

void CECG_1Dlg::OnCw40hz() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);	
}

void CECG_1Dlg::OnCw067() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	UpdateData(false);
}

void CECG_1Dlg::OnBampl() 
{
	// TODO: Add your control notification handler code here
	dsp_flf.Amplifier(AR_ECG,AR_ECG,2500,5);
	OnButton1();
}

void CECG_1Dlg::OnBdspall() 
{
	// TODO: Add your control notification handler code here
	int count = ecg_data.GetAllDataLenght()/2500;
	if(count>0)
	{

		//Format the buttons 
		dlg_dsp_all.m_bQRS = 0;
		dlg_dsp_all.m_bNoht50Hz = 0;
		dlg_dsp_all.m_bLow100Hz = 0;
		dlg_dsp_all.m_bLow40Hz = 0;
		dlg_dsp_all.m_bHigh068Hz = 0;

		int result = dlg_dsp_all.DoModal();
		if(result == IDOK)
		{
			CString str;
			//because we will recalculate all data
			//we can remove it 
			m_ctldata.ResetContent();
		//	dsp_flf.LoadFilterKernels(250);
			for(int i=0;i<count;i++)
			{
				
			//reads data from i*2500 to i*2500+2500
			GetDataFrom(AR_ECG,i,2500);
			//normalize array because it need or may be not normalized
			//	
			if(dlg_dsp_all.m_bQRS == 1)
				dsp_ecg.SetECG(AR_ECG,2500,AR_REV,&i_QRS_count,&i_QRS_ms,
					&i_PR_ms,&i_QT_QTc_ms,m_select_segment);
			
			if(dlg_dsp_all.m_bNoht50Hz == 1)
				dsp_flf.WFilter_Noht(AR_ECG,AR_ECG,2500,250,50);

			if(dlg_dsp_all.m_bLow40Hz == 1)
				dsp_flf.WFilter_Low40Hz(AR_ECG,AR_ECG,2500,250,0.67);
			
			if(dlg_dsp_all.m_bLow100Hz == 1)
				dsp_flf.WFilter_Low100Hz(AR_ECG,AR_ECG,2500,250,100);

			if(dlg_dsp_all.m_bHigh068Hz == 1)
				dsp_flf.WFilter_High(AR_ECG,AR_ECG,5000,1,250,0.67);
			
			//dsp_flf.SetArrToNormalize(AR_ECG,2500);
			
			//	ecg_data.GetInfoFrom(i,&i_QRS_count,&i_QRS_ms,&i_PR_ms,
			//		&i_QT_QTc_ms,&hh,&mm);
		
				
		//		dsp_flf.Delta2(AR_ECG,AR_ECG,2500);
				SetDataAt(AR_ECG,i,2500);
				
				//Format a string to be fitt in m_ctldata control
				str.Format("%d:%d  %d�/���",hh,mm,i_QRS_count);
				//inserts a string at current position
				m_ctldata.InsertString(i,str);
			}	
		}
	}
	OnBtest();
}

void CECG_1Dlg::OnRadio1() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	dsp_ecg.SetECG(AR_ECG,2500,AR_REV,&i_QRS_count,&i_QRS_ms,
		&i_PR_ms,&i_QT_QTc_ms,m_select_segment);
	OnButton1();
	UpdateData(false);
}

void CECG_1Dlg::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
		if(i_bmp==1)
	{
		//Calculate minute array positions
		byte old_min,min=0;
		byte old_hour,hour=0;
		//Heare we will store the begining positions of
		//each minute, bacause in one minute we may have
		//6 - 10secconds reccords
		CWordArray ctl_pos;
		ctl_pos.RemoveAll();
		int old_i=0;

	//	dsp_flf.Message(m_ctldata.GetCount()-1);

		for(int i=0;i<m_ctldata.GetCount()-1;i++)
		{
			ecg_data.GetPosTime(i,&old_hour,&old_min);
			old_i = i;
			//Loop untill old minute is gone
			do
			{
				i++;
				ecg_data.GetPosTime(i,&hour,&min);
			}
			//Important to be old_min == min
			while(old_min == min);
			//old_i wiw show thw bwgining of each minute
			ctl_pos.Add(old_i);
		}
//		dsp_flf.Message(ctl_pos.GetSize());
		////////////////////////////////////////

		int x = point.x;
		int y = point.y;
		//if mouse is on m_ctldata rect
		if(x>220&x<720&y>120&y<330)
		{
			//after this select the pointered date
			//Calculate the selected minute
			int cur_min = (x-220)/2;
		
			int c_index=0;
			//If calculated minute is < minute array
			//show pointer of a list box on te position
			//that shows the value from ctl_pos(index)
			if(cur_min <= ctl_pos.GetSize())
			{
				c_index = ctl_pos.GetAt(cur_min);
				m_ctldata.SetCurSel(c_index);
			}
		}
	}
	CDialog::OnLButtonDblClk(nFlags, point);
}

void CECG_1Dlg::OnBecgprint() 
{
	// TODO: Add your control notification handler code here
	if(ecg_data.GetAllDataLenght()/2500>0)
	{
		CPrintDialog dlgPrint(FALSE,PD_ALLPAGES,NULL);
		if(dlgPrint.DoModal()==IDOK)
		{
		CDC dcPrint;
			dcPrint.Attach(dlgPrint.GetPrinterDC());
			DOCINFO PrintJob;
			PrintJob.cbSize = sizeof(PrintJob);
			PrintJob.lpszDocName = "BMP printing";
			PrintJob.lpszOutput = NULL;
			PrintJob.lpszDatatype = NULL;
			PrintJob.fwType = NULL;

			dcPrint.SetMapMode(MM_LOMETRIC);
			if(dcPrint.StartDoc(&PrintJob)>=0)
			{
				dcPrint.StartPage();
				//Draw ECG single record information
				CFont Font;
				Font.CreateFont(40,20,-900,0,FW_DONTCARE,FALSE,FALSE,0,
					DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,
					CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,
					DEFAULT_PITCH|FF_DONTCARE,
					"MS Sans Serif");
				CFont* pOldFont = dcPrint.SelectObject(&Font);
			
		
				dcPrint.TextOut(770,-40,"EGN:  " + ecg_data.person.sEGN);
				dcPrint.TextOut(730,-40,"Name: "+
					ecg_data.person.sName_1 + " "+
					ecg_data.person.sName_2 + " "+
					ecg_data.person.sName_3);
				CString date;
	date = ecg_data.ecg_info.velo_test_date.Format("%Yy.%mm.%dd/");
		
				dcPrint.TextOut(690,-40,"ECG record info: "+
					date +
					s_ECG_Info);
				for(int i=0;i<2500;i++)
				{
					dcPrint.MoveTo(450+AR_ECG[i]/3,-20-i);
					dcPrint.LineTo(450+AR_ECG[i+1]/3,-20-i-1);
				}
				for(i=0;i<5;i++)
				{
					if(i!=2)
					{
						dcPrint.MoveTo(250+100*i,-20);
						dcPrint.LineTo(250+100*i,-2500);
					}
				}
				CString str;
				for(i=0;i<11;i++)
				{
					str.Format("|%ds",i);
					dcPrint.TextOut(290,-20-i*250,str);
				}
				dcPrint.EndPage();
				dcPrint.EndDoc();
				//return the old font
				dcPrint.SelectObject(pOldFont);
			}
		
			dcPrint.DeleteDC();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Georgi Petrov
Instructor / Trainer
Bulgaria Bulgaria
PhD, Cum Laude in digital automation systems
M.S. in Telemommunication management
B.S. in Telecommunication systems engineering
Programming: CUDA, C/C++, VHDL
Software and Hardware development and consulting:
data acquisition, image processing, medical instrumentation

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 15 Apr 2004
Article Copyright 2003 by Georgi Petrov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid