Hi Evan,
Per your request, I’ve come up with an initial plan for adding support for custom analog output voltage waveforms to MWorks’ NIDAQ interface. Here are the changes involved:
-
Extend the existing Analog Output Voltage Waveform Channel to support a new waveform type (“custom”). Add a parameter called “samples”, whose value should be a list (or the name of a variable containing a list) of voltage samples in the waveform, one per analog_output_data_interval
time step.
As we discussed offline, the samples list could be included explicitly in the experiment file or be generated dynamically via a Python action.
-
Add two parameters to NIDAQ Device:
-
analog_output_running
: boolean value (or variable containing such) that controls whether analog output is running. The value can be changed dynamically, so that analog output can be started and stopped as needed throughout your experiment. To preserve existing behavior, defaults to YES
.
-
analog_output_waveform_repeats
: boolean value (or variable containing such) that controls whether analog output waveforms run once and then stop or repeat indefinitely. To preserve existing behavior, defaults to YES
.
Note that these parameters need to be per device (rather than per channel), because NI-DAQmx Base supports only one analog output “task” at a given time, and these parameters apply to all channels in the task.
The list of samples associated with a custom waveform can be changed at any time, but the changes won’t take effect until analog output is stopped and restarted. The reason for this is that changing the output samples for one channel requires re-sending the samples for all channels (again, due to the single-task limitation of NI’s API). Rather than implicitly restarting all waveform output channels when one gets new samples, MWorks will require you to explicitly stop output in order for any changes to take effect, so that it’s clear in your experiment that all waveform output channels are restarting.
I think that covers everything. Does it sound like this will meet your needs?
Thanks,
Chris
Hi Chris,
I think that covers everything we discussed. There is a particular
important scenario that this may also cover, but I’m not sure. The desired
behavior would be a pulse with a duration on the order of hundreds of
milliseconds, followed by a decay waveform to zero which lasts on the order
of tens of milliseconds. The durations would be pre-set, but in the event
of a subject response (say a saccade), the pulse would terminate with the
decay waveform as soon as possible. However, if the output is finished (or
if the decay has already started), the decay waveform should not be
re-delivered.
Can a new waveform be loaded into NIDAQ while the output is running? Even
if that’s possible, there would need to be a way to avoid restarting the
decay waveform if that’s when the response came, which would happen often
enough to be a worry. One way I can think of avoiding the issue is with a
separate MWorks timer that expires when the main pulse finishes and after
which the update would be withheld. Any other ideas would be greatly
appreciated!
Another question - when you say that the parameters are specific to the
device rather than the channel, I assume different channels can still have
different waveforms. Is that correct?
Thanks!
Hi Evan,
when you say that the parameters are specific to the device rather than the channel, I assume different channels can still have different waveforms. Is that correct?
Yes, that’s correct. The waveform for each channel is arbitrary, but all channels start/stop/repeat as a group. Also, because all channels share the same onboard sample buffer, each waveform must contain the same number of samples.
Can a new waveform be loaded into NIDAQ while the output is running?
Yes, that is supported by NI’s API, even when repetition is enabled. I believe the device begins outputting the new samples as soon as they’re received.
Given this, another way we could implement custom output waveforms is to make any changes to the “samples” parameter apply immediately, without requiring analog output to be stopped and restarted. Then, you could achieve the scenario you described by first outputting just the pulse and then replacing it with the decay at the appropriate time. To avoid having the pulse signal stop before the decay is loaded, you could pad the end of the pulse with some extra samples.
While it should work, one issue with this design is that it really only makes sense with a single analog output channel. As I said before, changing the output of one channel requires re-sending the samples for all channels, meaning all channels would restart every time one was updated. In general, I think this would be unexpected and unhelpful behavior, so I’d probably make MWorks enforce the requirement that a custom waveform channel be the only analog output channel.
Chris
Hi Evan,
Do you have any more thoughts on my proposed design? Should I go ahead and implement it?
Thanks,
Chris
Hi Chris,
I just emailed the lab looking for feedback a few days ago, I would give it
a couple more days before starting on the implementation. Do you think it
would be useful to get feedback from others as well?
Evan
Hi Chris,
You can go ahead and implement this; I haven’t received any feedback. It’s
not currently urgent.
Thanks,
Evan