2013-09-30

Arduino breakout board testing notes
























Now I have mounted the olimex eck board on the Arduino shield breakout board.

.END

Arduino breakout board testing notes
























Now I have mounted the olimex eck board on the Arduino shield breakout board.

.END

Olimex EKG/EMG shield breakout board for Arduino, Raspberry Pi, and NXP Cortex M0 boards























Now I am making an Arduino shield breakout board for the Olimex EKG/EMG shield.  Then I can use this breakout board to route signals to non Arduino hardware, such as Raspberry Pi and NXP Cortex M0 boards.

.END

From Bulgaria with toy






















From Bulgaria with toy!

.END

EESTEC Workshop 2012  Day 4. EMG

http://cs.curs.pub.ro/wiki/pm/eestec/4

http://cs.curs.pub.ro/wiki/pm/eestec/1
http://cs.curs.pub.ro/wiki/pm/eestec/2
http://cs.curs.pub.ro/wiki/pm/eestec/3


.END2


ECG toy arrives just in time!















I already switched off the scope, unplugged power, and thinking of moving it off the desktop, but at the same time the UPS guy knocked at my door, and gave me the olimex ECG toy!

I thought the toy might come a couple of days later, when I have started to forget the ECG things I have been playing.  But it arrives an hour too early, because I am a big tired and need to do some yoga or taichi to refresh my memory, ...

.END


Packing up ECG experimental hardware























It is a bit disappointed to see that both my high pass and low pass filters not working.  But I am not too upset, because I knew I was doing a quick and dirty project, using the simplest hardware, without much serious design.  I guess the main problem is that the resistor value of the RC low pass filter is too high, therefore picking up too much noise.  One thing I should do is to use OP AMPs which should pick up much less noise and better performance.  But I saw that the opamp circuit is a bit too complicated, so I was too lazy to try my luck that way.

But I am still happy to have revised the RC network which I learned ages ago in technical college, and had almost forgotten the details.  All these years, I still found the idea of using imaginary numbers to represent the phase a bit too abstract, at least comparing to the digital logic circuits which I have always been comfortable to play with.

Anyway, so much for the preliminary test of ECG for now.

I was thinking of shifting also the scope from the desktop, to get more desktop space to switch in my other suspended project, the NXP LPC1114 barebone thing, ...

But, wait a moment, I heard someone knocking at my door, ...

.END

Low pass filter for ECG signal a total failure!























I increased the resistor value from 10K to 470K, but still the input and output waveform does not look right. The input seems to have picked up a heavy line signal of 4Vpp, and though the 470K/2.2uF seems to have filter away the 50Hz line noise, but the ouput is still too noisy with the order of 50mVpp, which over shadows the ECG signal, even existing.  I vaguely remember that high value carbon resistor pick high noise.  But I have no metal film resistor to do more trials and errors.  So I gave up for now, and hoping to get the Olimex thing in a couple of days.

.END


Low pass filter first trial not OK












I compared high pass filter with and without 200VAC LED lamp noise, before trying low pass filter, trying to filter out all high frequencies including even 50Hz line noise.

But using 2u2 and10K pair to make the low pass filter does not work.  Need to try other RC values later.

.END

Low pass filter for ECG signals design notes

On second thought, if the ECG signal frequency is only 10Hz, which is much lower than the line frequency of 50Hz, then actually I am having luck, because I can use a low pass filter of say 10Hz or 20Hz, to filter all high frequency noises including 50Hz line noise.

So I used the muzique calculator again, and got the RC pair of 2.2uF and 7K to start my low pass filter trials and errors design.

.END

Simple R-C Filter Cutoff Calculator - Muzique.com Lab Notebook

http://www.muzique.com/schem/filter.htm

The simple R-C filter rolls off the frequency response at 6 dB per octave above the cutoff frequency. The position of the resistor and capacitor are switched to change from low pass to high pass but the same calculation applies to both filters. This calculator assumes a low source impedance, which usually is small enough that it does not change the corner frequency.
Input any two values in the form boxes and hit the Calculate button to find the remaining value.

