mirror of
https://github.com/open-sdr/openwifi.git
synced 2025-04-20 00:20:48 +00:00
Add phase_offset check and override scripts
This commit is contained in:
parent
aa21e8cb40
commit
0c00ce9575
31
user_space/receiver_phase_offset_override.sh
Executable file
31
user_space/receiver_phase_offset_override.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Author: Xianjun Jiao
|
||||
# SPDX-FileCopyrightText: 2023 UGent
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# To avoid override, just run without any arguments
|
||||
# To override, example: ./receiver_phase_offset_override.sh -8
|
||||
|
||||
set -x
|
||||
|
||||
if [[ -n $1 ]]; then
|
||||
phase_offset=$1
|
||||
else
|
||||
echo "Disable phase offset override by setting bit31 to 0"
|
||||
reg_val=$((0<<31))
|
||||
printf "0x%X\n" $reg_val
|
||||
echo "./sdrctl dev sdr0 set reg rx 19 $reg_val"
|
||||
./sdrctl dev sdr0 set reg rx 19 $reg_val
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo $phase_offset
|
||||
printf "0x%X\n" $phase_offset
|
||||
|
||||
reg_val=$(( ($phase_offset & 65535) | (1 << 31) ))
|
||||
printf "0x%X\n" $reg_val
|
||||
|
||||
./sdrctl dev sdr0 set reg rx 19 $reg_val
|
||||
|
||||
set +x
|
223
user_space/side_ch_ctl_src/iq_capture_freq_offset.py
Executable file
223
user_space/side_ch_ctl_src/iq_capture_freq_offset.py
Executable file
@ -0,0 +1,223 @@
|
||||
#
|
||||
# openwifi iq capture and frequency offset calculation program
|
||||
# Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
#
|
||||
# ATTENTION! If you can see the packet matched by addr1&addr2, most probably fpga and ltf FO estimation will be the same
|
||||
# For those cases where fpga FO estimation is wrong, you won't see them.
|
||||
# So, the value of this script is to show the correct/same FO estimation for overriding it into the receiver for performance check
|
||||
# By script receiver_phase_offset_override.sh
|
||||
#
|
||||
# Need these commands on board, after setup communication and know MAC addr of both sides
|
||||
# insmod side_ch.ko iq_len_init=1000
|
||||
# ./side_ch_ctl wh11d997
|
||||
# ./side_ch_ctl wh7h635c982f
|
||||
# ./side_ch_ctl wh6h44332236
|
||||
# ./side_ch_ctl wh1h6001
|
||||
# ./side_ch_ctl wh8d25
|
||||
# ./side_ch_ctl g0
|
||||
|
||||
# On host PC
|
||||
# python3 iq_capture_freq_offset.py 1000
|
||||
# It will print phase_offset value: FPGA VS python
|
||||
# You can override this correct vlaue to receiver via receiver_phase_offset_override.sh on board.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
metric_plot_enable = False
|
||||
|
||||
freq_offset_fpga_store = np.zeros(64,)
|
||||
freq_offset_ltf_store = np.zeros(64,)
|
||||
|
||||
def phase_offset_to_freq_offset(phase_offset):
|
||||
freq_offset = (20.0e6*phase_offset/512.0)/(2.0*3.14159265358979323846)
|
||||
return freq_offset
|
||||
|
||||
def plot_phase_offset(phase_offset_fpga, phase_offset_ltf):
|
||||
freq_offset_fpga = phase_offset_to_freq_offset(phase_offset_fpga)
|
||||
freq_offset_ltf = phase_offset_to_freq_offset(phase_offset_ltf)
|
||||
|
||||
for i in range(len(phase_offset_fpga)):
|
||||
freq_offset_fpga_store[:(64-1)] = freq_offset_fpga_store[1:]
|
||||
freq_offset_fpga_store[(64-1):] = freq_offset_fpga[i]
|
||||
freq_offset_ltf_store[:(64-1)] = freq_offset_ltf_store[1:]
|
||||
freq_offset_ltf_store[(64-1):] = freq_offset_ltf[i]
|
||||
|
||||
fig_fo_log = plt.figure(1)
|
||||
fig_fo_log.clf()
|
||||
plt.plot(freq_offset_fpga_store, 'b.-', label='FPGA')
|
||||
plt.plot(freq_offset_ltf_store, 'r.-', label='python LTF')
|
||||
plt.legend(loc='upper right')
|
||||
fig_fo_log.canvas.flush_events()
|
||||
|
||||
def ltf_freq_offset_estimation(iq_capture):
|
||||
num_trans = np.shape(iq_capture)[0]
|
||||
phase_offset_ltf = np.zeros(num_trans,)
|
||||
|
||||
if metric_plot_enable:
|
||||
fig_metric = plt.figure(0)
|
||||
fig_metric.clf()
|
||||
|
||||
for i in range(num_trans):
|
||||
iq = iq_capture[i, 0:-65]
|
||||
iq_delay = iq_capture[i, 64:-1]
|
||||
# iq_delay_conj_prod = np.multiply(iq_delay, np.conj(iq))
|
||||
iq_delay_conj_prod = np.multiply(np.conj(iq_delay), iq)
|
||||
iq_delay_conj_prod_mv_sum = np.convolve(iq_delay_conj_prod, np.ones(32,), 'valid')
|
||||
iq_delay_conj_prod_mv_sum_power = np.real(np.multiply(np.conj(iq_delay_conj_prod_mv_sum),iq_delay_conj_prod_mv_sum))
|
||||
iq_delay_conj_prod_power = np.real(np.multiply(np.conj(iq_delay_conj_prod),iq_delay_conj_prod))
|
||||
iq_delay_conj_prod_power_mv_sum = np.convolve(iq_delay_conj_prod_power, np.ones(32,), 'valid')
|
||||
metric_normalized = iq_delay_conj_prod_mv_sum_power/iq_delay_conj_prod_power_mv_sum
|
||||
|
||||
max_idx_metric_normalized = np.argmax(metric_normalized)
|
||||
phase_offset_ltf[i] = np.angle(iq_delay_conj_prod_mv_sum[max_idx_metric_normalized])*8.0
|
||||
|
||||
if metric_plot_enable:
|
||||
plt.plot(metric_normalized)
|
||||
|
||||
iq_power = np.real(np.multiply(np.conj(iq),iq))
|
||||
iq_total_power = np.sum(iq_power)
|
||||
iq_power_mv_sum = np.convolve(iq_power, np.ones(32,), 'valid')
|
||||
iq_power_normalized = 500.0*iq_power_mv_sum/iq_total_power
|
||||
plt.plot(iq_power_normalized)
|
||||
|
||||
if metric_plot_enable:
|
||||
fig_metric.canvas.flush_events()
|
||||
|
||||
return phase_offset_ltf
|
||||
|
||||
# fig_iq_capture = plt.figure(0)
|
||||
# fig_iq_capture.clf()
|
||||
# plt.xlabel("sample")
|
||||
# plt.ylabel("I/Q")
|
||||
# plt.title("I (blue) and Q (red) capture")
|
||||
# plt.plot(iq_capture.real, 'b')
|
||||
# plt.plot(iq_capture.imag, 'r')
|
||||
# plt.ylim(-32767, 32767)
|
||||
# fig_iq_capture.canvas.flush_events()
|
||||
|
||||
# agc_gain_lock = np.copy(agc_gain)
|
||||
# agc_gain_lock[agc_gain>127] = 80 # agc lock
|
||||
# agc_gain_lock[agc_gain<=127] = 0 # agc not lock
|
||||
|
||||
# agc_gain_value = np.copy(agc_gain)
|
||||
# agc_gain_value[agc_gain>127] = agc_gain[agc_gain>127] - 128
|
||||
|
||||
# fig_agc_gain = plt.figure(1)
|
||||
# fig_agc_gain.clf()
|
||||
# plt.xlabel("sample")
|
||||
# plt.ylabel("gain/lock")
|
||||
# plt.title("AGC gain (blue) and lock status (red)")
|
||||
# plt.plot(agc_gain_value, 'b')
|
||||
# plt.plot(agc_gain_lock, 'r')
|
||||
# plt.ylim(0, 82)
|
||||
# fig_agc_gain.canvas.flush_events()
|
||||
|
||||
# fig_rssi_half_db = plt.figure(2)
|
||||
# fig_rssi_half_db.clf()
|
||||
# plt.xlabel("sample")
|
||||
# plt.ylabel("dB")
|
||||
# plt.title("RSSI half dB (uncalibrated)")
|
||||
# plt.plot(rssi_half_db)
|
||||
# plt.ylim(100, 270)
|
||||
# fig_rssi_half_db.canvas.flush_events()
|
||||
|
||||
def parse_iq(iq, iq_len):
|
||||
# print(len(iq), iq_len)
|
||||
num_dma_symbol_per_trans = 1 + iq_len
|
||||
num_int16_per_trans = num_dma_symbol_per_trans*4 # 64bit per dma symbol
|
||||
num_trans = round(len(iq)/num_int16_per_trans)
|
||||
# print(len(iq), iq.dtype, num_trans)
|
||||
iq = iq.reshape([num_trans, num_int16_per_trans])
|
||||
phase_offset_fpga = np.zeros(num_trans, dtype=np.int16)
|
||||
start_idx_demod_is_ongoing = np.zeros(num_trans, dtype=np.uint16)
|
||||
|
||||
timestamp = iq[:,0] + pow(2,16)*iq[:,1] + pow(2,32)*iq[:,2] + pow(2,48)*iq[:,3]
|
||||
iq_capture = np.int16(iq[:,4::4]) + np.int16(iq[:,5::4])*1j
|
||||
phase_offset_fpga_high4_mat = iq[:,7::4]
|
||||
demod_is_ongoing_mat = np.bitwise_and(phase_offset_fpga_high4_mat, np.uint16(0x8000))
|
||||
phase_offset_fpga_low8_mat = iq[:,6::4]
|
||||
for i in range(num_trans):
|
||||
# print(demod_is_ongoing_mat[i,:])
|
||||
start_idx_demod_is_ongoing_tmp = np.nonzero(demod_is_ongoing_mat[i,:])
|
||||
# print(start_idx_demod_is_ongoing_tmp[0][0])
|
||||
start_idx_demod_is_ongoing[i] = start_idx_demod_is_ongoing_tmp[0][0]
|
||||
# print(type(start_idx_demod_is_ongoing_tmp[0][0]))
|
||||
phase_offset_fpga_low8 = np.right_shift(np.bitwise_and(phase_offset_fpga_low8_mat[i,start_idx_demod_is_ongoing[i]], np.uint16(0xFF00)), 8)
|
||||
phase_offset_fpga_high4 = np.right_shift(np.bitwise_and(phase_offset_fpga_high4_mat[i,start_idx_demod_is_ongoing[i]], np.uint16(0x7800)), 3)
|
||||
|
||||
sign_bit = np.bitwise_and(phase_offset_fpga_high4, np.uint16(0x800))
|
||||
sign_bit12 = np.left_shift(sign_bit, 1)
|
||||
sign_bit13 = np.left_shift(sign_bit, 2)
|
||||
sign_bit14 = np.left_shift(sign_bit, 3)
|
||||
sign_bit15 = np.left_shift(sign_bit, 4)
|
||||
phase_offset_fpga_tmp = phase_offset_fpga_high4 + phase_offset_fpga_low8 + sign_bit12 + sign_bit13 + sign_bit14 + sign_bit15
|
||||
phase_offset_fpga[i] = np.int16(phase_offset_fpga_tmp)
|
||||
|
||||
# iq_capture = iq_capture.reshape([num_trans*iq_len,])
|
||||
|
||||
return timestamp, iq_capture, phase_offset_fpga, start_idx_demod_is_ongoing
|
||||
|
||||
UDP_IP = "192.168.10.1" #Local IP to listen
|
||||
UDP_PORT = 4000 #Local port to listen
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
|
||||
sock.bind((UDP_IP, UDP_PORT))
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 464) # for low latency. 464 is the minimum udp length in our case (CSI only)
|
||||
|
||||
# align with side_ch_control.v and all related user space, remote files
|
||||
MAX_NUM_DMA_SYMBOL = 8192
|
||||
|
||||
if len(sys.argv)<2:
|
||||
print("Assume iq_len = 8187! (Max UDP 65507 bytes; (65507/8)-1 = 8187)")
|
||||
iq_len = 8187
|
||||
else:
|
||||
iq_len = int(sys.argv[1])
|
||||
print(iq_len)
|
||||
# print(type(num_eq))
|
||||
|
||||
if iq_len>8187:
|
||||
iq_len = 8187
|
||||
print('Limit iq_len to 8187! (Max UDP 65507 bytes; (65507/8)-1 = 8187)')
|
||||
|
||||
num_dma_symbol_per_trans = 1 + iq_len
|
||||
num_byte_per_trans = 8*num_dma_symbol_per_trans
|
||||
|
||||
# if os.path.exists("iq.txt"):
|
||||
# os.remove("iq.txt")
|
||||
# iq_fd=open('iq.txt','a')
|
||||
|
||||
plt.ion()
|
||||
|
||||
while True:
|
||||
try:
|
||||
data, addr = sock.recvfrom(MAX_NUM_DMA_SYMBOL*8) # buffer size
|
||||
# print(addr)
|
||||
test_residual = len(data)%num_byte_per_trans
|
||||
# print(len(data)/8, num_dma_symbol_per_trans, test_residual)
|
||||
if (test_residual != 0):
|
||||
print("Abnormal length")
|
||||
|
||||
iq = np.frombuffer(data, dtype='uint16')
|
||||
# np.savetxt(iq_fd, iq)
|
||||
|
||||
timestamp, iq_capture, phase_offset_fpga, start_idx_demod_is_ongoing = parse_iq(iq, iq_len)
|
||||
# print(timestamp)
|
||||
phase_offset_ltf = ltf_freq_offset_estimation(iq_capture)
|
||||
|
||||
plot_phase_offset(phase_offset_fpga, phase_offset_ltf)
|
||||
|
||||
# freq_offset_fpga = phase_offset_to_freq_offset(phase_offset_fpga)
|
||||
# print(start_idx_demod_is_ongoing, freq_offset_fpga)
|
||||
print(phase_offset_fpga, phase_offset_ltf)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('User quit')
|
||||
break
|
||||
|
||||
print('close()')
|
||||
# iq_fd.close()
|
||||
sock.close()
|
Loading…
x
Reference in New Issue
Block a user