Using FunctionGenerator to simulate a TTL pulse for NI-USB6001

397 views
Skip to first unread message

Sarah P

unread,
May 15, 2020, 5:37:52 PM5/15/20
to Bonsai Users
Hi Goncalo,
I am starting a new post with my questions about FunctionGenerator.
All my questions are asked in order to simulate and eventually implement a system that is described here.
And for this particular post on FunctionGenerator, I will be referring to the attached code as an example code for how I would have optogenetic control on my system.

In the attached code, I am generating a continous 5V (0-5V) square pulse using the FunctionGenerator in order to send a 5V TTL to NIDAQ's AnalogOutput with a KeyDown trigger. Once I press F1 (in my case) to trigger KeyDown, the TTL from AnalogOutput is sending the signal to AnalogInput. My NI-USB6001 is wired so that the AI and AO channels are hard wired together, and there is a LED attached to a AO channel. The code works and I am able to trigger the LED. However, I have a few question.

The AnalogInput baseline voltage hovers at 5V when I start the Bonsai code. How do I keep the baseline at 0V at all times, except when it receives the TTL from the AnalogOutput?

When I stop the Bonsai code, sometimes the LED stays lit and sometimes the LED is off. Is there a way to make the LED turn off every time Bonsai is turned off?

When I set BufferLength = 200 in FunctionGenerator, in which hardware is the data being stored temporarily? Is FunctionGenerator using my computer memory as hardware?

Thank you!
Sarah
NI6001TriggersLED.bonsai

Gonçalo Lopes

unread,
May 16, 2020, 10:20:43 AM5/16/20
to Sarah P, Bonsai Users
Hi Sarah,

Given you are using ContinuousSamples, the signal will follow the TTL until you eventually stop the workflow. At the point the task is terminated and the connection to the DAQ is severed, the terminal will be left at whatever value the signal happened to be in when you stopped it (either HIGH or LOW). To control this, you will have to specify in Bonsai another event (e.g. another key press) to manually terminate your signal generation and send the zero value to the port. You can use TakeUntilConcat node after your SkipUntil for this, and couple it with either a FunctionGenerator set at zero amplitude, or a ScalarBuffer as source, so that when you press it the signal will be set to zero before you stop the workflow.

In general it is good practice to design functionality in the workflow to settle the whole system before actually stopping the recording.
Hope this helps.

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bonsai-users/8760245e-a106-4bff-9a03-74675b2547e8%40googlegroups.com.

Sarah P

unread,
May 18, 2020, 5:01:09 PM5/18/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
Your suggestion works great! Thank you!

The next question I have about this code is whether there is a way to send a specified number of square pulses from the 1st FunctionGenerator to the AnalogOutput node?

Thank you!
Best regards,
Sarah
NI6001TriggersLED.bonsai

Gonçalo Lopes

unread,
May 18, 2020, 6:00:16 PM5/18/20
to Sarah P, Bonsai Users
Would the Take operator work for this?

Sarah P

unread,
May 19, 2020, 11:08:56 AM5/19/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
I tried Take and I think I understand parts of what the code is doing but also have questions.
When I set Take to 1, the LED does not turn on. I think the code is reading the negative half of first pulse generated by the FunctionGenerator. When I set Take to 2, the LED blinks once. So that when Take = 2, 4, 6, 8, 10, the LED blinks 1X, 2X, 3X, 4X, 5X, respectively. This is where my understanding ends. :)

