bhclowers

Members
  • Content Count

    11
  • Joined

  • Last visited

Everything posted by bhclowers

  1. The use of the sound card is an interesting concept. I will have to look into it but worry that the sound card will ultimately be limited in the types of waveforms it can output with respect to custom binary waveforms (i.e. not sine/cos). This gets to the heart of my original question is whether or not the pynq be used to output the waveform of interest at the specific resolution (i.e. 1 us control spanning across multiple minutes and even an hour)?
  2. We've been conducting an experiment where we are recording the impulse response from a linear frequency sweep. This linear frequency typically spans from 5 Hz - 20 kHz. It produces a signal that looks like the red decay curve attached. We can obviously transform this using the FT to get the respective frequency components back. However, we've noticed that depending on what function generator we use we get artifacts in the resulting spectrum. To be clear, these ARE NOT overtones. That is an obvious issue that we've eliminated. In short, we've narrowed the problem down to the way some function generators (e.g. the Analog Discovery) output the sweep is that the step size for the frequency change scales depending upon the frequency range being swept. Another way to say this is that it is the rate of frequency changes which induces kink in the sweep which shows up at an artifact. (See the following post for more info on that issue). Our solution at this point is to define the linear frequency sweep with same resolution (which is overkill for the low frequency components) throughout but ensures that the data come out correctly. We currently use a NI card but we are running into some issues there too. So, now to the questions are: Is there a python interface to the pynq board that will allow us to define a waveform that has the same resolution (1 us or shorter) throughout and sustain this waveform for 10's of minutes? Alternatively, is there way to stream a waveform from disk on the pynq (of course latency could be an issue there) or load a large waveform into memory (~10 million points in byte form (0's/1's))? I've thought about trying to search for issues related to PWM but that is not quite right as in some cases we might want a non-linear or custom waveform. Any advice or guidance would be appreciated. Brian
  3. To add some degree of closure to this issue, I wanted to share my largely functioning solution. For my particular purposes I intend to fold the data to realize a signal averaging effect though this is not fully implmented in the code. Compared to the original python API, I wound up building upon the following library https://github.com/amuramatsu/dwf Also, you'll need to the munch module: https://github.com/Infinidat/munch In short, it takes many of the suggestions from Attila and records both channels in a streaming fashion. Given that one of my channels is simply monitoring a TTL for a start point for the data, I imagine the digial in stream could be implemented to lessen the memory load. Generally, I feel that I've achieved 85% of my original goal. In addition to the digial in recording rather than the analog for the trigger signal, I never was able to figure out how to externally trigger the data acquisition and PWM generation. Any suggestions on that front would be appreciated. One last question thought, what parameters do I need to reset if I want to repeat the acquisition within a class? At present, I need to reinitialize the AI after closing it before I can repeat the acquisition. Is that the procedue that needs to occur or is there a faster way? Finally, Atilla, should you ever make it to Pullman, please let me know and I'd be happy to buy you a beer. digilent_interface_v7.py
  4. After playing around with saving one channel, figuring out how to detect the rising edge of the incoming locator pulse (I'm purposely not using the word "trigger" here) and folding the data appropriately, how do I stream two channels? I know that I need to setup both channels to accept data, create and new array for that information to go but how to handle the streaming component? Is there a simple way to get both channels? I seem to be messing up the account of the cSamples and cAvailable variable when I try to make it happen. cSamples = 0 while cSamples < nSamples: dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts)) if cSamples == 0 and (sts == DwfStateConfig or sts == DwfStatePrefill or sts == DwfStateArmed) : # Acquisition not yet started. continue dwf.FDwfAnalogInStatusRecord(hdwf, byref(cAvailable), byref(cLost), byref(cCorrupted)) cSamples += cLost.value if cLost.value : fLost = 1 if cCorrupted.value : fCorrupted = 1 if cAvailable.value==0 : continue if cSamples+cAvailable.value > nSamples : cAvailable = c_int(nSamples-cSamples) dwf.FDwfAnalogInStatusData(hdwf, c_int(0), byref(rgdSamples, cSamples), cAvailable) # get channel 1 data #How to configure cSamples and cAvailable to handle both channels? # dwf.FDwfAnalogInStatusData(hdwf, c_int(1), byref(rgdSamples2, cSamples), cAvailable) # get channel 2 data cSamples += cAvailable.value
  5. I think I'm running in circles here and not sure how to solve the problem. There are a few python examples provided in the SDK that seem to address the issues of triggered acquisition (AnalogIn_Trigger.py) and streaming data (AnalogIn_ShiftScreen.py) but I can't seem to figure out how to join the concepts. For AnalogIn_Trigger.py the following code has a while loop that, by my understanding, waits for the status of the AnalogIn to reach a state that will allow the data to be pulled out of the system. However, earlier in the example you need to set the data acquisition rate and the length of the sample to be read. Simply put, if you are trying to take all the data between the triggers this will not work. For example if you have triggers every 25 ms, sample at 100,000 ksps (every 10 us), and want to take 25 ms worth of data you will miss triggers. You can obviously reduce the number of points you want to take with this example to around 2400 and things will work out ok but you lose the last 100 data points to allow the system to get ready for the next trigger. for iTrigger in range(1,101): # new acquisition is started automatically after done state while True: dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts)) if sts.value == DwfStateDone.value : break time.sleep(0.001)#Will removal of this cause any issues? Is this the slow point? dwf.FDwfAnalogInStatusData(hdwf, 0, rgdSamples, numSamples) # get channel 1 data #dwf.FDwfAnalogInStatusData(hdwf, 1, rgdSamples, 8192) # get channel 2 data dc = sum(rgdSamples)/len(rgdSamples) print "Acquisition #"+str(iTrigger)+" average: "+str(dc)+"V" Alternatively, in the ShiftScreen example the data is continuously streamed to the array supporting the matplotlib window but there is no trigger component or way to align these data with a trigger. What I'm struggling with is how to achieve a data acquisition script that allows for repeated acquisitions and the data following each trigger to be aligned. For my application it is important not to miss triggers as this negates any effort at quantify a process after each trigger. Do I simply stream data from the trigger channel and the analogIn channel and then align them post-acquisition? I've looked at these post too but can't seem to find a solution:
  6. Atilla, After digging into the forums and example a bit, I see that in many examples (AnalogIn_Record.py and AnalogIn_Sample.py) do not use triggers for acquisition. However, examples like AnalogIn_ShiftScreen.py do. It is my understanding that AnalogIn_Record can stream the data to disk at a reasonable sampling speed, however, I'm wondering how to marry the idea of triggered signal averaging without missing triggers. In the AnalogIn_ShiftScreen.py shown below there is a time.sleep statement in the trigger loop, which I assume is designed to capture data after each trigger. However, if you try to take all the data between triggers and then sleep, won't you miss a tigger? Let's say you have a trigger pulse every 50 ms and you want to take data at 100ksps on the rising edge of a trigger, if you take analog in data for those 50 ms is there a way to know or test whether you've missed the next trigger? I guess, what I'm asking is how to combine the concepts in the AnalogIn and the repeated triggers? I'd like to realize signal averaging on a trigger and not miss data after a trigger pulse. Thanks again so much. I feel like I'm making progress but run into new unanticipated problems... Brian # begin acquisition dwf.FDwfAnalogInConfigure(hdwf, c_bool(False), c_bool(True)) for iTrigger in range(1,101): # new acquisition is started automatically after done state while True: dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts)) if sts.value == DwfStateDone.value : break time.sleep(0.001)#Is this necessary and will it cause triggers or data to be missed? dwf.FDwfAnalogInStatusData(hdwf, 0, rgdSamples, 8192) # get channel 1 data #dwf.FDwfAnalogInStatusData(hdwf, 1, rgdSamples, 8192) # get channel 2 data dc = sum(rgdSamples)/len(rgdSamples) print "Acquisition #"+str(iTrigger)+" average: "+str(dc)+"V" dwf.FDwfDeviceCloseAll()
  7. vonPuffelen and the Prolific Atilla, Thank you very much. I believe I have arrived at a solution (see attached). It appears to produce the correct output and seems quite stead. On a somewhat related note, I'm trying to use the PWM output as a trigger for data acquisition at a trigger signal for another piece of hardware. The challenge I'm seeing now is with the analog data acquisition. It seems as though the the current script is pulling from the buffer both before and after the trigger. Is there a way to adjust the range that is pulled from the buffer so that point 0 of the returned array is aligned with the rising edge of the trigger? As shown in the attachement, the trigger signal is smack in the middle. I imagine I could rotate the data in the python script after it is returned but this, of course, adds to overhead. Again, thank you all for your help! Cheers, Brian AnalogIn_Acquisition_6.py
  8. This definitely puts me on the right track. Thank you. I still have a few questions: 1.) Now that I can create a custom array and see the output (which looks reasonable), how do I scale the frequency to match the range I'm after and the number of elements in my Custom Pulsing Array? My initial approach was to take the length in time I'd like to pulsing array to cover, divide by the number of points in the pulsing array, convert that to a frequency in Hz and use that number to divide into the system clock. However, whenever I do that I don't get the result I'm after. 2.) How to correclty set the number of bits in FDwfDigitalOutDataSet. Is it simply the sum of all the elements in the pulsing array? Again, thanks again for the help. I see that I'm close but still fumbling... ## Configure Digital Out Channel hzSys = c_double() dwf.FDwfDigitalOutInternalClockInfo(hdwf, byref(hzSys)) ## Enable Digital pulses on IO pin 0 dwf.FDwfDigitalOutEnableSet(hdwf, c_int(0), c_int(1)) ## Configure for Custom Output dwf.FDwfDigitalOutTypeSet(hdwf, c_int(0), DwfDigitalOutTypeCustom) ## prescaler to a function the target acquisition rate and the number of target samples. SystemFrequency/Acq Freq/NumDataPoints print("DIGITAL Params:") print(hzSys.value) print(hzSys.value/hzAcq) print(int(hzSys.value/hzAcq)) dwf.FDwfDigitalOutDividerSet(hdwf, c_int(0), c_int(int(hzSys.value/20)))#How to set this properly to cover the range I'm after? pulsesLo = 50 pulsesHi = 974 pulseArray = [] for i in range(pulsesLo+pulsesHi): pulseArray.append(0) for i in range(pulsesHi): pulseArray[i] = 1 CustomOutput = (c_byte * len(pulseArray))(*pulseArray) dwf.FDwfDigitalOutDataSet(hdwf, c_int(0), CustomOutput, c_int(pulsesHi+pulsesLo))#Is this the correct way to set the number of bits #Start Digital Out dwf.FDwfDigitalOutConfigure(hdwf, c_int(1)) time.sleep(2)
  9. After going through a range of the SDK examples, I'm running into some strange behavior that I'm hoping someone can help explain. The result I'm trying to achieve is sending out a low duty cycle pulse (Digital or Analog but something similar to a TTL) that triggers the repeated acquisition on the Analog Discovery. I can achieve this result using the GUI but would like to insert this process into a python script so I can process and save the data. When I route W1 into CH1 in the following example what I see is expected. However, when I try to route the digital out into CH1 things look extremely wonky. Again, I'd like to see a waveform that would be considered a PWM waveform that has a duty cycle of ~99% low and I'd like to be able to control that duty cycle with a reasonable degree of precision and accuracy. Any help would be appreciated and hope the solution is easy as I've been staring at this entirely too long. Am I just trying to put too many points into the digital out? Another potential solution that I'm not entirely sure how to implement, is loading a custom waveform from a file and running that through the waveform generator. Is there an example for that that would also fit with the DAQ needs? Cheers, Brian AnalogIn_Acquisition_5.py
  10. In short, we rely heavily upon the Analog Discovery units in the lab and have grown to rely upon the scripting features that enable triggered signal averaging and custom signal processing. Is there a mechnism or plan to enable a similar set of features with the OpenScopeMZ. As a stand alone, simple scope the system works well but without the ablity to script its potential seems stunted. Ideas? Thoughts? Timeline?
  11. I have an external event that operates at a frequency of 10-20 kHz that can be accessed through a TTL signal. This TTL signal has negative peaks that last about 2 us which could potentially be used as trigger events. I also have a custom waveform that I'd can load into the waveforms software via the custom tab and what I'd like to do is use the external TTL signals as a mechanism to march through each row of the custom waveform. When the number of external clock pulses exceeds the custom waveform length I'd like the row to simply reset (e.g. modulo operator). Now to top it off I'd like this whole process to be triggered by yet a second master pulse that starts the whole crazy sequence. Is this doable? If so might someone point me to the appropriate Waveforms SDK functions? Better yet, if some python pseudo code could be produced and you visit Pullman I will buy beers. The problem I have now with simply setting the frequency and using a master signal trigger is that there is some jitter that creates a scenario where the custom waveform "marches" out of sync with the master pulse. Cheers, Brian