Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года

Работа с несколькими измерительными модулями

Вы не вошли.

 Поиск | Регистрация | Вход 

07.09.2021 11:38:14
#1

Участник
Здесь с 11.08.2021
Сообщений: 6

Работа с несколькими измерительными модулями

Здравствуйте.
Поставлена следующая задача - опрашивать одновременно модули LTR11 и LTR212 и выводить показания на экран. Использется крейт LTR-U-8. Работаю в Borland C++ Builder 6.

Опыта работы сразу с несколькими модулями нет (Как и в использовании более 2х потоков). До этого создавал простые программы на основе ваших примеров.
Решение сделал такое: Опрос модулей вынес в отдельный поток. В одном цикле вызываются функции Recv и Process обоих модулей (сначала LTR11 потом LTR212). Частоту опроса LTR11  установил 1000Гц, LTR212 - 150Гц (режим 4х каналов с высокой точностью). Настроил массивы для хранения одного элемента (за вызов Recv получаем одно значение) т.к. процесс длится не больше 5 сек. Массивы обработанных данных через вызов Synchronize() передаю в главный поток и там отображаю в TextBox и точками на графике.

Возникла проблема: при текущих настройках (LTR11 - 1000Гц, LTR212 - 150ГЦ) практически сразу возникает задержка в показаниях LTR11. Однако если снизить частоту LTR11 до равной или меньшей LTR212 проблема пропадает. Проблема, мне кажется, вызвана разницей частот опроса.

Вопросы следующие:
1. Правильно ли опрашивать модули с такой разницей частот опроса в одном потоке как я делаю сейчас? Или их стоит разнести по отдельным потокам?
2. В функции Recv() есть аргумент - "количество слов данных в запрашиваемом массиве". Правильно я понял, что это количество точек, которое мы запрашиваем на считывание из буфера АЦП? И зависит ли время исполнения этой функции от этого аргумента?
3. В руководстве программиста LTR11 написано, что показания сначала записываются в fifo-буфер АЦП, а Recv() нужна для того чтобы "своевременно откачивать данные". Допустим в буфере уже есть 1000 значений, с помощью Recv() я запросил 100. Получается мы считаем первые 100 точек(fifo-буфер). Что произойдёт с остальными? Они сдвинутся(<-) и запись продолжиться? Или буфер обнулится?
4. Есть ли подробное руководство по использованию временных меток(tmark, Start)? Информации из руководств программиста модулей мне не хватило, чтоб разобраться.

С уважением, Максим(gug.shm@mail.ru).

P.S.
Пожалуйста, если у вас есть и если можно, можете предоставить пример ПО для одновременного опроса нескольких модулей?

07.09.2021 13:05:09
#2

Сотрудник "Л Кард"
Здесь с 17.04.2014
Сообщений: 1,291

Re: Работа с несколькими измерительными модулями

