3
$\begingroup$

I'm trying to plot a 3d antenna radiation pattern using python (or js if possible) but my code is not working. Here is what my dataset looks like:

Theta [deg.]  Phi   [deg.]  Abs(RCS )[dB(m^2)]   Abs(Theta)[dB(m^2)]  Phase(Theta)[deg.]  Abs(Phi  )[dB(m^2)]  Phase(Phi  )[deg.]  Ax.Ratio[dB    ]    
---------------------------------------------------------------------------------------------------------------------------------------------------------
 175.000           2.500           -4.083e+01          -4.117e+01             118.796          -5.208e+01             120.015           4.000e+01     
 177.500           2.500           -4.005e+01          -4.018e+01             118.327          -5.539e+01             117.213           4.000e+01     
 180.000           2.500           -4.054e+01          -4.055e+01             119.035          -6.585e+01             103.657           3.685e+01     
   0.000           5.000           -4.039e+01          -4.043e+01              52.496          -6.111e+01             247.581           3.244e+01     
   2.500           5.000           -4.028e+01          -4.039e+01              51.026          -5.616e+01             277.199           1.871e+01     
   5.000           5.000           -4.011e+01          -4.040e+01              52.497          -5.194e+01             295.813           1.265e+01     
   7.500           5.000           -4.016e+01          -4.043e+01              50.019          -5.247e+01             298.975           1.271e+01     
  10.000           5.000           -4.000e+01          -4.036e+01              50.000          -5.101e+01             306.994           1.091e+01     
  12.500           5.000           -4.026e+01          -4.064e+01              52.824          -5.102e+01             311.570           1.059e+01     

Here are my functions for converting spherical to cartesian and vice-versa:

import math
import pandas as pd
import numpy as np
import plotly.graph_objects as go


def spherical_to_cartesian(theta, phi, rcs):
    x = rcs * math.cos(phi) * math.sin(theta)
    y = rcs * math.sin(phi) * math.sin(theta)
    z = rcs * math.cos(theta)
    return x, y, z


def get_transformed_dataframe(path):
    df = pd.read_csv(path, sep="\s+", skiprows=2, header=None)
    df.columns = ['theta', 'phi', 'rcs', 'abs(theta)', 'phase(theta)', 'abs(phi)', 'phase(phi)', 'ax.ratio']
    result_df = df.apply(lambda x: spherical_to_cartesian(x.theta, x.phi, x.rcs), axis=1, result_type='expand')
    result_df.columns = ['x', 'y', 'z']
    result = df.join(result_df)
    return result


df = get_transformed_dataframe('test.txt')
x, y, z = df.x, df.y, df.z
fig = go.Figure(data=[go.Surface(z=z, x=x, y=y)])
fig.update_layout(title='test')
fig.show()

This is my output, which shows nothing: Plotted output

And this is the kind of output I'm trying to get:

Desired output

Any idea what is wrong with my code, and how can I get closer to my desired output?

$\endgroup$
1
  • $\begingroup$ please add link to the input data $\endgroup$ Jul 16, 2023 at 20:44

1 Answer 1

2
$\begingroup$

Today I wanted to do the same thing and met the same problem. I guess your data was obtained from CST Studio Suite like a farfield.

After some observations I found a good solution. Actually, I used mounting to Google Drive, but it is easy to switch to another data source. Below there is a full code, which provides you with the exact result:

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as Axes3D
from numpy import sin,cos,pi, exp,log
from tqdm import tqdm
# import mpl_toolkits.mplot3d.axes3d as Axes3D
from matplotlib import cm, colors

filepath = 'Data_From_CST.txt'

vals_theta = []
vals_phi = []
vals_r = []
with open(filepath) as f:
  for s in f.readlines()[2:]:
    vals_theta.append(float(s.strip().split()[0]))
    vals_phi.append(float(s.strip().split()[1]))
    vals_r.append(float(s.strip().split()[2]))


theta1d = vals_theta
theta = np.array(theta1d)/180*pi;

phi1d = vals_phi
phi = np.array(phi1d)/180*pi;

power1d = vals_r
power = np.array(power1d);
# power = power-min(power)
power = 10**(power/10) # I used linscale

X = power*sin(phi)*sin(theta)
Y = power*cos(phi)*sin(theta)
Z = power*cos(theta)

X = X.reshape([360,181])
Y = Y.reshape([360,181])
Z = Z.reshape([360,181])

def interp_array(N1):  # add interpolated rows and columns to array
    N2 = np.empty([int(N1.shape[0]), int(2*N1.shape[1] - 1)])  # insert interpolated columns
    N2[:, 0] = N1[:, 0]  # original column
    for k in range(N1.shape[1] - 1):  # loop through columns
        N2[:, 2*k+1] = np.mean(N1[:, [k, k + 1]], axis=1)  # interpolated column
        N2[:, 2*k+2] = N1[:, k+1]  # original column
    N3 = np.empty([int(2*N2.shape[0]-1), int(N2.shape[1])])  # insert interpolated columns
    N3[0] = N2[0]  # original row
    for k in range(N2.shape[0] - 1):  # loop through rows
        N3[2*k+1] = np.mean(N2[[k, k + 1]], axis=0)  # interpolated row
        N3[2*k+2] = N2[k+1]  # original row
    return N3

interp_factor=1

for counter in range(interp_factor):  # Interpolate between points to increase number of faces
    X = interp_array(X)
    Y = interp_array(Y)
    Z = interp_array(Z)

N = np.sqrt(X**2 + Y**2 + Z**2)
Rmax = np.max(N)
N = N/Rmax

fig = plt.figure(figsize=(10,8))

ax = fig.add_subplot(1,1,1, projection='3d')
axes_length = 0.65
ax.plot([0, axes_length*Rmax], [0, 0], [0, 0], linewidth=2, color='red')
ax.plot([0, 0], [0, axes_length*Rmax], [0, 0], linewidth=2, color='green')
ax.plot([0, 0], [0, 0], [0, axes_length*Rmax], linewidth=2, color='blue')

# Find middle points between values for face colours
N = interp_array(N)[1::2,1::2]

mycol = cm.jet(N)

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=mycol, linewidth=0.5, antialiased=True, shade=False)  # , alpha=0.5, zorder = 0.5)

ax.set_xlim([-axes_length*Rmax, axes_length*Rmax])
ax.set_ylim([-axes_length*Rmax, axes_length*Rmax])
ax.set_zlim([-axes_length*Rmax, axes_length*Rmax])

m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(power)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

fig.colorbar(m, shrink=0.8)
ax.view_init(azim=300, elev=30)

plt.show()

Output img.

As you can easily see, this code expects three data arrays: two Euler's angles and a function you want to plot.

In my studies I used these two useful sources:

  1. https://stackoverflow.com/questions/54822873/python-plotting-antenna-radiation-pattern;
  2. https://stackoverflow.com/a/63059296.
$\endgroup$
1
  • $\begingroup$ An error occurs when the following code runs: line 36, in <module> X = X.reshape([360,181]) ValueError: cannot reshape array of size 9 into shape (360,181) $\endgroup$ Apr 25, 2023 at 8:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.