Close

Necpp And Testing Scimitars

A project log for Evolved Broadband Antenna

Using an evolutionary neural network to create an optimized broadband antenna for the ranges of 108MHz to 400MHz

jtklenkeJTKLENKE 08/18/2020 at 01:120 Comments

The first thing I did was to find an example and test it in google colab. The example came from the PyPi Website. It simulates a vertical pole and calculates the impedance for the frequency 34.5 MHz.

!pip install necpp
import necpp


def handle_nec(result):
  if (result != 0):
    print (necpp.nec_error_message())

def impedance(frequency, z0, height):
  
  nec = necpp.nec_create()
  handle_nec(necpp.nec_wire(nec, 1, 17, 0, 0, z0, 0, 0, z0+height, 0.1, 1, 1))
  handle_nec(necpp.nec_geometry_complete(nec, 0))
  handle_nec(necpp.nec_gn_card(nec, 1, 0, 0, 0, 0, 0, 0, 0))
  handle_nec(necpp.nec_fr_card(nec, 0, 1, frequency, 0))
  handle_nec(necpp.nec_ex_card(nec, 0, 0, 1, 0, 1.0, 0, 0, 0, 0, 0)) 
  handle_nec(necpp.nec_rp_card(nec, 0, 90, 1, 0,5,0,0, 0, 90, 1, 0, 0, 0))
  result_index = 0
  
  z = complex(necpp.nec_impedance_real(nec,result_index), 
              necpp.nec_impedance_imag(nec,result_index))
  
  necpp.nec_delete(nec)
  return z


z = impedance(frequency = 34.5, z0 = 0.5, height = 4.0)
print ("Impedance \t(%6.1f,%+6.1fI) Ohms" % (z.real, z.imag))

 After getting that to work I started trying to get multiple wires and connections to work with the goal of eventually putting together a scimitar geometry. At first I was getting a lot of strange errors and the lack of good documentation and examples made debugging really difficult. The error was "index 2 is out of bounds for axis 0 with size 2" or sometime just the program crashing. Eventually I figured out the problem was with the segment count so I brute forced my way to a segment count that worked for the shape I was trying. Later I found out that the segment count has to be high enough so that the largest segment of a wire has to be smaller than 20% of the smallest wavelength. Basically, divide the speed of light by the highest frequency, divide that by 5 and make sure the wire has enough segments so that they are all smaller than that value. From there I could calculate the impedance for a specific frequency for any geometry I wanted, the final code looked like this:

def impedance(freq,pts):
  nec = necpp.nec_create()
  for a in range(0,pts.shape[0]-1):
    y1=pts.item((a,0))
    z1=pts.item((a,1))
    y2=pts.item((a+1,0))
    z2=pts.item((a+1,1))
    handle_nec(necpp.nec_wire(nec, a+1, segmentCount(y1,z1,y2,z2), 0, y1, z1, 0, y2, z2, 0.001, 1, 1))

 

  handle_nec(necpp.nec_geometry_complete(nec, 1))
  handle_nec(necpp.nec_gn_card(nec, 1, 0, 0, 0, 0, 0, 0, 0))
  handle_nec(necpp.nec_fr_card(nec, 0, 1, freq, 0))
  handle_nec(necpp.nec_ex_card(nec, 0, 1, 1, 0, 1.0, 0, 0, 0, 0, 0)) 
  handle_nec(necpp.nec_ld_card(nec, 5, 1, 0, 0, 58001000, 0, 0))
  handle_nec(necpp.nec_xq_card(nec, 0))
  result_index = 0
  z = complex(necpp.nec_impedance_real(nec,result_index), 
         necpp.nec_impedance_imag(nec,result_index))
  

  necpp.nec_delete(nec)
  return z

where this would return the real and imaginary components of impedance for a certain frequency (freq) for a given list of points (pts). Impedance could then be turned into VSWR through the simple little equation (1+(sqrt((R-Z)^2+j^2)/(sqrt((R+Z)^2+j^2)))/(1-((sqrt((R-Z)^2+j^2)/(sqrt((R+Z)^2+j^2)))) where R is the real component j is the imaginary component and Z is the source impedance found more clearly here. Next, I used plt.plot to more easily visualize where the wires were in place of plt.scatter. Then, I decided to start graphing the VSWR for multiple frequencies. Originally, I called the impedance functions for every frequency in the range but this was slow because the program had to rebuild the geometry and environment each time it tested a frequency. I learned that you can run and access multiple frequencies at once and modified the impedance code so that result_index would be looped through and all the frequencies would be added to a list which would then be returrned:

  for result_index in range(0,n):
      z = complex(necpp.nec_impedance_real(nec,result_index), 
              necpp.nec_impedance_imag(nec,result_index))
      A.append(z)
  necpp.nec_delete(nec)
  return A

 and the frequency card (fr_card) had to be modified to this:

handle_nec(necpp.nec_fr_card(nec, 0, n, freq, d))

 where n is the number of frequencies tested and d is the distance between samplings

In order to get better results I moved the tip of the scimitar to (0,0) and the wide part of the scimitar off the ground plane. Given the size constraint of the space the antenna had to fit in I created a scaled (and slightly raised) version of the patented scimitar antenna and for an antenna that looked like this:

got this:

the orange line marks a VSWR of 2, which is the goal for the entire frequency range. The scale of the antenna is in meters so it is very small.

Discussions