Проблема вызова большого количества VI.

Простейшие вопросы в области инженерной разработки
Аватара пользователя
donetskant
beginner
beginner
Сообщения: 17
Зарегистрирован: 04 дек 2014, 23:12
Версия LabVIEW: 2019
Благодарил (а): 1 раз
Контактная информация:

Проблема вызова большого количества VI.

Сообщение donetskant »

Всем здравствуйте!
Есть такая задача. На вход программы (с драйвера) поступает пакет данных: 10600 каналов по 2048 значений (подряд во времени) в каждом канале. Пакет поступает каждые 200мс. То есть частота получаемых данных: 10140 раз в секунду (приблизительно 10 кГц). Нужно отфильровать информацию по каждому каналу полосовым фильтром (вернее даже шестью полосовыми фильтрами, шесть полос). Самая нижняя полоса пропускания – от 0 до 50 Гц.
Логичное решение – загонять все данные в очередь и в параллельном цикле каждый пакет данных разбивать на каналы, каждый канал – массив 2048 значений и этот массив загонять в фильтр Баттерворта. Но если мы вызываем каждые 200 мс фильтр, то на частотах от 0 до 50 Гц мы каждые 200 мс на выходе будем наблюдать переходный процесс в самом начале (на остальных частотах так же, просто не так заметно).
Как этого избежать? В фильтре есть специальный вход:
init/cont controls the initialization of the internal states. The default is FALSE. The first time this VI runs or if init/cont is FALSE, LabVIEW initializes the internal states to 0. If init/cont is TRUE, LabVIEW initializes the internal states to the final states from the previous call to this instance of this VI. To process a large data sequence that consists of smaller blocks, set this input to FALSE for the first block and to TRUE for continuous filtering of all remaining blocks.
Он работает, всё замечательно на одном канале, переходный процесс есть только в начале, а потом процесс фильтрации установившийся. Конкретно фильтр работает в subVI. Но когда мы увеличиваем количество каналов до двух, то разумеется, нам нужно 2 различных экземпляра этого subVI (можно его так же назвать FGV, но кажется это не совсем корректно).
Хорошо, идем дальше. Как сделать 10600 различных экземпляров subVI и обратиться к ним в внешнем цикле (к примеру, они будут иметь разное имя файла)? Вот здесь пример кода без различных экземпляров subVI.
2023-04-04_00-02-11.png
2023-04-04_00-02-11.png (3.56 КБ) 1213 просмотров
Я пока придумал сделать 10600 subVI в папке и вызывать их асинхронным вызовом. И я понимаю, что с этого момента я делаю что-то не то… Проблема появилась сразу же. Вот этот код выполняется очень долго, около 4 минут.
2023-04-04_00-01-40.png
2023-04-04_00-01-40.png (6.67 КБ) 1213 просмотров
Может быть можно как-нибудь вызывать в цикле разные экземпляры subVI? Я понимаю, что возможно работа с 10600 FGV это плохой вариант – обращение к памяти, хранение 10600 экземпляров и прочее.
В принципе, есть очень тупой вариант вообще не использовать различные экземпляры subVI, а загонять каждый раз в фильтр пакет значений, которые нужно отфильтровать, а перед ним – небольшой набор предыдущих данных, чтобы фильтр по предыдущим данных прошел переходный процесс и «устаканился», фильтруя нужный пакет данных.
Что посоветуете? Заранее спасибо за ответы.
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

donetskant писал(а): 04 апр 2023, 00:16 10600 каналов по 2048 значений (подряд во времени) в каждом канале.
Можно попробовать (я не делал, только в качестве идеи)
Скопировать фильтр из библиотеки, переименовать, залезть внутрь, изменить массивы одномерные на двумерные, добавить цикл FOR
А вообще тема была где-то ранее
Фильтр.png
Изображение
Аватара пользователя
donetskant
beginner
beginner
Сообщения: 17
Зарегистрирован: 04 дек 2014, 23:12
Версия LabVIEW: 2019
Благодарил (а): 1 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение donetskant »

