diff --git a/config_model.py b/config_model.py index 73dd2c6..5278ea1 100644 --- a/config_model.py +++ b/config_model.py @@ -355,8 +355,9 @@ class AppConfig: pass # 备份失败不影响保存 # 保存配置 - with path.open("w", encoding="utf-8") as f: - json.dump(self.to_dict(), f, ensure_ascii=False, indent=2) + # 使用 newline='\n' 确保跨平台换行符一致(LF),避免 Windows CRLF 导致的问题 + with path.open("w", encoding="utf-8", newline='\n') as f: + json.dump(self.to_dict(), f, ensure_ascii=False, indent=2, sort_keys=False) def ensure_placeholder(self, key: str, type_hint: str) -> PlaceholderConfig: if key not in self.placeholders: diff --git a/temperature_600table_with_load_status.py b/temperature_600table_with_load_status.py index 50f15fc..09f9d1b 100644 --- a/temperature_600table_with_load_status.py +++ b/temperature_600table_with_load_status.py @@ -364,10 +364,24 @@ def _calculate_effective_time_points( effective_time_points[slot_str] = None continue - if target_effective_hours > total_effective_hours: - LOGGER.warning("Target effective time %.3fh exceeds total effective time %.3fh for slot %s", - target_effective_hours, total_effective_hours, slot_str) - effective_time_points[slot_str] = None + # 如果目标时间 >= 总有效时间(允许小的浮点误差),使用最后一个有效时间段的结束时间 + # 这样可以处理边界情况:实验正好运行了目标时长,但由于浮点精度可能略小于目标值 + tolerance = 0.01 # 允许 0.01 小时的容差 + if target_effective_hours >= total_effective_hours - tolerance: + if effective_periods: + # 使用最后一个有效时间段的结束时间 + last_period = effective_periods[-1] + target_time_point = last_period['end'] + effective_time_points[slot_str] = target_time_point + LOGGER.info("Slot %s: effective %.3fh >= total %.3fh, using last period end time %s", + slot_str, target_effective_hours, total_effective_hours, + target_time_point.strftime('%H:%M:%S')) + else: + # 如果没有有效时间段,使用实验结束时间 + effective_time_points[slot_str] = end_time + LOGGER.info("Slot %s: effective %.3fh >= total %.3fh, using experiment end time %s", + slot_str, target_effective_hours, total_effective_hours, + end_time.strftime('%H:%M:%S') if end_time else "N/A") continue # 在有效时间段中查找累计运行target_effective_hours小时的时间点 @@ -522,12 +536,18 @@ def _query_influxdb_with_load_status( filters or {}, ) - # 查询逻辑:查询目标时间点附近的数据,但只要 load_status = 1 的数据 - # 使用一个时间窗口来查找最接近的有效数据点 - window_minutes = 10 # 前后10分钟的窗口 + # 查询逻辑:查询目标时间点之前(包含目标时间点)的数据,获取最接近目标时间点的瞬时值 + # 使用实验开始时间作为查询起点,目标时间点作为查询终点,确保获取该时间点的瞬时数值 + # 需要从实验开始时间查询,因为有效时间点是基于累计运行时间计算的 + + # 获取实验开始时间(需要从环境变量或传入参数获取) + # 为了简化,我们使用一个合理的时间窗口:从目标时间点往前推足够长的时间 + # 但为了精确,我们应该查询到目标时间点为止,取最后一条 + window_minutes = 60 # 往前查询60分钟,确保能覆盖到数据 query_start = target_time - timedelta(minutes=window_minutes) - query_end = target_time + timedelta(minutes=window_minutes) + # 查询终点设置为目标时间点,确保获取的是该时间点或之前的数据 + query_end = target_time query_start_rfc = query_start.strftime('%Y-%m-%dT%H:%M:%SZ') query_end_rfc = query_end.strftime('%Y-%m-%dT%H:%M:%SZ') @@ -538,7 +558,7 @@ def _query_influxdb_with_load_status( for key, value in filters.items(): tag_filters += f'\n |> filter(fn: (r) => r["{key}"] == "{value}")' - # 查询温度数据(不需要load_status筛选,因为已经基于有效时间点查询) + # 查询温度数据:查询到目标时间点为止,取最后一条(最接近目标时间点的瞬时值) flux = f''' from(bucket: "{influx_bucket}") |> range(start: {query_start_rfc}, stop: {query_end_rfc}) diff --git a/temperature_table_with_load_status.py b/temperature_table_with_load_status.py index df9981b..bcbc588 100644 --- a/temperature_table_with_load_status.py +++ b/temperature_table_with_load_status.py @@ -368,10 +368,24 @@ def _calculate_effective_time_points( effective_time_points[slot_str] = None continue - if target_effective_hours > total_effective_hours: - LOGGER.warning("Target effective time %.3fh exceeds total effective time %.3fh for slot %s", - target_effective_hours, total_effective_hours, slot_str) - effective_time_points[slot_str] = None + # 如果目标时间 >= 总有效时间(允许小的浮点误差),使用最后一个有效时间段的结束时间 + # 这样可以处理边界情况:实验正好运行了目标时长,但由于浮点精度可能略小于目标值 + tolerance = 0.01 # 允许 0.01 小时的容差 + if target_effective_hours >= total_effective_hours - tolerance: + if effective_periods: + # 使用最后一个有效时间段的结束时间 + last_period = effective_periods[-1] + target_time_point = last_period['end'] + effective_time_points[slot_str] = target_time_point + LOGGER.info("Slot %s: effective %.3fh >= total %.3fh, using last period end time %s", + slot_str, target_effective_hours, total_effective_hours, + target_time_point.strftime('%H:%M:%S')) + else: + # 如果没有有效时间段,使用实验结束时间 + effective_time_points[slot_str] = end_time + LOGGER.info("Slot %s: effective %.3fh >= total %.3fh, using experiment end time %s", + slot_str, target_effective_hours, total_effective_hours, + end_time.strftime('%H:%M:%S') if end_time else "N/A") continue # 在有效时间段中查找累计运行target_effective_hours小时的时间点 @@ -526,12 +540,18 @@ def _query_influxdb_with_load_status( filters or {}, ) - # 查询逻辑:查询目标时间点附近的数据,但只要 load_status = 1 的数据 - # 使用一个时间窗口来查找最接近的有效数据点 - window_minutes = 10 # 前后10分钟的窗口 + # 查询逻辑:查询目标时间点之前(包含目标时间点)的数据,获取最接近目标时间点的瞬时值 + # 使用实验开始时间作为查询起点,目标时间点作为查询终点,确保获取该时间点的瞬时数值 + # 需要从实验开始时间查询,因为有效时间点是基于累计运行时间计算的 + + # 获取实验开始时间(需要从环境变量或传入参数获取) + # 为了简化,我们使用一个合理的时间窗口:从目标时间点往前推足够长的时间 + # 但为了精确,我们应该查询到目标时间点为止,取最后一条 + window_minutes = 60 # 往前查询60分钟,确保能覆盖到数据 query_start = target_time - timedelta(minutes=window_minutes) - query_end = target_time + timedelta(minutes=window_minutes) + # 查询终点设置为目标时间点,确保获取的是该时间点或之前的数据 + query_end = target_time query_start_rfc = query_start.strftime('%Y-%m-%dT%H:%M:%SZ') query_end_rfc = query_end.strftime('%Y-%m-%dT%H:%M:%SZ') @@ -542,7 +562,7 @@ def _query_influxdb_with_load_status( for key, value in filters.items(): tag_filters += f'\n |> filter(fn: (r) => r["{key}"] == "{value}")' - # 查询温度数据(不需要load_status筛选,因为已经基于有效时间点查询) + # 查询温度数据:查询到目标时间点为止,取最后一条(最接近目标时间点的瞬时值) flux = f''' from(bucket: "{influx_bucket}") |> range(start: {query_start_rfc}, stop: {query_end_rfc})