xref: /openwifi/user_space/side_ch_ctl_src/side_info_display.py (revision e556af35c696ecef552192823e107caf37eb6af9)
122dd0cc4SXianjun Jiao#
222dd0cc4SXianjun Jiao# openwifi side info receive and display program
322dd0cc4SXianjun Jiao# Xianjun jiao. [email protected]; [email protected]
422dd0cc4SXianjun Jiao#
522dd0cc4SXianjun Jiaoimport os
622dd0cc4SXianjun Jiaoimport sys
722dd0cc4SXianjun Jiaoimport socket
822dd0cc4SXianjun Jiaoimport numpy as np
922dd0cc4SXianjun Jiaoimport matplotlib.pyplot as plt
1022dd0cc4SXianjun Jiao
118cfbbc8eSXianjun Jiaodef display_side_info(freq_offset, csi, equalizer, waterfall_flag, CSI_LEN, EQUALIZER_LEN):
1222dd0cc4SXianjun Jiao    if not hasattr(display_side_info, 'freq_offset_store'):
1322dd0cc4SXianjun Jiao        display_side_info.freq_offset_store = np.zeros((256,))
1422dd0cc4SXianjun Jiao
1522dd0cc4SXianjun Jiao    len_freq_offset = len(freq_offset)
1622dd0cc4SXianjun Jiao    display_side_info.freq_offset_store[:(256-len_freq_offset)] = display_side_info.freq_offset_store[len_freq_offset:]
1722dd0cc4SXianjun Jiao    display_side_info.freq_offset_store[(256-len_freq_offset):] = freq_offset
1822dd0cc4SXianjun Jiao
1922dd0cc4SXianjun Jiao    fig_freq_offset = plt.figure(0)
2022dd0cc4SXianjun Jiao    fig_freq_offset.clf()
2122dd0cc4SXianjun Jiao    plt.xlabel("packet idx")
2222dd0cc4SXianjun Jiao    plt.ylabel("Hz")
2322dd0cc4SXianjun Jiao    plt.title("freq offset")
2422dd0cc4SXianjun Jiao    plt.plot(display_side_info.freq_offset_store)
259fde3bffSthavinga    fig_freq_offset.canvas.flush_events()
2622dd0cc4SXianjun Jiao
2722dd0cc4SXianjun Jiao    good_row_idx = 0
2822dd0cc4SXianjun Jiao    if ( len(equalizer)==0 ):
2922dd0cc4SXianjun Jiao        csi_for_plot = csi.T
3022dd0cc4SXianjun Jiao    else:
3122dd0cc4SXianjun Jiao        equalizer[equalizer == 32767+32767*1j] = 0
3222dd0cc4SXianjun Jiao        num_row_equalizer, num_col_equalizer = equalizer.shape
3322dd0cc4SXianjun Jiao        equalizer_for_plot = np.zeros((num_row_equalizer, num_col_equalizer)) + 1j*np.zeros((num_row_equalizer, num_col_equalizer))
3422dd0cc4SXianjun Jiao
3522dd0cc4SXianjun Jiao        num_row_csi, num_col_csi = csi.shape
3622dd0cc4SXianjun Jiao        csi_for_plot = np.zeros((num_row_csi, num_col_csi)) + 1j*np.zeros((num_row_csi, num_col_csi))
3722dd0cc4SXianjun Jiao
3822dd0cc4SXianjun Jiao        # only take out the good equalizer result, when output > 2000, it is not good
3922dd0cc4SXianjun Jiao        for i in range(num_row_equalizer):
4022dd0cc4SXianjun Jiao            if (not (np.any(abs(equalizer[i,:].real)>2000) or np.any(abs(equalizer[i,:].imag)>2000)) ):
4122dd0cc4SXianjun Jiao                equalizer_for_plot[good_row_idx,:] = equalizer[i,:]
4222dd0cc4SXianjun Jiao                csi_for_plot[good_row_idx,:] = csi[i,:]
4322dd0cc4SXianjun Jiao                good_row_idx = good_row_idx + 1
4422dd0cc4SXianjun Jiao
4522dd0cc4SXianjun Jiao        csi_for_plot = csi_for_plot[0:good_row_idx,:]
4622dd0cc4SXianjun Jiao        equalizer_for_plot = equalizer_for_plot[0:good_row_idx,:]
4722dd0cc4SXianjun Jiao        csi_for_plot = csi_for_plot.T
4822dd0cc4SXianjun Jiao        equalizer_for_plot = equalizer_for_plot.T
4922dd0cc4SXianjun Jiao
5022dd0cc4SXianjun Jiao    if ( (len(equalizer)==0) or ((len(equalizer)>0)and(good_row_idx>0)) ):
5122dd0cc4SXianjun Jiao        fig_csi = plt.figure(1)
5222dd0cc4SXianjun Jiao        fig_csi.clf()
538cfbbc8eSXianjun Jiao        # if waterfall_flag == 0:
5422dd0cc4SXianjun Jiao        ax_abs_csi = fig_csi.add_subplot(211)
5522dd0cc4SXianjun Jiao        ax_abs_csi.set_xlabel("subcarrier idx")
5622dd0cc4SXianjun Jiao        ax_abs_csi.set_ylabel("abs")
5722dd0cc4SXianjun Jiao        ax_abs_csi.set_title("CSI")
5822dd0cc4SXianjun Jiao        plt.plot(np.abs(csi_for_plot))
5922dd0cc4SXianjun Jiao        ax_phase_csi = fig_csi.add_subplot(212)
6022dd0cc4SXianjun Jiao        ax_phase_csi.set_xlabel("subcarrier idx")
6122dd0cc4SXianjun Jiao        ax_phase_csi.set_ylabel("phase")
6222dd0cc4SXianjun Jiao        plt.plot(np.angle(csi_for_plot))
639fde3bffSthavinga        fig_csi.canvas.flush_events()
6422dd0cc4SXianjun Jiao
658cfbbc8eSXianjun Jiao        # else:
668cfbbc8eSXianjun Jiao
678cfbbc8eSXianjun Jiao        if waterfall_flag == 1:
688cfbbc8eSXianjun Jiao            # print(np.abs(display_side_info.csi_mat_for_waterfall))
698cfbbc8eSXianjun Jiao            display_side_info.csi_mat_for_waterfall = np.roll(display_side_info.csi_mat_for_waterfall, 1, axis=0)
708cfbbc8eSXianjun Jiao            # print(np.abs(display_side_info.csi_mat_for_waterfall))
718cfbbc8eSXianjun Jiao
728cfbbc8eSXianjun Jiao            display_side_info.csi_mat_for_waterfall[0,:] = csi[0,:]
738cfbbc8eSXianjun Jiao
748cfbbc8eSXianjun Jiao            fig_waterfall = plt.figure(3)
758cfbbc8eSXianjun Jiao            fig_waterfall.clf()
768cfbbc8eSXianjun Jiao
778cfbbc8eSXianjun Jiao            ax_abs_csi_waterfall = fig_waterfall.add_subplot(121)
788cfbbc8eSXianjun Jiao            ax_abs_csi_waterfall.set_title('CSI amplitude')
798cfbbc8eSXianjun Jiao            ax_abs_csi_waterfall.set_xlabel("subcarrier idx")
808cfbbc8eSXianjun Jiao            ax_abs_csi_waterfall.set_ylabel("time")
818cfbbc8eSXianjun Jiao            # ax_abs_csi_waterfall_shw = ax_abs_csi_waterfall.imshow(np.abs(display_side_info.csi_mat_for_waterfall), vmin=200, vmax=500)
828cfbbc8eSXianjun Jiao            ax_abs_csi_waterfall_shw = ax_abs_csi_waterfall.imshow(np.abs(display_side_info.csi_mat_for_waterfall))
838cfbbc8eSXianjun Jiao            plt.colorbar(ax_abs_csi_waterfall_shw)
848cfbbc8eSXianjun Jiao
858cfbbc8eSXianjun Jiao            ax_phase_csi_waterfall = fig_waterfall.add_subplot(122)
868cfbbc8eSXianjun Jiao            ax_phase_csi_waterfall.set_title('CSI phase')
878cfbbc8eSXianjun Jiao            ax_phase_csi_waterfall.set_xlabel("subcarrier idx")
888cfbbc8eSXianjun Jiao            ax_phase_csi_waterfall.set_ylabel("time")
898cfbbc8eSXianjun Jiao            # ax_phase_csi_waterfall_shw = ax_phase_csi_waterfall.imshow(np.angle(display_side_info.csi_mat_for_waterfall), vmin=-3.14, vmax=3.14)
908cfbbc8eSXianjun Jiao            ax_phase_csi_waterfall_shw = ax_phase_csi_waterfall.imshow(np.angle(display_side_info.csi_mat_for_waterfall))
918cfbbc8eSXianjun Jiao            plt.colorbar(ax_phase_csi_waterfall_shw)
928cfbbc8eSXianjun Jiao
938cfbbc8eSXianjun Jiao            fig_waterfall.canvas.flush_events()
948cfbbc8eSXianjun Jiao
9522dd0cc4SXianjun Jiao    if ( (len(equalizer)>0) and (good_row_idx>0) ):
9622dd0cc4SXianjun Jiao        fig_equalizer = plt.figure(2)
9722dd0cc4SXianjun Jiao        fig_equalizer.clf()
9822dd0cc4SXianjun Jiao        plt.xlabel("I")
9922dd0cc4SXianjun Jiao        plt.ylabel("Q")
10022dd0cc4SXianjun Jiao        plt.title("equalizer")
10122dd0cc4SXianjun Jiao        plt.scatter(equalizer_for_plot.real, equalizer_for_plot.imag)
1029fde3bffSthavinga        fig_freq_offset.canvas.flush_events()
10322dd0cc4SXianjun Jiao
10422dd0cc4SXianjun Jiaodef parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN):
10522dd0cc4SXianjun Jiao    # print(len(side_info), num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN)
10622dd0cc4SXianjun Jiao    CSI_LEN_HALF = round(CSI_LEN/2)
10722dd0cc4SXianjun Jiao    num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN
10822dd0cc4SXianjun Jiao    num_int16_per_trans = num_dma_symbol_per_trans*4 # 64bit per dma symbol
10922dd0cc4SXianjun Jiao    num_trans = round(len(side_info)/num_int16_per_trans)
11022dd0cc4SXianjun Jiao    # print(len(side_info), side_info.dtype, num_trans)
11122dd0cc4SXianjun Jiao    side_info = side_info.reshape([num_trans, num_int16_per_trans])
11222dd0cc4SXianjun Jiao
11322dd0cc4SXianjun Jiao    timestamp = side_info[:,0] + pow(2,16)*side_info[:,1] + pow(2,32)*side_info[:,2] + pow(2,48)*side_info[:,3]
11422dd0cc4SXianjun Jiao
115*e556af35SXianjun Jiao    freq_offset = (20e6*np.int16(side_info[:,4])/512)/(2*3.14159265358979323846)
11622dd0cc4SXianjun Jiao
11722dd0cc4SXianjun Jiao    csi = np.zeros((num_trans, CSI_LEN), dtype='int16')
11822dd0cc4SXianjun Jiao    csi = csi + csi*1j
11922dd0cc4SXianjun Jiao
12022dd0cc4SXianjun Jiao    equalizer = np.zeros((0,0), dtype='int16')
12122dd0cc4SXianjun Jiao    if num_eq>0:
12222dd0cc4SXianjun Jiao        equalizer = np.zeros((num_trans, num_eq*EQUALIZER_LEN), dtype='int16')
12322dd0cc4SXianjun Jiao        equalizer = equalizer + equalizer*1j
12422dd0cc4SXianjun Jiao
12522dd0cc4SXianjun Jiao    for i in range(num_trans):
126*e556af35SXianjun Jiao        tmp_vec_i = np.int16(side_info[i,8:(num_int16_per_trans-1):4])
127*e556af35SXianjun Jiao        tmp_vec_q = np.int16(side_info[i,9:(num_int16_per_trans-1):4])
12822dd0cc4SXianjun Jiao        tmp_vec = tmp_vec_i + tmp_vec_q*1j
12922dd0cc4SXianjun Jiao        # csi[i,:] = tmp_vec[0:CSI_LEN]
13022dd0cc4SXianjun Jiao        csi[i,:CSI_LEN_HALF] = tmp_vec[CSI_LEN_HALF:CSI_LEN]
13122dd0cc4SXianjun Jiao        csi[i,CSI_LEN_HALF:] = tmp_vec[0:CSI_LEN_HALF]
13222dd0cc4SXianjun Jiao        if num_eq>0:
13322dd0cc4SXianjun Jiao            equalizer[i,:] = tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)]
13422dd0cc4SXianjun Jiao        # print(i, len(tmp_vec), len(tmp_vec[0:CSI_LEN]), len(tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)]))
13522dd0cc4SXianjun Jiao
13622dd0cc4SXianjun Jiao    return timestamp, freq_offset, csi, equalizer
13722dd0cc4SXianjun Jiao
13822dd0cc4SXianjun JiaoUDP_IP = "192.168.10.1" #Local IP to listen
13922dd0cc4SXianjun JiaoUDP_PORT = 4000         #Local port to listen
14022dd0cc4SXianjun Jiao
14122dd0cc4SXianjun Jiaosock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
14222dd0cc4SXianjun Jiaosock.bind((UDP_IP, UDP_PORT))
143a4eb2001SXianjun Jiaosock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 464) # for low latency. 464 is the minimum udp length in our case (CSI only)
14422dd0cc4SXianjun Jiao
14522dd0cc4SXianjun Jiao# align with side_ch_control.v and all related user space, remote files
146f71252c5SXianjun JiaoMAX_NUM_DMA_SYMBOL = 8192
14722dd0cc4SXianjun JiaoCSI_LEN = 56 # length of single CSI
14822dd0cc4SXianjun JiaoEQUALIZER_LEN = (56-4) # for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48)
14922dd0cc4SXianjun JiaoHEADER_LEN = 2 # timestamp and frequency offset
15022dd0cc4SXianjun Jiao
15122dd0cc4SXianjun Jiaoif len(sys.argv)<2:
15222dd0cc4SXianjun Jiao    print("Assume num_eq = 8!")
15322dd0cc4SXianjun Jiao    num_eq = 8
15422dd0cc4SXianjun Jiaoelse:
15522dd0cc4SXianjun Jiao    num_eq = int(sys.argv[1])
15622dd0cc4SXianjun Jiao    print(num_eq)
15722dd0cc4SXianjun Jiao    # print(type(num_eq))
15822dd0cc4SXianjun Jiao
1598cfbbc8eSXianjun Jiaowaterfall_flag = 0
1608cfbbc8eSXianjun Jiaoif len(sys.argv)>2:
1618cfbbc8eSXianjun Jiao    print("Will plot CSI in waterfall!")
1628cfbbc8eSXianjun Jiao    display_side_info.csi_mat_for_waterfall = np.zeros((64, CSI_LEN)) + 1j*np.zeros((64, CSI_LEN))
1638cfbbc8eSXianjun Jiao    waterfall_flag = 1
1648cfbbc8eSXianjun Jiao
16522dd0cc4SXianjun Jiaonum_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN
16622dd0cc4SXianjun Jiaonum_byte_per_trans = 8*num_dma_symbol_per_trans
16722dd0cc4SXianjun Jiao
16822dd0cc4SXianjun Jiaoif os.path.exists("side_info.txt"):
16922dd0cc4SXianjun Jiao    os.remove("side_info.txt")
17022dd0cc4SXianjun Jiaoside_info_fd=open('side_info.txt','a')
17122dd0cc4SXianjun Jiao
1729fde3bffSthavingaplt.ion()
1739fde3bffSthavinga
17422dd0cc4SXianjun Jiaowhile True:
17522dd0cc4SXianjun Jiao    try:
176f71252c5SXianjun Jiao        data, addr = sock.recvfrom(MAX_NUM_DMA_SYMBOL*8) # buffer size
17722dd0cc4SXianjun Jiao        # print(addr)
1788cfbbc8eSXianjun Jiao        # print(len(data), num_byte_per_trans)
17922dd0cc4SXianjun Jiao        test_residual = len(data)%num_byte_per_trans
18022dd0cc4SXianjun Jiao        if (test_residual != 0):
18122dd0cc4SXianjun Jiao            print("Abnormal length")
18222dd0cc4SXianjun Jiao
183*e556af35SXianjun Jiao        side_info = np.frombuffer(data, dtype='uint16')
18422dd0cc4SXianjun Jiao        np.savetxt(side_info_fd, side_info)
18522dd0cc4SXianjun Jiao
18622dd0cc4SXianjun Jiao        timestamp, freq_offset, csi, equalizer = parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN)
1878cfbbc8eSXianjun Jiao        # print(timestamp)
18822dd0cc4SXianjun Jiao        # print(freq_offset)
18922dd0cc4SXianjun Jiao        # print(csi[0,0:10])
19022dd0cc4SXianjun Jiao        # print(equalizer[0,0:10])
1918cfbbc8eSXianjun Jiao        display_side_info(freq_offset, csi, equalizer, waterfall_flag, CSI_LEN, EQUALIZER_LEN)
19222dd0cc4SXianjun Jiao
19322dd0cc4SXianjun Jiao    except KeyboardInterrupt:
19422dd0cc4SXianjun Jiao        print('User quit')
19522dd0cc4SXianjun Jiao        break
19622dd0cc4SXianjun Jiao
19722dd0cc4SXianjun Jiaoprint('close()')
19822dd0cc4SXianjun Jiaoside_info_fd.close()
19922dd0cc4SXianjun Jiaosock.close()
200