ujin1 писал(а): 04 апр 2023, 05:49 Скопировать фильтр из библиотеки, переименовать, залезть внутрь, изменить массивы одномерные на двумерные, добавить цикл FOR
То есть Вы предлагаете обрабатывать все 10600 каналов в одном вызове фильтра? Не факт что это это будет параллельно...
А почему Вы предлагаете перейти от фильтра Баттерворта (заказчки сказали что я должен использовать его, но конечно это обсуждаемо) к IIR Cascade Filter? Вы просто уже второй человек, котоый вместо проблемы вызова 106600 экземпляров FGV и параллельной обработки каналов предлагаете использовать другой фильтр, который будет работать посладовательно. Объясните пожалуйста, почему?
Я попробую и проверю время выполнения.
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

donetskant писал(а): 04 апр 2023, 09:52 То есть Вы предлагаете обрабатывать все 10600 каналов в одном вызове фильтра? Не факт что это это будет параллельно...
Смотря на чем вы выполняете. Однопроцессорная система, многопроцессорная система, FPGA
На однопроцессорной системе все равно все будет выполняться последовательно, только еще и переключение будет между процессами (потоками)
На многопроцессорной системе можно настроить параллельное выполнение. Правой кнопкой по циклу FOR -> Configure Iteration Parallelism.
На FPGA можно распараллелить в зависимости от объема. Как не знаю не пробовал.
Кроме этого выполнение зависит от вызываемой dll. Может ли вызываться несколько экземпляров этой библиотеки. Это все узнается и проверяется.
Iteration parallelism.png
Iteration parallelism.png (9.41 КБ) 1168 просмотров
Iteration parallelism1.png
Iteration parallelism1.png (401 байт) 1168 просмотров
donetskant писал(а): 04 апр 2023, 09:52 А почему Вы предлагаете перейти от фильтра Баттерворта (заказчки сказали что я должен использовать его, но конечно это обсуждаемо) к IIR Cascade Filter? Вы просто уже второй человек, котоый вместо проблемы вызова 106600 экземпляров FGV и параллельной обработки каналов предлагаете использовать другой фильтр, который будет работать посладовательно. Объясните пожалуйста, почему?
Я попробую и проверю время выполнения.
Если залезть внутрь фильтра Баттерворта, там увидите как раз IIR Cascade Filter. Там во многих фильтрах один и тот же IIR Cascade Filter только с разными коэффициентами.
Коэффициенты оставляете одни и те же. Т.е. не индексируете вход с коэффициентами.
Изображение
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение dadreamer »

donetskant писал(а): 04 апр 2023, 00:16Я пока придумал сделать 10600 subVI в папке и вызывать их асинхронным вызовом. И я понимаю, что с этого момента я делаю что-то не то… Проблема появилась сразу же. Вот этот код выполняется очень долго, около 4 минут.
2023-04-04_00-01-40.png
Может быть можно как-нибудь вызывать в цикле разные экземпляры subVI?
Вы неверно запускаете реентерантные :vi: , посмотрите: Asynchronously Calling Multiple Instances of a VI for Parallel Execution. Должна быть опция Enable simultaneous calls on reentrant VIs (0x40). Не нужно делать 10600 экземпляров SubVI, достаточно открыть один SubVI и сделать 10600 запусков его в роли клона. IIR Cascade Filter (DBL).vi уже сконфигурирован как реентерантный. Осталось только проверить, как поведёт себя функция IIR_Filter2 из lvanlys.dll, если её запустить одновременно из разных потоков. Если там глобальные переменные используются (похоже на это), то вызовы могут наложиться друг на друга и на выходе будет ерунда. :)
Последний раз редактировалось dadreamer 04 апр 2023, 13:25, всего редактировалось 2 раза.
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

