##// END OF EJS Templates
Update RC API methods...
Juan C. Espinoza -
r222:547f05cc34b8
parent child
Show More
@@ -1,927 +1,952
1
1
2 import ast
2 import ast
3 import json
3 import json
4 import requests
4 import requests
5 import numpy as np
5 import numpy as np
6 from base64 import b64encode
6 from base64 import b64encode
7 from struct import pack
7 from struct import pack
8
8
9 from django.db import models
9 from django.db import models
10 from django.core.urlresolvers import reverse
10 from django.core.urlresolvers import reverse
11 from django.core.validators import MinValueValidator, MaxValueValidator
11 from django.core.validators import MinValueValidator, MaxValueValidator
12
12
13 from apps.main.models import Configuration
13 from apps.main.models import Configuration
14 from devices.rc import api
14 from devices.rc import api
15 from .utils import RCFile
15 from .utils import RCFile
16
16
17 # Create your models here.
17 # Create your models here.
18
18
19 LINE_TYPES = (
19 LINE_TYPES = (
20 ('none', 'Not used'),
20 ('none', 'Not used'),
21 ('tr', 'Transmission/reception selector signal'),
21 ('tr', 'Transmission/reception selector signal'),
22 ('tx', 'A modulating signal (Transmission pulse)'),
22 ('tx', 'A modulating signal (Transmission pulse)'),
23 ('codes', 'BPSK modulating signal'),
23 ('codes', 'BPSK modulating signal'),
24 ('windows', 'Sample window signal'),
24 ('windows', 'Sample window signal'),
25 ('sync', 'Synchronizing signal'),
25 ('sync', 'Synchronizing signal'),
26 ('flip', 'IPP related periodic signal'),
26 ('flip', 'IPP related periodic signal'),
27 ('prog_pulses', 'Programmable pulse'),
27 ('prog_pulses', 'Programmable pulse'),
28 ('mix', 'Mixed line'),
28 ('mix', 'Mixed line'),
29 )
29 )
30
30
31
31
32 SAMPLING_REFS = (
32 SAMPLING_REFS = (
33 ('none', 'No Reference'),
33 ('none', 'No Reference'),
34 ('begin_baud', 'Begin of the first baud'),
34 ('begin_baud', 'Begin of the first baud'),
35 ('first_baud', 'Middle of the first baud'),
35 ('first_baud', 'Middle of the first baud'),
36 ('sub_baud', 'Middle of the sub-baud')
36 ('sub_baud', 'Middle of the sub-baud')
37 )
37 )
38
38
39 DAT_CMDS = {
39 DAT_CMDS = {
40 # Pulse Design commands
40 # Pulse Design commands
41 'DISABLE' : 0, # Disables pulse generation
41 'DISABLE' : 0, # Disables pulse generation
42 'ENABLE' : 24, # Enables pulse generation
42 'ENABLE' : 24, # Enables pulse generation
43 'DELAY_START' : 40, # Write delay status to memory
43 'DELAY_START' : 40, # Write delay status to memory
44 'FLIP_START' : 48, # Write flip status to memory
44 'FLIP_START' : 48, # Write flip status to memory
45 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
45 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
46 'TX_ONE' : 72, # Output '0' in line TX
46 'TX_ONE' : 72, # Output '0' in line TX
47 'TX_ZERO' : 88, # Output '0' in line TX
47 'TX_ZERO' : 88, # Output '0' in line TX
48 'SW_ONE' : 104, # Output '0' in line SW
48 'SW_ONE' : 104, # Output '0' in line SW
49 'SW_ZERO' : 112, # Output '1' in line SW
49 'SW_ZERO' : 112, # Output '1' in line SW
50 'RESTART': 120, # Restarts CR8 Firmware
50 'RESTART': 120, # Restarts CR8 Firmware
51 'CONTINUE' : 253, # Function Unknown
51 'CONTINUE' : 253, # Function Unknown
52 # Commands available to new controllers
52 # Commands available to new controllers
53 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
53 # In Pulse Design Executable, the clock divisor code is written as 12 at the start, but it should be written as code 22(below) just before the final enable.
54 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
54 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
55 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
55 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
56 'CLOCK_DIVIDER' : 8,
56 'CLOCK_DIVIDER' : 8,
57 }
57 }
58
58
59
59
60 class RCConfiguration(Configuration):
60 class RCConfiguration(Configuration):
61
61
62 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
62 ipp = models.FloatField(verbose_name='IPP [Km]', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
63 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(400)], default=1)
63 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(400)], default=1)
64 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
64 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
65 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
65 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
66 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
66 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
67 time_before = models.PositiveIntegerField(verbose_name='Time before [μS]', default=12)
67 time_before = models.PositiveIntegerField(verbose_name='Time before [μS]', default=12)
68 time_after = models.PositiveIntegerField(verbose_name='Time after [μS]', default=1)
68 time_after = models.PositiveIntegerField(verbose_name='Time after [μS]', default=1)
69 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
69 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
70 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
70 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
71 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
71 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
72 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
72 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
73 total_units = models.PositiveIntegerField(default=0)
73 total_units = models.PositiveIntegerField(default=0)
74 mix = models.BooleanField(default=False)
74 mix = models.BooleanField(default=False)
75
75
76 class Meta:
76 class Meta:
77 db_table = 'rc_configurations'
77 db_table = 'rc_configurations'
78
78
79 def get_absolute_url_plot(self):
79 def get_absolute_url_plot(self):
80 return reverse('url_plot_rc_pulses', args=[str(self.id)])
80 return reverse('url_plot_rc_pulses', args=[str(self.id)])
81
81
82 def get_absolute_url_import(self):
82 def get_absolute_url_import(self):
83 return reverse('url_import_rc_conf', args=[str(self.id)])
83 return reverse('url_import_rc_conf', args=[str(self.id)])
84
84
85 @property
85 @property
86 def ipp_unit(self):
86 def ipp_unit(self):
87
87
88 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
88 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
89
89
90 @property
90 @property
91 def us2unit(self):
91 def us2unit(self):
92
92
93 return self.clock_in/self.clock_divider
93 return self.clock_in/self.clock_divider
94
94
95 @property
95 @property
96 def km2unit(self):
96 def km2unit(self):
97
97
98 return 20./3*(self.clock_in/self.clock_divider)
98 return 20./3*(self.clock_in/self.clock_divider)
99
99
100 def clone(self, **kwargs):
100 def clone(self, **kwargs):
101
101
102 lines = self.get_lines()
102 lines = self.get_lines()
103 self.pk = None
103 self.pk = None
104 self.id = None
104 self.id = None
105 for attr, value in kwargs.items():
105 for attr, value in kwargs.items():
106 setattr(self, attr, value)
106 setattr(self, attr, value)
107 self.save()
107 self.save()
108
108
109 for line in lines:
109 for line in lines:
110 line.clone(rc_configuration=self)
110 line.clone(rc_configuration=self)
111
111
112 return self
112 return self
113
113
114 def get_lines(self, **kwargs):
114 def get_lines(self, **kwargs):
115 '''
115 '''
116 Retrieve configuration lines
116 Retrieve configuration lines
117 '''
117 '''
118
118
119 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
119 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
120
120
121
121
122 def clean_lines(self):
122 def clean_lines(self):
123 '''
123 '''
124 '''
124 '''
125
125
126 empty_line = RCLineType.objects.get(name='none')
126 empty_line = RCLineType.objects.get(name='none')
127
127
128 for line in self.get_lines():
128 for line in self.get_lines():
129 line.line_type = empty_line
129 line.line_type = empty_line
130 line.params = '{}'
130 line.params = '{}'
131 line.save()
131 line.save()
132
132
133 def parms_to_dict(self):
133 def parms_to_dict(self):
134 '''
134 '''
135 '''
135 '''
136
136
137 ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr',
137 ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr',
138 'created_date', 'programmed_date')
138 'created_date', 'programmed_date')
139
139
140 data = {}
140 data = {}
141 for field in self._meta.fields:
141 for field in self._meta.fields:
142 if field.name in ignored:
142 if field.name in ignored:
143 continue
143 continue
144 data[field.name] = '{}'.format(field.value_from_object(self))
144 data[field.name] = '{}'.format(field.value_from_object(self))
145
145
146 data['device_id'] = data.pop('device')
146 data['device_id'] = data.pop('device')
147 data['lines'] = []
147 data['lines'] = []
148
148
149 for line in self.get_lines():
149 for line in self.get_lines():
150 line_data = json.loads(line.params)
150 line_data = json.loads(line.params)
151 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
151 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
152 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
152 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
153 if 'code' in line_data:
153 if 'code' in line_data:
154 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
154 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
155 line_data['type'] = line.line_type.name
155 line_data['type'] = line.line_type.name
156 line_data['name'] = line.get_name()
156 line_data['name'] = line.get_name()
157 data['lines'].append(line_data)
157 data['lines'].append(line_data)
158
158
159 data['delays'] = self.get_delays()
159 data['delays'] = self.get_delays()
160 data['pulses'] = self.get_pulses()
160 data['pulses'] = self.get_pulses()
161
161
162 return data
162 return data
163
163
164 def dict_to_parms(self, data):
164 def dict_to_parms(self, data):
165 '''
165 '''
166 '''
166 '''
167
167
168 self.name = data['name']
168 self.name = data['name']
169 self.ipp = float(data['ipp'])
169 self.ipp = float(data['ipp'])
170 self.ntx = int(data['ntx'])
170 self.ntx = int(data['ntx'])
171 self.clock_in = float(data['clock_in'])
171 self.clock_in = float(data['clock_in'])
172 self.clock_divider = int(data['clock_divider'])
172 self.clock_divider = int(data['clock_divider'])
173 self.clock = float(data['clock'])
173 self.clock = float(data['clock'])
174 self.time_before = data['time_before']
174 self.time_before = data['time_before']
175 self.time_after = data['time_after']
175 self.time_after = data['time_after']
176 self.sync = data['sync']
176 self.sync = data['sync']
177 self.sampling_reference = data['sampling_reference']
177 self.sampling_reference = data['sampling_reference']
178 self.total_units = self.ipp*self.ntx*self.km2unit
178 self.total_units = self.ipp*self.ntx*self.km2unit
179 self.save()
179 self.save()
180 self.clean_lines()
180 self.clean_lines()
181
181
182 lines = []
182 lines = []
183 positions = {'tx':0, 'tr':0}
183 positions = {'tx':0, 'tr':0}
184
184
185 for i, line_data in enumerate(data['lines']):
185 for i, line_data in enumerate(data['lines']):
186 name = line_data.pop('name', '')
186 name = line_data.pop('name', '')
187 line_type = RCLineType.objects.get(name=line_data.pop('type'))
187 line_type = RCLineType.objects.get(name=line_data.pop('type'))
188 if line_type.name=='codes':
188 if line_type.name=='codes':
189 code = RCLineCode.objects.get(name=line_data['code'])
189 code = RCLineCode.objects.get(name=line_data['code'])
190 line_data['code'] = code.pk
190 line_data['code'] = code.pk
191 line = RCLine.objects.filter(rc_configuration=self, channel=i)
191 line = RCLine.objects.filter(rc_configuration=self, channel=i)
192 if line:
192 if line:
193 line = line[0]
193 line = line[0]
194 line.line_type = line_type
194 line.line_type = line_type
195 line.params = json.dumps(line_data)
195 line.params = json.dumps(line_data)
196 else:
196 else:
197 line = RCLine(rc_configuration=self, line_type=line_type,
197 line = RCLine(rc_configuration=self, line_type=line_type,
198 params=json.dumps(line_data),
198 params=json.dumps(line_data),
199 channel=i)
199 channel=i)
200
200
201 if line_type.name=='tx':
201 if line_type.name=='tx':
202 line.position = positions['tx']
202 line.position = positions['tx']
203 positions['tx'] += 1
203 positions['tx'] += 1
204
204
205 if line_type.name=='tr':
205 if line_type.name=='tr':
206 line.position = positions['tr']
206 line.position = positions['tr']
207 positions['tr'] += 1
207 positions['tr'] += 1
208
208
209 line.save()
209 line.save()
210 lines.append(line)
210 lines.append(line)
211
211
212 for line, line_data in zip(lines, data['lines']):
212 for line, line_data in zip(lines, data['lines']):
213 if 'TX_ref' in line_data:
213 if 'TX_ref' in line_data:
214 params = json.loads(line.params)
214 params = json.loads(line.params)
215 if line_data['TX_ref'] in (0, '0'):
215 if line_data['TX_ref'] in (0, '0'):
216 params['TX_ref'] = '0'
216 params['TX_ref'] = '0'
217 else:
217 else:
218 params['TX_ref'] = [l.pk for l in lines if l.line_type.name=='tx' and line_data['TX_ref'] in l.get_name()][0]
218 params['TX_ref'] = [l.pk for l in lines if l.line_type.name=='tx' and line_data['TX_ref'] in l.get_name()][0]
219 line.params = json.dumps(params)
219 line.params = json.dumps(params)
220 line.save()
220 line.save()
221
221
222
222
223 def get_delays(self):
223 def get_delays(self):
224
224
225 pulses = [line.pulses_as_points() for line in self.get_lines()]
225 pulses = [line.pulses_as_points() for line in self.get_lines()]
226 points = [tup for tups in pulses for tup in tups]
226 points = [tup for tups in pulses for tup in tups]
227 points = set([x for tup in points for x in tup])
227 points = set([x for tup in points for x in tup])
228 points = list(points)
228 points = list(points)
229 points.sort()
229 points.sort()
230
230
231 if points[0]!=0:
231 if points[0]!=0:
232 points.insert(0, 0)
232 points.insert(0, 0)
233
233
234 return [points[i+1]-points[i] for i in range(len(points)-1)]
234 return [points[i+1]-points[i] for i in range(len(points)-1)]
235
235
236
236
237 def get_pulses(self, binary=True):
237 def get_pulses(self, binary=True):
238
238
239 pulses = [line.pulses_as_points() for line in self.get_lines()]
239 pulses = [line.pulses_as_points() for line in self.get_lines()]
240 points = [tup for tups in pulses for tup in tups]
240 points = [tup for tups in pulses for tup in tups]
241 points = set([x for tup in points for x in tup])
241 points = set([x for tup in points for x in tup])
242 points = list(points)
242 points = list(points)
243 points.sort()
243 points.sort()
244
244
245 line_points = [line.pulses_as_points() for line in self.get_lines()]
245 line_points = [line.pulses_as_points() for line in self.get_lines()]
246 #line_points = [[(x, x+y) for x,y in tups] for tups in line_points]
246 #line_points = [[(x, x+y) for x,y in tups] for tups in line_points]
247 line_points = [[t for x in tups for t in x] for tups in line_points]
247 line_points = [[t for x in tups for t in x] for tups in line_points]
248 states = [[1 if x in tups else 0 for tups in line_points] for x in points]
248 states = [[1 if x in tups else 0 for tups in line_points] for x in points]
249
249
250 if binary:
250 if binary:
251 states.reverse()
251 states.reverse()
252 states = [int(''.join([str(x) for x in flips]), 2) for flips in states]
252 states = [int(''.join([str(x) for x in flips]), 2) for flips in states]
253
253
254 return states[:-1]
254 return states[:-1]
255
255
256 def add_cmd(self, cmd):
256 def add_cmd(self, cmd):
257
257
258 if cmd in DAT_CMDS:
258 if cmd in DAT_CMDS:
259 return (255, DAT_CMDS[cmd])
259 return (255, DAT_CMDS[cmd])
260
260
261 def add_data(self, value):
261 def add_data(self, value):
262
262
263 return (254, value-1)
263 return (254, value-1)
264
264
265 def parms_to_binary(self, dat=True):
265 def parms_to_binary(self, dat=True):
266 '''
266 '''
267 Create "dat" stream to be send to CR
267 Create "dat" stream to be send to CR
268 '''
268 '''
269
269
270 data = bytearray()
270 data = bytearray()
271 # create header
271 # create header
272 data.extend(self.add_cmd('DISABLE'))
272 data.extend(self.add_cmd('DISABLE'))
273 data.extend(self.add_cmd('CONTINUE'))
273 data.extend(self.add_cmd('CONTINUE'))
274 data.extend(self.add_cmd('RESTART'))
274 data.extend(self.add_cmd('RESTART'))
275
275
276 if self.control_sw:
276 if self.control_sw:
277 data.extend(self.add_cmd('SW_ONE'))
277 data.extend(self.add_cmd('SW_ONE'))
278 else:
278 else:
279 data.extend(self.add_cmd('SW_ZERO'))
279 data.extend(self.add_cmd('SW_ZERO'))
280
280
281 if self.control_tx:
281 if self.control_tx:
282 data.extend(self.add_cmd('TX_ONE'))
282 data.extend(self.add_cmd('TX_ONE'))
283 else:
283 else:
284 data.extend(self.add_cmd('TX_ZERO'))
284 data.extend(self.add_cmd('TX_ZERO'))
285
285
286 # write divider
286 # write divider
287 data.extend(self.add_cmd('CLOCK_DIVIDER'))
287 data.extend(self.add_cmd('CLOCK_DIVIDER'))
288 data.extend(self.add_data(self.clock_divider))
288 data.extend(self.add_data(self.clock_divider))
289
289
290 # write delays
290 # write delays
291 data.extend(self.add_cmd('DELAY_START'))
291 data.extend(self.add_cmd('DELAY_START'))
292 # first delay is always zero
292 # first delay is always zero
293 data.extend(self.add_data(1))
293 data.extend(self.add_data(1))
294
294
295 delays = self.get_delays()
295 delays = self.get_delays()
296
296
297 for delay in delays:
297 for delay in delays:
298 while delay>252:
298 while delay>252:
299 data.extend(self.add_data(253))
299 data.extend(self.add_data(253))
300 delay -= 253
300 delay -= 253
301 data.extend(self.add_data(int(delay)))
301 data.extend(self.add_data(int(delay)))
302
302
303 # write flips
303 # write flips
304 data.extend(self.add_cmd('FLIP_START'))
304 data.extend(self.add_cmd('FLIP_START'))
305
305
306 states = self.get_pulses(binary=False)
306 states = self.get_pulses(binary=False)
307
307
308 for flips, delay in zip(states, delays):
308 for flips, delay in zip(states, delays):
309 flips.reverse()
309 flips.reverse()
310 flip = int(''.join([str(x) for x in flips]), 2)
310 flip = int(''.join([str(x) for x in flips]), 2)
311 data.extend(self.add_data(flip+1))
311 data.extend(self.add_data(flip+1))
312 while delay>252:
312 while delay>252:
313 data.extend(self.add_data(1))
313 data.extend(self.add_data(1))
314 delay -= 253
314 delay -= 253
315
315
316 # write sampling period
316 # write sampling period
317 data.extend(self.add_cmd('SAMPLING_PERIOD'))
317 data.extend(self.add_cmd('SAMPLING_PERIOD'))
318 wins = self.get_lines(line_type__name='windows')
318 wins = self.get_lines(line_type__name='windows')
319 if wins:
319 if wins:
320 win_params = json.loads(wins[0].params)['params']
320 win_params = json.loads(wins[0].params)['params']
321 if win_params:
321 if win_params:
322 dh = int(win_params[0]['resolution']*self.km2unit)
322 dh = int(win_params[0]['resolution']*self.km2unit)
323 else:
323 else:
324 dh = 1
324 dh = 1
325 else:
325 else:
326 dh = 1
326 dh = 1
327 data.extend(self.add_data(dh))
327 data.extend(self.add_data(dh))
328
328
329 # write enable
329 # write enable
330 data.extend(self.add_cmd('ENABLE'))
330 data.extend(self.add_cmd('ENABLE'))
331
331
332 if not dat:
332 if not dat:
333 return data
333 return data
334
334
335 return '\n'.join(['{}'.format(x) for x in data])
335 return '\n'.join(['{}'.format(x) for x in data])
336
336
337
337
338 def update_from_file(self, filename):
338 def update_from_file(self, filename):
339 '''
339 '''
340 Update instance from file
340 Update instance from file
341 '''
341 '''
342
342
343 f = RCFile(filename)
343 f = RCFile(filename)
344 self.dict_to_parms(f.data)
344 self.dict_to_parms(f.data)
345 self.update_pulses()
345 self.update_pulses()
346
346
347 def update_pulses(self):
347 def update_pulses(self):
348
348
349 for line in self.get_lines():
349 for line in self.get_lines():
350 line.update_pulses()
350 line.update_pulses()
351
351
352 def plot_pulses2(self, km=False):
352 def plot_pulses2(self, km=False):
353
353
354 import matplotlib.pyplot as plt
354 import matplotlib.pyplot as plt
355 from bokeh.resources import CDN
355 from bokeh.resources import CDN
356 from bokeh.embed import components
356 from bokeh.embed import components
357 from bokeh.mpl import to_bokeh
357 from bokeh.mpl import to_bokeh
358 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
358 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
359
359
360 lines = self.get_lines()
360 lines = self.get_lines()
361
361
362 N = len(lines)
362 N = len(lines)
363 npoints = self.total_units/self.km2unit if km else self.total_units
363 npoints = self.total_units/self.km2unit if km else self.total_units
364 fig = plt.figure(figsize=(12, 2+N*0.5))
364 fig = plt.figure(figsize=(12, 2+N*0.5))
365 ax = fig.add_subplot(111)
365 ax = fig.add_subplot(111)
366 labels = ['IPP']
366 labels = ['IPP']
367
367
368 for i, line in enumerate(lines):
368 for i, line in enumerate(lines):
369 labels.append(line.get_name(channel=True))
369 labels.append(line.get_name(channel=True))
370 l = ax.plot((0, npoints),(N-i-1, N-i-1))
370 l = ax.plot((0, npoints),(N-i-1, N-i-1))
371 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
371 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
372 ax.broken_barh(points, (N-i-1, 0.5),
372 ax.broken_barh(points, (N-i-1, 0.5),
373 edgecolor=l[0].get_color(), facecolor='none')
373 edgecolor=l[0].get_color(), facecolor='none')
374
374
375 n = 0
375 n = 0
376 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
376 f = ((self.ntx+50)/100)*5 if ((self.ntx+50)/100)*10>0 else 2
377 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
377 for x in np.arange(0, npoints, self.ipp if km else self.ipp*self.km2unit):
378 if n%f==0:
378 if n%f==0:
379 ax.text(x, N, '%s' % n, size=10)
379 ax.text(x, N, '%s' % n, size=10)
380 n += 1
380 n += 1
381
381
382
382
383 labels.reverse()
383 labels.reverse()
384 ax.set_yticks(range(len(labels)))
384 ax.set_yticks(range(len(labels)))
385 ax.set_yticklabels(labels)
385 ax.set_yticklabels(labels)
386 ax.set_xlabel = 'Units'
386 ax.set_xlabel = 'Units'
387 plot = to_bokeh(fig, use_pandas=False)
387 plot = to_bokeh(fig, use_pandas=False)
388 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
388 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), SaveTool()]
389 plot.toolbar_location="above"
389 plot.toolbar_location="above"
390
390
391 return components(plot, CDN)
391 return components(plot, CDN)
392
392
393 def plot_pulses(self, km=False):
393 def plot_pulses(self, km=False):
394
394
395 from bokeh.plotting import figure
395 from bokeh.plotting import figure
396 from bokeh.resources import CDN
396 from bokeh.resources import CDN
397 from bokeh.embed import components
397 from bokeh.embed import components
398 from bokeh.models import FixedTicker, PrintfTickFormatter
398 from bokeh.models import FixedTicker, PrintfTickFormatter
399 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
399 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, HoverTool, SaveTool
400 from bokeh.models.sources import ColumnDataSource
400 from bokeh.models.sources import ColumnDataSource
401
401
402 lines = self.get_lines().reverse()
402 lines = self.get_lines().reverse()
403
403
404 N = len(lines)
404 N = len(lines)
405 npoints = self.total_units/self.km2unit if km else self.total_units
405 npoints = self.total_units/self.km2unit if km else self.total_units
406 ipp = self.ipp if km else self.ipp*self.km2unit
406 ipp = self.ipp if km else self.ipp*self.km2unit
407
407
408 hover = HoverTool(tooltips=[("Line", "@name"),
408 hover = HoverTool(tooltips=[("Line", "@name"),
409 ("IPP", "@ipp"),
409 ("IPP", "@ipp"),
410 ("X", "@left")])
410 ("X", "@left")])
411
411
412 tools = [PanTool(dimensions=['width']),
412 tools = [PanTool(dimensions=['width']),
413 WheelZoomTool(dimensions=['width']),
413 WheelZoomTool(dimensions=['width']),
414 hover, SaveTool()]
414 hover, SaveTool()]
415
415
416 plot = figure(width=1000,
416 plot = figure(width=1000,
417 height=40+N*50,
417 height=40+N*50,
418 y_range = (0, N),
418 y_range = (0, N),
419 tools=tools,
419 tools=tools,
420 toolbar_location='above',
420 toolbar_location='above',
421 toolbar_sticky=False,)
421 toolbar_sticky=False,)
422
422
423 plot.xaxis.axis_label = 'Km' if km else 'Units'
423 plot.xaxis.axis_label = 'Km' if km else 'Units'
424 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
424 plot.xaxis[0].formatter = PrintfTickFormatter(format='%d')
425 plot.yaxis.axis_label = 'Pulses'
425 plot.yaxis.axis_label = 'Pulses'
426 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
426 plot.yaxis[0].ticker=FixedTicker(ticks=list(range(N)))
427 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
427 plot.yaxis[0].formatter = PrintfTickFormatter(format='Line %d')
428
428
429 for i, line in enumerate(lines):
429 for i, line in enumerate(lines):
430
430
431 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
431 points = [tup for tup in line.pulses_as_points(km=km) if tup!=(0,0)]
432
432
433 source = ColumnDataSource(data = dict(
433 source = ColumnDataSource(data = dict(
434 bottom = [i for tup in points],
434 bottom = [i for tup in points],
435 top = [i+0.5 for tup in points],
435 top = [i+0.5 for tup in points],
436 left = [tup[0] for tup in points],
436 left = [tup[0] for tup in points],
437 right = [tup[1] for tup in points],
437 right = [tup[1] for tup in points],
438 ipp = [int(tup[0]/ipp) for tup in points],
438 ipp = [int(tup[0]/ipp) for tup in points],
439 name = [line.get_name() for tup in points]
439 name = [line.get_name() for tup in points]
440 ))
440 ))
441
441
442 plot.quad(
442 plot.quad(
443 bottom = 'bottom',
443 bottom = 'bottom',
444 top = 'top',
444 top = 'top',
445 left = 'left',
445 left = 'left',
446 right = 'right',
446 right = 'right',
447 source = source,
447 source = source,
448 fill_alpha = 0,
448 fill_alpha = 0,
449 #line_color = 'blue',
449 #line_color = 'blue',
450 )
450 )
451
451
452 plot.line([0, npoints], [i, i])#, color='blue')
452 plot.line([0, npoints], [i, i])#, color='blue')
453
453
454 return components(plot, CDN)
454 return components(plot, CDN)
455
455
456 def status_device(self):
456 def status_device(self):
457
457
458 try:
458 try:
459 self.device.status = 0
459 req = requests.get(self.device.url('status'))
460 req = requests.get(self.device.url('status'))
460 payload = req.json()
461 payload = req.json()
461 if payload['status']=='ok':
462 if payload['status']=='ok':
462 self.device.status = 1
463 self.device.status = 2
463 else:
464 else:
464 self.device.status = 0
465 self.device.status = 1
466 self.device.save()
467 self.message = payload['status']
468 return False
465 except Exception as e:
469 except Exception as e:
466 self.device.status = 0
470 if 'No route to host' not in str(e):
471 self.device.status = 4
472 self.device.save()
467 self.message = str(e)
473 self.message = str(e)
468 return False
474 return False
469
475
470 self.device.save()
476 self.device.save()
471 return True
477 return True
472
473
478
474 def reset_device(self):
479 def reset_device(self):
475
480
476 try:
481 try:
477 req = requests.post(self.device.url('reset'))
482 req = requests.post(self.device.url('reset'))
478 if 'ok' in req.text:
483 payload = req.json()
484 if payload['reset']=='ok':
479 self.message = 'RC restarted'
485 self.message = 'RC restarted'
480 else:
486 else:
481 self.message = 'RC restart not ok'
487 self.message = 'RC restart not ok'
482 self.device.status = 4
488 self.device.status = 4
483 self.device.save()
489 self.device.save()
484 except Exception as e:
490 except Exception as e:
485 self.message = str(e)
491 self.message = str(e)
486 return False
492 return False
487
493
488 return True
494 return True
489
495
490 def stop_device(self):
496 def stop_device(self):
491
497
492 try:
498 try:
493 req = requests.post(self.device.url('stop'))
499 req = requests.post(self.device.url('stop'))
494 if 'ok' in req.text:
500 payload = req.json()
501 if payload['stop']=='ok':
495 self.device.status = 2
502 self.device.status = 2
496 self.device.save()
503 self.device.save()
497 self.message = 'RC stopped'
504 self.message = 'RC stopped'
498 else:
505 else:
499 self.message = 'RC stop not ok'
506 self.message = 'RC stop not ok'
500 self.device.status = 4
507 self.device.status = 4
501 self.device.save()
508 self.device.save()
502 return False
509 return False
503 except Exception as e:
510 except Exception as e:
504 self.message = str(e)
511 if 'No route to host' not in str(e):
512 self.device.status = 4
513 else:
514 self.device.status = 0
515 self.message = str(e)
516 self.device.save()
505 return False
517 return False
506
518
507 return True
519 return True
508
520
509 def start_device(self):
521 def start_device(self):
510
522
511 try:
523 try:
512 req = requests.post(self.device.url('start'))
524 req = requests.post(self.device.url('start'))
513 if 'ok' in req.text:
525 payload = req.json()
526 if payload['start']=='ok':
514 self.device.status = 3
527 self.device.status = 3
515 self.device.save()
528 self.device.save()
516 self.message = 'RC running'
529 self.message = 'RC running'
517 else:
530 else:
518 self.message = 'RC start not ok'
531 self.message = 'RC start not ok'
519 return False
532 return False
520 except Exception as e:
533 except Exception as e:
521 self.message = str(e)
534 if 'No route to host' not in str(e):
535 self.device.status = 4
536 else:
537 self.device.status = 0
538 self.message = str(e)
539 self.device.save()
522 return False
540 return False
523
541
524 return True
542 return True
525
543
526 def write_device(self):
544 def write_device(self):
527
545
528 values = zip(self.get_pulses(),
546 values = zip(self.get_pulses(),
529 [x-1 for x in self.get_delays()])
547 [x-1 for x in self.get_delays()])
530 payload = ''
548 payload = ''
531
549
532 for tup in values:
550 for tup in values:
533 vals = pack('<HH', *tup)
551 vals = pack('<HH', *tup)
534 payload += '\x05'+vals[0]+'\x04'+vals[1]+'\x05'+vals[2]+'\x05'+vals[3]
552 payload += '\x05'+vals[0]+'\x04'+vals[1]+'\x05'+vals[2]+'\x05'+vals[3]
535
553
536 try:
554 try:
537 ## reset
555 ## reset
538 if not self.reset_device():
556 if not self.reset_device():
539 return False
557 return False
540 ## stop
558 ## stop
541 if not self.stop_device():
559 if not self.stop_device():
542 return False
560 return False
543 ## write clock divider
561 ## write clock divider
544 req = requests.post(self.device.url('divisor'),
562 req = requests.post(self.device.url('divisor'),
545 {'divisor': '{:d}'.format(self.clock_divider-1)})
563 {'divisor': '{:d}'.format(self.clock_divider-1)})
546 if 'ok' not in req.text:
564 payload = req.json()
565 if payload['divisor']=='ok':
547 self.message = 'Error configuring RC clock divider'
566 self.message = 'Error configuring RC clock divider'
548 return False
567 return False
549 ## write pulses & delays
568 ## write pulses & delays
550 req = requests.post(self.device.url('write'), data=b64encode(payload))
569 req = requests.post(self.device.url('write'), data=b64encode(payload))
551 if 'ok' in req.text:
570 payload = req.json()
571 if payload['write']=='ok':
552 self.device.status = 2
572 self.device.status = 2
553 self.device.save()
573 self.device.save()
554 self.message = 'RC configured'
574 self.message = 'RC configured'
555 else:
575 else:
556 self.device.status = 4
576 self.device.status = 4
557 self.device.save()
577 self.device.save()
558 self.message = 'RC write not ok'
578 self.message = 'RC write not ok'
559 return False
579 return False
560
580
561 except Exception as e:
581 except Exception as e:
562 self.message = str(e)
582 if 'No route to host' not in str(e):
583 self.device.status = 4
584 else:
585 self.device.status = 0
586 self.message = str(e)
587 self.device.save()
563 return False
588 return False
564
589
565 return True
590 return True
566
591
567
592
568 class RCLineCode(models.Model):
593 class RCLineCode(models.Model):
569
594
570 name = models.CharField(max_length=40)
595 name = models.CharField(max_length=40)
571 bits_per_code = models.PositiveIntegerField(default=0)
596 bits_per_code = models.PositiveIntegerField(default=0)
572 number_of_codes = models.PositiveIntegerField(default=0)
597 number_of_codes = models.PositiveIntegerField(default=0)
573 codes = models.TextField(blank=True, null=True)
598 codes = models.TextField(blank=True, null=True)
574
599
575 class Meta:
600 class Meta:
576 db_table = 'rc_line_codes'
601 db_table = 'rc_line_codes'
577 ordering = ('name',)
602 ordering = ('name',)
578
603
579 def __str__(self):
604 def __str__(self):
580 return u'%s' % self.name
605 return u'%s' % self.name
581
606
582
607
583 class RCLineType(models.Model):
608 class RCLineType(models.Model):
584
609
585 name = models.CharField(choices=LINE_TYPES, max_length=40)
610 name = models.CharField(choices=LINE_TYPES, max_length=40)
586 description = models.TextField(blank=True, null=True)
611 description = models.TextField(blank=True, null=True)
587 params = models.TextField(default='[]')
612 params = models.TextField(default='[]')
588
613
589 class Meta:
614 class Meta:
590 db_table = 'rc_line_types'
615 db_table = 'rc_line_types'
591
616
592 def __str__(self):
617 def __str__(self):
593 return u'%s - %s' % (self.name.upper(), self.get_name_display())
618 return u'%s - %s' % (self.name.upper(), self.get_name_display())
594
619
595
620
596 class RCLine(models.Model):
621 class RCLine(models.Model):
597
622
598 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
623 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
599 line_type = models.ForeignKey(RCLineType)
624 line_type = models.ForeignKey(RCLineType)
600 channel = models.PositiveIntegerField(default=0)
625 channel = models.PositiveIntegerField(default=0)
601 position = models.PositiveIntegerField(default=0)
626 position = models.PositiveIntegerField(default=0)
602 params = models.TextField(default='{}')
627 params = models.TextField(default='{}')
603 pulses = models.TextField(default='')
628 pulses = models.TextField(default='')
604
629
605 class Meta:
630 class Meta:
606 db_table = 'rc_lines'
631 db_table = 'rc_lines'
607 ordering = ['channel']
632 ordering = ['channel']
608
633
609 def __str__(self):
634 def __str__(self):
610 if self.rc_configuration:
635 if self.rc_configuration:
611 return u'%s - %s' % (self.rc_configuration, self.get_name())
636 return u'%s - %s' % (self.rc_configuration, self.get_name())
612
637
613 def clone(self, **kwargs):
638 def clone(self, **kwargs):
614
639
615 self.pk = None
640 self.pk = None
616
641
617 for attr, value in kwargs.items():
642 for attr, value in kwargs.items():
618 setattr(self, attr, value)
643 setattr(self, attr, value)
619
644
620 self.save()
645 self.save()
621
646
622 return self
647 return self
623
648
624 def get_name(self, channel=False):
649 def get_name(self, channel=False):
625
650
626 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
651 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
627 s = ''
652 s = ''
628
653
629 if self.line_type.name in ('tx',):
654 if self.line_type.name in ('tx',):
630 s = chars[self.position]
655 s = chars[self.position]
631 elif self.line_type.name in ('codes', 'windows', 'tr'):
656 elif self.line_type.name in ('codes', 'windows', 'tr'):
632 if 'TX_ref' in json.loads(self.params):
657 if 'TX_ref' in json.loads(self.params):
633 pk = json.loads(self.params)['TX_ref']
658 pk = json.loads(self.params)['TX_ref']
634 if pk in (0, '0'):
659 if pk in (0, '0'):
635 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
660 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
636 else:
661 else:
637 ref = RCLine.objects.get(pk=pk)
662 ref = RCLine.objects.get(pk=pk)
638 s = chars[ref.position]
663 s = chars[ref.position]
639 s = '({})'.format(s)
664 s = '({})'.format(s)
640
665
641 s = '{}{}'.format(self.line_type.name.upper(), s)
666 s = '{}{}'.format(self.line_type.name.upper(), s)
642
667
643 if channel:
668 if channel:
644 return '{} {}'.format(s, self.channel)
669 return '{} {}'.format(s, self.channel)
645 else:
670 else:
646 return s
671 return s
647
672
648 def get_lines(self, **kwargs):
673 def get_lines(self, **kwargs):
649
674
650 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
675 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
651
676
652 def pulses_as_array(self):
677 def pulses_as_array(self):
653
678
654 y = np.zeros(self.rc_configuration.total_units)
679 y = np.zeros(self.rc_configuration.total_units)
655
680
656 for tup in ast.literal_eval(self.pulses):
681 for tup in ast.literal_eval(self.pulses):
657 y[tup[0]:tup[1]] = 1
682 y[tup[0]:tup[1]] = 1
658
683
659 return y.astype(np.int8)
684 return y.astype(np.int8)
660
685
661 def pulses_as_points(self, km=False):
686 def pulses_as_points(self, km=False):
662
687
663 if km:
688 if km:
664 unit2km = 1/self.rc_configuration.km2unit
689 unit2km = 1/self.rc_configuration.km2unit
665 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
690 return [(tup[0]*unit2km, tup[1]*unit2km) for tup in ast.literal_eval(self.pulses)]
666 else:
691 else:
667 return ast.literal_eval(self.pulses)
692 return ast.literal_eval(self.pulses)
668
693
669 def get_win_ref(self, params, tx_id, km2unit):
694 def get_win_ref(self, params, tx_id, km2unit):
670
695
671 ref = self.rc_configuration.sampling_reference
696 ref = self.rc_configuration.sampling_reference
672 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
697 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
673
698
674 if codes:
699 if codes:
675 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
700 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
676 else:
701 else:
677 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
702 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
678
703
679 if ref=='first_baud':
704 if ref=='first_baud':
680 return int(1 + (tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit)
705 return int(1 + (tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit)
681 elif ref=='sub_baud':
706 elif ref=='sub_baud':
682 return int(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
707 return int(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
683 else:
708 else:
684 return 0
709 return 0
685
710
686 def update_pulses(self):
711 def update_pulses(self):
687 '''
712 '''
688 Update pulses field
713 Update pulses field
689 '''
714 '''
690
715
691 km2unit = self.rc_configuration.km2unit
716 km2unit = self.rc_configuration.km2unit
692 us2unit = self.rc_configuration.us2unit
717 us2unit = self.rc_configuration.us2unit
693 ipp = self.rc_configuration.ipp
718 ipp = self.rc_configuration.ipp
694 ntx = int(self.rc_configuration.ntx)
719 ntx = int(self.rc_configuration.ntx)
695 ipp_u = int(ipp*km2unit)
720 ipp_u = int(ipp*km2unit)
696 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
721 total = ipp_u*ntx if self.rc_configuration.total_units==0 else self.rc_configuration.total_units
697 y = []
722 y = []
698
723
699 if self.line_type.name=='tr':
724 if self.line_type.name=='tr':
700 tr_params = json.loads(self.params)
725 tr_params = json.loads(self.params)
701
726
702 if tr_params['TX_ref'] in ('0', 0):
727 if tr_params['TX_ref'] in ('0', 0):
703 txs = self.get_lines(line_type__name='tx')
728 txs = self.get_lines(line_type__name='tx')
704 else:
729 else:
705 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
730 txs = RCLine.objects.filter(pk=tr_params['TX_ref'])
706
731
707 for tx in txs:
732 for tx in txs:
708 params = json.loads(tx.params)
733 params = json.loads(tx.params)
709
734
710 if float(params['pulse_width'])==0:
735 if float(params['pulse_width'])==0:
711 continue
736 continue
712 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
737 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
713 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
738 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
714 before = 0
739 before = 0
715 after = int(self.rc_configuration.time_after*us2unit)
740 after = int(self.rc_configuration.time_after*us2unit)
716
741
717 y_tx = self.points(ntx, ipp_u, width,
742 y_tx = self.points(ntx, ipp_u, width,
718 delay=delays,
743 delay=delays,
719 before=before,
744 before=before,
720 after=after,
745 after=after,
721 sync=self.rc_configuration.sync)
746 sync=self.rc_configuration.sync)
722
747
723 ranges = params['range'].split(',')
748 ranges = params['range'].split(',')
724
749
725 if len(ranges)>0 and ranges[0]!='0':
750 if len(ranges)>0 and ranges[0]!='0':
726 y_tx = self.mask_ranges(y_tx, ranges)
751 y_tx = self.mask_ranges(y_tx, ranges)
727
752
728 tr_ranges = tr_params['range'].split(',')
753 tr_ranges = tr_params['range'].split(',')
729
754
730 if len(tr_ranges)>0 and tr_ranges[0]!='0':
755 if len(tr_ranges)>0 and tr_ranges[0]!='0':
731 y_tx = self.mask_ranges(y_tx, tr_ranges)
756 y_tx = self.mask_ranges(y_tx, tr_ranges)
732
757
733 y.extend(y_tx)
758 y.extend(y_tx)
734
759
735 self.pulses = str(y)
760 self.pulses = str(y)
736 y = self.array_to_points(self.pulses_as_array())
761 y = self.array_to_points(self.pulses_as_array())
737
762
738 elif self.line_type.name=='tx':
763 elif self.line_type.name=='tx':
739 params = json.loads(self.params)
764 params = json.loads(self.params)
740 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
765 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
741 width = float(params['pulse_width'])*km2unit
766 width = float(params['pulse_width'])*km2unit
742
767
743 if width>0:
768 if width>0:
744 before = int(self.rc_configuration.time_before*us2unit)
769 before = int(self.rc_configuration.time_before*us2unit)
745 after = 0
770 after = 0
746
771
747 y = self.points(ntx, ipp_u, width,
772 y = self.points(ntx, ipp_u, width,
748 delay=delays,
773 delay=delays,
749 before=before,
774 before=before,
750 after=after,
775 after=after,
751 sync=self.rc_configuration.sync)
776 sync=self.rc_configuration.sync)
752
777
753 ranges = params['range'].split(',')
778 ranges = params['range'].split(',')
754
779
755 if len(ranges)>0 and ranges[0]!='0':
780 if len(ranges)>0 and ranges[0]!='0':
756 y = self.mask_ranges(y, ranges)
781 y = self.mask_ranges(y, ranges)
757
782
758 elif self.line_type.name=='flip':
783 elif self.line_type.name=='flip':
759 n = float(json.loads(self.params)['number_of_flips'])
784 n = float(json.loads(self.params)['number_of_flips'])
760 width = n*ipp*km2unit
785 width = n*ipp*km2unit
761 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
786 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
762
787
763 elif self.line_type.name=='codes':
788 elif self.line_type.name=='codes':
764 params = json.loads(self.params)
789 params = json.loads(self.params)
765 tx = RCLine.objects.get(pk=params['TX_ref'])
790 tx = RCLine.objects.get(pk=params['TX_ref'])
766 tx_params = json.loads(tx.params)
791 tx_params = json.loads(tx.params)
767 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
792 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
768 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
793 f = int(float(tx_params['pulse_width'])*km2unit/len(params['codes'][0]))
769 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
794 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
770 codes = [self.array_to_points(code) for code in codes]
795 codes = [self.array_to_points(code) for code in codes]
771 n = len(codes)
796 n = len(codes)
772
797
773 for i, tup in enumerate(tx.pulses_as_points()):
798 for i, tup in enumerate(tx.pulses_as_points()):
774 code = codes[i%n]
799 code = codes[i%n]
775 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
800 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
776
801
777 ranges = tx_params['range'].split(',')
802 ranges = tx_params['range'].split(',')
778 if len(ranges)>0 and ranges[0]!='0':
803 if len(ranges)>0 and ranges[0]!='0':
779 y = self.mask_ranges(y, ranges)
804 y = self.mask_ranges(y, ranges)
780
805
781 elif self.line_type.name=='sync':
806 elif self.line_type.name=='sync':
782 params = json.loads(self.params)
807 params = json.loads(self.params)
783 n = ipp_u*ntx
808 n = ipp_u*ntx
784 if params['invert'] in ('1', 1):
809 if params['invert'] in ('1', 1):
785 y = [(n-1, n)]
810 y = [(n-1, n)]
786 else:
811 else:
787 y = [(0, 1)]
812 y = [(0, 1)]
788
813
789 elif self.line_type.name=='prog_pulses':
814 elif self.line_type.name=='prog_pulses':
790 params = json.loads(self.params)
815 params = json.loads(self.params)
791 if int(params['periodic'])==0:
816 if int(params['periodic'])==0:
792 nntx = 1
817 nntx = 1
793 nipp = ipp_u*ntx
818 nipp = ipp_u*ntx
794 else:
819 else:
795 nntx = ntx
820 nntx = ntx
796 nipp = ipp_u
821 nipp = ipp_u
797
822
798 if 'params' in params and len(params['params'])>0:
823 if 'params' in params and len(params['params'])>0:
799 for p in params['params']:
824 for p in params['params']:
800 y_pp = self.points(nntx, nipp,
825 y_pp = self.points(nntx, nipp,
801 p['end']-p['begin'],
826 p['end']-p['begin'],
802 before=p['begin'])
827 before=p['begin'])
803
828
804 y.extend(y_pp)
829 y.extend(y_pp)
805
830
806 elif self.line_type.name=='windows':
831 elif self.line_type.name=='windows':
807 params = json.loads(self.params)
832 params = json.loads(self.params)
808
833
809 if 'params' in params and len(params['params'])>0:
834 if 'params' in params and len(params['params'])>0:
810 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
835 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
811 tr_ranges = tr_params['range'].split(',')
836 tr_ranges = tr_params['range'].split(',')
812 for p in params['params']:
837 for p in params['params']:
813 y_win = self.points(ntx, ipp_u,
838 y_win = self.points(ntx, ipp_u,
814 p['resolution']*p['number_of_samples']*km2unit,
839 p['resolution']*p['number_of_samples']*km2unit,
815 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit),
840 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit),
816 sync=self.rc_configuration.sync)
841 sync=self.rc_configuration.sync)
817
842
818 if len(tr_ranges)>0 and tr_ranges[0]!='0':
843 if len(tr_ranges)>0 and tr_ranges[0]!='0':
819 y_win = self.mask_ranges(y_win, tr_ranges)
844 y_win = self.mask_ranges(y_win, tr_ranges)
820
845
821 y.extend(y_win)
846 y.extend(y_win)
822
847
823 elif self.line_type.name=='mix':
848 elif self.line_type.name=='mix':
824 values = self.rc_configuration.parameters.split('-')
849 values = self.rc_configuration.parameters.split('-')
825 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
850 confs = [RCConfiguration.objects.get(pk=value.split('|')[0]) for value in values]
826 modes = [value.split('|')[1] for value in values]
851 modes = [value.split('|')[1] for value in values]
827 ops = [value.split('|')[2] for value in values]
852 ops = [value.split('|')[2] for value in values]
828 delays = [value.split('|')[3] for value in values]
853 delays = [value.split('|')[3] for value in values]
829 masks = [value.split('|')[4] for value in values]
854 masks = [value.split('|')[4] for value in values]
830 mask = list('{:8b}'.format(int(masks[0])))
855 mask = list('{:8b}'.format(int(masks[0])))
831 mask.reverse()
856 mask.reverse()
832 if mask[self.channel] in ('0', '', ' '):
857 if mask[self.channel] in ('0', '', ' '):
833 y = np.zeros(confs[0].total_units, dtype=np.int8)
858 y = np.zeros(confs[0].total_units, dtype=np.int8)
834 else:
859 else:
835 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
860 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
836
861
837 for i in range(1, len(values)):
862 for i in range(1, len(values)):
838 mask = list('{:8b}'.format(int(masks[i])))
863 mask = list('{:8b}'.format(int(masks[i])))
839 mask.reverse()
864 mask.reverse()
840
865
841 if mask[self.channel] in ('0', '', ' '):
866 if mask[self.channel] in ('0', '', ' '):
842 continue
867 continue
843 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
868 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
844 delay = float(delays[i])*km2unit
869 delay = float(delays[i])*km2unit
845
870
846 if modes[i]=='P':
871 if modes[i]=='P':
847 if delay>0:
872 if delay>0:
848 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
873 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
849 y_temp = np.empty_like(Y)
874 y_temp = np.empty_like(Y)
850 y_temp[:delay] = 0
875 y_temp[:delay] = 0
851 y_temp[delay:] = Y[:-delay]
876 y_temp[delay:] = Y[:-delay]
852 elif delay+len(Y)>len(y):
877 elif delay+len(Y)>len(y):
853 y_new = np.zeros(delay+len(Y), dtype=np.int8)
878 y_new = np.zeros(delay+len(Y), dtype=np.int8)
854 y_new[:len(y)] = y
879 y_new[:len(y)] = y
855 y = y_new
880 y = y_new
856 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
881 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
857 y_temp[-len(Y):] = Y
882 y_temp[-len(Y):] = Y
858 elif delay+len(Y)==len(y):
883 elif delay+len(Y)==len(y):
859 y_temp = np.zeros(delay+len(Y))
884 y_temp = np.zeros(delay+len(Y))
860 y_temp[-len(Y):] = Y
885 y_temp[-len(Y):] = Y
861 elif delay+len(Y)<len(y):
886 elif delay+len(Y)<len(y):
862 y_temp = np.zeros(len(y), dtype=np.int8)
887 y_temp = np.zeros(len(y), dtype=np.int8)
863 y_temp[delay:delay+len(Y)] = Y
888 y_temp[delay:delay+len(Y)] = Y
864
889
865 if ops[i]=='OR':
890 if ops[i]=='OR':
866 y = y | y_temp
891 y = y | y_temp
867 elif ops[i]=='XOR':
892 elif ops[i]=='XOR':
868 y = y ^ y_temp
893 y = y ^ y_temp
869 elif ops[i]=='AND':
894 elif ops[i]=='AND':
870 y = y & y_temp
895 y = y & y_temp
871 elif ops[i]=='NAND':
896 elif ops[i]=='NAND':
872 y = y & ~y_temp
897 y = y & ~y_temp
873 else:
898 else:
874 y = np.concatenate([y, Y])
899 y = np.concatenate([y, Y])
875
900
876 total = len(y)
901 total = len(y)
877 y = self.array_to_points(y)
902 y = self.array_to_points(y)
878
903
879 else:
904 else:
880 y = []
905 y = []
881
906
882 if self.rc_configuration.total_units != total:
907 if self.rc_configuration.total_units != total:
883 self.rc_configuration.total_units = total
908 self.rc_configuration.total_units = total
884 self.rc_configuration.save()
909 self.rc_configuration.save()
885
910
886 self.pulses = str(y)
911 self.pulses = str(y)
887 self.save()
912 self.save()
888
913
889 @staticmethod
914 @staticmethod
890 def array_to_points(X):
915 def array_to_points(X):
891
916
892 d = X[1:]-X[:-1]
917 d = X[1:]-X[:-1]
893
918
894 up = np.where(d==1)[0]
919 up = np.where(d==1)[0]
895 if X[0]==1:
920 if X[0]==1:
896 up = np.concatenate((np.array([-1]), up))
921 up = np.concatenate((np.array([-1]), up))
897 up += 1
922 up += 1
898
923
899 dw = np.where(d==-1)[0]
924 dw = np.where(d==-1)[0]
900 if X[-1]==1:
925 if X[-1]==1:
901 dw = np.concatenate((dw, np.array([len(X)-1])))
926 dw = np.concatenate((dw, np.array([len(X)-1])))
902 dw += 1
927 dw += 1
903
928
904 return [(tup[0], tup[1]) for tup in zip(up, dw)]
929 return [(tup[0], tup[1]) for tup in zip(up, dw)]
905
930
906 @staticmethod
931 @staticmethod
907 def mask_ranges(Y, ranges):
932 def mask_ranges(Y, ranges):
908
933
909 y = [(0, 0) for __ in Y]
934 y = [(0, 0) for __ in Y]
910
935
911 for index in ranges:
936 for index in ranges:
912 if '-' in index:
937 if '-' in index:
913 args = [int(a) for a in index.split('-')]
938 args = [int(a) for a in index.split('-')]
914 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
939 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
915 else:
940 else:
916 y[int(index-1)] = Y[int(index-1)]
941 y[int(index-1)] = Y[int(index-1)]
917
942
918 return y
943 return y
919
944
920 @staticmethod
945 @staticmethod
921 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
946 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
922
947
923 delays = len(delay)
948 delays = len(delay)
924
949
925 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
950 Y = [(int(ipp*x+before+delay[x%delays]+sync), int(ipp*x+width+before+delay[x%delays]+after+sync)) for x in range(ntx)]
926
951
927 return Y
952 return Y
General Comments 0
You need to be logged in to leave comments. Login now