This made me think that Take is taking the 1st BufferLength of pulses from the FunctionGenerator. But when I change the FunctionGenerator properties (i.e., BufferLength, Frequency, and SampleRate, this is no longer the case. What exactly is Take(1) taking as the 1st specified number of contiguous elements from the FunctionGenerator? Does the start of the sequence taken by Take(1) start with SkipUntil?

I noticed that the duration of the LED pulses varies with sequential blinks. With the attached code's FunctionGenerator properties, generally, the 1st LED blink has the longest duration and the last LED blink has the shortest duration. This makes me wonder about the duration of LED blinks in the middle. The variable duration also changes when the FunctionGenerator properties (i.e., BufferLength, Frequency, and SampleRate) are changed. How can I keep the duration consistent between LED blinks?

Also, is the SampleRate property of FunctionGenerator in units of samples/sec?
Is the Frequency unit Hz?
It BufferLength in samples or samples/s?

Thank you!
Sarah

NI6001TriggersLEDCtrlNumPulses.bonsai

Gonçalo Lopes

unread,
Jun 10, 2020, 2:46:38 AM6/10/20
to Sarah P, Bonsai Users
Hi Sarah,

I'm not sure how you intend to use this in the broader system, but if I understand correctly your description, it might be easier to just use FiniteSamples rather than ContinuousSamples in DAQmx AnalogOutput. That way the samples you upload to the board will be played through to the end and no further (with continuous samples the current buffer is repeated until the task is terminated).

In that case you would simply specify the total number of samples and pulses in FunctionGenerator and simply upload everything in one go to the board.

Let me know if you have made further progress on this as I've realized it's been a while.
Hope this helps.

Gonçalo Lopes

unread,
Jun 10, 2020, 2:47:57 AM6/10/20
to Sarah P, Bonsai Users
Regarding the remaining questions, all frequency units are in Hz and BufferLength is in samples.

Sarah P

unread,
Jun 29, 2020, 12:44:29 PM6/29/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
Thank you for replying. I haven't made progress on Bonsai this month because I've been supporting my PI's grant writing. But I'm back on it!
I'm working on this code so that I can incorporate it later into my main code (system explained here). I would like to use this code to trigger the on/off time and duration of LED light for optogenetics, or scent release.

I tried what you suggested. But I'm getting an error message. Where is the code not working?
image.png

I set FunctionGenerator to:
BufferLength = 1000 samples (I also tried 100 samples)
Frequency = 15 Hz
SampleRate = 1000 Hz
Waveform = square

I set AnalogOutput to:
BufferSize = 1000 samples
SampleMode = FiniteSamples
SampleRate = 1000 Hz

Thank you!
Sarah

NI6001TriggersLEDCtrlNumPulses.bonsai

Gonçalo Lopes

unread,
Jun 29, 2020, 8:33:53 PM6/29/20
to Sarah P, Bonsai Users
Hi Sarah,

I think in this case you may want to set the SampleMode property in AnalogOutput to ContinuousSamples rather than FiniteSamples so that the generator is continuously producing data. Otherwise the NI board is going to complain once you send more data than you said you would in the buffer size.

Hope this helps.

Sarah P

unread,
Jun 30, 2020, 10:04:22 AM6/30/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
I think I'm confused. My original question was "is a way to send a specified number of square pulses from the 1st FunctionGenerator to the AnalogOutput node?" Your first suggestion was to use Take, but I had some questions about that. Then you suggested setting SampleMode in AnalogOutput to FiniteSamples. And then, you are now suggesting that I set SampleMode in AnalogOutput to ContinuousSamples. It seems we've come full circle. :)

Perhaps I should ask the question differently.
What must I do to control the number of pulses sent from the FunctionGenerator to AnalogOutput?
And, what must I do to control the duration in which pulses will be sent from the FunctionGenerator to AnalogOutput? (There will be a variable number of pulses depending on the duration.)

Thank you!
Sarah

NI6001TriggersLEDCtrlNumPulses.bonsai

Gonçalo Lopes

unread,
Jul 8, 2020, 3:55:51 PM7/8/20
to Sarah P, Bonsai Users
Hi Sarah,

Yes, the virtues of asynchronous communication ;-)

If you want to send a finite pulse train, you should indeed use FiniteSamples and make sure the waveform is designed accordingly. In case you want to control the exact number of pulses, probably the easiest way is to design the waveform like so:

image.png
In FunctionGenerator you need to make sure that BufferLength, Frequency and SampleRate are lined up to represent your individual pulse shape. Range will then control how many pulses to generate, and you simply collect all of them and paste them together in the final waveform with ToArray > Concat.

For example, if you set SampleRate to 1000, then BufferLength would be the pulse duration in milliseconds, and Frequency would always be SampleRate / BufferLength, e.g.:
SampleRate: 1000
BufferLength: 100
Frequency: 10

Would specify a single 100ms square pulse.

I guess you could automate this so you specify only PulseDuration (ms) and Count. I'm attaching a small example of this.

Hope this helps.
PulseTrain.bonsai
PulseTrain.bonsai.layout

Sarah P

unread,
Jul 13, 2020, 4:55:20 PM7/13/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
This is great! This really helps a lot! Thank you!
May I ask a few questions?
- Could you explain the Expression Transform? What does Expression "1000.0/it" mean? Is 1000.0 the SampleRate from FunctionGenerator? If it is, and if I change the SampleRate of FunctionGenerator, then will I have to change the Expression in Expression Transform? For example, if I SampleRate of FunctionGenerator is 2000 Hz, then would I change the Expression in Expression Transform to "2000.0/it"?

I used your code (PulseTrain.bonsai) with NIDAQ nodes as shown in PulseTrain_SAP.bonsai. To send the correct number of pulses from AnalogOutput to AnalogInput, I had to set the BufferSize of AnalogOutput and AnalogInput to the product of PulseTrain's Count and PulseDuration, so Count X PulseDuration (5 x 100 = 500, in this example code). Is there a way to automatically synchronize the  BufferSize of AnalogOutput and AnalogInput to the product of PulseTrain's Count and PulseDuration? I tried playing around with Externalize Property and Create Property Source, but had trouble getting it to work.

Thank you!
Sarah
PulseTrain.bonsai
PulseTrain.bonsai.layout
PulseTrain_SAP.bonsai

Gonçalo Lopes

