취소
다음에 대한 결과 표시 
다음에 대한 검색 
다음을 의미합니까? 

콜백함수를 이용한 continuous DAQ

해결 완료!
솔루션으로 이동

안녕하세요,

콜백함수를 이용해서 continuous DAQ를 구현하던 도중 궁금한 점이 생겨서 왔습니다.

USB-6212, python 3.7.6, windows 10, NIDAQmx 19.6, PyDAQmx 1.4.3 사용 중입니다.

 

현재 pause trigger를 이용해서 TTL신호 레벨이 low일 때만 데이터를 받고 싶은데,

callback으로 트리거 될 때마다 데이터를 읽자니 버퍼에 일정 개수의 데이터가 와야 콜백으로 넘길 수 있는 것 같더군요.

코드의 일부분은 아래와 같습니다. 질문은 코드 아래에 적겠습니다.

 

import PyDAQmx as pydaqmx
import PyDAQmx.DAQmxCallBack as pydaqmxcb
nidaq = ctypes.windll.nicaiu
 
nidaq.DAQmxSetDigLvlPauseTrigSrc(AItaskHandle, b"/Dev%d/PFI0" %num)
nidaq.DAQmxSetPauseTrigType(AItaskHandle, DAQmx_Val_DigLvl)
nidaq.DAQmxSetDigLvlPauseTrigWhen(AItaskHandle, DAQmx_Val_High)
nidaq.DAQmxRegisterEveryNSamplesEvent(AItaskHandle,1,1000,0,EveryNCallback,id_AIdata)
 
