LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Finite data storage, retrieval and display within a while loop

There are a couple of problems with your loop 4.

 

  1. The trigger condition will only trigger if all elements in the waveform are over the threshold.  This is probably not what you want.  I would recommend either writing your own routine to analyze the data or using the analog edge trigger VI for the purpose.
  2. You need a state machine to handle disabling your max calculation.  The "state" can be as simple as a timestamp in a shift register.  Check the timestamp in the shift register to see if it is over two seconds in the past.  If it is, do the calculation.  If not, skip it.  When your trigger condition hits, update the timestamp to the current time.

You only need one queue for each loop, not one for each variable.  But to pass variables and other data, you will need to change your loops from simple consumers to state machines.  Let's take loop 4 as an example.  Loop 4 has one input (feedback gain), and you may want another (trigger level).  To change to a state machine architecture, you will need to do several things:

 

  1. Change the queue data type to be a cluster of a typedef enum (the command) and a variant (the data).  The enum will have values corresponding to each command for the loop.  These commands for this loop are ChangeFeedbackGain, ChangeTriggerLevel, ProcessData, and Exit.
  2. Add a case statement right after the dequeue which is switched by the enum.  The different commands will be handled in different cases.
  3. You already have a state shift register in this loop; it contains your level.  Expand this to be a cluster containing the level, the blank time mentioned above, your feedback gain, and your trigger level.
  4. Add cases for all the commands.  The ProcessData command is what your loop currently does (and when you add the case statement, just enclose it).  The other commands either update the state data cluster or exit the loop.
  5. Move the inputs to the UI event structure.  For example, when the UI detects a Feedback Gain change, it fires a ChangeFeedbackGain command to loop 4.

Doing this for all your loops and moving all your UI inputs into the event structure allows for several optimizations.  For example, if changing a variable results in multiple actions across several loops, you can now do this by dispatching several commands.  With your current structure, you would need to use local variables and polling to determine if things had changed.  This is really nice for instrument control.  For example, if the vertical gain on a scope changes, you can send a change vertical gain command to the scope acquisition loop.  Depending upon whether or not the instrument is currently acquiring data, you could either simply update the vertical range in the state cluster (not running) or stop the acquisition, change the range, update the state cluster, and restart the acquisition (running).  You also then only need one queue per loop, not one queue for variable.

 

You can search these forums for examples of queue driven state machines.  There are lots.  Finally, no discussion of this type of architecture would be complete without mentioning LabVIEW class based architectures.  I will simply say that implementing this type of architecture with LabVIEW classes gives you a lot of benefits, but gives you a much different mind set for design.  It results in a more flexible architecture that is easier to maintain, but the learning curve can be steep.  If you are interested in learning more about this, let us know and we can point you in the right direction.

0 Kudos
Message 31 of 44
(1,108 Views)

Hi DFGray,

 

There is a lot of infromation here for me to swallow.... I am really interested in working out the QSM... But my skills are not quite their yet... I have changed tracks slightly and used a simple state machine for the "max hold" function in loop 4; it works great... But, I don't the the architecture is not quite correct as all code in the loop should be in the state machine... Is that right?

 

Also, I still don't understand how the QSM works in terms of architecture and wiring... I found the attached... Is this getting close?

 

Regards,

Jack

Download All
0 Kudos
Message 32 of 44
(1,091 Views)

You are getting ... close-ish.

