呼吸体动检测基本稳定

This commit is contained in:
marques 2025-11-10 14:37:42 +08:00
parent 265fcd958a
commit f258838a86
3 changed files with 40 additions and 18 deletions

View File

@ -28,7 +28,7 @@ import numpy as np
import signal_method
import os
from matplotlib import pyplot as plt
os.environ['DISPLAY'] = "localhost:14.0"
os.environ['DISPLAY'] = "localhost:10.0"
def process_one_signal(samp_id):
signal_path = list((org_signal_root_path / f"{samp_id}").glob("OrgBCG_Sync_*.txt"))
@ -144,14 +144,15 @@ def process_one_signal(samp_id):
print("resp_movement_mask revise is skipped")
# 分析Resp的幅值突变区间
if resp_movement_mask is not None:
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:
resp_amp_change_mask, resp_amp_change_list = signal_method.position_based_sleep_recognition_v3(
signal_data=resp_data,
movement_mask=resp_movement_mask,
movement_list=resp_movement_position_list,
sampling_rate=resp_fs)
sampling_rate=resp_fs,
**resp_amp_change_conf)
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
@ -237,4 +238,4 @@ if __name__ == '__main__':
all_samp_disable_df = utils.read_disable_excel(disable_df_path)
process_one_signal(select_ids[7])
process_one_signal(select_ids[0])

View File

@ -48,6 +48,12 @@ resp_movement_revise:
merge_gap_sec: 10
min_duration_sec: 1
resp_amp_change:
mav_calc_window_sec: 5
threshold_amplitude: 0.1
threshold_energy: 0.4
bcg:
downsample_fs: 100

View File

@ -194,10 +194,15 @@ def movement_revise(signal_data, sampling_rate, movement_mask, movement_list, up
# 往左右两边取compare_size个点的mav取平均值
for start, end in movement_list:
left_values = collect_values(arr=mav, index=start - 1, step=-1, limit=compare_size, mask=movement_mask)
right_values = collect_values(arr=mav, index=end + 5, step=1, limit=compare_size, mask=movement_mask)
left_points = start - 5
right_points = end + 5
left_values = collect_values(arr=mav, index=left_points, step=-1, limit=compare_size, mask=movement_mask)
right_values = collect_values(arr=mav, index=right_points, step=1, limit=compare_size, mask=movement_mask)
left_value_metrics = np.median(left_values) if len(left_values) > 0 else 0
right_value_metrics = np.median(right_values) if len(right_values) > 0 else 0
if left_value_metrics == 0:
value_metrics = right_value_metrics
elif right_value_metrics == 0:
@ -207,7 +212,7 @@ def movement_revise(signal_data, sampling_rate, movement_mask, movement_list, up
# 逐秒遍历mav判断是否需要修正
# print(f"Revising movement from index {start} to {end}, left_mean: {left_value_mean:.2f}, right_mean: {right_value_mean:.2f}, mean: {value_mean:.2f}")
for i in range(start, end + 5):
for i in range(left_points, right_points):
if i < 0 or i >= len(mav):
continue
# print(f"Index {i}, mav: {mav[i]:.2f}, left_mean: {left_value_mean:.2f}, right_mean: {right_value_mean:.2f}, mean: {value_mean:.2f}")
@ -514,9 +519,13 @@ def position_based_sleep_recognition_v2(signal_data, movement_mask, sampling_rat
return position_changes, position_change_times
def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_list, sampling_rate=100):
def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_list, sampling_rate, mav_calc_window_sec,
threshold_amplitude, threshold_energy):
"""
:param threshold_energy:
:param threshold_amplitude:
:param mav_calc_window_sec:
:param movement_list:
:param signal_data:
:param movement_mask: mask的采样率为1Hz
@ -524,11 +533,6 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
:param window_size_sec:
:return:
"""
mav_calc_window_sec = 1 # 计算mav的窗口大小单位秒
# 判断是否存在显著变化 (可根据实际情况调整阈值)
threshold_amplitude = 0.1 # 幅值变化阈值
threshold_energy = 0.1 # 能量变化阈值
# 获取有效片段起止位置
valid_list = utils.event_mask_2_list(movement_mask, event_true=False)
@ -549,16 +553,26 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
return [], []
def clac_mav(data_segment):
mav = np.nanmean(
# 确定data_segment长度为mav_calc_window_sec的整数倍
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 = np.nanstd(
np.nanmax(data_segment.reshape(-1, mav_calc_window_sec * sampling_rate),
axis=0)) - np.nanmean(
axis=0) -
np.nanmin(data_segment.reshape(-1, mav_calc_window_sec * sampling_rate), axis=0))
return mav
def clac_energy(data_segment):
energy = np.nansum(np.abs(data_segment ** 2))
energy = np.nansum(np.abs(data_segment ** 2)) // (len(data_segment) // sampling_rate)
return energy
def calc_mav_by_quantiles(data_segment):
# 先计算所有的mav值
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))
# 计算分位数
position_changes = np.zeros(len(signal_data) // sampling_rate, dtype=int)
position_change_list = []
@ -583,7 +597,8 @@ def position_based_sleep_recognition_v3(signal_data, movement_mask, movement_lis
# 避免过短的片段
if movement_end - movement_start <= sampling_rate: # 小于1秒的片段不考虑
print(f"Skipping movement segment {i + 1} due to insufficient length. movement start: {movement_start}, movement end: {movement_end}")
print(
f"Skipping movement segment {i + 1} due to insufficient length. movement start: {movement_start}, movement end: {movement_end}")
continue
# 计算前后片段的幅值和能量