@@ -23,4 +23,5 | |||
|
23 | 23 | {"fields": {"params": "{\"invert\":{\"value\": 0, \"help\": \"Set to 1 for synchro pulse at the end\"}}", "name": "sync", "description": ""}, "model": "rc.rclinetype", "pk": 5}, |
|
24 | 24 | {"fields": {"params": "{ \"periodic\": { \"value\": 0, \"help\": \"Set to 1 for IPP periodic\"}, \"params\": {\"begin\": { \"value\": 0, \"widget\":\"unit\"}, \"end\": {\"value\": 0, \"widget\":\"unit\"}}}", "name": "prog_pulses", "description": ""}, "model": "rc.rclinetype", "pk": 6}, |
|
25 | 25 | {"fields": {"params": "{\"number_of_flips\": {\"value\": 0}}", "name": "flip", "description": ""}, "model": "rc.rclinetype", "pk": 7}, |
|
26 |
{"fields": {"params": "{}", "name": "none", "description": ""}, "model": "rc.rclinetype", "pk": 8} |
|
|
26 | {"fields": {"params": "{}", "name": "none", "description": ""}, "model": "rc.rclinetype", "pk": 8}, | |
|
27 | {"fields": {"params": "{}", "name": "mix", "description": ""}, "model": "rc.rclinetype", "pk": 9}] No newline at end of file |
@@ -78,7 +78,7 class RCConfigurationForm(forms.ModelForm): | |||
|
78 | 78 | |
|
79 | 79 | class Meta: |
|
80 | 80 | model = RCConfiguration |
|
81 | exclude = ('type', 'parameters', 'status') | |
|
81 | exclude = ('type', 'parameters', 'status', 'mix') | |
|
82 | 82 | |
|
83 | 83 | def clean(self): |
|
84 | 84 | form_data = super(RCConfigurationForm, self).clean() |
@@ -11,7 +11,7 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 | from .utils import RCFile, pulses, pulses_from_code, create_mask, pulses_to_points | |
|
14 | from .utils import RCFile | |
|
15 | 15 | |
|
16 | 16 | # Create your models here. |
|
17 | 17 | |
@@ -123,7 +123,7 class RCConfiguration(Configuration): | |||
|
123 | 123 | ''' |
|
124 | 124 | ''' |
|
125 | 125 | |
|
126 |
empty_line = RCLineType.objects.get( |
|
|
126 | empty_line = RCLineType.objects.get(name='none') | |
|
127 | 127 | |
|
128 | 128 | for line in self.get_lines(): |
|
129 | 129 | line.line_type = empty_line |
@@ -134,12 +134,15 class RCConfiguration(Configuration): | |||
|
134 | 134 | ''' |
|
135 | 135 | ''' |
|
136 | 136 | |
|
137 | ignored = ('parameters', 'type', 'polymorphic_ctype', 'configuration_ptr', | |
|
138 | 'created_date', 'programmed_date') | |
|
139 | ||
|
137 | 140 | data = {} |
|
138 | 141 | for field in self._meta.fields: |
|
139 | ||
|
142 | if field.name in ignored: | |
|
143 | continue | |
|
140 | 144 | data[field.name] = '{}'.format(field.value_from_object(self)) |
|
141 | 145 | |
|
142 | data.pop('parameters') | |
|
143 | 146 | data['lines'] = [] |
|
144 | 147 | |
|
145 | 148 | for line in self.get_lines(): |
@@ -214,7 +217,7 class RCConfiguration(Configuration): | |||
|
214 | 217 | |
|
215 | 218 | def get_delays(self): |
|
216 | 219 | |
|
217 |
pulses = [line. |
|
|
220 | pulses = [line.pulses_as_points() for line in self.get_lines()] | |
|
218 | 221 | points = [tup for tups in pulses for tup in tups] |
|
219 | 222 | points = set([x for tup in points for x in tup]) |
|
220 | 223 | points = list(points) |
@@ -228,13 +231,13 class RCConfiguration(Configuration): | |||
|
228 | 231 | |
|
229 | 232 | def get_pulses(self, binary=True): |
|
230 | 233 | |
|
231 |
pulses = [line. |
|
|
234 | pulses = [line.pulses_as_points() for line in self.get_lines()] | |
|
232 | 235 | points = [tup for tups in pulses for tup in tups] |
|
233 | 236 | points = set([x for tup in points for x in tup]) |
|
234 | 237 | points = list(points) |
|
235 | 238 | points.sort() |
|
236 | 239 | |
|
237 |
line_points = [ |
|
|
240 | line_points = [line.pulses_as_points() for line in self.get_lines()] | |
|
238 | 241 | line_points = [[(x, x+y) for x,y in tups] for tups in line_points] |
|
239 | 242 | line_points = [[t for x in tups for t in x] for tups in line_points] |
|
240 | 243 | states = [[1 if x in tups else 0 for tups in line_points] for x in points] |
@@ -330,16 +333,44 class RCConfiguration(Configuration): | |||
|
330 | 333 | |
|
331 | 334 | f = RCFile(filename) |
|
332 | 335 | self.dict_to_parms(f.data) |
|
336 | self.update_pulses() | |
|
337 | self.save() | |
|
333 | 338 | |
|
334 | 339 | def update_pulses(self): |
|
335 | 340 | |
|
336 | 341 | for line in self.get_lines(): |
|
337 | if line.line_type.name=='tr': | |
|
338 | continue | |
|
339 | 342 | line.update_pulses() |
|
343 | ||
|
344 | def plot_pulses(self): | |
|
345 | ||
|
346 | import matplotlib.pyplot as plt | |
|
347 | from bokeh.resources import CDN | |
|
348 | from bokeh.embed import components | |
|
349 | from bokeh.mpl import to_bokeh | |
|
350 | from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, PreviewSaveTool | |
|
351 | ||
|
352 | lines = self.get_lines() | |
|
340 | 353 | |
|
341 | for tr in self.get_lines(line_type__name='tr'): | |
|
342 | tr.update_pulses() | |
|
354 | max_value = self.ipp*self.km2unit*self.ntx | |
|
355 | ||
|
356 | N = len(lines) | |
|
357 | fig = plt.figure(figsize=(10, 2+N*0.5)) | |
|
358 | ax = fig.add_subplot(111) | |
|
359 | labels = [] | |
|
360 | ||
|
361 | for i, line in enumerate(lines): | |
|
362 | labels.append(line.get_name()) | |
|
363 | l = ax.plot((0, max_value),(N-i-1, N-i-1)) | |
|
364 | points = [(tup[0], tup[1]-tup[0]) for tup in line.pulses_as_points() if tup<>(0,0)] | |
|
365 | ax.broken_barh(points, (N-i-1, 0.5), | |
|
366 | edgecolor=l[0].get_color(), facecolor='none') | |
|
367 | ||
|
368 | labels.reverse() | |
|
369 | ax.set_yticklabels(labels) | |
|
370 | plot = to_bokeh(fig, use_pandas=False) | |
|
371 | plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), PreviewSaveTool()] | |
|
372 | ||
|
373 | return components(plot, CDN) | |
|
343 | 374 | |
|
344 | 375 | def status_device(self): |
|
345 | 376 | |
@@ -441,23 +472,23 class RCLine(models.Model): | |||
|
441 | 472 | def get_name(self): |
|
442 | 473 | |
|
443 | 474 | chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|
475 | s = '' | |
|
444 | 476 | |
|
445 | 477 | if self.line_type.name in ('tx',): |
|
446 | return '%s%s' % (self.line_type.name.upper(), chars[self.position]) | |
|
478 | s = chars[self.position] | |
|
447 | 479 | elif self.line_type.name in ('codes', 'windows', 'tr'): |
|
448 |
if 'TX_ref' |
|
|
449 | return self.line_type.name.upper() | |
|
450 | pk = json.loads(self.params)['TX_ref'] | |
|
451 | if pk in (0, '0'): | |
|
452 | refs = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx')) | |
|
453 | return '%s (%s)' % (self.line_type.name.upper(), refs) | |
|
454 | else: | |
|
455 | ref = RCLine.objects.get(pk=pk) | |
|
456 | return '%s (%s)' % (self.line_type.name.upper(), chars[ref.position]) | |
|
457 | elif self.line_type.name in ('flip', 'prog_pulses', 'sync', 'none', 'mix'): | |
|
458 | return '%s %s' % (self.line_type.name.upper(), self.channel) | |
|
480 | if 'TX_ref' in json.loads(self.params): | |
|
481 | pk = json.loads(self.params)['TX_ref'] | |
|
482 | if pk in (0, '0'): | |
|
483 | s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx')) | |
|
484 | else: | |
|
485 | ref = RCLine.objects.get(pk=pk) | |
|
486 | s = chars[ref.position] | |
|
487 | ||
|
488 | if s: | |
|
489 | return '{}({}) {}'.format(self.line_type.name.upper(), s, self.channel) | |
|
459 | 490 | else: |
|
460 | return self.line_type.name.upper() | |
|
491 | return '{} {}'.format(self.line_type.name.upper(), self.channel) | |
|
461 | 492 | |
|
462 | 493 | def get_lines(self, **kwargs): |
|
463 | 494 | |
@@ -465,25 +496,16 class RCLine(models.Model): | |||
|
465 | 496 | |
|
466 | 497 | def pulses_as_array(self): |
|
467 | 498 | |
|
468 | return (np.fromstring(self.pulses, dtype=np.uint8)-48).astype(np.int8) | |
|
469 | ||
|
470 | def get_pulses(self): | |
|
471 | ||
|
472 | X = self.pulses_as_array() | |
|
499 | y = np.zeros(self.rc_configuration.ntx*self.rc_configuration.ipp*self.rc_configuration.km2unit) | |
|
473 | 500 | |
|
474 | d = X[1:]-X[:-1] | |
|
501 | for tup in ast.literal_eval(self.pulses): | |
|
502 | y[tup[0]:tup[1]] = 1 | |
|
503 | ||
|
504 | return y.astype(np.int8) | |
|
475 | 505 | |
|
476 | up = np.where(d==1)[0] | |
|
477 | if X[0]==1: | |
|
478 | up = np.concatenate((np.array([-1]), up)) | |
|
479 | up += 1 | |
|
506 | def pulses_as_points(self): | |
|
480 | 507 | |
|
481 | dw = np.where(d==-1)[0] | |
|
482 | if X[-1]==1: | |
|
483 | dw = np.concatenate((dw, np.array([len(X)-1]))) | |
|
484 | dw += 1 | |
|
485 | ||
|
486 | return [(tup[0], tup[1]) for tup in zip(up, dw)] | |
|
508 | return ast.literal_eval(self.pulses) | |
|
487 | 509 | |
|
488 | 510 | def get_win_ref(self, params, tx_id, km2unit): |
|
489 | 511 | |
@@ -502,7 +524,7 class RCLine(models.Model): | |||
|
502 | 524 | else: |
|
503 | 525 | return 0 |
|
504 | 526 | |
|
505 |
def update_pulses(self |
|
|
527 | def update_pulses(self): | |
|
506 | 528 | ''' |
|
507 | 529 | Update pulses field |
|
508 | 530 | ''' |
@@ -513,93 +535,128 class RCLine(models.Model): | |||
|
513 | 535 | ntx = self.rc_configuration.ntx |
|
514 | 536 | ipp_u = int(ipp*km2unit) |
|
515 | 537 | |
|
516 | x = np.arange(0, ipp_u*ntx) | |
|
538 | y = [] | |
|
517 | 539 | |
|
518 | 540 | if self.line_type.name=='tr': |
|
519 | params = json.loads(self.params) | |
|
520 | if params['TX_ref'] in ('0', 0): | |
|
521 | txs = [tx.update_pulses(save=False, tr=True) for tx in self.get_lines(line_type__name='tx')] | |
|
541 | tr_params = json.loads(self.params) | |
|
542 | ||
|
543 | if tr_params['TX_ref'] in ('0', 0): | |
|
544 | txs = self.get_lines(line_type__name='tx') | |
|
522 | 545 | else: |
|
523 |
txs = [ |
|
|
524 | if len(txs)==0 or 0 in [len(tx) for tx in txs]: | |
|
525 | return | |
|
546 | txs = [RCLine.objects.filter(pk=tr_params['TX_ref'])] | |
|
526 | 547 | |
|
527 | y = np.any(txs, axis=0, out=np.ones(ipp_u*ntx)) | |
|
528 | ||
|
529 | ranges = params['range'].split(',') | |
|
530 | if len(ranges)>0 and ranges[0]<>'0': | |
|
531 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) | |
|
532 | y = y.astype(np.int8) & mask | |
|
548 | for tx in txs: | |
|
549 | params = json.loads(tx.params) | |
|
550 | if float(params['pulse_width'])==0: | |
|
551 | continue | |
|
552 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] | |
|
553 | width = float(params['pulse_width'])*km2unit+int(self.rc_configuration.time_before*us2unit) | |
|
554 | before = 0 | |
|
555 | after = int(self.rc_configuration.time_after*us2unit) | |
|
556 | ||
|
557 | y_tx = self.points(ntx, ipp_u, width, | |
|
558 | delay=delays, | |
|
559 | before=before, | |
|
560 | after=after, | |
|
561 | sync=self.rc_configuration.sync) | |
|
562 | ||
|
563 | ranges = params['range'].split(',') | |
|
564 | ||
|
565 | if len(ranges)>0 and ranges[0]<>'0': | |
|
566 | y_tx = self.mask_ranges(y_tx, ranges) | |
|
567 | ||
|
568 | tr_ranges = tr_params['range'].split(',') | |
|
569 | ||
|
570 | if len(tr_ranges)>0 and tr_ranges[0]<>'0': | |
|
571 | y_tx = self.mask_ranges(y_tx, tr_ranges) | |
|
572 | ||
|
573 | y.extend(y_tx) | |
|
533 | 574 | |
|
534 | 575 | elif self.line_type.name=='tx': |
|
535 | 576 | params = json.loads(self.params) |
|
536 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] | |
|
537 |
|
|
|
538 | delay=delays, | |
|
539 | before=int(self.rc_configuration.time_before*us2unit), | |
|
540 | after=int(self.rc_configuration.time_after*us2unit) if tr else 0, | |
|
541 | sync=self.rc_configuration.sync) | |
|
542 | ||
|
543 | ranges = params['range'].split(',') | |
|
577 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] | |
|
578 | width = float(params['pulse_width'])*km2unit | |
|
544 | 579 | |
|
545 | if len(ranges)>0 and ranges[0]<>'0': | |
|
546 |
|
|
|
547 |
|
|
|
580 | if width>0: | |
|
581 | before = int(self.rc_configuration.time_before*us2unit) | |
|
582 | after = 0 | |
|
583 | ||
|
584 | y = self.points(ntx, ipp_u, width, | |
|
585 | delay=delays, | |
|
586 | before=before, | |
|
587 | after=after, | |
|
588 | sync=self.rc_configuration.sync) | |
|
589 | ||
|
590 | ranges = params['range'].split(',') | |
|
591 | ||
|
592 | if len(ranges)>0 and ranges[0]<>'0': | |
|
593 | y = self.mask_ranges(y, ranges) | |
|
548 | 594 | |
|
549 | 595 | elif self.line_type.name=='flip': |
|
550 |
|
|
|
551 | y = pulses(x, 2*width, width) | |
|
596 | n = float(json.loads(self.params)['number_of_flips']) | |
|
597 | width = n*ipp*km2unit | |
|
598 | y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width) | |
|
552 | 599 | |
|
553 | 600 | elif self.line_type.name=='codes': |
|
554 | 601 | params = json.loads(self.params) |
|
555 | 602 | tx = RCLine.objects.get(pk=params['TX_ref']) |
|
556 | 603 | tx_params = json.loads(tx.params) |
|
557 | delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d] | |
|
558 | y = pulses_from_code(tx.pulses_as_array(), | |
|
559 | params['codes'], | |
|
560 | int(float(tx_params['pulse_width'])*km2unit)) | |
|
604 | delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d] | |
|
605 | f = int(float(tx_params['pulse_width'])*km2unit)/len(params['codes'][0]) | |
|
606 | codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']] | |
|
607 | codes = [self.array_to_points(code) for code in codes] | |
|
608 | n = len(codes) | |
|
561 | 609 | |
|
610 | for i, tup in enumerate(tx.pulses_as_points()): | |
|
611 | code = codes[i%n] | |
|
612 | y.extend([(c[0]+tup[0], c[1]+tup[0]) for c in code]) | |
|
613 | ||
|
562 | 614 | ranges = tx_params['range'].split(',') |
|
563 | 615 | if len(ranges)>0 and ranges[0]<>'0': |
|
564 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) | |
|
565 | y = y.astype(np.int8) & mask | |
|
616 | y = self.mask_ranges(y, ranges) | |
|
566 | 617 | |
|
567 | 618 | elif self.line_type.name=='sync': |
|
568 | 619 | params = json.loads(self.params) |
|
569 |
|
|
|
620 | n = ipp_u*ntx | |
|
570 | 621 | if params['invert'] in ('1', 1): |
|
571 |
y |
|
|
622 | y = [(n-1, n)] | |
|
572 | 623 | else: |
|
573 |
y |
|
|
624 | y = [(0, 1)] | |
|
574 | 625 | |
|
575 | 626 | elif self.line_type.name=='prog_pulses': |
|
576 | 627 | params = json.loads(self.params) |
|
577 | 628 | if int(params['periodic'])==0: |
|
578 | nntx = ntx | |
|
579 | else: | |
|
580 | 629 | nntx = 1 |
|
630 | nipp = ipp_u*ntx | |
|
631 | else: | |
|
632 | nntx = ntx | |
|
633 | nipp = ipp_u | |
|
581 | 634 | |
|
582 | 635 | if 'params' in params and len(params['params'])>0: |
|
583 | y = sum([pulses(x, ipp_u*nntx, (pp['end']-pp['begin']), shift=pp['begin']) for pp in params['params']]) | |
|
584 | else: | |
|
585 | y = np.zeros(ipp_u*ntx) | |
|
586 | ||
|
636 | for p in params['params']: | |
|
637 | y_pp = self.points(nntx, nipp, | |
|
638 | p['end']-p['begin'], | |
|
639 | before=p['begin']) | |
|
640 | ||
|
641 | y.extend(y_pp) | |
|
642 | ||
|
587 | 643 | elif self.line_type.name=='windows': |
|
588 | params = json.loads(self.params) | |
|
644 | params = json.loads(self.params) | |
|
589 | 645 | |
|
590 | 646 | if 'params' in params and len(params['params'])>0: |
|
591 | y = sum([pulses(x, ipp_u, pp['resolution']*pp['number_of_samples']*km2unit, | |
|
592 | shift=0, | |
|
593 | before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(pp, params['TX_ref'],km2unit), | |
|
594 | sync=self.rc_configuration.sync) for pp in params['params']]) | |
|
595 | tr = self.get_lines(line_type__name='tr')[0] | |
|
596 | ranges = json.loads(tr.params)['range'].split(',') | |
|
597 | if len(ranges)>0 and ranges[0]<>'0': | |
|
598 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) | |
|
599 | y = y & mask | |
|
600 | else: | |
|
601 | y = np.zeros(ipp_u*ntx) | |
|
602 | ||
|
647 | tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params) | |
|
648 | tr_ranges = tr_params['range'].split(',') | |
|
649 | for p in params['params']: | |
|
650 | y_win = self.points(ntx, ipp_u, | |
|
651 | p['resolution']*p['number_of_samples']*km2unit, | |
|
652 | before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit), | |
|
653 | sync=self.rc_configuration.sync) | |
|
654 | ||
|
655 | if len(tr_ranges)>0 and tr_ranges[0]<>'0': | |
|
656 | y_win = self.mask_ranges(y_win, tr_ranges) | |
|
657 | ||
|
658 | y.extend(y_win) | |
|
659 | ||
|
603 | 660 | elif self.line_type.name=='mix': |
|
604 | 661 | values = self.rc_configuration.parameters.split('-') |
|
605 | 662 | confs = RCConfiguration.objects.filter(pk__in=[value.split('|')[0] for value in values]) |
@@ -608,7 +665,7 class RCLine(models.Model): | |||
|
608 | 665 | masks = [value.split('|')[3] for value in values] |
|
609 | 666 | |
|
610 | 667 | y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array() |
|
611 | ||
|
668 | ysize = len(y) | |
|
612 | 669 | for i in range(1, len(values)): |
|
613 | 670 | mask = list('{:8b}'.format(int(masks[i]))) |
|
614 | 671 | mask.reverse() |
@@ -621,25 +678,60 class RCLine(models.Model): | |||
|
621 | 678 | y_temp = np.empty_like(Y) |
|
622 | 679 | y_temp[:delay] = 0 |
|
623 | 680 | y_temp[delay:] = Y[:-delay] |
|
624 | ||
|
681 | y_tempsize = len(y_temp) | |
|
625 | 682 | if modes[i]=='OR': |
|
626 |
y |
|
|
683 | y = y | y_temp | |
|
627 | 684 | elif modes[i]=='XOR': |
|
628 |
y |
|
|
685 | y = y ^ y_temp | |
|
629 | 686 | elif modes[i]=='AND': |
|
630 |
y |
|
|
687 | y = y & y_temp | |
|
631 | 688 | elif modes[i]=='NAND': |
|
632 |
y |
|
|
689 | y = y & ~y_temp | |
|
633 | 690 | |
|
634 | y = y2 | |
|
691 | y = self.array_to_points(y) | |
|
635 | 692 | |
|
636 | 693 | else: |
|
637 |
y = |
|
|
694 | y = [] | |
|
638 | 695 | |
|
639 | if save: | |
|
640 | self.pulses = (y+48).astype(np.uint8).tostring() | |
|
641 | self.save() | |
|
642 | else: | |
|
643 | return y | |
|
696 | self.pulses = y | |
|
697 | self.save() | |
|
698 | ||
|
699 | @staticmethod | |
|
700 | def array_to_points(X): | |
|
701 | ||
|
702 | d = X[1:]-X[:-1] | |
|
703 | ||
|
704 | up = np.where(d==1)[0] | |
|
705 | if X[0]==1: | |
|
706 | up = np.concatenate((np.array([-1]), up)) | |
|
707 | up += 1 | |
|
708 | ||
|
709 | dw = np.where(d==-1)[0] | |
|
710 | if X[-1]==1: | |
|
711 | dw = np.concatenate((dw, np.array([len(X)-1]))) | |
|
712 | dw += 1 | |
|
713 | ||
|
714 | return [(tup[0], tup[1]) for tup in zip(up, dw)] | |
|
715 | ||
|
716 | @staticmethod | |
|
717 | def mask_ranges(Y, ranges): | |
|
718 | ||
|
719 | y = [(0, 0) for __ in Y] | |
|
720 | ||
|
721 | for index in ranges: | |
|
722 | if '-' in index: | |
|
723 | args = [int(a) for a in index.split('-')] | |
|
724 | y[args[0]-1:args[1]] = Y[args[0]-1:args[1]] | |
|
725 | else: | |
|
726 | y[int(index-1)] = Y[int(index-1)] | |
|
727 | ||
|
728 | return y | |
|
729 | ||
|
730 | @staticmethod | |
|
731 | def points(ntx, ipp, width, delay=[0], before=0, after=0, sync=0): | |
|
732 | ||
|
733 | delays = len(delay) | |
|
734 | ||
|
735 | Y = [(ipp*x+before+delay[x%delays], ipp*x+width+before+delay[x%delays]+after) for x in range(ntx)] | |
|
644 | 736 | |
|
645 | No newline at end of file | |
|
737 | return Y No newline at end of file |
@@ -4,7 +4,7 urlpatterns = ( | |||
|
4 | 4 | url(r'^(?P<conf_id>-?\d+)/$', 'apps.rc.views.conf', name='url_rc_conf'), |
|
5 | 5 | url(r'^(?P<conf_id>-?\d+)/import/$', 'apps.rc.views.import_file', name='url_import_rc_conf'), |
|
6 | 6 | url(r'^(?P<conf_id>-?\d+)/edit/$', 'apps.rc.views.conf_edit', name='url_edit_rc_conf'), |
|
7 |
url(r'^(?P<conf_id>-?\d+)/plot/$', 'apps.rc.views. |
|
|
7 | url(r'^(?P<conf_id>-?\d+)/plot/$', 'apps.rc.views.plot_pulses', name='url_plot_rc_pulses'), | |
|
8 | 8 | url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_rc_conf'), |
|
9 | 9 | url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_rc_conf'), |
|
10 | 10 |
@@ -1,8 +1,5 | |||
|
1 | 1 | |
|
2 | 2 | import json |
|
3 | import numpy as np | |
|
4 | import matplotlib.pyplot as plt | |
|
5 | ||
|
6 | 3 | |
|
7 | 4 | class RCFile(object): |
|
8 | 5 | ''' |
@@ -207,109 +204,3 class RCFile(object): | |||
|
207 | 204 | return json.dumps(self.data, indent=indent) |
|
208 | 205 | |
|
209 | 206 | |
|
210 | def pulses_to_points(X): | |
|
211 | ||
|
212 | ||
|
213 | d = X[1:]-X[:-1] | |
|
214 | ||
|
215 | up = np.where(d==1)[0] | |
|
216 | if X[0]==1: | |
|
217 | up = np.concatenate((np.array([-1]), up)) | |
|
218 | up += 1 | |
|
219 | ||
|
220 | dw = np.where(d==-1)[0] | |
|
221 | if X[-1]==1: | |
|
222 | dw = np.concatenate((dw, np.array([len(X)-1]))) | |
|
223 | dw += 1 | |
|
224 | ||
|
225 | return [(tup[0], tup[1]-tup[0]) for tup in zip(up, dw)] | |
|
226 | ||
|
227 | def pulses_from_code(X, codes, width): | |
|
228 | ||
|
229 | d = X[1:]-X[:-1] | |
|
230 | ||
|
231 | up = np.where(d==1)[0] | |
|
232 | if X[0]==1: | |
|
233 | up = np.concatenate((np.array([-1]), up)) | |
|
234 | up += 1 | |
|
235 | ||
|
236 | f = width/len(codes[0]) | |
|
237 | codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in codes] | |
|
238 | ||
|
239 | y = np.zeros(len(X)) | |
|
240 | ||
|
241 | j=0 | |
|
242 | n = len(codes) | |
|
243 | for i in up: | |
|
244 | y[i:i+width] = codes[j%n] | |
|
245 | j += 1 | |
|
246 | ||
|
247 | return y | |
|
248 | ||
|
249 | ||
|
250 | def create_mask(ranges, ipp, ntx, sync): | |
|
251 | ||
|
252 | x = np.arange(ipp*ntx) | |
|
253 | iranges = set() | |
|
254 | ||
|
255 | for index in ranges: | |
|
256 | if '-' in index: | |
|
257 | args = [int(a) for a in index.split('-')] | |
|
258 | iranges = iranges.union([i for i in range(args[0], args[1]+1)]) | |
|
259 | else: | |
|
260 | iranges.add(int(index)) | |
|
261 | ||
|
262 | y = np.any([(x>=(idx-1)*ipp+sync) & (x<idx*ipp+sync) for idx in iranges], axis=0).astype(np.int8) | |
|
263 | ||
|
264 | return y | |
|
265 | ||
|
266 | ||
|
267 | def pulses(X, period, width, delay=0, before=0, after=0, sync=0, shift=0): | |
|
268 | ||
|
269 | delay_array = delay | |
|
270 | ||
|
271 | if isinstance(delay, (list, tuple)): | |
|
272 | delay_array = np.ones(len(X)) | |
|
273 | delays = [d for __ in xrange(len(X)/(period*len(delay))) for d in delay] | |
|
274 | for i, delay in enumerate(delays): | |
|
275 | delay_array[np.arange(period*i, period*(i+1))] *= delay | |
|
276 | ||
|
277 | if after>0: | |
|
278 | width += after+before | |
|
279 | before = 0 | |
|
280 | ||
|
281 | Y = ((X%period<width+delay_array+before+sync) & (X%period>=delay_array+before+sync)).astype(np.int8) | |
|
282 | ||
|
283 | if shift>0: | |
|
284 | y = np.empty_like(Y) | |
|
285 | y[:shift] = 0 | |
|
286 | y[shift:] = Y[:-shift] | |
|
287 | return y | |
|
288 | else: | |
|
289 | return Y | |
|
290 | ||
|
291 | ||
|
292 | def plot_pulses(unit, maximun, lines): | |
|
293 | ||
|
294 | from bokeh.resources import CDN | |
|
295 | from bokeh.embed import components | |
|
296 | from bokeh.mpl import to_bokeh | |
|
297 | from bokeh.models.tools import WheelZoomTool, ResetTool, PanTool, PreviewSaveTool | |
|
298 | ||
|
299 | N = len(lines) | |
|
300 | fig = plt.figure(figsize=(10, 2+N*0.5)) | |
|
301 | ax = fig.add_subplot(111) | |
|
302 | labels = [] | |
|
303 | ||
|
304 | for i, line in enumerate(lines): | |
|
305 | labels.append(line.get_name()) | |
|
306 | l = ax.plot((0, maximun),(N-i-1, N-i-1)) | |
|
307 | ax.broken_barh(pulses_to_points(line.pulses_as_array()), (N-i-1, 0.5), | |
|
308 | edgecolor=l[0].get_color(), facecolor='none') | |
|
309 | ||
|
310 | labels.reverse() | |
|
311 | ax.set_yticklabels(labels) | |
|
312 | plot = to_bokeh(fig, use_pandas=False) | |
|
313 | plot.tools = [PanTool(dimensions=['width']), WheelZoomTool(dimensions=['width']), ResetTool(), PreviewSaveTool()] | |
|
314 | ||
|
315 | return components(plot, CDN) |
@@ -10,7 +10,6 from apps.main.views import sidebar | |||
|
10 | 10 | |
|
11 | 11 | from .models import RCConfiguration, RCLine, RCLineType, RCLineCode |
|
12 | 12 | from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm |
|
13 | from .utils import plot_pulses | |
|
14 | 13 | |
|
15 | 14 | |
|
16 | 15 | def conf(request, conf_id): |
@@ -329,25 +328,13 def import_file(request, conf_id): | |||
|
329 | 328 | if request.method=='POST': |
|
330 | 329 | form = RCImportForm(request.POST, request.FILES) |
|
331 | 330 | if form.is_valid(): |
|
332 |
|
|
|
333 | if True: | |
|
334 | ||
|
331 | try: | |
|
335 | 332 | conf.update_from_file(request.FILES['file_name']) |
|
336 | conf.save() | |
|
337 | ||
|
338 | for line in conf.get_lines(): | |
|
339 | if line.line_type.name=='tr': | |
|
340 | continue | |
|
341 | line.update_pulses() | |
|
342 | ||
|
343 | for tr in conf.get_lines('tr'): | |
|
344 | tr.update_pulses() | |
|
345 | ||
|
346 | 333 | messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name']) |
|
347 | return redirect(conf.get_absolute_url()) | |
|
334 | return redirect(conf.get_absolute_url_edit()) | |
|
348 | 335 | |
|
349 |
|
|
|
350 |
|
|
|
336 | except Exception as e: | |
|
337 | messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e)) | |
|
351 | 338 | |
|
352 | 339 | else: |
|
353 | 340 | messages.warning(request, 'Your current configuration will be replaced') |
@@ -363,16 +350,11 def import_file(request, conf_id): | |||
|
363 | 350 | return render(request, 'rc_import.html', kwargs) |
|
364 | 351 | |
|
365 | 352 | |
|
366 |
def |
|
|
353 | def plot_pulses(request, conf_id): | |
|
367 | 354 | |
|
368 | conf = get_object_or_404(RCConfiguration, pk=conf_id) | |
|
369 | lines = RCLine.objects.filter(rc_configuration=conf) | |
|
370 | ||
|
371 | unit = (conf.clock/conf.clock_divider)*3./20 | |
|
372 | ||
|
373 | N = conf.ipp*conf.km2unit*conf.ntx | |
|
355 | conf = get_object_or_404(RCConfiguration, pk=conf_id) | |
|
374 | 356 | |
|
375 |
script, div = plot_pulses( |
|
|
357 | script, div = conf.plot_pulses() | |
|
376 | 358 | |
|
377 | 359 | kwargs = {} |
|
378 | 360 | |
@@ -380,6 +362,9 def view_pulses(request, conf_id): | |||
|
380 | 362 | kwargs['suptitle'] = conf.name |
|
381 | 363 | kwargs['div'] = mark_safe(div) |
|
382 | 364 | kwargs['script'] = mark_safe(script) |
|
383 | ||
|
384 | return render(request, 'rc_pulses.html', kwargs) | |
|
365 | ||
|
366 | if 'json' in request.GET: | |
|
367 | return HttpResponse(json.dumps({'div':mark_safe(div), 'script':mark_safe(script)}), content_type="application/json") | |
|
368 | else: | |
|
369 | return render(request, 'rc_pulses.html', kwargs) | |
|
385 | 370 |
General Comments 0
You need to be logged in to leave comments.
Login now