Repository navigation
Adding Continuous Acquisition Chart Multiple Samples example in NI-DMM #2220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1ee80b2
3d7669b
20c6c25
4d53b59
be80a33
0226df1
6edc712
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #!/usr/bin/python | ||
|
|
||
| import argparse | ||
| import collections | ||
| import nidmm | ||
| import pytest | ||
| import sys | ||
|
|
||
|
|
||
| # Number of most recent measurements kept on the chart | ||
| CHART_HISTORY_SIZE = 250 | ||
|
|
||
|
|
||
| def example(resource_name, options, function, measurement_range, digits, samples_to_fetch, total_samples): | ||
| # Imported lazily because matplotlib is unavailable on some platforms (e.g. 32-bit Python) | ||
| import matplotlib.pyplot as plt | ||
|
|
||
| with nidmm.Session(resource_name=resource_name, options=options) as session: | ||
| session.configure_measurement_digits(measurement_function=nidmm.Function[function], range=measurement_range, resolution_digits=digits) | ||
| # A sample_count of 0 configures a continuous acquisition | ||
| session.configure_multi_point(trigger_count=1, sample_count=0) | ||
|
|
||
| figure, axes = plt.subplots() | ||
| (line,) = axes.plot([]) | ||
| axes.set_title('Measurements') | ||
| axes.set_xlabel('Samples') | ||
| axes.set_ylabel('Measured value') | ||
| axes.grid(True) | ||
|
|
||
| measurements = collections.deque(maxlen=CHART_HISTORY_SIZE) | ||
|
|
||
| try: | ||
| with session.initiate(): | ||
| samples_fetched = 0 | ||
|
|
||
| # A total_samples of None runs until the chart window is closed or Ctrl+C is pressed | ||
| while plt.fignum_exists(figure.number) and ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intentionally skipped the LabVIEW STOP button behavior to keep the example simple.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's certainly precedent for leaving out something like in our Python examples. This, like that, is a continuous acquisition, so perhaps we should use a similar termination mechanism?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to If Please let me know if this aligns with what you had in mind.
Yes, the graph is updated continuously as new measurements are fetched. After each fetch, the newly acquired measurements are added to the chart, and the graph is refreshed to display the latest measurements. The chart maintains a rolling window of the most recent 250 measurements. |
||
| total_samples is None or samples_fetched < total_samples | ||
| ): | ||
| # The last fetch only takes the samples still needed to reach total_samples | ||
| samples_in_this_fetch = samples_to_fetch | ||
| if total_samples is not None: | ||
| samples_in_this_fetch = min(samples_to_fetch, total_samples - samples_fetched) | ||
|
|
||
| new_samples = session.fetch_multi_point(array_size=samples_in_this_fetch) | ||
|
|
||
| measurements.extend(new_samples) | ||
| samples_fetched += len(new_samples) | ||
| first_sample = samples_fetched - len(measurements) | ||
| line.set_data(range(first_sample, samples_fetched), measurements) | ||
| axes.relim() | ||
| axes.autoscale_view() | ||
| plt.pause(0.001) | ||
|
|
||
| # The acquisition has stopped; keep the final chart on screen until its window is closed | ||
| if total_samples is not None and plt.fignum_exists(figure.number): | ||
| plt.show() | ||
| except KeyboardInterrupt: | ||
| pass | ||
| finally: | ||
| plt.close(figure) | ||
|
|
||
|
|
||
| def _main(argsv): | ||
| parser = argparse.ArgumentParser(description='Continuously acquires measurements and displays them on a chart using the NI-DMM API.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| parser.add_argument('-n', '--resource-name', default='PXI1Slot2', help='Contains the resource_name of the device to initialize.') | ||
| parser.add_argument('-f', '--function', default='DC_VOLTS', choices=nidmm.Function.__members__.keys(), type=str.upper, help='Specifies the measurement_function used to acquire the measurement.') | ||
| parser.add_argument('-r', '--range', default=10, type=float, help='Specifies the range for the function specified in the Measurement_Function parameter.') | ||
| parser.add_argument('-d', '--digits', default=5.5, type=float, help='Specifies the resolution of the measurement in digits.') | ||
| parser.add_argument('-s', '--samples-to-fetch', default=4, type=int, help='Specifies the number of measurements to fetch at a time.') | ||
| parser.add_argument('--total-samples', default=None, type=int, help='Stops fetching after this many samples and keeps the chart open until its window is closed; omit to run until the chart window is closed or Ctrl+C is pressed.') | ||
| parser.add_argument('-op', '--option-string', default='', type=str, help='Sets the initial value of certain attributes for the session.') | ||
| args = parser.parse_args(argsv) | ||
| example(args.resource_name, args.option_string, args.function, args.range, args.digits, args.samples_to_fetch, args.total_samples) | ||
|
|
||
|
|
||
| def main(): | ||
| _main(sys.argv[1:]) | ||
|
|
||
|
|
||
| def test_example(): | ||
| plt = pytest.importorskip('matplotlib.pyplot') | ||
| plt.switch_backend('Agg') # Avoid opening a chart window during the test | ||
| options = {'simulate': True, 'driver_setup': {'Model': '4082', 'BoardType': 'PXIe', }, } | ||
| example('PXI1Slot2', options, 'DC_VOLTS', 10, 5.5, 4, 10) | ||
|
|
||
|
|
||
| def test_main(): | ||
| plt = pytest.importorskip('matplotlib.pyplot') | ||
| plt.switch_backend('Agg') # Avoid opening a chart window during the test | ||
| cmd_line = ['--option-string', 'Simulate=1, DriverSetup=Model:4082; BoardType:PXIe', '--total-samples', '10', ] | ||
| _main(cmd_line) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this matplotlib stuff feels like a distraction from the demonstration of how to use nidmm. @marcoskirsch what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a bit more involved than what we did for the nidaqmx examples:
But that might be because it's doing a chart rather than a single graph.