修正幅值改变计算

This commit is contained in:
marques 2025-11-11 10:39:23 +08:00
parent 40fdda6497
commit 60e245b1e3
4 changed files with 55 additions and 52 deletions

View File

@ -12,7 +12,6 @@
提供数据处理前后的可视化对比帮助理解数据变化
绘制多条可用性趋势图展示数据的可用区间体动区间低幅值区间等
todo: 使用mask 屏蔽无用区间
# 低幅值区间规则标定与剔除
@ -28,8 +27,10 @@ import numpy as np
import signal_method
import os
from matplotlib import pyplot as plt
os.environ['DISPLAY'] = "localhost:10.0"
def process_one_signal(samp_id, show=False):
signal_path = list((org_signal_root_path / f"{samp_id}").glob("OrgBCG_Sync_*.txt"))
if not signal_path:
@ -74,7 +75,6 @@ def process_one_signal(samp_id, show=False):
sample_rate=resp_fs)
print("Begin plotting signal data...")
# fig = plt.figure(figsize=(12, 8))
# # 绘制三个图raw_data、resp_data_1、resp_data_2
# ax0 = fig.add_subplot(3, 1, 1)
@ -116,7 +116,8 @@ def process_one_signal(samp_id, show=False):
sampling_rate=resp_fs,
**resp_low_amp_conf
)
print(f"resp_low_amp_mask_shape: {resp_low_amp_mask.shape}, num_low_amp: {np.sum(resp_low_amp_mask == 1)}, count_low_amp_positions: {len(resp_low_amp_position_list)}")
print(
f"resp_low_amp_mask_shape: {resp_low_amp_mask.shape}, num_low_amp: {np.sum(resp_low_amp_mask == 1)}, count_low_amp_positions: {len(resp_low_amp_position_list)}")
else:
resp_low_amp_mask, resp_low_amp_position_list = None, None
print("resp_low_amp_mask is None")
@ -129,7 +130,8 @@ def process_one_signal(samp_id, show=False):
sampling_rate=resp_fs,
**resp_movement_conf
)
print(f"resp_movement_mask_shape: {resp_movement_mask.shape}, num_movement: {np.sum(resp_movement_mask == 1)}, count_movement_positions: {len(resp_movement_position_list)}")
print(
f"resp_movement_mask_shape: {resp_movement_mask.shape}, num_movement: {np.sum(resp_movement_mask == 1)}, count_movement_positions: {len(resp_movement_position_list)}")
else:
resp_movement_mask, resp_movement_position_list = None, None
print("resp_movement_mask is None")
@ -144,11 +146,11 @@ def process_one_signal(samp_id, show=False):
**resp_movement_revise_conf,
verbose=False
)
print(f"After revise, resp_movement_mask_shape: {resp_movement_mask.shape}, num_movement: {np.sum(resp_movement_mask == 1)}, count_movement_positions: {len(resp_movement_position_list)}")
print(
f"After revise, resp_movement_mask_shape: {resp_movement_mask.shape}, num_movement: {np.sum(resp_movement_mask == 1)}, count_movement_positions: {len(resp_movement_position_list)}")
else:
print("resp_movement_mask revise is skipped")
# 分析Resp的幅值突变区间
resp_amp_change_conf = conf.get("resp_amp_change", None)
if resp_amp_change_conf is not None and resp_movement_mask is not None:
@ -159,13 +161,12 @@ def process_one_signal(samp_id, show=False):
sampling_rate=resp_fs,
**resp_amp_change_conf,
verbose=True)
print(f"amp_change_mask_shape: {resp_amp_change_mask.shape}, num_amp_change: {np.sum(resp_amp_change_mask == 1)}, count_amp_change_positions: {len(resp_amp_change_list)}")
print(
f"amp_change_mask_shape: {resp_amp_change_mask.shape}, num_amp_change: {np.sum(resp_amp_change_mask == 1)}, count_amp_change_positions: {len(resp_amp_change_list)}")
else:
resp_amp_change_mask = None
print("amp_change_mask is None")
# 分析Bcg的低幅值区间
bcg_low_amp_conf = conf.get("bcg_low_amp", None)
if bcg_low_amp_conf is not None:
@ -174,10 +175,12 @@ def process_one_signal(samp_id, show=False):
sampling_rate=bcg_fs,
**bcg_low_amp_conf
)
print(f"bcg_low_amp_mask_shape: {bcg_low_amp_mask.shape}, num_low_amp: {np.sum(bcg_low_amp_mask == 1)}, count_low_amp_positions: {len(bcg_low_amp_position_list)}")
print(
f"bcg_low_amp_mask_shape: {bcg_low_amp_mask.shape}, num_low_amp: {np.sum(bcg_low_amp_mask == 1)}, count_low_amp_positions: {len(bcg_low_amp_position_list)}")
else:
bcg_low_amp_mask, bcg_low_amp_position_list = None, None
print("bcg_low_amp_mask is None")
# 分析Bcg的高幅值伪迹区间
bcg_movement_conf = conf.get("bcg_movement", None)
if bcg_movement_conf is not None:
@ -186,26 +189,29 @@ def process_one_signal(samp_id, show=False):
sampling_rate=bcg_fs,
**bcg_movement_conf
)
print(f"bcg_movement_mask_shape: {bcg_movement_mask.shape}, num_movement: {np.sum(bcg_movement_mask == 1)}, count_movement_positions: {len(bcg_movement_position_list)}")
print(
f"bcg_movement_mask_shape: {bcg_movement_mask.shape}, num_movement: {np.sum(bcg_movement_mask == 1)}, count_movement_positions: {len(bcg_movement_position_list)}")
else:
bcg_movement_mask = None
print("bcg_movement_mask is None")
# 分析Bcg的幅值突变区间
if bcg_movement_mask is not None:
bcg_amp_change_mask, bcg_amp_change_list = signal_method.position_based_sleep_recognition_v2(
signal_data=bcg_data,
movement_mask=bcg_movement_mask,
sampling_rate=bcg_fs)
print(f"bcg_amp_change_mask_shape: {bcg_amp_change_mask.shape}, num_amp_change: {np.sum(bcg_amp_change_mask == 1)}, count_amp_change_positions: {len(bcg_amp_change_list)}")
print(
f"bcg_amp_change_mask_shape: {bcg_amp_change_mask.shape}, num_amp_change: {np.sum(bcg_amp_change_mask == 1)}, count_amp_change_positions: {len(bcg_amp_change_list)}")
else:
bcg_amp_change_mask = None
print("bcg_amp_change_mask is None")
# 如果signal_data采样率过进行降采样
if signal_fs == 1000:
signal_data = utils.downsample_signal_fast(original_signal=signal_data, original_fs=signal_fs, target_fs=100)
signal_data_raw = utils.downsample_signal_fast(original_signal=signal_data_raw, original_fs=signal_fs, target_fs=100)
signal_data_raw = utils.downsample_signal_fast(original_signal=signal_data_raw, original_fs=signal_fs,
target_fs=100)
signal_fs = 100
draw_tools.draw_signal_with_mask(samp_id=samp_id,
@ -226,9 +232,6 @@ def process_one_signal(samp_id, show=False):
show=show,
save_path=save_samp_path / f"{samp_id}_Signal_Plots.png")
# 复制事件文件 到保存路径
sa_label_save_name = f"{samp_id}" + label_path.name
shutil.copyfile(label_path, save_samp_path / sa_label_save_name)
@ -240,22 +243,21 @@ def process_one_signal(samp_id, show=False):
"SA_Score": score_mask,
"Disable_Label": manual_disable_mask,
"Resp_LowAmp_Label": resp_low_amp_mask if resp_low_amp_mask is not None else np.zeros(signal_second, dtype=int),
"Resp_Movement_Label": resp_movement_mask if resp_movement_mask is not None else np.zeros(signal_second, dtype=int),
"Resp_AmpChange_Label": resp_amp_change_mask if resp_amp_change_mask is not None else np.zeros(signal_second, dtype=int),
"Resp_Movement_Label": resp_movement_mask if resp_movement_mask is not None else np.zeros(signal_second,
dtype=int),
"Resp_AmpChange_Label": resp_amp_change_mask if resp_amp_change_mask is not None else np.zeros(signal_second,
dtype=int),
"Bcg_LowAmp_Label": bcg_low_amp_mask if bcg_low_amp_mask is not None else np.zeros(signal_second, dtype=int),
"Bcg_Movement_Label": bcg_movement_mask if bcg_movement_mask is not None else np.zeros(signal_second, dtype=int),
"Bcg_AmpChange_Label": bcg_amp_change_mask if bcg_amp_change_mask is not None else np.zeros(signal_second, dtype=int)
"Bcg_Movement_Label": bcg_movement_mask if bcg_movement_mask is not None else np.zeros(signal_second,
dtype=int),
"Bcg_AmpChange_Label": bcg_amp_change_mask if bcg_amp_change_mask is not None else np.zeros(signal_second,
dtype=int)
}
mask_label_save_name = f"{samp_id}_Processed_Labels.csv"
utils.save_process_label(save_path=save_samp_path / mask_label_save_name, save_dict=save_dict)
if __name__ == '__main__':
yaml_path = Path("./dataset_config/HYS_config.yaml")
disable_df_path = Path("./排除区间.xlsx")
@ -280,4 +282,3 @@ if __name__ == '__main__':
# print(f"Processing sample ID: {samp_id}")
# process_one_signal(samp_id, show=False)
# print(f"Finished processing sample ID: {samp_id}\n\n")

