KerberosSDR 코드 노트 (6) 시뮬레이션 프로그램

다음 내용은 비교적 간단합니다. 시뮬레이션에 사용되는 몇 가지 프로그램에 대해 이야기합니다. 이러한 프로그램은 디버깅 프로세스 중에 kerberossdr 하드웨어에서 분리 될 수 있으며, 이는 훨씬 더 편리합니다.

_receiver / C의 sim.sh, 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 대신 후속 프로그램에 데이터를 출력한다는 것입니다. 하드웨어가 제공되며 각 프로그램에 대한 로그를 기록합니다.

다음 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 <https://www.gnu.org/licenses/>.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#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<CH_NO; m++)
    {
        buffers[m] = malloc(BUFFER_SIZE*sizeof(**buffers));
        //每个通道的buffers都要创建一个内存空间,空间大小取决于存多少iq数据,由BUFFER_SIZE决定
    }
        
    for(int m=0; m< CH_NO; m++)
    {   //然后打开_dataFiles下的“sim通道号.iq”文件,这些文件是后面讲的python程序生成的
        sprintf(filename, "_dataFiles/sim%d.iq", m);
        if((fds[m] = fopen(filename, "rb")) == NULL) {
            fprintf(stderr, "Could not open file \n");		
            success=0;
        }
    }
    if(success != 1)
        return -1;
    
    fprintf(stderr,"All files opened\n");
        
    
    for(int b=0; b<500; b++)
    { //分500次来读取
        fprintf(stderr, "Transfering block:%d ",b);	
        usleep(1000000);
        for(int m=0; m< CH_NO; m++)
        {
            read_len = fread(buffers[m], sizeof(**buffers),BUFFER_SIZE, fds[m]);
            //从打开的第m个文件里读取第m通道的数据,读到buffers[m]里,读取长度是BUFFER_SIZE
            if(read_len != BUFFER_SIZE) //如果一次读到的长度不是BUFFER_SIZE代表出错了
            {
                fprintf(stderr, " [ FAILED ]\n");	
                fprintf(stderr, "ERROR: Read bytes: %zu\n",read_len);	
                success = 0;
                break;
            }
            fwrite(buffers[m], sizeof(**buffers), BUFFER_SIZE, stdout);
            //读完了就往stdout里写,发给sync程序
            fflush(stdout);
        }
        if(success)
            fprintf(stderr, " [ DONE ]\n");
        else
        {
            
            break;
        }
    }
        
    
    
    /* Closing files */
    for(int m=0; m< CH_NO; m++)
    {            
        if(fclose(fds[m])==EOF) //关闭时要把文件句斌释放
            fprintf(stderr," File close failed closed\n");
    }
    fprintf(stderr,"All files closed\n");
        
    /* Freeing up sample buffers */
    for (int m=0; m<CH_NO; m++)
    {
        free(buffers[m]); //关闭时还要释放缓存的内存空间
    }
    fprintf(stderr, "Hydra test finished\n");	
    return 0;
}

다음으로 _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")

 

추천

출처blog.csdn.net/shukebeta008/article/details/104094489