##// END OF EJS Templates
Fix RCConfiguration.dict_to_params ...
Juan C. Espinoza -
r114:f848f75e3768
parent child
Show More
@@ -1,761 +1,762
1 1
2 2 import ast
3 3 import json
4 4 import numpy as np
5 5
6 6 from polymorphic import PolymorphicModel
7 7
8 8 from django.db import models
9 9 from django.core.urlresolvers import reverse
10 10 from django.core.validators import MinValueValidator, MaxValueValidator
11 11
12 12 from apps.main.models import Configuration
13 13 from devices.rc import api
14 14 from .utils import RCFile
15 15
16 16 # Create your models here.
17 17
18 18 LINE_TYPES = (
19 19 ('none', 'Not used'),
20 20 ('tr', 'Transmission/reception selector signal'),
21 21 ('tx', 'A modulating signal (Transmission pulse)'),
22 22 ('codes', 'BPSK modulating signal'),
23 23 ('windows', 'Sample window signal'),
24 24 ('sync', 'Synchronizing signal'),
25 25 ('flip', 'IPP related periodic signal'),
26 26 ('prog_pulses', 'Programmable pulse'),
27 27 ('mix', 'Mixed line'),
28 28 )
29 29
30 30
31 31 SAMPLING_REFS = (
32 32 ('none', 'No Reference'),
33 33 ('first_baud', 'Middle of the first baud'),
34 34 ('sub_baud', 'Middle of the sub-baud')
35 35 )
36 36
37 37 DAT_CMDS = {
38 38 # Pulse Design commands
39 39 'DISABLE' : 0, # Disables pulse generation
40 40 'ENABLE' : 24, # Enables pulse generation
41 41 'DELAY_START' : 40, # Write delay status to memory
42 42 'FLIP_START' : 48, # Write flip status to memory
43 43 'SAMPLING_PERIOD' : 64, # Establish Sampling Period
44 44 'TX_ONE' : 72, # Output '0' in line TX
45 45 'TX_ZERO' : 88, # Output '0' in line TX
46 46 'SW_ONE' : 104, # Output '0' in line SW
47 47 'SW_ZERO' : 112, # Output '1' in line SW
48 48 'RESTART': 120, # Restarts CR8 Firmware
49 49 'CONTINUE' : 253, # Function Unknown
50 50 # Commands available to new controllers
51 51 # 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.
52 52 'CLOCK_DIVISOR_INIT' : 12, # Specifies Clock Divisor. Legacy command, ignored in the actual .dat conversion
53 53 'CLOCK_DIVISOR_LAST' : 22, # Specifies Clock Divisor (default 60 if not included) syntax: 255,22 254,N-1.
54 54 'CLOCK_DIVIDER' : 8,
55 55 }
56 56
57 57
58 58 class RCConfiguration(Configuration):
59 59
60 60 ipp = models.FloatField(verbose_name='Inter pulse period [Km]', validators=[MinValueValidator(1), MaxValueValidator(9000)], default=300)
61 61 ntx = models.PositiveIntegerField(verbose_name='Number of TX', validators=[MinValueValidator(1), MaxValueValidator(300)], default=1)
62 62 clock_in = models.FloatField(verbose_name='Clock in [MHz]', validators=[MinValueValidator(1), MaxValueValidator(80)], default=1)
63 63 clock_divider = models.PositiveIntegerField(verbose_name='Clock divider', validators=[MinValueValidator(1), MaxValueValidator(256)], default=1)
64 64 clock = models.FloatField(verbose_name='Clock Master [MHz]', blank=True, default=1)
65 65 time_before = models.PositiveIntegerField(verbose_name='Time before [μS]', default=12)
66 66 time_after = models.PositiveIntegerField(verbose_name='Time after [μS]', default=1)
67 67 sync = models.PositiveIntegerField(verbose_name='Synchro delay', default=0)
68 68 sampling_reference = models.CharField(verbose_name='Sampling Reference', choices=SAMPLING_REFS, default='none', max_length=40)
69 69 control_tx = models.BooleanField(verbose_name='Control Switch TX', default=False)
70 70 control_sw = models.BooleanField(verbose_name='Control Switch SW', default=False)
71 71 total_units = models.PositiveIntegerField(default=0)
72 72 mix = models.BooleanField(default=False)
73 73
74 74 class Meta:
75 75 db_table = 'rc_configurations'
76 76
77 77
78 78 def __unicode__(self):
79 79
80 80 if self.mix:
81 81 return u'[MIXED]: %s' % self.name
82 82 else:
83 83 return u'[%s]: %s' % (self.device.name, self.name)
84 84
85 85 def get_absolute_url_plot(self):
86 86 return reverse('url_plot_rc_pulses', args=[str(self.id)])
87 87
88 88 def get_absolute_url_import(self):
89 89 return reverse('url_import_rc_conf', args=[str(self.id)])
90 90
91 91 @property
92 92 def ipp_unit(self):
93 93
94 94 return '{} ({})'.format(self.ipp, int(self.ipp*self.km2unit))
95 95
96 96 @property
97 97 def us2unit(self):
98 98
99 99 return self.clock_in/self.clock_divider
100 100
101 101 @property
102 102 def km2unit(self):
103 103
104 104 return 20./3*(self.clock_in/self.clock_divider)
105 105
106 106 def clone(self, **kwargs):
107 107
108 108 lines = self.get_lines()
109 109 self.pk = None
110 110 self.id = None
111 111 for attr, value in kwargs.items():
112 112 setattr(self, attr, value)
113 113 self.save()
114 114
115 115 for line in lines:
116 116 line.clone(rc_configuration=self)
117 117
118 118 return self
119 119
120 120 def get_lines(self, **kwargs):
121 121 '''
122 122 Retrieve configuration lines
123 123 '''
124 124
125 125 return RCLine.objects.filter(rc_configuration=self.pk, **kwargs)
126 126
127 127
128 128 def clean_lines(self):
129 129 '''
130 130 '''
131 131
132 132 empty_line = RCLineType.objects.get(name='none')
133 133
134 134 for line in self.get_lines():
135 135 line.line_type = empty_line
136 136 line.params = '{}'
137 137 line.save()
138 138
139 139 def parms_to_dict(self):
140 140 '''
141 141 '''
142 142
143 143 ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr',
144 144 'created_date', 'programmed_date')
145 145
146 146 data = {}
147 147 for field in self._meta.fields:
148 148 if field.name in ignored:
149 149 continue
150 150 data[field.name] = '{}'.format(field.value_from_object(self))
151 151
152 152 data['lines'] = []
153 153
154 154 for line in self.get_lines():
155 155 line_data = json.loads(line.params)
156 156 if 'TX_ref' in line_data and line_data['TX_ref'] not in (0, '0'):
157 157 line_data['TX_ref'] = RCLine.objects.get(pk=line_data['TX_ref']).get_name()
158 158 if 'code' in line_data:
159 159 line_data['code'] = RCLineCode.objects.get(pk=line_data['code']).name
160 160 line_data['type'] = line.line_type.name
161 161 data['lines'].append(line_data)
162 162
163 163 data['delays'] = self.get_delays()
164 164 data['pulses'] = self.get_pulses()
165 165
166 166 return data
167 167
168 168 def dict_to_parms(self, data):
169 169 '''
170 170 '''
171 171
172 172 self.name = data['name']
173 173 self.ipp = data['ipp']
174 174 self.ntx = data['ntx']
175 175 self.clock_in = data['clock_in']
176 176 self.clock_divider = data['clock_divider']
177 177 self.clock = data['clock']
178 178 self.time_before = data['time_before']
179 179 self.time_after = data['time_after']
180 180 self.sync = data['sync']
181 181 self.sampling_reference = data['sampling_reference']
182 self.save()
182 183 self.clean_lines()
183 184
184 185 lines = []
185 186 positions = {'tx':0, 'tr':0}
186 187
187 188 for i, line_data in enumerate(data['lines']):
188 189 line_type = RCLineType.objects.get(name=line_data.pop('type'))
189 190 if line_type.name=='codes':
190 191 code = RCLineCode.objects.get(name=line_data['code'])
191 192 line_data['code'] = code.pk
192 193 line = RCLine.objects.filter(rc_configuration=self, channel=i)
193 194 if line:
194 195 line = line[0]
195 196 line.line_type = line_type
196 197 line.params = json.dumps(line_data)
197 198 else:
198 199 line = RCLine(rc_configuration=self, line_type=line_type,
199 200 params=json.dumps(line_data),
200 201 channel=i)
201 202
202 203 if line_type.name=='tx':
203 204 line.position = positions['tx']
204 205 positions['tx'] += 1
205 206
206 207 if line_type.name=='tr':
207 208 line.position = positions['tr']
208 209 positions['tr'] += 1
209 210
210 211 line.save()
211 212 lines.append(line)
212 213
213 214 for line, line_data in zip(lines, data['lines']):
214 215 if 'TX_ref' in line_data:
215 216 params = json.loads(line.params)
216 217 if line_data['TX_ref'] in (0, '0'):
217 218 params['TX_ref'] = '0'
218 219 else:
219 220 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]
220 221 line.params = json.dumps(params)
221 222 line.save()
222 223
223 224
224 225 def get_delays(self):
225 226
226 227 pulses = [line.pulses_as_points() for line in self.get_lines()]
227 228 points = [tup for tups in pulses for tup in tups]
228 229 points = set([x for tup in points for x in tup])
229 230 points = list(points)
230 231 points.sort()
231 232
232 233 if points[0]<>0:
233 234 points.insert(0, 0)
234 235
235 236 return [points[i+1]-points[i] for i in range(len(points)-1)]
236 237
237 238
238 239 def get_pulses(self, binary=True):
239 240
240 241 pulses = [line.pulses_as_points() for line in self.get_lines()]
241 242 points = [tup for tups in pulses for tup in tups]
242 243 points = set([x for tup in points for x in tup])
243 244 points = list(points)
244 245 points.sort()
245 246
246 247 line_points = [line.pulses_as_points() for line in self.get_lines()]
247 248 line_points = [[(x, x+y) for x,y in tups] for tups in line_points]
248 249 line_points = [[t for x in tups for t in x] for tups in line_points]
249 250 states = [[1 if x in tups else 0 for tups in line_points] for x in points]
250 251
251 252 if binary:
252 253 states.reverse()
253 254 states = [int(''.join([str(x) for x in flips]), 2) for flips in states]
254 255
255 256 return states[:-1]
256 257
257 258 def add_cmd(self, cmd):
258 259
259 260 if cmd in DAT_CMDS:
260 261 return (255, DAT_CMDS[cmd])
261 262
262 263 def add_data(self, value):
263 264
264 265 return (254, value-1)
265 266
266 267 def parms_to_binary(self):
267 268 '''
268 269 Create "dat" stream to be send to CR
269 270 '''
270 271
271 272 data = []
272 273 # create header
273 274 data.append(self.add_cmd('DISABLE'))
274 275 data.append(self.add_cmd('CONTINUE'))
275 276 data.append(self.add_cmd('RESTART'))
276 277
277 278 if self.control_sw:
278 279 data.append(self.add_cmd('SW_ONE'))
279 280 else:
280 281 data.append(self.add_cmd('SW_ZERO'))
281 282
282 283 if self.control_tx:
283 284 data.append(self.add_cmd('TX_ONE'))
284 285 else:
285 286 data.append(self.add_cmd('TX_ZERO'))
286 287
287 288 # write divider
288 289 data.append(self.add_cmd('CLOCK_DIVIDER'))
289 290 data.append(self.add_data(self.clock_divider))
290 291
291 292 # write delays
292 293 data.append(self.add_cmd('DELAY_START'))
293 294 # first delay is always zero
294 295 data.append(self.add_data(1))
295 296
296 297 delays = self.get_delays()
297 298
298 299 for delay in delays:
299 300 while delay>252:
300 301 data.append(self.add_data(253))
301 302 delay -= 253
302 303 data.append(self.add_data(delay))
303 304
304 305 # write flips
305 306 data.append(self.add_cmd('FLIP_START'))
306 307
307 308 states = self.get_pulses(binary=False)
308 309
309 310 for flips, delay in zip(states, delays):
310 311 flips.reverse()
311 312 flip = int(''.join([str(x) for x in flips]), 2)
312 313 data.append(self.add_data(flip+1))
313 314 while delay>252:
314 315 data.append(self.add_data(1))
315 316 delay -= 253
316 317
317 318 # write sampling period
318 319 data.append(self.add_cmd('SAMPLING_PERIOD'))
319 320 wins = self.get_lines(line_type__name='windows')
320 321 if wins:
321 322 win_params = json.loads(wins[0].params)['params']
322 323 if win_params:
323 324 dh = int(win_params[0]['resolution']*self.km2unit)
324 325 else:
325 326 dh = 1
326 327 else:
327 328 dh = 1
328 329 data.append(self.add_data(dh))
329 330
330 331 # write enable
331 332 data.append(self.add_cmd('ENABLE'))
332 333
333 334 return '\n'.join(['{}'.format(x) for tup in data for x in tup])
334 335
335 336 def update_from_file(self, filename):
336 337 '''
337 338 Update instance from file
338 339 '''
339 340
340 341 f = RCFile(filename)
341 342 self.dict_to_parms(f.data)
342 343 self.update_pulses()
343 344
344 345 def update_pulses(self):
345 346
346 347 for line in self.get_lines():
347 348 line.update_pulses()
348 349
349 350 def plot_pulses(self):
350 351
351 352 import matplotlib.pyplot as plt
352 353 from bokeh.resources import CDN
353 354 from bokeh.embed import components
354 355 from bokeh.mpl import to_bokeh
355 356 from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, PreviewSaveTool
356 357
357 358 lines = self.get_lines()
358 359
359 360 N = len(lines)
360 361 fig = plt.figure(figsize=(10, 2+N*0.5))
361 362 ax = fig.add_subplot(111)
362 363 labels = []
363 364
364 365 for i, line in enumerate(lines):
365 366 labels.append(line.get_name())
366 367 l = ax.plot((0, self.total_units),(N-i-1, N-i-1))
367 368 points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points() if tup<>(0,0)]
368 369 ax.broken_barh(points, (N-i-1, 0.5),
369 370 edgecolor=l[0].get_color(), facecolor='none')
370 371
371 372 labels.reverse()
372 373 ax.set_yticklabels(labels)
373 374 plot = to_bokeh(fig, use_pandas=False)
374 375 plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), PreviewSaveTool()]
375 376
376 377 return components(plot, CDN)
377 378
378 379 def status_device(self):
379 380
380 381 return 0
381 382
382 383 def stop_device(self):
383 384
384 385 answer = api.disable(ip = self.device.ip_address,
385 386 port = self.device.port_address)
386 387
387 388 if answer[0] != "1":
388 389 self.message = answer[0:]
389 390 return 0
390 391
391 392 self.message = answer[2:]
392 393 return 1
393 394
394 395 def start_device(self):
395 396
396 397 answer = api.enable(ip = self.device.ip_address,
397 398 port = self.device.port_address)
398 399
399 400 if answer[0] != "1":
400 401 self.message = answer[0:]
401 402 return 0
402 403
403 404 self.message = answer[2:]
404 405 return 1
405 406
406 407 def write_device(self):
407 408 answer = api.write_config(ip = self.device.ip_address,
408 409 port = self.device.port_address,
409 410 parms = self.parms_to_dict())
410 411
411 412 if answer[0] != "1":
412 413 self.message = answer[0:]
413 414 return 0
414 415
415 416 self.message = answer[2:]
416 417 return 1
417 418
418 419
419 420 class RCLineCode(models.Model):
420 421
421 422 name = models.CharField(max_length=40)
422 423 bits_per_code = models.PositiveIntegerField(default=0)
423 424 number_of_codes = models.PositiveIntegerField(default=0)
424 425 codes = models.TextField(blank=True, null=True)
425 426
426 427 class Meta:
427 428 db_table = 'rc_line_codes'
428 429 ordering = ('name',)
429 430
430 431 def __unicode__(self):
431 432 return u'%s' % self.name
432 433
433 434
434 435 class RCLineType(models.Model):
435 436
436 437 name = models.CharField(choices=LINE_TYPES, max_length=40)
437 438 description = models.TextField(blank=True, null=True)
438 439 params = models.TextField(default='[]')
439 440
440 441 class Meta:
441 442 db_table = 'rc_line_types'
442 443
443 444 def __unicode__(self):
444 445 return u'%s - %s' % (self.name.upper(), self.get_name_display())
445 446
446 447
447 448 class RCLine(models.Model):
448 449
449 450 rc_configuration = models.ForeignKey(RCConfiguration, on_delete=models.CASCADE)
450 451 line_type = models.ForeignKey(RCLineType)
451 452 channel = models.PositiveIntegerField(default=0)
452 453 position = models.PositiveIntegerField(default=0)
453 454 params = models.TextField(default='{}')
454 455 pulses = models.TextField(default='')
455 456
456 457 class Meta:
457 458 db_table = 'rc_lines'
458 459 ordering = ['channel']
459 460
460 461 def __unicode__(self):
461 462 if self.rc_configuration:
462 463 return u'%s - %s' % (self.rc_configuration, self.get_name())
463 464
464 465 def clone(self, **kwargs):
465 466
466 467 self.pk = None
467 468
468 469 for attr, value in kwargs.items():
469 470 setattr(self, attr, value)
470 471
471 472 self.save()
472 473
473 474 return self
474 475
475 476 def get_name(self):
476 477
477 478 chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
478 479 s = ''
479 480
480 481 if self.line_type.name in ('tx',):
481 482 s = chars[self.position]
482 483 elif self.line_type.name in ('codes', 'windows', 'tr'):
483 484 if 'TX_ref' in json.loads(self.params):
484 485 pk = json.loads(self.params)['TX_ref']
485 486 if pk in (0, '0'):
486 487 s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx'))
487 488 else:
488 489 ref = RCLine.objects.get(pk=pk)
489 490 s = chars[ref.position]
490 491 s = '({})'.format(s)
491 492 if s:
492 493 return '{}{} {}'.format(self.line_type.name.upper(), s, self.channel)
493 494 else:
494 495 return '{} {}'.format(self.line_type.name.upper(), self.channel)
495 496
496 497 def get_lines(self, **kwargs):
497 498
498 499 return RCLine.objects.filter(rc_configuration=self.rc_configuration, **kwargs)
499 500
500 501 def pulses_as_array(self):
501 502
502 503 y = np.zeros(self.rc_configuration.total_units)
503 504
504 505 for tup in ast.literal_eval(self.pulses):
505 506 y[tup[0]:tup[1]] = 1
506 507
507 508 return y.astype(np.int8)
508 509
509 510 def pulses_as_points(self):
510 511
511 512 return ast.literal_eval(self.pulses)
512 513
513 514 def get_win_ref(self, params, tx_id, km2unit):
514 515
515 516 ref = self.rc_configuration.sampling_reference
516 517 codes = [line for line in self.get_lines(line_type__name='codes') if int(json.loads(line.params)['TX_ref'])==int(tx_id)]
517 518
518 519 if codes:
519 520 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit/len(json.loads(codes[0].params)['codes'][0])
520 521 else:
521 522 tx_width = float(json.loads(RCLine.objects.get(pk=tx_id).params)['pulse_width'])*km2unit
522 523
523 524 if ref=='first_baud':
524 525 return int(1 + (tx_width + 1)/2 + params['first_height']*km2unit - params['resolution']*km2unit)
525 526 elif ref=='sub_baud':
526 527 return int(1 + params['first_height']*km2unit - params['resolution']*km2unit/2)
527 528 else:
528 529 return 0
529 530
530 531 def update_pulses(self):
531 532 '''
532 533 Update pulses field
533 534 '''
534 535
535 536 km2unit = self.rc_configuration.km2unit
536 537 us2unit = self.rc_configuration.us2unit
537 538 ipp = self.rc_configuration.ipp
538 539 ntx = self.rc_configuration.ntx
539 540 ipp_u = int(ipp*km2unit)
540 541 total = ipp_u*ntx
541 542 y = []
542 543
543 544 if self.line_type.name=='tr':
544 545 tr_params = json.loads(self.params)
545 546
546 547 if tr_params['TX_ref'] in ('0', 0):
547 548 txs = self.get_lines(line_type__name='tx')
548 549 else:
549 550 txs = [RCLine.objects.filter(pk=tr_params['TX_ref'])]
550 551
551 552 for tx in txs:
552 553 params = json.loads(tx.params)
553 554 if float(params['pulse_width'])==0:
554 555 continue
555 556 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
556 557 width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit)
557 558 before = 0
558 559 after = int(self.rc_configuration.time_after*us2unit)
559 560
560 561 y_tx = self.points(ntx, ipp_u, width,
561 562 delay=delays,
562 563 before=before,
563 564 after=after,
564 565 sync=self.rc_configuration.sync)
565 566
566 567 ranges = params['range'].split(',')
567 568
568 569 if len(ranges)>0 and ranges[0]<>'0':
569 570 y_tx = self.mask_ranges(y_tx, ranges)
570 571
571 572 tr_ranges = tr_params['range'].split(',')
572 573
573 574 if len(tr_ranges)>0 and tr_ranges[0]<>'0':
574 575 y_tx = self.mask_ranges(y_tx, tr_ranges)
575 576
576 577 y.extend(y_tx)
577 578
578 579 elif self.line_type.name=='tx':
579 580 params = json.loads(self.params)
580 581 delays = [float(d)*km2unit for d in params['delays'].split(',') if d]
581 582 width = float(params['pulse_width'])*km2unit
582 583
583 584 if width>0:
584 585 before = int(self.rc_configuration.time_before*us2unit)
585 586 after = 0
586 587
587 588 y = self.points(ntx, ipp_u, width,
588 589 delay=delays,
589 590 before=before,
590 591 after=after,
591 592 sync=self.rc_configuration.sync)
592 593
593 594 ranges = params['range'].split(',')
594 595
595 596 if len(ranges)>0 and ranges[0]<>'0':
596 597 y = self.mask_ranges(y, ranges)
597 598
598 599 elif self.line_type.name=='flip':
599 600 n = float(json.loads(self.params)['number_of_flips'])
600 601 width = n*ipp*km2unit
601 602 y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width)
602 603
603 604 elif self.line_type.name=='codes':
604 605 params = json.loads(self.params)
605 606 tx = RCLine.objects.get(pk=params['TX_ref'])
606 607 tx_params = json.loads(tx.params)
607 608 delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d]
608 609 f = int(float(tx_params['pulse_width'])*km2unit)/len(params['codes'][0])
609 610 codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']]
610 611 codes = [self.array_to_points(code) for code in codes]
611 612 n = len(codes)
612 613
613 614 for i, tup in enumerate(tx.pulses_as_points()):
614 615 code = codes[i%n]
615 616 y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code])
616 617
617 618 ranges = tx_params['range'].split(',')
618 619 if len(ranges)>0 and ranges[0]<>'0':
619 620 y = self.mask_ranges(y, ranges)
620 621
621 622 elif self.line_type.name=='sync':
622 623 params = json.loads(self.params)
623 624 n = ipp_u*ntx
624 625 if params['invert'] in ('1', 1):
625 626 y = [(n-1, n)]
626 627 else:
627 628 y = [(0, 1)]
628 629
629 630 elif self.line_type.name=='prog_pulses':
630 631 params = json.loads(self.params)
631 632 if int(params['periodic'])==0:
632 633 nntx = 1
633 634 nipp = ipp_u*ntx
634 635 else:
635 636 nntx = ntx
636 637 nipp = ipp_u
637 638
638 639 if 'params' in params and len(params['params'])>0:
639 640 for p in params['params']:
640 641 y_pp = self.points(nntx, nipp,
641 642 p['end']-p['begin'],
642 643 before=p['begin'])
643 644
644 645 y.extend(y_pp)
645 646
646 647 elif self.line_type.name=='windows':
647 648 params = json.loads(self.params)
648 649
649 650 if 'params' in params and len(params['params'])>0:
650 651 tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params)
651 652 tr_ranges = tr_params['range'].split(',')
652 653 for p in params['params']:
653 654 y_win = self.points(ntx, ipp_u,
654 655 p['resolution']*p['number_of_samples']*km2unit,
655 656 before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit),
656 657 sync=self.rc_configuration.sync)
657 658
658 659 if len(tr_ranges)>0 and tr_ranges[0]<>'0':
659 660 y_win = self.mask_ranges(y_win, tr_ranges)
660 661
661 662 y.extend(y_win)
662 663
663 664 elif self.line_type.name=='mix':
664 665 values = self.rc_configuration.parameters.split('-')
665 666 confs = RCConfiguration.objects.filter(pk__in=[value.split('|')[0] for value in values])
666 667 modes = [value.split('|')[1] for value in values]
667 668 ops = [value.split('|')[2] for value in values]
668 669 delays = [value.split('|')[3] for value in values]
669 670 masks = [value.split('|')[4] for value in values]
670 671 mask = list('{:8b}'.format(int(masks[0])))
671 672 mask.reverse()
672 673 if mask[self.channel] in ('0', '', ' '):
673 674 y = np.zeros(total, dtype=np.int8)
674 675 else:
675 676 y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array()
676 677
677 678 for i in range(1, len(values)):
678 679 mask = list('{:8b}'.format(int(masks[i])))
679 680 mask.reverse()
680 681
681 682 if mask[self.channel] in ('0', '', ' '):
682 683 continue
683 684 Y = confs[i].get_lines(channel=self.channel)[0].pulses_as_array()
684 685 delay = float(delays[i])*km2unit
685 686
686 687 if delay>0:
687 688 if delay<self.rc_configuration.ipp*km2unit and len(Y)==len(y):
688 689 y_temp = np.empty_like(Y)
689 690 y_temp[:delay] = 0
690 691 y_temp[delay:] = Y[:-delay]
691 692 elif delay+len(Y)>len(y):
692 693 y_new = np.zeros(delay+len(Y), dtype=np.int8)
693 694 y_new[:len(y)] = y
694 695 y = y_new
695 696 y_temp = np.zeros(delay+len(Y), dtype=np.int8)
696 697 y_temp[-len(Y):] = Y
697 698 elif delay+len(Y)==len(y):
698 699 y_temp = np.zeros(delay+len(Y))
699 700 y_temp[-len(Y):] = Y
700 701
701 702 if ops[i]=='OR':
702 703 y = y | y_temp
703 704 elif ops[i]=='XOR':
704 705 y = y ^ y_temp
705 706 elif ops[i]=='AND':
706 707 y = y & y_temp
707 708 elif ops[i]=='NAND':
708 709 y = y & ~y_temp
709 710
710 711 total = len(y)
711 712 y = self.array_to_points(y)
712 713
713 714 else:
714 715 y = []
715 716
716 717 if self.rc_configuration.total_units <> total:
717 718 self.rc_configuration.total_units = total
718 719 self.rc_configuration.save()
719 720
720 721 self.pulses = y
721 722 self.save()
722 723
723 724 @staticmethod
724 725 def array_to_points(X):
725 726
726 727 d = X[1:]-X[:-1]
727 728
728 729 up = np.where(d==1)[0]
729 730 if X[0]==1:
730 731 up = np.concatenate((np.array([-1]), up))
731 732 up += 1
732 733
733 734 dw = np.where(d==-1)[0]
734 735 if X[-1]==1:
735 736 dw = np.concatenate((dw, np.array([len(X)-1])))
736 737 dw += 1
737 738
738 739 return [(tup[0], tup[1]) for tup in zip(up, dw)]
739 740
740 741 @staticmethod
741 742 def mask_ranges(Y, ranges):
742 743
743 744 y = [(0, 0) for __ in Y]
744 745
745 746 for index in ranges:
746 747 if '-' in index:
747 748 args = [int(a) for a in index.split('-')]
748 749 y[args[0]-1:args[1]] = Y[args[0]-1:args[1]]
749 750 else:
750 751 y[int(index-1)] = Y[int(index-1)]
751 752
752 753 return y
753 754
754 755 @staticmethod
755 756 def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0):
756 757
757 758 delays = len(delay)
758 759
759 760 Y = [(ipp*x+before+delay[x%delays], ipp*x+width+before+delay[x%delays]+after) for x in range(ntx)]
760 761
761 762 return Y No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now