mxbiflow 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. mxbiflow/__init__.py +3 -0
  2. mxbiflow/assets/__init__.py +5 -0
  3. mxbiflow/assets/clicker.wav +0 -0
  4. mxbiflow/config_store.py +68 -0
  5. mxbiflow/data_logger.py +114 -0
  6. mxbiflow/default/__init__.py +4 -0
  7. mxbiflow/default/idle/assets/apple_v1.png +0 -0
  8. mxbiflow/default/idle/idle.py +57 -0
  9. mxbiflow/detector_bridge.py +87 -0
  10. mxbiflow/game.py +84 -0
  11. mxbiflow/infra/eventbus.py +31 -0
  12. mxbiflow/main.py +106 -0
  13. mxbiflow/models/animal.py +130 -0
  14. mxbiflow/models/reward.py +7 -0
  15. mxbiflow/models/session.py +145 -0
  16. mxbiflow/mxbiflow.py +43 -0
  17. mxbiflow/path.py +41 -0
  18. mxbiflow/scene/__init__.py +8 -0
  19. mxbiflow/scene/scene_manager.py +64 -0
  20. mxbiflow/scene/scene_protocol.py +22 -0
  21. mxbiflow/scheduler.py +90 -0
  22. mxbiflow/tasks/GNGSiD/models.py +70 -0
  23. mxbiflow/tasks/GNGSiD/stages/detect_stage/config.json +116 -0
  24. mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage.py +161 -0
  25. mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage_models.py +65 -0
  26. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/config.json +70 -0
  27. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage.py +173 -0
  28. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage_models.py +80 -0
  29. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/config.json +83 -0
  30. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_models.py +58 -0
  31. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_stage.py +149 -0
  32. mxbiflow/tasks/GNGSiD/tasks/artifacts.py +13 -0
  33. mxbiflow/tasks/GNGSiD/tasks/detect/models.py +21 -0
  34. mxbiflow/tasks/GNGSiD/tasks/detect/scene.py +271 -0
  35. mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_models.py +31 -0
  36. mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_scene.py +336 -0
  37. mxbiflow/tasks/GNGSiD/tasks/touch/touch_models.py +17 -0
  38. mxbiflow/tasks/GNGSiD/tasks/touch/touch_scene.py +256 -0
  39. mxbiflow/tasks/GNGSiD/tasks/utils/targets.py +57 -0
  40. mxbiflow/tasks/cross_modal/bundle_dir.py +553 -0
  41. mxbiflow/tasks/cross_modal/config.py +41 -0
  42. mxbiflow/tasks/cross_modal/media.py +61 -0
  43. mxbiflow/tasks/cross_modal/models.py +57 -0
  44. mxbiflow/tasks/cross_modal/scene.py +252 -0
  45. mxbiflow/tasks/cross_modal/stage.py +218 -0
  46. mxbiflow/tasks/cross_modal/trial_io.py +23 -0
  47. mxbiflow/tasks/cross_modal/trial_schema.py +113 -0
  48. mxbiflow/tasks/default/error_task/error_scene.py +53 -0
  49. mxbiflow/tasks/default/idle_task/assets/apple_v1.png +0 -0
  50. mxbiflow/tasks/default/idle_task/idle_scene.py +85 -0
  51. mxbiflow/tasks/default/initial_habituation_training/README.md +188 -0
  52. mxbiflow/tasks/default/initial_habituation_training/stages/config.csv +7 -0
  53. mxbiflow/tasks/default/initial_habituation_training/stages/config.json +67 -0
  54. mxbiflow/tasks/default/initial_habituation_training/stages/initial_habituation_training_stage.py +172 -0
  55. mxbiflow/tasks/default/initial_habituation_training/stages/models.py +56 -0
  56. mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward.py +244 -0
  57. mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward_models.py +50 -0
  58. mxbiflow/tasks/task_protocol.py +26 -0
  59. mxbiflow/tasks/task_table.py +29 -0
  60. mxbiflow/tasks/two_alternative_choice/assets/starter.py +27 -0
  61. mxbiflow/tasks/two_alternative_choice/models.py +68 -0
  62. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/config.json +118 -0
  63. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_models.py +41 -0
  64. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_stage.py +122 -0
  65. mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_models.py +19 -0
  66. mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_scene.py +249 -0
  67. mxbiflow/timer/__init__.py +3 -0
  68. mxbiflow/timer/frame_timer.py +47 -0
  69. mxbiflow/timer/realtime_timer.py +0 -0
  70. mxbiflow/tmp_email.py +13 -0
  71. mxbiflow/ui/components/animal.py +87 -0
  72. mxbiflow/ui/components/baseconfig.py +68 -0
  73. mxbiflow/ui/components/card.py +18 -0
  74. mxbiflow/ui/components/device_card/__init__.py +17 -0
  75. mxbiflow/ui/components/device_card/detector/beambreak_detector_card.py +29 -0
  76. mxbiflow/ui/components/device_card/detector/fusion_detector.py +45 -0
  77. mxbiflow/ui/components/device_card/detector/mock_detector_card.py +20 -0
  78. mxbiflow/ui/components/device_card/detector/rfid_detector.py +40 -0
  79. mxbiflow/ui/components/device_card/device_card.py +67 -0
  80. mxbiflow/ui/components/device_card/rewarder/mock_rewarder_card.py +20 -0
  81. mxbiflow/ui/components/device_card/rewarder/rpi_gpio_rewarder.py +33 -0
  82. mxbiflow/ui/components/devices.py +183 -0
  83. mxbiflow/ui/components/dialog/__init__.py +3 -0
  84. mxbiflow/ui/components/dialog/add_devices_dialog.py +64 -0
  85. mxbiflow/ui/components/experiment_groups.py +122 -0
  86. mxbiflow/ui/experiment_panel.py +91 -0
  87. mxbiflow/ui/mxbi_panel.py +152 -0
  88. mxbiflow/utils/logger.py +19 -0
  89. mxbiflow/utils/serial.py +10 -0
  90. mxbiflow-0.1.1.dist-info/METADATA +168 -0
  91. mxbiflow-0.1.1.dist-info/RECORD +93 -0
  92. mxbiflow-0.1.1.dist-info/WHEEL +4 -0
  93. mxbiflow-0.1.1.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,149 @@
