dev: разработан новый алгоритм детекции состояний системы в клиентских трейсах

This commit is contained in:
Andrew 2025-02-06 18:44:12 +03:00
parent 90b6660a15
commit 9be6843307
4 changed files with 138 additions and 73 deletions

View File

@ -1,23 +1,29 @@
{
"robot_zero_velocity_trashold": [
0.008
"act_vel_min": [
1800.0
],
"actuator_zero_velocity_trashold": [
100.0
"act_vel_close": [
1700.0
],
"actuator_finishing_velocity": [
2000.0
"act_vel_thresh": [
10.0
],
"actuator_finishing_velocity_trashold": [
"act_vel_negative": [
200.0
],
"actuator_current_trashold": [
0.5
"rob_vel_thresh": [
4.0
],
"ROI_start": [
8.0
"act_force_close": [
700.0
],
"ROI_finish": [
43.0
"act_force_weld": [
1300.0
],
"force_increase": [
100.0
],
"force_decrease": [
100.0
]
}

View File

@ -241,13 +241,15 @@ class OperatorSettings(settingsWindow):
class FilterSettings(settingsWindow):
def __init__(self, path, name, upd_func):
assosiated_names = {
"robot_zero_velocity_trashold" : "Robot zero speed filter +-m/sec",
"actuator_zero_velocity_trashold" : "Actuator zero speed filter +-m/sec",
"actuator_finishing_velocity" : "Actuator finishing speed m/sec",
"actuator_finishing_velocity_trashold" : "Actuator finishing speed filter m/sec",
"actuator_current_trashold": "Actuator force filter N",
"ROI_start" : "Start time, sec",
"ROI_finish" : "End time, sec"
"act_vel_min" : "Minimum for ME speed in Closing mm/sec",
"act_vel_close" : "Maximum for ME speed in Squeeze mm/sec",
"act_vel_thresh" : "ME zero speed threshold mm/sec",
"act_vel_negative" : "ME Relief speed mm/sec",
"rob_vel_thresh": "Robot zero speed threshold mm/sec",
"act_force_close" : "Maximum ME force in Closing, N",
"act_force_weld" : "Minimum ME force in Welding, N",
"force_increase": "ME force rising speed in Squeeze",
"force_decrease":"ME force falling speed in Relief"
}
super().__init__(path, name, upd_func, assosiated_names)
self._num_points.setVisible(False)

View File

@ -173,63 +173,104 @@ class TraceStageDetector(BaseTraceStageDetector):
def __init__(self, parent:TraceProcessor = None):
super().__init__(parent)
def detect_stages(self, df: pd.DataFrame) -> list:
df = df.sort_index()
stage_markers = []
timestamps = df['time'].to_list() # времена (в секундах) как список
for i, time in enumerate(timestamps):
mark = self._mark_timestamp(df, i, time)
if mark: stage_markers.append(mark)
# Объединяем подряд идущие одинаковые метки в единые этапы.
stages = self._merge_marks_to_stages(stage_markers, timestamps)
return stages
def _mark_timestamp(self, df:pd.DataFrame, index:int, time:float) -> Union[str, None]:
# Не интересные значения помечаем как "unknown"
if (time < self._parent._settings.filter["ROI_start"][0] or
time > self._parent._settings.filter["ROI_finish"][0]):
return "unknown"
rob_vel = df.loc[index, "CartVel_Act"]
act_vel = df.loc[index, "DriveMotorVel_Act7"]
act_curr = df.loc[index, "DriveMotorCurr_Act7"]
@staticmethod
def is_closing(rob_vel:float,
act_vel:float,
act_force:float,
th:dict) -> bool:
# act_vel > min, rob_vel ~ 0, act_force ниже порога
return act_vel > th['act_vel_min'] and abs(rob_vel) < th['rob_vel_thresh'] and act_force < th['act_force_close']
if abs(rob_vel) > self._parent._settings.filter["robot_zero_velocity_trashold"][0]:
return "Oncomming"
@staticmethod
def is_squeeze(rob_vel:float,
act_vel:float,
act_force:float,
force_rate:float,
th:dict) -> bool:
# rob_vel ~ 0, act_vel меньше, чем в closing, и резкий рост act_force
return abs(rob_vel) < th['rob_vel_thresh'] and act_vel < th['act_vel_close'] and force_rate > th['force_increase']
if (abs(act_vel) < self._parent._settings.filter["actuator_zero_velocity_trashold"][0] and
abs(act_curr) > self._parent._settings.filter["actuator_current_trashold"][0]):
return "Squeeze&Welding&Relief"
@staticmethod
def is_welding(rob_vel:float,
act_vel:float,
act_force:float,
th:dict) -> bool:
# обе скорости ≈ 0, act_force выше порога сварки
return abs(rob_vel) < th['rob_vel_thresh'] and abs(act_vel) < th['act_vel_thresh'] and act_force > th['act_force_weld']
if self._parent._settings.filter["actuator_finishing_velocity_trashold"][0] > abs(abs(act_vel) - self._parent._settings.filter["actuator_finishing_velocity"][0]):
return "Closing"
@staticmethod
def is_relief(rob_vel:float,
act_vel:float,
act_force:float,
force_rate:float,
th:dict) -> bool:
# резкое падение act_force, отрицательный act_vel, малые rob_vel
return force_rate < -th['force_decrease'] and act_vel < -th['act_vel_negative'] and abs(rob_vel) < th['rob_vel_thresh']
return None
def detect_stages(self, df:pd.DataFrame):
timestamps = df['time'].to_list()
n = len(df)
th = {key: item[0] for key, item in self._parent._settings.filter.items()}
# Вычисляем разностную производную силы
act_force = df["DriveMotorTorq_Act7"].values
force_diff = np.diff(act_force, prepend=act_force[0])
def _merge_marks_to_stages(self, stage_markers:list, timestamps:list) -> list:
stages = []
current_stage = stage_markers[0]
start_time = timestamps[0]
states = []
current_state = "Oncomming"
state_start = timestamps[0]
for i in range(1, len(stage_markers)):
if stage_markers[i] != current_stage:
end_time = timestamps[i - 1]
stages.append({
"stage": current_stage,
"start_time": start_time,
"end_time": end_time
})
current_stage = stage_markers[i]
start_time = timestamps[i]
# Проходим по всем записям
for i in range(n):
rob_vel = df.loc[i, "CartVel_Act"]
act_vel = df.loc[i, "DriveMotorVel_Act7"]
act_force_val = df.loc[i, "DriveMotorTorq_Act7"]
force_rate = force_diff[i]
stages.append({
"stage": current_stage,
"start_time": start_time,
"end_time": timestamps[-1]
})
return stages
if current_state == "Oncomming":
if self.is_closing(rob_vel, act_vel, act_force_val, th):
state_end = timestamps[i]
states.append(("Oncomming", state_start, state_end))
current_state = "Closing"
state_start = timestamps[i]
elif current_state == "Closing":
if self.is_squeeze(rob_vel, act_vel, act_force_val, force_rate, th):
state_end = timestamps[i]
states.append(("Closing", state_start, state_end))
current_state = "Squeeze"
state_start = timestamps[i]
elif current_state == "Squeeze":
if self.is_welding(rob_vel, act_vel, act_force_val, th):
state_end = timestamps[i]
states.append(("Squeeze", state_start, state_end))
current_state = "Welding"
state_start = timestamps[i]
elif current_state == "Welding":
if self.is_relief(rob_vel, act_vel, act_force_val, force_rate, th):
state_end = timestamps[i]
states.append(("Welding", state_start, state_end))
current_state = "Relief"
state_start = timestamps[i]
elif current_state == "Relief":
# Когда признаки relief отпадают, считаем, что цикл завершён и возвращаемся в Oncomming
if not self.is_relief(rob_vel, act_vel, act_force_val, force_rate, th):
state_end = timestamps[i]
states.append(("Relief", state_start, state_end))
current_state = "Oncomming"
state_start = timestamps[i]
# Фиксируем последний сегмент
states.append((current_state, state_start, timestamps[-1]))
return states
class TextStageDetector(BaseTextStageDetector):
@ -305,8 +346,9 @@ class TraceProcessor(BaseRawTraceProcessor):
def _detect_stages(self, trace_df:pd.DataFrame, text_data:list) -> dict[list]:
if trace_df is not None and text_data is not None:
trace_stages = self._data_detector.detect_stages(trace_df)
welding_stages = self._text_detector.detect_welding(text_data)
events = self._form_events(trace_stages, welding_stages)
#welding_stages = self._text_detector.detect_welding(text_data)
#events = self._form_events(trace_stages, welding_stages)
events = self.__form_events_2(trace_stages)
return events
return None
@ -355,6 +397,21 @@ class TraceProcessor(BaseRawTraceProcessor):
normalized_events = TraceProcessor._normalize_events(events)
return normalized_events
@staticmethod
def __form_events_2(trace_stages:list):
events = {
"Closing":[[],[]],
"Squeeze":[[],[]],
"Welding":[[],[]],
"Relief":[[],[]],
"Oncomming":[[],[]]
}
for stage in trace_stages:
name, start_t, end_t = stage
events[name][0].append(start_t)
events[name][1].append(end_t)
return events
@staticmethod
def _rename_df_columns(dataframe: pd.DataFrame) -> pd.DataFrame:
correct_mapping = {

View File

@ -86,7 +86,7 @@ DIAEXTENDED
#BEGINCHANNELHEADER
200,DriveMotorPos_Act7
201,AxisValAtMMInterface
202,°
202,<EFBFBD>
210,EXPLIZIT
211,teslaSP_VelTCP_KRCIpo.r64
213,BLOCK
@ -101,7 +101,7 @@ DIAEXTENDED
#BEGINCHANNELHEADER
200,DriveMotorVel_Act7
201,AxisValAtMMInterface
202,°/s
202,<EFBFBD>/s
210,EXPLIZIT
211,teslaSP_VelTCP_KRCIpo.r64
213,BLOCK
@ -124,7 +124,7 @@ DIAEXTENDED
220,3806
221,7
240,0
241,1.000000e+00
241,1.000000e+03
#ENDCHANNELHEADER
@ -169,7 +169,7 @@ DIAEXTENDED
220,3806
221,10
240,0
241,1.000000e-03
241,1.000000e+00
#ENDCHANNELHEADER