2020/6/10

chirp config and adc.py parameters

再來一次。用 mmWave Demo Visualizer (2.1) 的 Best Range Resolution 的 command,並且改 lvdsStreamCfg 輸出..
sensorStop
flushCfg
dfeDataOutputMode 1
channelCfg 15 3 0
adcCfg 2 1
adcbufCfg -1 0 0 1 0
profileCfg 0 77 429 7 57.14 0 0 70 1 256 5209 0 0 30
chirpCfg 0 0 0 0 0 0 0 1
chirpCfg 1 1 0 0 0 0 0 2
frameCfg 0 1 16 0 100 1 0
lowPower 0 1
guiMonitor -1 1 1 0 0 0 1
cfarCfg -1 0 0 8 4 4 0 5120
cfarCfg -1 1 0 4 2 3 0 5120
peakGrouping -1 1 1 1 1 255
multiObjBeamForming -1 1 0.5
clutterRemoval -1 0
calibDcRangeSig -1 0 -5 8 256
extendedMaxVelocity -1 0
bpmCfg -1 0 0 1
lvdsStreamCfg -1 0 1 0
nearFieldCfg -1 0 0 0
compRangeBiasAndRxChanPhase 0.0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
measureRangeBiasAndRxChanPhase 0 1.5 0.2
CQRxSatMonitor 0 3 5 123 0
CQSigImgMonitor 0 127 4
analogMonitor 1 1
sensorStart
這個對應的參數:
  • ADC Samples: 256
  • Loop Per Frame : 16
  • TX : 2
  • RX : 4

numpy reshape

np.reshape( ) 是把 array 重新安排 (group) ,可以重新安排維度..

舉例,宣告出一個一維的 array..
import numpy as np
A = np.array([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6])
把他分成6個group,每個 group 有 4 個 item..
A.reshape((6,3))

array([[1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4],
       [5, 5, 5, 5],
       [6, 6, 6, 6]])
這樣就變成二維矩陣。
其中,第一個維度..
A.reshape((6,3))[0]

array([1,1,1,1])

三個維度的話...
先分成三個 group,每個 group 再分成兩個 group...
這樣每個最小 group 裡面有 4 個 item.
A.reshape((3,2,4))

array([[[1, 1, 1, 1],
        [2, 2, 2, 2]],

       [[3, 3, 3, 3],
        [4, 4, 4, 4]],

       [[5, 5, 5, 5],
        [6, 6, 6, 6]]])
每個維度的 index.. 和 item..
A.reshape((3,2,4))[1]

array([[3, 3, 3, 3],
       [4, 4, 4, 4]])


A.reshape((3,2,4))[1][0]

array([3, 3, 3, 3])

openradar , frame reshape and chirps. frame parameters

覺得有關 frame, chirps 的參數,在 realtime.py 和 adc.py 中不一致。
這個也和 AWR1642 config command 有關。

realtime.py 的參數:
numFrames = 300
numADCSamples = 128
numTxAntennas = 3
numRxAntennas = 4
numLoopsPerFrame = 128
numChirpsPerFrame = numTxAntennas * numLoopsPerFrame

numRangeBins = numADCSamples
numDopplerBins = numLoopsPerFrame
numAngleBins = 64
他有 numChirpsPFrame = numTxAntennas * numLoopsPerFrame
跟 stanley 說明的一樣,一個 loop ,就是 一個 profile.
一個 frame 的定義就是 N 個 loop。

這個 numLoopsPerFrame 只有在 這裡有用到,其他 source code 的地方都沒有用。

adc.py 的參數:
ADC_PARAMS = {'chirps': 128, 
              'rx': 4,
              'tx': 3,
              'samples': 128,
              'IQ': 2,
              'bytes': 2}

BYTES_IN_FRAME = (ADC_PARAMS['chirps'] * ADC_PARAMS['rx'] * ADC_PARAMS['tx'] *
                  ADC_PARAMS['IQ'] * ADC_PARAMS['samples'] * ADC_PARAMS['bytes'])
