LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Build XY Graph Output to FFT?

Solved!
Go to solution

So, build waveform's Y-input expects an array. I make an array with "Build Array" and switch it to concatenate inputs such that the scalar stream of n values is turned into a 1D array of length n. When I connect the scalar wire to the input of Build Array, it switches back to it's normal mode and therefore outputs a 1D array of length 1!!! Why is that happening?

 

jla3141_0-1626555809909.png====>  jla3141_1-1626555847131.png

 

 

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 11 of 22
(3,134 Views)
Solution
Accepted by topic author jla3141

@jla3141 wrote:

When I connect the scalar wire to the input of Build Array, it switches back to it's normal mode and therefore outputs a 1D array of length 1!!! Why is that happening?

 


I assume you haven't done any simple tutorials and lessons about dataflow. If you want to build an array from a series of scalars, one option would be to autoindex at the right loop boundary. Another option would be to initialize a shift register with an empty 1D array and use built array to append a new element with each iteration. Just wiring a scalar to a "built array" of height=1 does nothing useful. It would just increase the number of dimension by one (or do nothing in concatenate mode). You cannot concatenate a scalar into a scalar. Makes no sense.

 

Only once you have accumulated to correct number of samples, an FFT would make sense.

Message 12 of 22
(3,129 Views)

@altenbach wrote:

I assume you haven't done any simple tutorials and lessons about dataflow. If you want to build an array from a series of scalars, one option would be to autoindex at the right loop boundary. Another option would be to initialize a shift register with an empty 1D array and use built array to append a new element with each iteration. Just wiring a scalar to a "built array" of height=1 does nothing useful. It would just increase the number of dimension by one (or do nothing in concatenate mode). You cannot concatenate a scalar into a scalar. Makes no sense.

 

Only once you have accumulated to correct number of samples, an FFT would make sense.


I haven't done any tutorials. I'm not autoindexing at the loop boundary. As you can see, it correctly generates the 'dynamically' plotted signal:

jla3141_0-1626564506713.png

 

But the FFT function is not working for me at all.

 

jla3141_1-1626564534510.png

jla3141_0-1626564680330.png

 

I'm attaching VIs but I feel like they're kind of useless, because it isn't possible for you to realistically generate the data I'm using. It's coming from a laser source and photodiode.

 

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 13 of 22
(3,119 Views)

Once the waveform graph contains data, you can stop the VI and right-click the graph...data operations...make current value default. When you now save the VI and attach it, we will also have your data.

 

We have all started learning LabVIEW once and I understand that your first goal should be to get it working. The problem is that with all your express VIs and dynamic data, you sort of painting yourself into a corner. Well written code that does the same is probably 3x smaller, 10x more efficient, and 100x easier to maintain and debug.

 

All you probably need is a simple state machine that easily fits on one screen.

 

How fast is the data coming in, i.e. how long does it take for the FOR loop to complete and produce that array?

0 Kudos
Message 14 of 22
(3,107 Views)

The for loop has to run once for each position along an optical delay stage (all the DLS stuff in the program). Typically, 200-400 times. I'm not sure improvements in performance are that noticeable, because the program has to "poll" the stage controller's API to make sure it's reached its desired position before progressing. It's not the fastest moving thing in the world.

jla3141_0-1626572980725.png

Using this, the loop time is ~530ms. So, approx. 1.5-2.5 minutes.

 

VI attached with values saved.

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 15 of 22
(3,103 Views)

Now I'm really confused!  If you have a time-varying signal that you want to analyze, a common analysis procedure is to decompose it into a series of sinusoids of a base frequency (typically chosen with a period equal to the length of the signal sample, a few minutes in your case) and (integer) higher harmonics of this base frequency, plotting the gain and phase of the harmonics that best fit your signal.  This process is called "Fourier Analysis".

 

If you happen to have all of your Time Samples equally spaced, so you have a sample characterized by an array of points (representing the data) and a single "sampling interval" ("dt"), there are some mathematical identities that let you speed up the process of finding the gain and phase of the multiple-frequency sinusoids that best "fit" (in the traditional "Least-Squares" measure) your data points.  This faster method is called the Fast Fourier Transform (or the FFT).  Jim Cooley would prefer you call it the Cooley-Tukey Transform, especially if the number of sampled points is a power of 2 (when it becomes optimally "fast").

 

Looking at your data file, I'm not sure what the columns represent, but it doesn't look to me like you have anything "sampled" properly at equal intervals.  It is also not clear to me what your independent variable is -- is it "time" (of sample), or is it "position" (of your measuring instrument)?  Is there a way to make (or "force") the independent variable to be equally spaced?

 