dadreamer писал(а): 04 апр 2023, 11:12
donetskant писал(а): 04 апр 2023, 00:16Я пока придумал сделать 10600 subVI в папке и вызывать их асинхронным вызовом. И я понимаю, что с этого момента я делаю что-то не то… Проблема появилась сразу же. Вот этот код выполняется очень долго, около 4 минут.
2023-04-04_00-01-40.png
Может быть можно как-нибудь вызывать в цикле разные экземпляры subVI?
Вы неверно запускаете реентерантные :vi: , посмотрите: Asynchronously Calling Multiple Instances of a VI for Parallel Execution. Должна быть опция Enable simultaneous calls on reentrant VIs (0x40). Не нужно делать 10600 экземпляров SubVI, достаточно открыть один SubVI и сделать 10600 запусков его в роли клона. IIR Cascade Filter (DBL).vi уже сконфигурирован как реентерантный. Осталось только проверить, как поведёт себя функция IIR_Filter2 из lvanlys.dll, если её запустить одновременно из разных потоков. Если там глобальные переменные используются (похоже на это), то вызовы могут наложиться друг на друга и на выходе будет ерунда. :)
Переключение между потоками (процессами) должно быть медленнее чем индексация массива + вызов функции (меньше миллисекунды).
Плюс в других потоках (процессах) эта функция так же будет вызываться.
В библиотеке фильтров есть Butterworth Filter PtByPt VI. Аналогичная, только один канал и данные последовательно подаются по одному значению. Внутри вызывается IIR Cascade Filter PtByPt VI
В этой функции вызовы dll только для рассчета коэффициентов. Остальное внутри фукции. Скорее всего IIR_Filter2 так же используется только для рассчета. А данные для хранения и использования в следующий циклах берутся/сохраняются во внешних сдвиговых регистрах.
IIR PtByPt.png
Изображение
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

donetskant писал(а): 04 апр 2023, 09:52
ujin1 писал(а): 04 апр 2023, 05:49 Скопировать фильтр из библиотеки, переименовать, залезть внутрь, изменить массивы одномерные на двумерные, добавить цикл FOR
То есть Вы предлагаете обрабатывать все 10600 каналов в одном вызове фильтра? Не факт что это это будет параллельно...
А почему Вы предлагаете перейти от фильтра Баттерворта (заказчки сказали что я должен использовать его, но конечно это обсуждаемо) к IIR Cascade Filter? Вы просто уже второй человек, котоый вместо проблемы вызова 106600 экземпляров FGV и параллельной обработки каналов предлагаете использовать другой фильтр, который будет работать посладовательно. Объясните пожалуйста, почему?
Я попробую и проверю время выполнения.
Выложите где-нибудь массив данных близких к рабочим. Вроде затраты времени небольшие и можно попробовать.
Изображение
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

Изображение
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение dadreamer »

Да, эта функция точно реентерантная. Вот листинг IIR_Filter2 из C Gen:

Код: Выделить всё

/* IIR Filtering using either 2nd order stages or 4th order stages */
/*
		Michael Cerna 2/22/94

*/

#include "lvdsp.h"

#define dnone 0
#define dfir  1
#define diir  2

//errnum DSPAPI aaIIRCascadeFiltering(floatnum x[],sizenum n,AALIIRFilterPtr filterInfo,floatnum y[]); 

extern "C" errnum IIR_Filter2 (FlNum1DH xH,intnum *stage_type,FlNum1DH aH,FlNum1DH bH,
							   FlNum1DH sH,binary *reset,errnum *dsperr);