1. Во первых по поводу "Настроил массивы для хранения одного элемента (за вызов Recv получаем одно значение)", выглядит не очень правильно для частоты 1000 Гц. ОС общего назначения вполне может задерживать вызовы на единицы-десятки мс, а у Вас для приема по одной точке вызовы должны выполняться раз в 1 мс. При таких частотах и выше данные следует принимать и обрабатывать все же блоками (например принимать и обрабатывать по 20 точек с частотой обновления на графике в 50 раз в секунду, сильно большая частота обновления все равно не до конца понятно, что дает).
Во вторых, не до конца понял, Вы с обоих модулей принимаете по одной точке? Тогда LTR212 выдает 150 (точнее 150,15) точек (по каждому разрешенному) каналу в секунду, а LTR11 - 1000 суммарно, т.е. на одну точку LTR212 приходится 6,6 точек LTR11 (при одном канале LTR212), если Вы читаете последовательно по одной точке, то Вы будете читать  с наименьшей скоростью из двух потоков (150.15 Гц) и, соответственно, данные будете получать от LTR11 в 6,6 раз медленнее, чем они приходят.
Т.е. если использовать такой подход, то нужно рассчитывать размер приема данных исходя из соотношения частот, например по 20 точек LTR11 и по (3 точки * кол-во каналов) для LTR212 (LTR212 - АЦП с параллельными каналами и частота АЦП соответствует частоте каждого канала, т.е. с частотой 150.15 Гц будут выдаваться блок по одной точке на каждый разрешенный канал, LTR11 - АЦП с коммутацией каналов, где каналы опрашиваются последовательно, и частота задается общая на все каналы, а частота на канал - частота АЦП/число каналов), тогда частота блоков с обоих модулей будет около 50 блоков в секунду. Другой вопрос, что это может хорошо работать для одинаковых модулей в одном крейте, а вот для разных в принципе этот подход не очень удобен, т.к. частоты могут быть не кратны (если речь идет о LTR212, а не LTR212M - то у него еще и генератор свой, а не общей от крейта), иметься разные задержки старта и т.п. Также сложнее обрабатывать нештатные ситуации, т.к. прием с одного модуля влияет на другой.

Я сам предпочитаю подход с выделением потока на каждый модуль и работа с каждым модулем как отдельными (только с добавлением обработки меток при необходимости) , т.к. это сильно упрощает сам сбор, избавляет от многих сложностей из-за разных частот сбора, разных задержек, все модули работают независимо и т.д.

Но подходы могут вообще разные. В LGraph2, насколько я знаю, используется третий подход, где всего один поток, в котором периодически вызывается Recv на все модули с минимальным таймаутом и заведомо большим размером, т.е. раз в заданный интервал вчитываются по сути все накопленные данные, правда он требует потом ручного выравнивания данных на кадр при обработке.

2. Функция Recv возвращает управление, когда произойдет одно из событий  - будет принято запрашиваемое число отсчетов (точнее 32-битных слов, для некоторых модулей, как LTR212 одному отсчету соответствует два слова), либо истечет заданный таймаут. Т.е. функция ожидает одно из этих событий, что первое произойдет, то и послужит условием завершения работы функции. Как правило используется один из двух подходов. Либо определяющим для штатной работы выбирается параметр кол-во точек, а таймаут задается заведомо большим, и в этом случае скорость прихода точек (со всеми возможными задержками передачи) от модуля определяет время выполнения функции, а таймаут служит только чтобы не зависнуть в функции навсегда при нештатных ситуаций (для потока на модуль с моей точки зрения - это наиболее удобный вариант). Во втором подходе наоборот, кол-во точек задается заведомо большее, а таймаут определяет время работы функции, т.е. работа идет по методу вычитать все, что накопится за это время (но требует выравнивания данных на кадр).

3. Если в буфере накопилось 1000 отсчетов, то Вы считаете самые первые пришедшие 100 отсчетов и в буфере останется еще 900. При следующем чтении Вы вычитаете следующие 100 отсчетов и в буфере останется 800 (плюс в конец добавятся новые пришедшие данные за это время). Т.е. в фифо новые данные всегда добавляются в конец буфера, а Вы вычитываете их из начала буфера всегда последовательно (если конечно не произойдет переполнение буфера из-за слишком медленного считывания, когда размер несчитанных данных превысит размер буфера, в этом случае новые данные будут отбрасываться, а Recv на считывании блока с разрывом данных вернет ошибку, соответствующую переполнению буфера).

4. С точки зрения описания программиста, информация об этом находится в разделе 4.6 общего руководства по ltrapi (https://www.lcard.ru/download/ltrapi.pdf). Также раздел 4.7 руководства пользователя (https://www.lcard.ru/download/ltr.pdf).

Контакты

Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4, стр. 2

Многоканальный телефон:
+7 (495) 785-95-25

Отдел продаж: sale@lcard.ru
Техническая поддержка: support@lcard.ru

Время работы: с 9-00 до 19-00 мск