
档案库房与机房、车间最大的区别在于:档案装具本身就是环境扰动源。密集架合拢时,架体间的空气几乎不流通,形成大量"微环境"。同一间库房内,密集架内部与通道、上层与下层、角落与中心,温湿度可能存在显著差异。
后果 | 机理 | 影响程度 |
|---|---|---|
局部霉变 | 角落湿度偏高(>65%RH),霉菌在纸质档案上滋生 | 不可逆损伤 |
纸张脆化 | 局部温度偏高(>25℃)加速纸张酸化 | 长期累积性损伤 |
胶片粘连 | 相对湿度低于30%时,明胶层失水变脆 | 永久性损坏 |
验收/审计不通过 | 标准(如JGJ 25-2010)要求库房温度14~24℃、湿度45~60%RH,且要求"均匀" | 合规风险 |
能耗浪费 | 为了把最差点的环境拉到标准范围内,空调/除湿机满负荷运行,其他区域过冷/过干 | 运行成本高 |
┌─────────────────────────────────────────────────────────────────────┐
│ 库房平面示意图(200㎡,密集架6组×4列) │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 外墙(西晒) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │架A-1│ │架A-2│ │架A-3│ │架A-4│ │架A-5│ │架A-6│ ← 温度高 │ │
│ │ │26.2℃│ │25.8℃│ │25.1℃│ │24.5℃│ │24.0℃│ │23.5℃│ 2~3℃ │ │
│ │ │58% │ │56% │ │53% │ │51% │ │49% │ │48% │ 湿度高 │ │
│ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │
│ │ 通道(0.8m) 通道(0.8m) 通道(0.8m) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │架B-1│ │架B-2│ │架B-3│ │架B-4│ │架B-5│ │架B-6│ │ │
│ │ │25.5℃│ │25.0℃│ │24.3℃│ │23.8℃│ │23.5℃│ │23.2℃│ │ │
│ │ │55% │ │53% │ │50% │ │49% │ │48% │ │47% │ │ │
│ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │
│ │ 通道(0.8m) 通道(0.8m) 通道(0.8m) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │架C-1│ │架C-2│ │架C-3│ │架C-4│ │架C-5│ │架C-6│ ← 温度低 │ │
│ │ │23.0℃│ │22.8℃│ │22.5℃│ │22.3℃│ │22.2℃│ │22.0℃│ 偏低 │ │
│ │ │47% │ │46% │ │46% │ │45% │ │45% │ │45% │ 湿度低 │ │
│ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │
│ │ ↑ 中心通道 ↑ │ │
│ │ 外墙(西晒) 内墙(远离外墙) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ 温度梯度:西墙→东墙 递减约3~4℃ │
│ 湿度梯度:西墙→东墙 递减约10~13%RH │
│ 垂直梯度:上层比下层高0.5~1.5℃(热空气上升) │
└─────────────────────────────────────────────────────────────────────┘关键发现:如果只看"平均值"(24.2℃ / 50.5%RH),库房完全达标。但西墙角落的密集架内部温度26.2℃、湿度58%,已经接近标准上限。这就是均匀性问题的隐蔽性——平均值达标≠每个点位都达标。
均匀性控制的前提是"看得见"——知道哪里偏热、哪里偏湿。传感器部署需要覆盖以下维度:
维度 | 部署要点 | 目的 |
|---|---|---|
水平方向 | 外墙附近、内墙附近、中心通道 | 捕捉外墙传热导致的梯度 |
垂直方向 | 距地面0.5m(下层)、1.5m(中层)、2.5m(上层) | 捕捉热空气上升导致的分层 |
密集架内部 | 每列密集架至少1个传感器(架体中部) | 捕捉密集架内微环境 |
回风/送风 | 空调回风口、送风口附近 | 评估空调效果 |
室外对照 | 库房外墙上(遮阳、通风) | 提供室外基准,用于焓值计算 |
┌─────────────────────────────────────────────────────────────────────┐
│ 传感器部署三维示意图 │
│ │
│ 侧视图(垂直方向): │
│ │
│ 3.0m ───────────────────── 天花板 │
│ ┌───┐ │
│ 2.5m ─┤ S3├──── 上层传感器(距地2.5m) │
│ │ │ (热空气聚集区) │
│ │ │ │
│ 1.5m ─┤ S2├──── 中层传感器(距地1.5m,人体/档案主要区域) │
│ │ │ │
│ │ │ │
│ 0.5m ─┤ S1├──── 下层传感器(距地0.5m,地面冷辐射区) │
│ └───┘ │
│ 0.0m ───────────────────── 地面 │
│ │
│ 俯视图(水平方向): │
│ │
│ 西墙 ────┬───┬───┬───┬───┬───┬──── 东墙 │
│ │S1 │S2 │S3 │S4 │S5 │S6 │ │
│ │ │ │ │ │ │ │ ← 每列密集架内1个传感器 │
│ ├───┼───┼───┼───┼───┼───┤ │
│ │ │ │ │ │ │ │ │
│ ├───┼───┼───┼───┼───┼───┤ │
│ │S7 │S8 │S9 │S10│S11│S12│ │
│ └───┴───┴───┴───┴───┴───┘ │
│ │
│ 总计:每区12个传感器(6列×2层密集架)+ 2个通道 + 1个室外 = 15个 │
└─────────────────────────────────────────────────────────────────────┘参数 | 设定值 | 说明 |
|---|---|---|
采集间隔 | 30秒 | 密集架内微环境变化慢,30秒足够 |
数据对齐窗口 | ±2秒 | 多传感器数据时间戳对齐,便于空间分析 |
异常值过滤 | 3σ准则 | 剔除明显异常(传感器故障、通信错误) |
数据平滑 | 移动平均(5点) | 消除瞬时波动,反映真实趋势 |
# data_acquisition.py
import time
import numpy as np
from collections import deque
from typing import Dict, List, Optional
from dataclasses import dataclass
@dataclass
class SensorReading:
sensor_id: str
zone_id: str
position: str # e.g., "A-1-upper", "A-1-lower"
temperature: float
humidity: float
timestamp: float
is_valid: bool = True
class MultiSensorAcquisition:
"""多传感器数据采集与预处理"""
def __init__(self, num_sensors: int, acquisition_interval: float = 30.0):
self.num_sensors = num_sensors
self.acquisition_interval = acquisition_interval
self.sensor_readings: Dict[str, deque] = {} # sensor_id -> deque of readings
self.sensor_configs: Dict[str, dict] = {} # sensor_id -> config
self.lock = threading.RLock()
def register_sensor(self, sensor_id: str, zone_id: str, position: str,
max_history: int = 100):
"""注册传感器"""
with self.lock:
self.sensor_readings[sensor_id] = deque(maxlen=max_history)
self.sensor_configs[sensor_id] = {
'zone_id': zone_id,
'position': position
}
def add_reading(self, sensor_id: str, temperature: float, humidity: float):
"""添加传感器读数"""
if sensor_id not in self.sensor_readings:
return
# 异常值检测(3σ准则)
is_valid = self._validate_reading(sensor_id, temperature, humidity)
reading = SensorReading(
sensor_id=sensor_id,
zone_id=self.sensor_configs[sensor_id]['zone_id'],
position=self.sensor_configs[sensor_id]['position'],
temperature=temperature,
humidity=humidity,
timestamp=time.time(),
is_valid=is_valid
)
with self.lock:
self.sensor_readings[sensor_id].append(reading)
def _validate_reading(self, sensor_id: str, temperature: float,
humidity: float) -> bool:
"""验证读数是否有效"""
# 范围检查
if not (10.0 <= temperature <= 40.0):
return False
if not (10.0 <= humidity <= 90.0):
return False
# 3σ准则检查
readings = self.sensor_readings[sensor_id]
if len(readings) < 10:
return True # 数据不足,跳过统计检验
temps = [r.temperature for r in readings if r.is_valid]
humis = [r.humidity for r in readings if r.is_valid]
if len(temps) < 10:
return True
temp_mean = np.mean(temps)
temp_std = np.std(temps)
humi_mean = np.mean(humis)
humi_std = np.std(humis)
# 如果偏差超过3σ,认为是异常值
if abs(temperature - temp_mean) > 3 * temp_std:
return False
if abs(humidity - humi_mean) > 3 * humi_std:
return False
return True
def get_latest_readings(self, zone_id: Optional[str] = None) -> Dict[str, SensorReading]:
"""获取最新读数"""
with self.lock:
result = {}
for sensor_id, readings in self.sensor_readings.items():
if readings and (zone_id is None or
self.sensor_configs[sensor_id]['zone_id'] == zone_id):
result[sensor_id] = readings[-1]
return result
def get_smoothed_readings(self, sensor_id: str, window: int = 5) -> Optional[dict]:
"""获取平滑后的读数(移动平均)"""
with self.lock:
if sensor_id not in self.sensor_readings:
return None
readings = list(self.sensor_readings[sensor_id])
if len(readings) < window:
return None
# 取最近window个有效读数
valid_readings = [r for r in readings[-window:] if r.is_valid]
if len(valid_readings) < window // 2:
return None
return {
'sensor_id': sensor_id,
'temperature': np.mean([r.temperature for r in valid_readings]),
'humidity': np.mean([r.humidity for r in valid_readings]),
'sample_count': len(valid_readings)
}指标 | 定义 | 标准 |
|---|---|---|
最大值 | 所有传感器读数的最大值 | 温度≤24℃(纸质档案) |
最小值 | 所有传感器读数的最小值 | 温度≥14℃ |
极差(Range) | 最大值 - 最小值 | 温度≤3℃(推荐值) |
标准差(σ) | 读数的标准差 | 温度≤1℃(推荐值) |
变异系数(CV) | σ / 均值 | 温度≤5%(推荐值) |
达标率 | 读数在标准范围内的传感器比例 | ≥95% |
# uniformity_evaluator.py
import numpy as np
from typing import Dict, List
class UniformityEvaluator:
"""均匀性评估器"""
def __init__(self, temp_standard: tuple = (14.0, 24.0),
humi_standard: tuple = (45.0, 60.0)):
self.temp_standard = temp_standard # (min, max)
self.humi_standard = humi_standard # (min, max)
def evaluate(self, readings: Dict[str, SensorReading]) -> dict:
"""评估当前均匀性状态"""
valid_readings = [r for r in readings.values() if r.is_valid]
if not valid_readings:
return {"status": "no_data"}
temperatures = [r.temperature for r in valid_readings]
humidities = [r.humidity for r in valid_readings]
temp_min = min(temperatures)
temp_max = max(temperatures)
temp_mean = np.mean(temperatures)
temp_std = np.std(temperatures)
humi_min = min(humidities)
humi_max = max(humidities)
humi_mean = np.mean(humidities)
humi_std = np.std(humidities)
# 达标率
temp_compliant = sum(1 for t in temperatures
if self.temp_standard[0] <= t <= self.temp_standard[1])
humi_compliant = sum(1 for h in humidities
if self.humi_standard[0] <= h <= self.humi_standard[1])
temp_compliance_rate = temp_compliant / len(temperatures) * 100
humi_compliance_rate = humi_compliant / len(humidities) * 100
# 综合评分(0~100)
score = self._calculate_score(
temp_range=temp_max - temp_min,
temp_cv=temp_std / temp_mean if temp_mean > 0 else 0,
humi_range=humi_max - humi_min,
humi_cv=humi_std / humi_mean if humi_mean > 0 else 0,
temp_compliance=temp_compliance_rate,
humi_compliance=humi_compliance_rate
)
return {
"status": "ok",
"temperature": {
"min": temp_min,
"max": temp_max,
"mean": temp_mean,
"std": temp_std,
"range": temp_max - temp_min,
"cv": temp_std / temp_mean if temp_mean > 0 else 0,
"compliance_rate": temp_compliance_rate,
"compliant": self.temp_standard[0] <= temp_mean <= self.temp_standard[1]
},
"humidity": {
"min": humi_min,
"max": humi_max,
"mean": humi_mean,
"std": humi_std,
"range": humi_max - humi_min,
"cv": humi_std / humi_mean if humi_mean > 0 else 0,
"compliance_rate": humi_compliance_rate,
"compliant": self.humi_standard[0] <= humi_mean <= self.humi_standard[1]
},
"score": score,
"hotspots": self._identify_hotspots(valid_readings),
"coldspots": self._identify_coldspots(valid_readings)
}
def _calculate_score(self, temp_range, temp_cv, humi_range, humi_cv,
temp_compliance, humi_compliance) -> float:
"""计算综合评分"""
# 各指标权重
weights = {
'temp_range': 0.15, # 温度极差
'temp_cv': 0.10, # 温度变异系数
'humi_range': 0.15, # 湿度极差
'humi_cv': 0.10, # 湿度变异系数
'temp_compliance': 0.25, # 温度达标率
'humi_compliance': 0.25 # 湿度达标率
}
# 各指标得分(0~100)
temp_range_score = max(0, 100 - (temp_range - 2.0) * 20) # 极差2℃以内满分
temp_cv_score = max(0, 100 - temp_cv * 500) # CV 5%以内满分
humi_range_score = max(0, 100 - (humi_range - 10.0) * 5) # 极差10%以内满分
humi_cv_score = max(0, 100 - humi_cv * 500) # CV 5%以内满分
score = (
temp_range_score * weights['temp_range'] +
temp_cv_score * weights['temp_cv'] +
humi_range_score * weights['humi_range'] +
humi_cv_score * weights['humi_cv'] +
temp_compliance * weights['temp_compliance'] +
humi_compliance * weights['humi_compliance']
)
return round(score, 1)
def _identify_hotspots(self, readings: List[SensorReading]) -> List[dict]:
"""识别热点(温度或湿度偏高的位置)"""
hotspots = []
for r in readings:
is_hot = r.temperature > self.temp_standard[1]
is_humid = r.humidity > self.humi_standard[1]
if is_hot or is_humid:
hotspots.append({
'sensor_id': r.sensor_id,
'position': r.position,
'temperature': r.temperature,
'humidity': r.humidity,
'type': 'hot' if is_hot else 'humid'
})
return hotspots
def _identify_coldspots(self, readings: List[SensorReading]) -> List[dict]:
"""识别冷点(温度或湿度偏低的位置)"""
coldspots = []
for r in readings:
is_cold = r.temperature < self.temp_standard[0]
is_dry = r.humidity < self.humi_standard[0]
if is_cold or is_dry:
coldspots.append({
'sensor_id': r.sensor_id,
'position': r.position,
'temperature': r.temperature,
'humidity': r.humidity,
'type': 'cold' if is_cold else 'dry'
})
return coldspots基于传感器分布和物理隔断,将库房划分为若干调控区域:
┌─────────────────────────────────────────────────────────────────────┐
│ 库房分区示意图 │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 外墙(西晒) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 区域A │ │ 区域B │ │ 区域C │ │ │
│ │ │ (西墙高温区) │ │ (中间过渡区) │ │ (内墙低温区) │ │ │
│ │ │ 传感器: │ │ 传感器: │ │ 传感器: │ │ │
│ │ │ S1~S4 │ │ S5~S8 │ │ S9~S12 │ │ │
│ │ │ 调控设备: │ │ 调控设备: │ │ 调控设备: │ │ │
│ │ │ - 空调风口1 │ │ - 空调风口2 │ │ - 空调风口3 │ │ │
│ │ │ - 除湿机1 │ │ - 新风机 │ │ - 加湿机1 │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ 分区原则: │
│ 1. 每个区域包含4~6个传感器(覆盖水平+垂直方向) │
│ 2. 区域边界与物理隔断(墙、门)对齐 │
│ 3. 每个区域有独立的调控设备(或可控的风阀/风口) │
│ 4. 区域之间允许有限的热交换(通过通道气流) │
└─────────────────────────────────────────────────────────────────────┘# zone_controller.py
import time
from typing import Dict, List, Optional
from dataclasses import dataclass
@dataclass
class ZoneConfig:
"""区域配置"""
zone_id: str
sensors: List[str] # 该区域的传感器列表
devices: List[str] # 该区域可调用的设备
temp_setpoint: float = 22.0
temp_deadband: float = 0.5
humi_setpoint: float = 50.0
humi_deadband: float = 5.0
priority: int = 1 # 调控优先级(数字越小越高)
@dataclass
class ZoneStatus:
"""区域状态"""
zone_id: str
temp_current: float = 0.0
humi_current: float = 0.0
temp_deviation: float = 0.0 # 与设定值的偏差
humi_deviation: float = 0.0
uniformity_score: float = 0.0
active_devices: List[str] = None
last_adjustment: float = 0.0
class ZoneController:
"""分区调控控制器"""
def __init__(self, evaluator: UniformityEvaluator):
self.zones: Dict[str, ZoneConfig] = {}
self.zone_status: Dict[str, ZoneStatus] = {}
self.evaluator = evaluator
self.lock = threading.RLock()
def register_zone(self, config: ZoneConfig):
"""注册区域"""
self.zones[config.zone_id] = config
self.zone_status[config.zone_id] = ZoneStatus(zone_id=config.zone_id)
def update_zone_status(self, sensor_readings: Dict[str, SensorReading]):
"""更新所有区域的状态"""
with self.lock:
for zone_id, zone_config in self.zones.items():
# 获取该区域的所有传感器读数
zone_readings = {
sid: r for sid, r in sensor_readings.items()
if sid in zone_config.sensors and r.is_valid
}
if not zone_readings:
continue
# 计算区域平均值
temps = [r.temperature for r in zone_readings.values()]
humis = [r.humidity for r in zone_readings.values()]
status = self.zone_status[zone_id]
status.temp_current = sum(temps) / len(temps)
status.humi_current = sum(humis) / len(humis)
status.temp_deviation = status.temp_current - zone_config.temp_setpoint
status.humi_deviation = status.humi_current - zone_config.humi_setpoint
# 计算均匀性评分
eval_result = self.evaluator.evaluate(zone_readings)
status.uniformity_score = eval_result.get('score', 0)
def decide_actions(self) -> Dict[str, dict]:
"""决策各区域的调控动作"""
actions = {}
with self.lock:
# 按优先级排序
sorted_zones = sorted(
self.zones.items(),
key=lambda x: x[1].priority
)
for zone_id, zone_config in sorted_zones:
status = self.zone_status[zone_id]
# 检查是否需要调控
temp_upper = zone_config.temp_setpoint + zone_config.temp_deadband
temp_lower = zone_config.temp_setpoint - zone_config.temp_deadband
humi_upper = zone_config.humi_setpoint + zone_config.humi_deadband
humi_lower = zone_config.humi_setpoint - zone_config.humi_deadband
action = {
'zone_id': zone_id,
'temp_action': 'none',
'humi_action': 'none',
'reason': '',
'devices': []
}
# 温度调控决策
if status.temp_current > temp_upper:
action['temp_action'] = 'cool'
action['reason'] += f'温度偏高({status.temp_current:.1f}℃) '
elif status.temp_current < temp_lower:
action['temp_action'] = 'heat'
action['reason'] += f'温度偏低({status.temp_current:.1f}℃) '
# 湿度调控决策
if status.humi_current > humi_upper:
action['humi_action'] = 'dehumidify'
action['reason'] += f'湿度偏高({status.humi_current:.1f}%RH) '
elif status.humi_current < humi_lower:
action['humi_action'] = 'humidify'
action['reason'] += f'湿度偏低({status.humi_current:.1f}%RH) '
# 均匀性检查
if status.uniformity_score < 80:
action['reason'] += f'均匀性差({status.uniformity_score:.1f}分) '
# 选择设备
if action['temp_action'] != 'none' or action['humi_action'] != 'none':
action['devices'] = self._select_devices(zone_config, action)
actions[zone_id] = action
return actions
def _select_devices(self, zone_config: ZoneConfig,
action: dict) -> List[str]:
"""选择合适的设备"""
selected = []
for device in zone_config.devices:
# 根据动作类型选择设备
if action['temp_action'] == 'cool' and 'ac' in device.lower():
selected.append(device)
elif action['temp_action'] == 'heat' and 'heater' in device.lower():
selected.append(device)
elif action['humi_action'] == 'dehumidify' and 'dehumidifier' in device.lower():
selected.append(device)
elif action['humi_action'] == 'humidify' and 'humidifier' in device.lower():
selected.append(device)
return selected传统PID控制是"事后调节"——等温度超了才动作。对于档案库房这种大惯性系统,事后调节往往来不及。我们采用基于空间梯度的预测性调控:
# predictive_control.py
import time
import numpy as np
from typing import Dict, List
class PredictiveController:
"""基于梯度的预测性控制器"""
def __init__(self, zone_controller: ZoneController):
self.zone_controller = zone_controller
self.history: Dict[str, List[dict]] = {} # zone_id -> history
self.prediction_horizon = 1800 # 预测时间窗口(秒),30分钟
def record_state(self, zone_id: str, timestamp: float,
temperature: float, humidity: float):
"""记录状态历史"""
if zone_id not in self.history:
self.history[zone_id] = []
self.history[zone_id].append({
'timestamp': timestamp,
'temperature': temperature,
'humidity': humidity
})
# 只保留最近2小时的数据
cutoff = timestamp - 7200
self.history[zone_id] = [
s for s in self.history[zone_id] if s['timestamp'] > cutoff
]
def predict_trend(self, zone_id: str) -> dict:
"""预测趋势"""
if zone_id not in self.history or len(self.history[zone_id]) < 10:
return {"status": "insufficient_data"}
history = self.history[zone_id]
timestamps = np.array([s['timestamp'] for s in history])
temperatures = np.array([s['temperature'] for s in history])
humidities = np.array([s['humidity'] for s in history])
# 线性拟合
temp_coeffs = np.polyfit(timestamps, temperatures, 1)
humi_coeffs = np.polyfit(timestamps, humidities, 1)
temp_slope = temp_coeffs[0] # 温度变化率(℃/秒)
humi_slope = humi_coeffs[0] # 湿度变化率(%RH/秒)
# 预测未来30分钟的值
current_time = timestamps[-1]
future_time = current_time + self.prediction_horizon
predicted_temp = np.polyval(temp_coeffs, future_time)
predicted_humi = np.polyval(humi_coeffs, future_time)
return {
"status": "ok",
"temp_slope": temp_slope * 3600, # 转换为℃/小时
"humi_slope": humi_slope * 3600, # 转换为%RH/小时
"predicted_temp": predicted_temp,
"predicted_humi": predicted_humi,
"current_temp": temperatures[-1],
"current_humi": humidities[-1],
"time_horizon": self.prediction_horizon / 60 # 分钟
}
def should_preempt(self, zone_id: str, zone_config: ZoneConfig) -> dict:
"""判断是否需要提前干预"""
prediction = self.predict_trend(zone_id)
if prediction["status"] != "ok":
return {"preempt": False}
# 计算预测值是否会超出范围
temp_upper = zone_config.temp_setpoint + zone_config.temp_deadband
temp_lower = zone_config.temp_setpoint - zone_config.temp_deadband
humi_upper = zone_config.humi_setpoint + zone_config.humi_deadband
humi_lower = zone_config.humi_setpoint - zone_config.humi_deadband
preempt_temp = None
preempt_humi = None
if prediction["predicted_temp"] > temp_upper:
preempt_temp = "cool"
elif prediction["predicted_temp"] < temp_lower:
preempt_temp = "heat"
if prediction["predicted_humi"] > humi_upper:
preempt_humi = "dehumidify"
elif prediction["predicted_humi"] < humi_lower:
preempt_humi = "humidify"
return {
"preempt": preempt_temp is not None or preempt_humi is not None,
"temp_action": preempt_temp,
"humi_action": preempt_humi,
"reason": f"预测{int(prediction['time_horizon'])}分钟后超出范围",
"predicted_temp": prediction["predicted_temp"],
"predicted_humi": prediction["predicted_humi"],
"temp_slope": prediction["temp_slope"],
"humi_slope": prediction["humi_slope"]
}┌─────────────────────────────────────────────────────────────────────┐
│ 空调风口分区控制示意图 │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 空调主机(2台,一用一备) │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 空调A │ │ 空调B │ │ │
│ │ │ (主用) │ │ (备用) │ │ │
│ │ └──────┬──────┘ └─────────────┘ │ │
│ └─────────┼──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────┼──────────────────────────────────────────────────────┐ │
│ │ 送风总管 │ │ │
│ └─────────┼──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────┼──────────────────────────────────────────────────────┐ │
│ │ 电动风阀 │ │ │
│ │ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │ │
│ │ │ 风阀A1 │ │ 风阀B1 │ │ 风阀C1 │ │ │
│ │ │ (区域A) │ │ (区域B) │ │ (区域C) │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └─────────┼─────────────────┼─────────────────┼────────────────┘ │
│ │ │ │ │
│ ┌─────────▼────────┐ ┌─────▼──────┐ ┌───────▼────────┐ │ │
│ │ 区域A送风口 │ │ 区域B送风口│ │ 区域C送风口 │ │ │
│ │ (可调风量) │ │ (可调风量) │ │ (可调风量) │ │ │
│ └──────────────────┘ └────────────┘ └────────────────┘ │ │
│ │
│ 控制策略: │
│ - 根据各区域温度偏差,调节对应风阀开度和送风口风量 │
│ - 温度偏高的区域(如区域A)增大送风量 │
│ - 温度偏低的区域(如区域C)减小送风量 │
│ - 保持总送风量恒定(空调主机负荷稳定) │
└─────────────────────────────────────────────────────────────────────┘# damper_control.py
import time
from typing import Dict, List
class DamperController:
"""风阀联动控制器"""
def __init__(self, zone_controller: ZoneController):
self.zone_controller = zone_controller
self.damper_positions: Dict[str, float] = {} # damper_id -> position (0~100%)
self.lock = threading.RLock()
# PID参数
self.kp = 2.0 # 比例系数
self.ki = 0.1 # 积分系数
self.kd = 0.5 # 微分系数
# 积分项
self.integral = 0.0
self.last_error = 0.0
self.last_time = time.time()
def register_damper(self, damper_id: str, zone_id: str):
"""注册风阀"""
self.damper_positions[damper_id] = 50.0 # 默认50%
def update_damper_positions(self):
"""根据各区域状态更新风阀位置"""
with self.lock:
for zone_id, zone_config in self.zone_controller.zones.items():
status = self.zone_controller.zone_status[zone_id]
# 计算温度偏差
error = status.temp_deviation # 正值表示偏高,负值表示偏低
# PID计算
current_time = time.time()
dt = current_time - self.last_time
if dt <= 0:
dt = 1.0
# 比例项
p_term = self.kp * error
# 积分项
self.integral += error * dt
# 积分限幅
self.integral = max(-100, min(100, self.integral))
i_term = self.ki * self.integral
# 微分项
d_term = self.kd * (error - self.last_error) / dt
# PID输出
output = p_term + i_term + d_term
# 更新风阀位置
for damper_id in self.damper_positions:
if damper_id.startswith(zone_id):
current_pos = self.damper_positions[damper_id]
new_pos = current_pos + output
# 限幅
new_pos = max(0, min(100, new_pos))
self.damper_positions[damper_id] = new_pos
self.last_error = error
self.last_time = current_time
def get_damper_positions(self) -> Dict[str, float]:
"""获取当前风阀位置"""
with self.lock:
return self.damper_positions.copy()指标 | 调控前 | 调控后 | 改善幅度 |
|---|---|---|---|
温度极差 | 4.2℃ | 1.8℃ | ↓57% |
温度标准差 | 1.3℃ | 0.5℃ | ↓62% |
湿度极差 | 13%RH | 5%RH | ↓62% |
湿度标准差 | 3.8%RH | 1.5%RH | ↓61% |
达标率(温度) | 78% | 98% | ↑20% |
达标率(湿度) | 82% | 99% | ↑17% |
均匀性评分 | 65分 | 92分 | ↑27分 |
指标 | 传统统一调控 | 分区调控 | 变化 |
|---|---|---|---|
空调日均运行时间 | 18小时 | 12小时 | ↓33% |
除湿机日均运行时间 | 8小时 | 5小时 | ↓38% |
加湿机日均运行时间 | 2小时 | 1.5小时 | ↓25% |
日均耗电量 | 85 kWh | 62 kWh | ↓27% |
月度电费(估算) | ¥3,400 | ¥2,480 | ↓27% |
关键词:档案库房,温湿度均匀性,多传感器采集,分区调控,空间梯度,预测性控制,风阀联动,均匀性评估,设备协同,气流组织
标签:#档案库房 #温湿度均匀性 #多传感器采集 #分区调控 #空间梯度 #预测性控制 #风阀联动 #均匀性评估 #设备协同 #气流组织
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。