11-19-2014 05:31 AM
Hi,
I want to generate a continuous analog waveform-output (e.g. sine) using NI Daqmx. The program-example in http://www.ni.com/example/29872/en/ works very fine and does completely what i want, but there are two problems:
1) I want to count the number of waveform-periods that are performed.
2) If i press the stop-button (or another event happens), the program should not interrupt the signal-generation anywhere. It should complete the last running period and than stop.
I tried to fix this by timing the loop so that i have exactly one period per loop. This works fine for small freqencies, but for higher frequencies (e.g. 100Hz - 1000Hz) not anymore 😞
A second method was using finit generation (always generating one period in a loop). But with this method there is another serious proplem: If i perform higher frequencies (e.g. 100Hz or higher) the loop needs too much time and the signal is not continous anymore because there is a short pause between each period.
I'm new in LabVIEW, could'nt find a solution so far and would be very glad if somebody could help me with that 🙂
Solved! Go to Solution.
11-19-2014 05:31 PM
The key step is to ensure that the Stop button is not wired to the Stop of your loop. In a "simple" control system, there is a single loop, and the Stop button (and everything else!) lives inside the loop. When you press Stop, if it is wired to the loop Stop, everything stops.
What you want is for the Stop button to signal a condition, namely "Stop at the end of the current cycle". If you are generating the data a point at a time, you should be able to tell (by examining the phase of the signal) when you are at end-of-cycle. One thing you could do would be to ask (for each iteration of the loop) "Am I at end-of-cycle, i.e. is the Phase 0?". If this is True and the Stop button is pressed, Stop.
BS
11-24-2014 05:44 AM
Dear Bob,
thank you very much for your answer and your very helpful advice. I solved the Problem now. I could't solve the Problem using the Standard-Daqmx-Timing-VI with continuous samples, as like in the example linked above, because there was no posibility to detect the time reaching the end of a cycle. So i wrote it by my own, using a timed loop and now i have the complete generation and every generated point under my control. So I am able to ask "am I at the end of cycle" as you recommended and the generation stops at the end of the current cycle after pressing the stop-button, even @ very high frequencies (e.g. 1000Hz), while generating a smooth coninous signal.
For those people, who have the same Problem:
Solving the Problem with a timed loop caused another serious problem: The Standard-Software-Timing in Labview reaches a maximum-resolution of 1kHz or 1us using a time-delay. If one generated cycle consists of 100 points and you want to reach e.g. a signal-frequency of 1000Hz, you need a timed loop with a frequency of 100000Hz. This is why i used an external timing-source.
My program, which fulfills my requirements described above, is attached below.
Best regards
Daniel
11-24-2014 09:27 AM
Daniel,
Thank you for marking my answer as the Solution, and congratulations on getting your own code to work.
In the spirit of being "even more helpful", I am attaching my "reworking" of your code, which shows some ideas you might not have considered. It also illustrates a few principles I always encourage my students to follow, including Always Make an Icon and Always Write a Description. I also added a "feature" to allow the program to generate "at least N cycles" by including a Number of Cycles control (set by default to 1, which makes it behave the same way as your program).
The main difference (aside from "Style") between our routines is that I generate my waveform "on the fly" inside the loop. Generating a point is extremely fast, so it has almost no impact on the ability of the loop to run. Note that I use the index "I" has a "phase counter" -- the output of the Integer Divide is both "relative phase" in the remainder and "completed cycles" in the Quotient. By dividing relative phase by number of points (I convert to Dbl to avoid the Dread Red Coercion Dots, my personal foible) and multiplying by 2 pi, I get the argument needed for the Sinusoid function, the output of which is my sinusoid. [Note that the first point is at Phase = 0, so the sinusoid starts at 0; if you want it to end at zero, as your example does, include an increment just before the Dbl conversion line].
I implemented the "At Least N Cycles" by adding a Greater than or equal to comparison to the Phase = 0 and Stop = True tests -- I used the Compound Arithmetic function to let me do all three Ands together.
I also added the Simple Error Handler at the end of the Error Line, "just in case" -- it is always a good idea to either have an Error Indicator or Error Handler to give you a clue when thing go awry (Third Rule of Programming -- It Never Works the First Time!).
Bob Schor
Extra Credit -- why is the Third Rule not the First Rule? (tongue firmly in cheek ...)
11-24-2014 09:29 AM
... and we are never quite so stupid as when we are being so smart! Guess who forgot to include the code ...
BS
11-27-2014 05:19 AM
Dear Bob,
thank you for your help, your program looks very well and has many advantages compared to mine. But unfortunately i've still a problem: At least i want to reach a signal-frequency of about 1kHz. At the oscilloscope i could see, that the maximum speed i can reach (regardless which program-version I use) is about 500Hz. I found out, that it seems to be the timed-loop itself (without any other blocks inside of it exept a counter) which needs too much time and can't run faster than about 50000Hz without producing errors. Is there a possibility to make the loop more efficient (probably using another structure)?
If not it would be enough for me to detect the 0-phases of the signal instead of controling every single generated point of it. It would reduce the problem by a factor 100 and the "slow loop" wouldn't have any impact anymore. So what i want to do is to write one complete cycle per loop consisting of 100 samples instead of writing one single point per loop. But so far I found no other possibility doing this, than using finit-generation with the standard-daqmx-blocks, which produces the pauses between each cycle I described above and I want to avoid. Every attempt to send an array of points to the daqmx-writing-block without using the daqmx-start- and daqmx-stop-block every cycle failed. Unfortunately it seems to be those blocks who need very much time and cause the pauses between each cycle...
11-28-2014 09:28 AM
You know, when you (re)state the problem that way, a much simpler way that I think will work popped into my head. I'm currently at home, enjoying watching the snow fall outside my window on the day after Thanksgiving (I am not indulging in Black Friday shopping), and will need to get access to my RT Hardware (maybe later today) to do some testing before I lead you down (another) wrong path, but I will respond shortly (unless someone else beats me to it).
BS
11-28-2014 10:21 PM
OK, here's something to try whenever you have a Sampling or Stimulus Generation chore -- open MAX and try to create a MAX task that can do what you need. If you can, save that Task in MAX and simply open the Task in your own VI.
For example, I've got a Multi-Function card on a PXI system that has an internal 100KHz internal time base. I created a Generate Signals Task for the Multi-function board. Choose Continuous Samples (means it needs a While Loop, Do Until I Tell You to Stop), set 100 Samples to write (the period of your sinuusoid), and leave the rate at 1KHz for now. Note that this is only a 10Hz sinusoid, but we're about to fix that. Be sure the range and Terminal Configuration are what you want.
Now click the Advanced Timing tab. Choose External Clock source, and the 100KHz clock. Now go back to the configuration tab and put, say, 30000, in the rate (it will become 30K). Also note the timing on the sample sinusoid.
When you created the Task, MAX gave it a real dumb name, like MyOutputTask. Name it something sensible to you (I chose "Sinusoid"). Save the task.
We now have a Task that expects 100 points and will drive the D/A converter at 30KHz, outputting those 100 points until we tell it to stop. Something like this:
The Orange input labelled "Sinusoid" is an array of Dbl, the sinusoidal waveform you want to output. The box wired to the input of the Start Task is simply a Task Constant (hover around the upper left corner until the Wiring Tool appears, right click, choose Create Constant, and you'll get an I/O task). If you now click the downward triangle, you should see the Tasks that MAX has created -- in my case, Sinusoid. Note this has all of the settings you put in MAX, including voltage range, sampling rate, etc. So all you need to do is build a While Loop and tell it to output 1 channel, N Samples, and it will do cycle-after-cycle until you say Stop. Bring the Error line out and close the Task (I left this step out).
Now, I'm home, and I've built this "remotely" at work, so I haven't tested it. I think, however, that it should work. Give it a try.
The Lesson To Learn is that DAQmx isn't too difficult if you first "Do It in MAX", make a Task, and then tell DAQmx "Do what I just did in MAX". The nice thing is that with MAX, you can actually run and test your tasks and see if they work, then save them for VIs.
Bob Schor
12-01-2014 04:36 AM
Hallo Bob,
thank you for your work and your detailed and very comprehensive description. I tried this out using the MAX-Tool and configured it as you described. It worked, but the controlling-problem stays :-(. The clue is, that the continuous sampling of the "Daqmx-Write"-Block doesn't perform one cycle per Loop and there is no way to synchronize the signal-generation with the Loop. The signal becomes generated as long as the loop runs and stops (anytime) after i press the stop-button anywhere, but not at the end of one cycle. If i choose finite-generation in the MAX-tool, I need to perform the start- and stopt-buttons in the loop again, what causes interruptions between each cycle. So unfortunately the problem remains the same as at the beginning :(.
Sorry for my bad english (I'm german) and my late answers, but i've restricted access to the hardware and so i can't work on it everyday.
Daniel
12-01-2014 04:36 AM
Hallo Bob,
thank you for your work and your detailed and very comprehensive description. I tried this out using the MAX-Tool and configured it as you described. It worked, but the controlling-problem stays :-(. The clue is, that the continuous sampling of the "Daqmx-Write"-Block doesn't perform one cycle per Loop and there is no way to synchronize the signal-generation with the Loop. The signal becomes generated as long as the loop runs and stops (anytime) after i press the stop-button anywhere, but not at the end of one cycle. If i choose finite-generation in the MAX-tool, I need to perform the start- and stopt-buttons in the loop again, what causes interruptions between each cycle. So unfortunately the problem remains the same as at the beginning :(.
Sorry for my bad english (I'm german) and my late answers, but i've restricted access to the hardware and so i can't work on it everyday.
Daniel