NI acquisition with IEPE channels (modal test)#

This example demonstrates a typical modal-testing configuration on an NI 9234 (or similar IEPE-capable module):

  1. One IEPE force channel (impact hammer)

  2. Two IEPE accelerometer channels (response sensors)

  3. Trigger on the force channel with presamples to capture the impact

  4. Live time + FFT visualization

IEPE channels are configured through nidaqwrapper.AITask.add_channel by passing units ('N' or 'g') together with sensitivity and sensitivity_units. nidaqwrapper routes these to nidaqmx’s add_ai_force_iepe_chan and add_ai_accel_chan, which automatically enable IEPE constant-current excitation. Voltage channels can be mixed into the same task by simply passing units='V' (no sensitivity needed).

Adjust device='cDAQ1Mod1', channel indices, and sensitivities to match your hardware and sensors.

[ ]:
import LDAQ

Create the AITask with IEPE channels#

Channel 0 is the impact hammer (force, mV/N sensitivity); channels 1 and 2 are accelerometers (mV/g sensitivity).

[ ]:
# NI 9234 supports up to 51.2 kS/s:
task_in = LDAQ.national_instruments.AITask("modal_test_task", sample_rate=25600)

# Channel 0 - impact hammer (IEPE force):
task_in.add_channel(
    channel_name='hammer',
    device='cDAQ1Mod1',
    channel_ind=0,
    sensitivity=2.25,            # mV/N - set to your hammer's calibration
    sensitivity_units='mV/N',
    units='N',
)

# Channels 1 and 2 - IEPE accelerometers:
task_in.add_channel(
    channel_name='accel_1',
    device='cDAQ1Mod1',
    channel_ind=1,
    sensitivity=100.0,           # mV/g - set to your sensor's calibration
    sensitivity_units='mV/g',
    units='g',
)
task_in.add_channel(
    channel_name='accel_2',
    device='cDAQ1Mod1',
    channel_ind=2,
    sensitivity=100.0,
    sensitivity_units='mV/g',
    units='g',
)

Wrap the task in NIAcquisition#

[ ]:
acq = LDAQ.national_instruments.NIAcquisition(task_in, acquisition_name="NI")

Configure live visualization#

Show the hammer time signal, the accelerometer time signals, and the FFT of each on separate subplots.

[ ]:
vis = LDAQ.Visualization(refresh_rate=100)
vis.add_lines((0, 0), "NI", [0])                                  # hammer time
vis.add_lines((1, 0), "NI", [1, 2])                               # accel time
vis.add_lines((2, 0), "NI", [0], function="fft", refresh_rate=3000)
vis.add_lines((3, 0), "NI", [1], function="fft", refresh_rate=3000)

vis.config_subplot((0, 0), t_span=0.1, ylim=(-5, 100))
vis.config_subplot((1, 0), t_span=0.1, ylim=(-20, 20))
vis.config_subplot((2, 0), t_span=2.0, ylim=(0, 1.2), xlim=(0, 5000))
vis.config_subplot((3, 0), t_span=2.0, ylim=(0, 1.2), xlim=(0, 5000))

Run with a trigger on the hammer channel#

Capture presamples of pre-trigger data so the rising edge of the impact is preserved.

[ ]:
ldaq = LDAQ.Core(acquisitions=[acq], visualization=vis)
ldaq.set_trigger(
    source="NI",
    channel="hammer",
    level=10.0,         # N - adjust to your impact magnitude
    duration=1.0,       # s of post-trigger data
    presamples=1000,    # samples of pre-trigger data
    trigger_type='abs',
)

ldaq.run(hotkeys=False)

Inspect the measurement#

[ ]:
measurement = ldaq.get_measurement_dict()
print(f"Channels:    {measurement['NI']['channel_names']}")
print(f"Data shape:  {measurement['NI']['data'].shape}")
print(f"Sample rate: {measurement['NI']['sample_rate']} Hz")