From fbc48f27be2447d325a76585a6c8a55725bb717e Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Tue, 23 Apr 2024 13:01:55 +0800 Subject: [PATCH 01/13] Add and update AO examples --- examples/analog_out/ao_voltage_hw_timed.py | 25 --------- examples/analog_out/ao_voltage_sw_timed.py | 24 --------- .../cont_gen_voltage_wfm_int_clk.py | 32 +++++++++++ ...ltage_wfm_int_clk_every_n_samples_event.py | 40 ++++++++++++++ .../cont_gen_voltage_wfm_int_clk_non_regen.py | 54 +++++++++++++++++++ examples/analog_out/gen_voltage_sample.py | 13 +++++ .../analog_out/gen_voltage_wfm_int_clk.py | 17 ++++++ 7 files changed, 156 insertions(+), 49 deletions(-) delete mode 100644 examples/analog_out/ao_voltage_hw_timed.py delete mode 100644 examples/analog_out/ao_voltage_sw_timed.py create mode 100644 examples/analog_out/cont_gen_voltage_wfm_int_clk.py create mode 100644 examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py create mode 100644 examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py create mode 100644 examples/analog_out/gen_voltage_sample.py create mode 100644 examples/analog_out/gen_voltage_wfm_int_clk.py diff --git a/examples/analog_out/ao_voltage_hw_timed.py b/examples/analog_out/ao_voltage_hw_timed.py deleted file mode 100644 index 8955bf2a9..000000000 --- a/examples/analog_out/ao_voltage_hw_timed.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Example of AO voltage hw operation.""" - -import nidaqmx - -with nidaqmx.Task() as task: - task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - - task.timing.cfg_samp_clk_timing(1000) - - print("1 Channel N Samples Write: ") - print(task.write([1.1, 2.2, 3.3, 4.4, 5.5], auto_start=True)) - task.wait_until_done() - task.stop() - - task.ao_channels.add_ao_voltage_chan("Dev1/ao1:3") - - print("N Channel N Samples Write: ") - print( - task.write( - [[1.1, 2.2, 3.3], [1.1, 2.2, 4.4], [2.2, 3.3, 4.4], [2.2, 3.3, 4.4]], - auto_start=True, - ) - ) - task.wait_until_done() - task.stop() diff --git a/examples/analog_out/ao_voltage_sw_timed.py b/examples/analog_out/ao_voltage_sw_timed.py deleted file mode 100644 index 928436aa4..000000000 --- a/examples/analog_out/ao_voltage_sw_timed.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Example of AO voltage sw operation.""" - -import nidaqmx - -with nidaqmx.Task() as task: - task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - - print("1 Channel 1 Sample Write: ") - print(task.write(1.0)) - task.stop() - - print("1 Channel N Samples Write: ") - print(task.write([1.1, 2.2, 3.3, 4.4, 5.5], auto_start=True)) - task.stop() - - task.ao_channels.add_ao_voltage_chan("Dev1/ao1") - - print("N Channel 1 Sample Write: ") - print(task.write([1.1, 2.2])) - task.stop() - - print("N Channel N Samples Write: ") - print(task.write([[1.1, 2.2, 3.3], [1.1, 2.2, 4.4]], auto_start=True)) - task.stop() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py new file mode 100644 index 000000000..b0dee5c25 --- /dev/null +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -0,0 +1,32 @@ +"""Example of analog output voltage generation. + +This example demonstrates how to output a continuous periodic +waveform using an internal sample clock. +""" + +import numpy as np + +import nidaqmx +from nidaqmx.constants import AcquisitionType + +with nidaqmx.Task() as task: + frequency = 10 + amplitude = 1 + sampling_rate = 100 + duration = 1 + + # generate the time array + t = np.arange(0, duration, 1 / sampling_rate) + # Generate the sine wave + data = amplitude * np.sin(2 * np.pi * frequency * t) + + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.timing.cfg_samp_clk_timing( + 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 + ) + task.write(data) + task.start() + + input("Running task. Press Enter to stop.\n") + + task.stop() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py new file mode 100644 index 000000000..32c4065c3 --- /dev/null +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -0,0 +1,40 @@ +"""Example of analog output voltage generation with events. + +This example demonstrates how to use a Every N Samples events to output a +continuous periodic waveform to an Analog Output Channel +using an internal sample clock. The Every N Samples events indicate when +the specified number of samples generation is complete. +""" + +import numpy as np + +import nidaqmx +from nidaqmx.constants import AcquisitionType + +with nidaqmx.Task() as task: + frequency = 10 + amplitude = 1 + sampling_rate = 100 + duration = 1 + + # generate the time array + t = np.arange(0, duration, 1 / sampling_rate) + # Generate the sine wave + data = amplitude * np.sin(2 * np.pi * frequency * t) + + def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): + """Callback function for written data.""" + print(f"transferred {number_of_samples} samples event invoked.") + return 0 + + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.timing.cfg_samp_clk_timing( + 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 + ) + task.register_every_n_samples_transferred_from_buffer_event(100, callback) + task.write(data) + task.start() + + input("Running task. Press Enter to stop.\n") + + task.stop() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py new file mode 100644 index 000000000..5eafa235b --- /dev/null +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -0,0 +1,54 @@ +"""Example of analog output voltage generation. + +This example demonstrates how to output a continuous periodic +waveform with new data using an internal sample clock while +the task is running. +""" + +import time + +import numpy as np + +import nidaqmx +from nidaqmx.constants import AcquisitionType, RegenerationMode + + +def get_sine_wave_data(cycle): + """Generate a sine wave data.""" + frequency = (10, 50) + amplitude = (1, 3) + sampling_rate = (100, 500) + duration = 1 + selection = cycle % 2 + + # generate the time array + t = np.arange(0, duration, 1 / sampling_rate[selection]) + # Generate the sine wave + data = amplitude[selection] * np.sin(2 * np.pi * frequency[selection] * t) + return data + + +with nidaqmx.Task() as task: + is_first_run = True + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION + task.timing.cfg_samp_clk_timing( + 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 + ) + + try: + cycle = 1 + print("Starting task. Press Ctrl+C to stop.") + time.sleep(1.0) + + while True: + data = get_sine_wave_data(cycle) + task.write(data) + cycle = cycle + 1 + if is_first_run: + is_first_run = False + task.start() + except KeyboardInterrupt: + pass + finally: + task.stop() diff --git a/examples/analog_out/gen_voltage_sample.py b/examples/analog_out/gen_voltage_sample.py new file mode 100644 index 000000000..968d3b633 --- /dev/null +++ b/examples/analog_out/gen_voltage_sample.py @@ -0,0 +1,13 @@ +"""Example of analog output voltage generation. + +This example demonstrates how to output a single Voltage Update +(Sample) to an Analog Output Channel. +""" + +import nidaqmx + +with nidaqmx.Task() as task: + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + + print(f"Generate {task.write(1.1)} voltage sample.") + task.stop() diff --git a/examples/analog_out/gen_voltage_wfm_int_clk.py b/examples/analog_out/gen_voltage_wfm_int_clk.py new file mode 100644 index 000000000..10d8659c3 --- /dev/null +++ b/examples/analog_out/gen_voltage_wfm_int_clk.py @@ -0,0 +1,17 @@ +"""Example of analog output voltage generation. + +This example demonstrates how to output a finite number of +voltage samples to an Analog Output Channel using an internal +sample clock. +""" + +import nidaqmx +from nidaqmx.constants import AcquisitionType + +with nidaqmx.Task() as task: + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=1000) + + print(f"Generate {task.write([1.1, 2.2, 3.3, 4.4, 5.5])} voltage samples.") + task.wait_until_done() + task.stop() From 1a2b25438bd4b2237e3e3d57525655cf2658d519 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Mon, 29 Apr 2024 09:27:36 +0800 Subject: [PATCH 02/13] reworked on given comments --- examples/analog_out/analog_out_helper.py | 24 ++++++++++ .../cont_gen_voltage_wfm_int_clk.py | 21 +++------ ...ltage_wfm_int_clk_every_n_samples_event.py | 26 +++++------ .../cont_gen_voltage_wfm_int_clk_non_regen.py | 44 +++++++------------ .../analog_out/gen_voltage_wfm_int_clk.py | 12 ++++- ...en_voltage_sample.py => voltage_update.py} | 1 - tests/acceptance/test_examples.py | 10 +++++ 7 files changed, 78 insertions(+), 60 deletions(-) create mode 100644 examples/analog_out/analog_out_helper.py rename examples/analog_out/{gen_voltage_sample.py => voltage_update.py} (95%) diff --git a/examples/analog_out/analog_out_helper.py b/examples/analog_out/analog_out_helper.py new file mode 100644 index 000000000..9a581463e --- /dev/null +++ b/examples/analog_out/analog_out_helper.py @@ -0,0 +1,24 @@ +"""Helper functions for the analog_out example.""" + +import numpy +import numpy.typing + +np = numpy + + +def create_sine_wave( + frequency: float, amplitude: float, sampling_rate: float, duration: float +) -> numpy.typing.NDArray[numpy.double]: + """Generate a sine wave.""" + t = np.arange(0, duration, 1 / sampling_rate) + + return amplitude * np.sin(2 * np.pi * frequency * t) + + +def create_voltage_sample(voltage: float, number_of_samples: int) -> float: + """Generate a voltage sample.""" + data = [] + for i in range(number_of_samples): + data.append(voltage * i / number_of_samples) + + return data diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index b0dee5c25..47dcb3de9 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -4,29 +4,22 @@ waveform using an internal sample clock. """ -import numpy as np +from analog_out_helper import create_sine_wave import nidaqmx from nidaqmx.constants import AcquisitionType with nidaqmx.Task() as task: - frequency = 10 - amplitude = 1 - sampling_rate = 100 - duration = 1 - - # generate the time array - t = np.arange(0, duration, 1 / sampling_rate) - # Generate the sine wave - data = amplitude * np.sin(2 * np.pi * frequency * t) + sampling_rate = 1000.0 + data = create_sine_wave( + frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 + ) task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.timing.cfg_samp_clk_timing( - 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 - ) + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) task.write(data) task.start() - input("Running task. Press Enter to stop.\n") + input("Generating voltage continuously. Press Enter to stop.\n") task.stop() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 32c4065c3..597b9fbb9 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -6,35 +6,29 @@ the specified number of samples generation is complete. """ -import numpy as np +from analog_out_helper import create_sine_wave import nidaqmx from nidaqmx.constants import AcquisitionType with nidaqmx.Task() as task: - frequency = 10 - amplitude = 1 - sampling_rate = 100 - duration = 1 - - # generate the time array - t = np.arange(0, duration, 1 / sampling_rate) - # Generate the sine wave - data = amplitude * np.sin(2 * np.pi * frequency * t) + sampling_rate = 1000.0 + data = create_sine_wave( + frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 + ) def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): """Callback function for written data.""" - print(f"transferred {number_of_samples} samples event invoked.") + print("Transferred N samples") + return 0 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.timing.cfg_samp_clk_timing( - 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 - ) - task.register_every_n_samples_transferred_from_buffer_event(100, callback) + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) + task.register_every_n_samples_transferred_from_buffer_event(1000, callback) task.write(data) task.start() - input("Running task. Press Enter to stop.\n") + input("Generating voltage continuously. Press Enter to stop.\n") task.stop() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 5eafa235b..85e5f938d 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -1,48 +1,38 @@ """Example of analog output voltage generation. -This example demonstrates how to output a continuous periodic -waveform with new data using an internal sample clock while -the task is running. +This example demonstrates how to continuously generate an +analog output waveform by providing new data to the output buffer +as the task is running. + +This example is useful if you want to generate a non-repeating waveform, +make updates on-the-fly, or generate a frequency that is not an +even divide-down of your sample clock. In this example, +the default frequency value is 17.0 to demonstrate that non-regenerative output +can be used to create a signal with a frequency that is not an even divide-down +of your sample clock. """ -import time - -import numpy as np +from analog_out_helper import create_sine_wave import nidaqmx from nidaqmx.constants import AcquisitionType, RegenerationMode -def get_sine_wave_data(cycle): - """Generate a sine wave data.""" - frequency = (10, 50) - amplitude = (1, 3) - sampling_rate = (100, 500) - duration = 1 - selection = cycle % 2 - - # generate the time array - t = np.arange(0, duration, 1 / sampling_rate[selection]) - # Generate the sine wave - data = amplitude[selection] * np.sin(2 * np.pi * frequency[selection] * t) - return data - - with nidaqmx.Task() as task: is_first_run = True + sampling_rate = 1000.0 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION - task.timing.cfg_samp_clk_timing( - 1000, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=100 - ) + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) try: cycle = 1 - print("Starting task. Press Ctrl+C to stop.") - time.sleep(1.0) + print("Generating voltage continuously. Press Ctrl+C to stop.") while True: - data = get_sine_wave_data(cycle) + data = create_sine_wave( + frequency=17.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 + ) task.write(data) cycle = cycle + 1 if is_first_run: diff --git a/examples/analog_out/gen_voltage_wfm_int_clk.py b/examples/analog_out/gen_voltage_wfm_int_clk.py index 10d8659c3..c90b80680 100644 --- a/examples/analog_out/gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/gen_voltage_wfm_int_clk.py @@ -5,13 +5,21 @@ sample clock. """ +from analog_out_helper import create_voltage_sample + import nidaqmx from nidaqmx.constants import AcquisitionType with nidaqmx.Task() as task: + data = [] + total_samples = 1000 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=1000) + task.timing.cfg_samp_clk_timing( + 1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=total_samples + ) - print(f"Generate {task.write([1.1, 2.2, 3.3, 4.4, 5.5])} voltage samples.") + data = create_voltage_sample(5.0, total_samples) + number_of_samples_written = task.write(data, auto_start=True) + print(f"Generate {number_of_samples_written} voltage samples.") task.wait_until_done() task.stop() diff --git a/examples/analog_out/gen_voltage_sample.py b/examples/analog_out/voltage_update.py similarity index 95% rename from examples/analog_out/gen_voltage_sample.py rename to examples/analog_out/voltage_update.py index 968d3b633..7f2fd872f 100644 --- a/examples/analog_out/gen_voltage_sample.py +++ b/examples/analog_out/voltage_update.py @@ -10,4 +10,3 @@ task.ao_channels.add_ao_voltage_chan("Dev1/ao0") print(f"Generate {task.write(1.1)} voltage sample.") - task.stop() diff --git a/tests/acceptance/test_examples.py b/tests/acceptance/test_examples.py index a1c07a1c4..94dba5a19 100644 --- a/tests/acceptance/test_examples.py +++ b/tests/acceptance/test_examples.py @@ -1,8 +1,10 @@ from __future__ import annotations import contextlib +import os import re import runpy +import sys import warnings from pathlib import Path @@ -29,6 +31,8 @@ def test___shipping_example___run___no_errors(example_path: Path, system): ) if example_path.name == "ci_pulse_freq.py": pytest.skip("Example times out if there is no signal.") + if example_path.name == "analog_out_helper.py": + pytest.skip("Helper for analog output.") if re.search(r"\binput\(|\bKeyboardInterrupt\b", example_source): pytest.skip("Example waits for keyboard input.") if example_path.name == "nidaqmx_warnings.py": @@ -38,6 +42,12 @@ def test___shipping_example___run___no_errors(example_path: Path, system): context_manager = contextlib.nullcontext() with context_manager: + example_dir = os.path.dirname(os.path.abspath(example_path)) + if example_dir not in sys.path: + # Solving ModuleNotFoundError. + # Add the example directory to sys.path so that the + # helper module can be found. + sys.path.append(example_dir) runpy.run_path(str(example_path)) From 46bb3311e6899001694537c380648f2138bcae74 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Mon, 29 Apr 2024 14:14:49 +0800 Subject: [PATCH 03/13] updated sample rate, removed unused variable --- examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py | 3 --- examples/analog_out/gen_voltage_wfm_int_clk.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 85e5f938d..4389359e8 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -26,15 +26,12 @@ task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) try: - cycle = 1 print("Generating voltage continuously. Press Ctrl+C to stop.") - while True: data = create_sine_wave( frequency=17.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 ) task.write(data) - cycle = cycle + 1 if is_first_run: is_first_run = False task.start() diff --git a/examples/analog_out/gen_voltage_wfm_int_clk.py b/examples/analog_out/gen_voltage_wfm_int_clk.py index c90b80680..5820ba8bf 100644 --- a/examples/analog_out/gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/gen_voltage_wfm_int_clk.py @@ -15,7 +15,7 @@ total_samples = 1000 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") task.timing.cfg_samp_clk_timing( - 1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=total_samples + 1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=total_samples ) data = create_voltage_sample(5.0, total_samples) From 69ca680252721651ce92e6492836dc136f0b0e3d Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Fri, 3 May 2024 18:05:25 +0800 Subject: [PATCH 04/13] reworked on comments part 2 --- examples/analog_out/analog_out_helper.py | 24 -------- .../cont_gen_voltage_wfm_int_clk.py | 43 +++++++++---- ...ltage_wfm_int_clk_every_n_samples_event.py | 60 +++++++++++++------ .../analog_out/gen_voltage_wfm_int_clk.py | 4 +- tests/acceptance/test_examples.py | 10 ---- 5 files changed, 75 insertions(+), 66 deletions(-) delete mode 100644 examples/analog_out/analog_out_helper.py diff --git a/examples/analog_out/analog_out_helper.py b/examples/analog_out/analog_out_helper.py deleted file mode 100644 index 9a581463e..000000000 --- a/examples/analog_out/analog_out_helper.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Helper functions for the analog_out example.""" - -import numpy -import numpy.typing - -np = numpy - - -def create_sine_wave( - frequency: float, amplitude: float, sampling_rate: float, duration: float -) -> numpy.typing.NDArray[numpy.double]: - """Generate a sine wave.""" - t = np.arange(0, duration, 1 / sampling_rate) - - return amplitude * np.sin(2 * np.pi * frequency * t) - - -def create_voltage_sample(voltage: float, number_of_samples: int) -> float: - """Generate a voltage sample.""" - data = [] - for i in range(number_of_samples): - data.append(voltage * i / number_of_samples) - - return data diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index 47dcb3de9..7aff07aa2 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -4,22 +4,41 @@ waveform using an internal sample clock. """ -from analog_out_helper import create_sine_wave +import numpy as np +import numpy.typing import nidaqmx from nidaqmx.constants import AcquisitionType -with nidaqmx.Task() as task: - sampling_rate = 1000.0 - data = create_sine_wave( - frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 - ) - task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) - task.write(data) - task.start() +def create_sine_wave( + frequency: float, amplitude: float, sampling_rate: float, duration: float +) -> numpy.typing.NDArray[numpy.double]: + """Generate a sine wave.""" + t = np.arange(0, duration, 1 / sampling_rate) - input("Generating voltage continuously. Press Enter to stop.\n") + return amplitude * np.sin(2 * np.pi * frequency * t) - task.stop() + +def main(): + """Continuously generates a sine wave.""" + with nidaqmx.Task() as task: + sampling_rate = 1000.0 + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) + + actual_sampling_rate = task.timing.samp_clk_rate + print(f"Actual sampling rate: {actual_sampling_rate} Hz") + + data = create_sine_wave( + frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, duration=1.0 + ) + task.write(data) + task.start() + + input("Generating voltage continuously. Press Enter to stop.\n") + + task.stop() + +if __name__ == "__main__": + main() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 597b9fbb9..a52aeae53 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -6,29 +6,55 @@ the specified number of samples generation is complete. """ -from analog_out_helper import create_sine_wave +import numpy as np +import numpy.typing import nidaqmx from nidaqmx.constants import AcquisitionType -with nidaqmx.Task() as task: - sampling_rate = 1000.0 - data = create_sine_wave( - frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 - ) - def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): - """Callback function for written data.""" - print("Transferred N samples") +def create_sine_wave( + frequency: float, amplitude: float, sampling_rate: float, duration: float +) -> numpy.typing.NDArray[numpy.double]: + """Generate a sine wave.""" + t = np.arange(0, duration, 1 / sampling_rate) - return 0 + return amplitude * np.sin(2 * np.pi * frequency * t) - task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) - task.register_every_n_samples_transferred_from_buffer_event(1000, callback) - task.write(data) - task.start() - input("Generating voltage continuously. Press Enter to stop.\n") +def main(): + """Continuously generates a sine wave using an Every N Samples event.""" + total_write = 0 + with nidaqmx.Task() as task: + sampling_rate = 1000.0 - task.stop() + + def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): + """Callback function for Transferred N samples.""" + nonlocal total_write + total_write += number_of_samples + print(f"Transferred data: {number_of_samples} samples. Total {total_write}.", end="\r") + + return 0 + + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) + task.register_every_n_samples_transferred_from_buffer_event(1000, callback) + + actual_sampling_rate = task.timing.samp_clk_rate + print(f"Actual sampling rate: {actual_sampling_rate} Hz") + + data = create_sine_wave( + frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 + ) + task.write(data) + task.start() + + input("Generating voltage continuously. Press Enter to stop.\n") + + task.stop() + print(f"\nTransferred {total_write} total samples.") + + +if __name__ == "__main__": + main() diff --git a/examples/analog_out/gen_voltage_wfm_int_clk.py b/examples/analog_out/gen_voltage_wfm_int_clk.py index 5820ba8bf..60b485dcf 100644 --- a/examples/analog_out/gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/gen_voltage_wfm_int_clk.py @@ -5,8 +5,6 @@ sample clock. """ -from analog_out_helper import create_voltage_sample - import nidaqmx from nidaqmx.constants import AcquisitionType @@ -18,7 +16,7 @@ 1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=total_samples ) - data = create_voltage_sample(5.0, total_samples) + data = [5.0 * i / total_samples for i in range(total_samples)] number_of_samples_written = task.write(data, auto_start=True) print(f"Generate {number_of_samples_written} voltage samples.") task.wait_until_done() diff --git a/tests/acceptance/test_examples.py b/tests/acceptance/test_examples.py index 94dba5a19..a1c07a1c4 100644 --- a/tests/acceptance/test_examples.py +++ b/tests/acceptance/test_examples.py @@ -1,10 +1,8 @@ from __future__ import annotations import contextlib -import os import re import runpy -import sys import warnings from pathlib import Path @@ -31,8 +29,6 @@ def test___shipping_example___run___no_errors(example_path: Path, system): ) if example_path.name == "ci_pulse_freq.py": pytest.skip("Example times out if there is no signal.") - if example_path.name == "analog_out_helper.py": - pytest.skip("Helper for analog output.") if re.search(r"\binput\(|\bKeyboardInterrupt\b", example_source): pytest.skip("Example waits for keyboard input.") if example_path.name == "nidaqmx_warnings.py": @@ -42,12 +38,6 @@ def test___shipping_example___run___no_errors(example_path: Path, system): context_manager = contextlib.nullcontext() with context_manager: - example_dir = os.path.dirname(os.path.abspath(example_path)) - if example_dir not in sys.path: - # Solving ModuleNotFoundError. - # Add the example directory to sys.path so that the - # helper module can be found. - sys.path.append(example_dir) runpy.run_path(str(example_path)) From 2a02b27a4d0f0b493c2c604b6b8e4a61a5fce2c4 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Fri, 3 May 2024 19:16:10 +0800 Subject: [PATCH 05/13] updated non regen example --- .../cont_gen_voltage_wfm_int_clk.py | 1 + ...ltage_wfm_int_clk_every_n_samples_event.py | 1 - .../cont_gen_voltage_wfm_int_clk_non_regen.py | 75 +++++++++++++------ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index 7aff07aa2..d990c2113 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -40,5 +40,6 @@ def main(): task.stop() + if __name__ == "__main__": main() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index a52aeae53..2786c014a 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -28,7 +28,6 @@ def main(): with nidaqmx.Task() as task: sampling_rate = 1000.0 - def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): """Callback function for Transferred N samples.""" nonlocal total_write diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 4389359e8..111d68492 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -12,30 +12,61 @@ of your sample clock. """ -from analog_out_helper import create_sine_wave +import numpy as np +import numpy.typing import nidaqmx from nidaqmx.constants import AcquisitionType, RegenerationMode -with nidaqmx.Task() as task: - is_first_run = True - sampling_rate = 1000.0 - task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION - task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) - - try: - print("Generating voltage continuously. Press Ctrl+C to stop.") - while True: - data = create_sine_wave( - frequency=17.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 - ) - task.write(data) - if is_first_run: - is_first_run = False - task.start() - except KeyboardInterrupt: - pass - finally: - task.stop() +def create_sine_wave( + frequency: float, amplitude: float, sampling_rate: float, phase_in: float, phase_out: float +) -> numpy.typing.NDArray[numpy.double]: + """Generate a sine wave.""" + number_of_samples = int(sampling_rate * (phase_out - phase_in) * np.pi) + t = np.linspace(phase_in * np.pi, phase_out * np.pi, number_of_samples) + + return amplitude * np.sin(2 * np.pi * frequency * t) + + +def main(): + """Continuously generates non-repeating waveform.""" + with nidaqmx.Task() as task: + is_first_run = True + sampling_rate = 1000.0 + task.ao_channels.add_ao_voltage_chan("Dev1/ao0") + task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION + task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) + + actual_sampling_rate = task.timing.samp_clk_rate + print(f"Actual sampling rate: {actual_sampling_rate} Hz") + + try: + full_cycle = 2.0 + full_cycle_and_one_quadrant = full_cycle + 0.5 + phase_in = 0.0 + phase_out = 0.0 + print("Generating voltage continuously. Press Ctrl+C to stop.") + while True: + phase_out = phase_in + full_cycle_and_one_quadrant + data = create_sine_wave( + frequency=17.0, + amplitude=1.0, + sampling_rate=actual_sampling_rate, + phase_in=phase_in, + phase_out=phase_out, + ) + task.write(data) + if is_first_run: + is_first_run = False + task.start() + + phase_in = phase_out % full_cycle + except KeyboardInterrupt: + pass + finally: + task.stop() + + +if __name__ == "__main__": + main() From 716166755f362d665e53d515c84b49b69d443629 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Tue, 7 May 2024 11:35:18 +0800 Subject: [PATCH 06/13] updated printout text and precision format --- examples/analog_out/cont_gen_voltage_wfm_int_clk.py | 2 +- .../cont_gen_voltage_wfm_int_clk_every_n_samples_event.py | 2 +- examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py | 2 +- examples/analog_out/gen_voltage_wfm_int_clk.py | 2 +- examples/analog_out/voltage_update.py | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index d990c2113..6925fa6bf 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -28,7 +28,7 @@ def main(): task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate} Hz") + print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") data = create_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, duration=1.0 diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 2786c014a..dc225e604 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -41,7 +41,7 @@ def callback(task_handle, every_n_samples_event_type, number_of_samples, callbac task.register_every_n_samples_transferred_from_buffer_event(1000, callback) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate} Hz") + print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") data = create_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 111d68492..5e1de83a4 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -39,7 +39,7 @@ def main(): task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate} Hz") + print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") try: full_cycle = 2.0 diff --git a/examples/analog_out/gen_voltage_wfm_int_clk.py b/examples/analog_out/gen_voltage_wfm_int_clk.py index 60b485dcf..f823c7408 100644 --- a/examples/analog_out/gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/gen_voltage_wfm_int_clk.py @@ -18,6 +18,6 @@ data = [5.0 * i / total_samples for i in range(total_samples)] number_of_samples_written = task.write(data, auto_start=True) - print(f"Generate {number_of_samples_written} voltage samples.") + print(f"Generating {number_of_samples_written} voltage samples.") task.wait_until_done() task.stop() diff --git a/examples/analog_out/voltage_update.py b/examples/analog_out/voltage_update.py index 7f2fd872f..169ea8e33 100644 --- a/examples/analog_out/voltage_update.py +++ b/examples/analog_out/voltage_update.py @@ -9,4 +9,5 @@ with nidaqmx.Task() as task: task.ao_channels.add_ao_voltage_chan("Dev1/ao0") - print(f"Generate {task.write(1.1)} voltage sample.") + number_of_samples_written = task.write(1.1) + print(f"Generated {number_of_samples_written} voltage sample.") From 6eaaef8666562bbd84e4b99d9f61c6dcd6db782f Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Tue, 7 May 2024 11:39:49 +0800 Subject: [PATCH 07/13] replaced precision from .2f to g --- examples/analog_out/cont_gen_voltage_wfm_int_clk.py | 2 +- .../cont_gen_voltage_wfm_int_clk_every_n_samples_event.py | 2 +- examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index 6925fa6bf..d40372491 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -28,7 +28,7 @@ def main(): task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") + print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") data = create_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, duration=1.0 diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index dc225e604..7675a1166 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -41,7 +41,7 @@ def callback(task_handle, every_n_samples_event_type, number_of_samples, callbac task.register_every_n_samples_transferred_from_buffer_event(1000, callback) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") + print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") data = create_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 5e1de83a4..05367a4bb 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -39,7 +39,7 @@ def main(): task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate - print(f"Actual sampling rate: {actual_sampling_rate:.2f} S/s") + print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") try: full_cycle = 2.0 From 74dd515bbcc3f6423399a1c1804599c2037a681f Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Fri, 10 May 2024 00:24:35 +0800 Subject: [PATCH 08/13] updated non regen example as per suggestion --- .../cont_gen_voltage_wfm_int_clk_non_regen.py | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 05367a4bb..a5fb61a93 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -12,6 +12,8 @@ of your sample clock. """ +from typing import Tuple + import numpy as np import numpy.typing @@ -19,21 +21,54 @@ from nidaqmx.constants import AcquisitionType, RegenerationMode -def create_sine_wave( - frequency: float, amplitude: float, sampling_rate: float, phase_in: float, phase_out: float -) -> numpy.typing.NDArray[numpy.double]: - """Generate a sine wave.""" - number_of_samples = int(sampling_rate * (phase_out - phase_in) * np.pi) - t = np.linspace(phase_in * np.pi, phase_out * np.pi, number_of_samples) +def create_sine_wave_with_phase( + frequency: float, + amplitude: float, + sampling_rate: float, + phase_in: float, + number_of_samples: int, +) -> Tuple[numpy.typing.NDArray[numpy.double], float]: + """Generates a sine wave with a specified phase. + + Args: + frequency (float): Specifies the frequency of the sine wave. + amplitude (float): Specifies the amplitude of the sine wave. + sampling_rate (float): Specifies the sampling rate of the sine wave. + phase_in (float): Specifies the phase of the sine wave in radians. + number_of_samples (int): Specifies the number of samples to generate. + + Returns: + Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple + containing the generated data and the phase of the sine wave after generation. + """ + duration_time = number_of_samples / sampling_rate + duration_radians = (duration_time / frequency) * 2 * np.pi + phase_out = (phase_in + duration_radians) % (2 * np.pi) + t = np.linspace(phase_in, phase_out, number_of_samples) - return amplitude * np.sin(2 * np.pi * frequency * t) + return (amplitude * np.sin(frequency * t), phase_out) def main(): - """Continuously generates non-repeating waveform.""" + """ + Generate a continuous voltage waveform using an analog output channel of a NI-DAQmx device. + + This function sets up a task to generate a continuous voltage waveform using the specified analog output channel + of a NI-DAQmx device. It configures the sampling rate, number of samples, and regeneration mode of the task. + It then enters a loop where it continuously generates a sine wave with a specified frequency, amplitude, and phase, + and writes the waveform to the analog output channel. The loop continues until the user interrupts the program + by pressing Ctrl+C. + + Args: + None + + Returns: + None + """ with nidaqmx.Task() as task: is_first_run = True sampling_rate = 1000.0 + number_of_samples = 1000 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") task.out_stream.regen_mode = RegenerationMode.DONT_ALLOW_REGENERATION task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) @@ -42,26 +77,23 @@ def main(): print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") try: - full_cycle = 2.0 - full_cycle_and_one_quadrant = full_cycle + 0.5 phase_in = 0.0 phase_out = 0.0 print("Generating voltage continuously. Press Ctrl+C to stop.") while True: - phase_out = phase_in + full_cycle_and_one_quadrant - data = create_sine_wave( + data, phase_out = create_sine_wave_with_phase( frequency=17.0, amplitude=1.0, sampling_rate=actual_sampling_rate, phase_in=phase_in, - phase_out=phase_out, + number_of_samples=number_of_samples, ) task.write(data) if is_first_run: is_first_run = False task.start() - phase_in = phase_out % full_cycle + phase_in = phase_out except KeyboardInterrupt: pass finally: From 97d6644c6c7b777f5f8f49c8cf24614cc31c8180 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Fri, 10 May 2024 00:31:19 +0800 Subject: [PATCH 09/13] fixed style error --- .../cont_gen_voltage_wfm_int_clk_non_regen.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index a5fb61a93..4e97a56b8 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -50,14 +50,14 @@ def create_sine_wave_with_phase( def main(): - """ - Generate a continuous voltage waveform using an analog output channel of a NI-DAQmx device. - - This function sets up a task to generate a continuous voltage waveform using the specified analog output channel - of a NI-DAQmx device. It configures the sampling rate, number of samples, and regeneration mode of the task. - It then enters a loop where it continuously generates a sine wave with a specified frequency, amplitude, and phase, - and writes the waveform to the analog output channel. The loop continues until the user interrupts the program - by pressing Ctrl+C. + """Generate a continuous voltage waveform using an analog output channel of a NI-DAQmx device. + + This function sets up a task to generate a continuous voltage waveform using the specified + analog output channel of a NI-DAQmx device. It configures the sampling rate, number of samples, + and regeneration mode of the task. It then enters a loop where it continuously generates a + sine wave with a specified frequency, amplitude, and phase, and writes the waveform to the + analog output channel. + The loop continues until the user interrupts the program by pressing Ctrl+C. Args: None From f990e9971131bc220e68a517aada45a165934ef6 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Mon, 27 May 2024 09:06:03 +0800 Subject: [PATCH 10/13] updated sine wave generation function with phase --- .../cont_gen_voltage_wfm_int_clk.py | 43 +++++++++++++++---- ...ltage_wfm_int_clk_every_n_samples_event.py | 43 +++++++++++++++---- .../cont_gen_voltage_wfm_int_clk_non_regen.py | 15 +++---- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index d40372491..0e460b195 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -4,6 +4,8 @@ waveform using an internal sample clock. """ +from typing import Tuple + import numpy as np import numpy.typing @@ -11,27 +13,52 @@ from nidaqmx.constants import AcquisitionType -def create_sine_wave( - frequency: float, amplitude: float, sampling_rate: float, duration: float -) -> numpy.typing.NDArray[numpy.double]: - """Generate a sine wave.""" - t = np.arange(0, duration, 1 / sampling_rate) +def generate_sine_wave( + frequency: float, + amplitude: float, + sampling_rate: float, + phase_in: float, + number_of_samples: int, +) -> Tuple[numpy.typing.NDArray[numpy.double], float]: + """Generates a sine wave with a specified phase. + + Args: + frequency (float): Specifies the frequency of the sine wave. + amplitude (float): Specifies the amplitude of the sine wave. + sampling_rate (float): Specifies the sampling rate of the sine wave. + phase_in (float): Specifies the phase of the sine wave in radians. + number_of_samples (int): Specifies the number of samples to generate. + + Returns: + Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple + containing the generated data and the phase of the sine wave after generation. + """ + duration_time = number_of_samples / sampling_rate + duration_radians = duration_time * 2 * np.pi + phase_out = (phase_in + duration_radians) % (2 * np.pi) + t = np.linspace(phase_in, phase_in + duration_radians, number_of_samples, endpoint=False) - return amplitude * np.sin(2 * np.pi * frequency * t) + return (amplitude * np.sin(frequency * t), phase_out) def main(): """Continuously generates a sine wave.""" with nidaqmx.Task() as task: sampling_rate = 1000.0 + number_of_samples = 1000 + phase = 0.0 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") - data = create_sine_wave( - frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, duration=1.0 + data, phase = generate_sine_wave( + frequency=10.0, + amplitude=1.0, + sampling_rate=actual_sampling_rate, + phase_in=phase, + number_of_samples=number_of_samples, ) task.write(data) task.start() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 7675a1166..99e468023 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -6,6 +6,8 @@ the specified number of samples generation is complete. """ +from typing import Tuple + import numpy as np import numpy.typing @@ -13,13 +15,32 @@ from nidaqmx.constants import AcquisitionType -def create_sine_wave( - frequency: float, amplitude: float, sampling_rate: float, duration: float -) -> numpy.typing.NDArray[numpy.double]: - """Generate a sine wave.""" - t = np.arange(0, duration, 1 / sampling_rate) +def generate_sine_wave( + frequency: float, + amplitude: float, + sampling_rate: float, + phase_in: float, + number_of_samples: int, +) -> Tuple[numpy.typing.NDArray[numpy.double], float]: + """Generates a sine wave with a specified phase. + + Args: + frequency (float): Specifies the frequency of the sine wave. + amplitude (float): Specifies the amplitude of the sine wave. + sampling_rate (float): Specifies the sampling rate of the sine wave. + phase_in (float): Specifies the phase of the sine wave in radians. + number_of_samples (int): Specifies the number of samples to generate. + + Returns: + Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple + containing the generated data and the phase of the sine wave after generation. + """ + duration_time = number_of_samples / sampling_rate + duration_radians = duration_time * 2 * np.pi + phase_out = (phase_in + duration_radians) % (2 * np.pi) + t = np.linspace(phase_in, phase_in + duration_radians, number_of_samples, endpoint=False) - return amplitude * np.sin(2 * np.pi * frequency * t) + return (amplitude * np.sin(frequency * t), phase_out) def main(): @@ -27,6 +48,8 @@ def main(): total_write = 0 with nidaqmx.Task() as task: sampling_rate = 1000.0 + number_of_samples = 1000 + phase = 0.0 def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): """Callback function for Transferred N samples.""" @@ -43,8 +66,12 @@ def callback(task_handle, every_n_samples_event_type, number_of_samples, callbac actual_sampling_rate = task.timing.samp_clk_rate print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") - data = create_sine_wave( - frequency=10.0, amplitude=1.0, sampling_rate=sampling_rate, duration=1.0 + data, phase = generate_sine_wave( + frequency=10.0, + amplitude=1.0, + sampling_rate=actual_sampling_rate, + phase_in=phase, + number_of_samples=number_of_samples, ) task.write(data) task.start() diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 4e97a56b8..3b025d140 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -21,7 +21,7 @@ from nidaqmx.constants import AcquisitionType, RegenerationMode -def create_sine_wave_with_phase( +def generate_sine_wave( frequency: float, amplitude: float, sampling_rate: float, @@ -42,9 +42,9 @@ def create_sine_wave_with_phase( containing the generated data and the phase of the sine wave after generation. """ duration_time = number_of_samples / sampling_rate - duration_radians = (duration_time / frequency) * 2 * np.pi + duration_radians = duration_time * 2 * np.pi phase_out = (phase_in + duration_radians) % (2 * np.pi) - t = np.linspace(phase_in, phase_out, number_of_samples) + t = np.linspace(phase_in, phase_in + duration_radians, number_of_samples, endpoint=False) return (amplitude * np.sin(frequency * t), phase_out) @@ -77,23 +77,20 @@ def main(): print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") try: - phase_in = 0.0 - phase_out = 0.0 + phase = 0.0 print("Generating voltage continuously. Press Ctrl+C to stop.") while True: - data, phase_out = create_sine_wave_with_phase( + data, phase = generate_sine_wave( frequency=17.0, amplitude=1.0, sampling_rate=actual_sampling_rate, - phase_in=phase_in, + phase_in=phase, number_of_samples=number_of_samples, ) task.write(data) if is_first_run: is_first_run = False task.start() - - phase_in = phase_out except KeyboardInterrupt: pass finally: From e894f1f4d19acc5527a64b5586ffd641482129af Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Wed, 29 May 2024 10:05:37 +0800 Subject: [PATCH 11/13] set phase_in parameter optional for examples do not need it --- examples/analog_out/cont_gen_voltage_wfm_int_clk.py | 8 +++----- .../cont_gen_voltage_wfm_int_clk_every_n_samples_event.py | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index 0e460b195..ec7cc4e0b 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -17,8 +17,8 @@ def generate_sine_wave( frequency: float, amplitude: float, sampling_rate: float, - phase_in: float, number_of_samples: int, + phase_in: float = 0.0, ) -> Tuple[numpy.typing.NDArray[numpy.double], float]: """Generates a sine wave with a specified phase. @@ -26,8 +26,8 @@ def generate_sine_wave( frequency (float): Specifies the frequency of the sine wave. amplitude (float): Specifies the amplitude of the sine wave. sampling_rate (float): Specifies the sampling rate of the sine wave. - phase_in (float): Specifies the phase of the sine wave in radians. number_of_samples (int): Specifies the number of samples to generate. + phase_in (Optional[float]): Specifies the phase of the sine wave in radians. Returns: Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple @@ -46,18 +46,16 @@ def main(): with nidaqmx.Task() as task: sampling_rate = 1000.0 number_of_samples = 1000 - phase = 0.0 task.ao_channels.add_ao_voltage_chan("Dev1/ao0") task.timing.cfg_samp_clk_timing(sampling_rate, sample_mode=AcquisitionType.CONTINUOUS) actual_sampling_rate = task.timing.samp_clk_rate print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") - data, phase = generate_sine_wave( + data, _ = generate_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, - phase_in=phase, number_of_samples=number_of_samples, ) task.write(data) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 99e468023..68f2c96d3 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -19,8 +19,8 @@ def generate_sine_wave( frequency: float, amplitude: float, sampling_rate: float, - phase_in: float, number_of_samples: int, + phase_in: float = 0.0, ) -> Tuple[numpy.typing.NDArray[numpy.double], float]: """Generates a sine wave with a specified phase. @@ -28,8 +28,8 @@ def generate_sine_wave( frequency (float): Specifies the frequency of the sine wave. amplitude (float): Specifies the amplitude of the sine wave. sampling_rate (float): Specifies the sampling rate of the sine wave. - phase_in (float): Specifies the phase of the sine wave in radians. number_of_samples (int): Specifies the number of samples to generate. + phase_in (Optional[float]): Specifies the phase of the sine wave in radians. Returns: Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple @@ -49,7 +49,6 @@ def main(): with nidaqmx.Task() as task: sampling_rate = 1000.0 number_of_samples = 1000 - phase = 0.0 def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data): """Callback function for Transferred N samples.""" @@ -66,11 +65,10 @@ def callback(task_handle, every_n_samples_event_type, number_of_samples, callbac actual_sampling_rate = task.timing.samp_clk_rate print(f"Actual sampling rate: {actual_sampling_rate:g} S/s") - data, phase = generate_sine_wave( + data, _ = generate_sine_wave( frequency=10.0, amplitude=1.0, sampling_rate=actual_sampling_rate, - phase_in=phase, number_of_samples=number_of_samples, ) task.write(data) From f4ac72ab2225722adaa57f6b3b35e7652b85cbe5 Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Wed, 29 May 2024 10:12:22 +0800 Subject: [PATCH 12/13] updated generate_sine_wave function in non-regen example to align other examples --- .../analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index 3b025d140..de02ca524 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -25,8 +25,8 @@ def generate_sine_wave( frequency: float, amplitude: float, sampling_rate: float, - phase_in: float, number_of_samples: int, + phase_in: float = 0.0, ) -> Tuple[numpy.typing.NDArray[numpy.double], float]: """Generates a sine wave with a specified phase. @@ -34,8 +34,8 @@ def generate_sine_wave( frequency (float): Specifies the frequency of the sine wave. amplitude (float): Specifies the amplitude of the sine wave. sampling_rate (float): Specifies the sampling rate of the sine wave. - phase_in (float): Specifies the phase of the sine wave in radians. number_of_samples (int): Specifies the number of samples to generate. + phase_in (Optional[float]): Specifies the phase of the sine wave in radians. Returns: Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple @@ -84,8 +84,8 @@ def main(): frequency=17.0, amplitude=1.0, sampling_rate=actual_sampling_rate, - phase_in=phase, number_of_samples=number_of_samples, + phase_in=phase, ) task.write(data) if is_first_run: From 4a1fca4d82a0849db4d933918d8dedb2fe2508ab Mon Sep 17 00:00:00 2001 From: Joo Liang Cheah Date: Thu, 30 May 2024 01:32:04 +0800 Subject: [PATCH 13/13] removed types from the docstring --- .../analog_out/cont_gen_voltage_wfm_int_clk.py | 14 +++++++------- ...en_voltage_wfm_int_clk_every_n_samples_event.py | 14 +++++++------- .../cont_gen_voltage_wfm_int_clk_non_regen.py | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py index ec7cc4e0b..61555ef6f 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk.py @@ -23,15 +23,15 @@ def generate_sine_wave( """Generates a sine wave with a specified phase. Args: - frequency (float): Specifies the frequency of the sine wave. - amplitude (float): Specifies the amplitude of the sine wave. - sampling_rate (float): Specifies the sampling rate of the sine wave. - number_of_samples (int): Specifies the number of samples to generate. - phase_in (Optional[float]): Specifies the phase of the sine wave in radians. + frequency: Specifies the frequency of the sine wave. + amplitude: Specifies the amplitude of the sine wave. + sampling_rate: Specifies the sampling rate of the sine wave. + number_of_samples: Specifies the number of samples to generate. + phase_in: Specifies the phase of the sine wave in radians. Returns: - Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple - containing the generated data and the phase of the sine wave after generation. + Indicates a tuple containing the generated data and the phase + of the sine wave after generation. """ duration_time = number_of_samples / sampling_rate duration_radians = duration_time * 2 * np.pi diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py index 68f2c96d3..01d66fc78 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_every_n_samples_event.py @@ -25,15 +25,15 @@ def generate_sine_wave( """Generates a sine wave with a specified phase. Args: - frequency (float): Specifies the frequency of the sine wave. - amplitude (float): Specifies the amplitude of the sine wave. - sampling_rate (float): Specifies the sampling rate of the sine wave. - number_of_samples (int): Specifies the number of samples to generate. - phase_in (Optional[float]): Specifies the phase of the sine wave in radians. + frequency: Specifies the frequency of the sine wave. + amplitude: Specifies the amplitude of the sine wave. + sampling_rate: Specifies the sampling rate of the sine wave. + number_of_samples: Specifies the number of samples to generate. + phase_in: Specifies the phase of the sine wave in radians. Returns: - Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple - containing the generated data and the phase of the sine wave after generation. + Indicates a tuple containing the generated data and the phase + of the sine wave after generation. """ duration_time = number_of_samples / sampling_rate duration_radians = duration_time * 2 * np.pi diff --git a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py index de02ca524..9c0be568a 100644 --- a/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py +++ b/examples/analog_out/cont_gen_voltage_wfm_int_clk_non_regen.py @@ -31,15 +31,15 @@ def generate_sine_wave( """Generates a sine wave with a specified phase. Args: - frequency (float): Specifies the frequency of the sine wave. - amplitude (float): Specifies the amplitude of the sine wave. - sampling_rate (float): Specifies the sampling rate of the sine wave. - number_of_samples (int): Specifies the number of samples to generate. - phase_in (Optional[float]): Specifies the phase of the sine wave in radians. + frequency: Specifies the frequency of the sine wave. + amplitude: Specifies the amplitude of the sine wave. + sampling_rate: Specifies the sampling rate of the sine wave. + number_of_samples: Specifies the number of samples to generate. + phase_in: Specifies the phase of the sine wave in radians. Returns: - Tuple[numpy.typing.NDArray[numpy.double], float]: Indicates a tuple - containing the generated data and the phase of the sine wave after generation. + Indicates a tuple containing the generated data and the phase + of the sine wave after generation. """ duration_time = number_of_samples / sampling_rate duration_radians = duration_time * 2 * np.pi