Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

live_plot1.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. '''
  2. description: kiap bci main class, other kiap modules are imported
  3. author: Ioannis Vlachos
  4. date: 30.08.18
  5. Copyright (c) 2018 Ioannis Vlachos
  6. All rights reserved.'''
  7. # import argparse
  8. import ctypes
  9. # import logging
  10. import multiprocessing as mp
  11. import os
  12. import subprocess
  13. import sys
  14. import time
  15. from datetime import date
  16. from multiprocessing import Pipe, Value, current_process
  17. from subprocess import PIPE, Popen
  18. from timeit import default_timer
  19. import cere_conn as cc
  20. import matplotlib
  21. import matplotlib.pyplot as plt
  22. import numpy as np
  23. # import psutil
  24. from matplotlib import gridspec
  25. from pyfiglet import Figlet
  26. # from scipy import signal, stats
  27. from sklearn.decomposition.pca import PCA
  28. import aux
  29. # from modules import bci, daq, data
  30. # from mp_gui.kiapGUIToolBox import kiapGUI
  31. # matplotlib.use('Qt4Agg', warn=False, force=True)
  32. matplotlib.use('TkAgg', warn=False, force=True)
  33. def update_ch_map():
  34. ch_u_list = [(ii, 0) for ii in range(1, params.daq.n_channels_max + 1) if ii not in params.daq.exclude_channels]
  35. ck.set_spike_rate_estimator_ch_u_list(ch_u_list)
  36. ch_map = ck.get_spike_rate_estimator_ch_u_map()
  37. log.debug(ch_map)
  38. log.info(f"# of channels in ch_map: {len(ch_map['list'])}")
  39. log.warning('Only unit 0 will be returned. Check spike-sorting status in Central.')
  40. return None
  41. def plot_results(data_buffer, global_buffer_idx, ch_ids):
  42. fig = plt.figure(1, figsize=(8, 8))
  43. plt.clf()
  44. gs = gridspec.GridSpec(3, 1, height_ratios=[2, 1, 2])
  45. plt.subplot(gs[0])
  46. ax1 = plt.gca()
  47. plt.ylim(-2, 300)
  48. plt.xlim(-2, params.buffer.length * params.daq.spike_rates.loop_interval / 1000.)
  49. ax1.set_xticks([])
  50. ax1.set_yticks([])
  51. plt.ylabel('Rates (sp/sec)')
  52. # ax1.set_title('Rates')
  53. plt.subplot(gs[1])
  54. ax2 = plt.gca()
  55. plt.ylim(-100, 200)
  56. plt.xlim(-2, params.buffer.length * params.daq.spike_rates.loop_interval / 1000.)
  57. plt.ylabel('PC1, PC2')
  58. plt.xlabel('sec')
  59. plt.subplot(gs[2])
  60. ax3 = plt.gca()
  61. plt.xlim(-200, 200)
  62. plt.ylim(-200, 200)
  63. # plt.xlim(-2, params.buffer.length * params.daq.spike_rates.loop_interval / 1000.)
  64. plt.ylabel('PC1 vs PC2')
  65. fig.canvas.draw()
  66. col = ['b', 'r', 'g']
  67. n_channels_plot = len(range(ch_ids[0],ch_ids[1]))
  68. lines1 = [ax1.plot(np.arange(params.buffer.shape[0]) * 0, 'C0', alpha=0.5)[0] for zz in range(n_channels_plot)] # rates
  69. lines2 = [ax2.plot(np.arange(params.buffer.shape[0]) * 0, alpha=0.5)[0] for zz in range(2)]
  70. lines3 = [ax3.plot(np.arange(1) * 0,'.', alpha=0.5)[0] for zz in range(1)]
  71. lines3.append(ax3.plot(np.arange(1),'C3o',mec='k')[0])
  72. background1 = fig.canvas.copy_from_bbox(ax1.bbox)
  73. background2 = fig.canvas.copy_from_bbox(ax2.bbox)
  74. background3 = fig.canvas.copy_from_bbox(ax3.bbox)
  75. for ii in range(params.plot.n_channels):
  76. ax1.draw_artist(lines1[ii])
  77. plt.pause(0.1)
  78. # plt.ion()
  79. print(ch_ids,n_channels_plot)
  80. offset = np.arange(0,n_channels_plot)*40 + ch_ids[0]*40
  81. min1,max1 = 0,0
  82. pca = PCA(n_components=2, svd_solver = 'arpack')
  83. while 1:
  84. cnt = 0
  85. tstart = time.time()
  86. while recording_status.value > 0:
  87. cnt += 1
  88. fig.canvas.restore_region(background1)
  89. fig.canvas.restore_region(background2)
  90. fig.canvas.restore_region(background3)
  91. # subplot 1
  92. b_idx = global_buffer_idx.value
  93. # log.error(f'b_idx: {b_idx}')
  94. if b_idx>20 and b_idx%20==0:
  95. print(b_idx)
  96. min1 = min(min1, int(np.min(data_buffer[b_idx-20:b_idx,ch_ids[0]:ch_ids[1]]-offset)))
  97. max1 = max(max1, int(np.max(data_buffer[b_idx-20:b_idx,ch_ids[0]:ch_ids[1]]-offset)))
  98. ax1.set_title(f'min/max rate: {min1}, {max1} sp/sec')
  99. plt.draw()
  100. xx = np.arange(b_idx) * params.daq.spike_rates.loop_interval / 1000.
  101. # for ii in range(params.plot.n_channels):
  102. for ii in range(n_channels_plot):
  103. lines1[ii].set_xdata(xx)
  104. lines1[ii].set_ydata(data_buffer[:b_idx, ii])
  105. ax1.draw_artist(lines1[ii])
  106. if b_idx >2 and np.var(data_buffer[:,0])>0:
  107. pca_res = pca.fit_transform(data_buffer[:b_idx, ch_ids[0]:ch_ids[1]])
  108. # subplot 2
  109. [lines2[zz].set_xdata(xx) for zz in range(2)]
  110. [lines2[zz].set_ydata(pca_res[:,zz]) for zz in range(2)]
  111. # subplot 3
  112. lines3[0].set_xdata(pca_res[:,0])
  113. lines3[0].set_ydata(pca_res[:,1])
  114. lines3[1].set_xdata(pca_res[-1,0])
  115. lines3[1].set_ydata(pca_res[-1,1])
  116. [ax2.draw_artist(lines2[zz]) for zz in range(2)]
  117. [ax3.draw_artist(lines3[zz]) for zz in range(2)]
  118. fig.canvas.blit(ax1.bbox)
  119. fig.canvas.blit(ax2.bbox)
  120. fig.canvas.blit(ax3.bbox)
  121. time.sleep(t_sleep) # to avoid high cpu usage
  122. time.sleep(t_sleep)
  123. return None
  124. log = aux.log # aux file contains logging configuration
  125. # args = aux.args
  126. t_sleep = 0.05
  127. if __name__ == '__main__':
  128. ch1 = int(sys.argv[1])
  129. ch2 = int(sys.argv[2])
  130. ch_ids = [ch1,ch2]
  131. # xx
  132. print('-' * 100)
  133. print(Figlet(font='standard', width=120).renderText('K I A P - B C I\nby\nW Y S S - C E N T E R\n\nlive-plot'))
  134. print('-' * 100)
  135. params = aux.load_config()
  136. recording_status = Value('i', 1)
  137. global_buffer_idx = Value('i', 0)
  138. # n_channels = params.daq.n_channels_max - len(params.daq.exclude_channels)
  139. n_channels = params.daq.n_channels
  140. n_channels_plot = len(range(ch_ids[0],ch_ids[1]))
  141. shared_array_base = mp.Array(ctypes.c_float, params.buffer.length * n_channels)
  142. data_buffer = np.ctypeslib.as_array(shared_array_base.get_obj())
  143. data_buffer = data_buffer.reshape(params.buffer.length, n_channels)
  144. visual = mp.Process(name='visual', target=plot_results, args=(data_buffer, global_buffer_idx, ch_ids))
  145. visual.daemon = True # kill visualization if main app terminates
  146. visual.start()
  147. processes = [visual]
  148. pids = [mp.current_process().pid, visual.pid]
  149. print(f'pids: {pids}')
  150. os.system(f'taskset -p -c 3 {mp.current_process().pid}') # set process affinity to core 3
  151. os.system(f'taskset -p -c 4 {visual.pid}') # set process affinity to core 4
  152. ck = cc.CereConn()
  153. ck.send_open()
  154. t = time.time()
  155. while ck.get_state() != cc.ccS_Idle:
  156. time.sleep(0.005)
  157. # get only unit 0, caution: switch of spike sorting in central
  158. ck.set_spike_rate_estimator_loop_interval_ms(params.daq.spike_rates.loop_interval)
  159. ch_u_list = [(ii, 0) for ii in range(1, params.daq.n_channels_max + 1) if ii not in params.daq.exclude_channels]
  160. ck.set_spike_rate_estimator_ch_u_list(ch_u_list)
  161. ck.set_spike_rate_estimation_method_exponential(params.daq.spike_rates.decay_factor, params.daq.spike_rates.max_bins)
  162. # Set CAR, both for LFP (1kHz data) and for raw data (used for SBP)
  163. if params.daq.car_channels:
  164. ck.set_car_channels(2, params.daq.car_channels)
  165. ck.set_car_channels(6, params.daq.car_channels)
  166. update_ch_map()
  167. time.sleep(0.5)
  168. # gids = [5]
  169. # bin_width = 0.005
  170. # run_time = 1
  171. ck.send_record()
  172. offset = np.arange(0,params.daq.n_channels)*40
  173. while True:
  174. idx = global_buffer_idx.value
  175. rates = ck.get_spike_rate_data()
  176. # ts = data['ts']
  177. data = rates['rates']
  178. if data.shape[0]>0:
  179. data = data+offset
  180. if idx + data.shape[0] >= data_buffer.shape[0]:
  181. idx = 0
  182. data_buffer[idx:idx + data.shape[0], :data.shape[1]] = data
  183. global_buffer_idx.value = idx + data.shape[0]
  184. # print(data)
  185. time.sleep(t_sleep)
  186. ck.send_close()