Data acquisition and streaming¶
Acquire a DAQ window¶
DAQ channels expose signals from the FPGA design. A channel number is not necessarily an analog-input connector number. This example uses the repository's DAQ design; run it from the repository root:
import asyncio
import numpy as np
from noa.noa import Noa
from noa.daq import DaqTrigger, TriggerKind
async def main():
async with Noa("arch1-00001.local") as device:
await device.load_bitstream(
"examples/daq/design_1_wrapper.bit",
"examples/daq/design_1.hwh",
)
try:
await device.daq.setup_data(window_size=1000, decimation=1, delay=0)
await device.daq.enable_channel(1, dtype="fixdt(1,32,29)")
await device.daq.trigger(DaqTrigger(kind=TriggerKind.Immediate))
samples = await asyncio.wait_for(device.daq.read(1), timeout=5)
np.savetxt("channel1.csv", samples, delimiter=",")
finally:
await device.daq.reset()
if __name__ == "__main__":
asyncio.run(main())
Match the timing and data type to your design. A host timeout prevents an indefinite wait; it does not reconfigure the FPGA trigger.
Queues and callbacks¶
Without a callback, enable_channel() buffers windows in a queue. await read(channel) waits for one window; read_ready(channel) checks whether one is already available. The default capacity is 100 windows. When full, new windows are dropped with a warning; consume data promptly.
Alternatively, use a short asynchronous callback:
async def on_window(channel, samples):
print(channel, len(samples))
await device.daq.enable_channel(0, dtype="fixdt(1,32,29)", cb=on_window)
Use queue reads or a callback for a given channel. disable_channel() stops its subscription; reset() resets acquisition.
Triggers¶
await device.daq.trigger(DaqTrigger(
kind=TriggerKind.RisingEdge, channel=0, threshold=0, hysteresis=10,
))
The repository example notes that trigger logic treats signals as signed 32-bit integers. Thresholds are raw design values, not automatically converted to volts or the decoded dtype. See the API reference for trigger names.
Stream data to the FPGA¶
With a design exposing the expected stream-input interface:
import numpy as np
await device.stream_in.write(np.arange(100, dtype=np.uint32), dtype="uint32")
Samples are encoded as 32-bit words. Provide a NumPy array with the representation appropriate to dtype. write() splits large transfers into chunks and marks the final chunk. Consumption and timing depend on FPGA logic.
For raw data, write_chunk(data, last=True) accepts a multiple of four bytes, at most 1,000,000 bytes per call. Prefer write() unless you manage encoding yourself.
See the DAQ and stream-input examples.