plot-antenna 2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plot_antenna/Version.py +1 -0
- plot_antenna/__init__.py +4 -0
- plot_antenna/contrib.py +83 -0
- plot_antenna/eznec.py +101 -0
- plot_antenna/plot_antenna.py +2592 -0
- plot_antenna-2.0.dist-info/LICENSE +23 -0
- plot_antenna-2.0.dist-info/METADATA +331 -0
- plot_antenna-2.0.dist-info/RECORD +11 -0
- plot_antenna-2.0.dist-info/WHEEL +5 -0
- plot_antenna-2.0.dist-info/entry_points.txt +4 -0
- plot_antenna-2.0.dist-info/top_level.txt +1 -0
plot_antenna/Version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION="2.0"
|
plot_antenna/__init__.py
ADDED
plot_antenna/contrib.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
|
|
3
|
+
# Parsers for contributed data structures
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from csv import DictReader
|
|
7
|
+
from . import plot_antenna as aplot
|
|
8
|
+
|
|
9
|
+
def parse_csv_measurement_data (args):
|
|
10
|
+
""" Parses measurement data from CSV file
|
|
11
|
+
This has the columns:
|
|
12
|
+
- Messwert: The measurement
|
|
13
|
+
- Einheit Messwert: Unit of the measurement (e.g. dBm)
|
|
14
|
+
- Position Drehscheibe: Azimuth angle
|
|
15
|
+
- Position Positionierer: Elevation angle
|
|
16
|
+
- Polarisation: 'PH' for horizontal, 'PV' for vertical polarization
|
|
17
|
+
- Messfrequenz: frequency
|
|
18
|
+
- Einheit Messfrequenz: unit of frequency
|
|
19
|
+
For an example see test/Messdaten.csv
|
|
20
|
+
The format has the following peculiarities:
|
|
21
|
+
- The elevation angles slightly vary for a single azimuth scan.
|
|
22
|
+
This means we may have 10° and some values at 10.1°. Since the
|
|
23
|
+
elevation angle steps are 10° we round to the nearest integer.
|
|
24
|
+
- Azimuth is scanned continuously, so azimuth angles do not
|
|
25
|
+
match at all for two different elevation angles. This still
|
|
26
|
+
means we can plot an azimuth polarization diagram. But for
|
|
27
|
+
elevation or 3d plots we need to interpolate the azimuth
|
|
28
|
+
angles. For this the --interpolate-azimuth-step option was
|
|
29
|
+
added. Typically we interpolate the azimuth values to e.g. a
|
|
30
|
+
2° grid.
|
|
31
|
+
- Some azimuth angles are greater than 360°.
|
|
32
|
+
"""
|
|
33
|
+
gdata_dict = {}
|
|
34
|
+
with open (args.filename, 'r') as f:
|
|
35
|
+
dr = DictReader (f, delimiter = ';')
|
|
36
|
+
for rec in dr:
|
|
37
|
+
args.dB_unit = rec ['Einheit Messwert']
|
|
38
|
+
f = float (rec ['Messfrequenz']) * 1e3 # MHz
|
|
39
|
+
if f not in gdata_dict:
|
|
40
|
+
p = rec ['Polarisation'][1:]
|
|
41
|
+
k = (f, p)
|
|
42
|
+
if k not in gdata_dict:
|
|
43
|
+
gdata_dict [k] = aplot.Gain_Data (k)
|
|
44
|
+
gdata = gdata_dict [k]
|
|
45
|
+
azi = float (rec ['Position Drehscheibe']) % 360
|
|
46
|
+
# Need to round elevation values: these sometimes differ
|
|
47
|
+
# during a scan
|
|
48
|
+
ele = round (float (rec ['Position Positionierer']), 0)
|
|
49
|
+
# Don't allow values outside angle range
|
|
50
|
+
if azi < 0 or azi > 360 or ele < 0 or ele > 360:
|
|
51
|
+
continue
|
|
52
|
+
# We treat the value as 'dBi' although this is dBm
|
|
53
|
+
# Probably needs conversion but we may get away with
|
|
54
|
+
# allowing a unit to be specified for the plot, it must be a
|
|
55
|
+
# dezibel value, though (not linear gain or so)
|
|
56
|
+
gain = float (rec ['Messwert'])
|
|
57
|
+
gdata.pattern [(ele, azi)] = gain
|
|
58
|
+
return gdata_dict
|
|
59
|
+
# end def parse_csv_measurement_data
|
|
60
|
+
|
|
61
|
+
def main_csv_measurement_data (argv = sys.argv [1:], pic_io = None):
|
|
62
|
+
""" Parse a contributed measurement format, see docstring of
|
|
63
|
+
parse_csv_measurement_data.
|
|
64
|
+
The pic_io argument is for testing.
|
|
65
|
+
"""
|
|
66
|
+
cmd = aplot.options_general ()
|
|
67
|
+
aplot.options_gain (cmd)
|
|
68
|
+
cmd.add_argument ('filename', help = 'CSV File to parse and plot')
|
|
69
|
+
args = aplot.process_args (cmd, argv)
|
|
70
|
+
# Set default polarization, we need this otherwise the sum isn't computed
|
|
71
|
+
if not args.polarization:
|
|
72
|
+
args.polarization ['sum'] = True
|
|
73
|
+
if pic_io is not None:
|
|
74
|
+
args.output_file = pic_io
|
|
75
|
+
args.save_format = 'png'
|
|
76
|
+
gdata = parse_csv_measurement_data (args)
|
|
77
|
+
gp = aplot.Gain_Plot (args, gdata)
|
|
78
|
+
gp.compute ()
|
|
79
|
+
gp.plot ()
|
|
80
|
+
# end def main_csv_measurement_data
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
main_csv_measurement_data ()
|
plot_antenna/eznec.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from csv import DictReader
|
|
5
|
+
from . import plot_antenna as aplot
|
|
6
|
+
|
|
7
|
+
def parse_eznec_data (args):
|
|
8
|
+
""" Parses eznec date exported with 'FF Tab'
|
|
9
|
+
This is either organized in Azimuth- or Elevation slices.
|
|
10
|
+
We determine the format during parsing.
|
|
11
|
+
It looks like the format supports only a single frequency.
|
|
12
|
+
"""
|
|
13
|
+
gdata_dict = {}
|
|
14
|
+
state_seen = None
|
|
15
|
+
state = 'start'
|
|
16
|
+
head_seen = False
|
|
17
|
+
gdata_dict = {}
|
|
18
|
+
with open (args.filename, 'r') as rfile:
|
|
19
|
+
for line in rfile:
|
|
20
|
+
line = line.strip ()
|
|
21
|
+
if state == 'start':
|
|
22
|
+
line = line.replace (',', '.')
|
|
23
|
+
if line.startswith ('Frequency'):
|
|
24
|
+
if not line.endswith ('MHz'):
|
|
25
|
+
raise ValueError \
|
|
26
|
+
('Unsupported frequency format: %s' % line)
|
|
27
|
+
frq = float (line.rsplit () [-2])
|
|
28
|
+
continue
|
|
29
|
+
if 'Pattern' in line:
|
|
30
|
+
if line.startswith ('Azimuth'):
|
|
31
|
+
state = 'azi'
|
|
32
|
+
elif line.startswith ('Elevation'):
|
|
33
|
+
state = 'ele'
|
|
34
|
+
else:
|
|
35
|
+
raise ValueError ('Unsupported slice format %s' % line)
|
|
36
|
+
if state_seen and state_seen != state:
|
|
37
|
+
raise ValueError ('Mid-file change of slice format')
|
|
38
|
+
state_seen = state
|
|
39
|
+
r = line.split ('=', 1) [1]
|
|
40
|
+
r = r.split () [0]
|
|
41
|
+
angle = int (r)
|
|
42
|
+
if state == 'azi':
|
|
43
|
+
angle += 90
|
|
44
|
+
head_seen = False
|
|
45
|
+
continue
|
|
46
|
+
if state in ('azi', 'ele'):
|
|
47
|
+
if not head_seen:
|
|
48
|
+
l = ' '.join (line.split ())
|
|
49
|
+
if l != 'Deg V dB H dB Tot dB V Pha H Pha':
|
|
50
|
+
raise ValueError ('Expect Degree line, got %s' % line)
|
|
51
|
+
head_seen = True
|
|
52
|
+
continue
|
|
53
|
+
if not line:
|
|
54
|
+
state = 'start'
|
|
55
|
+
continue
|
|
56
|
+
line = line.replace (',', '.')
|
|
57
|
+
values = line.split ()
|
|
58
|
+
deg = int (values [0])
|
|
59
|
+
if state == 'ele':
|
|
60
|
+
if 90 < deg < 270:
|
|
61
|
+
continue
|
|
62
|
+
if deg <= 90:
|
|
63
|
+
deg += 90
|
|
64
|
+
elif deg >= 270:
|
|
65
|
+
deg -= 270
|
|
66
|
+
vert, hori, tot = (float (x) for x in values [1:4])
|
|
67
|
+
gd = {}
|
|
68
|
+
for pol, gain in zip (('H', 'V', 'sum'), (hori, vert, tot)):
|
|
69
|
+
k = (frq, pol)
|
|
70
|
+
if k not in gdata_dict:
|
|
71
|
+
gdata_dict [k] = aplot.Gain_Data (k)
|
|
72
|
+
gdata = gdata_dict [k]
|
|
73
|
+
if state == 'azi':
|
|
74
|
+
ele = angle
|
|
75
|
+
azi = deg
|
|
76
|
+
else:
|
|
77
|
+
ele = deg
|
|
78
|
+
azi = angle
|
|
79
|
+
#print (ele, azi, pol, gain)
|
|
80
|
+
gdata.pattern [(ele, azi)] = gain
|
|
81
|
+
return gdata_dict
|
|
82
|
+
# end def parse_csv_measurement_data
|
|
83
|
+
|
|
84
|
+
def main_eznec (argv = sys.argv [1:], pic_io = None):
|
|
85
|
+
""" Parse eznec far field data.
|
|
86
|
+
"""
|
|
87
|
+
cmd = aplot.options_general ()
|
|
88
|
+
aplot.options_gain (cmd)
|
|
89
|
+
cmd.add_argument ('filename', help = 'EZNEC far field data to plot')
|
|
90
|
+
args = aplot.process_args (cmd, argv)
|
|
91
|
+
if pic_io is not None:
|
|
92
|
+
args.output_file = pic_io
|
|
93
|
+
args.save_format = 'png'
|
|
94
|
+
gdata = parse_eznec_data (args)
|
|
95
|
+
gp = aplot.Gain_Plot (args, gdata)
|
|
96
|
+
gp.compute ()
|
|
97
|
+
gp.plot ()
|
|
98
|
+
# end def main_eznec
|
|
99
|
+
|
|
100
|
+
if __name__ == '__main__':
|
|
101
|
+
main_eznec ()
|