LabVIEW is an unusual Programming Language in many ways, not the least of which is that time is part of the Language.  There is a LabVIEW data type called a Waveform which is expressly created for sampled data -- it incorporates sampled data ("Y"), the (constant) interval between samples ("dt") and the actual time that the first Sample was acquired ("t0").  Many routines (including FFTs) will accept a Waveform as input, and will "do the right thing" with such equally-sampled data.

 

Bob Schor

Message 16 of 22
(3,085 Views)

@Bob_Schor wrote:

Looking at your data file, I'm not sure what the columns represent, but it doesn't look to me like you have anything "sampled" properly at equal intervals.  It is also not clear to me what your independent variable is -- is it "time" (of sample), or is it "position" (of your measuring instrument)?  Is there a way to make (or "force") the independent variable to be equally spaced?

 

LabVIEW is an unusual Programming Language in many ways, not the least of which is that time is part of the Language.  There is a LabVIEW data type called a Waveform which is expressly created for sampled data -- it incorporates sampled data ("Y"), the (constant) interval between samples ("dt") and the actual time that the first Sample was acquired ("t0").  Many routines (including FFTs) will accept a Waveform as input, and will "do the right thing" with such equally-sampled data.


Hi Bob, thanks for your reply. I'm sorry to be confusing. Ultimately, the delay or "X" values in that data file represent movements of a delay stage in a laser setup. The movements are roughly fractions of a micron. The delay stage has a retroreflector on it and so an optical path length is introduced into the system:

 

(2*distance)/speed_of_light = time delay

 

The factor of 2 comes from the fact that the light must travel 'down' and then 'back' the delay stage. The time delay introduced should be quite repeatable (stage has a 150 nm repeatability). The independent variable is position, but this is explicably linked to time by the speed of light. The spacing of values is determined by: (final_position - initial_position)/(number_of_points). So, for a typical mesaurement: (50mm-48mm)/400 = 5E-6 m <===> 3.3E-14 s or 33 femtoseconds. This is how many processes that occur faster than ns are understood experimentally. See here for more details. You're correct in saying that the X values are not perfectly periodic in space/time. Very few things are---that just ends up being a source of noise, though. It's fine to take the average of X and use that as dx <==(2*X/c)==> dt.

 

I hope that makes sense. The below code should programmatically describe the above.

 

jla3141_1-1626579158830.png

 

The dependent variable is voltage from a balanced photodiode, captured by an oscilloscope.

 

All agreed on the FFT front. I usually do it as a post-processing step outside of LabVIEW in Python or Matlab (as shown above). LabVIEW is capable of doing it though, so why not use it? If only I could figure it out ... 🙂

 

 

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 17 of 22
(3,082 Views)

OK, the FFT now works, but only when it's probed?! If I don't probe and just let the vi run to completion, the graph is blank. If I probe these positions:

jla3141_0-1626593505631.png

when the VI comes to completion it then displays the FFT correctly:

jla3141_1-1626593629913.png

What difference does probing make?!

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 18 of 22
(3,058 Views)

In answer to the question "What difference does probing make?", one that comes to mind is "it slows things down and "messes" with the intrinsic LabVIEW variable called "Time".

 

Since I really dislike little snapshots of pieces of a Block Diagram, I went looking to see if you posted a VI, and am very pleased to see that you did!  So I opened it, and am now not so pleased!

 

For your own sanity (and ours), please learn a little more LabVIEW, and some better coding habits. 

Things to avoid:

  • Frame Sequence Structure.  Strive for none.  They are almost never needed.
  • Everything in one VI, with wires running all over the place.  (Learn about sub-VIs).

Things to embrace:

  • The Error Line.  Most LabVIEW functions use the Error Line, and you should, too.  A single Error Line running horizontally with functions and sub-VIs "sitting" on it shows the flow of data much better and cleaner than does the Frame Sequence.
  • User-created sub-VIs.  Allows you to organize your code into "functional blocks", and has the added advantage of saving (a lot of) Block Diagram Space.
  • If you do create sub-VIs, create a simple Icon for them so they'll be "recognizable" on the Block Diagram.