그리고 EveryNCallback은
def EveryNCallback_py(taskHandle, eventType, nSamples, callbackData_ptr😞
DAQmx_Val_GroupByScanNumber = 1
 
callbackData = pydaqmxcb.get_callbackdata_from_id(callbackData_ptr)
read = uInt32()

nidaq.DAQmxReadAnalogF64(taskHandle,samples_per_chan,float64(-1),DAQmx_Val_GroupByScanNumber,AIdata.ctypes.data,Length,ctypes.byref(read),None)
 
return 0

EveryNCallback = pydaqmx.DAQmxEveryNSamplesEventCallbackPtr(EveryNCallback_py)
 
 
이 상황에서 TTL신호가 low일 때 특정 개수의 데이타가 버퍼에 채워지면 계속 callback 함수가 불리는 것 같은데,
 
1. 그러면 low->high로 넘어가는 순간 버퍼에 충분한 데이타가 들어있지 않으면 callback이 불리지 않은 채로 데이타가 버퍼에 남아있다가 다음 트리거가 들어오면 데이타를 마저 채워서 callback으로 넘기는 건가요? (트리거별로 별개의 데이터로 취급하고 싶은데, 이 경우 앞의 트리거에서 들어온 데이타로 오염이 되는거겠죠?)
한 트리거당 약 1천개 정도의 데이타를 받고 싶은데, 이 경우 수십~수백 개의 데이타가 다음 트리거로 전이되면 좀 타격이 있을 것 같습니다.
 
1-1. low일 동안만 쭉 DAQ를 할 수 있는 다른 방법은 없을까요?
혹은 아예 한 번에 10개~정도의 적은 데이타만 읽어서 callback을 자주 부르는 방법을 쓰는게 나을까요?(속도가 괜찮을지는 모르겠네요..)
 
2. low로 몇 번 내려갔는지 카운트 하고 싶으면 어떤 방법을 사용하면 좋을까요? (트리거 별 데이타 구분을 위하여)
 
 
감사합니다.
0 포인트
1/5 메시지
1,943 조회수

디지털 신호의 속도가 얼마나 빠른가요?

방식은 좋지만 

nidaq.DAQmxReadAnalogF64(taskHandle,samples_per_chan,float64(-1),DAQmx_Val_GroupByScanNumber,AIdata.ctypes.data,Length,ctypes.byref(read),None)

이런 형태 사용하시면, 말씀하신 것처럼 samples_per_chan 의 갯수만큼 무한정 기다리고, 데이터가 섞이게 됩니다.

 

제 생각엔 float64(-1) 을 0으로 변경하신 후 디지털 신호가 High로 바뀌는 타이밍을 찾아 한번씩만 호출하면 될 것 같습니다. 

다만, High로 변경되는 것을 파악하기가 다소 어려울 수 있겠습니다.

0 포인트
2/5 메시지
1,906 조회수

답변 감사합니다.

 

아날로그 신호는 대략 수MS로 읽고 싶고, 트리거는 해당 신호가 수천 point 찍힐 동안 low 상태로 있도록 하고 있습니다(수kHz 가량).

현재 사용중인 NIDAQ는 400kS/s까지 가능해서 다른 모델 구매 전까지는 좀 더 천천히 읽을 것 같습니다.(~수백Hz)

 

기다리는 것은 크게 문제가 되지 않을 것 같은데, 버퍼 내에 데이타가 계속 쌓여서 밀리는 건 아닌가 걱정이 되네요. 아직 NI 사용해 본 지 한 달여밖에 되지 않아 지식이 부족합니다.. 매뉴얼에도 자세하게 언급된 부분이 없는 것 같구요.(혹은 어디에 정보가 숨어있는지 금방 찾기가 힘드네요)

 

그럼 콜백과 트리거를 사용하는 대신 DI를 하나씩 실시간으로 읽어서 high로 바뀔 때 버퍼 내의 데이타를 모두 가져오도록 AI read하면 된다는 말씀인가요?

하나의 task 내에서 반복적으로 AI read를 하고 싶은 것인데(한 task 내에서 한 번만 읽고 끝->task 다시 시작하면 혹시 속도가 느려질까봐서요. 읽은 데이타도 파일로 저장할 예정이라..ㅠㅜ), task start 후에 DI 및 AI를 하나씩 실시간으로 읽는 방법을 몰라서 일단 콜백함수를 썼던 것이었거든요.

혹시 실시간으로 DI를 하나씩 읽다가 high가 되는 순간 AI를 읽고, 다시 DI를 하나씩 읽다가 low가 되는 순간 버퍼를 비우는 것이 가능할까요?

예를 들어

if (DI==1 && DI_-1==0 && DI_-2==0) nidaq.DAQmxReadAnalogF64(AItaskHandle,-1,0,DAQmx_Val_GroupByScanNumber,AIdata.ctypes.data,Length,ctypes.byref(read),None)

else if (DI==0 && DI_-1==1 && DI_-2==1) flush buffer (버퍼 비우는 명령은 아직 모르겠네요. 좀 찾아봐야 할 것 같습니다.)

 

질문이 추가되어 죄송합니다.

감사합니다!

 

0 포인트
3/5 메시지
1,900 조회수
솔루션
주제 작성자 Serenade이(가) 승인함

네 말씀하신것처럼, DI에서 모니터링 하고 있다가 특정 시점에 AI를 읽어오게 하는 방법을 말씀드렸었습니다. 다만 이 경우 AI 샘플속도가 빨라서 어려울 수 있습니다. 이상적으론 DI 측정 속도가 AI 샘플속도보다 빠르고, DI에서 엣지를 인식한 후 코드가 아주 빠르게 실행되어야 합니다. 하지만 실제론 DI가 빠르게 반응하기 어렵고, 코드가 실행되는 속도로 인한 오차도 발생해서 제대로 구현되지 않을 수 있습니다. 우려하시는 대부분의 문제도 맞습니다. 버퍼를 조절하기 어렵고 타이밍을 맞추기도 어려워질 가능성이 높네요.

 

사실, 이런 커스텀 트리거를 사용하려면 FPGA Device가 권장됩니다. 다만 FPGA는 LabVIEW를 사용해야 하기 때문에 개발환경 변경으로 인해 어려움이 있을 수 있겠네요. 

 

 

0 포인트
4/5 메시지
1,877 조회수

안녕하세요,

답변 감사합니다. 많은 참고가 되었습니다.

 

다행히 아주 strict한 DAQ는 아니라서 앞 뒤로 수십 개의 데이터가 잘려도 괜찮습니다.

일단 현재 있는 시스템으로 구현하였습니다.

 

그대로 pause trigger + 콜백함수 사용,

RegisterEveryNSamplesEvent에서 버퍼에 100개 정도 데이터가 들어오면 콜백 호출

콜백 내에서 counter 값 읽어오기(falling edge 카운트)

로 해결하였습니다.

 

0 포인트
5/5 메시지
1,850 조회수