Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсач МОБС (2).docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
5.84 Mб
Скачать

4.1. Определение требований к алгоритму выделения r – зубца

  1. Частота дискретизации 500 Гц

  2. Частота АЦП не меньше 16 бит

  3. Алгоритм разрабатывался на базе микроконтроллера STM32F373C8

5. Реализация алгоритма выделения r – зубца

Реализация алгоритма выделения R-зубца выполнена на языке «C»; графический интерфейс приложения выполнен на языке высокого уровня «Python 3.4».

1.

Рисунок 5. Исходный сигнал ЭКГ

Рисунок 6. Увеличенный масштаб исходного сигнала ЭКГ

2.

Рисунок 7. Применение фильтров верхних и нижних частот на исходный сигнал ЭКГ

Рисунок 8. Увеличенный масштаб применения фильтров верхних и нижних частот на исходный сигнал ЭКГ

3.

Рисунок 9. Операция дифференцирования

Рисунок 10. Увеличенный масштаб операции дифференцирования

4.

Рисунок 11. Операция возведения в квадрат

Рисунок 12. Увеличенный масштаб операции возведения в квадрат

5.

Рисунок 12. Операция интегрирования с вычислением R-зубцов

6. Тестирование

Проведем тестирование на пяти различных сигналах ЭКГ.

1.

Рисунок 13. Сигнал ЭКГ №1

2.

Рисунок 14. Сигнал ЭКГ №2

3.

Рисунок 15. Увеличенный сигнал ЭКГ №2

Рисунок 16. Сигнал ЭКГ №3

4.

Рисунок 17. Сигнал ЭКГ №4

5.

Рисунок 18. Сигнал ЭКГ №5

6.1. Оценка точности выделения r – зубца

При тестировании программного обеспечения ни один R-зубец не был найден неверно.

Следовательно, на выбранном отрезке времени, точность выделения R-зубца равняется 100%.

Однако при тестировании в режиме реального времени ожидается погрешность около 1%.

Выводы

В результате проделанной работы был предложен метод неинвазивной регистрации и анализа ЭКГ человека. В основе метода лежит алгоритм Пан-Томпкинса, основанный на анализе QRS-комплекса в режиме реального времени. Используя метод Пан – Томпкинса можно определить амплитудные показатели R-зубца, а также значения R-R интервалов. Рассчитанные показатели позволяют определить наличие патологий сердечной мышцы у пациентов.

По полученным данным исследования, сформулируем требования к АЦП обработки ЭКГ сигнала.

Выходная частота дискретизации сигнала составляет 500Гц. Требуемая разрядность АЦП для данной системы не менее 16 бит, с общим коэффициентом усиления K=500.

В данном курсовом проекте была написана программа на языке СИ, реализующая метод выделения QRS комплекса, а также была произведена визуализация полученных данных на языке программирования Python. Алгоритм разработан на базе микроконтроллера STM32F373C8

Список используемой литературы

1. Рангайан Р.Н. Анализ биомедицинских сигналов. Практический подход, 2007 – 404 с.

2. Барановский А.Л. Кардиомониторы. Аппаратура непрерывного контроля ЭКГ, 1993 –248 с.

3. Мельник О.В., Михеев А.А., Нечаев Г.И. Выделение дрейфа изолинии электрокардиосигнала // Биомедицинские технологии и радиоэлектроника, 2005, № 1-2 С.26-30.

4. Васильев В.П. Основы теории и расчета цифровых фильтров: учеб. Пособие для высш. учеб. Заведений – М.: Академия, 2007 – 272 с.

Приложение А. Листинг №1

#include "algo.h"

#define st_arr_l(__arr__) \

sizeof(__arr__) / sizeof(*__arr__)

#define EXP 10

#define INTER_STEP 4

static PyObject *err_str(const char *msg) {

// Бросает исключение в питон

raise_exception(msg);

return NULL;

}

// Дифференциация

static void differ(float *signal, Py_ssize_t size, float dx) {

Py_ssize_t i = 1;

float last_val = *signal;

for (; i < size; i++) {

float tmp = signal[i];

signal[i] = (signal[i] - last_val) / dx; // tan(alpha)

last_val = tmp;

}

*signal = signal[1];

}

// Возведение переданных значений в квадрат

static void sig_sqr(float *signal, Py_ssize_t size) {

Py_ssize_t i = 0;

for (; i < size; i++, signal++)

*signal *= *signal;

}

// Алгоритм скользящего окна

void moving_window(const float *signal, float *out, Py_ssize_t size) {

const int N = 38;

Py_ssize_t i = N;

int j = 0;

for (; i < size; i++) {

out[i] = 0.0f;

for (j = 0; j < N; j++) out[i] += signal[i - N + j];

out[i] /= (float)N;

}

}

// Применение высокочастотного фильтра

static void band_filters_impl_hi(const float *src, float *dst, Py_ssize_t size) {

Py_ssize_t i = 1;

*dst = *src;

for (; i < size; i++) {

dst[i] = dst[i - 1] - src[i] / 32;

if (i > 15)

dst[i] += src[i - 16];

if (i > 16)

dst[i] -= src[i - 17];

if (i > 31)

dst[i] += src[i - 32] / 32;

}

}

// Применение низкочастотного фильтра

static void band_filters_impl_lo(const float *src, float *dst, Py_ssize_t size) {

Py_ssize_t i = 0;

for (; i < size; i++) {

if (i < 2)

dst[i] = src[i];

else {

dst[i] = 2 * dst[i - 1] - dst[i - 2] + src[i] / 32;

if (i > 5)

dst[i] -= src[i - 6] / 16;

if (i > 11)

dst[i] += src[i - 12] / 32;

}

}

}