View File

@ -50,7 +50,7 @@ resp_movement_revise:
min_duration_sec: 1
resp_amp_change:
mav_calc_window_sec: 1
mav_calc_window_sec: 4
threshold_amplitude: 0.25
threshold_energy: 0.4

View File

@ -602,8 +602,8 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
if len(data_segment) % (mav_calc_window_sec * sampling_rate) != 0:
data_segment = data_segment[:-(len(data_segment) % (mav_calc_window_sec * sampling_rate))]
mav_values = np.nanmax(data_segment.reshape(-1, mav_calc_window_sec * sampling_rate), axis=0) - np.nanmin(
data_segment.reshape(-1, mav_calc_window_sec * sampling_rate))
mav_values = np.nanmax(data_segment.reshape(-1, mav_calc_window_sec * sampling_rate), axis=1) - np.nanmin(
data_segment.reshape(-1, mav_calc_window_sec * sampling_rate), axis=1)
# 计算分位数
q20 = np.nanpercentile(mav_values, 20)
q80 = np.nanpercentile(mav_values, 80)
@ -638,10 +638,12 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
movement_end = movement_list[i][1]
# 避免过短的片段
if movement_end - movement_start <= sampling_rate: # 小于1秒的片段不考虑
if movement_end - movement_start <= 1: # 小于1秒的片段不考虑
if verbose:
print(
f"Skipping movement segment {i + 1} due to insufficient length. movement start: {movement_start}, movement end: {movement_end}")
pre_valid_start = pre_valid_start
pre_valid_end = next_valid_end
continue
# 计算前后片段的幅值和能量
@ -665,7 +667,7 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
# print(
# f"Significant position change detected between segments {movement_start} and {movement_end}: left:{pre_valid_start}to{pre_valid_end} left_mav={left_mav:.2f}, right_mav={right_mav:.2f}, amplitude_change={amplitude_change:.2f}, left_energy={left_energy:.2f}, right_energy={right_energy:.2f}, energy_change={energy_change:.2f}")
if verbose:
print(f"Significant position change detected between segments {movement_start} and {movement_end}: left:{pre_valid_start}to{pre_valid_end} left_mav={left_mav:.2f}, right_mav={right_mav:.2f}, amplitude_change={amplitude_change:.2f}")
print(f"Significant position change detected between segments {movement_start}s and {movement_end}:s left:{pre_valid_start}to{pre_valid_end} left_mav={left_mav:.2f}, right:{next_valid_start}to{next_valid_end} right_mav={right_mav:.2f}, amplitude_change={amplitude_change:.2f}")
# 记录姿势变化发生的时间点 用当前分割的体动的起始位置和结束位置表示
position_changes[movement_start:movement_end] = 1
position_change_list.append(movement_list[i])

View File

@ -222,7 +222,7 @@ def event_mask_2_list(mask, event_true=True):
normal_2_event = -1
_append = 1
mask_start = np.where(np.diff(mask, prepend=_append, append=_append) == normal_2_event)[0]
mask_end = np.where(np.diff(mask, prepend=_append, append=_append) == event_2_normal)[0] + 1
mask_end = np.where(np.diff(mask, prepend=_append, append=_append) == event_2_normal)[0]
event_list =[[start, end] for start, end in zip(mask_start, mask_end)]
return event_list