1
+ from random import choice
2
+ from typing import TYPE_CHECKING, Final
3
+
4
+ from mxbi.data_logger import DataLogger, DataLoggerType
5
+ from mxbi.models.animal import ScheduleCondition
6
+ from mxbi.tasks.GNGSiD.models import PersistentData, Result
7
+ from mxbi.tasks.GNGSiD.stages.size_reduction_stage.size_reduction_models import (
8
+ SizeReductionStageConfig,
9
+ config,
10
+ )
11
+ from mxbi.tasks.GNGSiD.tasks.touch.touch_models import TrialConfig
12
+ from mxbi.tasks.GNGSiD.tasks.touch.touch_scene import GNGSiDTouchScene
13
+ from mxbi.utils.logger import logger
14
+
15
+ if TYPE_CHECKING:
16
+ from mxbi.models.animal import AnimalState
17
+ from mxbi.models.session import SessionState
18
+ from mxbi.models.task import Feedback
19
+ from mxbi.theater import Theater
20
+
21
+
22
+ _presistent_data: dict[str, PersistentData] = {}
23
+
24
+
25
+ class SizeReductionStage:
26
+ STAGE_NAME: Final[str] = "GNGSiD_SIZE_REDUCTION_STAGE"
27
+
28
+ def __init__(
29
+ self,
30
+ theater: "Theater",
31
+ session_state: "SessionState",
32
+ animal_state: "AnimalState",
33
+ ) -> None:
34
+ self._theater = theater
35
+ self._session_state = session_state
36
+ self._animal_state = animal_state
37
+
38
+ self._stage_config = self._load_stage_config(animal_state.name)
39
+
40
+ _fixed_config = self._stage_config.params
41
+ _levels_config = self._stage_config.levels_table[animal_state.level]
42
+
43
+ master_amp, digital_amp = self._prepare_stimulus_intensity(
44
+ self._animal_state.name, _fixed_config.stimulus_freq
45
+ )
46
+
47
+ _config = TrialConfig(
48
+ level=_levels_config.level,
49
+ stimulation_size=_levels_config.stimulation_size,
50
+ stimulus_duration=_fixed_config.stimulus_duration,
51
+ time_out=_fixed_config.time_out,
52
+ inter_trial_interval=_fixed_config.inter_trial_interval,
53
+ reward_duration=_fixed_config.reward_duration,
54
+ reward_delay=_levels_config.reward_delay,
55
+ stimulus_freq=_fixed_config.stimulus_freq,
56
+ stimulus_freq_duration=_fixed_config.stimulus_freq_duration,
57
+ stimulus_freq_master_amp=master_amp,
58
+ stimulus_freq_digital_amp=digital_amp,
59
+ stimulus_interval=_fixed_config.stimulus_interval,
60
+ )
61
+
62
+ self._data_logger = DataLogger(
63
+ self._session_state,
64
+ self._animal_state.name,
65
+ self.STAGE_NAME,
66
+ DataLoggerType.JSONL,
67
+ )
68
+
69
+ self._presistent_data = _presistent_data.get(self._animal_state.name)
70
+
71
+ if self._presistent_data is None:
72
+ self._presistent_data = PersistentData(
73
+ rewards=0,
74
+ correct=0,
75
+ incorrect=0,
76
+ timeout=0,
77
+ )
78
+ _presistent_data[self._animal_state.name] = self._presistent_data
79
+
80
+ self._task = GNGSiDTouchScene(
81
+ theater,
82
+ session_state.session_config,
83
+ animal_state,
84
+ session_state.session_config.screen_type,
85
+ _config,
86
+ self._presistent_data,
87
+ )
88
+
89
+ def start(self) -> "Feedback":
90
+ trial_data = self._task.start()
91
+ self._data_logger.save(trial_data.model_dump())
92
+
93
+ feedback = self._handle_result(trial_data.result)
94
+ logger.debug(
95
+ f"{self.STAGE_NAME}: "
96
+ f"session_id={self._session_state.session_id}, "
97
+ f"animal_name={self._animal_state.name}, "
98
+ f"animal_level={self._animal_state.level}, "
99
+ f"state_name={self.STAGE_NAME}, "
100
+ f"result={trial_data}, "
101
+ f"feedback={feedback}"
102
+ )
103
+
104
+ return feedback
105
+
106
+ def _load_stage_config(self, monkey: str) -> SizeReductionStageConfig:
107
+ stage_config = config.root.get(monkey) or config.root.get("default")
108
+ if stage_config is None:
109
+ raise ValueError("No default stage config found")
110
+ return stage_config
111
+
112
+ def _handle_result(self, result: "Result") -> "Feedback":
113
+ feedback = False
114
+ match result:
115
+ case Result.CORRECT:
116
+ _presistent_data[self._animal_state.name].correct += 1
117
+ feedback = True
118
+ case Result.INCORRECT:
119
+ _presistent_data[self._animal_state.name].incorrect += 1
120
+ feedback = False
121
+ case Result.TIMEOUT:
122
+ _presistent_data[self._animal_state.name].timeout += 1
123
+ feedback = False
124
+ case Result.CANCEL:
125
+ feedback = False
126
+
127
+ return feedback
128
+
129
+ def quit(self) -> None:
130
+ self._task.cancle()
131
+
132
+ def on_idle(self) -> None:
133
+ self._task.cancle()
134
+
135
+ def on_return(self) -> None:
136
+ self._task.cancle()
137
+
138
+ @property
139
+ def condition(self) -> "ScheduleCondition | None":
140
+ return self._stage_config.condition
141
+
142
+ def _prepare_stimulus_intensity(self, monkey: str, frequency: int):
143
+ bt = choice(([[10, 30], [50, 70]])) if monkey == "wolfgang" else []
144
+ at = [80, 80, 80] if monkey == "wolfgang" else [80, 80, 80]
145
+ intensity_options = at * 10 + bt
146
+
147
+ stimulus_intensity = choice(intensity_options)
148
+
149
+ return self._theater.acontroller.get_amp_value(frequency, stimulus_intensity)
@@ -0,0 +1,13 @@
1
+ from tkinter import Canvas
2
+
3
+
4
+ class BaseViews:
5
+ def _create_background(self, master, width, height) -> None:
6
+ self._backgroud = Canvas(
7
+ master,
8
+ bg="black",
9
+ width=width,
10
+ height=height,
11
+ highlightthickness=0,
12
+ )
13
+ self._backgroud.place(relx=0.5, rely=0.5, anchor="center")
@@ -0,0 +1,21 @@
1
+ from mxbi.tasks.GNGSiD.models import BaseDataToShow, BaseTrialConfig, BaseTrialData
2
+
3
+
4
+ class TrialConfig(BaseTrialConfig):
5
+ go: bool
6
+ visual_stimulus_delay: int
7
+
8
+ stimulus_freq: int
9
+ stimulus_freq_duration: int
10
+ stimulus_freq_master_amp: int
11
+ stimulus_freq_digital_amp: int
12
+
13
+ stimulus_interval: int
14
+
15
+
16
+ class TrialData(BaseTrialData):
17
+ trial_config: TrialConfig
18
+
19
+
20
+ class DataToShow(BaseDataToShow):
21
+ stimulus: bool
@@ -0,0 +1,271 @@
1
+ from datetime import datetime
2
+ from math import ceil
3
+ from tkinter import CENTER, Canvas, Event
4
+ from typing import TYPE_CHECKING, Final
5
+
6
+ from mxbi.tasks.GNGSiD.models import Result, TouchEvent
7
+ from mxbi.tasks.GNGSiD.tasks.detect.models import DataToShow, TrialConfig, TrialData
8
+ from mxbi.tasks.GNGSiD.tasks.utils.targets import DetectTarget
9
+ from mxbi.utils.aplayer import ToneConfig
10
+ from mxbi.utils.tkinter.components.canvas_with_border import CanvasWithInnerBorder
11
+ from mxbi.utils.tkinter.components.showdata_widget import ShowDataWidget
12
+
13
+ if TYPE_CHECKING:
14
+ from concurrent.futures import Future
15
+
16
+ from mxbi.models.animal import AnimalState
17
+ from mxbi.models.session import ScreenConfig, SessionConfig
18
+ from mxbi.tasks.GNGSiD.models import PersistentData
19
+ from mxbi.theater import Theater
20
+ from numpy import int16
21
+ from numpy.typing import NDArray
22
+
23
+
24
+ class GNGSiDDetectScene:
25
+ def __init__(
26
+ self,
27
+ theater: "Theater",
28
+ session_config: "SessionConfig",
29
+ animal_state: "AnimalState",
30
+ screen_type: "ScreenConfig",
31
+ trial_config: "TrialConfig",
32
+ persistent_data: "PersistentData",
33
+ ) -> None:
34
+ self._theater: "Final[Theater]" = theater
35
+ self._animal_state: "Final[AnimalState]" = animal_state
36
+ self._screen_type: "Final[ScreenConfig]" = screen_type
37
+ self._trial_config: "Final[TrialConfig]" = trial_config
38
+ self._persistent_data: Final["PersistentData"] = persistent_data
39
+
40
+ self._tone: Final[NDArray[int16]] = self._prepare_stimulus()
41
+ self._standard_reward_stimulus = self._theater.new_standard_reward_stimulus(
42
+ self._trial_config.stimulus_duration
43
+ )
44
+
45
+ self._set_stimulus_intensity()
46
+
47
+ self._on_trial_start()
48
+
49
+ # region public api
50
+ def start(self) -> TrialData:
51
+ self._theater.mainloop()
52
+ return self._data
53
+
54
+ def cancle(self) -> None:
55
+ self._data.result = Result.CANCEL
56
+ self._theater.aplayer.stop()
57
+ self._on_trial_end()
58
+
59
+ # endregion
60
+
61
+ # region Lifecycle
62
+ def _on_trial_start(self) -> None:
63
+ self._create_view()
64
+ self._init_data()
65
+ self._bind_first_stage()
66
+
67
+ def _on_inter_trial(self) -> None:
68
+ self._background.after(
69
+ self._trial_config.inter_trial_interval, self._on_trial_end
70
+ )
71
+
72
+ def _on_trial_end(self) -> None:
73
+ self._background.destroy()
74
+ self._theater.root.quit()
75
+
76
+ # endregion
77
+
78
+ # region Views
79
+ def _create_view(self) -> None:
80
+ self._create_background()
81
+ self._create_show_data_view()
82
+ self._create_target()
83
+
84
+ def _create_background(self) -> None:
85
+ self._background = CanvasWithInnerBorder(
86
+ master=self._theater.root,
87
+ bg="black",
88
+ width=self._screen_type.width,
89
+ height=self._screen_type.height,
90
+ border_width=40,
91
+ )
92
+ self._background.place(relx=0.5, rely=0.5, anchor="center")
93
+
94
+ def _create_show_data_view(self) -> None:
95
+ self._show_data_widget = ShowDataWidget(self._background)
96
+ self._show_data_widget.place(relx=0, rely=1, anchor="sw")
97
+ data = DataToShow(
98
+ name=self._animal_state.name,
99
+ id=self._animal_state.trial_id,
100
+ level_id=self._animal_state.current_level_trial_id,
101
+ level=self._trial_config.level,
102
+ rewards=self._persistent_data.rewards,
103
+ correct=self._animal_state.correct_trial,
104
+ incorrect=self._persistent_data.incorrect,
105
+ timeout=self._persistent_data.timeout,
106
+ stimulus=self._trial_config.go,
107
+ )
108
+ self._show_data_widget.show_data(data.model_dump())
109
+
110
+ def _create_target(self):
111
+ xshift = 240
112
+ xcenter = self._screen_type.width * 0.5 + xshift
113
+ ycenter = self._screen_type.height * 0.5
114
+
115
+ self._trigger_canvas = DetectTarget(
116
+ self._background, self._trial_config.stimulation_size
117
+ )
118
+ self._trigger_canvas.place(x=xcenter, y=ycenter, anchor="center")
119
+
120
+ def _create_wrong_view(self) -> None:
121
+ self._trigger_canvas = Canvas(
122
+ self._background,
123
+ bg="grey",
124
+ width=self._screen_type.width,
125
+ height=self._screen_type.height,
126
+ )
127
+ self._trigger_canvas.place(relx=0.5, rely=0.5, anchor=CENTER)
128
+
129
+ # endregion
130
+
131
+ # region event binding
132
+ def _bind_first_stage(self) -> None:
133
+ self._background.focus_set()
134
+ self._background.bind("<r>", lambda e: self._give_standard_stimulus())
135
+ self._trigger_canvas.bind("<ButtonPress>", self._on_first_touched)
136
+ self._trigger_canvas.after(self._trial_config.time_out, self._on_timeout)
137
+
138
+ def _bind_second_stage(self) -> None:
139
+ self._trigger_canvas.bind("<ButtonPress>", self._on_second_touched)
140
+
141
+ # TODO: Confirm the waiting time
142
+ if not self._trial_config.go:
143
+ self._trigger_canvas.after(
144
+ self._trial_config.stimulus_duration, self._on_incorrect
145
+ )
146
+
147
+ # endregion
148
+
149
+ # region event handlers
150
+ def _on_first_touched(self, event: Event) -> None:
151
+ self._trigger_canvas.destroy()
152
+ self._record_touch(event)
153
+
154
+ if self._trial_config.go:
155
+ future = self._give_stimulus(self._tone)
156
+ future.add_done_callback(self._on_stimulus_complete)
157
+
158
+ self._background.after(
159
+ self._trial_config.visual_stimulus_delay,
160
+ lambda: (self._create_target(), self._bind_second_stage()),
161
+ )
162
+
163
+ def _on_second_touched(self, event: Event) -> None:
164
+ self._trigger_canvas.destroy()
165
+ self._record_touch(event)
166
+
167
+ if self._trial_config.go:
168
+ self._on_incorrect()
169
+ else:
170
+ future = self._give_stimulus(self._tone)
171
+ future.add_done_callback(self._on_stimulus_complete)
172
+
173
+ self._background.after(2000, self._create_target)
174
+
175
+ def _record_touch(self, event: Event) -> None:
176
+ self._data.touch_events.append(
177
+ TouchEvent(time=datetime.now().timestamp(), x=event.x, y=event.y)
178
+ )
179
+
180
+ # endregion
181
+
182
+ # region result handlers
183
+ def _on_correct(self) -> None:
184
+ self._trigger_canvas.destroy()
185
+
186
+ self._give_reward()
187
+ self._data.result = Result.CORRECT
188
+ self._data.correct_rate = (self._animal_state.correct_trial + 1) / (
189
+ self._animal_state.current_level_trial_id + 1
190
+ )
191
+ self._on_inter_trial()
192
+
193
+ def _on_incorrect(self) -> None:
194
+ self._theater._aplayer.stop()
195
+ self._trigger_canvas.destroy()
196
+
197
+ self._data.result = Result.INCORRECT
198
+ self._data.correct_rate = self._animal_state.correct_trial / (
199
+ self._animal_state.current_level_trial_id + 1
200
+ )
201
+
202
+ self._create_wrong_view()
203
+ self._on_inter_trial()
204
+
205
+ def _on_timeout(self) -> None:
206
+ self._data.result = Result.TIMEOUT
207
+ self._data.correct_rate = self._animal_state.correct_trial / (
208
+ self._animal_state.current_level_trial_id + 1
209
+ )
210
+
211
+ self._create_wrong_view()
212
+ self._on_inter_trial()
213
+
214
+ # endregion
215
+
216
+ # region stimulus and reward
217
+ def _prepare_stimulus(self) -> "NDArray[int16]":
218
+ cycle = (
219
+ self._trial_config.stimulus_freq_duration
220
+ + self._trial_config.stimulus_interval
221
+ )
222
+ repeat = ceil(self._trial_config.stimulus_duration / cycle)
223
+ repeat = max(repeat, 1)
224
+
225
+ freq_1 = ToneConfig(
226
+ frequency=self._trial_config.stimulus_freq,
227
+ duration=self._trial_config.stimulus_freq_duration,
228
+ )
229
+ freq_2 = ToneConfig(frequency=0, duration=self._trial_config.stimulus_interval)
230
+
231
+ return self._theater.aplayer.generate_stimulus([freq_1, freq_2], repeat)
232
+
233
+ def _give_stimulus(self, tone: "NDArray[int16]") -> "Future[bool]":
234
+ return self._theater.aplayer.play_stimulus(tone)
235
+
236
+ def _on_stimulus_complete(self, future: "Future[bool]") -> None:
237
+ if future.result():
238
+ self._background.after(self._trial_config.reward_delay, self._on_correct)
239
+
240
+ def _give_reward(self, _=None) -> None:
241
+ self._persistent_data.rewards += 1
242
+ self._theater.reward.give_reward(self._trial_config.reward_duration)
243
+
244
+ def _set_stimulus_intensity(self) -> None:
245
+ self._theater.acontroller.set_master_volume(
246
+ self._trial_config.stimulus_freq_master_amp
247
+ )
248
+ self._theater.acontroller.set_digital_volume(
249
+ self._trial_config.stimulus_freq_digital_amp
250
+ )
251
+
252
+ def _give_standard_stimulus(self) -> None:
253
+ self._standard_reward_stimulus.play(self._trial_config.reward_duration)
254
+
255
+ # endregion
256
+
257
+ # region data
258
+ def _init_data(self):
259
+ self._data = TrialData(
260
+ animal=self._animal_state.name,
261
+ trial_id=self._animal_state.trial_id,
262
+ current_level_trial_id=self._animal_state.current_level_trial_id,
263
+ trial_config=self._trial_config,
264
+ trial_start_time=datetime.now().timestamp(),
265
+ trial_end_time=0,
266
+ result=Result.TIMEOUT,
267
+ correct_rate=0,
268
+ touch_events=[],
269
+ )
270
+
271
+ # endregion
@@ -0,0 +1,31 @@
1
+ from mxbi.tasks.GNGSiD.models import BaseDataToShow, BaseTrialConfig, BaseTrialData
2
+
3
+
4
+ class TrialConfig(BaseTrialConfig):
5
+ is_stimulus_trial: bool
6
+ visual_stimulus_delay: int
7
+
8
+ medium_reward_duration: int
9
+ medium_reward_threshold: int
10
+ low_reward_duration: int
11
+
12
+ attention_duration: int
13
+ extra_response_time: int
14
+
15
+ stimulus_freq_high: int
16
+ stimulus_freq_high_duration: int
17
+ stimulus_freq_high_master_amp: int
18
+ stimulus_freq_high_digital_amp: int
19
+ stimulus_freq_low: int
20
+ stimulus_freq_low_duration: int
21
+ stimulus_freq_low_master_amp: int
22
+ stimulus_freq_low_digital_amp: int
23
+ stimulus_interval: int
24
+
25
+
26
+ class TrialData(BaseTrialData):
27
+ trial_config: TrialConfig
28
+
29
+
30
+ class DataToShow(BaseDataToShow):
31
+ stimulus: bool