errnum IIR_Filter2 (
		FlNum1DH xH,
		intnum *stage_type,		/* 0 == 2 for 2nd order, 1 == 4 for 4th order */
		FlNum1DH aH,
		FlNum1DH bH,
		FlNum1DH sH,
		binary *reset,
		errnum *dsperr)
{
	sizenum ns,na,nb,n;
	intnum init=1;
	floatnum *s,*y,*a,*b;
	intnum whichfilter=dnone;
	sizenum stage_num,stage_size,order;
	intnum type;
	AALIIRFilterInfo filterInfo;
	errnum	err=noErr;
	
	ENTERLVSB
	*dsperr=NoErr;
	
	n=(**xH).dimSize;
	if (n<1) {
		*dsperr=SamplesGTZeroErr;
		LEAVELVSB
		return(noErr);
	}
	
	ns=(**sH).dimSize;
	
	na=(**aH).dimSize;		/* number of reverse coefficients */
	nb=(**bH).dimSize;		/* number of forward coefficients */
	
	switch (*stage_type) {
	case(0):
		stage_size = 2;
		type = 0;		/* valid type for filter structure */
		order = na;		/* valid order for filter structure */
		break;
	case(1):
		stage_size = 4;
		type = 2;		/* valid type of bandpass */
		order = na>>1;	/* valid order for filter structure */
		break;
	default:
		*dsperr=InvSelectionErr;
		LEAVELVSB
		return(noErr);
	}
	
	if(na > 0)
		stage_num = na/(stage_size);
	else if(nb > 0)
		stage_num = nb/(stage_size+1);
	else
		stage_num = 0;
	
	if (*reset == LVBooleanTrue) init=0; /* if reset is true, filter retains state info in sH */
	
	whichfilter |= (na>0) ? diir : dnone;
	whichfilter |= (nb>0) ? dfir : dnone;
	
	switch (whichfilter) {
				case 0 :		/* no a's or b's do nothing  */
					break;
				case 1 :		/* have b's, no a's ... err? */
				case 2 :		/* have a's, no b's ... err? */
					*dsperr = ArraySizeErr;
					break;
				case 3 :		/* have a's and b's do iir filter */
					/********
						* Resize state info if necessary
					********/
					if (ns != (stage_size*stage_num)) {
						if(err=NumericArrayResize(fD,1L,(UHandle*)&sH,(stage_size*stage_num))) {
							NumericArrayResize(fD,1L,(UHandle*)&sH,0L);
							(**sH).dimSize=0;
							*dsperr=OutOfMemErr;
							LEAVELVSB
							return(err);
						}
						(**sH).dimSize = ns = (stage_size*stage_num);
						init=1;
					}
					
					s=(**sH).data;
					
					/* clear state info - now cleared inside IIR_Filtering2 */
					/* if (init) {
					if (nb>1)
					ClearMem((UPtr)s,(**sH).dimSize*sizeof(floatnum));
					} */
					/*
					*		set up and perform the iir filter
					*/
					y=(**xH).data;
					a=(**aH).data;
					b=(**bH).data;
					
					filterInfo.type = type;
					filterInfo.order = order;
					filterInfo.reset = init;
					filterInfo.na = na;
					filterInfo.a = a;
					filterInfo.nb = nb;
					filterInfo.b = b;
					filterInfo.ns = ns;
					filterInfo.s = s;
					
					*dsperr=aaIIRCascadeFiltering(y,n,&filterInfo,y);
					
					break;
				}  /* end case */
	
	if (*dsperr!=NoErr) {
		NumericArrayResize(fD,1L,(UHandle*)&xH,0L);
		(**xH).dimSize=0;
	}
	
	LEAVELVSB
	return (noErr);
}
Если флаг reset установлен, в aaIIRCascadeFiltering выполняется очистка и обнуление массива:

Код: Выделить всё

	if(filterInfo->reset) {
		//Clear1D(s, ns);
//		aaClear1D(s, ns);
		memset(s,0,ns*sizeof(floatnum));
		filterInfo->reset = 0;
		}
maxim_MA
beginner
beginner
Сообщения: 15
Зарегистрирован: 16 авг 2022, 17:07
Версия LabVIEW: 2020
Благодарил (а): 1 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение maxim_MA »

