
船舶淡水柜自动补水控制仿真上下限液位启停电磁阀在船上淡水比油还金贵。淡水柜见底了没人知道水泵空转烧了全船断水——这种事我见过不止一次。一个可靠的上下限补水逻辑就是淡水系统的第一道保险。—— 参考哈尔滨工程大学《工业过程控制》第 4 章液位控制系统、第 8 章过程控制系统的安全保护一、实际应用场景描述在船舶、海上平台、远洋渔船、海军舰艇中淡水柜FW Tank是船员日常用水、锅炉补水的核心储水单元。由于船舶摇晃、用水波动大、维护人员有限淡水柜的自动补水控制直接关系全船生活质量甚至航行安全┌──────────────────────────────────────────────────────┐│ 船舶淡水柜自动补水系统架构 ││ ││ [淡水柜 FW-TK-01] ││ ╔══════════════════╗ ││ ║ ┌───┐ ║ ← 进水管(补水泵出口) ││ ║ │▓▓▓│ 水位 ║ ││ ║ │▓▓▓│ ─────────── ║ ← 液位变送器 LT-101 ││ ║ │ │ ║ ││ ╚══════════════════╝ ││ ││ ││ │└→ 出水管 → 全船用水(厨房/浴室/锅炉) ││ │ ││ [补水电磁阀 XV-101] ─── 补水泵 P-101 ││ │ ││ ▼ ││ [海水淡化装置 / 造水机] ││ ││ 控制逻辑: ││ • 液位 ≤ 30cm → 开阀 启泵(补水) ││ • 液位 ≥ 80cm → 关阀 停泵(防溢流) ││ • 液位在 30~80cm → 保持当前状态(滞环防抖) ││ • 液位 ≤ 5cm → 低低联锁(紧急补水报警) ││ • 液位 ≥ 95cm → 高高联锁(紧急关阀停泵) │└──────────────────────────────────────────────────────┘典型应用工况工况 液位变化 控制动作正常用水 缓慢下降5 L/min 液位降至 30cm → 开阀启泵洗澡高峰 快速下降12 L/min 频繁补水泵运行率升高夜间低耗 几乎不降 泵长时间停机节能造水机故障 只出不进 液位持续下降 → 低低报警补水泵故障 阀开但无水 液位下降 → 低低联锁信号断线 无法判断 保持当前状态安全位置二、引入痛点2.1 现场真实困境场景 现场反馈 根因水漫机房 半夜淡水柜溢了整个机舱都是水 无高高联锁或联锁失效泵烧了 液位变送器坏了泵空转一晚上 无低低联锁保护频繁启停 泵一天启停上百次半年就换了 无滞环或滞环过窄半夜没水 早上起来没水洗脸厨师罢工 补水逻辑未考虑用水高峰报警没人管 报警响了三天没人看 无分级报警无远程通知标准混乱 新船 80cm 关阀老船 70cm 关阀 参数硬编码缺乏统一管理2.2 核心矛盾淡水柜补水的核心矛盾是补水及时性与泵寿命之间的平衡。 补水太积极——泵频繁启停寿命骤降补水太迟钝——用水高峰供不上全船断水。必须用带滞环的两位式控制来兼顾。2.3 三种实现方案对比方案 核心思想 优势 劣势浮球开关 机械式上下限 简单可靠、无需供电 精度差、易卡涩、不可远程PLC 两位控制 编程实现上下限 灵活、可加滞环 需 PLC 编程知识本程序方案 Python 仿真 OOP 灵活验证、便于教学、易扩展 需额外硬件部署三、核心逻辑讲解3.1 理论基础两位式控制On-Off Control参考哈工程《工业过程控制》第 4 章液位控制系统两位式控制是最简单的控制方式——执行机构只有全开和全关两种状态u(t) \begin{cases} 1 \text{ (开阀/启泵)} \text{当 } H \leq H_{low} \\ 0 \text{ (关阀/停泵)} \text{当 } H \geq H_{high} \end{cases}必然存在的稳态振荡由于执行机构只有两个极端位置液位必然在 H_{low} 和 H_{high} 之间周期性波动——这不是故障而是两位式控制的固有特性。3.2 滞环控制Hysteresis滞环控制原理:H_high 80cm ─── 关阀停泵││ 滞环区 (75~80cm)│ → 保持当前状态, 防抖│H_low 30cm ─── 开阀启泵|← 滞环宽度 50cm →|为什么要滞环• 没有滞环: 液位在 80cm 附近反复横跳 → 泵一天启停几百次• 有滞环: 液位在 30~80cm 之间自然波动 → 泵每天只启停几次3.3 液位动态模型参考哈工程《工业过程控制》第 2 章过程动态特性\frac{dH}{dt} \frac{Q_{in} - Q_{out}}{A}其中- H 液位高度cm- Q_{in} 进水流量cm³/s- Q_{out} 出水流量 用水量cm³/s- A 淡水柜横截面积cm²离散化欧拉法H[k1] H[k] \frac{(Q_{in} - Q_{out}) \cdot \Delta t}{A}3.4 多级保护优先级控制优先级从高到低:1. 【最高】信号失效 → 保持当前状态(安全位置)不知道液位多少, 就别乱动2. 【高】 高高联锁(≥95cm) → 紧急关阀停泵要溢出来了, 什么都别管, 先关!3. 【高】 低低联锁(≤5cm) → 紧急开阀补水要见底了, 开阀! 泵坏了也开!4. 【中】 高报警(≥90cm) → 报警 准备关阀5. 【中】 低报警(≤15cm) → 报警 开阀补水6. 【低】 正常控制区 → 带滞环的两位式控制四、代码讲解面向对象设计4.1 类结构总览类名 职责 设计模式ValveState 电磁阀状态枚举 枚举类型PumpState 补水泵状态枚举 枚举类型TankLevelStatus 液位状态枚举正常/报警/联锁 枚举类型TankConfig 淡水柜与补水参数配置 值对象TankState 淡水柜状态快照 值对象LevelTransmitter 液位变送器模拟 单一职责WaterSupplyController 补水控制逻辑核心 策略模式WaterTankModel 淡水柜液位动态模型 单一职责MarineWaterSystem 船舶淡水系统聚合根 外观模式4.2 完整源代码单文件约 680 行直接复制下方代码保存为marine_water_tank_control.py 即可运行仅需 Python 3.8 标准库无需安装任何第三方包。detailssummary/summary船舶淡水柜自动补水控制仿真程序参考: 哈尔滨工程大学《工业过程控制》第4章液位控制系统、第5章PID控制作者: 工业控制与上位机开发工程师适用: CSDN技术博客完整发布版(单文件, ~680行)功能:- 模拟船舶淡水柜液位动态- 上下限液位自动启停补水电磁阀与补水泵- 支持滞环防抖、故障模拟、补水泵模型- 实时数据记录与趋势分析import enumimport dataclassesimport loggingimport timeimport mathimport randomfrom typing import List, Optional, Tuplefrom dataclasses import dataclass, fieldfrom collections import deque# # 1. 基础枚举与值对象# class ValveState(enum.Enum):电磁阀状态OPEN 开启CLOSED 关闭FAULT 故障class PumpState(enum.Enum):补水泵状态RUNNING 运行STOPPED 停止FAULT 故障class TankLevelStatus(enum.Enum):液位状态NORMAL 正常HIGH_ALARM 高报警LOW_ALARM 低报警HIGH_HIGH_TRIP 高高联锁LOW_LOW_TRIP 低低联锁dataclass(frozenTrue)class TankConfig:淡水柜与补水控制配置 —— 值对象不可变参考哈工程《工业过程控制》第4章液位控制系统:- 船舶淡水柜通常为常压容器- 补水控制采用两位式开关控制- 需设置上下限与滞环防止频繁启停tank_id: str FW-101max_level: float 100.0min_level: float 0.0normal_high: float 80.0normal_low: float 30.0hysteresis: float 5.0alarm_high: float 90.0alarm_low: float 15.0trip_high: float 95.0trip_low: float 5.0# 补水泵参数pump_flow_rate: float 20.0 # L/minpump_start_delay: float 2.0 # 启动延迟(s)pump_stop_delay: float 1.0 # 停止延迟(s)# 用水负载consumption_rate: float 5.0 # 正常用水量(L/min)consumption_variation: float 2.0 # 用水量波动(L/min)# 仿真参数tank_cross_area: float 50.0 # 横截面积(cm²)sample_interval: float 1.0 # 采样周期(s)def __post_init__(self):if self.normal_low self.normal_high:raise ValueError(正常低液位必须小于正常高液位)if self.hysteresis 0:raise ValueError(滞环宽度必须大于0)dataclassclass TankState:淡水柜状态快照 —— 值对象timestamp: floatlevel: floatlevel_status: TankLevelStatusvalve_state: ValveStatepump_state: PumpStateflow_in: floatflow_out: floatpump_running: boolvalve_open: boolevent: str # # 2. 液位变送器模拟单一职责# class LevelTransmitter:液位变送器模拟模拟:- 4-20mA信号输出- 测量噪声- 信号断线/超量程故障def __init__(self, config: TankConfig, noise_std: float 0.3,fault_prob: float 0.0):self.config configself.noise_std noise_stdself.fault_prob fault_probself._signal_4ma 4.0self._signal_20ma 20.0logging.info(f[液位变送器] 初始化, 量程: 0-{config.max_level}cm)def read(self, real_level: float, timestamp: float) - Tuple[float, bool]:读取液位值, 返回: (液位值cm, 信号是否有效)# 模拟信号故障返回无效值if random.random() self.fault_prob:logging.warning(f[液位变送器] 信号故障! t{timestamp:.0f}s)return -999.0, False# 添加测量噪声noise random.gauss(0, self.noise_std)measured real_level noisemeasured max(-5.0, min(self.config.max_level 5, measured))return measured, Truedef to_4_20ma(self, level: float) - float:液位转4-20mA信号ratio level / self.config.max_levelreturn self._signal_4ma ratio * (self._signal_20ma - self._signal_4ma)# # 3. 补水控制逻辑策略模式# class WaterSupplyController:淡水柜补水控制逻辑核心算法: 带滞环的两位式控制参考哈工程《工业过程控制》§4.2 液位控制方案控制规则:1. 液位 ≤ 正常低液位 → 开启补水电磁阀 启动补水泵2. 液位 ≥ 正常高液位 → 关闭补水电磁阀 停止补水泵3. 液位在滞环区内 → 保持当前状态防抖4. 液位 ≥ 高高联锁 → 紧急关闭双重保护5. 液位 ≤ 低低联锁 → 紧急报警缺水危险def __init__(self, config: TankConfig):self.config configself._valve_open: bool Falseself._pump_running: bool Falseself._pump_delay_timer: float 0.0self._pending_pump_state: bool Falselogging.info(f[补水控制器] 初始化)logging.info(f 开阀液位: ≤ {config.normal_low}cm)logging.info(f 关阀液位: ≥ {config.normal_high}cm)logging.info(f 滞环宽度: {config.hysteresis}cm)def evaluate(self, level: float, signal_valid: bool,dt: float) - Tuple[ValveState, PumpState, str]:执行一次控制逻辑评估cfg self.config# 优先级1: 信号失效 → 保持当前状态if not signal_valid:reason 液位信号失效, 保持当前状态(安全位置)valve_state (ValveState.OPEN if self._valve_openelse ValveState.CLOSED)pump_state (PumpState.RUNNING if self._pump_runningelse PumpState.STOPPED)return valve_state, pump_state, reason# 优先级2: 高高联锁(紧急关阀)if level cfg.trip_high:if self._valve_open:self._valve_open Falseself._pump_running Falsereason f高高联锁触发({level:.1f}cm≥{cfg.trip_high}cm), 紧急关阀停泵else:reason f高高联锁保持({level:.1f}cm≥{cfg.trip_high}cm)return ValveState.CLOSED, PumpState.STOPPED, reason# 优先级3: 低低联锁(紧急补水)if level cfg.trip_low:reason f低低联锁触发({level:.1f}cm≤{cfg.trip_low}cm), 缺水危险!if not self._valve_open:self._valve_open Trueself._pending_pump_state Trueself._pump_delay_timer cfg.pump_start_delayreturn ValveState.OPEN, PumpState.STOPPED, reason# 优先级4: 高报警if level cfg.alarm_high:reason f高液位报警({level:.1f}cm≥{cfg.alarm_high}cm)if self._valve_open and level cfg.normal_high:self._valve_open Falseself._pump_running Falsereason f, 已达高限, 关阀停泵return ValveState.CLOSED, PumpState.STOPPED, reason# 优先级5: 低报警if level cfg.alarm_low:reason f低液位报警({level:.1f}cm≤{cfg.alarm_low}cm)if not self._valve_open:self._valve_open Trueself._pending_pump_state Trueself._pump_delay_timer cfg.pump_start_delayreason , 开阀补水return ValveState.OPEN, PumpState.RUNNING, reason# 优先级6: 正常控制区(带滞环)if not self._valve_open:if level cfg.normal_low:self._valve_open Trueself._pending_pump_state Trueself._pump_delay_timer cfg.pump_start_delayreason f液位降至低限({level:.1f}cm≤{cfg.normal_low}cm), 开阀补水return ValveState.OPEN, PumpState.STOPPED, reasonelse:reason f液位正常({level:.1f}cm), 保持关阀return ValveState.CLOSED, PumpState.STOPPED, reasonelse:if level cfg.normal_high:self._valve_open Falseself._pump_running Falsereason f液位升至高限({level:.1f}cm≥{cfg.normal_high}cm), 关阀停泵return ValveState.CLOSED, PumpState.STOPPED, reasonelse:reason f补水进行中({level:.1f}cm{cfg.normal_high}cm)return ValveState.OPEN, PumpState.RUNNING, reasondef update_pump_delay(self, dt: float) - PumpState:更新泵启动延迟计时器if self._pending_pump_state and self._pump_delay_timer 0:self._pump_delay_timer - dtif self._pump_delay_timer 0:self._pump_running Trueself._pending_pump_state Falselogging.info(f[补水泵] 启动延迟结束, 泵已运行)return PumpState.RUNNINGreturn PumpState.STOPPEDreturn PumpState.RUNNING if self._pump_running else PumpState.STOPPEDpropertydef valve_open(self) - bool:return self._valve_openpropertydef pump_running(self) - bool:return self._pump_running# # 4. 淡水柜动态模型单一职责# class WaterTankModel:淡水柜液位动态模型简化模型(参考哈工程§2.3 过程动态特性):dH/dt (Q_in - Q_out) / Adef __init__(self, config: TankConfig):self.config configself._level: float 50.0self._time: float 0.0logging.info(f[淡水柜模型] 初始化, 初始液位: {self._level}cm)def step(self, dt: float, valve_open: bool, pump_running: bool) - float:执行一个仿真步长, 更新液位cfg self.config# 进水流量if valve_open and pump_running:q_in cfg.pump_flow_rateelif valve_open and not pump_running:q_in cfg.pump_flow_rate * 0.1 # 延迟中小流量else:q_in 0.0# 出水流量(模拟用水波动)q_out cfg.consumption_rate random.uniform(-cfg.consumption_variation, cfg.consumption_variation)q_out max(0.0, q_out)# 液位变化率 (L/min → cm/s)dV_dt (q_in - q_out) * 1000.0 / 60.0 # cm³/sdH_dt dV_dt / cfg.tank_cross_area# 欧拉积分self._level dH_dt * dtself._time dtself._level max(cfg.min_level, min(cfg.max_level, self._level))return self._levelpropertydef level(self) - float:return self._levelpropertydef time(self) - float:return self._time# # 5. 船舶淡水系统仿真器聚合根/外观模式# class MarineWaterSystem:船舶淡水柜自动补水系统聚合根对外只暴露:.step() —— 执行一个仿真周期.get_status() —— 获取系统状态.get_history() —— 获取历史数据.run_simulation() —— 运行指定时长仿真def __init__(self, config: TankConfig None,noise_std: float 0.3, fault_prob: float 0.0):self.config config or TankConfig()self.transmitter LevelTransmitter(self.config, noise_std, fault_prob)self.controller WaterSupplyController(self.config)self.tank WaterTankModel(self.config)self._history: List[TankState] []self._step_count: int 0self._last_valid_valve: bool Falseself._last_valid_pump: bool Falselogging.info(f[淡水系统] 初始化完成, 柜号: {self.config.tank_id})def step(self) - TankState:执行一个控制周期dt self.config.sample_interval# 1. 读取液位real_level self.tank.levelmeasured_level, signal_valid self.transmitter.read(real_level, self.tank.time)# 2. 控制逻辑评估valve_state, pump_state, event self.controller.evaluate(measured_level, signal_valid, dt)# 3. 信号失效时保持上一次有效物理状态if not signal_valid:self.controller._valve_open self._last_valid_valveself.controller._pump_running self._last_valid_pumpelse:self._last_valid_valve self.controller.valve_openself._last_valid_pump self.controller.pump_running# 4. 更新泵延迟actual_pump_state self.controller.update_pump_delay(dt)# 5. 液位动态演化new_level self.tank.step(dt, self.controller.valve_open, self.controller.pump_running)# 6. 判断液位状态level_status self._check_level_status(new_level)# 7. 记录状态flow_in self.config.pump_flow_rate if self.controller.valve_open else 0.0state TankState(timestampself.tank.time, levelnew_level,level_statuslevel_status, valve_statevalve_state,pump_stateactual_pump_state, flow_inflow_in,flow_outself.config.consumption_rate,pump_runningself.controller.pump_running,valve_openself.controller.valve_open, eventevent)self._history.append(state)self._step_count 1if self._step_count % 10 0:logging.info(ft{state.timestamp:5.0f}s | f液位{state.level:6.1f}cm | f阀{state.valve_state.value:2s} | f泵{state.pump_state.value:2s} | f{state.event})return statedef _check_level_status(self, level: float) - TankLevelStatus:cfg self.configif level cfg.trip_high: return TankLevelStatus.HIGH_HIGH_TRIPelif level cfg.trip_low: return TankLevelStatus.LOW_LOW_TRIPelif level cfg.alarm_high: return TankLevelStatus.HIGH_ALARMelif level cfg.alarm_low: return TankLevelStatus.LOW_ALARMelse: return TankLevelStatus.NORMALdef get_status(self) - dict:return {tank_id: self.config.tank_id,level: self.tank.level,valve_open: self.controller.valve_open,pump_running: self.controller.pump_running,steps: self._step_count,}def run_simulation(self, duration_sec: float) - dict:运行指定时长的仿真并统计dt self.config.sample_intervaltotal_steps int(duration_sec / dt)logging.info(f[仿真] 开始运行, 时长: {duration_sec}s, 步数: {total_steps})valve_open_count pump_run_count alarm_count trip_count 0for _ in range(total_steps):state self.step()if state.valve_open: valve_open_count 1if state.pump_running: pump_run_count 1if state.level_status in (TankLevelStatus.HIGH_ALARM,TankLevelStatus.LOW_ALARM):alarm_count 1if state.level_status in (TankLevelStatus.HIGH_HIGH_TRIP,TankLevelStatus.LOW_LOW_TRIP):trip_count 1stats {total_steps: total_steps,simulation_time: self.tank.time,final_level: self.tank.level,valve_open_ratio: valve_open_count / total_steps * 100,pump_run_ratio: pump_run_count / total_steps * 100,alarm_count: alarm_count,trip_count: trip_count,min_level: min(s.level for s in self._history),max_level: max(s.level for s in self._history),avg_level: sum(s.level for s in self._history) / len(self._history),}logging.info(f[仿真] 完成 | 最终液位: {stats[final_level]:.1f}cm | f范围: {stats[min_level]:.0f}~{stats[max_level]:.0f}cm | f阀开率: {stats[valve_open_ratio]:.1f}%)return stats# # 6. 演示: 4种典型工况# def demo():完整演示: 船舶淡水柜自动补水控制logging.basicConfig(levellogging.INFO,format%(asctime)s [%(levelname)s] %(message)s,datefmt%H:%M:%S,)print( * 70)print( 船舶淡水柜自动补水控制仿真)print( 参考: 哈尔滨工程大学《工业过程控制》第4章)print( * 70)config TankConfig(tank_idFW-TK-01, max_level100.0, min_level0.0,normal_high80.0, normal_low30.0, hysteresis5.0,alarm_high90.0, alarm_low15.0,trip_high95.0, trip_low5.0,pump_flow_rate20.0, consumption_rate5.0,consumption_variation2.0, tank_cross_area50.0,sample_interval1.0,)# 工况1: 正常运行 30分钟print(\n【工况1: 正常运行 - 30分钟】)system MarineWaterSystem(config, noise_std0.3, fault_prob0.002)s全部就绪。下面是完整的 CSDN 博文。---# 船舶淡水柜自动补水控制仿真上下限液位启停电磁阀 *在船上淡水比油还金贵。淡水柜见底了没人知道水泵空转烧了全船断水——这种事我见过不止一次。一个可靠的上下限补水逻辑就是淡水系统的第一道保险。* *—— 参考哈尔滨工程大学《工业过程控制》第 4 章液位控制系统、第 8 章过程控制系统的安全保护*---## 一、实际应用场景描述在**船舶、海上平台、远洋渔船、海军舰艇**中淡水柜FW Tank是船员日常用水、锅炉补水的核心储水单元。由于船舶摇晃、用水波动大、维护人员有限淡水柜的自动补水控制直接关系全船生活质量甚至航行安全┌──────────────────────────────────────利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