pyfers 1.0.0__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.
pyfers-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyfers
3
+ Version: 1.0.0
4
+ Summary: XML generator for FERS
5
+ Home-page: https://github.com/darrynjordan/FERS
6
+ Author: Darryn Anton Jordan
7
+ Author-email: <darrynjordan@icloud.com>
8
+ License: UNKNOWN
9
+ Keywords: radar,simulation,fers,uct
10
+ Platform: UNKNOWN
11
+ Classifier: Development Status :: 1 - Planning
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: Unix
15
+ Classifier: Operating System :: MacOS :: MacOS X
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Description-Content-Type: text/markdown
18
+
19
+ # pyfers
20
+ Python package that enables simple generation of XML descriptors required by FERS.
21
+
22
+ ## Install
23
+ ```
24
+ pip3 install pyfers
25
+ ```
26
+
27
+ ## Examples
28
+ ```
29
+ ```
30
+
31
+
pyfers-1.0.0/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # pyfers
2
+ Python package that enables simple generation of XML descriptors required by FERS.
3
+
4
+ ## Install
5
+ ```
6
+ pip3 install pyfers
7
+ ```
8
+
9
+ ## Examples
10
+ ```
11
+ ```
@@ -0,0 +1 @@
1
+ from pyfers.fers import FersXMLGenerator
@@ -0,0 +1,347 @@
1
+ import os
2
+ import h5py
3
+ import numpy as np
4
+ import subprocess as sbp
5
+ import matplotlib.pyplot as f
6
+ import scipy.constants as const
7
+
8
+ from xml.etree.ElementTree import Element, SubElement
9
+ from xml.etree.ElementTree import ElementTree as Tree
10
+ from xml.etree import ElementTree
11
+ from xml.dom import minidom
12
+
13
+ def prettify_xml(elem):
14
+ """
15
+ Return a pretty-printed XML string for the Element.
16
+ """
17
+ rough_string = ElementTree.tostring(elem, 'utf-8')
18
+ reparsed = minidom.parseString(rough_string)
19
+ return reparsed.toprettyxml(indent=" ")
20
+
21
+ def write_hdf5(dataset, filename):
22
+ '''
23
+ Write IQ data to an HDF5 file.
24
+ '''
25
+ h5 = h5py.File(filename, 'w')
26
+ h5.create_dataset('/I/value', data=np.real(dataset))
27
+ h5.create_dataset('/Q/value', data=np.imag(dataset))
28
+ h5.close()
29
+
30
+
31
+ def read_hdf5(filename):
32
+ '''
33
+ Read IQ data from an HDF5 file.
34
+ '''
35
+ if (os.path.exists(filename) == False):
36
+ print("HDF5 file not found. Please check the path.")
37
+ exit()
38
+
39
+ h5 = h5py.File(filename, 'r')
40
+
41
+ dataset_list = list(h5.keys())
42
+
43
+ # read attributes
44
+ # attribute_list = h5[dataset_list[0]].attrs.keys()
45
+ # for attr in attribute_list:
46
+ # print(attr, h5[dataset_list[0]].attrs[attr])
47
+
48
+ scale = np.float64(h5[dataset_list[0]].attrs['fullscale'])
49
+ # rate = np.float64(h5[dataset_list[0]].attrs['rate'])
50
+ # time = np.float64(h5[dataset_list[0]].attrs['time'])
51
+
52
+ n_pulses = int(np.floor(np.size(dataset_list)/2))
53
+ ns_pulse = int(np.size(h5[dataset_list[0]]))
54
+
55
+ i_matrix = np.zeros((n_pulses, ns_pulse), dtype='float64')
56
+ q_matrix = np.zeros((n_pulses, ns_pulse), dtype='float64')
57
+
58
+ for i in range(0, n_pulses):
59
+ i_matrix[i, :] = np.array(h5[dataset_list[2*i + 0]], dtype='float64')
60
+ q_matrix[i, :] = np.array(h5[dataset_list[2*i + 1]], dtype='float64')
61
+
62
+ dataset = np.array(i_matrix + 1j*q_matrix).astype('complex128')
63
+
64
+ dataset *= scale
65
+
66
+ return dataset
67
+
68
+
69
+ class FersXMLGenerator:
70
+ def __init__(self, xml_filename):
71
+ """
72
+ FersXMLGenerator constructor.
73
+ """
74
+ self.filename = xml_filename
75
+ self.simulation = Element('simulation')
76
+ self.simulation.set('name', 'milosar')
77
+ self.tree = Tree(self.simulation)
78
+
79
+ def add_parameters(self, t_start, t_end, sim_rate, bits, over_sample=1, interp_rate=1000):
80
+ parameters = SubElement(self.simulation, 'parameters')
81
+
82
+ starttime = SubElement(parameters, 'starttime')
83
+ starttime.text = str(t_start)
84
+
85
+ endtime = SubElement(parameters, 'endtime')
86
+ endtime.text = str(t_end)
87
+
88
+ rate = SubElement(parameters, 'rate')
89
+ rate.text = str(sim_rate)
90
+
91
+ adc_bits = SubElement(parameters, 'adc_bits')
92
+ adc_bits.text = str(bits)
93
+
94
+ oversample = SubElement(parameters, 'oversample')
95
+ oversample.text = str(over_sample)
96
+
97
+ interprate = SubElement(parameters, 'interprate')
98
+ interprate.text = str(interp_rate)
99
+
100
+ light_speed = SubElement(parameters, 'c')
101
+ light_speed.text = str(const.speed_of_light)
102
+
103
+ def add_pulse(self, name, pulse_file, power_watts, centre_freq):
104
+ pulse = SubElement(self.simulation, 'pulse')
105
+ pulse.set('name', name)
106
+ pulse.set('type', 'file')
107
+ pulse.set('filename', pulse_file)
108
+
109
+ power = SubElement(pulse, 'power')
110
+ power.text = str(power_watts)
111
+
112
+ carrier = SubElement(pulse, 'carrier')
113
+ carrier.text = str(centre_freq)
114
+
115
+ def add_clock(self, name, frequency, f_offset=0, random_f_offset=0, p_offset=0, random_p_offset=0, synconpulse='true'):
116
+ timing = SubElement(self.simulation, 'timing')
117
+ timing.set('name', name)
118
+ timing.set('synconpulse', synconpulse)
119
+
120
+ freq = SubElement(timing, 'frequency')
121
+ freq.text = str(frequency)
122
+
123
+ freq_offset = SubElement(timing, 'freq_offset')
124
+ freq_offset.text = str(f_offset)
125
+
126
+ random_freq_offset = SubElement(timing, 'random_freq_offset')
127
+ random_freq_offset.text = str(random_f_offset)
128
+
129
+ phase_offset = SubElement(timing, 'phase_offset')
130
+ phase_offset.text = str(p_offset)
131
+
132
+ random_phase_offset = SubElement(timing, 'random_phase_offset')
133
+ random_phase_offset.text = str(random_p_offset)
134
+
135
+ # add_noise(timing, -2, 1e-6)
136
+ # add_noise(timing, -1, 1e-6)
137
+ # add_noise(timing, 0, 1e-6)
138
+ # add_noise(timing, 1, 1e-6)
139
+ # add_noise(timing, 2, 1e-6)
140
+
141
+
142
+ def add_antenna(self, name, pattern, eff=1, a=1, b=2, g=5, d=0.1, is_plot=False, is_norm=False, n_points=1000, dB_range=40):
143
+ antenna = SubElement(self.simulation, 'antenna')
144
+ antenna.set('name', name)
145
+ antenna.set('pattern', pattern)
146
+
147
+ efficiency = SubElement(antenna, 'efficiency')
148
+ efficiency.text = str(eff)
149
+
150
+ if (pattern == "parabolic"):
151
+ diameter = SubElement(antenna, 'diameter')
152
+ diameter.text = str(d)
153
+
154
+ if (pattern == "sinc"):
155
+ alpha = SubElement(antenna, 'alpha')
156
+ alpha.text = str(a)
157
+
158
+ beta = SubElement(antenna, 'beta')
159
+ beta.text = str(b)
160
+
161
+ gamma = SubElement(antenna, 'gamma')
162
+ gamma.text = str(g)
163
+
164
+ if (is_plot):
165
+ theta = np.linspace(-np.pi, np.pi, n_points)
166
+ G = a*pow((np.sin(b*theta)/(b*theta)), g)
167
+ G = 10*np.log10(abs(G))
168
+
169
+ if (is_norm):
170
+ G = G - np.nanmax(G)
171
+
172
+ ax = plt.subplot(1, 1, 1, projection='polar')
173
+ ax.plot(theta, G)
174
+
175
+ half_power_indx = find_nearest_index(G[0 : n_points//2], max(G) - 3)
176
+ ax.plot(theta[half_power_indx], G[half_power_indx], 'ro')
177
+ ax.plot((0, theta[half_power_indx]), (-dB_range, G[half_power_indx]), 'r')
178
+
179
+ half_power_indx = find_nearest_index(G[n_points//2 : n_points], max(G) - 3) + n_points//2
180
+ ax.plot(theta[half_power_indx], G[half_power_indx], 'ro')
181
+ ax.plot((0, theta[half_power_indx]), (-dB_range, G[half_power_indx]), 'r')
182
+
183
+ ax.set_title('Antenna Radiation Pattern')
184
+ ax.set_theta_zero_location('N')
185
+ ax.set_ylim(-dB_range, round_nearest(max(G), 10))
186
+ ax.set_rlabel_position(292.5)
187
+ ax.annotate('HPBW\n' + str(np.around(360*theta[half_power_indx]/np.pi, 2)) + '°', xy=(0, G[half_power_indx]), horizontalalignment='center', verticalalignment='top')
188
+ ax.grid(True)
189
+ plt.draw()
190
+
191
+ def add_monostatic_radar(self, waypoints, antenna, timing, prf, pulse, window_length, noise_temp=290, window_skip=0, tx_type='pulsed'):
192
+ platform = add_platform('radar_platform', self.simulation)
193
+ path = add_path(platform)
194
+ add_rotation(platform)
195
+
196
+ for i in range (0, int(np.size(waypoints, axis=1))):
197
+ add_point(path, waypoints[0, i], waypoints[1, i], waypoints[2, i], waypoints[3, i])
198
+
199
+ add_monostatic(platform, 'receiver', tx_type, antenna, pulse, timing, prf, window_length, noise_temp, window_skip)
200
+
201
+ def add_pseudo_monostatic_radar(self, spacing, waypoints, antenna, timing, prf, pulse, window_length, noise_temp=290, window_skip=0, tx_type='pulsed', nodirect='false', nopropagationloss='false'):
202
+ tx_platform = add_platform('tx_platform', self.simulation)
203
+ rx_platform = add_platform('rx_platform', self.simulation)
204
+ tx_path = add_path(tx_platform)
205
+ rx_path = add_path(rx_platform)
206
+ add_rotation(tx_platform)
207
+ add_rotation(rx_platform)
208
+
209
+ for i in range (0, int(np.size(waypoints, axis=1))):
210
+ add_point(tx_path, waypoints[0, i] + spacing[0]/2, waypoints[1, i] + spacing[1]/2, waypoints[2, i] + spacing[2]/2, waypoints[3, i])
211
+ add_point(rx_path, waypoints[0, i] - spacing[0]/2, waypoints[1, i] - spacing[1]/2, waypoints[2, i] - spacing[2]/2, waypoints[3, i])
212
+
213
+ add_transmitter(tx_platform, 'transmitter', tx_type, antenna, pulse, timing, prf)
214
+ add_receiver(rx_platform, 'receiver', nodirect, antenna, nopropagationloss, timing, prf, window_length, noise_temp, window_skip)
215
+
216
+ def add_target(self, name, x, y, z, t, rcs):
217
+ platform = add_platform('target_platform', self.simulation)
218
+ path = add_path(platform)
219
+ add_rotation(platform)
220
+
221
+ for i in range (0, int(np.size(x))):
222
+ add_point(path, x[i], y[i], z[i], t[i])
223
+
224
+ target = SubElement(platform, 'target')
225
+ target.set('name', name)
226
+
227
+ t_rcs = SubElement(target, 'rcs')
228
+ t_rcs.set('type', 'isotropic')
229
+
230
+ t_rcs_v = SubElement(t_rcs, 'value')
231
+ t_rcs_v.text = str(rcs)
232
+
233
+ def write_xml(self):
234
+ self.tree.write(self.filename)
235
+
236
+ my_file = open(self.filename, "w")
237
+ my_file.write(prettify_xml(self.simulation))
238
+ my_file.close()
239
+
240
+ def run(self):
241
+ # print('Launching FERS:', self.filename)
242
+ try:
243
+ sbp.run(['fers', 'sim.fersxml'])
244
+ except:
245
+ print('ERROR: failed to launch - check that FERS is installed correctly.')
246
+ exit(1)
247
+
248
+ def add_monostatic(platform, name, tx_type, antenna, pulse, timing, prf, window_length, noise_temp=290, window_skip=0):
249
+ monostatic = SubElement(platform, 'monostatic')
250
+ monostatic.set('name', name)
251
+ monostatic.set('type', tx_type)
252
+ monostatic.set('antenna', antenna)
253
+ monostatic.set('pulse', pulse)
254
+ monostatic.set('timing', timing)
255
+
256
+ skip = SubElement(monostatic, 'window_skip')
257
+ skip.text = str(window_skip)
258
+
259
+ window = SubElement(monostatic, 'window_length')
260
+ window.text = str(window_length)
261
+
262
+ rx_prf = SubElement(monostatic, 'prf')
263
+ rx_prf.text = str(prf)
264
+
265
+ noise = SubElement(monostatic, 'noise_temp')
266
+ noise.text = str(noise_temp)
267
+
268
+ def add_transmitter (platform, name, tx_type, antenna, pulse, timing, prf):
269
+ transmitter = SubElement(platform, 'transmitter')
270
+ transmitter.set('name', name)
271
+ transmitter.set('type', tx_type)
272
+ transmitter.set('antenna', antenna)
273
+ transmitter.set('pulse', pulse)
274
+ transmitter.set('timing', timing)
275
+
276
+ tx_prf = SubElement(transmitter, 'prf')
277
+ tx_prf.text = str(prf)
278
+
279
+ def add_receiver (platform, name, nodirect, antenna, nopropagationloss, timing, prf, window_length, noise_temp=290, window_skip=0):
280
+ receiver = SubElement(platform, 'receiver')
281
+ receiver.set('name', name)
282
+ receiver.set('nodirect', nodirect)
283
+ receiver.set('antenna', antenna)
284
+ receiver.set('nopropagationloss', nopropagationloss)
285
+ receiver.set('timing', timing)
286
+
287
+ skip = SubElement(receiver, 'window_skip')
288
+ skip.text = str(window_skip)
289
+
290
+ window = SubElement(receiver, 'window_length')
291
+ window.text = str(window_length)
292
+
293
+ rx_prf = SubElement(receiver, 'prf')
294
+ rx_prf.text = str(prf)
295
+
296
+ noise = SubElement(receiver, 'noise_temp')
297
+ noise.text = str(noise_temp)
298
+
299
+ def add_platform (name, root):
300
+ platform = SubElement(root, 'platform')
301
+ platform.set('name', name)
302
+ return platform
303
+
304
+ def add_path (platform, interp='linear'):
305
+ path = SubElement(platform, 'motionpath')
306
+ path.set('interpolation', interp)
307
+ return path
308
+
309
+ def add_point(path, x, y, z, t):
310
+ point = SubElement(path, 'positionwaypoint')
311
+
312
+ t_x = SubElement(point, 'x')
313
+ t_x.text = str(x)
314
+
315
+ t_y = SubElement(point, 'y')
316
+ t_y.text = str(y)
317
+
318
+ t_a = SubElement(point, 'altitude')
319
+ t_a.text = str(z)
320
+
321
+ t_t = SubElement(point, 'time')
322
+ t_t.text = str(t)
323
+
324
+ def add_rotation(platform, s_az=2*np.pi, az_rate=0, s_el=2*np.pi, el_rate=0):
325
+ rotation = SubElement(platform, 'fixedrotation')
326
+
327
+ t_s_az = SubElement(rotation, 'startazimuth')
328
+ t_s_az.text = str(s_az)
329
+
330
+ t_az_r = SubElement(rotation, 'azimuthrate')
331
+ t_az_r.text = str(az_rate)
332
+
333
+ t_s_el = SubElement(rotation, 'startelevation')
334
+ t_s_el.text = str(s_el)
335
+
336
+ t_el_r = SubElement(rotation, 'elevationrate')
337
+ t_el_r.text = str(el_rate)
338
+
339
+
340
+ def add_noise(clock, alpha, weight):
341
+ noise_entry = SubElement(clock, 'noise_entry')
342
+
343
+ t_alpha = SubElement(noise_entry, 'alpha')
344
+ t_alpha.text = str(alpha)
345
+
346
+ t_weight = SubElement(noise_entry, 'weight')
347
+ t_weight.text = str(weight)
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyfers
3
+ Version: 1.0.0
4
+ Summary: XML generator for FERS
5
+ Home-page: https://github.com/darrynjordan/FERS
6
+ Author: Darryn Anton Jordan
7
+ Author-email: <darrynjordan@icloud.com>
8
+ License: UNKNOWN
9
+ Keywords: radar,simulation,fers,uct
10
+ Platform: UNKNOWN
11
+ Classifier: Development Status :: 1 - Planning
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: Unix
15
+ Classifier: Operating System :: MacOS :: MacOS X
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Description-Content-Type: text/markdown
18
+
19
+ # pyfers
20
+ Python package that enables simple generation of XML descriptors required by FERS.
21
+
22
+ ## Install
23
+ ```
24
+ pip3 install pyfers
25
+ ```
26
+
27
+ ## Examples
28
+ ```
29
+ ```
30
+
31
+
@@ -0,0 +1,9 @@
1
+ README.md
2
+ setup.py
3
+ pyfers/__init__.py
4
+ pyfers/fers.py
5
+ pyfers.egg-info/PKG-INFO
6
+ pyfers.egg-info/SOURCES.txt
7
+ pyfers.egg-info/dependency_links.txt
8
+ pyfers.egg-info/requires.txt
9
+ pyfers.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ h5py
2
+ numpy
3
+ scipy
@@ -0,0 +1 @@
1
+ pyfers
pyfers-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
pyfers-1.0.0/setup.py ADDED
@@ -0,0 +1,26 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name="pyfers",
8
+ version='1.0.0',
9
+ author="Darryn Anton Jordan",
10
+ author_email="<darrynjordan@icloud.com>",
11
+ description='XML generator for FERS',
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ packages=find_packages(),
15
+ install_requires=['numpy', 'h5py', 'scipy'],
16
+ keywords=['radar', 'simulation', 'fers', 'uct'],
17
+ url="https://github.com/darrynjordan/FERS",
18
+ classifiers=[
19
+ "Development Status :: 1 - Planning",
20
+ "Intended Audience :: Developers",
21
+ "Programming Language :: Python :: 3",
22
+ "Operating System :: Unix",
23
+ "Operating System :: MacOS :: MacOS X",
24
+ "Operating System :: Microsoft :: Windows",
25
+ ]
26
+ )