Плагин: сумматор и дифференциатор
1. Назначение
Плагин осуществляет создание трех расчетных каналов на базе двух каналов АЦП. Плагин создает три расчетных канала: один содержит сумму двух входных каналов, а два других - производные входных каналов.
- Суммирование каналов.
- Дифференцирование каналов.
- Работает в реальном масштабе времени.
2. Исходный текст плагина
/*
Плагин, создающий три рассчетных канала:
1. сумму двух каналов
2. производную по каналу A
2. производную по каналу B
На вход плагину поступают два входных канала.
Среда разработки LabWindows CVI 9.0.
*/
#include
#include
#include
#include
#include "..\\include\\plugin.h"
static struct PluginDataInfoStr DataInfo; // структура с настройками АЦП
static int device_index=0; // работаем с первым модулем АЦП
static int first=1; // признак начала поступления данных (когда еще нет предистории)
double *buffer; // временный буфер для расчетов
double dt; // дельта по времени оцифровки АЦП
double last_points[2][2]; // последние два отсчета по обоим каналам АЦП
// *********************************************************************************************************
// собственно главная функция с рассчетом
void __stdcall PluginDataExchange(struct PluginDataStr *data_str)
{
int i, j, adc_channel, index1, index2, nch, n, ch;
double *ptr, *ptr1, *ptr2;
// сгенерируем рассчетный канал, равный сумме двух каналов АЦП
index1=DataInfo.chan_kadr_offset[device_index][DataInfo.adc_channels[0]]; // смещение в кадре первого канала
index2=DataInfo.chan_kadr_offset[device_index][DataInfo.adc_channels[1]]; // смещение в кадре второго канала
ptr1=&data_str->data_to_plugin[index1];
ptr2=&data_str->data_to_plugin[index2];
ptr=&data_str->data_from_plugin[device_index]; // куда складываем результат
for(i=0, nch=DataInfo.nch[device_index], n=data_str->n; i < n; i++, ptr+=3, ptr1+=nch, ptr2+=nch) *ptr=*ptr1+*ptr2;
// комментарий к строке выше: ptr+=3, цифра 3 поскольку плагин генерирует три канала, которые образуют
// кадровую структуру
// сгенерируем производные по двум каналам
for(ch=0; ch < 2; ch++)
{
// переложим данные с текущего канала
n=data_str->n; // сколько кадров пришло
index1=DataInfo.chan_kadr_offset[0][DataInfo.adc_channels[ch]]; // смещение в кадре обрабатываемого канала
ptr1=&data_str->data_to_plugin[index1];
if(first) // если функций вызвана первый раз с момента пуска АЦП
{
ptr=buffer+1; // учитываем специфику функции Difference()
for(i=0; i < n; i++, ptr1 += nch) *ptr++=*ptr1;
buffer[0]=buffer[1]; // производная по первой точке всегда будет ноль (не знаем, что было перед)
last_points[ch][0]=buffer[n-1]; // сохраним последние два отсчета АЦП
last_points[ch][1]=buffer[n];
n--; // пока что нет предистории (прошлых двух точек)
}
else
{
// предистория уже есть, поэтому первые две точки будут взяты из прошлого вызова
ptr=buffer+2;
for(i=0; i < n; i++, ptr1 += nch) *ptr++=*ptr1;
for(i=0; i < 2; i++) buffer[i]=last_points[ch][i];
last_points[ch][0]=buffer[n]; // сохраним последние два отсчета АЦП
last_points[ch][1]=buffer[1+n];
}
Difference (buffer+1, n, dt, buffer[0], buffer[n+1], buffer+1); // расчет производной
ptr=&data_str->data_from_plugin[1+ch]; // куда положим результат
for(i=0, ptr1=buffer+1; i < n; i++, ptr+=3) *ptr=*ptr1++; // перенесем результат
}
data_str->n_from_plugin=n; // сколько создали кадров данных
first=0; // сбросим флаг первого вызова
}
//*********************************************************************************************************
// информационная функция
void __stdcall PluginInfo(struct PluginInfoStr *p_info)
{
int i;
// установим общие переменные
strcpy(p_info->name, "Sumderiv"); // название плагина
p_info->version=0x00010000; // версия 1.0
p_info->lgraph_version=0x221; // плагин разработан для версии 2.33
p_info->max_nch=2; // максимальное число входных каналов 2
p_info->min_nch=2; // минимальное число входных каналов 2
// установим названия входных каналов
for(i=0; i < 2; i++) sprintf(p_info->channel_names[i], "Канал %u", i+1);
p_info->parameters=0; // параметры отсутствуют
}
// *********************************************************************************************************
// обработка данных о параметрах модулей АЦП от LGraph
void __stdcall PluginDataInfo(struct PluginDataInfoStr *d_info)
{
if(!d_info->devices) { strcpy(d_info->error, "Нет модуля АЦП"); return; }
if(!d_info->nch[device_index]) { strcpy(d_info->error, "Не выбраны каналы АЦП"); return; }
DataInfo=*d_info;
dt=2000.0/DataInfo.rate[device_index]; // рассчитаем интервал между отсчетами в секундах
d_info->input_kadrs_min=100; // обрабатываем за один раз не менее 100 кадров
d_info->input_kadrs_max=1000000; // и не более 1e6 кадров
d_info->plugin_nch=3; // число рассчетных каналов, порождаемые плагином
strncpy(d_info->plugin_channel_names[0], "Сумма двух каналов", 23); // названия каналов, порождаемые плагином
strncpy(d_info->plugin_channel_names[1], "Производная канала 1", 23); // названия каналов, порождаемые плагином
strncpy(d_info->plugin_channel_names[2], "Производная канала 2", 23); // названия каналов, порождаемые плагином
if(buffer == NULL) buffer=malloc(sizeof(double)*1000002); // выделим память под временный буфер
if(buffer == NULL) { strcpy(d_info->error, "Не хватает памяти"); return; }
}
// визуальные элементы у плагина отсутствуют
void __stdcall PluginVisualSetting(struct PluginVisualMainStr *main_visual_settings, struct PluginVisualStr p_visual[]){}
/*
Функция сообщает плагину, что начался сбор данных
*/
void __stdcall PluginStartInput(struct PluginDataStr *data_str)
{
first=1; // установим признак начала сбора данных
}
/*
Функция сообщает плагину, что закончился сбор данных
*/
void __stdcall PluginStopInput(struct PluginDataStr *data_str)
{
}
//*********************************************************************************************************
// Функция вызываемая при загрузке - выгрузке DLL плагина
int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if (InitCVIRTE (hinstDLL, 0, 0) == 0) return 0;
break;
case DLL_PROCESS_DETACH:
if(buffer != NULL) free(buffer);
if (!CVIRTEHasBeenDetached ()) CloseCVIRTE ();
break;
}
return 1;
}