Capacitor (uF) = 2.2 uF, Corner Frequency (Hz) = 10 => Resistor (ohms) - 7.238K

.END2

High pass filter problem





















So I am designing a low pass filter to filter out the high frequency noise from the ECG wave signal.  But I have no idea of the frequency of the ECG wave.   I think I might make a rough guess to start trials and errors.

I looked at the the MIT Open Course ECG slide again and found that there are 6 wave signals in a period of about 17mm or (17mm * 0.04 second/mm =  17 * 40 mS = 700mS).

In other words, the average frequency of the 7 waves would be roughly 7 / 700mS = (7 * 1000) / 700
= 10Hz!

Now I seem to be in big trouble, because if the ECG signal is only 10Hz, then the high pass filter I made earlier must also have filter away the ECG signal, together with the 50Hz line frequency.

.END

High pass filter testing notes



















So after a couple of trials and errors, I found using 0.1uF and 1K a good pair of RC values to filter the 50Hz line frequency nose.   (The blue channel is input, yellow trace output of high pass filter.)  I also found that a 200VAC LED lamp creates a lot of high frequency noise.

Anyway, the simple RC based high pass filter is more or less working.  Now I think I need to make a high low pass filter to filter the high frequency noise, and hopefully get the ECG signal I want.

.END



High pass 50Hz line frequency filter design notes


























I found the ECG signal picking up a heavy 50Hz noise.  So I googled a simple RC 50Hz high pass filter circuit to try to get rid of the annoying line noise.

.END

Maxim Tutorial 733 A Filter Primer Oct 06, 2008

http://www.maximintegrated.com/app-notes/index.mvp/id/733

http://pdfserv.maximintegrated.com/en/an/AN733.pdf

Abstract: This comprehensive article covers all aspects of analog filters. It first addresses the basic types: first- and second-order filters, highpass and lowpass filters, notch and all-pass filters, and high-order filters. The tutorial then explains the characteristics of the different implementations, such as Butterworth filters, Chebychev filters, Bessel filters, elliptic filters, state-variable filters, and switched-capacitor filters.

Introduction

Ease of use makes integrated, switched-capacitor filters attractive for many applications. This article helps you prepare for such designs by describing the filter products and explaining the concepts that govern their operation.

Starting with a simple integrator, we first develop an intuitive approach to active filters in general. We then introduce practical realizations such as the state-variable filter and its implementation in switched-capacitor form. Specific integrated filters described here include Maxim's MAX7400 family of higher-order switched-capacitor filters.

.END2

Normal ECG wave period and amplitude
























ECG Wave timing

Biomedical Signal and Image Processing

http://ocw.mit.edu/courses/health-sciences-and-technology/hst-582j-biomedical-signal-and-image-processing-spring-2007/index.htm

Slides: Introduction to Clinical Electrocardiography (Courtesy of Andrew Reisner, MD. Used with permission.)

http://ocw.mit.edu/courses/health-sciences-and-technology/hst-582j-biomedical-signal-and-image-processing-spring-2007/lecture-notes/l3_ecg_reisner.pdf

Cite as: Andrew Reisner. Course materials for HST.582J / 6.555J / 16.456J, Biomedical Signal and Image Processing, Spring 2007. MIT OpenCourseWare

MIT OpenCourseWare  http://ocw.mit.edu HST.582J / 6.555J / 16.456J Biomedical Signal and Image Processing Spring 2007

For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms.

.END

ECG noise removing methods learning notes

Biomedical Signal and Image Processing

http://ocw.mit.edu/courses/health-sciences-and-technology/hst-582j-biomedical-signal-and-image-processing-spring-2007/syllabus/

Overview

This course presents the fundamentals of digital signal processing with particular emphasis on problems in biomedical research and clinical medicine. It covers principles and algorithms for processing both deterministic and random signals. Topics include data acquisition, imaging, filtering, coding, feature extraction, and modeling. The focus of the course is a series of labs that provide practical experience in processing physiological data, with examples from cardiology, speech processing, and medical imaging. The labs are done on the MIT Server in MATLAB® during weekly lab sessions that take place in an electronic classroom.

