Глава 2. Получение и визуализация данных эксперимента
Рассмотрим пример, связанный с автоматизацией регистрации температуры в каком-либо физическом эксперименте. Для этого нам потребуется термопара, подключённая к аналого-цифровому преобразователю (АЦП). Такое электронное устройство мы можем легко найти в стандартной плате сбора данных. Компания National Instruments специализируется на выпуске соответствующих устройств, которые уже давно стали фактическим стандартом для экспериментальных исследований. Однако для работы с этими устройствами обычно используется система LabView, которую мы и собираемся заменить программой на Python.
Мы использовали устройство DAQ (Data acquisition, система сбораданных) NI USB 6351. Это устройство, как следует из его обозначения, использует USB-интерфейс для взаимодействия с компьютером.
Для сопряжения с внешними устройствами (датчиками, периферийным оборудованием) имеется:
Из этого изобилия возможностей мы будем использовать только один аналоговый двуполярный вход AI0 (клеммы + и – ), к которым и подключим термопару.
Первый этап состоит в установке актуальных драйверов поддержки оборудования National Instruments. Возможно, вместе с драйверами вы разрешите инсталлятору установить ряд дополнительных программ, которые обычно весьма полезны на стадии отладки приложений, работающих с DAQ.
Драйверы относятся к свободнораспространяемому программному обеспечению, необходима только регистрация на сайте.
На втором этапе проверяем подключение и работу устройства с использованием загруженной вместе с драйверами программы NI Device Monitor. Устройство сбора данных в нашей системе установилось с именем Dev1, для работы нам нужен аналоговый вход ai0.
Устанавливаем пакет nidaqmx из командной строки Windows в режиме администратора:
python -m pip install nidaqmx
Эта библиотека постоянно модифицируется и её функциональные возможности всё время увеличиваются. Поэтому при использовании рассмотренных ниже примеров следует обязательно руководствоваться актуальным описанием для данной библиотеки.
Мы использовали оболочку IDLE Python в режиме программирования (программа сохранялась в файл и запускалась на выполнение).
Итак, напишем простую проверочную программу на Python для тестирования подключения к плате сбора данных:
Работа с DAQ-устройствами происходит в парадигме задач: сначала устройство программируется на определённый вид деятельности, а затем мы начинаем получать данные с этого устройства. В нашем случае в строке 4 мы программируем аналоговый вход 0 на получение значений напряжения (это выглядит, на первый взгляд, тривиально, но в коллекции методов у нас есть возможность запрограммировать конкретный вход на измерение иных физических величин). Выполняем задачу в строке 5, измеряя в 10 раз значение напряжения. Конструкция with … as (так называемый менеджер контекста, где мы пишем всё, что связано с DAQ-задачей) делает более удобной работу с объектом Task библиотеки nidaqmx и корректно формирует завершение задачи.
Результат выполнения программы будет выведен в виде списка:
[0.07741842546889639, 0.07774029508782221, 0.07774029508782221, 0.07774029508782221, 0.07774029508782221, 0.07741842546889639, 0.07774029508782221, 0.07774029508782221, 0.07806216470670671, 0.07774029508782221]
Теперь подключим термопару (в нашем случае это была термопара железо-константан, т.е. типа J) ко входу ai0 и модифицируем программу следующим образом:
Мы изменили вид данных, возвращаемых со входа ai0, разрешив использовать встроенную в библиотеку калибровку температуры для данного типа термопары (строка 10). В зависимости от вида термопары можно выбрать несколько уже готовых калибровок. В строке 12 указывается, что для каждого обращения к плате сбора данных мы будем брать только одно значение. Однако при этом создаётся цикл (со строки 11) для выборки 100 значений с задержкой между измерениями 0.5 с (строка 14).
Хотелось бы, чтобы измеренное значение появлялось на графике в тот момент, когда выполнено очередное измерение. Для этого в строке 4 переводим окно визуализации графика в интерактивный режим. Теперь поле графика появится сразу после первого выполнения метода plt.pause. Для отображения точек был использован метод scatter из библиотеки matplotlib (строка 13), который выводит точку с указанными значениями координат i, temp на поле графика. Точки линиями не соединяются.
Интерактивный режим включается с помощью метода ion() пакета matplotlib, а выключается методом ioff(). При этом в интерактивном режиме метод show() не используется, вместо него можно использовать метод draw(), который отображает график и не задерживает выполнение программы. В нашем варианте функцию обновления графика с успехом выполняет метод pause().
Если мы хотим привязаться не к номеру измерения, как в рассмотренном примере, а к реальным меткам времени, воспользуемся возможностями модуля time (импорт в строке 3):
Вычисление времени, прошедшего с начала измерения, осуществляется в строке 18. В этом варианте программы мы использовали бесконечный цикл для чтения информации с аналогового входа платы сбора данных, однако предусмотрели выход из программы по нажатию комбинации клавиш Ctrl-C. Для этого использовалась стандартная конструкция обработчика ошибок Python try … except.
Использование метода scatter позволяет достаточно удобно реализовать динамическое отображение измеряемых значений. В принципе, ничто не мешает заменить этот метод классическим plot, однако следует учесть, что линии, соединяющие точки, при этом всё равно не будут отображаться.
Программа, которая строит график в реальном времени с возможностью выбора типа соединительной линии и маркера экспериментальных точек, будет несколько сложнее (представлено Anthony Zhang на github). При этом, как и в классическом виртуальном инструменте LabView Chart, получаем бесконечную «ленту самописца», что очень удобно для визуализации данных с неизвестным временем завершения процесса. Попробуйте реализовать этот вариант программы самостоятельно. Вот что у вас должно получиться:
Обратите внимание, что Python и библиотека matplotlib поддерживают отрисовку специальных символов в подписях осей координат и в любых других текстовых метках на поле графика. Если потребуются отобразить, например, греческие буквы, можно использовать следующую конструкцию:
plt.title(r'$\Sigma \alpha^2 \beta \omega_i$')
Символ r (отключение экранировки) перед текстовой строкой обязателен
Символы \(\sum_{k=1}^{\infty} \Delta_j \) можно изобразить на графике с помощью следующей строки:
r'$\sum_{j=0}^\infty \Delta_j$'
Если вы заметили неточность, ошибку или хотите поделиться своими мыслями по поводу статьи - мы рады обратной связи. Давайте вместе сделаем ресурс лучше!