A useful thing to do when you want to learn about some LabVIEW function (like the FFT) is to write a tiny little program using building blocks provided by LabVIEW.  There is a Signal Processing sub-Palette on the Block Diagram that has functions for Waveform Generation and Waveform Measurement.  The Snippet below shows a routine with the "Tones and Noise" function, generating a 10 Hz sinusoid of amplitude 1, a 35 Hz sinusoid of amplitude 0.6 and phase of 90°, and a little bit (0.1) of noise.  This feeds into an FFT Magnitude and Phase function that outputs Gain and Phase.  Notice that "Signal", "Gain", and "Phase" are all Clusters -- Signal is, in fact, a Waveform, while Gain and Phase are closely related "frequency analogs" of Waveforms (I don't know if NI has a name for this).

Simple FFT Example.png

I notice that you are running LabVIEW 2018, so I saved the VI for this Version, and have attached it.  Notice the Error Line running through this code, and notice its "standard position" (lower left and right Connectors) on the sub-VIs -- the VIs that you develop should adhere to this pattern.

 

Here's the resulting Front Panel (with the Noise parameter at 0.1 instead of 0 -- you can see the noise on the Gain plot as little bumps at higher frequencies).  Yes, I should have changed the labels on the Graphs so the X axis on the FFTs say "Frequency" and the Y Axes say "Gain" or "Phase" ...

Simple FFT Front Panel.png

 

Bob Schor 

Message 19 of 22
(3,001 Views)

@Bob_Schor wrote:

In answer to the question "What difference does probing make?", one that comes to mind is "it slows things down and "messes" with the intrinsic LabVIEW variable called "Time".


Interesting. Actually, it now works whether probed or not, but requires the program to be run at least once beforehand.



@Bob_Schor wrote:

Since I really dislike little snapshots of pieces of a Block Diagram, I went looking to see if you posted a VI, and am very pleased to see that you did!  So I opened it, and am now not so pleased!


Yes, the VI is a little bit scary. I have inherited it unfortunately, though doubt v much I could do much better! I am making attempts to clean it up. I have at least made a few things sub-VIs but that doesn't really address code inefficiency---just presentability.



@Bob_Schor wrote:

For your own sanity (and ours), please learn a little more LabVIEW, and some better coding habits. 

Things to avoid:

  • Frame Sequence Structure.  Strive for none.  They are almost never needed.
  • Everything in one VI, with wires running all over the place.  (Learn about sub-VIs).

Things to embrace:

  • The Error Line.  Most LabVIEW functions use the Error Line, and you should, too.  A single Error Line running horizontally with functions and sub-VIs "sitting" on it shows the flow of data much better and cleaner than does the Frame Sequence.
  • User-created sub-VIs.  Allows you to organize your code into "functional blocks", and has the added advantage of saving (a lot of) Block Diagram Space.
  • If you do create sub-VIs, create a simple Icon for them so they'll be "recognizable" on the Block Diagram.

Thanks so much for these tips. I will begin implementing. Like much of the programming in research, nobody checks it for readability, there is no QA and once it works, well, that's it! In fact, a simple ctrl+u has made the VI look a little more readable to me...



@Bob_Schor wrote:

A useful thing to do when you want to learn about some LabVIEW function (like the FFT) is to write a tiny little program using building blocks provided by LabVIEW.  There is a Signal Processing sub-Palette on the Block Diagram that has functions for Waveform Generation and Waveform Measurement.  The Snippet below shows a routine with the "Tones and Noise" function, generating a 10 Hz sinusoid of amplitude 1, a 35 Hz sinusoid of amplitude 0.6 and phase of 90°, and a little bit (0.1) of noise.  This feeds into an FFT Magnitude and Phase function that outputs Gain and Phase.  Notice that "Signal", "Gain", and "Phase" are all Clusters -- Signal is, in fact, a Waveform, while Gain and Phase are closely related "frequency analogs" of Waveforms (I don't know if NI has a name for this).

Simple FFT Example.png

I notice that you are running LabVIEW 2018, so I saved the VI for this Version, and have attached it.  Notice the Error Line running through this code, and notice its "standard position" (lower left and right Connectors) on the sub-VIs -- the VIs that you develop should adhere to this pattern.

 

Here's the resulting Front Panel (with the Noise parameter at 0.1 instead of 0 -- you can see the noise on the Gain plot as little bumps at higher frequencies).  Yes, I should have changed the labels on the Graphs so the X axis on the FFTs say "Frequency" and the Y Axes say "Gain" or "Phase" ...

Simple FFT Front Panel.png

 

Bob Schor 


Agreed, initially I should have started with something a little more basic. Unfortunately, I think I thought I could handle it because I can implement FFTs in seconds in other languages. If I upgrade to 2020, will this VI still work?


Also, I hadn't realised that I can only edit posts for X number of hours. I'm not sure how I feel about attachments existing here forever more. Is it possible to pull the attachments down, somehow, if I choose to in the future?

// PhD engineering, not an idiot, just new to LabVIEW, please be gentle 🙂 \\
0 Kudos
Message 20 of 22
(2,940 Views)