Lecture Topics

Biomedical Signals and Images

ECG: Cardiac electrophysiology, relation of electrocardiogram (ECG) components to cardiac events, clinical applications. Guest lecture.

...

Imaging Modalities: Survey of major modalities for medical imaging: ultrasound, X-ray, CT, MRI, PET, and SPECT.

...

MRI: Physics and signal processing for magnetic resonance imaging. Guest lecture.

...

DFT: The discrete Fourier transform and its properties, the fast Fourier transform (FFT), the overlap-save algorithm, digital filtering of continuous-time signals.

...

PDFs: Introduction to random variables and probability density functions (PDFs).
Classification: Bayes' rule, detection, statistical classification.

...

ECG Filtering and Frequency Analysis of the Electrogram Design filters to remove noise from electrocardiogram (ECG) signals and then design a system to detect life-threatening ventricular arrhythmias. The detector is tested on normal and abnormal ECG signals. (3 weeks - Greenberg)

...

.END

2013-09-29

ECG waving timing



























I wikied to find that the PQRST signal is roughly 500mS.  That signal I captured earlier was 500 uS long, 2 orders of magnitude too short.  The amplitude is also very wrong.  Obviously I made a very wrong guess.

Summary Of Normal Durations And Amplitudes Of The EKG - EKG Basics # 2

http://faculty.etsu.edu/arnall/www/public_html/heartlung/lectures/ekg2.html

1mm = 40ms duration or 0.1mV amplitude

P Waves

Normal Duration : 2.5 mm ( * 40 ms = 100 ms)
Normal Amplitude : 2.3 mm (* 0.1 mV = 0.23 mv)

PR Intervals

Normal Duration : 3-5 mm

Q Waves

Normal Duration : .75 mm - 1.0 mm
Normal Amplitude : <25% of the R wave amplitude

QRS Complex

Normal Duration : <3.0 mm
Normal Amplitude : Variable

ST Segment

Normal Amplitude : 1-2 mm
Normal Duration : 2-3 mm

T Wave

Normal Duration : 2 mm
Normal Amplitude : < 5 mm in Limb Leads & < 10 mm in Precordial Leads


.END

ECG Lead II measurement notes























Now I am using the ATTEN ADS1102CAL+ (100MHz, 1G sample, 7 inch wide screen, RMB1,850 2013jun) to measure the Lead II voltage.

By  a couple of trials and errors, I seemed to have captured my own heart signal at the following setting.

Ch 1, Ch 2, 50 mV,

M 10 uS.

I need to check the timing to make sure if what I am seeing is indeed the P, QRS, and T wave.

Very roughly, R wave is 100 mV, and P,QRS, and T total time is 50 uS.  So I need to google again.

. END

ECG 10 electrode / 12 lead definition

























ECG 10 electrode / 12 lead definition

References

1. Electrocardiographic Leads, I Introduction, Mcfee and Johnson, 1953

 [Just read Page 557]

http://circ.ahajournals.org/content/8/4/554

http://circ.ahajournals.org/content/8/4/554.full.pdf+html


2. Principles and Practice of Bioelectric and Biomagnet Fields by Malmivuo and Plonsey, 1995

[Just read Chapter 15 The 12-Lead ECG System]

http://www.bem.fi/book/15/15.htm

.END

Disposable ECG electrodes



















Disposable ECG electrodes, RMB0.4 each

.END

ECG 10 electrode 15 pin serial plug to 10 pin Dupoint socket adapter





















ECG 10 electrode 15 pin serial plug to 10 pin Dupoint socket adapter

.END

ECG 10 electrode serial 15 pin connector pinout

























ECG 10 electrode serial 15 pin connector pinout.


END

Open source ECG hardware turorial and example

Olimex Arduino compatible ECG board tutorial

http://cs.curs.pub.ro/wiki/pm/eestec/3

 license:CC Attribution-Noncommercial-Share Alike 3.0 Unported


Open Source Prosthetic Arm using Olimex ECG/EMG board - 2013jun16 (Open source project)

