Write to Analgue Output of DAQ

This forum deals with BCI2000 configuration issues.
Locked
nabeel
Posts: 9
Joined: 27 Sep 2006, 12:07

Write to Analgue Output of DAQ

Post by nabeel » 02 Nov 2006, 08:39

Dear All,
I am using NI PCI-MIO-16E-4, i want to ask that is it possible to write also to Analogue Channel of NI DAQ using BCI2000. The idea is, during conducting an experiment, by using BCI2000 send certain parameters to a second PC by writing these parameters to the Analogue Output of NIDAQ and access it from the second PC.

Thanks

Nabeel

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

DA Output ...

Post by gschalk » 02 Nov 2006, 11:39

Nabeel,

BCI2000 does not support analog output out of the box. However, the National Instrument boards do support concurrent analog input and analog output, and this capacity could be easily added to the National Instruments source module. Here are some functions that you could use as a framework to get you started.

I hope this helps.

The Gerv
//////////////////


// **************************************************************************
// Function: DACOutput
// Purpose: This function writes output signals to the analog output ports
// Parameters: daccfg - ptr to structure that describes output (defined in NIDAQ.h)
// Returns: NIDAQ_ERR_NOERR (1) ... no error
// **************************************************************************
int NIADC::DACOutput(const DACCFG *daccfg)
{
i16 iStatus, iRetVal;
i16 iChan = 0;
i16 piChanVect[NIDAQ_MAXDACHANNELS];
i16 iGroup = 1;
u32 ulCount;
u32 ulIterations = 1;
i16 iFIFOMode = 0;
i16 iDelayMode = 0;
f64 dUpdateRate;
i16 iUpdateTB = 0;
u32 ulUpdateInt = 0;
i16 iWhichClock = 0;
i16 iUnits = 0;
// i16 iIgnoreWarning = 0;
int i, numchannels, sample, channel;

// fprintf(fp, "entering DACOutput\r\n");

// determine number of channels and set the channel map
numchannels=0;
for (i=0; i<NIDAQ_MAXDACHANNELS; i++)
if (daccfg->channelmap)
{
piChanVect[numchannels]=i;
numchannels++;
}

// determine total number of samples (channels*samples)
ulCount=daccfg->numsamples*numchannels;
if (daccfg->numsamples > NIDAQ_MAXDASAMPLES)
throw("Number of analog output samples too large");
if (daccfg->numsamples <= 0)
throw("Number of analog output samples <= 0");

// allocate buffer to hold output samples]
if (pioutBuffer) delete [] pioutBuffer;
if (pdoutBuffer) delete [] pdoutBuffer;
pdoutBuffer=new f64[daccfg->numsamples*numchannels];
pioutBuffer=new i16[daccfg->numsamples*numchannels];

// create the interleaved output buffer
i=0;
for (sample=0; sample<daccfg->numsamples; sample++)
for (channel=0; channel<NIDAQ_MAXDACHANNELS; channel++)
{
if (daccfg->channelmap[channel]) // if this channel is active
{
pdoutBuffer=daccfg->samples[channel][sample];
i++;
}
}

// set up group of channels ... only needed for AT-AO-6/10 boards
// iStatus = WFM_Group_Setup(iDevice, numchannels, piChanVect, iGroup);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Group_Setup", iIgnoreWarning);

// set this to triggered mode if desired
if (daccfg->triggered)
{
// device, what is triggered, BY what signal, and which transition ?
iStatus = Select_Signal(iDevice, ND_DIGITAL_LINE, ND_PFI_7, ND_LOW_TO_HIGH);
iStatus = Select_Signal(iDevice, ND_OUT_START_TRIGGER, ND_PFI_1, ND_LOW_TO_HIGH);
// iStatus = Select_Signal(iDevice, ND_OUT_START_TRIGGER, ND_IN_START_TRIGGER, ND_LOW_TO_HIGH);
// iRetVal = NIDAQErrorHandler(iStatus, "Select_Signal", iIgnoreWarning);
}

// scale buffer values
iStatus = WFM_Scale(iDevice, iChan, ulCount, 1.0, pdoutBuffer, pioutBuffer);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Scale", iIgnoreWarning);

// load buffer values into output buffer
iStatus = WFM_Load(iDevice, numchannels, piChanVect, pioutBuffer, ulCount, ulIterations, iFIFOMode);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Load", iIgnoreWarning);

// converts a waveform generation update rate to the timebase and update-interval values needed to produce the desired rate
iStatus = WFM_Rate(daccfg->outputrate, iUnits, &iUpdateTB, &ulUpdateInt);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Rate", iIgnoreWarning);

// configure output frequency
iStatus = WFM_ClockRate(iDevice, iGroup, iWhichClock, iUpdateTB, ulUpdateInt, iDelayMode);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_ClockRate", iIgnoreWarning);

// actually start the output
iStatus = WFM_Group_Control(iDevice, iGroup, NIDAQ_iOpSTART);
// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Group_Control/START", iIgnoreWarning);

// fprintf(fp, "exiting DACOutput\r\n");

return(NIDAQ_ERR_NOERR);
}