unread,
Jul 18, 2020, 7:54:48 PM7/18/20
to Sarah P, Bonsai Users
Hi Sarah,

The ExpressionTransform node is used to perform simple numerical calculations. It's been covered elsewhere, but the keyword it represents the input value. As you realized, there is a dependency on SampleRate. To resolve this dependency, you have to restructure the PulseTrain node differently.

I am attaching an example PulseTrain node where the SampleRate is externalized as a property, and all calculations assume milliseconds as a common unit. The properties mean:
 - Count: the number of pulses in the train
 - PulseDuration: the duration of each pulse (on + off cycle) in milliseconds
 - SampleRate: the sample rate of the generator, in Hz

From these you have to calculate BufferLength and Frequency for the FunctionGenerator (SampleRate is the same).

BufferLength is expressed in samples, so we have to calculate it from PulseDuration * Count  = TotalMilliseconds and then BufferLength = TotalMilliseconds * SampleRate (Hz) / 1000.0 ms, the total number of samples in our signal.

Frequency will simply be 1000 / PulseDuration, in Hz.

This should also solve the issue with AnalogOutput, which is expecting the buffer to contain the entire waveform and should wait until the signal is fully played out.

Hope this helps.

PulseTrain-ms.bonsai

Sarah P

unread,
Jul 20, 2020, 3:03:33 PM7/20/20
to Gonçalo Lopes, Bonsai Users
Hi Goncalo,
This is incredibly helpful!
Thank you!
Sarah

Sarah P

unread,
Jul 20, 2020, 5:08:13 PM7/20/20
to Bonsai Users
So, one more question about the attached code.
I'd like to PublishSubject BufferLength and SampleRate from the PulseTrain workflow to AnalogOutput and AnalogInput, so that I only have to input value once into PulseTrain to change the BufferLength and SampleRate for the FunctionGenerator, AnalogOutput, and AnalogInput. I'd like the changed BufferLength and SampleRate values from PulseTrain to take effect immediately. With the current code, though, the change takes effect the second time I run the code after I've inputted different BufferLength and SampleRate values into PulseTrain. How can I change the code so that the BufferLength and SampleRate values from PulseTrain take effect immediately in AnalogOutput and AnalogInput?

Thank you!
Sarah
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Bonsai Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users+unsubscribe@googlegroups.com.
PulseTrain_SAPv2build.bonsai

Sarah P

unread,
Jul 21, 2020, 5:13:36 PM7/21/20
to Bonsai Users
Hi Goncalo,
I am re-visiting this post because I have encountered a problem with the code (..._FuncGen.bonsai). I am using a second FunctionGenerator to zero the amplitude of the first FunctionGenerator. The problem I'm encountering is that the AnalogInput is zero-ing with a significant delay, compared to when AnalogOutput zeros, so that there are more pulses being sent into AnalogInput than expected. If I remove the second FunctionGenerator, the number of pulses recorded by AnalogOutput and AnalogInput are the same.

I tried using ScalarBuffer as source by replacing the second FunctionGenerator with ScalarBuffer, which was your other suggestion (code: ..._ScalarBuffer.bonsai). However, I'm getting an error message: "Positive number required. Parameter name: bytesAllocated." I tried to follow what your previous posts about ScalarBuffer on google groups (here and here) but I'm not sure what I'm missing.

Questions:
1) How do I resolve this error message in regards to using ScalarBuffer as source?

2) If I use ScalarBuffer as source, will it resolve the delay issue between AnalogInput and AnalogOutput?

3) If ScalarBuffer does not resolve the delay issue, then could you please help and suggest another way I can zero AnalogOutput?

Thank you!
Sarah
To unsubscribe from this group and stop receiving emails from it, send an email to bonsai...@googlegroups.com.
ConcatLatestFrameCounter_build_temp_FuncGen.bonsai
ConcatLatestFrameCounter_build_temp_ScalarBuffer.bonsai

Gonçalo Lopes

unread,
Aug 1, 2020, 6:35:57 AM8/1/20
to Sarah P, Bonsai Users
Hi Sarah,

1) I think you're just missing a 1 in the ScalarBuffer. If you set the Size to have 0 height, then the entire buffer will have 0 samples (100 x 0).

2) and 3) I'm not sure I understand the problem, but again if you use ContinuousSamples the buffer in hardware will loop continuously, until you tell it to stop. This can make it hard to have the exact output you want, as you have to time precisely when you want the output task to stop. This is why it would be easier to simply generate the entire waveform at once and send it out using FiniteSamples.

Hope this helps.


To unsubscribe from this group and stop receiving emails from it, send an email to bonsai-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bonsai-users/1b942e11-0898-4511-8eb0-5832236d838eo%40googlegroups.com.

Sarah P

unread,
Aug 11, 2020, 2:21:07 PM8/11/20
to Gonçalo Lopes, Bonsai Users
Thank you! I am able to get ScalarBuffer to work!

Sarah
Reply all
Reply to author
Forward
0 new messages