接下来的内容比较简单,讲一下几个用来仿真的程序。用这些程序在调试过程中,可以脱离kerberossdr硬件,会方便好多。
分别是sim.sh,_receiver/C下的sim.c以及_dataFiles下的DOA_sim_gen.py和sim_gen.py
先来看看sim.sh
#!/bin/bash
echo "Starting Hydra offline test"
rm _receiver/C/gate_control_fifo
mkfifo _receiver/C/gate_control_fifo
rm _receiver/C/sync_control_fifo
mkfifo _receiver/C/sync_control_fifo
#python3 _GUI/hydra_main_window.py &
./_receiver/C/sim 2>log_err_sim 1| ./_receiver/C/sync 2>log_err_sync 1| ./_receiver/C/gate 2>log_err_gate 1| python3 _GUI/hydra_main_window.py
它与run.sh很像,主要的区别是启动的时候把./_receiver/C/rtl_daq的部分换成了./_receiver/C/sim,由仿真程序输出数据给后面的程序,而不是由rtlsdr硬件给出,另外,每个程序它都记录了log。
接下来看看sim.c
/* KerberosSDR DAQ
*
* Copyright (C) 2018-2019 Carl Laufer, Tamás Pető
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#define CH_NO 4 // Number of channels
#define BUFFER_SIZE 1024*512
int main()
{
fprintf(stderr, "Hydra test started \n");
int success = 1;
char filename[32];
size_t read_len;
FILE **fds; // File descriptor array
fds = malloc(CH_NO * sizeof(*fds));
uint8_t **buffers;
buffers = malloc(CH_NO *sizeof(*buffers));
//初始化buffers指针,每个接收机通道都会有一个这个指针所以大小要乘以CH_NO
for (int m=0; m
接下来讲_dataFiles下的两个python程序,它们各自都可以单独用来生成仿真数据,先看sim_gen.py
# -*- coding: utf-8 -*-
import numpy as np
from struct import pack
import matplotlib.pyplot as plt
fname_template = "sim" #文件名开头
ch_no = 4 #通道总数
delays = [0, 10, 20, 30] #几个通道的延迟大小
phase_shifts=[0, 45, 0,0] #几个通道的相位差
blocks = 100 #有多少个标准长度
block_size = 1024*512 #标准长度大小注意这里和使用硬件时的1024*256不同,但是与sim.c相符
fds= [] # File descriptors
for m in range(ch_no):
fname=fname_template+str(m)+".iq" #生成文件名,每个通道一个文件
fds.append( open(fname, 'w+b', buffering=0))
#打开文件,存入fds数组,数组元素是每个通道的iq数据的文件
print("All files opened")
signal = np.zeros((block_size), dtype=np.uint8)
#这是用来存储当前要发送的通道的数据的一维数组
raw_sig_nch = np.zeros((ch_no, block_size), dtype=np.uint8)
#这是用来存储生成的4个通道数据的二维数组
for b in range(blocks):
print("Writing block: %d"%b)
raw_sig = np.random.normal(0,1,(block_size//2+max(delays)))+1j*np.random.normal(0,1,(block_size//2+max(delays)))
#生成一组原始数据,它们在-1~1中间变化,均值为0,标准差为1
#由于它在后面作为复数的模,复数表示的话长度减半,所以长度是block_size//2
#但是这组数据要给其它几个通道生成延时后的数据的,所以要足够长,这样人为延迟后数据还够用
#就要在原来的长度上加上最大的延迟
#raw_sig = np.exp(1j*2*np.pi*(100/(block_size//2+max(delays))) * np.arange((block_size//2+max(delays))))
#有了基础数据后就可以对各通道逐一生成数据了
for m in range(ch_no):
raw_sig_m = raw_sig*np.exp(1j*np.deg2rad(phase_shifts[m]))
#每个通道使用的模都来在raw_sig,但是各通道都乘以了一个e^(j*phi)
#也就是说相对于基础数据的每个采样点,后面的3个通道的每个相应采样点都相对移动了一个
#固定的相位差,每个通道的相位差都是各自的phase_shifts[m]只是同一通道的这个相位差不变
raw_sig_m += (1+1j)
raw_sig_m *= (255/2)
#这里做的是把-1~1映射为了0~255,同样对虚部也是一样的操作
raw_sig_nch[m,0::2] = raw_sig_m.real[delays[m]:delays[m]+block_size//2]
raw_sig_nch[m,1::2] = raw_sig_m.imag[delays[m]:delays[m]+block_size//2]
#接下来要对raw_sig_m做延迟处理,方法是获得对应通道的延迟delays[m]
#然后在处理完的基础数据的数组上直接跳过delays[m]个采样点,就算做好延迟了
#为了存储和发送,这里把raw_sig_m的实部和虚部分开了
#本来应该从0开始到block_size//2(因为一半是i另一半是q),现在延迟delays[m]个
#就是从raw_sig_m的delays[m]开始,到delays[m]+block_size//2结束
#生成完了以后要存入raw_sig_nch二维数组,横坐标m是通道号
#纵坐标,0开始是实部,1开始是虚部,然后一列隔一列存所以步进是2
signal[0::2] = raw_sig_m.real[delays[m]:delays[m]+block_size//2]
signal[1::2] = raw_sig_m.imag[delays[m]:delays[m]+block_size//2]
#signal也是类似的,它相当于是raw_sig_nch的其中一行,也就是当前处理的这个通道的iq数据
byte_array= pack('B'*block_size, *signal)
#最后往文件里写的是signal就行了,因为文件里只需要一维的数据,把单个通道的存入一个文件
fds[m].write(byte_array)
#注意这样每个通道对应一个iq文件,里面只有这个通道的iq数据
for f in fds:
f.close()
#最后把4个通道的文件句柄关闭掉
print("Al files are closed")
"""
iq_samples = np.zeros((ch_no, block_size//2), dtype=complex)
for m in range(ch_no):
real = raw_sig_nch[m, 0 ::2]
imag = raw_sig_nch[m, 1::2]
iq_samples[m,:].real, iq_samples[m,:].imag = real, imag
iq_samples /= (255 / 2)
iq_samples -= (1 + 1j)
pw=2**15
offset = 50000
delay = 0
phasors = (iq_samples[0, offset: pw+offset] * iq_samples[1, offset+delay: pw+offset+delay].conj())
phasors /= np.abs(phasors)
#K = 1000
#plt.scatter(phasors.real, phasors.imag)
xw = np.abs(np.fft.fft(iq_samples[1,:]))
#plt.plot(iq_samples[3,:].imag)
plt.plot(xw)
"""
上面这个生成的iq文件,应该只是测延迟和相位校准算法的,不是测doa算法的,下面这个才是。
接下来看DOA_sim_gen.py
# -*- coding: utf-8 -*-
import os
import sys
import numpy as np
from struct import pack
# Import the pyArgus module
root_path = os.path.pardir#getcwd()
pyargus_path = os.path.join(os.path.join(root_path, "pyArgus"), "pyArgus")
sys.path.insert(0, pyargus_path)
import directionEstimation_v1p15 as de
#要生成doa的数据要引用pyargus库的de包
####################################
# PARAMETERS
####################################
fname_template = "sim"
ch_no = 4
delays = [0, 0, 0, 0]
phase_shifts=[0, 0, 0,0]
blocks = 100
block_size = 1024*512
pn = 10**-3 # Noise power #噪声功率
fds= [] # File descriptors
# Antenna system parameters
M = 4 # Number of antenna elemenets
UCA_radius = 0.5 # [wavelength]
ULA_spacing = 0.5 # [wavelength]
DOAs = np.linspace(0,360, blocks)
antenna_array_type = "UCA"
if antenna_array_type == "UCA":
x = UCA_radius * np.cos(2*np.pi/M * np.arange(M))
y = UCA_radius * np.sin(-2*np.pi/M * np.arange(M))
array_resp_vectors = de.gen_scanning_vectors(M, x, y, DOAs)
#生成扫描向量
elif antenna_array_type == "ULA":
x = np.arange(M) * ULA_spacing
y = np.zeros(M)
array_resp_vectors = de.gen_scanning_vectors(M, x, y, DOAs)
else:
print("[ ERROR ] Unidentified antenna array alignment")
####################################
# Simulation
####################################
# Opening simulation files
for m in range(ch_no):
fname=fname_template+str(m)+".iq"
fds.append( open(fname, 'w+b', buffering=0))
print("[ INFO ] All files opened")
signal = np.zeros((block_size), dtype=np.uint8)
raw_sig_nch = np.zeros((ch_no, block_size), dtype=np.uint8)
for b in range(blocks):
print("[ INFO ] Writing block: %d"%b)
raw_sig = np.random.normal(0,1,(block_size//2+max(delays)))+1j*np.random.normal(0,1,(block_size//2+max(delays)))
#生成原始信号,和上一个程序类似
raw_sig /= np.max(np.abs(raw_sig))
raw_sig *= np.max(np.abs(raw_sig))*0.9
#把生成的信号做归一化,再取最大值的90%
#raw_sig = np.exp(1j*2*np.pi*(100/(block_size//2+max(delays))) * np.arange((block_size//2+max(delays))))
for m in range(ch_no):
noise = np.random.normal(0,pn,(block_size//2+max(delays)))+1j*np.random.normal(0,pn,(block_size//2+max(delays)))
#生成噪声,是另一段随机数据,但是标准差是噪声功率pn,后面没用到
# Use this to generate ULA simulation
#raw_sig_m = raw_sig*np.exp(1j*2*np.pi*0.5*np.cos(np.deg2rad(0))*np.arange(4))[m]
# Modifly the phase of received signal according to the realtive position of the element #根据阵元的相对位置来改变接收到的信号的相位
raw_sig_m = raw_sig*array_resp_vectors[m,b]
#用扫描向量来改变相位
raw_sig_m += (1+1j)
#raw_sig_m *= (255/2)
raw_sig_m *= (255/2)
#数据范围映射
raw_sig_nch[m,0::2] = raw_sig_m.real[delays[m]:delays[m]+block_size//2]
raw_sig_nch[m,1::2] = raw_sig_m.imag[delays[m]:delays[m]+block_size//2]
#延迟生成的方法和上一个程序一样
signal[0::2] = raw_sig_m.real[delays[m]:delays[m]+block_size//2]
signal[1::2] = raw_sig_m.imag[delays[m]:delays[m]+block_size//2]
byte_array= pack('B'*block_size, *signal)
fds[m].write(byte_array)
#最终文件生成的方法也和上一个程序一样
for f in fds:
f.close()
print("[ DONE ] Al files are closed")