Search code examples
pythonplotspherical-coordinate

3D antenna radiation plot in spherical coorinates problem


I want to plot 3D antenna radiation pattern from CSV file, after data loading i have got:

        Theta    Phi     Dir
0       0.000    0.0   8.272
1       5.000    0.0   8.221
2      10.000    0.0   8.064
3      15.000    0.0   7.804
4      20.000    0.0   7.444
...       ...    ...     ...
2659  160.000  355.0 -13.240
2660  165.000  355.0 -12.330
2661  170.000  355.0 -11.460
2662  175.000  355.0 -10.870
2663  180.000  355.0 -10.670

so Theta chages from 0 to 180 deg, and Phi 0 to 355. Then i run code:

import pandas as pd
import numpy as np
from array import *
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from plotly.offline import plot

# Read data from CSV file
df = pd.read_csv('output_file.csv')


# reshaping data for plot
theta1d = df['Theta']                  
theta1d = np.array(theta1d)
theta1d_unique = np.unique(theta1d)

angle_count_theta = len(theta1d_unique)

phi1d = df['Phi']                  
phi1d = np.array(phi1d)
phi1d_unique = np.unique(phi1d)

angle_count_phi = len(phi1d_unique)


theta2d = theta1d.reshape([angle_count_theta, angle_count_phi])
phi2d = phi1d.reshape([angle_count_theta, angle_count_phi])

dir1d = df['Dir']                  
dir1d = np.array(dir1d)


R = np.empty((angle_count_theta, angle_count_phi))
row_count = 0

for j in range(angle_count_phi):
    for i in range(angle_count_theta):
        R[i,j] = dir1d[row_count * angle_count_theta + i]
    row_count += 1
    
THETA = np.deg2rad(theta2d)
PHI = np.deg2rad(phi2d)

THETA = THETA.reshape(R.shape[0],R.shape[1])
PHI = PHI.reshape(R.shape[0],R.shape[1])

# transformation of spherical data 

X = R * np.sin(THETA) * np.cos(PHI) 
Y = R * np.sin(THETA) * np.sin(PHI)
Z = R * np.cos(THETA)


min_X = np.min(X)
max_X = np.max(X)
min_Y = np.min(Y)
max_Y = np.max(Y)

layout = go.Layout(title="3D Radiation Pattern of 5G CW data", xaxis = dict(range=[min_X,max_X],), yaxis = dict(range=[min_Y,max_Y],))

fig = go.Figure(data=[go.Surface(x=X, y=Y, z=Z, surfacecolor=R, colorscale='mygbm', colorbar = dict(title = "Gain", thickness = 50, xpad = 500))], layout = layout)

fig.update_layout(autosize = True, margin = dict(l = 50, r = 50, t = 250, b = 250))

plot(fig)

Here are plots.

What I have from python script:

what i have from python script

and

From x-y side:

from x-y side

(from 'top') we can see that there is no smooth connection between values, but sphere back to (0, 0, 0) point.

The proper radiation pattern:

The proper radiation pattern

How to solve this?


Solution

  • I think that you are just getting row/column order muddled up (multiple times). Theta changes fastest in your input.

    Note that you will also get a small gap in your plot unless your input data file includes the full-circle value for phi=360 degrees at the end.

    I don't have your data, so I had to generate my own (see the Fortran program at the bottom of the post - its much simpler than your actual data). However, see if this solution works for your file.

    import pandas as pd
    import numpy as np
    from array import *
    import numpy as np
    import pandas as pd
    import plotly.graph_objects as go
    from plotly.offline import plot
    
    # Read data from CSV file
    df = pd.read_csv('output_file.csv')
    
    # Separate columns
    theta1d = np.array( df['Theta'] )
    phi1d   = np.array( df['Phi'] )
    dir1d   = np.array( df['Dir'] )
    
    # Reshape for plot. NOTE: theta varies fastest in your input file
    angle_count_theta = len( np.unique( theta1d ) )
    angle_count_phi   = len( np.unique( phi1d   ) )
    theta2d = theta1d.reshape( [ angle_count_phi, angle_count_theta ] )
    phi2d   = phi1d  .reshape( [ angle_count_phi, angle_count_theta ] )
    R       = np.empty       ( ( angle_count_phi, angle_count_theta ) )
    
    for i in range( angle_count_phi ):
       for j in range( angle_count_theta ):
            R[i,j] = dir1d[ i * angle_count_theta + j ]
        
    THETA = np.deg2rad(theta2d)
    PHI   = np.deg2rad(phi2d)
    X = R * np.sin( THETA ) * np.cos( PHI )
    Y = R * np.sin( THETA ) * np.sin( PHI )
    Z = R * np.cos( THETA )
    
    min_X = np.min(X)
    max_X = np.max(X)
    min_Y = np.min(Y)
    max_Y = np.max(Y)
    
    layout = go.Layout(title="3D Radiation Pattern of 5G CW data", xaxis = dict(range=[min_X,max_X],), yaxis = dict(range=[min_Y,max_Y],))
    fig = go.Figure(data=[go.Surface(x=X, y=Y, z=Z, surfacecolor=R, colorscale='mygbm', colorbar = dict(title = "Gain", thickness = 50, xpad = 500))], layout = layout)
    fig.update_layout(autosize = True, margin = dict(l = 50, r = 50, t = 250, b = 250))
    plot(fig)
    

    Output:

    enter image description here

    Some data generation:

    program test
       implicit none
       real, parameter :: PI = 4.0 * atan( 1.0 )
       integer nphi, ntheta
       integer i, j
       real theta, phi, z
       real dtheta, dphi
    
       nphi = 73;   ntheta = 37
       dphi = 360.0 / ( nphi - 1 )
       dtheta = 180.0 / ( ntheta - 1 )
    
       open( 10, file="output_file.csv" )
       write( 10, "( a, ',', a, ',', a )" ) "Theta", "Phi", "Dir"
       do j = 0, nphi - 1
          phi = j * dphi
          do i = 0, ntheta - 1
             theta = i * dtheta
             z = 10.0 * ( 1 + cos( theta * PI / 180.0 ) )
             write( 10, "( 1x, f7.2, ',', f7.2, ',', f7.2 )" ) theta, phi, z
          end do
       end do
       close( 10 )
    
    end program test