RCS Computation Toolkit This repository provides C++ and Python tools for computing radar cross section (RCS) from surface currents or analytical models
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

386 lines
10 KiB

import pandas as pd
import numpy as np
from tqdm import tqdm
import fnmatch
import os
import matplotlib.pyplot as plt
def VEC_MAG(v1):
return np.sqrt(v1[0]**2 + v1[1]**2 + v1[2]**2)
###############################
### USER DEFINED PARAMETERS ###
###############################
SURFACE_TRI_MESH = "SPHERE_BW"
FILENAME = "Currents_SPHERE_BW_"
### Time
steps = 24
local_dt = 5.66631973546866118951e-13
dt = local_dt * steps
T_END = 8e-9
Fs = 1.0/dt
### Set Frequency Range
FREQ_MIN = 3e9
FREQ_MAX = 3e9
df = 0.05e9
frequency_samples = np.arange(FREQ_MIN,FREQ_MAX+df,df)
### N2F Parameters
SCATTERING_MODE = 0 # 0 for PEC Scattering , 1 for FEBI scattering
OUTPUT_RCS_FILENAME = "RCS"
THETA=0
PHI=0
### Incident Field Parameters
Pulse_Type = 'TimeHarmonic'
if (Pulse_Type == 'Gaussian'):
MOD_FREQ = 3e9
T_DELAY = 0.6e-9
TAU = 0.25e-9
elif (Pulse_Type == 'TimeHarmonic'):
MOD_FREQ = 3e9
##############################################################
#### SECTION 1 ####
#### Read .tri file to get node and triangle information ####
#### Calculate Normal of triangles ####
#### Read Efields csv files for each time step ####
#### Compute curJ and curM on the nodes at eaach triangles####
#### SAve the curJ and curM into files ####
##############################################################
# Read Number of triangles
pfile = open(SURFACE_TRI_MESH+".tri",'r')
lines = pfile.readlines()
Num_Nodes = int(lines[1])
Num_tri = int(lines[Num_Nodes+2])
Nodes_Section = lines[2:Num_Nodes+2]
Tri_Section = lines[Num_Nodes+3::]
print('Number of Triangles = ',Num_tri)
print('Number of Nodes = ',Num_Nodes)
nfiles = len(fnmatch.filter(os.listdir("./"), '*.curJ'))
print('File Count:', nfiles)
# Find number of points
filename = FILENAME+"00000_BC.curJ"
df = pd.read_csv(filename,',')
num_pts = len(df)/90
# curJ = n x H
# Time, Triangle , node , xyz component
curJ = np.zeros([nfiles,Num_tri,3,3])
# curM = E x n
# Time, Triangle , node , xyz component
curM = np.zeros([nfiles,Num_tri,3,3])
### Read curJ and curM
print( " Read curJ and curM \n" )
for i in tqdm(range(nfiles)):
index = "%05d" % int(steps*i)
pfile = open(FILENAME+index+"_BC.curJ",'r')
lines = pfile.readlines()
counter = 0
for t in range(Num_tri):
for n in range(3):
curJ[i,t,n,0] = float(lines[counter])
counter = counter + 1
curJ[i,t,n,1] = float(lines[counter])
counter = counter + 1
curJ[i,t,n,2] = float(lines[counter])
counter = counter + 1
counter = counter + 1
pfile.close()
pfile = open(FILENAME+index+"_BC.curM",'r')
lines = pfile.readlines()
counter = 0
for t in range(Num_tri):
for n in range(3):
curM[i,t,n,0] = float(lines[counter])
counter = counter + 1
curM[i,t,n,1] = float(lines[counter])
counter = counter + 1
curM[i,t,n,2] = float(lines[counter])
counter = counter + 1
counter = counter + 1
pfile.close()
##############################################################
#### SECTION 2 ####
#### Regenerate Incident Pulse and perform FFT ####
#### Normalization Values to compute RCS ####
##############################################################
def nextpow2(L):
ind = 1
while(ind < L):
ind *= 2
return ind
NFFT = nextpow2(nfiles*8)
zero_pad_dim = NFFT-nfiles
time = np.hstack( [ np.linspace(0,T_END,nfiles) , np.linspace(T_END+dt,T_END+dt*(zero_pad_dim+1),zero_pad_dim) ])
TRUNC = int(NFFT/2-1)
f = np.fft.fftfreq(NFFT, d=dt)
print(f)
Normalization = np.zeros(NFFT,dtype=complex)
if (Pulse_Type == 'Gaussian'):
EXPONENT = ( time - T_DELAY )**2 / TAU**2
ENVELOPE = np.exp(-EXPONENT)
MODULATION = np.cos( 2 * np.pi * MOD_FREQ * ( time - T_DELAY ) )
TD = ENVELOPE * MODULATION
index_T = np.argmin(abs(time-T_DELAY))
while (ENVELOPE[index_T] > 0.01*max(ENVELOPE)):
index_T = index_T + 1
print(index_T)
print(time[index_T])
FD = np.fft.fft(TD,NFFT) / nfiles
FD_max = max(FD[0:TRUNC])
FD_cutoff = 0.1 * FD_max
for i in range(NFFT):
if ( abs(FD[i]) > FD_cutoff):
Normalization[i] = 0.5 / abs(FD[i])
elif (Pulse_Type == 'TimeHarmonic'):
MODULATION = np.cos( 2 * np.pi * MOD_FREQ * (time) )
TD = MODULATION
FD = np.fft.fft(TD,NFFT) / NFFT
index = np.argmin( abs(MOD_FREQ - f) )
Normalization[index] = 0.5 / abs(FD[i])
print(len(FD))
plt.figure()
plt.plot(time*1e9,TD)
plt.grid()
plt.xlabel("Time (ns)")
plt.ylabel("Pulse")
plt.xlim([0,6])
plt.savefig("TimePulse.png")
plt.figure()
plt.plot(f[0:TRUNC] /1e9,abs(FD[0:TRUNC]))
plt.grid()
plt.xlabel("FREQ (GHZ)")
plt.ylabel("Frequency Domain Pulse")
plt.xlim([0,6])
plt.savefig("FreqPulse.png")
plt.figure()
plt.plot(f[0:TRUNC] /1e9,abs(Normalization[0:TRUNC]*FD[0:TRUNC]))
plt.grid()
plt.xlabel("FREQ (GHZ)")
plt.ylabel("Normalized Frequency Domain Pulse")
plt.xlim([0,6])
plt.savefig("FreqPulse_Norm.png")
plt.figure()
plt.plot(f[0:TRUNC] /1e9,abs(Normalization[0:TRUNC]))
plt.grid()
plt.xlabel("FREQ (GHZ)")
plt.ylabel("Normalized Frequency Domain Pulse")
plt.xlim([0,6])
plt.savefig("F_Norm.png")
##############################################################
#### SECTION 3 ####
#### Perform FFT on curJ and curM ####
#### Single out the frequency of interest ####
#### (Positive and Negative components) ####
#### Write filtered curJ and curM to file ####
##############################################################
#%%
FD_curJ = np.zeros([NFFT,Num_tri,3,3]).astype(np.complex_)
FD_curM = np.zeros([NFFT,Num_tri,3,3]).astype(np.complex_)
# Perform FFT on time domain signal
# Take the positive part of frequency specturm
print("\n\n=======================================")
print('Number of FFT = ' + str(NFFT))
for t in tqdm(range(Num_tri)):
for n in range(3):
for c in range(3):
Y = np.fft.fft( curJ[:,t,n,c] , NFFT)/nfiles
FD_curJ[:,t,n,c] = Y * Normalization
for t in tqdm(range(Num_tri)):
for n in range(3):
for c in range(3):
Y = np.fft.fft( curM[:,t,n,c] , NFFT)/nfiles
FD_curM[:,t,n,c] = Y * Normalization
FD_curJ_final = FD_curJ[0:TRUNC,:,:,:]
FD_curM_final = FD_curM[0:TRUNC,:,:,:]
plt.figure()
plt.plot(f[0:TRUNC]/1e9,abs( np.mean(FD_curJ_final, axis=(1,2,3)) ))
plt.grid()
plt.xlabel("FREQ (GHZ)")
plt.ylabel("Frequency Domain Spectrum curJ")
plt.xlim([0,6])
plt.savefig("FreqcurJ.png")
plt.figure()
plt.plot(f[0:TRUNC]/1e9,abs( np.mean(FD_curM_final,axis=(1,2,3)) ))
plt.grid()
plt.xlabel("FREQ (GHZ)")
plt.ylabel("Frequency Domain Spectrum curM")
plt.xlim([0,6])
plt.savefig("FreqcurM.png")
#%%
##############################################################
#### SECTION 4 ####
#### Set up simulation files for near to far computuation ####
#### Compute RCS of object ####
##############################################################
RCS = np.zeros(len(frequency_samples))
RCS_CUT_THETA = np.zeros([len(frequency_samples),181])
for counter,FREQ in enumerate(frequency_samples):
# Writing output
index_f = "%06d" % int(FREQ/1e6)
outfile="OUTPUT"+str(index_f)
print("Writing output file : " + outfile)
# Window spectrum at 1 frequency
# Delta function
F_opt = 0 # Final value of the spectrum amplitude
index = np.argmin( abs(FREQ - f) )
print(index)
print(f[index])
F_curJ_opt = FD_curJ_final[index,:,:,:] * 2
F_curM_opt = FD_curM_final[index,:,:,:] * 2
fid=open(outfile+".curJ",'w')
for t in tqdm(range(Num_tri)):
for n in range(3):
for c in range(3):
line = str( np.real(F_curJ_opt[t,n,c] ) ) + " " + str( np.imag(F_curJ_opt[t,n,c] ) ) + '\n'
fid.write(line)
fid.write('\n')
fid.close()
fid=open(outfile+".curM",'w')
for t in tqdm(range(Num_tri)):
for n in range(3):
for c in range(3):
line = str( np.real(F_curM_opt[t,n,c] ) ) + " " + str( np.imag(F_curM_opt[t,n,c] ) ) + '\n'
fid.write(line)
fid.write('\n')
fid.close()
REGIONFILE = "FF"+str(index_f)
if (SCATTERING_MODE == 1):
filep = open(REGIONFILE+".region", "w")
filep.write("1\n")
filep.write("0 FEBI\n")
filep.write("0 FEBI "+ outfile +"\n")
filep.write("Coupling\n")
filep.close()
else:
filep = open(REGIONFILE+".region", "w")
filep.write("1\n")
filep.write("0 MOM\n")
filep.write("0 MOM "+ outfile +"\n")
filep.write("Coupling\n")
filep.close()
cmd = "cp ./" + SURFACE_TRI_MESH + ".tri ./" + outfile + ".tri"
os.system(cmd)
cmd = "./n2f_main " + REGIONFILE + " " + str(int(FREQ/1e6)) + " 0 0 0 180 360 0 1"
os.system(cmd)
cmd = "emsurftranslator -s " + outfile
os.system(cmd)
print("\n\n==== Process Farfield Result ====\n")
cmd = "sed -i 's/ / /g' " + REGIONFILE + ".cs"
os.system(cmd)
data = pd.read_csv("./"+REGIONFILE+".cs",delimiter=" ",skiprows=1,header=None)
data1=data.iloc[0:361*10]
del data1[data1.columns[0]]
data2=data.iloc[361*10::]
del data2[data2.columns[-1]]
d1 = data1.to_numpy()
d2 = data2.to_numpy()
result = np.concatenate((d1,d2))
df = pd.DataFrame( result, columns = ['Theta','Phi','coRCS','xRCS'])
theta_df = df[ df['Theta'] == THETA ]
theta_phi_df = theta_df[ theta_df['Phi'] == PHI ]
phi_df = df[ df['Phi'] == PHI ]
RCS[counter] = theta_phi_df['coRCS']
print(phi_df)
RCS_CUT_THETA[counter,:] = phi_df['coRCS']
output_df = pd.DataFrame({'Frequency':frequency_samples, 'coRCS':RCS})
output_df.to_csv(OUTPUT_RCS_FILENAME+".xlsx", index=False)
theta_space = np.linspace(0,180,181)
for counter,FREQ in enumerate(frequency_samples):
output_df2 = pd.DataFrame({'Theta':theta_space, 'coRCS':RCS_CUT_THETA[counter,:]})
output_df2.to_csv(OUTPUT_RCS_FILENAME+"_"+str(int(FREQ))+".xlsx", index=False)