http://www.youtube.com/watch?v=ZUIqR2JodlY


Open Arms - Open Source Myo-Electric Prosthesis



.END

ECG 10 electrode cables
























TaoBao ECG 10 electrode 12 lead set RMB158

.END

Olimex ECG Board instrument amp





















Olimex ECG Board instrument amp


.END

Olimex ECG board singal amp





















Olimex ECG board singal amp

.END

Olimex ecg config




























Olimex ecg config

.END

Olimex EKG board cal signal



















Olimex EKG board cal signal

.END

My Olimex EKG Board Order

My Olimex EKG Board Order 

From: ...@element14.com To: tlfong01@... Subject: ... order Date: Fri, 27 Sep 2013 

Element14 Ref: 15266320 Customer Order: 27/09/2013 13:23 Date of order: 9/27/13 1:27 PM
What you ordered:

2144343 ...  BOARD, ECG / EMG ARDUINO SHIELD SHIELD-EKG-EMG OLIMEX [HKD248.58] 

http://hk.element14.com/olimex/shield-ekg-emg/board-ecg-emg-arduino-shield/dp/2144343  
   

2144344 ...  ELECTRODES, PASSIVE, ECG/EMG SHIELD SHIELD-EKG-EMG-PA OLIMEX [HKD126.69]
   
http://hk.element14.com/olimex/shield-ekg-emg-pa/electrodes-passive-ecg-emg-shield/dp/2144344 

...

.END

Olimex Open Source Hardware Arduino compatible EKG shield learning notes

SHIELD-EKG-EMG - OPEN SOURCE HARDWARE ELECTROCARDIOGRAPHY ELECTROMYOGRAPHY SHIELD FOR DUINOMITE, PINGUINO, MAPLE, ARDUINO LIKE DEVELOPMENT BOARDS

https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/

This is an EKG/EMG shield which allows Arduino like boards to capture Electrocardiography Electromiography signals. The shield opens new possibilities to experiment with bio feedback. You can monitor your heartbeat and log your pulse, recognize gestures by monitoring and analize the muscule activity as it is done in this project.

FEATURES

Stackable headers up to 6 channels may be stacked and wired to A0-A6 analogue inputs

Calibration signal generation by D4/D9 digital output

Precise Trimmer potentiometer for calibration

Input connector for normal or Active electrodes

Works with both 3.3V and 5V Arduino boards

DOCUMENTS

SHIELD-EKG-EMG user's manual revision E

HARDWARE

SHIELD-EKG-EMG schematic in PDF format released under Creative Commons Attribution-Share Alike 3.0 United States License

SHIELD-EKG-EMG schematic and board in Eagle format released under Creative Commons Attribution-Share Alike 3.0 United States License

SOFTWARE

//********************************************************************/
//* Demo program for:                                                */
//*    Board: SHIELD-EKG/EMG + PIC32-PINGUINO-OTG/MX220              */
//*  Manufacture: OLIMEX                                      */
//*  COPYRIGHT (C) 2012                                      */
//*  Designed by:  Penko Todorov Bozhkov                      */
//*   Module Name:  Example                                           */
//*   File   Name:  ShieldEkgEmgDemoWithPIC32-Pinguino-OTG_MX220.pde  */
//*   Revision:  Rev.A                                        */
//*   History:  Added support for PIC32-PINGUINO-MX220               */
//*   Date: 09.05.2012                                                */
//*   Built with PinguinoX.3 rev399                     */
//*********************************************************************/
/*************************************************************************************
Purpose of this programme is to give you an easy way to 
connect PIC32-PINGUINO-OTG to ElectricGuru(TM), see:
http://www.realization.org/page/topics/electric_guru.htm
where you'll be able to observe yours own EKG or EMG signal.
It is based on:
**************************************************************************************
* ModularEEG firmware for one-way transmission, v0.5.4-p2
* Copyright (c) 2002-2003, Joerg Hansmann, Jim Peters, Andreas Robinson
* License: GNU General Public License (GPL) v2
**************************************************************************************
For proper communication packet format given below have to be supported:
/////////////////////////////////////////////////////
////////// Packet Format Version 2 ////////////
/////////////////////////////////////////////////////
// 17-byte packets are transmitted from PIC32-PINGUINO-OTG at 256Hz,
// using 1 start bit, 8 data bits, 1 stop bit, no parity, 57600 bits per second.

// Minimial transmission speed is 256Hz * sizeof(PIC32-PINGUINO-OTG_packet) * 10 = 43520 bps.

struct PIC32-PINGUINO-OTG_packet
{
  uint8_t sync0; // = 0xa5
  uint8_t sync1; // = 0x5a
  uint8_t version; // = 2 (packet version)
  uint8_t count; // packet counter. Increases by 1 each packet.
  uint16_t data[6]; // 10-bit sample (= 0 - 1023) in big endian (Motorola) format.
  uint8_t switches; // State of PD5 to PD2, in bits 3 to 0. -> This is not used in current application. The value is set to 0x01
};
*/
/***************************************************************************************/
// In the source below was used the example given by:
// Jean-Pierre MANDON 2011
// Using interrupt with Pinguino32
// http://blog.pinguino.cc/