One of the strengths of a QSM is the fact that it only works when needed (when there's an item in the queue), but do it as fast as it can (no loop time).

By placing your 3 machines in the same loop you've limited your programs speed to the slowest machine. Not only that, but all 3 must get 1 queue item before the next loop!

The solution to that is simple, each QSM should have a single loop so they can work at their own pace.

Another beauty of the QSM is that it lends itself very well to producer/consumer, you can have 1 or more loops that generate commands and place them in queues, whereby the QSM will act.

If you only want to go through some measurement/calculation steps a simple/pure state machine is probably a better choice. The same idea as your attempt, but no queue, just an Enum (preferrably, although inteteger or string can also be used) sent to a case structure and send the next case as output of the structure.

If you dont have any branches/choices to make in a state machine, it's basically a series of sub-vi's bundled in a case structure.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 33 of 44
(1,086 Views)

Hi Yameda,

 

Thanks for the reply... I understanding the value that can be added using a QSM; but I can't follow how they are wired (i.e. enum, event structure with commands etc)... I have spent ages searching on online for an example that clearly explains how the enums and event structures are wired to the queues and how the queues are sent between loops to no avail.

 

Any chance you can post a very simple example of a QSM for me with a short description of the wiring (... a picture says a thousand words)?... I wouldn't normally ask, but I am really stuck and just can't put the pieces of the puzzule together as yet (not through a lack of trying!).... This seems to be best resource I have found, but the actual wiring info is unclear to me..http://expressionflow.com/2007/10/01/labview-queued-state-machine-architecture/

 

Regards,

Jack

 

0 Kudos
Message 34 of 44
(1,080 Views)

Yes!... Very interested in this.... But the curve is steep... I have been reading up the QSM and would like to make changes to my vi... But I just don't get how to wire the enums, queues, and event structures... e.g. What does the enum in the "element type" of the queue do? How does is work?...How do I have one queue and have all loops access that data without having some data removed from the queue due to ealier dequeue operations? Will one queue from an event structure carry all UI events (or is one queue needed per event)?

 

Lots of questions I know, but the basic principles of building a QSM are unclear and I cannot find a good resource online that explains this.

 

Regards,

Jack

0 Kudos
Message 35 of 44
(1,079 Views)

Take a look at this, i think it'll solve most of your questions.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 36 of 44
(1,077 Views)

Thanks, Yamaeda...

 

I had a play for your vi and added some simple numeric calculations to the various cases in the second loop ad used your boolean and numeric control to turn on the calculations and switrch calculations (i.e, /, +, x, +, etc )... I think I am now starting to get my head around this...

 

Questions:

 

1. What does the "EnumCommands" state do? Why is it default? Is this like an "idle" for when are no commands (i.e. waiting until a value change from boolean or numeric occurs)?

 

2. Let's say I have a top loop with my UI controls (i.e. booleans and numeric controls) that generate the commands for data acquisition (e.g. set sample rate and read rate), data display (e.g. change x-axis range) , real-time processing (calculate RMS or peak amplitude between graph cursors), start subvis, write data to file, etc... And lets say I have multiple while loops; one for DAQ, one for display, one for start subvis, one for write to file... How do I send the queued data from my top UI loop 1 to the all different consumer loops (loops 2 and 3) without lossing data in loop 3 due to the dequeue in loop 2? Hope this makes sense..?

 

I made some changes to your QSM[1].vi that describes my problem and how I think (?) this might be solved.. I am sure I will be wrong... But is gets my problem across....See attached..

 

Many thanks,

Jack

 

 

 

 

0 Kudos
Message 37 of 44
(1,066 Views)

You can use Preview Queue to see if the queued item is to be consumed in that particular loop. That way you can wait with the dequeue until you're consuming it.

The EnumCommands was mostly a pedagogical name, i then decided to put in a couple of commands to give you some examples. Since all event data is turned into a variant you can send arrays and clusters as inputs also, if you need to.

 

If you have that many loops you might want to look at several queues/user events to send the commands. The queue is mainly for queueing up alot of operations to process, if you have many different loops i'd probably go for several user events.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 38 of 44
(1,061 Views)

Hi everyone,

 

I has been a while since I posted an update on the my progress regaring the TMS application that I been developing, which you have all been so helpful assisting me with... I am happy to say that thanks to your advice and feedback, the application is now functional and works exceptionally well for my specific needs (ignore the frontal panel as I still need to "pretty" it up) .... Much better than any commerical software package than most other research use to run such instruments... So a HUGE thanks you to all...!!

 

Now that I can come this far, could I trouble you one more time.... To put the icing on the cake, so to speak, I would like to add a series of radio buttons (IDLE, DAQ, SELF-CAL, STOP) that can be used as the main application controls that will let the user select a desired state... I see the radio buttons are basically enums and can be used to control a case structure.... I get something working on a small scale application, but I cannot addthis functionally to my TMS.vi...

 

I assume I need another while loop around that contained a case stucture controlled by the radio buttons, with the TMS.vi code in the "DAQ" case, a stop button on the "STOP" case, the PCIe card self-cal code in the "SELF-CAL" case, and the idle case left empty... Despite trying for hours, I cannot get this to work..

 

Would any of you have any suggestions?

 

Regards,

Jack

0 Kudos
Message 39 of 44
(1,033 Views)

To put the icing on the cake, so to speak, I would like to add a series of radio buttons (IDLE, DAQ, SELF-CAL, STOP) that can be used as the main application controls that will let the user select a desired state...

You need that state machine we have been pushing you towards.  You may need one per loop.  There are many ways to handle this.  I used to prefer the queue driven task handler.  You can find an example of this here.  However, that is old school LabVIEW.  I would recommend you look into LabVIEW classes and the command pattern for new designs.  It would not be very difficult to convert your current code into classes and implement the command pattern.  Essentially, each loop would become a base class (e.g. DAQLoop), with a set of commands, and each state would become a child class (e.g. Run command of DAQLoop classes would gather data for DAQ or SELF-CAL classes (states), but would do nothing during IDLE class).  This will warp your thinking in very different ways, but you will be glad you did it.

Let us know if you need more information.

0 Kudos
Message 40 of 44
(1,022 Views)