<Была такая же проблема, ее можно решить штатными библиотеками пример для ких фильтра, по аналогии можно переделать любой.
Вложения
fir.JPG
Аватара пользователя
donetskant
beginner
beginner
Сообщения: 17
Зарегистрирован: 04 дек 2014, 23:12
Версия LabVIEW: 2019
Благодарил (а): 1 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение donetskant »

ujin1 писал(а): 04 апр 2023, 11:44 Выложите где-нибудь массив данных близких к рабочим. Вроде затраты времени небольшие и можно попробовать.
ht_tps://drive.google.com/file/d/1Bq2TPkRWtBwaAuatBJl1bgP6XIDtfXSR/view?usp=sharing (убрать подчеркивание)
35мб.
Большое спасибо всем, очень полезно, разбираюсь дальше.
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

maxim_MA писал(а): 04 апр 2023, 14:07 <Была такая же проблема, ее можно решить штатными библиотеками пример для ких фильтра, по аналогии можно переделать любой.
Проверил только что. Работает параллельно. Даже на orange Pi. Нужно дальше разбираться с обновлением коэффициентов на лету. Понятно, что и это будет работать.
Переделанный файл из примера.
Вложения
Extract the Sine Wave.vi
(32.17 КБ) 29 скачиваний
Filter.vi
(20.88 КБ) 26 скачиваний
Изображение
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

donetskant писал(а): 04 апр 2023, 15:25
ujin1 писал(а): 04 апр 2023, 11:44 Выложите где-нибудь массив данных близких к рабочим. Вроде затраты времени небольшие и можно попробовать.
ht_tps://drive.google.com/file/d/1Bq2TPkRWtBwaAuatBJl1bgP6XIDtfXSR/view?usp=sharing (убрать подчеркивание)
35мб.
Большое спасибо всем, очень полезно, разбираюсь дальше.
ОК пример завтра попробую
Изображение
ujin1
adviser
adviser
Сообщения: 231
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 18 раз
Поблагодарили: 37 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение ujin1 »

donetskant писал(а): 04 апр 2023, 15:25
ujin1 писал(а): 04 апр 2023, 11:44 Выложите где-нибудь массив данных близких к рабочим. Вроде затраты времени небольшие и можно попробовать.
ht_tps://drive.google.com/file/d/1Bq2TPkRWtBwaAuatBJl1bgP6XIDtfXSR/view?usp=sharing (убрать подчеркивание)
35мб.
Большое спасибо всем, очень полезно, разбираюсь дальше.
Как будто все работает на Ваших данных. Нужно проверить. Первый вариант создать десяток фильтров и второй вариант параллельно этот метод. Чтобы убедиться в отсутствии разницы и влияния каналов друг на друга.
2 фильтра, 10600 каналов, 2048 значений.
На orange Pi 2 фильтра, 300 каналов, 2048 значений обрабатываются за 200 мс. Они у меня под рукой, просто ради эксперимента проверяю.
Каналы, фильтры друг на друга не влияют, режим continue работает.
Можно еще что-нибудь пооптимизировать и поразбираться. Сделать выделение буферов под массивы при инициализации или смене параметров. Tools->Profile->Show Buffer Allocations.
Вложения
Фильтр.jpg
10600x2048.vi
(958.61 КБ) 43 скачивания
Filter.vi
(35.25 КБ) 42 скачивания
Изображение
Аватара пользователя
donetskant
beginner
beginner
Сообщения: 17
Зарегистрирован: 04 дек 2014, 23:12
Версия LabVIEW: 2019
Благодарил (а): 1 раз
Контактная информация:

Re: Проблема вызова большого количества VI.

Сообщение donetskant »

ujin1 писал(а): 05 апр 2023, 09:36 Каналы, фильтры друг на друга не влияют, режим continue работает.
Можно еще что-нибудь пооптимизировать и поразбираться. Сделать выделение буферов под массивы при инициализации или смене параметров. Tools->Profile->Show Buffer Allocations.
Удивительно, что Вы так заинтересовались моей проблемой! Спасибо Вам огромное за помощь! :super:
Ответить
  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Для чайников»