#include <__cdc.c>
#include <interrupt.c>

extern void putUSBUSART(char *data, char Length);

// All definitions
#if defined(PIC32_PINGUINO_220)

 #define SDCD 0
 #define SDWP 1

#elif defined(PIC32_PINGUINO_OTG) 

 #define LED2_ON TRISD &= (~0x0002); LATD |= 0x0002;
 #define LED2_OFF TRISD &= (~0x0002); LATD &= (~0x0002);
 #define LED2_TOGG TRISD &= (~0x0002); LATD ^= 0x0002;

#else

 #error: "The selected board is not supported!!!" 

#endif

#define LED1 13
#define CAL_SIG 9
#define NUMCHANNELS 6
#define HEADERLEN 4
#define PACKETLEN (NUMCHANNELS * 2 + HEADERLEN + 1)


// Global constants and variables
volatile unsigned char TXBuf[PACKETLEN];  //The transmission packet
volatile unsigned char CurrentCh;         //Current channel being sampled.
volatile unsigned char counter = 0; //Additional divider used to generate CAL_SIG
volatile unsigned int ADC_Value = 0; //ADC current value


/****************************************************/
/*  Function name: toggle_LED1        */
/*  Parameters                        */
/*    Input   :  No                 */
/*    Output  :  No                   */
/*    Action: Switches-over LED1.     */
/****************************************************/
void toggle_LED1(void){
 if(digitalRead(LED1) == HIGH){ digitalWrite(LED1, LOW); }
 else{ digitalWrite(LED1, HIGH); }
}


/****************************************************/
/*  Function name: toggle_GAL_SIG     */
/*  Parameters                        */
/*    Input   :  No                   */
/*    Output  :  No                   */
/*    Action: Switches-over GAL_SIG.  */
/****************************************************/
void toggle_GAL_SIG(void){
 if(digitalRead(CAL_SIG) == HIGH){ digitalWrite(CAL_SIG, LOW); }
 else{ digitalWrite(CAL_SIG, HIGH); }
}


void ISR_wrapper_vector_4(void) __attribute__ ((section (".vector_4")));
// Put the ISR_wrapper in the good place

void ISR_wrapper_vector_4(void) { Tmr1Interrupt(); }
// ISR_wrapper will call the Tmr1Interrupt()

void Tmr1Interrupt(void) __attribute__ ((interrupt));
// Tmr1Interrupt is declared as an interrupt routine


