-
Notifications
You must be signed in to change notification settings - Fork 171
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
New Example for Time Based Synchronization #674
base: master
Are you sure you want to change the base?
Conversation
I really appreciate the new example; thank you! Some requests:
I'll make more specific code comments in the file itself. |
# Perform the measurement | ||
perform_measurement() |
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.
Our examples usually prefer simplicity. I would remove this function and simply put your with ... task:
block at the top-level
time.sleep(1) | ||
|
||
# Read data after the task starts | ||
data = task.read(number_of_samples_per_channel=num_samples) |
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.
This is a more standard read from a finite task:
data = task.read(number_of_samples_per_channel=num_samples) | |
data = task.read(READ_ALL_AVAILABLE) |
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.
Note you'll need to import READ_ALL_AVAILABLE or fully specify it
num_samples = 1000 | ||
task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=num_samples) |
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.
With my suggested change to the read, this can be simplified
num_samples = 1000 | |
task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=num_samples) | |
task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=1000) |
# Calculate the start time (1 minute from now) | ||
start_time = datetime.now(timezone.utc) + timedelta(minutes=1) |
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.
1 minute is a lot...
# Calculate the start time (1 minute from now) | |
start_time = datetime.now(timezone.utc) + timedelta(minutes=1) | |
# Calculate the start time (10 seconds from now) | |
start_time = datetime.now(timezone.utc) + timedelta(seconds=10) |
print(f"Scheduled start time: {start_time}") | ||
|
||
# Configure the time start trigger | ||
task.triggers.start_trigger.cfg_time_start_trig(start_time) | ||
|
||
print("Starting the task...") | ||
task.start() | ||
|
||
print("Waiting for the scheduled start time...") | ||
# Wait until the scheduled start time |
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.
Two things:
- Generally printing commentary isn't really necessary, but for something that must wait, I like it. But let's not overdo it.
- You don't need comments that repeat the code. I like the comment describing how the time delta stuff works out. These feel a bit less useful.
print(f"Scheduled start time: {start_time}") | |
# Configure the time start trigger | |
task.triggers.start_trigger.cfg_time_start_trig(start_time) | |
print("Starting the task...") | |
task.start() | |
print("Waiting for the scheduled start time...") | |
# Wait until the scheduled start time | |
print(f"Scheduled start time: {start_time}") | |
task.triggers.start_trigger.cfg_time_start_trig(start_time) | |
task.start() | |
print("Waiting for the scheduled start time...") |
task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=num_samples) | ||
|
||
# Calculate the start time (1 minute from now) | ||
start_time = datetime.now(timezone.utc) + timedelta(minutes=1) |
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.
FYI: I was going to ask whether it's really necessary to specify UTC here, but then I looked up whether datetime.now()
returns an "aware" datetime and now I am sad.
https://discuss.python.org/t/datetime-api-no-atomic-way-to-get-aware-current-local-datetime-when-moving-between-time-zones/55041/8
https://stackoverflow.com/questions/24281525/what-is-the-point-of-a-naive-datetime
while datetime.now(timezone.utc) < start_time: | ||
time.sleep(1) |
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.
There is a DAQmx API for this, Task.wait_for_valid_timestamp
, so you don't need to poll.
https://github.com/ni/nidaqmx-python/blob/master/generated/nidaqmx/task/_task.py#L1028
I think you can wait for either TimestampEvent.FIRST_SAMPLE
or TimestampEvent.START_TRIGGER
.
I assume you are doing this to avoid getting a read timeout. FYI, another solution is to increase the read timeout to account for the scheduled start time, but that's probably less clear.
I've added tests applicable for this pull requestWhat does this Pull Request accomplish?
Adds an example for Time-Based Synchronization
Why should this Pull Request be merged?
No examples in nidaqmx python for this.
What testing has been done?
Confirmed working with cDAQ and AI Module