Jump to content

maling

Members
  • Posts

    12
  • Joined

  • Last visited

Everything posted by maling

  1. (Follow-up post: I was able to confirm the downsampling behavior in the app: a 32k length sinusoid downsampled to 16k exhibits the predicted binary ouput.)
  2. Aha, that explains a lot. So when you set a 32k wavegen signal in the funcCustom mode in the WaveForms UI, this signal stretching is also applied, and only every "N" samples are actually sent to the wavegen? It seems counterintuitive to allow users to import a 32k length sample in the WaveForms app GUI if only a subset of 4k samples will be chosen (in configuration 0, for instance). Perhaps a warning should be displayed to alert the user that their full signal will not be used? (Aside: It seems that the 32k sample length import is permitted regardless of which configuration the user has chosen - but no more than 32k.) For my application, I will (for now) just use the largest output buffer available. Thank you!
  3. In the available configurations for the Analog Discovery II, the largest buffer configuration for the AWG is 2 x 16k, which I take to mean that each channel of the AWG has its own 16k sample buffer. However, when you use the WaveForms GUI / app, and go to Wavegen -> dropdown that says "Simple" -> select "Custom" (funcCustom) -> button that says "Import" (import signal from .WAV) -> import a .WAV file of some length, you are able to successfully import up to 32k samples and produce the signal without issue. This still works for frequencies well above those suitable for funcPlay (well into the MHz range), so I assume it is indeed playing straight from the device buffer. I can't find any python examples (in the samples folder) which describe how this works under the hood. Do you manually tell the wavegen to switch from one buffer to another? Is there a way to force the device to share both channels of the buffer as a single 32k sample buffer? Is there something in the .WAV (encoded as int32) that allows you to cram more samples into the 16k buffer? Whatever the trick is, what is the trade-off of entering this mode? Is the available buffer for the oscilloscopes reduced? If so, would this affect the maximum frequency at which AnalogIn_Record.py could haul in data without losing samples? Do the two output channels (AWG 1 and 2) become coupled together? Thank you!
  4. Hi @attila, (Re accepted answer) That's solved it! I made the szerr.value modification, and did not get any error messages. But your example code (which runs perfectly!) helped me realize why: I think the issue isn't from the dwf library. My device connection step (FDwfEnum) was much more complicated than what you posted - I had originally based it on the Enumerate.py example, since I needed the device serial numbers and thought the other debug information might be useful. When I modified my device connection step to use only the dwf library (cutting out most of the Enumerate.py example - anything related to dmgr, ftd, and dftd), suddenly my old code worked perfectly. It's still beyond me exactly what was causing the issue, but it looks like the revised connection procedure has fixed it. Thank you for your patience in helping me sort through this. I hope this thread helps someone who finds themselves in similar shoes!
  5. Hi @attila, See below for an illustration of what does, and does not, produce the failure. The full code base is a bit large - if you need a full working example, let me know and I can do some rearranging. Of the functions below, GetSpectrum() does not produce the failure, while GetSpectra() does. Thank you! All nine devices are first connected. They each have the following configuration applied: DLLs.FDwf(dwf.FDwfAnalogImpedanceReset, [hdwf]) DLLs.FDwf(dwf.FDwfAnalogImpedanceModeSet, [hdwf, c_int(8)]) # 0 = W1-C1-DUT-C2-R-GND, 1 = W1-C1-R-C2-DUT-GND, 8 = AD IA adapter DLLs.FDwf(dwf.FDwfAnalogImpedanceReferenceSet, [hdwf, c_double(reference)]) # reference resistor value in Ohms DLLs.FDwf(dwf.FDwfAnalogImpedanceFrequencySet, [hdwf, c_double(start)]) # frequency in Hertz DLLs.FDwf(dwf.FDwfAnalogImpedanceAmplitudeSet, [hdwf, c_double(1)]) # 1V amplitude = 2V peak2peak signal DLLs.FDwf(dwf.FDwfAnalogImpedanceConfigure, [hdwf, c_int(1)]) # start Then either GetSpectrum() is called for each device one by one (no failure), or GetSpectra() is called to measure all devices simultaneously (failure). # Take an impedance spectrum measurement def GetSpectrum(hdwf, settings, DLLs, verbose = False): # Just takes a single spectrum from a device that's already been enumerated and opened. That's all it does. # Get the Digilent WaveForm library dwf = DLLs.dwf dmgr = DLLs.dmgr ftd = DLLs.ftd osname = DLLs.osname # Get the settings from settings steps = settings.steps # Set up some C variables sts = c_byte() szerr = create_string_buffer(512) # Prepare containers for measurement results frequencies = settings.frequencies rgRs = [0.0]*steps rgXs = [0.0]*steps # Perform the measurement redundantly repeat = 1 # Integer number of times to repeat the measurement for j in range(repeat): for i in range(steps): DLLs.FDwf(dwf.FDwfAnalogImpedanceFrequencySet, [hdwf, c_double(frequencies[i])]) # frequency in Hertz # Once you set a value, it will start its measurement routine automatically time.sleep(0.01) DLLs.FDwf(dwf.FDwfAnalogImpedanceStatus, [hdwf, None]) # ignore last capture since we changed the frequency while True: if DLLs.FDwf(dwf.FDwfAnalogImpedanceStatus, [hdwf, byref(sts)]) == 0: # This just checks whether the measurement using this frequency value has completed dwf.FDwfGetLastErrorMsg(szerr) print("There's been an error reading impedance") print(str(szerr.value)) quit() if sts.value == 2: break resistance = c_double() reactance = c_double() time.sleep() DLLs.FDwf(dwf.FDwfAnalogImpedanceStatusMeasure, [hdwf, DwfAnalogImpedanceResistance, byref(resistance)]) DLLs.FDwf(dwf.FDwfAnalogImpedanceStatusMeasure, [hdwf, DwfAnalogImpedanceReactance, byref(reactance)]) rgRs[i] += abs(resistance.value) # absolute value for logarithmic plot rgXs[i] += abs(reactance.value) # Adjust the data considering the degree of repetition for i in range(steps): rgRs[i] /= repeat rgXs[i] /= repeat # Return the data return Spectrum(frequencies, rgRs, rgXs) # Take an impedance spectrum measurement # Rearranges the for loops so that multiple measurements can occur simultaneously, even though the main computation is single threaded # Works from a list of devices that have already been enumerated and opened. Returns all of their spectra. def GetSpectra(hdwfs, settings, DLLs, verbose = False): # Get the Digilent WaveForm library dwf = DLLs.dwf dmgr = DLLs.dmgr ftd = DLLs.ftd osname = DLLs.osname # Get the settings from settings steps = settings.steps # Number of steps # Set up some C variables sts = c_byte() szerr = create_string_buffer(512) # Prepare containers for measurement results frequencies = settings.frequencies resistances = [[0.0]*steps for x in range(len(hdwfs))] reactances = [[0.0]*steps for x in range(len(hdwfs))] # Permit averaging of multiple measurements repeat = 1 # Integer number of times to repeat the measurement for j in range(repeat): # For each frequency... for i in range(steps): # Set frequency for all devices for k in range(len(hdwfs)): DLLs.FDwf(dwf.FDwfAnalogImpedanceFrequencySet, [hdwfs[k], c_double(frequencies[i])]) # frequency in Hertz # Once you set a value, it will start its measurement routine automatically # Wait for settings to take effect time.sleep(0.01) # Clear out the most-recently-read value for all devices # Do this all at once, so that we can wait for all devices to finish the next measurement at once. for k in range(len(hdwfs)): DLLs.FDwf(dwf.FDwfAnalogImpedanceStatus, [hdwfs[k], None]) # ignore last capture since we changed the frequency # Read the result from each of the devices, once they complete. for k in range(len(hdwfs)): hdwf = hdwfs[k] # Wait for the measurement to complete for this device. while True: if DLLs.FDwf(dwf.FDwfAnalogImpedanceStatus, [hdwf, byref(sts)]) == 0: # This just checks whether the measurement using this frequency value has completed dwf.FDwfGetLastErrorMsg(szerr) print("There's been an error reading impedance") print(str(szerr.value)) quit() if sts.value == 2: break # Compute the resistance and reactance from the harvested values resistance = c_double() reactance = c_double() DLLs.FDwf(dwf.FDwfAnalogImpedanceStatusMeasure, [hdwf, DwfAnalogImpedanceResistance, byref(resistance)]) DLLs.FDwf(dwf.FDwfAnalogImpedanceStatusMeasure, [hdwf, DwfAnalogImpedanceReactance, byref(reactance)]) resistances[k][i] += abs(resistance.value) # absolute value for logarithmic plot reactances[k][i] += abs(reactance.value) # Adjust the data considering the degree of averaging # For each device... for k in range(len(hdwfs)): for i in range(steps): resistances[k][i] /= repeat reactances[k][i] /= repeat # Return the data return [Spectrum(frequencies, resistances[k], reactances[k]) for k in range(len(hdwfs))] # The Digilent FDwf library requires you to explicitly check for errors after every execution. # This is a wrapper for convenience. def FDwf(self, fun, args): if fun(*args) == 0: # If the function returns 0, that means an error has occurred. print('') print('There has been an error while calling ' + str(fun) + ' with arguments' + str(args)) print('') # We have to go find the error szerr = create_string_buffer(512) self.dwf.FDwfGetLastErrorMsg(szerr) # Then print it print(szerr) # And abort execution raise NameError('Digilent')
  6. Hi @attila, I still have it on my list to try @reddish's pydwf project, but I believe that the above implementation is sufficient to catch any error messages which are generated. Given that no error messages are being produced, I was hoping you might have additional insight into possible causes of the failure. It feels very much like the failure is related to some manner of delayed communication with the Analog Discovery II. I don't have enough expertise to understand what might be happening under the hood, but I would be happy to provide example code if that would be useful. Thank you!
  7. Hi @attila, Ah, thank you, that explains a lot. I've tried implementing FDwfGetLastErrorMsg using the following wrapper: def FDwf(self, fun, args): if fun(*args) == 0: # If the function returns 0, that means an error has occurred. print('') print('There has been an error while calling ' + str(fun) + ' with arguments' + str(args)) print('') # We have to go find the error szerr = create_string_buffer(512) self.dwf.FDwfGetLastErrorMsg(szerr) # Then print it print(szerr) # And abort execution raise NameError('Digilent') After converting every call to FDwf functions to use this wrapper, I still do not receive any error messages (although the functions execute just fine up until the typical failure). This seems to indicate that whatever failure is occurring is something that is not well-handled in the underlying libraries. I believe that is consistent with my earlier observation that execution does not abort immediately following any given line of Python code. Do you have any intuition as to what might be going on?
  8. Another possibility, though I would be surprised if this were the case - does DWF 3.14.3 support Python 3? This post implies it may not, although perhaps the "updated" date in 2021 is deceptive: https://digilent.com/blog/waveforms-sdk-is-now-updated-to-include-python-3/
  9. Hi @attila Thanks for the reply! I just checked on the power issue (there was a chance - my USB hub could only supply 36 W.) However, dividing the Discovery II's between two identical hubs at 36 W each, the error still occurs with exactly the same behavior. I have tried to use FDwfGetLastErrorMsg(sz) as you suggested, but without the immediate return statements. Does the immediate return statement change the behavior of the function? Example: bool myfunc(){ FDwf...(.) FDwf...(..) ... } myfunc() FDwfGetLastErrorMsg(sz) print(sz)
  10. Hello all! I've been working with the WaveForms SDK for over a year now to control a collection of nine Digilent Analog Discovery II's connected to a powered USB hub. For the most part, it's been great - but recently I've encountered a problem that I can't seem to debug. This is primarily because on encountering most errors within the SDK, the SDK appears to abort the main Python script's execution silently, without raising an exception in Python. In this case, I've attempted to use FDwfGetLastErrorMsg, but no error is recognized by this method either. Question 1: Is there a more powerful way to access error messages from the WaveForms SDK when using Python? As for the issue itself, it's hard to pin down without those messages. Something appears to happen within the WaveForms SDK, a fixed time after several functions from the WaveForms SDK are called by my Python process. These functions are called repeatedly, in a measurement loop that is meant to run for hours or days. Everything works correctly for some number of iterations, but eventually the execution always aborts silently. The number of successful iterations varies semi-randomly, but it appears to fail earlier if I have more Digilents connected. (With five, it runs for quite some time; with seven, it fails in a few minutes; with nine, it fails within one minute.) I have verified that the timing of the silent failure does not coincide with any line of Python code that I am executing; it occurs a fixed amount of time after I have called the most recent SDK function. Overall, it sounds very much like some kind of communication error between the Digilents and the WaveForms process, with multiple devices stepping on each other's toes. Question 2: Does this sound familiar? Is there a tutorial for best practices when communicating with multiple Digilent Analog Discovery II's? And/or do you have any tips for debugging in situations like these? System details: Python 3.8.3 Anaconda 4.8.3 Windows 10 Thank you!
×
×
  • Create New...