/*********************************************************/
/*  Function name: Tmr1Interrupt          */
/*  Parameters                            */
/*    Input   :  No                       */
/*    Output  :  No                       */
/*    Action: All actions are done here.  */
/*********************************************************/
void Tmr1Interrupt(void)
{
if (IFS0bits.T1IF) // Timer Interrupt flag
{
TMR1=0; // reset the timer register
IFS0CLR=0x10; // Clear the timer interrupt flag
toggle_LED1(); // Toggle LED1 with frequency 250/2 = 125Hz. LED1 can be used to monitor Timer1 interrupt frequency!
//Read the 6 ADC inputs and store current values in Packet
for(CurrentCh=0;CurrentCh<6;CurrentCh++){
 ADC_Value = analogRead(CurrentCh);
 TXBuf[((2*CurrentCh) + HEADERLEN)] = ((unsigned char)((ADC_Value & 0xFF00) >> 8)); // Write High Byte
 TXBuf[((2*CurrentCh) + HEADERLEN + 1)] = ((unsigned char)(ADC_Value & 0x00FF)); // Write Low Byte
}
 
// Send Packet
putUSBUSART(TXBuf,17);
TXBuf[3]++; // increment packet counter
 
counter++; // increment the devider counter
if(counter == 12){ // 250/12/2 = 10.4Hz ->Toggle frequency
counter = 0;
toggle_GAL_SIG(); // Generate CAL signal with frequ ~10Hz
#if defined(PIC32_PINGUINO_OTG)
LED2_TOGG; // Show CAL_SIG frequency via LED2 blinking
#endif
}
 
}
}

/*********************************************************/
/*  Function name: init_timer1          */
/*  Parameters                          */
/*    Input   :  No                   */
/*    Output  :  No                   */
/*    Action: configure timer1 operation. */
/*********************************************************/
void init_timer1(void)
{
 IntConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR); // interrupt mode (interrupt.c)
 T1CON=0; // reset timer 1 configuration
 TMR1=0; // reset timer 1 counter register
 #if defined(PIC32_PINGUINO_OTG)
PR1=20000; // define the preload register
//PIC32_PINGUINO_OTG: 40000000(Peripheral Clk)/8(Prescaller)/20000(PR1) = 250Hz
 #elif defined(PIC32_PINGUINO_220)
PR1=10000; // define the preload register
//PIC32_PINGUINO_220: 20000000(Peripheral Clk)/8(Prescaller)/10000(PR1) = 250Hz
 #endif
 IPC1SET=0x7; // select interrupt priority and sub-priority
 IFS0CLR=0x10; // clear interrupt flag
 IEC0SET=0x10; // enable timer 1 interrupt
 T1CONSET=0x8010; // start timer 1 and set prescaler

}

/*********************************************************/
/*  Function name: setup                */
/*  Parameters                          */
/*    Input   :  No                   */
/*    Output  :  No                    */
/*    Action: Initializes all peripherals */
/*********************************************************/
void setup()
{
 init_timer1();
 pinMode(LED1, OUTPUT);
 pinMode(CAL_SIG, OUTPUT);
  //Write init whole packet
 TXBuf[0] = 0xa5;   //Sync 0
 TXBuf[1] = 0x5a;   //Sync 1
 TXBuf[2] = 0x02;     //Protocol version
 TXBuf[3] = 0x00;     //Packet counter
 TXBuf[4] = 0x02;     //CH1 High Byte
 TXBuf[5] = 0x00;     //CH1 Low Byte
 TXBuf[6] = 0x02;     //CH2 High Byte
 TXBuf[7] = 0x00;     //CH2 Low Byte
 TXBuf[8] = 0x02;     //CH3 High Byte
 TXBuf[9] = 0x00;     //CH3 Low Byte
 TXBuf[10] = 0x02;    //CH4 High Byte
 TXBuf[11] = 0x00;    //CH4 Low Byte
 TXBuf[12] = 0x02;    //CH5 High Byte
 TXBuf[13] = 0x00;    //CH5 Low Byte
 TXBuf[14] = 0x02;    //CH6 High Byte
 TXBuf[15] = 0x00;    //CH6 Low Byte 
 TXBuf[2 * NUMCHANNELS + HEADERLEN] =  0x01; // Switches state
}

/*********************************************************/
/*  Function name: loop                   */
/*  Parameters                            */
/*    Input   :  No                       */
/*    Output  :  No                       */
/*    Action: Do nothing.         */
/*********************************************************/
void loop()
{
 asm("NOP");
}

.END