이번엔 Muse 2를 연결해 볼 것이다!
우선 설명하기 전에 빠르게 시도해 볼 수 있는 코드를 올리겠다!
아래 코드는 Brainflow로 Muse 2를 연결하고 1초간 데이터를 수집하는 코드이다.
import pandas as pd
from time import sleep
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
board_id = BoardIds.MUSE_2_BOARD
params = BrainFlowInputParams()
params.serial_number = "Muse-0465" # Muse 2의 고유 시리얼 넘버
board_shim = BoardShim(board_id, params)
use_data_seconds = 1 # 1초 동안 데이터 수집
sampling_rate = BoardShim.get_sampling_rate(board_id)
num_points = use_data_seconds * sampling_rate # 몇 초 동안 몇개의 데이터를 가져올지
# Muse 2 연결
board_shim.prepare_session()
# Muse 2 데이터 수집 시작
board_shim.start_stream()
# 2초 동안 데이터 수집
sleep(use_data_seconds + 1)
# 수집한 데이터를 변수에 저장
data = board_shim.get_current_board_data(num_points)
# 저장된 데이터를 알기 위한 출력 코드
print(board_shim.get_board_descr(board_id))
# CSV로 저장
df = pd.DataFrame(data).T
df.to_csv(f"data.csv", index=False)
# Muse 2 데이터 수집 정지
board_shim.stop_stream()
# Muse 2 연결 해제
board_shim.release_session()
참고로 당시에 Brainflow나 Muse 2에 대한 정보들이 엄청 적어서.. 코드를 작성하는데 조금 어려움은 있었다..
그래도 현재 올린 코드는 내가 몇번이고 찾아보면서 그나마 다듬어서 제일 쉬운 데이터 수집 코드를 만들었다.
솔직히 변수 명은 딱히 생각 안나서.. 그냥 이해하기 쉬운 걸로 쓴 거다..
Muse 2 시리얼 코드 연결
암튼 코드를 설명하기 전에 Muse 2를 연결할 때는 시리얼 코드가 필요하여 그것부터 설명해 보면..
일단 Brainflow에서 Muse 2 기기를 인식하는 방식이 블루투스 연결 장치가 주변 블루투스 기기를 찾고 블루투스 이름으로 Muse 2 기기를 연결하게 되는 방식이다.
그런데 나의 경우 Muse 2 기기가 주변에 여러 개 있는 경우 특정 하나만 연결되도록 해야 했었다. 왜냐하면 나중에 수업 때 사용하거나 2개 이상 연결해서 프로젝트를 진행했어야 했기 때문에;;
![]() |
![]() |
그렇기에 특정할 수 있는 방법은 시리얼 넘버를 사용하는 것이다.
혹시라도 전체 시리얼 넘버가 공개되면 문제가 있을 수 있어서 가리고 올렸다.
하나는 머리에 착용했을 때 왼쪽 귀에 해당하는 곳에 적힌 시리얼 넘버와 박스 상자 위에 적힌 시리얼 넘버이다.
기기에서는 상단에 있는 MUSE-0465를 확인하면 되고 박스에서는 S/N : ____-____-0465를 확인하면 된다.. 그냥 숫자 4자리 확인하면 된다.
암튼 저 4자리 숫자가 기기를 특정할 수 있도록 하는 것인데.. 저것만 알아두면 된다..!
암튼 이제부턴 코드 설명!
코드 설명
import pandas as pd
from time import sleep
from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
먼저 필요한 라이브러리를 불러온다..!
여기에서 sleep 함수는 몇 초 동안 데이터를 수집하는지에서 대기하도록 하려고 쓰는 것이고.. pandas는 데이터를 저장하기 위한 것, 나머지는 Brainflow 라이브러리들이다.
참고로 pandas는 같이 설치가 안되기 때문에 pip install pandas로 설치하면 된다.
board_id = BoardIds.MUSE_2_BOARD
params = BrainFlowInputParams()
params.serial_number = "Muse-0465" # Muse 2의 고유 시리얼 넘버
board_shim = BoardShim(board_id, params)
여기가 가장 중요하다고 생각되는 부분이다.
Muse 2의 기기를 선택시키고 시리얼 넘버를 정하는 부분이다.
먼저 board_id이다. board_id는 BoardIds라는 클래스에서 특정 기기의 정보들을 작성하여 연결을 돕거나 하는 그런 클래스라고 생각하면 되는데.. 미리 어떤 기기를 연결할지 선택을 해야 한다.
나의 경우 Muse 2를 연결하기 때문에 MUSE_2_BOARD를 선택한다.
(참고로 다른 기기들의 경우는 https://github.com/brainflow-dev/brainflow/blob/41a1d4acff178b8afff301c842a686e6d5217cab/python_package/brainflow/board_shim.py#L19-L82 여기를 확인하면 된다. 다만 특정 버전의 줄을 선택한 것이기에 Brainflow가 업데이트되거나 코드가 업데이트되면서 바뀔 수 있으니 최신 코드를 확인해 보면 좋다.)
다만 Muse 2 기기를 선택할 때 주의할 점이 있는데..
위에 참고 사항으로 올려둔 링크를 타고 가보면 Muse 2가 2개일 것이다.. (참고로 Muse S나 Muse 2016도 있는데 그건 다른 기기;;)
MUSE_2_BLED_BOARD = 22 #:
MUSE_2_BOARD = 38 #:
왜 2개이냐 하면.. 이전 글에서 말했던 BLED112 동글 때문이다.
MUSE_2_BLED_BOARD는 BLED112 동글로 연결할 때 필요한 번호이다. 이젠 딱히 쓰이지는 않겠지만.. 만약 동글로 연결하게 된다면 저걸 선택하면 된다..
하지만 나는 일반 블루투스 연결 장치로 연결할 것이기 때문에 MUSE_2_BOARD로 선택한 것이다..!
BrainFlowInputParams는 EEG 기기의 추가 정보들을 지정해서 연결할 수 있도록 해주는 클래스이다.
여기에서는 시리얼 넘버만 사용해서 연결하지만 다른 EEG 기기들을 위해 IP나 Mac Address 등 다른 지정 방법들도 있다.
아무튼 저 클래스를 받아서 시리얼 넘버를 지정하게 되는데..
위에서 말했듯이 나의 경우 Muse-0465가 시리얼 번호이기 때문에 Muse-0465 시리얼 번호를 사용하면 된다.
그렇기 때문에 꼭 자신의 시리얼 번호를 확인 후 작성해서 연결하면 될 것 같다..
그리고 그냥 기기를 한 개만 사용하거나 굳이 시리얼 넘버를 지정하지 않아도 되는 경우라면 그냥 저 serial_number를 설정하는 부분은 주석 처리 하면 된다.
따로 지정하지 않으면 그냥 블루투스 장치 검색할 때 처음으로 뜨는 Muse 2 기기를 연결하게 된다..
use_data_seconds = 1 # 1초 동안 데이터 수집
sampling_rate = BoardShim.get_sampling_rate(board_id)
num_points = use_data_seconds * sampling_rate # 몇 초 동안 몇개의 데이터를 가져올지
여기서는 몇 초간의 데이터를 가져올지 설정하는 부분이다.
나는 테스트로 간단하게 작동하는지만 보는 것이기 때문에 1초를 사용한다.
그리고 sampling_rate를 기기 정보에서 가져온다. 그냥 sampling_rate = 256으로 작성해도 되긴 한다.
어쨌든 기기들마다 차이가 있으므로 Brainflow에서 미리 정의한 sampling_rate 정보를 가져온 것..
참고로 더 많은 추가 정보들을 가져올 수도 있다.
그리고 num_points인데.. 이거는 나중에 몇 개의 데이터를 가져올지 사용할 때 쓴다.
나는 1초 동안의 데이터를 가져오고 이 기기의 초당 데이터 개수는 256이기 때문에 256개를 가져오도록 한다. 만약 2초라면 512개를 가져오도록 하면 된다. 마찬가지로 그냥 num_points = 256으로 작성해도 된다.
# Muse 2 연결
board_shim.prepare_session()
# Muse 2 데이터 수집 시작
board_shim.start_stream()
# 2초 동안 데이터 수집
sleep(use_data_seconds + 1)
# 수집한 데이터를 변수에 저장
data = board_shim.get_current_board_data(num_points)
이번엔 연결하고 데이터를 수집하고 데이터를 가져오는 부분이다.
주석에 적힌 대로 이해하면 된다.
연결하고 수집을 시작하도록 명령한다.
그 후 2초 동안 데이터를 수집한다. 이렇게 하는 이유는 아래에서도 얘기할 텐데 Muse 2 기기는 256hz라고 해도 연구용으로 나온 기기는 아니다 보니.. 초당 256개의 데이터가 정확히 가져와지지는 않는 것 같다.
그렇기 때문에 2초를 수집해서 1초를 수집해서 조금 부족한걸 나머지 1초에서 가져오도록 하기 위해서 저렇게 한 것이다.
뭐 나는 간단하게 하려고 저렇게 했지만 초마다 정확하게 데이터를 가져와야 한다면 초를 판단해서 데이터가 256개가 아니라도 가져오도록 해야 할 것이다.. 하지만 귀찮고 어렵기 때문에 여기에서는 패스..
그 후 board_shim의 get_current_board_data로 이전에 지정한 가져올 데이터 개수대로 데이터를 가져온다.
즉 2초간 측정한 데이터에서 1초 분량인 256개의 데이터를 가져온다는 것이다.
참고로 get_current_board_data는 이름에서 짐작할 수 있듯이 최근의 특정 개수의 데이터를 가져온다는 것이다.
만약 지금까지 측정한 전체 데이터를 가져오도록 할 것이라면 get_board_data를 사용하면 된다.
# 저장된 데이터를 알기 위한 출력 코드
print(board_shim.get_board_descr(board_id))
# CSV로 저장
df = pd.DataFrame(data).T
df.to_csv(f"data.csv", index=False)
# Muse 2 데이터 수집 정지
board_shim.stop_stream()
# Muse 2 연결 해제
board_shim.release_session()
이번 건 데이터를 csv로 저장하고 데이터 수집 종료 후 Muse 2 기기의 연결을 해제시킨다.
먼저 print(board_shim.get_board_descr(board_id)) 이 코드는 csv로 저장하는 것을 설명한 뒤 설명할 것이다. (쓰고 있을 때 생각해 보니.. 그냥 csv 아래에 적어도 되긴 할 텐데라고 생각하긴 했는데.. 귀찮다..
먼저 csv로 저장하는 것을 보면
그냥 알 수 있듯이 데이터를 DataFrame에 등록시키고 data.csv로 저장하는 것이다.
DataFrame에 등록할 때 T는 그냥 행열 바꾸는 것이다. 저거 안 하면 csv로 열었을 때 읽기 좀 불편하다..
그리고 index를 없애는 건 굳이 필요 없어서.. 더 복잡하게 보일 것 같으니..
그리고 데이터 수집을 종료하고 연결을 해제시키는데 만약에 연결 해제 코드를 안 쓰고 실행해 버려서 코드가 끝나면 Muse 2 기기는 연결된 상태로 코드가 끝나게 될 수 있다.. 이럴 경우 다시 연결할 때 이미 컴퓨터에 연결되어 있기 때문에 다시 연결이 안 된다. 그래서 다시 연결하려면 Muse 2 기기의 전원 버튼을 꾹 눌러서 전원을 강제 종료 시키고 다시 켜서 연결시키도록 해야 한다. 귀찮게 다시 연결하도록 할 것이 아니라면 종료 코드는 써주는 게 좋다.
참고로 이미 연결이 잘 되어있는지 확인하려면 Muse 2의 LED 인디케이터를 확인하면 된다. 연결이 되어있을 땐 전체에 불이 들어와 있고 연결이 아직 안 되었을 땐 왔다 갔다 led가 빛난다.
암튼 이제 print(board_shim.get_board_descr(board_id)) 에 대해서 설명할 텐데 이건 수집한 데이터의 칼럼 이름이다.
즉 데이터에서 뭐가 뭐인지 설명하도록 되어있다는 것이다.
저 코드를 실행해 보면 뭔가 뜨는데 그건 아래와 같다.
{'eeg_channels': [1, 2, 3, 4], 'eeg_names': 'TP9,AF7,AF8,TP10', 'marker_channel': 7, 'name': 'Muse2', 'num_rows': 8, 'other_channels': [5], 'package_num_channel': 0, 'sampling_rate': 256, 'timestamp_channel': 6}
데이터에서 어떤 게 무엇인지 설명하고 있다.
이것에 대한 자세한 건 실행한 후 알아야 하기 때문에 이후에 다시 설명할 것이다.
암튼 여기에선 코드 설명이 끝났다..! 이제 실행해 보는 것이다!
코드 실행해 보기
이제 코드를 실행해 보자!
내가 만들었던 가상환경으로 설정하고 Muse 2 기기의 전원 버튼을 눌러 전원을 켜고 코드를 실행하면 아래처럼 나올 것이다!
[2025-02-16 19:00:33.345] [board_logger] [info] incoming json: {
"file": "",
"file_anc": "",
"file_aux": "",
"ip_address": "",
"ip_address_anc": "",
"ip_address_aux": "",
"ip_port": 0,
"ip_port_anc": 0,
"ip_port_aux": 0,
"ip_protocol": 0,
"mac_address": "",
"master_board": -100,
"other_info": "",
"serial_number": "Muse-0465",
"serial_port": "",
"timeout": 0
}
[2025-02-16 19:00:33.346] [board_logger] [info] Use timeout for discovery: 6
[INFO] SimpleBLE: D:\a\brainflow\brainflow\third_party\SimpleBLE\simpleble\src\backends\windows\Utils.cpp:33 in initialize_winrt: CoGetApartmentType: cotype=-1, qualifier=0, result=800401F0
[INFO] SimpleBLE: D:\a\brainflow\brainflow\third_party\SimpleBLE\simpleble\src\backends\windows\Utils.cpp:41 in initialize_winrt: RoInitialize: result=0
[2025-02-16 19:00:33.379] [board_logger] [info] found 1 BLE adapter(s)
[2025-02-16 19:00:33.459] [board_logger] [info] Found Muse device
[2025-02-16 19:00:36.094] [board_logger] [info] Connected to Muse Device
[2025-02-16 19:00:37.103] [board_logger] [info] found control characteristic
{'eeg_channels': [1, 2, 3, 4], 'eeg_names': 'TP9,AF7,AF8,TP10', 'marker_channel': 7, 'name': 'Muse2', 'num_rows': 8, 'other_channels': [5], 'package_num_channel': 0, 'sampling_rate': 256, 'timestamp_channel': 6}
물론 어느 정도 차이는 있을 수 있다.
로그에서 뜨는 건 어떤 걸로 연결할지에 대한 것들이다. 그냥 코드만 틀린 게 없다면 Found Muse Device와 Connected to Muse Device가 뜨는지 확인하면 된다.
[2025-02-16 19:00:33.459] [board_logger] [info] Found Muse device
[2025-02-16 19:00:36.094] [board_logger] [info] Connected to Muse Device
이게 제대로 떴다면 연결이 성공적으로 되었다는 것이다..!
실행할 때 Muse 2의 인디케이터는 왔다 갔다 불빛이 나오다가 어느 순간 연결이 되면서 불빛이 모두 켜진다.
그 후 다시 연결이 해제되어 다시 왔다 갔다 불빛이 나오게 되는 것을 볼 수 있을 것이다.
참고로 인디케이터가 대충 어떻게 뜨나면..
아래 영상은 연결 중이거나 연결이 아직 안 되었다는 표시다.
아래 영상은 연결이 되었다는 표시다.
어쨌든 이런 식으로 확인이 가능하다..
만약 코드는 끝났는데 다시 왔다 갔다 불빛으로 바뀌지 않는다면 코드를 확인하거나 코드가 갑자기 중단되지는 않았는지 확인하는 것이 좋다.
참고로 전원을 켜지 않았다 던 지 블루투스 연결 장치가 제대로 작동하지 않다던지, 연결이 안 되었을 경우에는 아래처럼 뜬다.
[2025-02-17 03:37:41.517] [board_logger] [info] incoming json: {
"file": "",
"file_anc": "",
"file_aux": "",
"ip_address": "",
"ip_address_anc": "",
"ip_address_aux": "",
"ip_port": 0,
"ip_port_anc": 0,
"ip_port_aux": 0,
"ip_protocol": 0,
"mac_address": "",
"master_board": -100,
"other_info": "",
"serial_number": "Muse-0465",
"serial_port": "",
"timeout": 0
}
[2025-02-17 03:37:41.518] [board_logger] [info] Use timeout for discovery: 6
[INFO] SimpleBLE: D:\a\brainflow\brainflow\third_party\SimpleBLE\simpleble\src\backends\windows\Utils.cpp:33 in initialize_winrt: CoGetApartmentType: cotype=-1, qualifier=0, result=800401F0
[INFO] SimpleBLE: D:\a\brainflow\brainflow\third_party\SimpleBLE\simpleble\src\backends\windows\Utils.cpp:41 in initialize_winrt: RoInitialize: result=0
[2025-02-17 03:37:41.552] [board_logger] [info] found 1 BLE adapter(s)
[2025-02-17 03:37:47.581] [board_logger] [error] Failed to find Muse Device
Traceback (most recent call last):
File "D:\개발\AI\블로그\MUSE 2\blog\1_main.py", line 15, in <module>
board_shim.prepare_session()
File "C:\Users\____\anaconda3\envs\blogEEG\lib\site-packages\brainflow\board_shim.py", line 1191, in prepare_session
raise BrainFlowError('unable to prepare streaming session', res)
brainflow.exit_codes.BrainFlowError: BOARD_NOT_READY_ERROR:7 unable to prepare streaming session
이렇게 뜨면 제대로 연결이 되지 않았다는 거니깐 기기나 연결 장치를 확인해 보면 좋을 것 같다.. (뭐.. 그래도 안되면.. 컴퓨터를 바꿔보는 것도.. 추천..)
그러면 이제 한번 저장된 csv 파일을 분석..? 해보자..!
수집된 데이터 확인!
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
16 | -1000 | -987.3046875 | -945.8007813 | 709.4726563 | 0 | 1739688027.40830 | 0 |
16 | -910.6445313 | -856.9335938 | -998.5351563 | -795.8984375 | 0 | 1739688027.41217 | 0 |
16 | -623.046875 | -791.9921875 | -981.9335938 | -1000 | 0 | 1739688027.41605 | 0 |
16 | -866.2109375 | -925.2929688 | -933.59375 | 202.6367188 | 0 | 1739688027.41992 | 0 |
17 | -1000 | -1000 | -892.578125 | 999.5117188 | 0 | 1739688027.42472 | 0 |
17 | -780.2734375 | -899.4140625 | -963.3789063 | -389.6484375 | 0 | 1739688027.42953 | 0 |
17 | -482.421875 | -773.4375 | -1000 | -1000 | 0 | 1739688027.43433 | 0 |
17 | -552.734375 | -866.2109375 | -917.96875 | -216.3085938 | 0 | 1739688027.43913 | 0 |
17 | -760.2539063 | -991.6992188 | -841.796875 | 999.5117188 | 0 | 1739688027.44394 | 0 |
17 | -636.2304688 | -936.5234375 | -862.3046875 | 242.1875 | 0 | 1739688027.44874 | 0 |
17 | 321.2890625 | -769.0429688 | -763.671875 | -1000 | 0 | 1739688027.45354 | 0 |
17 | -59.5703125 | -805.6640625 | -835.4492188 | -407.7148438 | 0 | 1739688027.45835 | 0 |
17 | -1000 | -979.9804688 | -931.1523438 | 999.5117188 | 0 | 1739688027.46315 | 0 |
17 | -635.2539063 | -963.8671875 | -836.9140625 | 511.71875 | 0 | 1739688027.46795 | 0 |
17 | -486.8164063 | -818.8476563 | -887.2070313 | -1000 | 0 | 1739688027.47275 | 0 |
17 | -990.7226563 | -813.4765625 | -1000 | -891.1132813 | 0 | 1739688027.47756 | 0 |
18 | -979.9804688 | -954.1015625 | -948.7304688 | 675.78125 | 0 | 1739688027.48136 | 0 |
18 | -724.1210938 | -985.3515625 | -816.40625 | 956.5429688 | 0 | 1739688027.48517 | 0 |
18 | -869.140625 | -876.4648438 | -904.296875 | -541.9921875 | 0 | 1739688027.48897 | 0 |
이렇게 측정되었다!
이제 위에서 말했던.. print(board_shim.get_board_descr(board_id)) 이 코드로 출력된 것과 같이 확인해 보면 된다.
{'eeg_channels': [1, 2, 3, 4], 'eeg_names': 'TP9,AF7,AF8,TP10', 'marker_channel': 7, 'name': 'Muse2', 'num_rows': 8, 'other_channels': [5], 'package_num_channel': 0, 'sampling_rate': 256, 'timestamp_channel': 6}
이제 이렇게 보면 출력했던 것이 무엇인지 짐작이 갈 것이다.
출력된 것에서 숫자들은 칼럼이다. 'eeg_channels': [1, 2, 3, 4]는 1, 2, 3, 4 컬럼이 eeg 채널이라는 것을 의미한다.
그러면 저기에서 설명한 것을 토대로 csv를 수정해 보면!
package_num_channel | TP9 | AF7 | AF8 | TP10 | other_channels | timestamp_channel | marker_channel |
16 | -1000 | -987.3046875 | -945.8007813 | 709.4726563 | 0 | 1739688027.40830 | 0 |
16 | -910.6445313 | -856.9335938 | -998.5351563 | -795.8984375 | 0 | 1739688027.41217 | 0 |
16 | -623.046875 | -791.9921875 | -981.9335938 | -1000 | 0 | 1739688027.41605 | 0 |
16 | -866.2109375 | -925.2929688 | -933.59375 | 202.6367188 | 0 | 1739688027.41992 | 0 |
17 | -1000 | -1000 | -892.578125 | 999.5117188 | 0 | 1739688027.42472 | 0 |
17 | -780.2734375 | -899.4140625 | -963.3789063 | -389.6484375 | 0 | 1739688027.42953 | 0 |
17 | -482.421875 | -773.4375 | -1000 | -1000 | 0 | 1739688027.43433 | 0 |
17 | -552.734375 | -866.2109375 | -917.96875 | -216.3085938 | 0 | 1739688027.43913 | 0 |
17 | -760.2539063 | -991.6992188 | -841.796875 | 999.5117188 | 0 | 1739688027.44394 | 0 |
17 | -636.2304688 | -936.5234375 | -862.3046875 | 242.1875 | 0 | 1739688027.44874 | 0 |
17 | 321.2890625 | -769.0429688 | -763.671875 | -1000 | 0 | 1739688027.45354 | 0 |
17 | -59.5703125 | -805.6640625 | -835.4492188 | -407.7148438 | 0 | 1739688027.45835 | 0 |
17 | -1000 | -979.9804688 | -931.1523438 | 999.5117188 | 0 | 1739688027.46315 | 0 |
17 | -635.2539063 | -963.8671875 | -836.9140625 | 511.71875 | 0 | 1739688027.46795 | 0 |
17 | -486.8164063 | -818.8476563 | -887.2070313 | -1000 | 0 | 1739688027.47275 | 0 |
17 | -990.7226563 | -813.4765625 | -1000 | -891.1132813 | 0 | 1739688027.47756 | 0 |
18 | -979.9804688 | -954.1015625 | -948.7304688 | 675.78125 | 0 | 1739688027.48136 | 0 |
18 | -724.1210938 | -985.3515625 | -816.40625 | 956.5429688 | 0 | 1739688027.48517 | 0 |
18 | -869.140625 | -876.4648438 | -904.296875 | -541.9921875 | 0 | 1739688027.48897 | 0 |
이렇게 할 수 있다!
표 맞추기가.. 컴퓨터로 보면 그나마 보이기는 하는데.. 모바일에서는 잘 안 보일 수 있으니.. 웬만하면 데스크톱으로 보는 것을 추천!
아무튼 이제 표를 보면 대충 이해가 될 것이다. 참고로 'eeg_channels': [1, 2, 3, 4], 'eeg_names': 'TP9, AF7, AF8, TP10' 이것이 1, 2, 3, 4로 정의되어 있지만 각각은 eeg_names도 의미하기 때문에 저걸로 대입한 것이다.
이제 이름과 매칭해서 보면 이해하기 쉬울 것이다.
- package_num_channel : 지금 보고 이해했는데.. 패킷 번호 같다. 데이터 받아올 때 번호 같은 거?
- TP9, AF7, AF8, TP10 : 전극에서 측정된 데이터.. (뇌파)
- other_channels : 잘은 모르겠지만.. 다른 기기에서 쓰일지도..
- timestamp_channel : 유닉스 시간으로 몇 초에 측정된 데이터인지
- marker_channel : 이것도 잘은 모르겠다. 다른 기기에서 쓰일지도..
아무튼 내가 이해한 걸로 써보면 대충 이렇다. package_num_channel은 당시에는 딱히 필요 없는 것 같아서 뭔지 신경 쓰진 않았는데.. 패킷 번호인 것 같다.
아무튼 지금은 봐서도 뭐가 뭐인지 모르겠다.
나중에 이걸로 처리를 해보면 알 수 있게 되겠지만.. 일단 이렇다.
참고로 데이터에서 -1000으로 보이는 건 결측값이다. 즉 측정이 되지 않거나 이상하게 된 것..
왜냐하면 내가 빠르게 실행하려고 머리에 착용하지 않고 실행해서 측정한 것이기 때문..
그러면 한번 측정된 것을 그래프로 봐보자!!
그래프로 보기
이것이 그래프로 표현했을 때 이다!
색은 흰 배경에 할라 했는데.. 잘 안 보여서 내가 제일 좋아하는 드라큘라 테마로 설정했다.
참고로 이건 위에 예시로 올린 데이터는 아니다. 새로 측정한 것이기 때문에..
아무튼 저걸 보면 그래프가 들쑥날쑥하다.. 이유는 당연하게도 아까 말했던 것처럼 착용하지 않고 측정해서 그렇다.
그러면 한번 직접 써서 측정해 보겠다!
쓰는 방법은.. 전극은 이마 쪽으로 하고 귀에 거는 형태로 쓰면 된다.
위 사진처럼 써서 측정하면 된다.
쓸 때 팁은 최대한 길게 뽑은 뒤에 귀에 걸고 앞부분을 이마에 최대한 밀착하게 누르면서 다시 길게 뽑은 걸 줄이면 된다.
참고로 이마를 까고 해야 해서.. 좀 쓴 모습을 들키기는 싫다;;
아무튼 착용하고 측정해 보았다!
이제 이것을 보면 알 수 있다! 이제 결측값이 없기 때문에 제대로 데이터가 어떻게 분포하고 있는지 알 수 있다!
아무튼 데이터가 이런 식으로 보이고 한다!
그래프 그리는 건 귀찮기 때문에 ChatGPT 한테 부탁했다! 그렇기에 그래프 그리는 코드는 딱히 공유 안 하겠다!
암튼 각각의 뇌 부위가 어떤 값인지 알 수가 있는데.. 각각이 다르게 측정된다는 게 신기하긴 하다..
이것을 이용해서 이후에는 델타 베타 알파 이런 값으로 바꾸고 집중도나 이런 것도 측정해 보면 더 신기해진다!!
암튼 이로써 코드를 작성해서 Brainflow랑 Muse 2를 연결해 보고 데이터 저장은 끝났다!
거의 5시간 이상 째 쓰고 있는데.. 하아 역시 힘들긴 하다.. 그래도 글 연습 하는 겸 쓰는 것이기도 하니 재밌을지도..?
그리고 아래는 위에 코드 설명에서 왜 1초를 더 추가 측정하는지에 대한 것이다.
데이터를 1초 더 측정하는 이유
위에서 말했던 2초를 측정하는 이유와 이전 글의 Muse 2에 대한 정보를 말할 때도 한번 말했던 것이다.
Muse 2의 기기 정보를 보면 초당 256개의 데이터가 측정된다고 작성이 되어있는데..
실제로 측정을 해보면 초당 256개가 모이지 않는 것을 발견할 수 있다.. 아닐 수도 있지만;;
아무튼 이런 이유를 생각해 보면 블루투스로 연결하다 보니 발생하는 것 같다.
관련 글은 Muse 2016에 대한 얘기지만 Muse 2와도 관련이 있는 것 같기 때문에 같이 첨부!
아래 사이트에 적힌 말처럼 블루투스로 데이터를 보내면서 손실들이 발생하는 것이 아닐까 생각된다..
https://mind-monitor.com/forums/viewtopic.php?t=1447
Muse 2016 Sampling Rate - Mind Monitor
Mindman Posts: 2 Joined: Sun Jul 12, 2020 12:50 am Post by Mindman » Sun Jul 12, 2020 12:54 am I've been doing some data analysis on the mind monitor data from a 2016 Muse. The lengths of my sessions are 25 minutes and the 2016 Muse sampling rate is suppo
mind-monitor.com
참고로 데이터를 딱 1초만 수집되게 해서 착용하고 측정해 보면..
이런 식으로 측정되는 것을 볼 수 있다.. (참고로 착용하고 측정한 건데 착용하지 않아도 빨간색으로 측정이 안된 건 동일하다.)
빨간색이 결측값에 해당한다. 전극이 닿지 않아 측정되지 않은 값이 아닌, 이건 데이터가 없어서 빨간색으로 뜨는 것이다.
0 값에 위치하게 한건 그냥 보기 쉽게 하려고이다.
아무튼 딱 1초만 측정하게 되면 연결되는 시간이나 BLE로 보내다 보니 값이 조금씩 비어서 저렇게 나오는 것 같다.
아무튼 그런 이유로 1초를 추가로 더 측정하는 것이다.
아무튼 이번 글은 여기에서 끝!
(다음은 뭔 글로 써야 하지.. 얼마나 더 길까..)
자랑
추가로 하나 자랑하자면..
{'eeg_channels': [1, 2, 3, 4], 'eeg_names': 'TP9,AF7,AF8,TP10', 'marker_channel': 7, 'name': 'Muse2', 'num_rows': 8, 'other_channels': [5], 'package_num_channel': 0, 'sampling_rate': 256, 'timestamp_channel': 6}
여기에서 원래 EEG 이름이 'eeg_names': 'TP9, Fp1, Fp2, TP10' 이걸로 설정되어 있었다..
저 설정은 잘못된 정보이다.. Muse 2를 찾아봐도 알 수 있듯이 Fp1, Fp2에 전극이 있지가 않다는 걸 알 수 있다.
그래서 좀 더 찾아보니.. 코드 다른 곳에선 AF7, AF8이 정확하게 적혀있는데.. 데이터를 출력하는 코드에서만 잘못되어 있었다..
그래서 내가 직접 코드를 수정해서 맞는 전극 위치로 수정한 것이 AF7, AF8이다.. 처음으로 대형 프로젝트에서 나도 코드 수정하는데 기여했다! 굉장히 뿌듯!
아무튼.. 당시에는 연구과제를 하며.. 나중에도 쓰겠지만.. 수업 자료를 만들고 있었다. 그때 이상하다는 것을 발견하고 수정 요청을 했는데.. 버전은 한 달 뒤에 바뀌어서 바로 수정은 되지 않았지만.. 아무튼 이것이 내 자랑!
https://github.com/brainflow-dev/brainflow/pull/744
Fix EEG names for Muse 2, Muse S, Muse 2016 by cheongpark · Pull Request #744 · brainflow-dev/brainflow
Description of Changes I noticed that the eeg_names for the Muse 2 I am using were incorrect. Upon checking, it seems that the names have changed. Original: TP9, Fp1, Fp2, TP10 Updated: TP9, AF7, A...
github.com
이것이 그때 수정했었을 때 수정 요청 날린 거!
https://github.com/brainflow-dev/brainflow/pull/745
Fix UTF-8 encoding problem by cheongpark · Pull Request #745 · brainflow-dev/brainflow
Traceback (most recent call last): File "C:\Users\cheongpark\brainflow\tools\build.py", line 309, in <module> main() File "C:\Users\cheongpark\brainflow\tools\build.py", l...
github.com
추가로 이건 이 글과는 상관없지만.. C++에서 빌드할 때 한국어나 일본어등 유니코드를 사용하는 윈도우 컴퓨터에서 빌드할 시 생기는 오류를 해결하기 위한 간단한 코드 한 줄 추가한 커밋이다.. 당시 올릴 때 이게 맞나? 올려도 되나? 여러 검증을 하면서 떨리기는 했었는데.. 올리고 나니.. 굉장히 뿌듯했다..!!
이거 작성한 2일 후에 생각나서 추가로 작성하는 거지만..
Muse 2는 이렇게 생겼다.
![]() |
![]() |
![]() |
참고로 저거 길이 조정 가능한데 저건 내가 착용할 때 맞춰놓은 길이이고.. (좀 더 길게 할 수 있다.)
길이를 제일 줄이면 이 정도.. (포장은 저 줄여진 상태로 온다.)
'개발 > Muse 2' 카테고리의 다른 글
[Muse 2] BrainFlow ML로 집중도 구하기!! (0) | 2025.02.21 |
---|---|
[Muse 2] BrainFlow로 집중도 구하기!! (1) | 2025.02.19 |
[Muse 2] BrainFlow Python 설치하기 (0) | 2025.02.16 |
[Muse 2] Muse 2 알아보기!! (0) | 2025.02.16 |
BrainFlow C++ 설치방법 (Muse 2, Muse S 지원 설치 | CMake 사용) (0) | 2024.05.22 |