@@ -23,4 +23,5 | |||||
23 | {"fields": {"params": "{\"invert\":{\"value\": 0, \"help\": \"Set to 1 for synchro pulse at the end\"}}", "name": "sync", "description": ""}, "model": "rc.rclinetype", "pk": 5}, |
|
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 | {"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}, |
|
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 | {"fields": {"params": "{\"number_of_flips\": {\"value\": 0}}", "name": "flip", "description": ""}, "model": "rc.rclinetype", "pk": 7}, |
|
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 | class Meta: |
|
79 | class Meta: | |
80 | model = RCConfiguration |
|
80 | model = RCConfiguration | |
81 | exclude = ('type', 'parameters', 'status') |
|
81 | exclude = ('type', 'parameters', 'status', 'mix') | |
82 |
|
82 | |||
83 | def clean(self): |
|
83 | def clean(self): | |
84 | form_data = super(RCConfigurationForm, self).clean() |
|
84 | form_data = super(RCConfigurationForm, self).clean() |
@@ -11,7 +11,7 from django.core.validators import MinValueValidator, MaxValueValidator | |||||
11 |
|
11 | |||
12 | from apps.main.models import Configuration |
|
12 | from apps.main.models import Configuration | |
13 | from devices.rc import api |
|
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 | # Create your models here. |
|
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 | 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 | |
@@ -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 | data = {} |
|
140 | data = {} | |
138 | for field in self._meta.fields: |
|
141 | for field in self._meta.fields: | |
139 |
|
142 | if field.name in ignored: | ||
|
143 | continue | |||
140 | data[field.name] = '{}'.format(field.value_from_object(self)) |
|
144 | data[field.name] = '{}'.format(field.value_from_object(self)) | |
141 |
|
145 | |||
142 | data.pop('parameters') |
|
|||
143 | data['lines'] = [] |
|
146 | data['lines'] = [] | |
144 |
|
147 | |||
145 | for line in self.get_lines(): |
|
148 | for line in self.get_lines(): | |
@@ -214,7 +217,7 class RCConfiguration(Configuration): | |||||
214 |
|
217 | |||
215 | def get_delays(self): |
|
218 | def get_delays(self): | |
216 |
|
219 | |||
217 |
pulses = [line. |
|
220 | pulses = [line.pulses_as_points() for line in self.get_lines()] | |
218 | points = [tup for tups in pulses for tup in tups] |
|
221 | points = [tup for tups in pulses for tup in tups] | |
219 | points = set([x for tup in points for x in tup]) |
|
222 | points = set([x for tup in points for x in tup]) | |
220 | points = list(points) |
|
223 | points = list(points) | |
@@ -228,13 +231,13 class RCConfiguration(Configuration): | |||||
228 |
|
231 | |||
229 | def get_pulses(self, binary=True): |
|
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 | points = [tup for tups in pulses for tup in tups] |
|
235 | points = [tup for tups in pulses for tup in tups] | |
233 | points = set([x for tup in points for x in tup]) |
|
236 | points = set([x for tup in points for x in tup]) | |
234 | points = list(points) |
|
237 | points = list(points) | |
235 | points.sort() |
|
238 | points.sort() | |
236 |
|
239 | |||
237 |
line_points = [ |
|
240 | line_points = [line.pulses_as_points() for line in self.get_lines()] | |
238 | line_points = [[(x, x+y) for x,y in tups] for tups in line_points] |
|
241 | line_points = [[(x, x+y) for x,y in tups] for tups in line_points] | |
239 | line_points = [[t for x in tups for t in x] for tups in line_points] |
|
242 | line_points = [[t for x in tups for t in x] for tups in line_points] | |
240 | states = [[1 if x in tups else 0 for tups in line_points] for x in points] |
|
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 | f = RCFile(filename) |
|
334 | f = RCFile(filename) | |
332 | self.dict_to_parms(f.data) |
|
335 | self.dict_to_parms(f.data) | |
|
336 | self.update_pulses() | |||
|
337 | self.save() | |||
333 |
|
338 | |||
334 | def update_pulses(self): |
|
339 | def update_pulses(self): | |
335 |
|
340 | |||
336 | for line in self.get_lines(): |
|
341 | for line in self.get_lines(): | |
337 | if line.line_type.name=='tr': |
|
|||
338 | continue |
|
|||
339 | line.update_pulses() |
|
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'): |
|
354 | max_value = self.ipp*self.km2unit*self.ntx | |
342 | tr.update_pulses() |
|
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 | def status_device(self): |
|
375 | def status_device(self): | |
345 |
|
376 | |||
@@ -441,23 +472,23 class RCLine(models.Model): | |||||
441 | def get_name(self): |
|
472 | def get_name(self): | |
442 |
|
473 | |||
443 | chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
|
474 | chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | |
|
475 | s = '' | |||
444 |
|
476 | |||
445 | if self.line_type.name in ('tx',): |
|
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 | elif self.line_type.name in ('codes', 'windows', 'tr'): |
|
479 | elif self.line_type.name in ('codes', 'windows', 'tr'): | |
448 |
if 'TX_ref' |
|
480 | if 'TX_ref' in json.loads(self.params): | |
449 | return self.line_type.name.upper() |
|
481 | pk = json.loads(self.params)['TX_ref'] | |
450 | pk = json.loads(self.params)['TX_ref'] |
|
482 | if pk in (0, '0'): | |
451 | if pk in (0, '0'): |
|
483 | s = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx')) | |
452 | refs = ','.join(chars[l.position] for l in self.rc_configuration.get_lines(line_type__name='tx')) |
|
484 | else: | |
453 | return '%s (%s)' % (self.line_type.name.upper(), refs) |
|
485 | ref = RCLine.objects.get(pk=pk) | |
454 | else: |
|
486 | s = chars[ref.position] | |
455 | ref = RCLine.objects.get(pk=pk) |
|
487 | ||
456 | return '%s (%s)' % (self.line_type.name.upper(), chars[ref.position]) |
|
488 | if s: | |
457 | elif self.line_type.name in ('flip', 'prog_pulses', 'sync', 'none', 'mix'): |
|
489 | return '{}({}) {}'.format(self.line_type.name.upper(), s, self.channel) | |
458 | return '%s %s' % (self.line_type.name.upper(), self.channel) |
|
|||
459 | else: |
|
490 | else: | |
460 | return self.line_type.name.upper() |
|
491 | return '{} {}'.format(self.line_type.name.upper(), self.channel) | |
461 |
|
492 | |||
462 | def get_lines(self, **kwargs): |
|
493 | def get_lines(self, **kwargs): | |
463 |
|
494 | |||
@@ -465,25 +496,16 class RCLine(models.Model): | |||||
465 |
|
496 | |||
466 | def pulses_as_array(self): |
|
497 | def pulses_as_array(self): | |
467 |
|
498 | |||
468 | return (np.fromstring(self.pulses, dtype=np.uint8)-48).astype(np.int8) |
|
499 | y = np.zeros(self.rc_configuration.ntx*self.rc_configuration.ipp*self.rc_configuration.km2unit) | |
469 |
|
||||
470 | def get_pulses(self): |
|
|||
471 |
|
||||
472 | X = self.pulses_as_array() |
|
|||
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] |
|
506 | def pulses_as_points(self): | |
477 | if X[0]==1: |
|
|||
478 | up = np.concatenate((np.array([-1]), up)) |
|
|||
479 | up += 1 |
|
|||
480 |
|
507 | |||
481 | dw = np.where(d==-1)[0] |
|
508 | return ast.literal_eval(self.pulses) | |
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)] |
|
|||
487 |
|
509 | |||
488 | def get_win_ref(self, params, tx_id, km2unit): |
|
510 | def get_win_ref(self, params, tx_id, km2unit): | |
489 |
|
511 | |||
@@ -502,7 +524,7 class RCLine(models.Model): | |||||
502 | else: |
|
524 | else: | |
503 | return 0 |
|
525 | return 0 | |
504 |
|
526 | |||
505 |
def update_pulses(self |
|
527 | def update_pulses(self): | |
506 | ''' |
|
528 | ''' | |
507 | Update pulses field |
|
529 | Update pulses field | |
508 | ''' |
|
530 | ''' | |
@@ -513,93 +535,128 class RCLine(models.Model): | |||||
513 | ntx = self.rc_configuration.ntx |
|
535 | ntx = self.rc_configuration.ntx | |
514 | ipp_u = int(ipp*km2unit) |
|
536 | ipp_u = int(ipp*km2unit) | |
515 |
|
537 | |||
516 | x = np.arange(0, ipp_u*ntx) |
|
538 | y = [] | |
517 |
|
539 | |||
518 | if self.line_type.name=='tr': |
|
540 | if self.line_type.name=='tr': | |
519 | params = json.loads(self.params) |
|
541 | tr_params = json.loads(self.params) | |
520 | if params['TX_ref'] in ('0', 0): |
|
542 | ||
521 | txs = [tx.update_pulses(save=False, tr=True) for tx in self.get_lines(line_type__name='tx')] |
|
543 | if tr_params['TX_ref'] in ('0', 0): | |
|
544 | txs = self.get_lines(line_type__name='tx') | |||
522 | else: |
|
545 | else: | |
523 |
txs = [ |
|
546 | txs = [RCLine.objects.filter(pk=tr_params['TX_ref'])] | |
524 | if len(txs)==0 or 0 in [len(tx) for tx in txs]: |
|
|||
525 | return |
|
|||
526 |
|
547 | |||
527 | y = np.any(txs, axis=0, out=np.ones(ipp_u*ntx)) |
|
548 | for tx in txs: | |
528 |
|
549 | params = json.loads(tx.params) | ||
529 | ranges = params['range'].split(',') |
|
550 | if float(params['pulse_width'])==0: | |
530 | if len(ranges)>0 and ranges[0]<>'0': |
|
551 | continue | |
531 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) |
|
552 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] | |
532 | y = y.astype(np.int8) & mask |
|
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 | elif self.line_type.name=='tx': |
|
575 | elif self.line_type.name=='tx': | |
535 | params = json.loads(self.params) |
|
576 | params = json.loads(self.params) | |
536 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] |
|
577 | delays = [float(d)*km2unit for d in params['delays'].split(',') if d] | |
537 |
|
|
578 | width = float(params['pulse_width'])*km2unit | |
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(',') |
|
|||
544 |
|
579 | |||
545 | if len(ranges)>0 and ranges[0]<>'0': |
|
580 | if width>0: | |
546 |
|
|
581 | before = int(self.rc_configuration.time_before*us2unit) | |
547 |
|
|
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 | elif self.line_type.name=='flip': |
|
595 | elif self.line_type.name=='flip': | |
550 |
|
|
596 | n = float(json.loads(self.params)['number_of_flips']) | |
551 | y = pulses(x, 2*width, width) |
|
597 | width = n*ipp*km2unit | |
|
598 | y = self.points(int((ntx+1)/(2*n)), ipp_u*n*2, width) | |||
552 |
|
599 | |||
553 | elif self.line_type.name=='codes': |
|
600 | elif self.line_type.name=='codes': | |
554 | params = json.loads(self.params) |
|
601 | params = json.loads(self.params) | |
555 | tx = RCLine.objects.get(pk=params['TX_ref']) |
|
602 | tx = RCLine.objects.get(pk=params['TX_ref']) | |
556 | tx_params = json.loads(tx.params) |
|
603 | tx_params = json.loads(tx.params) | |
557 | delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d] |
|
604 | delays = [float(d)*km2unit for d in tx_params['delays'].split(',') if d] | |
558 | y = pulses_from_code(tx.pulses_as_array(), |
|
605 | f = int(float(tx_params['pulse_width'])*km2unit)/len(params['codes'][0]) | |
559 | params['codes'], |
|
606 | codes = [(np.fromstring(''.join([s*f for s in code]), dtype=np.uint8)-48).astype(np.int8) for code in params['codes']] | |
560 | int(float(tx_params['pulse_width'])*km2unit)) |
|
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 | ranges = tx_params['range'].split(',') |
|
614 | ranges = tx_params['range'].split(',') | |
563 | if len(ranges)>0 and ranges[0]<>'0': |
|
615 | if len(ranges)>0 and ranges[0]<>'0': | |
564 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) |
|
616 | y = self.mask_ranges(y, ranges) | |
565 | y = y.astype(np.int8) & mask |
|
|||
566 |
|
617 | |||
567 | elif self.line_type.name=='sync': |
|
618 | elif self.line_type.name=='sync': | |
568 | params = json.loads(self.params) |
|
619 | params = json.loads(self.params) | |
569 |
|
|
620 | n = ipp_u*ntx | |
570 | if params['invert'] in ('1', 1): |
|
621 | if params['invert'] in ('1', 1): | |
571 |
y |
|
622 | y = [(n-1, n)] | |
572 | else: |
|
623 | else: | |
573 |
y |
|
624 | y = [(0, 1)] | |
574 |
|
625 | |||
575 | elif self.line_type.name=='prog_pulses': |
|
626 | elif self.line_type.name=='prog_pulses': | |
576 | params = json.loads(self.params) |
|
627 | params = json.loads(self.params) | |
577 | if int(params['periodic'])==0: |
|
628 | if int(params['periodic'])==0: | |
578 | nntx = ntx |
|
|||
579 | else: |
|
|||
580 | nntx = 1 |
|
629 | nntx = 1 | |
|
630 | nipp = ipp_u*ntx | |||
|
631 | else: | |||
|
632 | nntx = ntx | |||
|
633 | nipp = ipp_u | |||
581 |
|
634 | |||
582 | if 'params' in params and len(params['params'])>0: |
|
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']]) |
|
636 | for p in params['params']: | |
584 | else: |
|
637 | y_pp = self.points(nntx, nipp, | |
585 | y = np.zeros(ipp_u*ntx) |
|
638 | p['end']-p['begin'], | |
586 |
|
639 | before=p['begin']) | ||
|
640 | ||||
|
641 | y.extend(y_pp) | |||
|
642 | ||||
587 | elif self.line_type.name=='windows': |
|
643 | elif self.line_type.name=='windows': | |
588 | params = json.loads(self.params) |
|
644 | params = json.loads(self.params) | |
589 |
|
645 | |||
590 | if 'params' in params and len(params['params'])>0: |
|
646 | if 'params' in params and len(params['params'])>0: | |
591 | y = sum([pulses(x, ipp_u, pp['resolution']*pp['number_of_samples']*km2unit, |
|
647 | tr_params = json.loads(self.get_lines(line_type__name='tr')[0].params) | |
592 | shift=0, |
|
648 | tr_ranges = tr_params['range'].split(',') | |
593 | before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(pp, params['TX_ref'],km2unit), |
|
649 | for p in params['params']: | |
594 | sync=self.rc_configuration.sync) for pp in params['params']]) |
|
650 | y_win = self.points(ntx, ipp_u, | |
595 | tr = self.get_lines(line_type__name='tr')[0] |
|
651 | p['resolution']*p['number_of_samples']*km2unit, | |
596 | ranges = json.loads(tr.params)['range'].split(',') |
|
652 | before=int(self.rc_configuration.time_before*us2unit)+self.get_win_ref(p, params['TX_ref'], km2unit), | |
597 | if len(ranges)>0 and ranges[0]<>'0': |
|
653 | sync=self.rc_configuration.sync) | |
598 | mask = create_mask(ranges, ipp_u, ntx, self.rc_configuration.sync) |
|
654 | ||
599 | y = y & mask |
|
655 | if len(tr_ranges)>0 and tr_ranges[0]<>'0': | |
600 | else: |
|
656 | y_win = self.mask_ranges(y_win, tr_ranges) | |
601 | y = np.zeros(ipp_u*ntx) |
|
657 | ||
602 |
|
658 | y.extend(y_win) | ||
|
659 | ||||
603 | elif self.line_type.name=='mix': |
|
660 | elif self.line_type.name=='mix': | |
604 | values = self.rc_configuration.parameters.split('-') |
|
661 | values = self.rc_configuration.parameters.split('-') | |
605 | confs = RCConfiguration.objects.filter(pk__in=[value.split('|')[0] for value in values]) |
|
662 | confs = RCConfiguration.objects.filter(pk__in=[value.split('|')[0] for value in values]) | |
@@ -608,7 +665,7 class RCLine(models.Model): | |||||
608 | masks = [value.split('|')[3] for value in values] |
|
665 | masks = [value.split('|')[3] for value in values] | |
609 |
|
666 | |||
610 | y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array() |
|
667 | y = confs[0].get_lines(channel=self.channel)[0].pulses_as_array() | |
611 |
|
668 | ysize = len(y) | ||
612 | for i in range(1, len(values)): |
|
669 | for i in range(1, len(values)): | |
613 | mask = list('{:8b}'.format(int(masks[i]))) |
|
670 | mask = list('{:8b}'.format(int(masks[i]))) | |
614 | mask.reverse() |
|
671 | mask.reverse() | |
@@ -621,25 +678,60 class RCLine(models.Model): | |||||
621 | y_temp = np.empty_like(Y) |
|
678 | y_temp = np.empty_like(Y) | |
622 | y_temp[:delay] = 0 |
|
679 | y_temp[:delay] = 0 | |
623 | y_temp[delay:] = Y[:-delay] |
|
680 | y_temp[delay:] = Y[:-delay] | |
624 |
|
681 | y_tempsize = len(y_temp) | ||
625 | if modes[i]=='OR': |
|
682 | if modes[i]=='OR': | |
626 |
y |
|
683 | y = y | y_temp | |
627 | elif modes[i]=='XOR': |
|
684 | elif modes[i]=='XOR': | |
628 |
y |
|
685 | y = y ^ y_temp | |
629 | elif modes[i]=='AND': |
|
686 | elif modes[i]=='AND': | |
630 |
y |
|
687 | y = y & y_temp | |
631 | elif modes[i]=='NAND': |
|
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 | else: |
|
693 | else: | |
637 |
y = |
|
694 | y = [] | |
638 |
|
695 | |||
639 | if save: |
|
696 | self.pulses = y | |
640 | self.pulses = (y+48).astype(np.uint8).tostring() |
|
697 | self.save() | |
641 | self.save() |
|
698 | ||
642 | else: |
|
699 | @staticmethod | |
643 | return y |
|
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 | url(r'^(?P<conf_id>-?\d+)/$', 'apps.rc.views.conf', name='url_rc_conf'), |
|
4 | url(r'^(?P<conf_id>-?\d+)/$', 'apps.rc.views.conf', name='url_rc_conf'), | |
5 | url(r'^(?P<conf_id>-?\d+)/import/$', 'apps.rc.views.import_file', name='url_import_rc_conf'), |
|
5 | url(r'^(?P<conf_id>-?\d+)/import/$', 'apps.rc.views.import_file', name='url_import_rc_conf'), | |
6 | url(r'^(?P<conf_id>-?\d+)/edit/$', 'apps.rc.views.conf_edit', name='url_edit_rc_conf'), |
|
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 | url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_rc_conf'), |
|
8 | url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_rc_conf'), | |
9 | url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_rc_conf'), |
|
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 | import json |
|
2 | import json | |
3 | import numpy as np |
|
|||
4 | import matplotlib.pyplot as plt |
|
|||
5 |
|
||||
6 |
|
3 | |||
7 | class RCFile(object): |
|
4 | class RCFile(object): | |
8 | ''' |
|
5 | ''' | |
@@ -207,109 +204,3 class RCFile(object): | |||||
207 | return json.dumps(self.data, indent=indent) |
|
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 | from .models import RCConfiguration, RCLine, RCLineType, RCLineCode |
|
11 | from .models import RCConfiguration, RCLine, RCLineType, RCLineCode | |
12 | from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm |
|
12 | from .forms import RCConfigurationForm, RCLineForm, RCLineViewForm, RCLineEditForm, RCImportForm, RCLineCodesForm | |
13 | from .utils import plot_pulses |
|
|||
14 |
|
13 | |||
15 |
|
14 | |||
16 | def conf(request, conf_id): |
|
15 | def conf(request, conf_id): | |
@@ -329,25 +328,13 def import_file(request, conf_id): | |||||
329 | if request.method=='POST': |
|
328 | if request.method=='POST': | |
330 | form = RCImportForm(request.POST, request.FILES) |
|
329 | form = RCImportForm(request.POST, request.FILES) | |
331 | if form.is_valid(): |
|
330 | if form.is_valid(): | |
332 |
|
|
331 | try: | |
333 | if True: |
|
|||
334 |
|
||||
335 | conf.update_from_file(request.FILES['file_name']) |
|
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 | messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name']) |
|
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 |
|
|
336 | except Exception as e: | |
350 |
|
|
337 | messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], e)) | |
351 |
|
338 | |||
352 | else: |
|
339 | else: | |
353 | messages.warning(request, 'Your current configuration will be replaced') |
|
340 | messages.warning(request, 'Your current configuration will be replaced') | |
@@ -363,16 +350,11 def import_file(request, conf_id): | |||||
363 | return render(request, 'rc_import.html', kwargs) |
|
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) |
|
355 | 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 |
|
|||
374 |
|
356 | |||
375 |
script, div = plot_pulses( |
|
357 | script, div = conf.plot_pulses() | |
376 |
|
358 | |||
377 | kwargs = {} |
|
359 | kwargs = {} | |
378 |
|
360 | |||
@@ -380,6 +362,9 def view_pulses(request, conf_id): | |||||
380 | kwargs['suptitle'] = conf.name |
|
362 | kwargs['suptitle'] = conf.name | |
381 | kwargs['div'] = mark_safe(div) |
|
363 | kwargs['div'] = mark_safe(div) | |
382 | kwargs['script'] = mark_safe(script) |
|
364 | kwargs['script'] = mark_safe(script) | |
383 |
|
365 | |||
384 | return render(request, 'rc_pulses.html', kwargs) |
|
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