LabVIEW: как обмениваться большим количеством переменных между циклами?

#arrays #loops #labview

#массивы #циклы #labview

Вопрос:

У меня есть два цикла:

  1. Один цикл получает данные с устройства и обрабатывает их. Масштабирует полученные переменные, вычисляет дополнительные данные.
  2. Второй цикл визуализирует данные и сохраняет их.

Существует множество различных переменных, которые необходимо передавать между этими двумя циклами — около 50 переменных. Мне нужно, чтобы второй цикл имел доступ только к самым новым значениям данных. Он должен иметь возможность считывать эти переменные в любое время, когда они необходимы для визуализации.

Каков наилучший способ разделить такой вектор между двумя циклами?

Ответ №1:

Существуют различные способы обмена данными. Самая быстрая и простая — это локальная переменная, однако она довольно неконтролируема, и вам нужно убедиться, что вы записываете их в одном месте (плюс вам нужен индикатор).
Один из самых продвинутых вариантов — создать класс для ваших данных и использовать экземпляр (если вы создаете класс по ссылке, иначе это не будет иметь значения) и создать общедоступный метод ‘GET’.

Между ними у вас есть несколько других вариантов:

  • очереди
  • семафоры
  • узлы свойств
  • глобальные переменные
  • общие переменные
  • уведомители
  • Мероприятия
  • TCP-IP

Короче говоря, лучшего способа нет, все зависит от ваших навыков и приложения.

Комментарии:

1. В итоге я выбрал способ событий. Любой цикл производителя генерирует события, содержащие пользовательские данные с объединенным перечислением (содержащим тип события из предопределенного списка) и вариант с данными события. Потребительские циклы перехватывают любые события по всему приложению, считывают перечисление и затем преобразуют вариант к соответствующему типу данных, в зависимости от значения перечисления. Это работает как шарм с ~ 100 различными перечислениями / типами данных с очень высокой частотой дискретизации. Спасибо всем за ваши предложения.

Ответ №2:

Однако, пока вы рассматриваете циклы в одном приложении, есть хорошие и плохие идеи:

 queues (OK, has most features)
notifiers (OK)
events (OK)
FGVs (OK, but keep an eye on massively parallel access hindering exec)

semaphores (that's not data comms)
property nodes (very inefficient, prone to race cond.)
global variables (prone to race cond.)
shared variables (badly implemented by NI, prone to race cond.)
TCP-IP (slow, awkward, affected by firewall config)
  

Ответ №3:

Быстрый и грязный способ сделать это — записать каждое значение в индикатор в цикле производителя — эти индикаторы могут быть скрыты за экраном или на странице элемента управления tab, если вы не хотите их видеть — и прочитать локальную переменную каждого из них в цикле потребителя. Однако, если у вас есть 50 разных значений, может стать сложно поддерживать этот код, если вам нужно изменить или расширить его.

Как говорит Тон, есть много разных вариантов, но мое предложение было бы:

  • Создайте кластерный элемент управления с именованными элементами, содержащий все ваши данные
  • Сохраните этот кластер как typedef
  • Создайте уведомитель, используя этот кластер в качестве типа данных
  • Объедините данные в кластер (по имени) и запишите это в уведомитель в цикле производителя
  • Прочитайте кластер из уведомителя в цикле потребителя, разделите его по имени и делайте то, что вы хотите с каждым элементом.

Использование кластера означает, что вы можете легко передать его в разные подразделы для обработки разных элементов, если хотите, а сохранение в виде typedef означает, что вы можете добавлять, переименовывать или изменять элементы, и ваш код будет обновляться для соответствия. В вашем потребительском цикле вы можете использовать настройку тайм-аута чтения уведомителя для управления временем цикла, если хотите. Вы также можете использовать уведомитель, чтобы сообщать циклам, когда выходить, принудительно уничтожая его и перехватывая ошибку.

Комментарии:

1. Я согласен, что уведомитель является правильным шаблоном для отображения «только для новейших значений данных».

Ответ №4:

Два способа:

  1. Используйте цикл отображения с SEQ (очередь из одного элемента)
  2. Используйте структуру событий с пользовательским событием. (Не помещайте две структуры событий в один цикл!! Используйте другой)

Используйте перечисление со структурой регистра и вариантом, чтобы привести данные к ожидаемому типу.

(Уведомитель ненадежен для потоковой передачи данных, потому что это схема с потерями. Оставьте это только для запуска небольших действий)

Комментарии:

1. Спрашивающий говорит: «Мне нужно, чтобы второй цикл имел доступ только к самым новым значениям данных». Это именно то, что делает уведомитель. Если бы они хотели фиксировать и регистрировать каждое полученное значение, тогда очередь была бы более подходящей, но для этого варианта использования уведомитель идеален.

2. Возможно, нашему другу не нравится идея потери данных во время процесса отображения / регистрации. Цикл производителя должен быть медленнее, чем у потребителя, чтобы дать «шанс» не потерять значения…

3. Ах, я упустил из виду, что второй цикл «хранит» данные, а также визуализирует их, хотя это не соответствует комментарию о том, что нужны «только самые новые» значения. Отображение и ведение журнала обычно представляют собой два разных процесса, которые должны обрабатываться в отдельных циклах — так, например, цикл ведения журнала может останавливаться и ожидать дискового или сетевого ввода-вывода без зависания дисплея. Используйте уведомитель для отображения и очередь для ведения журнала.

Ответ №5:

Если все ваши переменные могут быть объединены в один кластер для одновременной отправки, то вам следует использовать очередь из одного элемента. Если ваши требования изменятся позже таким образом, что передача не может быть с потерями, то это вопрос изменения ввода в очередь получения VI (с уведомителем вам придется поменять местами все VIs). Настройка отдельных индикаторов и локальных переменных была бы чертовски утомительной. Кроме того, не очень хороший стиль.

Ответ №6:

Если циклы находятся внутри одного и того же VI, то:

Самым простым решением были бы локальные переменные.
Немного лучше использовать общие переменные.
Лучше использовать функциональные глобальные переменные (FGVS)
Лучшим решением было бы использовать SEQ (очередь из одного элемента).

В любом случае, для лучшего понимания, пожалуйста, ознакомьтесь с этой статьей.