I am trying to read an analog waveform created through DDS by an external DS04102C oscilloscope on myRIO. However, I find that the analog signal reads the incorrect voltage if the signal is at a frequency that is not 1kHz. Does anyone here know why that may be?
For instance, I can generate a 1V, 1kHz signal, then read a 1V, 1kHz signal. But if I change the 1kHz to 2kHz, for example, the measured voltage decreases.
I have attached my project below. The project uses the FPGA Target, "FPGA_AnalogReader", and the RT Host, "AnalogSignal_Reader". The FPGA code reads an analog value in the ConnectorC/AI0, then it outputs it to a FIFO to be read in the RT. I have been using a Case Selector to move between methods of timing as I am still learning how to sample Analog. On the RT, I keep the Case Selector on True, then use a value of 6000000 for "A Ticks to wait". The "A" refers to analog. The RT also has a disabled section (commented out) that would be used for Digital sampling.
The RT does scaling of (RawData * 20) / 4096 to convert the raw data value to a voltage.
Let me know if the attached zip folder doesn't work.
- Thank you
Solved! Go to Solution.
I haven't had a proper look at your code yet (Those are some big block diagrams)
My first guess would be an aliasing issue. Can you check at what data rate your signal is being generated and sampled at
Hello Niatross, thank you for getting back to me so promptly.
I have updated and reattached the VI project zipfile to this reply so that it would be easier to understand and follow. The block diagrams are smaller, for instance. Please use the "updated_FPGA AnalogReader.vi" target, and the "AnalogSignal_Reader.vi" Host.
My signal is being generated at 1kHz from an oscilloscope that has a 1GSa/s sampling rate (source: http://scopechart.com/hantek/hantek-dso4102c-dso4102c-24 ). This signal is outputted through the GenOut channel of the DSO4102C, then it is put through a BNC/probe to be connected to jumper wires, and these jumper wires are finally connected to the myRIO C/AI0. This oscilloscope also has a 25 MHz waveform generator, which may be what generates the waveform that I am trying to read.
As for the sampling rate of the signal, I am unsure since I have been varying parameters to test. However, I have found that using a delay of 1000000 us or 6000000 ticks works well for reading the 1kHz signal. This delay is in a While loop of the FPGA; it occurs prior to reading and writing the C/AI0 to a FIFO. If I increase the signal's frequency to 2kHz, for instance, the voltage amplitude decreases and the peaks/troughs of the generated signal become more pointy (visually).
- Best regards
Am I looking at the right loop?
I haven't had time to look at anything but your FPGA code but it definitely sounds like your sampling rate is too slow and you are getting aliasing issues. Can you post a screenshot of your data output with the plots showing the data points as well as the lines.
What is the value of D loop time whist you are running?
Do you change the values of D Ticks to wait and D us to wait? The defaults would result in either a loop time of 6s or or 0.13s. Both of which are obviously way to slow to acquire a 1kHz signal so I am guessing you are changing them somewhere.
Yes, that is the correct loop. I am using that one for Analog input, while the one below it is for Digital input.
But despite the digital code being there, I usually have had it Disabled in the RT and I have not been gathering data for it. This has been so that I could focus on the Analog input and get it right beforehand. The D loop timing is the same as for the A loop, but it is independent of the analog process.
I have attached screenshots of the waveforms in the zipfile below. Also, I have attached screenshots of the loop times of the FPGA. The one that says "0Period" is one where I set the Period control to 0 before running. The other one is where I set it to 1000.
As for the values of D ticks to wait and D us to wait, I have actually been using the values of 6000000 and 1000000, respectively. However, I can change the values of "Ticks to wait" and "us to wait" from the RT Host.
I know of the Nyquist-Shannon theorem where sampling frequency must be at least double the signal's frequency in order to prevent aliasing, but I am unsure how to implement this idea into my code. Do you have any suggestions on how to implement this into my project? Is it that, since the input signal is 1kHz, then there are 1000Sa/s from that signal. If this is true, then my program should be able to read at least 2000Sa/s, which would require a loop time of 0.0005s?
- Best regards
The Nyquist frequency is refering to the ability to identify frequency components in your data, for example if you were sampling at 2kHz your 1kHz signal would be visibile on an FFT of your data. The amplitude of the signal would depend upon the phase difference (Not sure if that is the correct term) between your acquisition and signal. If we assume your signal is a pure sine wave, if you were sampling at the peak of every wave you would measure the correct amplitude, but if you were measuring a quarter of the way through the period you would only measure half the correct amplitude, but you would still have the same frequency components.
I suspect this is what is happening to your data. If right click on the plot legend of your graph and select the item below you will be able to see the individual data points which will give you a better idea of what is actually going on.
Acquiring data at rates slower than your nyquist frequency will result in your sine wave been misrepresented as a lower frequency signal.
See image below for a visual representation.
I would recommend having somewhere in the order of 100 data points per period of your signal, less would be ok but lets say 100 for now. The more points you have the better. This would mean you need a sampling rate of 100kHz (a period of 10us)
I suggest you simplify your code. Remove the multiple waits and just have one controlling the timing of the loop. That way there is no uncertainty as to what rate your acquisition loop is running at.
The below is an example of what it could look like. The wait function is set to us.
Thank you for the suggestion about how to view the individual points on the plot. I have implemented your recommendation about simplifying the code and using 10us.
My resulting graph seems to not represent a sine wave, but a collection of spikes. Is this what it should look like? I have also attached pictures showing the usage of 1us and 100us.
It still looks like your FPGA loop is running too slowly. Unless you have changed the code since you last uploaded it your RT loop should be running at 10Hz. if your FPGA loop is running at a period of 1us (1MHz) this would mean you should be reading ~ 100,000 samples per RT loop....
As I wrote this I realised that your FIFO buffer is set to 1928 elements (right click on the FIFO in the project explorer and goto properties. This means that if the FPGA loop is running at 1MHz you will be loosing data because of a buffer overflow unless you are emptying the FIFO at least every 1.9ms. (Also, check whether your hardware can sample this quickly, I used 1us as an illustration.
Having said this, from the screenshots it doesn't look like you are reading anywhere near 1928 samples (There are 1928 points on your graphs), so unless you have a different wait time on your RT loop compared to the 100ms on the code you sent me or you haven't go the x axis set to autoscale something else is going on.
Can you monitor the speed that the FPGA loop is running at with code similar to below. Also can you monitor how many data elements you are reading with each iteration. Also, you are setting the loop times on the RT front panel BEFORE you run your code aren't you? Your dataflow means that these only get read once (And set the FPGA controls once) when you first run the RT code.
I have not changed the RT loop since the last time. And for my hardware, my myRIO ADC has a max sampling rate of 500kSa / s.
As for the speed of the FPGA loop, it runs at the value written to the Loop Timer. So, in that case, 1us. And for how many elements I read with each iteration, it should be 1 right? The number of elements per read is 1, and it is called once per loop. If not, how would I check?
And I reset the VI each time I change the loop time values so that they are read.
I made a mistake in my previous post (And I don't seem to be able to edit it for some reason) I would be running at somewhere around 100kHz NOT 1MHz. This gives you an FPGA loop time of 10us NOT 1us. Your myRIO should be able to do this if it has a max sampling rate of 500kS/s.
When I asked about how may elements you are reading I was talking about how many elements you read from the FIFO in the RT side, not the FPGA.
Now I have written this and had another look at your code I have noticed the index array function in your RT. What you are doing is emptying the FIFO (Which will have overflown because your RT loop isn't running quickly enough and/or the FIFO size isn't big enough) so you have lost some data anyway. Then you are taking the first element in the FIFO and only displaying that one in your charts. Effectively this means that you are displaying sampled data at 10Hz even though your are acquiring the data at 100kHz (You aren't doing anything with the vast majority of the data). This is why you are seeing 'spiky' data and aliasing problems).
This is my current guess anyway.
I suggest you do the following things.
- Wire a graph (NOT A CHART) to the data terminal of the FIFO read element. This will display all of the elements that you have read in that iteration. As long as there are enough data points covering a long enough time period you should see your sine wave. This will hopefully give you more of an understanding of what is going on.
- Make sure that the combination of your FIFO size and the RT loop rate means that your FIFO won't overflow. At the moment your RT loop rate is 100ms and your FPGA loop rate is 100kHz. This means that in 100ms you will have tried to write 10,000 samples to the FIFO. your FIFO only contains 1023 elements though so you will loose ~8977 readings every 100ms. How you achieve this depends upon how quickly you want your RT loop to run. As an example you could set your FIFO size to 12288 and you RT loop rate to 100ms.
Note, the requested size (depth) won't necessarily match the requested depth. See the detailed help of that invoke method for more details.