plot-antenna 2.2__tar.gz → 2.4__tar.gz
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-2.2/plot_antenna.egg-info → plot_antenna-2.4}/PKG-INFO +81 -11
- {plot_antenna-2.2 → plot_antenna-2.4}/README.rst +80 -10
- plot_antenna-2.4/VERSION +1 -0
- plot_antenna-2.4/plot_antenna/Version.py +1 -0
- plot_antenna-2.4/plot_antenna/contrib.py +220 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna/plot_antenna.py +124 -72
- {plot_antenna-2.2 → plot_antenna-2.4/plot_antenna.egg-info}/PKG-INFO +81 -11
- {plot_antenna-2.2 → plot_antenna-2.4}/test/test_plot.py +128 -23
- plot_antenna-2.2/VERSION +0 -1
- plot_antenna-2.2/plot_antenna/Version.py +0 -1
- plot_antenna-2.2/plot_antenna/contrib.py +0 -83
- {plot_antenna-2.2 → plot_antenna-2.4}/LICENSE +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna/__init__.py +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna/eznec.py +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna.egg-info/SOURCES.txt +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna.egg-info/dependency_links.txt +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna.egg-info/entry_points.txt +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna.egg-info/requires.txt +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/plot_antenna.egg-info/top_level.txt +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/pyproject.toml +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/setup.cfg +0 -0
- {plot_antenna-2.2 → plot_antenna-2.4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plot-antenna
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4
|
|
4
4
|
Summary: Antenna plotting program for plotting antenna simulation results
|
|
5
5
|
Home-page: https://github.com/schlatterbeck/plot-antenna
|
|
6
6
|
Author: Ralf Schlatterbeck
|
|
@@ -233,6 +233,28 @@ your own data with `plot-antenna`_. The eznec program in
|
|
|
233
233
|
``plot_antenna/eznec.py`` might even be better in this regard. See the
|
|
234
234
|
next section on documentation of the `plot-antenna`_ API.
|
|
235
235
|
|
|
236
|
+
Running the Tests
|
|
237
|
+
-----------------
|
|
238
|
+
|
|
239
|
+
For running the plotly tests, the ``kaleido`` python package needs to be
|
|
240
|
+
installed. For Debian Trixie and earlier version 0.2.1 is needed. This
|
|
241
|
+
is installed with pip as shown below, if you don't want to mess with the
|
|
242
|
+
``--break-system-packages`` option, installing everything into a virtual
|
|
243
|
+
environment is the way to go::
|
|
244
|
+
|
|
245
|
+
python3 -m pip install kaleido==0.2.1 --break-system-packages
|
|
246
|
+
|
|
247
|
+
The tests use pictures saved in ``test/pics`` and will compare |--| depending
|
|
248
|
+
on matplotlib or plotly version |--| the picture matching the backend
|
|
249
|
+
version to the picture produced during the test. For this to work,
|
|
250
|
+
especially for plotly, the correct fonts need to be installed. Plotly
|
|
251
|
+
seems to prefer the Open Sans font family. So at least on Debian the
|
|
252
|
+
package ``fonts-open-sans`` needs to be installed. Otherwise the tests
|
|
253
|
+
fail because the pictures do not match. If a test fails a picture with
|
|
254
|
+
the extension ``.debug`` will be produced in the directory ``test/pics``.
|
|
255
|
+
If differences are not immediately visible, the ``compare`` program from
|
|
256
|
+
imagemagick may help.
|
|
257
|
+
|
|
236
258
|
Plot-Antenna API
|
|
237
259
|
----------------
|
|
238
260
|
|
|
@@ -257,21 +279,41 @@ It has an internal ``pattern`` dictionary which stores the gain values
|
|
|
257
279
|
by a tuple of ``(theta, phi)`` where ``theta`` is the elevation angle
|
|
258
280
|
(measured from the zenith=0 degrees) and the azimuth angle phi measured
|
|
259
281
|
from the positive X-axis. The gain values in this data structure are in
|
|
260
|
-
dBi (Decibel over an isotropic radiator).
|
|
261
|
-
|
|
262
|
-
construct an azimuth plot of an antenna that has the
|
|
263
|
-
directions (gain=0dB) would be::
|
|
282
|
+
dBi (Decibel over an isotropic radiator).
|
|
283
|
+
|
|
284
|
+
A simple program to construct an azimuth plot of an antenna that has the
|
|
285
|
+
same pattern in all directions (gain=0dB) would be::
|
|
264
286
|
|
|
265
287
|
import numpy as np
|
|
266
288
|
from plot_antenna import plot_antenna
|
|
267
289
|
|
|
290
|
+
# Compute args, see below
|
|
268
291
|
frequency = 430.0
|
|
269
292
|
polarization = 'sum'
|
|
270
293
|
key = (frequency, polarization)
|
|
271
|
-
gdict = {key: plot_antenna.Gain_Data (
|
|
294
|
+
gdict = {key: plot_antenna.Gain_Data (key)}
|
|
272
295
|
data = gdict [key].pattern
|
|
273
|
-
for
|
|
274
|
-
|
|
296
|
+
for theta in np.arange (0, 181, 10):
|
|
297
|
+
for phi in np.arange (0, 361, 10):
|
|
298
|
+
data [(theta, phi)] = 0.0
|
|
299
|
+
gp = plot_antenna.Gain_Plot (args, gdict)
|
|
300
|
+
gp.compute ()
|
|
301
|
+
gp.plot ()
|
|
302
|
+
|
|
303
|
+
In the latest version you can also directly pass numpy arrays for gain,
|
|
304
|
+
theta, and phi angles, angles are in degrees::
|
|
305
|
+
|
|
306
|
+
import numpy as np
|
|
307
|
+
from plot_antenna import plot_antenna
|
|
308
|
+
|
|
309
|
+
# Compute args, see below
|
|
310
|
+
frequency = 430.0
|
|
311
|
+
polarization = 'sum'
|
|
312
|
+
key = (frequency, polarization)
|
|
313
|
+
thetas = np.arange (0, 181, 10)
|
|
314
|
+
phis = np.arange (0, 361, 10)
|
|
315
|
+
gains = np.zeros ((19, 37))
|
|
316
|
+
gdict = {key: plot_antenna.Gain_Data.from_gains (key, gains, thetas, phis)}
|
|
275
317
|
gp = plot_antenna.Gain_Plot (args, gdict)
|
|
276
318
|
gp.compute ()
|
|
277
319
|
gp.plot ()
|
|
@@ -290,14 +332,18 @@ line arguments but can be called with an empty string list, e.g.::
|
|
|
290
332
|
args.filename = ''
|
|
291
333
|
# Title
|
|
292
334
|
args.title = 'My Title'
|
|
293
|
-
# We want an azimuth plot
|
|
294
|
-
args.azimuth = True
|
|
295
335
|
# We might want to ship result to running browser with plotly
|
|
296
336
|
# args.show_in_browser = True
|
|
337
|
+
# If we want to do a 3d-plot we set args.plot3d, we could also set
|
|
338
|
+
# args.azimuth to get an azimuth plot. Both variables can be set and
|
|
339
|
+
# we get both plots (one after the other with matplotlib, both in
|
|
340
|
+
# different browser windows with plotly)
|
|
341
|
+
args.azimuth = False
|
|
342
|
+
args.plot3d = True
|
|
297
343
|
|
|
298
344
|
The ``cmd`` variable is a python ``ArgumentParser`` object. So if you
|
|
299
345
|
are parsing command line arguments you can add your own options before
|
|
300
|
-
calling ``process_args
|
|
346
|
+
calling ``process_args``.
|
|
301
347
|
|
|
302
348
|
If not parsing argument from the command line and arguments should be
|
|
303
349
|
changed this can be done by directly modifying args, e.g.::
|
|
@@ -319,6 +365,30 @@ the companion program for reading EZNEC data in
|
|
|
319
365
|
Release Notes
|
|
320
366
|
-------------
|
|
321
367
|
|
|
368
|
+
v2.4: Bug-fixes, coordinate transformation
|
|
369
|
+
|
|
370
|
+
- Fix max theta gain computation: We need to take *both sides of phi*
|
|
371
|
+
into account
|
|
372
|
+
- Allow to directly pass numpy arrays in API
|
|
373
|
+
- Coordinate transform for a contributed setup for a measurement device
|
|
374
|
+
- Update tests for debian trixie, in particular use better font defaults
|
|
375
|
+
that are more likely to be the same on multiple architectures
|
|
376
|
+
|
|
377
|
+
v2.3: Fix nec geo computation
|
|
378
|
+
|
|
379
|
+
- Fix a bug when parsing NEC geo info, in particular back-references in
|
|
380
|
+
geometry segments
|
|
381
|
+
- Update tests for recent changes, unfortunately the plotly PNG pics
|
|
382
|
+
seem not to be reproduceable across different installations of the
|
|
383
|
+
same plotly version
|
|
384
|
+
|
|
385
|
+
v2.2: Fix radial axis range of polar plots
|
|
386
|
+
|
|
387
|
+
- Polar plots were scaled differently depending on data, we now force
|
|
388
|
+
the polar axis range to a maximum of 1.01 (on both, matplotlib and
|
|
389
|
+
plotly backends) so that the trace(s) always fit without truncating
|
|
390
|
+
the trace at the boundary
|
|
391
|
+
|
|
322
392
|
v2.1: Scale by angle
|
|
323
393
|
|
|
324
394
|
- New option ``--scale-by-angle`` that allows to scale the azimuth or
|
|
@@ -201,6 +201,28 @@ your own data with `plot-antenna`_. The eznec program in
|
|
|
201
201
|
``plot_antenna/eznec.py`` might even be better in this regard. See the
|
|
202
202
|
next section on documentation of the `plot-antenna`_ API.
|
|
203
203
|
|
|
204
|
+
Running the Tests
|
|
205
|
+
-----------------
|
|
206
|
+
|
|
207
|
+
For running the plotly tests, the ``kaleido`` python package needs to be
|
|
208
|
+
installed. For Debian Trixie and earlier version 0.2.1 is needed. This
|
|
209
|
+
is installed with pip as shown below, if you don't want to mess with the
|
|
210
|
+
``--break-system-packages`` option, installing everything into a virtual
|
|
211
|
+
environment is the way to go::
|
|
212
|
+
|
|
213
|
+
python3 -m pip install kaleido==0.2.1 --break-system-packages
|
|
214
|
+
|
|
215
|
+
The tests use pictures saved in ``test/pics`` and will compare |--| depending
|
|
216
|
+
on matplotlib or plotly version |--| the picture matching the backend
|
|
217
|
+
version to the picture produced during the test. For this to work,
|
|
218
|
+
especially for plotly, the correct fonts need to be installed. Plotly
|
|
219
|
+
seems to prefer the Open Sans font family. So at least on Debian the
|
|
220
|
+
package ``fonts-open-sans`` needs to be installed. Otherwise the tests
|
|
221
|
+
fail because the pictures do not match. If a test fails a picture with
|
|
222
|
+
the extension ``.debug`` will be produced in the directory ``test/pics``.
|
|
223
|
+
If differences are not immediately visible, the ``compare`` program from
|
|
224
|
+
imagemagick may help.
|
|
225
|
+
|
|
204
226
|
Plot-Antenna API
|
|
205
227
|
----------------
|
|
206
228
|
|
|
@@ -225,21 +247,41 @@ It has an internal ``pattern`` dictionary which stores the gain values
|
|
|
225
247
|
by a tuple of ``(theta, phi)`` where ``theta`` is the elevation angle
|
|
226
248
|
(measured from the zenith=0 degrees) and the azimuth angle phi measured
|
|
227
249
|
from the positive X-axis. The gain values in this data structure are in
|
|
228
|
-
dBi (Decibel over an isotropic radiator).
|
|
229
|
-
|
|
230
|
-
construct an azimuth plot of an antenna that has the
|
|
231
|
-
directions (gain=0dB) would be::
|
|
250
|
+
dBi (Decibel over an isotropic radiator).
|
|
251
|
+
|
|
252
|
+
A simple program to construct an azimuth plot of an antenna that has the
|
|
253
|
+
same pattern in all directions (gain=0dB) would be::
|
|
232
254
|
|
|
233
255
|
import numpy as np
|
|
234
256
|
from plot_antenna import plot_antenna
|
|
235
257
|
|
|
258
|
+
# Compute args, see below
|
|
236
259
|
frequency = 430.0
|
|
237
260
|
polarization = 'sum'
|
|
238
261
|
key = (frequency, polarization)
|
|
239
|
-
gdict = {key: plot_antenna.Gain_Data (
|
|
262
|
+
gdict = {key: plot_antenna.Gain_Data (key)}
|
|
240
263
|
data = gdict [key].pattern
|
|
241
|
-
for
|
|
242
|
-
|
|
264
|
+
for theta in np.arange (0, 181, 10):
|
|
265
|
+
for phi in np.arange (0, 361, 10):
|
|
266
|
+
data [(theta, phi)] = 0.0
|
|
267
|
+
gp = plot_antenna.Gain_Plot (args, gdict)
|
|
268
|
+
gp.compute ()
|
|
269
|
+
gp.plot ()
|
|
270
|
+
|
|
271
|
+
In the latest version you can also directly pass numpy arrays for gain,
|
|
272
|
+
theta, and phi angles, angles are in degrees::
|
|
273
|
+
|
|
274
|
+
import numpy as np
|
|
275
|
+
from plot_antenna import plot_antenna
|
|
276
|
+
|
|
277
|
+
# Compute args, see below
|
|
278
|
+
frequency = 430.0
|
|
279
|
+
polarization = 'sum'
|
|
280
|
+
key = (frequency, polarization)
|
|
281
|
+
thetas = np.arange (0, 181, 10)
|
|
282
|
+
phis = np.arange (0, 361, 10)
|
|
283
|
+
gains = np.zeros ((19, 37))
|
|
284
|
+
gdict = {key: plot_antenna.Gain_Data.from_gains (key, gains, thetas, phis)}
|
|
243
285
|
gp = plot_antenna.Gain_Plot (args, gdict)
|
|
244
286
|
gp.compute ()
|
|
245
287
|
gp.plot ()
|
|
@@ -258,14 +300,18 @@ line arguments but can be called with an empty string list, e.g.::
|
|
|
258
300
|
args.filename = ''
|
|
259
301
|
# Title
|
|
260
302
|
args.title = 'My Title'
|
|
261
|
-
# We want an azimuth plot
|
|
262
|
-
args.azimuth = True
|
|
263
303
|
# We might want to ship result to running browser with plotly
|
|
264
304
|
# args.show_in_browser = True
|
|
305
|
+
# If we want to do a 3d-plot we set args.plot3d, we could also set
|
|
306
|
+
# args.azimuth to get an azimuth plot. Both variables can be set and
|
|
307
|
+
# we get both plots (one after the other with matplotlib, both in
|
|
308
|
+
# different browser windows with plotly)
|
|
309
|
+
args.azimuth = False
|
|
310
|
+
args.plot3d = True
|
|
265
311
|
|
|
266
312
|
The ``cmd`` variable is a python ``ArgumentParser`` object. So if you
|
|
267
313
|
are parsing command line arguments you can add your own options before
|
|
268
|
-
calling ``process_args
|
|
314
|
+
calling ``process_args``.
|
|
269
315
|
|
|
270
316
|
If not parsing argument from the command line and arguments should be
|
|
271
317
|
changed this can be done by directly modifying args, e.g.::
|
|
@@ -287,6 +333,30 @@ the companion program for reading EZNEC data in
|
|
|
287
333
|
Release Notes
|
|
288
334
|
-------------
|
|
289
335
|
|
|
336
|
+
v2.4: Bug-fixes, coordinate transformation
|
|
337
|
+
|
|
338
|
+
- Fix max theta gain computation: We need to take *both sides of phi*
|
|
339
|
+
into account
|
|
340
|
+
- Allow to directly pass numpy arrays in API
|
|
341
|
+
- Coordinate transform for a contributed setup for a measurement device
|
|
342
|
+
- Update tests for debian trixie, in particular use better font defaults
|
|
343
|
+
that are more likely to be the same on multiple architectures
|
|
344
|
+
|
|
345
|
+
v2.3: Fix nec geo computation
|
|
346
|
+
|
|
347
|
+
- Fix a bug when parsing NEC geo info, in particular back-references in
|
|
348
|
+
geometry segments
|
|
349
|
+
- Update tests for recent changes, unfortunately the plotly PNG pics
|
|
350
|
+
seem not to be reproduceable across different installations of the
|
|
351
|
+
same plotly version
|
|
352
|
+
|
|
353
|
+
v2.2: Fix radial axis range of polar plots
|
|
354
|
+
|
|
355
|
+
- Polar plots were scaled differently depending on data, we now force
|
|
356
|
+
the polar axis range to a maximum of 1.01 (on both, matplotlib and
|
|
357
|
+
plotly backends) so that the trace(s) always fit without truncating
|
|
358
|
+
the trace at the boundary
|
|
359
|
+
|
|
290
360
|
v2.1: Scale by angle
|
|
291
361
|
|
|
292
362
|
- New option ``--scale-by-angle`` that allows to scale the azimuth or
|
plot_antenna-2.4/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION="2.4"
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
|
|
3
|
+
# Parsers for contributed data structures
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import numpy as np
|
|
7
|
+
from csv import DictReader
|
|
8
|
+
from . import plot_antenna as aplot
|
|
9
|
+
|
|
10
|
+
def coordinate_transform (gd):
|
|
11
|
+
""" Coordinate transformation on gain data: The measurement
|
|
12
|
+
describes a great circle for each elevation, so the 'poles' are
|
|
13
|
+
on the axis of the positioner. The positioner axis becomes the
|
|
14
|
+
new Z axis and new elevations are the azimuth values. The new
|
|
15
|
+
azimuths are computed from the elevations.
|
|
16
|
+
"""
|
|
17
|
+
t = gd.phis_d [gd.phis_d <= 180]
|
|
18
|
+
p = sorted (list (set (gd.thetas_d).union (gd.thetas_d + 180)))
|
|
19
|
+
if p [-1] != 360.:
|
|
20
|
+
p.append (360.)
|
|
21
|
+
otl = gd.thetas_d.shape [0]
|
|
22
|
+
if gd.thetas_d [otl - 1] != 180:
|
|
23
|
+
otl += 1
|
|
24
|
+
p = np.array (p)
|
|
25
|
+
ng = np.zeros ((len (t), len (p)))
|
|
26
|
+
opl = gd.phis_d.shape [0]
|
|
27
|
+
for nth, theta in enumerate (t):
|
|
28
|
+
for nph, phi in enumerate (p):
|
|
29
|
+
if phi <= 180:
|
|
30
|
+
oth = nph
|
|
31
|
+
oph = nth
|
|
32
|
+
else:
|
|
33
|
+
oth = nph - (p.shape [0] // 2)
|
|
34
|
+
oph = opl - nth - 1
|
|
35
|
+
if oth == gd.gains.shape [0]:
|
|
36
|
+
# This happens only when 180° is missing for positioner
|
|
37
|
+
ng [nth, nph] = gd.gains [0, opl - oph - 1]
|
|
38
|
+
else:
|
|
39
|
+
ng [nth, nph] = gd.gains [oth, oph]
|
|
40
|
+
gd.gains = ng
|
|
41
|
+
gd.phis_d = p
|
|
42
|
+
gd.thetas_d = t
|
|
43
|
+
gd.phis = p * np.pi / 180
|
|
44
|
+
gd.thetas = t * np.pi / 180
|
|
45
|
+
# end def coordinate_transform
|
|
46
|
+
|
|
47
|
+
def parse_csv_measurement_data (args):
|
|
48
|
+
""" Parses measurement data from CSV file
|
|
49
|
+
This has the columns:
|
|
50
|
+
- Messwert: The measurement
|
|
51
|
+
May also be called 'eirp' or 'eirp (dBm)'
|
|
52
|
+
- Einheit Messwert: Unit of the measurement (e.g. dBm)
|
|
53
|
+
This can also be called "Einheit eirp"
|
|
54
|
+
Or we have a column 'eirp (dBm)' above and the column with the
|
|
55
|
+
unit is missing
|
|
56
|
+
- Position Drehscheibe: Azimuth angle
|
|
57
|
+
also called Position Drehscheibe (deg)
|
|
58
|
+
- Position Positionierer: Elevation angle
|
|
59
|
+
also seen as Position Positioner
|
|
60
|
+
or Position Positioner (deg)
|
|
61
|
+
- Polarisation: 'PH' for horizontal, 'PV' for vertical polarization
|
|
62
|
+
- Messfrequenz: frequency
|
|
63
|
+
For an example see test/Messdaten.csv
|
|
64
|
+
The format has the following peculiarities:
|
|
65
|
+
- The elevation angles slightly vary for a single azimuth scan.
|
|
66
|
+
This means we may have 10° and some values at 10.1°. Since the
|
|
67
|
+
elevation angle steps are 10° we round to the nearest integer.
|
|
68
|
+
- Azimuth is scanned continuously, so azimuth angles do not
|
|
69
|
+
match at all for two different elevation angles. This still
|
|
70
|
+
means we can plot an azimuth polarization diagram. But for
|
|
71
|
+
elevation or 3d plots we need to interpolate the azimuth
|
|
72
|
+
angles. For this the --interpolate-azimuth-step option was
|
|
73
|
+
added. Typically we interpolate the azimuth values to e.g. a
|
|
74
|
+
2° grid.
|
|
75
|
+
- Some azimuth angles are greater than 360°.
|
|
76
|
+
"""
|
|
77
|
+
# We always need to interpolate to do the coordinate transformation
|
|
78
|
+
# And we fix this to 1° for ease of coordinate transform
|
|
79
|
+
if args.interpolate_azimuth_step is None:
|
|
80
|
+
args.interpolate_azimuth_step = 1
|
|
81
|
+
gdata_dict = {}
|
|
82
|
+
with open (args.filename, 'r') as f:
|
|
83
|
+
dr = DictReader (f, delimiter = ';')
|
|
84
|
+
for rec in dr:
|
|
85
|
+
for m in ('Einheit Messwert', 'Einheit eirp'):
|
|
86
|
+
try:
|
|
87
|
+
args.dB_unit = rec [m]
|
|
88
|
+
break
|
|
89
|
+
except KeyError:
|
|
90
|
+
pass
|
|
91
|
+
else:
|
|
92
|
+
if 'eirp (dBm)' in rec:
|
|
93
|
+
args.dB_unit = 'dBm'
|
|
94
|
+
# Frequency: The internal representation is in MHz, so we
|
|
95
|
+
# multiply by 1e3 because the values are in GHz.
|
|
96
|
+
try:
|
|
97
|
+
f = float (rec ['Messfrequenz']) * 1e3
|
|
98
|
+
except KeyError:
|
|
99
|
+
f = float (rec ['Messfrequenz (GHz)']) * 1e3
|
|
100
|
+
if f not in gdata_dict:
|
|
101
|
+
p = rec ['Polarisation'][1:]
|
|
102
|
+
k = (f, p)
|
|
103
|
+
if k not in gdata_dict:
|
|
104
|
+
gdata_dict [k] = aplot.Gain_Data \
|
|
105
|
+
(k, transform = coordinate_transform)
|
|
106
|
+
gdata = gdata_dict [k]
|
|
107
|
+
for ds in ('Position Drehscheibe', 'Position Drehscheibe (deg)'):
|
|
108
|
+
try:
|
|
109
|
+
azi = float (rec [ds])
|
|
110
|
+
if args.invert_turntable:
|
|
111
|
+
azi = -azi
|
|
112
|
+
azi = (azi + args.turntable_offset) % 360
|
|
113
|
+
break
|
|
114
|
+
except KeyError:
|
|
115
|
+
pass
|
|
116
|
+
else:
|
|
117
|
+
raise ValueError ('No column "Position Drehscheibe"')
|
|
118
|
+
# Need to round elevation values: these sometimes differ
|
|
119
|
+
# during a scan
|
|
120
|
+
p = ( 'Position Positionierer', 'Position Positioner'
|
|
121
|
+
, 'Position Positioner (deg)'
|
|
122
|
+
)
|
|
123
|
+
for k in p:
|
|
124
|
+
try:
|
|
125
|
+
ele = float (rec [k])
|
|
126
|
+
if args.invert_positioner:
|
|
127
|
+
ele = -ele
|
|
128
|
+
ele %= 360
|
|
129
|
+
break
|
|
130
|
+
except KeyError:
|
|
131
|
+
pass
|
|
132
|
+
else:
|
|
133
|
+
raise ValueError ('No column "Position Positioner"')
|
|
134
|
+
if args.round_positioner:
|
|
135
|
+
rel = args.round_positioner
|
|
136
|
+
ele = round (ele / rel, 0) * rel
|
|
137
|
+
# Don't allow values outside angle range
|
|
138
|
+
if azi < 0 or azi > 360 or ele < 0 or ele > 360:
|
|
139
|
+
continue
|
|
140
|
+
# We treat the value as 'dBi' although this is dBm
|
|
141
|
+
# Probably needs conversion but we may get away with
|
|
142
|
+
# allowing a unit to be specified for the plot, it must be a
|
|
143
|
+
# dezibel value, though (not linear gain or so)
|
|
144
|
+
for k in ('Messwert', 'eirp', 'eirp (dBm)'):
|
|
145
|
+
try:
|
|
146
|
+
gain = float (rec [k])
|
|
147
|
+
break
|
|
148
|
+
except KeyError:
|
|
149
|
+
pass
|
|
150
|
+
else:
|
|
151
|
+
raise ValueError ('No column "eirp" or similar')
|
|
152
|
+
gdata.pattern [(ele, azi)] = gain
|
|
153
|
+
return gdata_dict
|
|
154
|
+
# end def parse_csv_measurement_data
|
|
155
|
+
|
|
156
|
+
def main_csv_measurement_data (argv = sys.argv [1:], pic_io = None):
|
|
157
|
+
""" Parse a contributed measurement format, see docstring of
|
|
158
|
+
parse_csv_measurement_data.
|
|
159
|
+
The pic_io argument is for testing.
|
|
160
|
+
"""
|
|
161
|
+
cmd = aplot.options_general ()
|
|
162
|
+
aplot.options_gain (cmd)
|
|
163
|
+
cmd.add_argument ('filename', help = 'CSV File to parse and plot')
|
|
164
|
+
cmd.add_argument \
|
|
165
|
+
( '--round-positioner'
|
|
166
|
+
, help = "Round positioner angle to this many degrees"
|
|
167
|
+
, type = int
|
|
168
|
+
)
|
|
169
|
+
cmd.add_argument \
|
|
170
|
+
( '--turntable-offset'
|
|
171
|
+
, help = "Offset in degrees of the turntable, default=%(default)s"
|
|
172
|
+
, type = float
|
|
173
|
+
, default = 0.0
|
|
174
|
+
)
|
|
175
|
+
cmd.add_argument \
|
|
176
|
+
( '--invert-turntable'
|
|
177
|
+
, help = "Invert turntable angles, default False"
|
|
178
|
+
, action = 'store_true'
|
|
179
|
+
)
|
|
180
|
+
cmd.add_argument \
|
|
181
|
+
( '--invert-positioner'
|
|
182
|
+
, help = "Invert positioner angles, default False"
|
|
183
|
+
, action = 'store_true'
|
|
184
|
+
)
|
|
185
|
+
args = aplot.process_args (cmd, argv)
|
|
186
|
+
# Set default polarization, we need this otherwise the sum isn't computed
|
|
187
|
+
if not args.polarization:
|
|
188
|
+
args.polarization ['sum'] = True
|
|
189
|
+
if pic_io is not None:
|
|
190
|
+
args.output_file = pic_io
|
|
191
|
+
args.save_format = 'png'
|
|
192
|
+
gdata = parse_csv_measurement_data (args)
|
|
193
|
+
gp = aplot.Gain_Plot (args, gdata)
|
|
194
|
+
gp.compute ()
|
|
195
|
+
if 0:
|
|
196
|
+
# Try find (old) azimuth where only the polarization changes
|
|
197
|
+
# This assumes that the phi angles are the same for H and V
|
|
198
|
+
keys = list (gp.gdata)
|
|
199
|
+
key = None
|
|
200
|
+
for k in keys:
|
|
201
|
+
if len (k) == 2 and k [1] == 'sum':
|
|
202
|
+
key = k
|
|
203
|
+
break
|
|
204
|
+
if key is not None:
|
|
205
|
+
stat = {}
|
|
206
|
+
for oph, phi in enumerate (gp.gdata [key].phis_d):
|
|
207
|
+
gbp = []
|
|
208
|
+
for oth, theta in enumerate (gp.gdata [key].thetas_d):
|
|
209
|
+
gbp.append (gp.gdata [key].gains [oth, oph])
|
|
210
|
+
gbp = np.array (gbp)
|
|
211
|
+
stat [phi] = (np.average (gbp), np.std (gbp))
|
|
212
|
+
for k in stat:
|
|
213
|
+
print ("%3g: avg: %g std: %g cv: %g" % (k, stat [k][0],
|
|
214
|
+
stat [k][1], stat [k][1] / abs (stat [k][0])))
|
|
215
|
+
|
|
216
|
+
gp.plot ()
|
|
217
|
+
# end def main_csv_measurement_data
|
|
218
|
+
|
|
219
|
+
if __name__ == '__main__':
|
|
220
|
+
main_csv_measurement_data ()
|