// **************************************************************************
// Function: DACOutputCleanup
// Purpose: Once an analog output operation has been started (using DACOutput),
// this function loops until the operation has finished and then
// does the necessary cleanup operations
// Parameters: daccfg - ptr to structure that describes output (defined in NIDAQ.h)
// Returns: NIDAQ_ERR_NOERR (1) ... no error
// **************************************************************************
int NIADC::DACOutputCleanup()
{
i16 iWFMstopped = 0;
i16 iStatus, iRetVal;
i16 iYieldON = 1;
i16 iChan = 0;
i16 iGroup = 1;
u32 ulItersDone, ulPtsDone;
// i16 iIgnoreWarning = 0;

// loop until analog output finished
while ((iWFMstopped == 0) && (iStatus == 0))
{
iStatus = WFM_Check(iDevice, iChan, &iWFMstopped, &ulItersDone, &ulPtsDone);
iRetVal = NIDAQYield(iYieldON);
Sleep(1);
}

// iRetVal = NIDAQErrorHandler(iStatus, "WFM_Check", iIgnoreWarning);

// Set group back to initial state
iStatus = WFM_Group_Control(iDevice, iGroup, NIDAQ_iOpCLEAR);
// Set output at 0 volts
iStatus = AO_VWrite(iDevice, iChan, 0.0);

return(NIDAQ_ERR_NOERR);
}




// daccfg structure
// fill in your own values here
daccfg.outputrate=(f64)1000;

daccfg.triggered=false; // we do not want the DAC output to be triggered by external inputs

daccfg.numsamples=100; // samples
daccfg.channelmap[0]=true;
daccfg.channelmap[1]=true;




struct STIMULUSCFG
{
int offset[STIMULUS_MAXSTIMCHANNELS]; // offset of first stimulus in train
int offset2[STIMULUS_MAXSTIMCHANNELS]; // offset of 2nd component of first stimulus in train
int duration[STIMULUS_MAXSTIMCHANNELS]; // duration of stimuli
int duration2[STIMULUS_MAXSTIMCHANNELS]; // duration of 2nd component of stimulus
int numstimuli[STIMULUS_MAXSTIMCHANNELS]; // number of stimuli in stimulus train
int stimulispacing[STIMULUS_MAXSTIMCHANNELS];
double stimulusamplitude[STIMULUS_MAXSTIMCHANNELS];
double stimulusamplitudemultiplier2ndcomp[STIMULUS_MAXSTIMCHANNELS];
};

DACCFG daccfg;

nabeel
Posts: 9
Joined: 27 Sep 2006, 12:07

Post by nabeel » 19 Nov 2006, 09:07

Dear Gerv,
First excuse me for my being a newcomer to C++. and thankyou very much for the code. I read the code but I could not get the point that how to add this part in the main program, the structure of “daccfg” I searched it in NIDAQ.h but I could not find it.
what I want to do is, I want to read the output signal from the filter chain at “ClassFilter, 2.D”,
And then write this output signal to NIDAQ output channel in real time. As you told BCI2000 does not have this functionality but NI boards do have.
I will be thankful if you guide me through the steps.
Nabeel

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

NIDAQ ...

Post by gschalk » 20 Nov 2006, 13:46

Nabeel,

Here is the definition for the DACCFG structure. With this, you should have practically all the code you need. Let me know if you have further questions.

Gerv









struct DACCFG
{
bool channelmap[NIDAQ_MAXDACHANNELS]; // which output channels are enabled
int numsamples; // how many samples do we actually write (number of samples is the same for all output channels)
f64 samples[NIDAQ_MAXDACHANNELS][NIDAQ_MAXDASAMPLES]; // this holds the actual output samples in Volts
f64 outputrate; // output rate in Hz
bool triggered; // triggered output (PFI0) ?
};

nabeel
Posts: 9
Joined: 27 Sep 2006, 12:07

Post by nabeel » 23 Nov 2006, 10:14

Dear Gerv,

I have made the modifications, i.e declaring the functions in in NIADC.cpp and .h .From the documentaion i read that the output of classfilter is NumControlSignals channels and 1 element per channel. now, to read this output and send it to NIDAC output channel, how can i call NIADC in this filer? and how to put output in DACCFG? I am providing Classifier output to DACCFG structure. To make an object of NIADC in Classfilter i am including NADC.h in Classfilter, and as result having errors :oops:

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

NIDAQ

Post by gschalk » 24 Nov 2006, 08:53

Nabeel,

I will be glad to review your code if you send it to me (schalk@wadsworth.org) and make suggestions. However, I will not be able to write the code for you. Thus, I suggest that you consult somebody with C++ programming experience using the suggestions I will send you.

Best,
The Gerv

Locked

Who is online

Users browsing this forum: No registered users and 21 guests