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.
@@ -0,0 +1 @@
1
+ VERSION="2.0"
@@ -0,0 +1,4 @@
1
+ try:
2
+ from .Version import VERSION as __version__
3
+ except ImportError:
4
+ __version__ = '0+unknown'
@@ -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 ()