// Вызывается ф-ия напрямую из питона

PyObject *band_filter(PyObject *self, PyObject *args) {

PyObject *data, *result = NULL;

PyObject *x, *y, *ry;

Py_ssize_t size;

if (!PyArg_ParseTuple(args, "O!", &PyTuple_Type, &data)) // Проверка ввода

return err_str("Incorrect input");

size = PyTuple_Size(data); // Проверка ввода

if (!size)

return err_str("Incorrect tuple given");

if (size != 2)

return err_str("Tuple must contain 2 tuples (x & y)");

PyArg_Parse(PyTuple_GetItem(data, 0), "O!", &PyTuple_Type, &x); // Вытаскивание значений по х, у из питона

PyArg_Parse(PyTuple_GetItem(data, 1), "O!", &PyTuple_Type, &y);

size = PyTuple_Size(x);

if (!size) // Проверка размеров массивов данных

return err_str("Incorrect coordinates given (length == 0)");

if (size != PyTuple_Size(y))

return err_str("Incorrect coordinates given (x_len != y_len)");

float *xvec = (float *)PyMem_RawMalloc(sizeof(float) * size); // Выделение памяти для локальных буфферных переменных

float *yvec = (float *)PyMem_RawMalloc(sizeof(float) * size);

if (!xvec || !yvec) {

PyMem_RawFree(xvec ?: yvec); // Ошибка при выделении памяти

return err_str("Error allocating memory");

}

Py_ssize_t i = 0;

for (; i < size; i++)

PyArg_Parse(PyTuple_GET_ITEM(y, i), "f", xvec + i); // Копирование входного сигнала в локальные переменные

float *ptr = yvec;

band_filters_impl_lo(xvec, yvec, size); // Применение низкочастотного фильтра

band_filters_impl_hi(yvec, xvec, size); // Примененеи высокочастотного фильтра

float *x_ptr = xvec == ptr ? yvec : xvec;

for (i = 0; i < size; i++) // Копирование временного массива из питона

PyArg_Parse(PyTuple_GET_ITEM(x, i), "f", x_ptr + i);

float dx = x_ptr[1] - x_ptr[0];

differ(ptr, size, dx); // дифференцирование

sig_sqr(ptr, size); // Возведение в квадрат

moving_window(ptr, x_ptr, size); // ПРименение алгоритма скользящего окна

memcpy(ptr, x_ptr, size * sizeof(*ptr)); // Перемещение значений в другую буфферную переменную

for (i = 0; i < size; i++) // Перемещение значений времени из питона в массив

PyArg_Parse(PyTuple_GET_ITEM(x, i), "f", x_ptr + i);

_PyTuple_Resize(&x, size);

ry = PyTuple_New(size);

if (!ry)

return err_str("Error allocating memory");

// Подготовка переменных для вывода обратно в питон

result = PyTuple_New(2);

if (result) {

for (i = 0; i < size; i++) {

PyTuple_SET_ITEM(ry, i, Py_BuildValue("f", ptr[i])); // Копируем в питон массив сигнала

PyTuple_SET_ITEM(x, i, Py_BuildValue("f", x_ptr[i])); // время

}

PyTuple_SET_ITEM(result, 0, Py_BuildValue("O", x)); // [ [ x_data ... ], [ y_data ... ] ]

PyTuple_SET_ITEM(result, 1, Py_BuildValue("O", ry));

} else

err_str("Error allocating memory");

// Освобождение памяти

PyMem_RawFree(xvec);

PyMem_RawFree(yvec);

return result;

}

#include "algo_ex.h"

static PyObject *exception;

// Модуль помогает кинуть исключение в питон в случае неверного ввода

int init_exception(PyObject *parent) {

exception = PyErr_NewException(LIB_NAME ".Exception", NULL, NULL);

Py_INCREF(exception);

PyModule_AddObject(parent, "exception", exception);

return exception != NULL;

}

void del_exception() {

// Освободить выделенную исключениями память

Py_CLEAR(exception);

}

void raise_exception_n(const char *msg, const char *file, int line) {

// Послать исключение в питон

char str[1024];

snprintf(str, sizeof(str), "Exception came from %s:%d: %s\n", file, line, msg);

PyErr_SetString(exception, str);

}

#include <Python.h>

#include "algo.h"

#include "algo_ex.h"

// Модуль инициализации С библиотеки при старте программы

static PyMethodDef module_methods[] = {

{ "band_filter", (PyCFunction)band_filter, METH_VARARGS }, // Определение методов, доступных из питона

{ NULL, NULL }

};

static int module_traverse(PyObject *m, visitproc visit, void *arg) {

/* Memory allocations */

return 0;

}

static int module_clear(PyObject *m) {

/* Memory clear */

del_exception();

return 0;

}

static struct PyModuleDef moduledef = { // Структура характеризует модуль С для питона (****)

PyModuleDef_HEAD_INIT,

LIB_NAME, // Имя модуля

NULL,

0,

module_methods, // Методы модуля

NULL,

module_traverse, // Ф-ия инициализации (ничего не делает)

module_clear, // Функция деинициализации

NULL

};

PyObject *PyInit_algo() {

// Ф-ия вызывается при старте программы

PyObject *module = PyModule_Create(&moduledef); // Инициализация параметров модуля см (****)

// Обработка ошибок инициализации

if (module == NULL)

return NULL;

if (!init_exception(module)) {

Py_DECREF(module);

return NULL;

}

return module;

}

18