Не реагирует SpO2 ни на дыхание чистым О2, ни на дыхание в кулёк. Дышал примерно по минуте того и другого. Кислородом - из баллона, десять полных вдохов. В кулёк - тоже минуту, но частота вдохов там непроизвольно повышалась; терпел, пока не начало конкретно торкать в ножки. Бррр... Неприятная процедура... Следил за числовыми показаниями, что в окне монитора (открывается нажатием на кнопку с изображением компьютерного монитора, "Opens Serial Terminal"). Если какие-то изменения и были, то в пределах нескольких десятых долей процента. Всё пляшет вокруг 94%, +/- несколько десяток. Магическое число... Не думаю, что это нормально. Надо поиграться с токами светодиодов, я понимаю.
Переставил чип с шумной платы на исправную (китайскую). Общее впечатление - чувствительность хуже, устойчивую детекцию пульса поймать труднее. Сатурация на дыхание кислородом не реагирует, как и в первом случае. Детекция постоянно сбивается; тыкался всеми пальцами, какие есть в наличии, по-всякому.
Типичная картинка (но в данный момент пульс детектируется, а обычно розовые пики находятся "под водой" - под ровной синей линией, в голубой заливке):
Теперь попробую посадить этот чип на МОЮ плату, где сейчас сидит первый китайский чип...
зы: То ли чип прогрелся, пока писал это сообщение, то ли фаза Луны поменялась - сейчас уже работа второго экземпляра стала очень похожа на работу первого. Но всё равно, как-то медленнннннее он выходит на детекцию пульса, адаптируется гораздо дольше, чем первый... Если не торопиться и подержать палец, то примерно секунд через сорок "подводные пики" "выходят на поверхность", и стартует детекция сердечного ритма (картинка выше)... А вот сатурация всё равно так и не работает. Не думаю, что стОит пересаживать его на мою плату, ибо тут что в лоб, что по лбу...
Снимаю первого китайца с моей платы, сажу туда европейца!
ПОКА каких-то особых отличий - ни в графиках, ни во впечатлениях от работы - НЕ наблюдаю. Кроме того, что на графике Р1 кривые вроде как полностью сместились в положительную область, и через ноль не переходят. Размах сигнала в районе 200 .. 250 ед. - примерно то же, что и было у второго китайца... Хотя, впрочем, побольше, даже раза в полтора-два... Но 600 единиц, как с утра, с первым, пока добиться ни разу не удалось.
ДА, а направленные вниз зубцы синей линии (перед встречей с розовыми пиками), сейчас в несколько раз "глубже", чем было у китайцев. Это то, что бросилось в глаза...
Кислород пока закончился, реакцию показаний сатурации не тестировал.
Сатурация быстро набирается простым упражнением - набираем полную грудь воздуха и пытаемся выдохнуть зажав нос и закрыв рот. Усилие прикладывать максимально возможное на 5 -10 секунд, тем самым создавая избыточное давление в лёгких и активно насыщая кровь кислородом. Через несколько вдохов - давление - выдохов начинает кружиться голова - признак высокой сатурации. Мне достаточно 5-7, что бы сатурация с 94 поднялась до 97 минуты за 2. Потом примерно за те же 2 - 3 минуты возвращается к значению 94. Бонусом падает пульс на 10 единиц.
А посмотрите на "заводской Китай". Там съёмник изготовлен так, что палец все время одинаково ложится на мыргалку. Отсюда и повторяемость результатов , а как следствие - пересчет raw в human-readable.
На выходных уделяю внимание семейным заботам, всё по теме осталось на работе. Продолжим с понедельника. За упражнение, повышающее сатурацию - спасибо, попробуем!
Насчёт заводских китайцев ("напалечных прищепок", надо полагать?) - не имею возможности их препарировать. Здесь покупать под разборку - дорого, а с Али что-то происходит нехорошее, связанное со всемирным фестивалем, думаю. Несколько заказов не пришли, пришлось просить продавцов продлить срок защиты; один уже просрочен оказался - возврата денег тоже нет уже недели две... Такого раньше не было. Как бы не загнулась лавка. Было бы весьма печально, как для голожопых самодельщиков...
Хочу добиться от прибора, чтобы он реагировал на упражнения, влияющие на сатурацию: дыхание в кулёк, задержку дыхания с последующей компрессией воздуха в груди, и подобные вариации.
Поигрался с настройками:
ток красного светодиода (авторское значение = 27,1 мА);
"магическое число" (65000);
порог срабатывания детектора пульса (100).
По сути вопроса - безуспешно. На изменения настроек система реагирует явным образом (яркость свечения красного; изменения в графике Р0 с изменении "магического числа"; увеличение числа ложных срабатываний детектора пульса с понижением порога срабатывания). Всё якобы работает, но только не так, как это нужно мне. На изменения реагирует только пульс - вне зависимости от комбинаций настроек: во время компрессии воздуха в груди довольно резво повышается на пару десятков ударов, а после выдоха - проседает примерно на ту же величину. Потом восстанавливается. Сатурация на всё это совершенно не реагирует...
Насчёт тока красного светодиода - в настройках, очевидно, имеется в виду НАЧАЛЬНЫЙ ток. Который после прикладывания пальца ступенчато регулируется автоматически. Т.е. какое стартовое значение тока ни выставляй, он либо повысится до некой нормы, нужной системе, либо понизится - до неё же. Просто на автоподстройку (на ступенчатый перебор значений токов) уходит время, и чтобы его сэкономить, пользователю предлагается вручную установить значение, наиболее близкое к тому, которое обычно выбирает система, применительно к данному экземпляру чипа. Тогда пульс начинает детектироваться практически сразу после прикладывания пальца, без автоперебора токов красного светодиода (что легко заметить визуально).
Вообще как-то всё печально. Бьюсь, как рыба об лёд... Смущает несоответствие авторской картинки P0 с тем, что есть у меня. Такое впечатление, что на момент написания статьи, в монитор выводились другие значения для этого графика - а именно БЕЗ отсечки постоянной составляющей. Была надежда, что всё дело именно в этом, но поскольку график Р0 участника nik182 имеет вид практически идентичный с моим, и при этом сатурация адекватно реагирует на физические упражнения, то график Р0 тут ни при чём...
Куда копать далее - понятия не имею. Вышел на упор.
На счёт автоматики уровня свечения диодов я не уверен. Посмотрите предпоследнюю картинку в #35. Я вывел сырые данные, без обработки. Средний уровень данных АЦП по RED 24500 из 65000, по IR 28700. Эти уровни зависит только от того, как приложил палец. Если постоянно удерживать палец в одном положении, то они ни как не меняются. Это значит, что никакой подстройки нет. Кроме того, в блоге около картинки №12 прямо говориться, что надо самому изменить ток диодов так, что бы отклик АЦП был примерно одинаков для обоих каналов и был меньше 65000 с помощью balanceIntesities.
Копать дальше в сторону цифровой обработки сигналов. Для получения адекватного значения сатурации надо аккуратно рассчитать RMS флуктуаций двух сигналов на частоте (!) сердцебиения. Любые другие колебания - от наводок сети 50 Гц, от тремора пальца - у меня его видно не вооружённым глазом на кривой пульса с частотой 10-15 Гц, и прочие дают большую погрешность и за ними можно не увидеть необходимые изменения, тем более, что изменения эти до 3% и меньше. Здесь не плохо было бы набирать статистику для уменьшения ошибки.
P0 в блоге только на картинках 4,5,7 они соответствуют Вашим и моим картинкам. Размах колебаний меньше 1000.
По автоподстройке - выставьте в .h начальный ток красного светодиода 4,4 мА. Сохраните, прошейте, включите, дождитесь загрузки и включения красного светодиода. ВЫключите свет, и положите палец на сенсор - чтобы ваш светящийся ноготь был вам хорошо виден. В таких условиях я без труда, чётко и ясно, вижу ступенчатое увеличение яркости красного светодиода до некоторого среднего значения. В конце такого цикла автоподстройки, одна ступень яркости иногда вроде бы отыгрывает назад, на понижение (процесс как бы совершает колебание вокруг целевого значения), после чего, как правило, происходит устойчивый "захват" пульса детектором, что динамически иллюстрирует график P1. Всего визуально различимо прохождение около пяти градаций яркости, каждая по полсекунды. Кстати, эти полсекунды тоже можно регулировать в .h - у меня, например, и стоит 500 мс, по умолчанию.
Насчёт остального - какие конкретные практические шаги вы порекомендуете? Чтобы крутить параметры более-менее осмысленно? Та модифицированная вами библиотека, которую вы предлагали выше - выводит ли она на P0 сырые данные с неотфильтрованной постоянной составляющей? Как можно практически рассчитать RMS кардиограммы? И что потом с этими расчётами делать, куда конкретно вставлять их результаты?
Если идти по тексту блога, то я имею в виду Р0 (IR LED RAW), изображённый на картинках 9, 10, 11, 12 и, наконец, 14. Я не знаю точно, куда вы смотрите, но на всех этих графиках я вижу вертикальную ось с отметками чуть ниже 1 000 000, напротив которых и расположены обе кривых (ИК и К каналы): https://morf.lv/implementing-pulse-oximeter-using-max30100
зы: Прикольно, на Р2 (красный - пульс, синий - сатурация) я могу чётко наблюдать вспышки своих экстрасистолий. Чуть только сердце затрепыхается - сразу из-за правого среза графика выезжает пик с почти вертикальными фронтом и спадом. Детектор пульса работает чётко! А вот график сатурации (Р2, синий) остаётся совершенно невозмутимым, что ни предпринимай...
Смотрю я туда же. Картинки 9, 10, 11, 12 и, наконец, 14 это картинки после обработки. К реальным сырым сигналам значения на осях не имеют никакого отношения. Реальные сырые значения на картинках 4,5,7 - это я уже писал. Примите как данность, что остальные картинки без алгоритмов обработки автора статьи Вы повторить не сможете в тех размерах осей как на картинках 9, 10, 11, 12 и, наконец, 14. Если сделать подобную обработку, то форма повториться, амплитуды скорее всего нет.
На счёт подстройки я уже тоже писал - каждый шаг программы вызывает один раз balanceIntesities - подпрограмму которая пытается подстроить ток. Время подстройки Вы указали правильно. Никакого автомата, исключительно программными средствами.
Расчёт сатурации не понятен. Похоже,что RMS считается непрерывно, без относительно к сердечному ритму. Соответственно когда кривые гладкие, без шума, по результат как то ворочается, как только на кривых появляется шум то что получается не понятно. Кроме того, если заглянуть в документ TI slaa274b.pdf то увидим что R через логарифм считается со штрихом, а графики сатурации для R без штриха. Как переводить одно в другое нигде не написано, но указывается, что уровни для этой процедуры должны быть близки. Вот гугл перевод оттуда: ===========
Для каждой длины волны света, то значение постоянного тока удаляются из сигнала, выходящий из части переменного сигнала, который отражает уровень артериальной оксигенации. Среднеквадратичное значение рассчитывается путем усреднения квадрата сигнала по числу циклов сердечных сокращений. Измерение постоянного тока непрерывно рассчитывается путем усреднения сигналов за несколько циклов сердечного сокращения.
Мощность возбуждения каждого светодиода контролируется таким образом, чтобы уровень постоянного тока, видимый на ПИН-диоде, соответствовал заданному целевому уровню с небольшим допуском. Делая это для каждого светодиода, конечный результат заключается в том, что уровни постоянного тока этих двух светодиодов соответствуют друг другу с небольшим допуском. Как только уровни DC совпадают, SaO2 рассчитывается путем деления логарифмов значений RMS (в переводе RMS - Среднеквадратичное значение).
===============
Как этой библиотеке происходит расчёт я не разбирался. А делать надо как и описано в переводе - накопить переменную составляющую за несколько сердечных циклов, рассчитать RMS, рассчитать отношение и по картинке 13 блога вычислить значение сатурации.
Спасибо за разъяснения. Т.е. ситуация, для меня по крайней мере, выглядит достаточно сложной. Поскольку у меня нет понятных мне инструментов для того, чтобы свести значения постоянных составляющих двух каналов в необходимый коридор. Автор вроде бы приводит в тексте кусок кода, позволяющий это сделать, но как это выполнить практически - не объясняет... Статья для программистов.
Время подстройки
RED_LED_CURRENT_ADJUSTMENT_MS 500
увеличил до 1000 мс. Синяя кривая на графике Р2 (сатурация) начала реагировать на компрессию воздуха в грудной клетке. НО - строго наоборот от того, что описываете вы - у меня она резко проседает ВНИЗ, примерно на 4%, держится там несколько секунд, и так же резко возвращается на исходный уровень (в р-н 94%).
Ну по крайней мере хоть какой-то реакции удалось наконец добиться...
зы: Увеличил также вдвое кол-во периодов усреднения сатурации, с 4 до 8. Вроде сатурация стала адекватно реагировать на "ныряние" с задержкой дыхания. Особенно хорошо видно, если на графике Р2 выключить красную кривую пульса - тогда сатурация растягивается во весь экран, и все реакции кривой становятся хорошо видны.
Прочитал, стало интересно. Max30100 не имею, а судя по этому топику, похоже и заказывать не стоит. Вот стало интересно: а если взять простой фоторезистор от набора Ардуино УНО, его можно приспособить как "регистратор" вместо диода или нет?
Да можно, но только два светодиода красный и инфракрасный и один фотодиод. Если читаете по английски, то есть полное описание как сделать железо со всеми номиналами http://www.ti.com/lit/an/slaa274b/slaa274b.pdf . МК другой, но это не принципиально. Но с max30100 всё же легче. Диоды, усилители, да и корпус датчика - всё в одном флаконе.
P.S. И ещё сильно смущает "математика". И по вашей ссылке там тоже предварительно уровни освещения подбираются так, чтобы отклик на обоих частотах был одинаков, а уже потом, считают переменную составляющую и её обрабатывают. И получается что в части "оксиметр" берется отношение логарифмов .. заранее подогнанных уровней. Меня это несколько напрягает, т.к. подогнать можно что угодно и куда угодно. Или я ошибаюсь? Как это "калибровать"?
По наводке в 50гц. Можно же "заземлять" измеряемый палец, обмотав его проводочком и соединив с Землей АЦП .. должно сильно помочь.
По оксигенации: раз измерение в пальце, если его туго бинтовать, поступление крови снизится и оксигенация должна измениться за счет накопления венозной крови. Так кто-то пробовал смотреть на изменения показаний?
Берётся отношение RMS, при одинаковом уровне DC составляющей. От уровня DC зависит размах колебаний. Если DC одинаковая, то не надо пересчитывать AC составляющую для которой рассчитывают RMS и вычисления упрощаются.
Бинтовать это лишнее. Достаточно сильнее нажать на датчик, что бы увидеть эффект.
Старые мануалы TI вообще кладезь информации. Я часто ими пользуюсь для получения схемотехнических решений. Достаточно зайти в раздел примеров на МК MSP430. Всё подробно расписано со схемами, номиналами деталей, расчётами режимов работы. Сейчас так не делают.
Бинтовать это лишнее. Достаточно сильнее нажать на датчик, что бы увидеть эффект.
Как я понял естественный диапазон изменений насыщенности довольно узкий 94 - 99 %. И бинтование, может быть, поможет удовлетворить любопытство - "насколько низкий уровень насыщенности может измерять данный прибор." (Знать бы еще какой должен быть уровень у пережатого пальца.)
Нашел фотодиод, буду пробовать. Кстати, по ссылке на Гайвера понравилось решение с RGB светодиодом - можно смотреть отклик на ещё паре частот, что должно позволить определять или надежней или что-то ещё, какие-то HbMet и HbCO2 надо почитать на эту тему..
> Max30100 не имею, а судя по этому топику, похоже и заказывать не стоит.
Странное заключение...
Если решите собирать на рассыпухе, то с очень большой долей вероятности (если со схемотехникой до сего момента вы общались примерно на уровне ардуинского бредборда с дырочками) - в САМОМ лучшем случае вы получите РОВНО те же проблемы, что и описанные выше, ПЛЮС пляски с железом: усилители, наводки, и т.д. и т.п... Просто, по-пионерски - усилить сигнал с фотодиода, оцифровать его и пытаться потом вытянуть оттуда какую-то полезную инфу - путь в никуда, потому что сперва вы должны отвязаться от массы мешающих, непостоянных факторов. Температура - первое, что приходит в голову. В чипе, насколько я читал, это решается дифференциальным измерением, когда сигнал снимается не относительно какого-то стационарного эталона, а относительно другого сигнала (помехи). И получается железная фильтрация - задолго до АЦП. Это только потом идут программные нормализация и ФНЧ Баттерворта (если иметь в виду статью, ссылку на которую я поместил в начале этого топика). Наконец, вы же не впихнёте схему из апноута по ссылке выше в пластинку объёмом несколько куб.мм... Будут навесные провода, или какая-то разводка, что неизбежно повлечёт за собой цепь традиционных проблем с наводками, которые придётся преодолевать... Смысл? Дешевле - ТОЧНО не получится. ЛУЧШЕ? Гхм... Кхм...
Мне кажется, что 30100 (-1, -2) - одно из лучших решений по теме "любительской", "домашней" оксиметрии, что предлагает рынок на сегодняшний день.
Бинтовать палец не имеет смысла, потому что вы задавите пульс. А наличие обнаруженного пульса - непременное условие расчёта сатурации. То же самое произойдёт, если вы сильно надавите пальцем на сенсор.
Резюме - не нужно требовать от РАБОТАЮЩЕЙ технологии больше, чем она может дать. Завышенные ожидания рождают разочарование. Если же играться в пределах этого поля - можно достичь счастья!
> Особенно хорошо видно, если на графике Р2 выключить красную кривую пульса - тогда сатурация растягивается во весь экран, и все реакции кривой становятся хорошо видны.
> Завышенные ожидания рождают разочарование.
Две ключевые фразы. Ждал слишком многого там, где оно не могло проявиться. Короче, выставил я все параметры в заголовке библиотеки по умолчанию, и выключил красную кривую пульса на P2. Оставшаяся синяя линия (сатурации) уверенно отображает даже обычные глубокие вздохи, безо всяких компрессий и минутных задержек. Просто спокойно посидеть пару минут, с пальцем на датчике, дождаться, пока все переходные пики и неровности уедут за левый срез окна Р2, потом глубоко вздохнуть, задержать на секунду воздух, и глубоко выдохнуть, после чего продолжить спокойное дыхание. И вот такая получается картинка:
Вполне себе приличный отклик, только я бы усреднял штук тридцать-сорок отчётов сатурации. В мануале я бы написал, что измерять сатурацию надо в одно и то же время суток, например, с утра, после пробуждения. Надеть сенсор на палец, и, например, через минуту, после сигнала окончания измерения, считать показания с дисплея. Во время цикла измерения ЖКИ должен отображать режим ожидания результатов - например, заполняющийся статус-бар или что-то в этом роде. Кроме того, прибор должен иметь индикатор детекции пульса, лучше всего звуковой. Чтобы пользователь не ждал напрасно, если палец лёг не так, как надо, и пульс не захвачен. Как пошли щелчки захвата пульса из звукового индикатора - с этого момента ожидаем звукового сигнала окончания измерения, и считываем результаты с ЖКИ. Что-то в этом роде надо написать... Усреднение - среднее арифметическое, с отбрасыванием единичных мусорных отчётов, отличающихся от общей массы на заданный порог. И всё должно получиться...
Разобрался, наконец, со спорадическими пропаданиями детекции пульса. Руки (пальцы) должны быть ТЁПЛЫМИ. У меня, например, традиционно плохое кровообращение в конечностях (хронически холодные руки и ноги); а погоды сейчас стоят, мягко говоря, нежаркие. Постановил: перед каждым экспериментом несколько минут прогревать пальцы под лампой накаливания. Теперь получаю неизменно превосходный результат - амплитуду импульсов кардиограммы (Р1) наблюдаю от 200 до 700 единиц (амплитуда - это то, что выше нулевой линии, от нуля до вершины импульса). Никогда не менее 300. Отказы детекции пульса просто прекратились... Если долго держу палец на сенсоре, без движения, то вижу, как амплитуда кардиограммы постепенно уменьшается. Всё логично.
Как видим, всё постепенно становится на свои места!
зы: Прикольно наблюдать разницу в амплитуде импульсов кардиограммы между прогретыми (левая рука) и непрогретыми (правая) пальцами. Прогретые - от 200 ед. и выше; непрогретые - до 30 ед. (и, естественно, никакой детекции).
зы: Прикольно наблюдать разницу в амплитуде импульсов кардиограммы между прогретыми (левая рука) и непрогретыми (правая) пальцами. Прогретые - от 200 ед. и выше; непрогретые - до 30 ед. (и, естественно, никакой детекции).
У меня руки всегда горячие. Поэтому Ваших проблем не наблюдал. Всё работало сразу. Ещё одно доказательство того, что важны все элементы - и датчик и объект :-) . Ещё раз поздравляю с решением проблемы.
> думаю, тема давно переосла Песочницу - ее нужно либо в аппаратные, либо в проекты
Если тут требуется моё согласие - я только "за"! Хочется помочь как можно большему числу таких как я сам горемык, чтоб не плясали с бубном, не наступали на уже пройденные грабли... И в этой связи - было бы здорово добавить слово "Пульсоксиметр" в заглавие топика, для поисковых ботов. Сам я это сделать как будто не могу - вроде как некуда нажимать...
)) Если бы у объекта все проблемы решались прогревом конечностей... Умище, УМИЩЕ девать некуда! ))
Другими словами: помогите убогому, люди добрые... Пытаюсь скомпилить из двух скетчей один. Чтобы строгоновский скетч выводил данные не только в компорт, но и в 1602 - показания пульса и сатурации. Взял готовый проект, где фигурирует 1602, посмотрел, попытался... Не компилится, хоть ты тресни... Понимаю, что тупо, но не могу сам решить - старенький уже, и нифига в этом не волоку... Уже честно пытался объявить, подставить в функции вывода НУЖНЫЕ имена переменных, но... Выручайте!
#include <Arduino.h>
#include <math.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "MAX30100.h"
MAX30100* pulseOxymeter;
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
// LCD 1206 1 2 4 5 6 11 12 13 14 15 16
// Arduino GND +5 13 GND 12 11 10 9 8 +5V GND
// MAX30100 SDA SCL
// Arduino A4 A5
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("Pulse oxymeter test!");
lcd.begin(16,2);
lcd.print("Initializing...");
delay(3000);
lcd.clear();
//pulseOxymeter = new MAX30100( DEFAULT_OPERATING_MODE, DEFAULT_SAMPLING_RATE, DEFAULT_LED_PULSE_WIDTH, DEFAULT_IR_LED_CURRENT, true, true );
pulseOxymeter = new MAX30100();
pinMode(2, OUTPUT);
//pulseOxymeter->printRegisters();
}
void loop() {
//return;
//You have to call update with frequency at least 37Hz. But the closer you call it to 100Hz the better, the filter will work.
pulseoxymeter_t result = pulseOxymeter->update();
if( result.pulseDetected == true )
{
Serial.println("BEAT");
Serial.print( "BPM: " );
Serial.print( result.heartBPM );
Serial.print( " | " );
Serial.print( "SaO2: " );
Serial.print( result.SaO2 );
Serial.println( "%" );
Serial.print("{P2|BPM|255,40,0|");
Serial.print(result.heartBPM);
Serial.print("|SaO2|0,0,255|");
Serial.print(result.SaO2);
Serial.println("}");
lcd.clear();
lcd.setCursor(1,0);
lcd.print("BPM: ");
lcd.print(pulseOxymeter.heartBPM());
lcd.setCursor(6,1);
lcd.print("SpO2: ");
lcd.print(pulseOxymeter.SaO2());
lcd.print(" %");
}
//These are special packets for FlexiPlot plotting tool
Serial.print("{P0|IR|0,0,255|");
Serial.print(result.dcFilteredIR);
Serial.print("|RED|255,0,0|");
Serial.print(result.dcFilteredRed);
Serial.println("}");
Serial.print("{P1|RED|255,0,255|");
Serial.print(result.irCardiogram);
Serial.print("|BEAT|0,0,255|");
Serial.print(result.lastBeatThreshold);
Serial.println("}");
delay(10);
//Basic way of determening execution of the loop via oscoliscope
digitalWrite( 2, !digitalRead(2) );
}
111111:85:29: error: request for member 'heartBPM' in 'pulseOxymeter', which is of pointer type 'MAX30100*' (maybe you meant to use '->' ?)
111111:89:29: error: request for member 'SaO2' in 'pulseOxymeter', which is of pointer type 'MAX30100*' (maybe you meant to use '->' ?)
exit status 1
request for member 'heartBPM' in 'pulseOxymeter', which is of pointer type 'MAX30100*' (maybe you meant to use '->' ?)
Вижу неточность: у меня стоит библиотека LiquidCrystal_I2C, но в этой схемке ЖКИ подключен к ардуине напрямую, без И2Ц-адаптера. Может ли этот момент послужить причиной?
Я пытался дописывать в функцию вывода "->", как советует компилятор, по-всякому, но безуспешно. Я не знаю, как работать с функциями библиотеки, какой параметр на что влияет, и как всё это правильно оформлять. Буду очень признателен, если вы объясните мне, где в общем случае обычно добывается подобная информация? Подозреваю, что в авторском описании к библиотеке, но какими запросами лучше искать такие документы? Нет ли В САМИХ библиотеках ключа к пониманию, как с ними работать? Может там и не требуется каких-то дополнительных мануалов для того, чтобы ими успешно пользоваться?
В библиотеках, насколько я понимаю, прописываются-расписываются ФУНКЦИИ, к которым обращается скетч по мере необходимости. Если библиотека НИКАК не откомментирована автором - можно ли понять ИЗ САМОГО ТЕКСТА КОДА, как правильно обращаться с функциями данной библиотеки?
Спасибо! Заменил, как указано выше. Написало, что данное выражение не может быть использовано как функция. Убрал пустые скобки (), т.е. нарисовал в скобках всё точно так, как в строке вывода в компорт. И всё скомпилилось без замечаний.
Прошил, включил. Загрузилось, выводятся показания на ЖКИ. Тестирую.
Программировать не умею, к сожалению. Не знаю, как снизить частоту вывода именно на ЖКИ, не затрагивая частоту опроса датчика и вывод результатов в компорт.
О, только сейчас заметил сообщение nik182 с готовым текстом... Большое спасибо! Но - да, надо бы "кашу из топора" ДОВАРИТЬ! ))
Сейчас проблема с запуском - после слова "Инициализация" вижу пустой экран, надо несколько раз перезапустить, тогда появляются строчки с пульсом и сатурацией. Но и они работают нестабильно - пульс скачет от нескольких сотен до пары десятков, хаотически. Иногда успокаивается, показывает адекватные числа пульса и сатурации...
Переместите lcd.clear(); в конец setup и поставьте задержку 2 секунды delay(2000);. Чистить экран в цикле не надо. Добавьте lcd.print(" "); в 61 и 66 строки. Обратите внимание на 52 и 54 строки - это данные графика Р2 - на LCD те же цифры, что отображаются на графике. Если на графике прыгает то и на LCD тоже будет прыгать. Это то , что даёт программа. Можно усреднить,но от прыжков это не избавит, только уменьшит амплитуду. Замедление не поможет. АЦП работает 1.6 мс. Любой опрос медленнее этого времени даст адекватные данные. Так что 37 Гц что 100 Гц на конечный результат не влияет. Основной цикл крутится около 20 мс.
#include <Arduino.h>
#include <math.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "MAX30100.h"
MAX30100* pulseOxymeter;
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
// LCD 1206 1 2 4 5 6 11 12 13 14 15 16
// Arduino GND +5 13 GND 12 11 10 9 8 +5V GND
// MAX30100 SDA SCL
// Arduino A4 A5
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("Pulse oxymeter test!");
lcd.begin(16,2);
lcd.print("Initializing...");
delay(3000);
lcd.clear();
//pulseOxymeter = new MAX30100( DEFAULT_OPERATING_MODE, DEFAULT_SAMPLING_RATE, DEFAULT_LED_PULSE_WIDTH, DEFAULT_IR_LED_CURRENT, true, true );
pulseOxymeter = new MAX30100();
pinMode(2, OUTPUT);
//pulseOxymeter->printRegisters();
}
//+++
uint32_t askTime = 0; // время последнего измерения. Для измерения времени между измерениями
#define ASK_TIME 10 // Время в мс между измерениями - 10 мс -> 100 Гц; 20 мс -> 50 Гц
uint32_t lsdTime = 0; // время последнего вывода на экран. Время в мс для измерения времени между выводом на экран
#define LSD_TIME 5000 // Время в мс между выводом на экран
//---
void loop() {
//return;
//You have to call update with frequency at least 37Hz. But the closer you call it to 100Hz the better, the filter will work.
//+++ // Ожидаем очередное время измерения для требуемой частоты опроса
uint8_t byteTmp = 0; // Флаг - опоздали 0 успели 1
while(millis() - askTime < ASK_TIME)
{
byteTmp = 1; // Раз ждем, значит успели, установим флаг.
}
askTime = millis(); // Обновляем время последнего опроса
//---
pulseoxymeter_t result = pulseOxymeter->update();
//+++ // Результат while(millis() - askTime < ASK_TIME) выводим после pulseOxymeter->update(),
// чтобы гарантированно не влиять на время его (pulseOxymeter->update()) запуска
if(byteTmp == 0) // Если не уложились во временной интервал, то сообщим об ошибке
{
Serial.println("TimeErr");
}
//---
if( result.pulseDetected == true )
{
Serial.println("BEAT");
Serial.print( "BPM: " );
Serial.print( result.heartBPM );
Serial.print( " | " );
Serial.print( "SaO2: " );
Serial.print( result.SaO2 );
Serial.println( "%" );
Serial.print("{P2|BPM|255,40,0|");
Serial.print(result.heartBPM);
Serial.print("|SaO2|0,0,255|");
Serial.print(result.SaO2);
Serial.println("}");
//+++
if(millis() - lsdTime >= LSD_TIME) // На экран выводим через интервалы LSD_TIME
{
lsdTime = millis(); // Обновляем время последнего вывода на экран
//---
lcd.clear();
lcd.setCursor(1,0);
lcd.print("BPM: ");
lcd.print(result.heartBPM);
lcd.setCursor(6,1);
lcd.print("SpO2: ");
lcd.print(result.SaO2);
lcd.print(" %");
//+++
}
//---
}
//These are special packets for FlexiPlot plotting tool
Serial.print("{P0|IR|0,0,255|");
Serial.print(result.dcFilteredIR);
Serial.print("|RED|255,0,0|");
Serial.print(result.dcFilteredRed);
Serial.println("}");
Serial.print("{P1|RED|255,0,255|");
Serial.print(result.irCardiogram);
Serial.print("|BEAT|0,0,255|");
Serial.print(result.lastBeatThreshold);
Serial.println("}");
//+++
//delay(10); // Задержка перенесена в while(millis() - askTime < ASK_TIME)
//---
//Basic way of determening execution of the loop via oscoliscope
digitalWrite( 2, !digitalRead(2) );
}
Пример кода. За основу взят код из сообщения #77 после исправления. Свои вставленные куски пометил начало и конец //+++ и //--- . Работоспособность не проверял.
Перепрошил. После включения устройства пишет "Initializing...", пока подано питание. Несколько перезагрузок могут включить строчки показаний, а могут и не включить. Случайный процесс. Убрал 2000 в конце сетапа, поставил 10. Никаких изменений.
Но если строчки показаний включились на экране, то, в принципе, показания, выводимые на ЖКИ, насколько я могу судить, повторяют показания в компорте. И тем вполне меня устраивают на данном этапе.
Разобраться бы теперь с загрузкой. Что-то там не так...
По варианту Bruzzer: наблюдаю те же проблемы с загрузкой, что и в варианте nik182 (после слова "Инициализация..." - пустой экран, несколько раз надо переподключать питание, чтобы включились строки показаний). Плюс к тому, когда (и если) включились строки - показания иногда самопроизвольно замирают, т.е. перестают обновляться через каждые 5000 (5 сек).
Сделал. Ничего не поменялось. Иногда включаются строчки показаний, но, как правило, после выключения слова "Инициализация..." экран остаётся пустым. А когда удаётся добиться индицирования показаний, то ведут они себя хаотически, и периодически замирают. Потом размораживаются, и опять показывают мусор... Что-то не так.
Так у меня этот же экземпляр "нормально" работает с другой прошивкой... С той, которая показывает стационарную сатурацию и что попало вместо пульса. Сейчас опять ею прошился - всё работает "нормально", как и работало!
Чудес не бывает. Если есть код, где работает нормально , то надо туда попробовать добавить то, что Вам надо из не работающего и посмотреть, на каком этапе начнутся глюки.
Ну я попробовал, описал выше... Только строго наоборот: за основу взял строгоновский скетч, куда добавил строчки вывода на ЖКИ - из того скетча, который нормально работает с ЖКИ, но ненормально - с 30100. Но из обсуждения выше я понял, что тупого добавления строчек для решения проблемы отнюдь недостаточно. Нужно понимать, сколько времени занимает процесс опроса датчика, и сколько - процесс вывода на ЖКИ. Понять-то понял, но до практической имплементации этого моего "понятия" - как до Луны...
Может лучше какой-то другой дисплей приобрести, с хорошо обкатанной людьми библиотекой? А то добавить строчки с выводом на ЖКИ - я хоть неправильно, но могу. А вот наоборот, как в тот, "рабочий" скетч (в котором, по сути, работает только ЖКИ) вставить СТРОГОНОВСКИЙ скетч - вообще не представляю...
Немного поясню свои слова про контроль периода измерений. И насколько меня стоит слушать.
Я не работал с данным датчиком, и не знаю как он работает, так же и с дисплеем.
Я исходил только из того, что автор библиотеки рекомендует вызывать update ее как можно ближе к 100 Гц. А в вашем исходном коде это не проверялось. Может быть это и не надо. Но если переделать скетч на контроль частоты запуска, то можно это и проверить. Задавать разные периоды и смотреть - успевает ли программа и есть ли изменение точности. Менять длительность периода можно при желании и кнопкой. Я не читал вашу тему целиком. Может быть вопрос точности уже не актуален.
Если все же контролировать длительность цикла loop, то обращу ваше внимание, что вы довольно много выводите в serial, я не уверен, но кажется у вас при определенных условиях может полностью заполниться буфер serial. Может быть это и не важно. Если важно, то - или меньше выводить, или поднять скорость serial.
Не реагирует SpO2 ни на дыхание чистым О2, ни на дыхание в кулёк. Дышал примерно по минуте того и другого. Кислородом - из баллона, десять полных вдохов. В кулёк - тоже минуту, но частота вдохов там непроизвольно повышалась; терпел, пока не начало конкретно торкать в ножки. Бррр... Неприятная процедура... Следил за числовыми показаниями, что в окне монитора (открывается нажатием на кнопку с изображением компьютерного монитора, "Opens Serial Terminal"). Если какие-то изменения и были, то в пределах нескольких десятых долей процента. Всё пляшет вокруг 94%, +/- несколько десяток. Магическое число... Не думаю, что это нормально. Надо поиграться с токами светодиодов, я понимаю.
Пульс обнаруживается только на пальцах. С соблюдением вышеописанных нюансов. Пульс в запястьях и в мочках ушей этот экземпляр не видит.
Шумный второй китаец (виновник не чип, а что-то в обвязке):
https://mega.nz/file/pIljCIgT#XUlxuYzFnDfnp4gCbEqaDdheF6oVpo3frlgQvs4pUD8
Переставил чип с шумной платы на исправную (китайскую). Общее впечатление - чувствительность хуже, устойчивую детекцию пульса поймать труднее. Сатурация на дыхание кислородом не реагирует, как и в первом случае. Детекция постоянно сбивается; тыкался всеми пальцами, какие есть в наличии, по-всякому.
Типичная картинка (но в данный момент пульс детектируется, а обычно розовые пики находятся "под водой" - под ровной синей линией, в голубой заливке):
https://mega.nz/file/cB13SYLT#iEzetDeu438v0PBqRQ2nyZIwYC_gCF76kV7ZGtzW6xs
Теперь попробую посадить этот чип на МОЮ плату, где сейчас сидит первый китайский чип...
зы: То ли чип прогрелся, пока писал это сообщение, то ли фаза Луны поменялась - сейчас уже работа второго экземпляра стала очень похожа на работу первого. Но всё равно, как-то медленнннннее он выходит на детекцию пульса, адаптируется гораздо дольше, чем первый... Если не торопиться и подержать палец, то примерно секунд через сорок "подводные пики" "выходят на поверхность", и стартует детекция сердечного ритма (картинка выше)... А вот сатурация всё равно так и не работает. Не думаю, что стОит пересаживать его на мою плату, ибо тут что в лоб, что по лбу...
Снимаю первого китайца с моей платы, сажу туда европейца!
Европеец:
https://mega.nz/file/RNsBAQBL#OfLpe790isVZQ-AGW9qqvC_NAUVlw5GJ-an6I0AJ5Yo
https://mega.nz/file/wNlF0QiJ#GIi2TgSZmNyrKbaru8pk8phAWL6m4iujvwVeVokdOcU
https://mega.nz/file/Yc1FAYZb#SV7Vf06FQhe1EPuqdthckQUNOGOc8yFxNerc-dcVur4
https://mega.nz/file/wMtlzIwL#cAkR-bHToLOvyiDpgMUGWaDCAOZ8R6nzR6qRriYSDPk
ПОКА каких-то особых отличий - ни в графиках, ни во впечатлениях от работы - НЕ наблюдаю. Кроме того, что на графике Р1 кривые вроде как полностью сместились в положительную область, и через ноль не переходят. Размах сигнала в районе 200 .. 250 ед. - примерно то же, что и было у второго китайца... Хотя, впрочем, побольше, даже раза в полтора-два... Но 600 единиц, как с утра, с первым, пока добиться ни разу не удалось.
ДА, а направленные вниз зубцы синей линии (перед встречей с розовыми пиками), сейчас в несколько раз "глубже", чем было у китайцев. Это то, что бросилось в глаза...
Кислород пока закончился, реакцию показаний сатурации не тестировал.
Сатурация быстро набирается простым упражнением - набираем полную грудь воздуха и пытаемся выдохнуть зажав нос и закрыв рот. Усилие прикладывать максимально возможное на 5 -10 секунд, тем самым создавая избыточное давление в лёгких и активно насыщая кровь кислородом. Через несколько вдохов - давление - выдохов начинает кружиться голова - признак высокой сатурации. Мне достаточно 5-7, что бы сатурация с 94 поднялась до 97 минуты за 2. Потом примерно за те же 2 - 3 минуты возвращается к значению 94. Бонусом падает пульс на 10 единиц.
А посмотрите на "заводской Китай". Там съёмник изготовлен так, что палец все время одинаково ложится на мыргалку. Отсюда и повторяемость результатов , а как следствие - пересчет raw в human-readable.
На выходных уделяю внимание семейным заботам, всё по теме осталось на работе. Продолжим с понедельника. За упражнение, повышающее сатурацию - спасибо, попробуем!
Насчёт заводских китайцев ("напалечных прищепок", надо полагать?) - не имею возможности их препарировать. Здесь покупать под разборку - дорого, а с Али что-то происходит нехорошее, связанное со всемирным фестивалем, думаю. Несколько заказов не пришли, пришлось просить продавцов продлить срок защиты; один уже просрочен оказался - возврата денег тоже нет уже недели две... Такого раньше не было. Как бы не загнулась лавка. Было бы весьма печально, как для голожопых самодельщиков...
Хочу добиться от прибора, чтобы он реагировал на упражнения, влияющие на сатурацию: дыхание в кулёк, задержку дыхания с последующей компрессией воздуха в груди, и подобные вариации.
Поигрался с настройками:
ток красного светодиода (авторское значение = 27,1 мА);
"магическое число" (65000);
порог срабатывания детектора пульса (100).
По сути вопроса - безуспешно. На изменения настроек система реагирует явным образом (яркость свечения красного; изменения в графике Р0 с изменении "магического числа"; увеличение числа ложных срабатываний детектора пульса с понижением порога срабатывания). Всё якобы работает, но только не так, как это нужно мне. На изменения реагирует только пульс - вне зависимости от комбинаций настроек: во время компрессии воздуха в груди довольно резво повышается на пару десятков ударов, а после выдоха - проседает примерно на ту же величину. Потом восстанавливается. Сатурация на всё это совершенно не реагирует...
Насчёт тока красного светодиода - в настройках, очевидно, имеется в виду НАЧАЛЬНЫЙ ток. Который после прикладывания пальца ступенчато регулируется автоматически. Т.е. какое стартовое значение тока ни выставляй, он либо повысится до некой нормы, нужной системе, либо понизится - до неё же. Просто на автоподстройку (на ступенчатый перебор значений токов) уходит время, и чтобы его сэкономить, пользователю предлагается вручную установить значение, наиболее близкое к тому, которое обычно выбирает система, применительно к данному экземпляру чипа. Тогда пульс начинает детектироваться практически сразу после прикладывания пальца, без автоперебора токов красного светодиода (что легко заметить визуально).
Вообще как-то всё печально. Бьюсь, как рыба об лёд... Смущает несоответствие авторской картинки P0 с тем, что есть у меня. Такое впечатление, что на момент написания статьи, в монитор выводились другие значения для этого графика - а именно БЕЗ отсечки постоянной составляющей. Была надежда, что всё дело именно в этом, но поскольку график Р0 участника nik182 имеет вид практически идентичный с моим, и при этом сатурация адекватно реагирует на физические упражнения, то график Р0 тут ни при чём...
Куда копать далее - понятия не имею. Вышел на упор.
На счёт автоматики уровня свечения диодов я не уверен. Посмотрите предпоследнюю картинку в #35. Я вывел сырые данные, без обработки. Средний уровень данных АЦП по RED 24500 из 65000, по IR 28700. Эти уровни зависит только от того, как приложил палец. Если постоянно удерживать палец в одном положении, то они ни как не меняются. Это значит, что никакой подстройки нет. Кроме того, в блоге около картинки №12 прямо говориться, что надо самому изменить ток диодов так, что бы отклик АЦП был примерно одинаков для обоих каналов и был меньше 65000 с помощью balanceIntesities.
Копать дальше в сторону цифровой обработки сигналов. Для получения адекватного значения сатурации надо аккуратно рассчитать RMS флуктуаций двух сигналов на частоте (!) сердцебиения. Любые другие колебания - от наводок сети 50 Гц, от тремора пальца - у меня его видно не вооружённым глазом на кривой пульса с частотой 10-15 Гц, и прочие дают большую погрешность и за ними можно не увидеть необходимые изменения, тем более, что изменения эти до 3% и меньше. Здесь не плохо было бы набирать статистику для уменьшения ошибки.
P0 в блоге только на картинках 4,5,7 они соответствуют Вашим и моим картинкам. Размах колебаний меньше 1000.
По автоподстройке - выставьте в .h начальный ток красного светодиода 4,4 мА. Сохраните, прошейте, включите, дождитесь загрузки и включения красного светодиода. ВЫключите свет, и положите палец на сенсор - чтобы ваш светящийся ноготь был вам хорошо виден. В таких условиях я без труда, чётко и ясно, вижу ступенчатое увеличение яркости красного светодиода до некоторого среднего значения. В конце такого цикла автоподстройки, одна ступень яркости иногда вроде бы отыгрывает назад, на понижение (процесс как бы совершает колебание вокруг целевого значения), после чего, как правило, происходит устойчивый "захват" пульса детектором, что динамически иллюстрирует график P1. Всего визуально различимо прохождение около пяти градаций яркости, каждая по полсекунды. Кстати, эти полсекунды тоже можно регулировать в .h - у меня, например, и стоит 500 мс, по умолчанию.
Насчёт остального - какие конкретные практические шаги вы порекомендуете? Чтобы крутить параметры более-менее осмысленно? Та модифицированная вами библиотека, которую вы предлагали выше - выводит ли она на P0 сырые данные с неотфильтрованной постоянной составляющей? Как можно практически рассчитать RMS кардиограммы? И что потом с этими расчётами делать, куда конкретно вставлять их результаты?
Если идти по тексту блога, то я имею в виду Р0 (IR LED RAW), изображённый на картинках 9, 10, 11, 12 и, наконец, 14. Я не знаю точно, куда вы смотрите, но на всех этих графиках я вижу вертикальную ось с отметками чуть ниже 1 000 000, напротив которых и расположены обе кривых (ИК и К каналы): https://morf.lv/implementing-pulse-oximeter-using-max30100
зы: Прикольно, на Р2 (красный - пульс, синий - сатурация) я могу чётко наблюдать вспышки своих экстрасистолий. Чуть только сердце затрепыхается - сразу из-за правого среза графика выезжает пик с почти вертикальными фронтом и спадом. Детектор пульса работает чётко! А вот график сатурации (Р2, синий) остаётся совершенно невозмутимым, что ни предпринимай...
Смотрю я туда же. Картинки 9, 10, 11, 12 и, наконец, 14 это картинки после обработки. К реальным сырым сигналам значения на осях не имеют никакого отношения. Реальные сырые значения на картинках 4,5,7 - это я уже писал. Примите как данность, что остальные картинки без алгоритмов обработки автора статьи Вы повторить не сможете в тех размерах осей как на картинках 9, 10, 11, 12 и, наконец, 14. Если сделать подобную обработку, то форма повториться, амплитуды скорее всего нет.
На счёт подстройки я уже тоже писал - каждый шаг программы вызывает один раз balanceIntesities - подпрограмму которая пытается подстроить ток. Время подстройки Вы указали правильно. Никакого автомата, исключительно программными средствами.
Расчёт сатурации не понятен. Похоже,что RMS считается непрерывно, без относительно к сердечному ритму. Соответственно когда кривые гладкие, без шума, по результат как то ворочается, как только на кривых появляется шум то что получается не понятно. Кроме того, если заглянуть в документ TI slaa274b.pdf то увидим что R через логарифм считается со штрихом, а графики сатурации для R без штриха. Как переводить одно в другое нигде не написано, но указывается, что уровни для этой процедуры должны быть близки. Вот гугл перевод оттуда: ===========
Для каждой длины волны света, то значение постоянного тока удаляются из сигнала, выходящий из части переменного сигнала, который отражает уровень артериальной оксигенации. Среднеквадратичное значение рассчитывается путем усреднения квадрата сигнала по числу циклов сердечных сокращений. Измерение постоянного тока непрерывно рассчитывается путем усреднения сигналов за несколько циклов сердечного сокращения.
Спасибо за разъяснения. Т.е. ситуация, для меня по крайней мере, выглядит достаточно сложной. Поскольку у меня нет понятных мне инструментов для того, чтобы свести значения постоянных составляющих двух каналов в необходимый коридор. Автор вроде бы приводит в тексте кусок кода, позволяющий это сделать, но как это выполнить практически - не объясняет... Статья для программистов.
Время подстройки
RED_LED_CURRENT_ADJUSTMENT_MS 500
увеличил до 1000 мс. Синяя кривая на графике Р2 (сатурация) начала реагировать на компрессию воздуха в грудной клетке. НО - строго наоборот от того, что описываете вы - у меня она резко проседает ВНИЗ, примерно на 4%, держится там несколько секунд, и так же резко возвращается на исходный уровень (в р-н 94%).
Ну по крайней мере хоть какой-то реакции удалось наконец добиться...
зы: Увеличил также вдвое кол-во периодов усреднения сатурации, с 4 до 8. Вроде сатурация стала адекватно реагировать на "ныряние" с задержкой дыхания. Особенно хорошо видно, если на графике Р2 выключить красную кривую пульса - тогда сатурация растягивается во весь экран, и все реакции кривой становятся хорошо видны.
Прочитал, стало интересно. Max30100 не имею, а судя по этому топику, похоже и заказывать не стоит. Вот стало интересно: а если взять простой фоторезистор от набора Ардуино УНО, его можно приспособить как "регистратор" вместо диода или нет?
Да можно, но только два светодиода красный и инфракрасный и один фотодиод. Если читаете по английски, то есть полное описание как сделать железо со всеми номиналами http://www.ti.com/lit/an/slaa274b/slaa274b.pdf . МК другой, но это не принципиально. Но с max30100 всё же легче. Диоды, усилители, да и корпус датчика - всё в одном флаконе.
Уже прочел, спасибо. Меня смущает что фоторезистор имеет "гистерезис" или "память" и времена релаксации в даташитах по 20-30мсек. Нашел это https://community.alexgyver.ru/threads/arduino-kak-lego-pulsoksimetr-i-ne-tolko.3162/, но там несколько иная схема как мне показалось.
Ваша статья просто кладезь.
P.S. И ещё сильно смущает "математика". И по вашей ссылке там тоже предварительно уровни освещения подбираются так, чтобы отклик на обоих частотах был одинаков, а уже потом, считают переменную составляющую и её обрабатывают. И получается что в части "оксиметр" берется отношение логарифмов .. заранее подогнанных уровней. Меня это несколько напрягает, т.к. подогнать можно что угодно и куда угодно. Или я ошибаюсь? Как это "калибровать"?
По наводке в 50гц. Можно же "заземлять" измеряемый палец, обмотав его проводочком и соединив с Землей АЦП .. должно сильно помочь.
По оксигенации: раз измерение в пальце, если его туго бинтовать, поступление крови снизится и оксигенация должна измениться за счет накопления венозной крови. Так кто-то пробовал смотреть на изменения показаний?
Берётся отношение RMS, при одинаковом уровне DC составляющей. От уровня DC зависит размах колебаний. Если DC одинаковая, то не надо пересчитывать AC составляющую для которой рассчитывают RMS и вычисления упрощаются.
Бинтовать это лишнее. Достаточно сильнее нажать на датчик, что бы увидеть эффект.
Старые мануалы TI вообще кладезь информации. Я часто ими пользуюсь для получения схемотехнических решений. Достаточно зайти в раздел примеров на МК MSP430. Всё подробно расписано со схемами, номиналами деталей, расчётами режимов работы. Сейчас так не делают.
Как я понял естественный диапазон изменений насыщенности довольно узкий 94 - 99 %. И бинтование, может быть, поможет удовлетворить любопытство - "насколько низкий уровень насыщенности может измерять данный прибор." (Знать бы еще какой должен быть уровень у пережатого пальца.)
Нашел фотодиод, буду пробовать. Кстати, по ссылке на Гайвера понравилось решение с RGB светодиодом - можно смотреть отклик на ещё паре частот, что должно позволить определять или надежней или что-то ещё, какие-то HbMet и HbCO2 надо почитать на эту тему..
> Max30100 не имею, а судя по этому топику, похоже и заказывать не стоит.
Странное заключение...
Если решите собирать на рассыпухе, то с очень большой долей вероятности (если со схемотехникой до сего момента вы общались примерно на уровне ардуинского бредборда с дырочками) - в САМОМ лучшем случае вы получите РОВНО те же проблемы, что и описанные выше, ПЛЮС пляски с железом: усилители, наводки, и т.д. и т.п... Просто, по-пионерски - усилить сигнал с фотодиода, оцифровать его и пытаться потом вытянуть оттуда какую-то полезную инфу - путь в никуда, потому что сперва вы должны отвязаться от массы мешающих, непостоянных факторов. Температура - первое, что приходит в голову. В чипе, насколько я читал, это решается дифференциальным измерением, когда сигнал снимается не относительно какого-то стационарного эталона, а относительно другого сигнала (помехи). И получается железная фильтрация - задолго до АЦП. Это только потом идут программные нормализация и ФНЧ Баттерворта (если иметь в виду статью, ссылку на которую я поместил в начале этого топика). Наконец, вы же не впихнёте схему из апноута по ссылке выше в пластинку объёмом несколько куб.мм... Будут навесные провода, или какая-то разводка, что неизбежно повлечёт за собой цепь традиционных проблем с наводками, которые придётся преодолевать... Смысл? Дешевле - ТОЧНО не получится. ЛУЧШЕ? Гхм... Кхм...
Мне кажется, что 30100 (-1, -2) - одно из лучших решений по теме "любительской", "домашней" оксиметрии, что предлагает рынок на сегодняшний день.
Бинтовать палец не имеет смысла, потому что вы задавите пульс. А наличие обнаруженного пульса - непременное условие расчёта сатурации. То же самое произойдёт, если вы сильно надавите пальцем на сенсор.
Резюме - не нужно требовать от РАБОТАЮЩЕЙ технологии больше, чем она может дать. Завышенные ожидания рождают разочарование. Если же играться в пределах этого поля - можно достичь счастья!
Удалено автором.
> Особенно хорошо видно, если на графике Р2 выключить красную кривую пульса - тогда сатурация растягивается во весь экран, и все реакции кривой становятся хорошо видны.
> Завышенные ожидания рождают разочарование.
Две ключевые фразы. Ждал слишком многого там, где оно не могло проявиться. Короче, выставил я все параметры в заголовке библиотеки по умолчанию, и выключил красную кривую пульса на P2. Оставшаяся синяя линия (сатурации) уверенно отображает даже обычные глубокие вздохи, безо всяких компрессий и минутных задержек. Просто спокойно посидеть пару минут, с пальцем на датчике, дождаться, пока все переходные пики и неровности уедут за левый срез окна Р2, потом глубоко вздохнуть, задержать на секунду воздух, и глубоко выдохнуть, после чего продолжить спокойное дыхание. И вот такая получается картинка:
https://mega.nz/file/AA0hkJIa#ueoYOkDCVxFEuw70WhzaBidlaRuHctkkZyFsfMgPDXE
Вполне себе приличный отклик, только я бы усреднял штук тридцать-сорок отчётов сатурации. В мануале я бы написал, что измерять сатурацию надо в одно и то же время суток, например, с утра, после пробуждения. Надеть сенсор на палец, и, например, через минуту, после сигнала окончания измерения, считать показания с дисплея. Во время цикла измерения ЖКИ должен отображать режим ожидания результатов - например, заполняющийся статус-бар или что-то в этом роде. Кроме того, прибор должен иметь индикатор детекции пульса, лучше всего звуковой. Чтобы пользователь не ждал напрасно, если палец лёг не так, как надо, и пульс не захвачен. Как пошли щелчки захвата пульса из звукового индикатора - с этого момента ожидаем звукового сигнала окончания измерения, и считываем результаты с ЖКИ. Что-то в этом роде надо написать... Усреднение - среднее арифметическое, с отбрасыванием единичных мусорных отчётов, отличающихся от общей массы на заданный порог. И всё должно получиться...
Разобрался, наконец, со спорадическими пропаданиями детекции пульса. Руки (пальцы) должны быть ТЁПЛЫМИ. У меня, например, традиционно плохое кровообращение в конечностях (хронически холодные руки и ноги); а погоды сейчас стоят, мягко говоря, нежаркие. Постановил: перед каждым экспериментом несколько минут прогревать пальцы под лампой накаливания. Теперь получаю неизменно превосходный результат - амплитуду импульсов кардиограммы (Р1) наблюдаю от 200 до 700 единиц (амплитуда - это то, что выше нулевой линии, от нуля до вершины импульса). Никогда не менее 300. Отказы детекции пульса просто прекратились... Если долго держу палец на сенсоре, без движения, то вижу, как амплитуда кардиограммы постепенно уменьшается. Всё логично.
Как видим, всё постепенно становится на свои места!
зы: Прикольно наблюдать разницу в амплитуде импульсов кардиограммы между прогретыми (левая рука) и непрогретыми (правая) пальцами. Прогретые - от 200 ед. и выше; непрогретые - до 30 ед. (и, естественно, никакой детекции).
думаю, тема давно переосла Песочницу - ее нужно либо в аппаратные, либо в проекты
У меня руки всегда горячие. Поэтому Ваших проблем не наблюдал. Всё работало сразу. Ещё одно доказательство того, что важны все элементы - и датчик и объект :-) . Ещё раз поздравляю с решением проблемы.
> думаю, тема давно переосла Песочницу - ее нужно либо в аппаратные, либо в проекты
Если тут требуется моё согласие - я только "за"! Хочется помочь как можно большему числу таких как я сам горемык, чтоб не плясали с бубном, не наступали на уже пройденные грабли... И в этой связи - было бы здорово добавить слово "Пульсоксиметр" в заглавие топика, для поисковых ботов. Сам я это сделать как будто не могу - вроде как некуда нажимать...
> ... и датчик и объект
)) Если бы у объекта все проблемы решались прогревом конечностей... Умище, УМИЩЕ девать некуда! ))
Другими словами: помогите убогому, люди добрые... Пытаюсь скомпилить из двух скетчей один. Чтобы строгоновский скетч выводил данные не только в компорт, но и в 1602 - показания пульса и сатурации. Взял готовый проект, где фигурирует 1602, посмотрел, попытался... Не компилится, хоть ты тресни... Понимаю, что тупо, но не могу сам решить - старенький уже, и нифига в этом не волоку... Уже честно пытался объявить, подставить в функции вывода НУЖНЫЕ имена переменных, но... Выручайте!
Приведите ошибку копи-пасте в свёрнутый спойлер - галочка свернуть на второй вкладке с кодом. У меня всё откомпилилось без ошибок.
У меня пишет следующее:
Вижу неточность: у меня стоит библиотека LiquidCrystal_I2C, но в этой схемке ЖКИ подключен к ардуине напрямую, без И2Ц-адаптера. Может ли этот момент послужить причиной?
Я пытался дописывать в функцию вывода "->", как советует компилятор, по-всякому, но безуспешно. Я не знаю, как работать с функциями библиотеки, какой параметр на что влияет, и как всё это правильно оформлять. Буду очень признателен, если вы объясните мне, где в общем случае обычно добывается подобная информация? Подозреваю, что в авторском описании к библиотеке, но какими запросами лучше искать такие документы? Нет ли В САМИХ библиотеках ключа к пониманию, как с ними работать? Может там и не требуется каких-то дополнительных мануалов для того, чтобы ими успешно пользоваться?
В библиотеках, насколько я понимаю, прописываются-расписываются ФУНКЦИИ, к которым обращается скетч по мере необходимости. Если библиотека НИКАК не откомментирована автором - можно ли понять ИЗ САМОГО ТЕКСТА КОДА, как правильно обращаться с функциями данной библиотеки?
Вам надо заменить в ошибочных строках pulseOxymeter на result.
pulseOxymeter используется только один раз pulseoxymeter_t result = pulseOxymeter->update();
Пытаюсь скомпилить из двух скетчей один. Чтобы строгоновский скетч выводил данные не только в компорт, но и в 1602 - показания пульса и сатурации...
Из описания библиотеки - Производить измерения надо с частотой не менее 37 Гц а лучше 100 Гц
Если вы после каждого измерения будете пытаться вывести на дисплей - вы и частоту измерений уменьшите, и на экране может быть каша.
Надо выводить на экран реже. Раз в несколько секунд.
Если умеете программировать, то полезно было бы постараться приблизиться к рекомендованным 100 Гц опроса датчика.
Спасибо! Заменил, как указано выше. Написало, что данное выражение не может быть использовано как функция. Убрал пустые скобки (), т.е. нарисовал в скобках всё точно так, как в строке вывода в компорт. И всё скомпилилось без замечаний.
Прошил, включил. Загрузилось, выводятся показания на ЖКИ. Тестирую.
Ещё раз большое спасибо!
Программировать не умею, к сожалению. Не знаю, как снизить частоту вывода именно на ЖКИ, не затрагивая частоту опроса датчика и вывод результатов в компорт.
Да, ваша правда - нестабильно как-то всё работает... То есть показания, то пустой экран. Несколько раз приходится перезапускать, чтобы появились.
О, только сейчас заметил сообщение nik182 с готовым текстом... Большое спасибо! Но - да, надо бы "кашу из топора" ДОВАРИТЬ! ))
Сейчас проблема с запуском - после слова "Инициализация" вижу пустой экран, надо несколько раз перезапустить, тогда появляются строчки с пульсом и сатурацией. Но и они работают нестабильно - пульс скачет от нескольких сотен до пары десятков, хаотически. Иногда успокаивается, показывает адекватные числа пульса и сатурации...
Переместите lcd.clear(); в конец setup и поставьте задержку 2 секунды delay(2000);. Чистить экран в цикле не надо. Добавьте lcd.print(" "); в 61 и 66 строки. Обратите внимание на 52 и 54 строки - это данные графика Р2 - на LCD те же цифры, что отображаются на графике. Если на графике прыгает то и на LCD тоже будет прыгать. Это то , что даёт программа. Можно усреднить,но от прыжков это не избавит, только уменьшит амплитуду. Замедление не поможет. АЦП работает 1.6 мс. Любой опрос медленнее этого времени даст адекватные данные. Так что 37 Гц что 100 Гц на конечный результат не влияет. Основной цикл крутится около 20 мс.
P.S. Изменил текст программы.
Пример кода. За основу взят код из сообщения #77 после исправления. Свои вставленные куски пометил начало и конец //+++ и //--- . Работоспособность не проверял.
Перепрошил. После включения устройства пишет "Initializing...", пока подано питание. Несколько перезагрузок могут включить строчки показаний, а могут и не включить. Случайный процесс. Убрал 2000 в конце сетапа, поставил 10. Никаких изменений.
Но если строчки показаний включились на экране, то, в принципе, показания, выводимые на ЖКИ, насколько я могу судить, повторяют показания в компорте. И тем вполне меня устраивают на данном этапе.
Разобраться бы теперь с загрузкой. Что-то там не так...
А пока пробую вариант Bruzzer...
У меня был неправильный комментарий к #define LSD_TIME 5000
правильно
#define LSD_TIME 5000 // Время в мс между выводом на экран
(в исходном сообщении исправил)
По варианту Bruzzer: наблюдаю те же проблемы с загрузкой, что и в варианте nik182 (после слова "Инициализация..." - пустой экран, несколько раз надо переподключать питание, чтобы включились строки показаний). Плюс к тому, когда (и если) включились строки - показания иногда самопроизвольно замирают, т.е. перестают обновляться через каждые 5000 (5 сек).
Я не спец по работе с экраном. Т.к. в моем варианте не учтены рекомендации nik182 то
По рекомендации nik182 добавьте задержку в setup после lcd.clear();
lcd.begin(16,2);
lcd.print("Initializing...");
delay(3000);
lcd.clear();
delay(2000);
И уберите lcd.clear(); в цикле loop (опять же По рекомендации nik182).
Сделал. Ничего не поменялось. Иногда включаются строчки показаний, но, как правило, после выключения слова "Инициализация..." экран остаётся пустым. А когда удаётся добиться индицирования показаний, то ведут они себя хаотически, и периодически замирают. Потом размораживаются, и опять показывают мусор... Что-то не так.
Были у меня пару таких дисплеев - бился с ними долго, не мог понять что делать - потом заказал у другого на али - пришли нормальные.
Так у меня этот же экземпляр "нормально" работает с другой прошивкой... С той, которая показывает стационарную сатурацию и что попало вместо пульса. Сейчас опять ею прошился - всё работает "нормально", как и работало!
Чудес не бывает. Если есть код, где работает нормально , то надо туда попробовать добавить то, что Вам надо из не работающего и посмотреть, на каком этапе начнутся глюки.
Ну я попробовал, описал выше... Только строго наоборот: за основу взял строгоновский скетч, куда добавил строчки вывода на ЖКИ - из того скетча, который нормально работает с ЖКИ, но ненормально - с 30100. Но из обсуждения выше я понял, что тупого добавления строчек для решения проблемы отнюдь недостаточно. Нужно понимать, сколько времени занимает процесс опроса датчика, и сколько - процесс вывода на ЖКИ. Понять-то понял, но до практической имплементации этого моего "понятия" - как до Луны...
Может лучше какой-то другой дисплей приобрести, с хорошо обкатанной людьми библиотекой? А то добавить строчки с выводом на ЖКИ - я хоть неправильно, но могу. А вот наоборот, как в тот, "рабочий" скетч (в котором, по сути, работает только ЖКИ) вставить СТРОГОНОВСКИЙ скетч - вообще не представляю...
Немного поясню свои слова про контроль периода измерений. И насколько меня стоит слушать.
Я не работал с данным датчиком, и не знаю как он работает, так же и с дисплеем.
Я исходил только из того, что автор библиотеки рекомендует вызывать update ее как можно ближе к 100 Гц. А в вашем исходном коде это не проверялось. Может быть это и не надо. Но если переделать скетч на контроль частоты запуска, то можно это и проверить. Задавать разные периоды и смотреть - успевает ли программа и есть ли изменение точности. Менять длительность периода можно при желании и кнопкой. Я не читал вашу тему целиком. Может быть вопрос точности уже не актуален.
Если все же контролировать длительность цикла loop, то обращу ваше внимание, что вы довольно много выводите в serial, я не уверен, но кажется у вас при определенных условиях может полностью заполниться буфер serial. Может быть это и не важно. Если важно, то - или меньше выводить, или поднять скорость serial.