直接用 chirps.
但是 bytes_in_frame,刪掉 rx, samples. IO. bytes 後...
chirps * tx
這樣看起來 chirps 好像是 loops ?


回到 realtime.py,讀完一個 frame 後..
 frame = dca.organize(adc_data, num_chirps=numChirpsPerFrame, num_rx=numRxAntennas, num_samples=numADCSamples)
其中 organize() :
  def organize(raw_frame, num_chirps, num_rx, num_samples):
        """Reorganizes raw ADC data into a full frame

        Args:
            raw_frame (ndarray): Data to format
            num_chirps         : Number of chirps included in the frame
            num_rx             : Number of receivers used in the frame
            num_samples        : Number of ADC samples included in each chirp

        Returns:
            ndarray: Reformatted frame of raw data of shape (num_chirps, num_rx, num_samples)

        """
        ret = np.zeros(len(raw_frame) // 2, dtype=complex)

        # Separate IQ data
        ret[0::2] = raw_frame[0::4] + 1j * raw_frame[2::4]
        ret[1::2] = raw_frame[1::4] + 1j * raw_frame[3::4]
        return ret.reshape((num_chirps, num_rx, num_samples))
最後的 reshape(num_chirps, num_rx, num_samples)
說明,安排的方式...
([[S,......samples],   <--rx0    第一個 chirp
  [S,......samples]],  <--rx1

 [[S,......samples],   <--rx0    第二個 chirp
  [S,......samples]],  <--rx1
  
  ...
  ..
 [[S,......samples],               第 num_chirps-1 個chirp
  [S,......samples]])
上面就是一個 frame.的所有 chirps.

所以...
framedata = data.organize(...)
framedata[0]    <-- 這是第一個 chirp 的 rx0,rx1 矩陣
framedata[0][1] <-- 這是第一個 chirp 的 rx1 array (所有 sample point)

回到 adc.py 跟 realtime.py:

參考 DCA1000EVM UDP RAW data format
raw data 是.. 每個chirp(不管是那一個 tx 送的),依照順序送 rx0,rx1,rx1,rx2 的 adc samples
所以 tx0, tx1 如果是依序送出的話, raw data 的資料也會依序是..
TX0 :  rx0,
       rx1,
       rx2,
       rx3,
TX1 :  rx0,
       rx1,
       rx2,
       rx3
所以orgnize( ) 是不用管TX0, TX1..他只需要知道一個 frame 到底有多少 chirp (TX0 + TX1)

chirps 應該是 TX 發出的FMCW波。
每個 chirps 會有 N 個 rx 信號。
所以 chirps_number * rx_number = frame rx number

最後... adc.py 跟 realtime.py 要對的起來的地方...
adc.py 的 read( ) 一個 frame,要剛好跟 realtime.py 的 orgnize( ) 的一個 frame 的 size 一樣。
read( ) 一個 frame (扣除 IO 跟 bytes):
chirps * tx * rx * samples
realtime.py 的 orgnize:
numChirpsPerFrame(numLoopsPerFrame * numTxAntennas)  * numRxAntennas * numADCSamples
這樣看來...numLoopsPerFrame 好像就是 adc.y 的 ADC_PARAMS['chirps']

2020/6/9

openradar : show range and doppler

在 demo/visualizer/realtime.py 有 fft processing 的 code..
   ...
        # (1) Reading in adc data
        adc_data = dca.read()
        frame = dca.organize(adc_data, num_chirps=numChirpsPerFrame, num_rx=numRxAntennas, num_samples=numADCSamples)

        # (2) Range Processing
        from mmwave.dsp.utils import Window
        radar_cube = dsp.range_processing(frame, window_type_1d=Window.BLACKMAN)
        assert radar_cube.shape == (
        numChirpsPerFrame, numRxAntennas, numADCSamples), "[ERROR] Radar cube is not the correct shape!"

        # (3) Doppler Processing 
        det_matrix, aoa_input = dsp.doppler_processing(radar_cube, num_tx_antennas=3, clutter_removal_enabled=True)

        # --- Show output
        if plotRangeDopp:
            det_matrix_vis = np.fft.fftshift(det_matrix, axes=1)
            plt.imshow(det_matrix_vis / det_matrix_vis.max())
            plt.pause(0.05)
            plt.clf()

  ...

2020/6/8

cv2.VideoCapture() in Windows

簡單的測試 code;
import cv2

cap = cv2.VideoCapture(0)
ret, frame = cap.read()
print(ret)
print(frame)
cv2.release()
其中 cv2.VideoCapture(0) 的 0, 就是機器上的 camera index,有幾個 camera,就用 0, 1, 2 來選。
只是不知道那一個 index 是那一個 camera..

這樣的 code,在 run 完後會出現一個 Warning:
[WARN:0] terminating async callback
這個只有在 windows 上才會有。
google 說,在VideoCapture 加上 option:
cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
說明使用 directshow 裝置。舊可以消除。

另外,在 windows 系統上,取得 VideoCapture 後,前幾個 read( ) 到的 frame 都是 黑或是灰(16) 的內容…
好像跟 camera 有關,使用nb 內建的 camera,比較不會出現這個問題。
使用外接的 usb camera,不同的camera,第一個影像出現的時間會不一樣。
跟 cpu 的速度也有關係。


* 2022/02/23 update

Linux 系統也一樣,其實是 camera (capture) 有關。
有些 hdmi usb capture 裝置,程式開啟裝置後,都要等 0.5 sec,有些不用。
所以 safe 的作法 (要take snapshot 的話)。 delay 1s:
import cv2
import time

cap = cv2.VideoCapture(2)
time.sleep(1)

ret, frame = cap.read()
cv2.imshow('ff',frame)
cv2.imsave("abc.jpg",frame)
...

cv2.imshow fail on ubuntu 18.04 anaconda

好麻煩呀,ubuntu18.04 conda python 3.8 的話,opencv 的 imshow 會 fail:
Traceback (most recent call last):
  File "testvideocap.py", line 5, in 
    cv2.imshow('dd',frame)
cv2.error: OpenCV(3.4.2) /tmp/build/80754af9/opencv-suite_1535558553474/work/modules/highgui/src/window.cpp:632: 
error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. 
If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'
好像是conda repo 的這個(3.4.2) 沒有人 mantain 了。
但是新的 mantainer 有做,所以換安裝新版 opencv 舊可以。
conda remove opencv
conda install -c conda-forge opencv=4.1.0
-c 是 channel 的意思,用 conda-forge 這個 channel 的 opencv4.1.0 package 來安裝。
是社群貢獻的 conda package repo(?).

2020/6/1

chirp config file and adc.py parameters . set I

sensorStop
flushCfg
dfeDataOutputMode 1
channelCfg 15 3 0
adcCfg 2 1
adcbufCfg -1 0 0 1 0
profileCfg 0 77 429 7 57.14 0 0 70 1 256 5209 0 0 30
chirpCfg 0 0 0 0 0 0 0 1
chirpCfg 1 1 0 0 0 0 0 2
frameCfg 0 0 16 0 100 1 0
lowPower 0 1
guiMonitor -1 1 1 0 0 0 1
cfarCfg -1 0 0 8 4 4 0 5120
cfarCfg -1 1 0 4 2 3 0 5120
peakGrouping -1 1 1 1 1 255
multiObjBeamForming -1 1 0.5
clutterRemoval -1 0
calibDcRangeSig -1 0 -5 8 256
extendedMaxVelocity -1 0
bpmCfg -1 0 0 1
lvdsStreamCfg -1 0 1 0
nearFieldCfg -1 0 0 0
compRangeBiasAndRxChanPhase 0.0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
measureRangeBiasAndRxChanPhase 0 1.5 0.2
CQRxSatMonitor 0 3 5 123 0
CQSigImgMonitor 0 127 4
analogMonitor 1 1
sensorStart

這樣對應的 ADC 參數是
ADC_PARAMS = {'chirps' : 16,
              'rx'     : 4,
              'tx'     : 1,
              'samples': 256,
              'IQ'     : 2
              'bytes'  : 2}