389 lines
12 KiB
Python
389 lines
12 KiB
Python
|
|
"""
|
|||
|
|
2026/3/29
|
|||
|
|
"""
|
|||
|
|
import struct
|
|||
|
|
import math
|
|||
|
|
|
|||
|
|
def calc_telem(value: float, method: str, param_str: str, ref_cache: dict) -> float:
|
|||
|
|
#def telem_calc(value: float, method: str, param_str: str, ref_cache: dict) -> float:
|
|||
|
|
try:
|
|||
|
|
x = value
|
|||
|
|
|
|||
|
|
# 空方法:原值
|
|||
|
|
if not method:
|
|||
|
|
return x
|
|||
|
|
|
|||
|
|
# 数值拟合 y = a*x + b
|
|||
|
|
if method == "数值拟合":
|
|||
|
|
a, b = map(float, param_str.split(','))
|
|||
|
|
return a * x + b
|
|||
|
|
|
|||
|
|
# 电压1:V = D/255*5.1 D无符号整型
|
|||
|
|
elif method == "电压1":
|
|||
|
|
D = int(x)
|
|||
|
|
return D / 255.0 * 5.1
|
|||
|
|
|
|||
|
|
# 电压6:V = D*20/65535 D有符号整型
|
|||
|
|
elif method == "电压6":
|
|||
|
|
D = int(x)
|
|||
|
|
return D * 20.0 / 65535.0
|
|||
|
|
|
|||
|
|
# 电压3:V = D*0.000305185 D有符号整型
|
|||
|
|
elif method == "电压3":
|
|||
|
|
D = int(x)
|
|||
|
|
return D * 0.000305185
|
|||
|
|
|
|||
|
|
# 电压2:V= D *10/4096-5 D有符号整型
|
|||
|
|
elif method == "电压2":
|
|||
|
|
D = int(x )
|
|||
|
|
return D * 10 / 4096 - 5
|
|||
|
|
# # 电阻拟合1
|
|||
|
|
# elif method == "电阻拟合1":
|
|||
|
|
# D = int(x)
|
|||
|
|
# V = D / 255.0 * 5.1
|
|||
|
|
# ref_key = param_str.strip()
|
|||
|
|
# Vref = ref_cache.get(ref_key, 5.1)
|
|||
|
|
# if abs(Vref - V) < 1e-12:
|
|||
|
|
# return 0.0
|
|||
|
|
# Rr = 10000.0
|
|||
|
|
# return V * Rr / (Vref - V)
|
|||
|
|
|
|||
|
|
# 电阻拟合1
|
|||
|
|
elif method == "电阻拟合1":
|
|||
|
|
D = int(x)
|
|||
|
|
V = D / 255.0 * 5.1
|
|||
|
|
# V基准固定为 5.0V
|
|||
|
|
Vref = 5.0
|
|||
|
|
if abs(Vref - V) < 1e-12:
|
|||
|
|
return 0.0
|
|||
|
|
Rr = 10000.0
|
|||
|
|
return V * Rr / (Vref - V)
|
|||
|
|
|
|||
|
|
# # 特殊公式8(按你描述完整实现)
|
|||
|
|
# elif method == "特殊公式8":
|
|||
|
|
# raw = int(x)
|
|||
|
|
# if param_str:
|
|||
|
|
# parts = param_str.split(',')
|
|||
|
|
# else:
|
|||
|
|
# parts = []
|
|||
|
|
# flag = int(parts[0]) if len(parts) >= 1 else 0
|
|||
|
|
|
|||
|
|
# if flag == 0:
|
|||
|
|
# # 遥测状态字:16位处理
|
|||
|
|
# w = raw & 0xFFFF
|
|||
|
|
# bh = (w >> 8) & 0xFF
|
|||
|
|
# bl = w & 0xFF
|
|||
|
|
# bh8 = bh + 0x8
|
|||
|
|
# bl8 = bl + 0x8
|
|||
|
|
# h4 = (bh8 >> 4) & 0xF
|
|||
|
|
# l4 = (bl8 >> 4) & 0xF
|
|||
|
|
# B1 = (l4 << 4) | h4
|
|||
|
|
# else:
|
|||
|
|
# # 遥控状态字:8位直接用
|
|||
|
|
# B1 = raw & 0xFF
|
|||
|
|
|
|||
|
|
# # 后面位比较逻辑你需要我也可以补全
|
|||
|
|
# return float(B1)
|
|||
|
|
elif method == "特殊公式8":
|
|||
|
|
"""
|
|||
|
|
最新规则:
|
|||
|
|
1) 原始值取整
|
|||
|
|
2) 低 16bit:低位
|
|||
|
|
3) 高 4bit :高位
|
|||
|
|
4) 合并 = (高位4bit << 16) | 低位16bit
|
|||
|
|
5) 结果 = 合并值 × 0.00205479
|
|||
|
|
"""
|
|||
|
|
raw_int = int(x) & 0xFFFFFFFF # 取32位无符号
|
|||
|
|
|
|||
|
|
# 低位 16bit
|
|||
|
|
low16 = raw_int & 0xFFFF
|
|||
|
|
|
|||
|
|
# 高位 4bit(最后4bit)
|
|||
|
|
high4 = (raw_int >> 28) & 0x0F
|
|||
|
|
|
|||
|
|
# 合并 20bit:高4位 <<16 | 低16位
|
|||
|
|
combined = (high4 << 16) | low16
|
|||
|
|
|
|||
|
|
# 乘以系数
|
|||
|
|
result = combined * 0.00205479
|
|||
|
|
|
|||
|
|
return float(result)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 状态量 / 10进制:不处理
|
|||
|
|
elif method in ["状态量", "10进制"]:
|
|||
|
|
return x
|
|||
|
|
|
|||
|
|
return x
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return value
|
|||
|
|
|
|||
|
|
import struct
|
|||
|
|
import math
|
|||
|
|
|
|||
|
|
def poly4_calc(D):
|
|||
|
|
"""正向 4 次多项式计算 y"""
|
|||
|
|
y = (-49.736 * (D ** 4)
|
|||
|
|
+ 383.38 * (D ** 3)
|
|||
|
|
- 1068.5 * (D ** 2)
|
|||
|
|
+ 1309.9 * D
|
|||
|
|
- 684.71)
|
|||
|
|
return y
|
|||
|
|
|
|||
|
|
|
|||
|
|
def inverse_poly4_fit(y):
|
|||
|
|
"""
|
|||
|
|
逆运算:已知 y → 求 D
|
|||
|
|
适用于:y ∈ [-112, 42]
|
|||
|
|
"""
|
|||
|
|
if not (-112 <= y <= 42):
|
|||
|
|
return 0.0 # 超范围保护
|
|||
|
|
|
|||
|
|
# 二分法区间(根据你的遥测范围实测得出)
|
|||
|
|
left = 1.5
|
|||
|
|
right = 4.5
|
|||
|
|
eps = 1e-5
|
|||
|
|
for _ in range(50):
|
|||
|
|
mid = (left + right) / 2
|
|||
|
|
current_y = poly4_calc(mid)
|
|||
|
|
if current_y < y:
|
|||
|
|
left = mid
|
|||
|
|
else:
|
|||
|
|
right = mid
|
|||
|
|
|
|||
|
|
return (left + right) / 2
|
|||
|
|
|
|||
|
|
# 固定系数
|
|||
|
|
Rr = 10000.0
|
|||
|
|
A = -6.01188
|
|||
|
|
B = 4622.53337
|
|||
|
|
C = -86421.72414
|
|||
|
|
|
|||
|
|
def calc_t_from_V(V):
|
|||
|
|
"""正向:V → t(内部用)"""
|
|||
|
|
if V >= 5.0:
|
|||
|
|
V = 4.9999
|
|||
|
|
if V <= 0:
|
|||
|
|
V = 0.0001
|
|||
|
|
|
|||
|
|
R = V * Rr / (5.0 - V)
|
|||
|
|
lnR = math.log(R)
|
|||
|
|
sqrt_val = math.sqrt(B**2 - 4 * C * (A - lnR))
|
|||
|
|
t = 2 * C / (sqrt_val - B) - 273.15
|
|||
|
|
return t
|
|||
|
|
|
|||
|
|
def calc_V_from_t(t_target):
|
|||
|
|
"""
|
|||
|
|
逆运算:已知温度 t → 求遥测电压 V
|
|||
|
|
:param t_target: 目标温度 ℃
|
|||
|
|
:return: V (V),精度 0.0001
|
|||
|
|
"""
|
|||
|
|
# 电压范围 0 ~ 5V
|
|||
|
|
left = 0.0001
|
|||
|
|
right = 4.9999
|
|||
|
|
eps = 1e-5
|
|||
|
|
|
|||
|
|
# 二分法迭代 50 次足够精确
|
|||
|
|
for _ in range(50):
|
|||
|
|
mid = (left + right) / 2
|
|||
|
|
t_mid = calc_t_from_V(mid)
|
|||
|
|
|
|||
|
|
if t_mid < t_target:
|
|||
|
|
left = mid
|
|||
|
|
else:
|
|||
|
|
right = mid
|
|||
|
|
|
|||
|
|
return (left + right) / 2
|
|||
|
|
def inverse_quadratic_fit(y, coeffs, y_min, y_max):
|
|||
|
|
"""
|
|||
|
|
通用二次多项式逆运算(3个拟合参数)
|
|||
|
|
公式:y = a2*D² + a1*D + a0
|
|||
|
|
已知 y → 求 D(只返回合法正根)
|
|||
|
|
|
|||
|
|
参数:
|
|||
|
|
y: 目标物理值
|
|||
|
|
coeffs: 拟合系数 [a2, a1, a0]
|
|||
|
|
y_min: y 有效最小值
|
|||
|
|
y_max: y 有效最大值
|
|||
|
|
返回:
|
|||
|
|
D: 原始码值
|
|||
|
|
"""
|
|||
|
|
# 1. 边界限幅
|
|||
|
|
y_clamped = max(y_min, min(y, y_max))
|
|||
|
|
|
|||
|
|
# 2. 取出系数
|
|||
|
|
a2, a1, a0 = coeffs
|
|||
|
|
|
|||
|
|
# 3. 构建一元二次方程标准形式:A*D² + B*D + C = 0
|
|||
|
|
A = a2
|
|||
|
|
B = a1
|
|||
|
|
C = a0 - y_clamped
|
|||
|
|
|
|||
|
|
# 4. 求判别式
|
|||
|
|
delta = B ** 2 - 4 * A * C
|
|||
|
|
if delta < 0:
|
|||
|
|
delta = 0 # 防止无实根
|
|||
|
|
|
|||
|
|
# 5. 求正根(遥测D一定为正)
|
|||
|
|
D = (-B + (delta ** 0.5)) / (2 * A)
|
|||
|
|
|
|||
|
|
# 6. 保证 D 不为负
|
|||
|
|
return max(D, 0.0)
|
|||
|
|
|
|||
|
|
def calc_telem_reverse(result: float, method: str, param_str: str) -> float:
|
|||
|
|
"""
|
|||
|
|
【逆运算】
|
|||
|
|
输入:A 软件发来的 结果值
|
|||
|
|
输出:反推出来的 原始值 D
|
|||
|
|
完全按你提供的处理方法反向计算
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
y = result
|
|||
|
|
|
|||
|
|
# ===================== 空方法:直接返回 =====================
|
|||
|
|
if not method:
|
|||
|
|
return y
|
|||
|
|
|
|||
|
|
# ===================== 数值拟合:Y = a*x + b → x=(y-b)/a =====================
|
|||
|
|
if method == "数值拟合":
|
|||
|
|
a, b = map(float, param_str.split(','))
|
|||
|
|
x = (y - b) / a
|
|||
|
|
return x
|
|||
|
|
|
|||
|
|
# ===================== 电压1:V = D/255*5.1 → D=V*255/5.1 =====================
|
|||
|
|
elif method == "电压1":
|
|||
|
|
D = y * 255.0 / 5.1
|
|||
|
|
return float(int(round(D))) # 原始是无符号整型
|
|||
|
|
|
|||
|
|
# ===================== 电压6:V = D*20/65535 → D=V*65535/20 =====================
|
|||
|
|
elif method == "电压6":
|
|||
|
|
D = y * 65535.0 / 20.0
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
# ===================== 电压3:V = D*0.000305185 → D=V / 0.000305185 =====================
|
|||
|
|
elif method == "电压3":
|
|||
|
|
D = y / 0.000305185
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
# ===================== 电压2:V电压2 = D *10/4096-5,其中D为无符号整型,计算时转化成十进制数。 → D=(V + 5)*409.6 =====================
|
|||
|
|
elif method == "电压2":
|
|||
|
|
D = (y + 5) * 409.6
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
# ===================== 电阻拟合1 → 逆运算 =====================
|
|||
|
|
# 公式:
|
|||
|
|
# V = D/255*5.1
|
|||
|
|
# R = V*10000/(5.0 - V)
|
|||
|
|
# 逆推 D
|
|||
|
|
#2026/3/30手算验证公式是正确的
|
|||
|
|
elif method == "电阻拟合1":
|
|||
|
|
R = y
|
|||
|
|
Vref = 5.0
|
|||
|
|
Rr = 10000.0
|
|||
|
|
|
|||
|
|
# 逆推 V
|
|||
|
|
if R <= 0.0:
|
|||
|
|
V = 0.0
|
|||
|
|
else:
|
|||
|
|
V = (R * Vref) / (R + Rr)
|
|||
|
|
|
|||
|
|
# 逆推 D
|
|||
|
|
D = V * 255.0 / 5.1
|
|||
|
|
return float(int(round(D)))
|
|||
|
|
|
|||
|
|
# ===================== 特殊公式8(逆运算) =====================
|
|||
|
|
# 正向:combined = (high4 <<16) | low16 result = combined * 0.00205479
|
|||
|
|
# 逆向:combined = y / 0.00205479
|
|||
|
|
# high4 = (combined >> 16) & 0xF
|
|||
|
|
# low16 = combined & 0xFFFF
|
|||
|
|
# raw = (high4 << 28) | low16
|
|||
|
|
elif method == "特殊公式8":
|
|||
|
|
combined = int(round(y / 0.00205479))
|
|||
|
|
low16 = combined & 0xFFFF
|
|||
|
|
high4 = (combined >> 16) & 0x0F
|
|||
|
|
raw = (high4 << 28) | low16
|
|||
|
|
return float(raw)
|
|||
|
|
|
|||
|
|
# ===================== 状态量 / 10进制:直接返回 =====================
|
|||
|
|
elif method in ["状态量", "10进制"]:
|
|||
|
|
return y
|
|||
|
|
|
|||
|
|
elif method == "特殊公式11-1":
|
|||
|
|
"""
|
|||
|
|
M057JG023 / M057JG024 专用逆运算
|
|||
|
|
输入:物理值 y
|
|||
|
|
输出:原始值 m(用于组帧)
|
|||
|
|
"""
|
|||
|
|
# if y < (0.0973 * 1840 + 180): # 区间1:y < 359.032
|
|||
|
|
# m = (y - 180) / 0.0973
|
|||
|
|
# elif y > (0.0974 * 1840 - 179.46): # 区间2:y > -0.444
|
|||
|
|
# m = (y + 179.46) / 0.0974
|
|||
|
|
# else: # m=1840
|
|||
|
|
# m = 1840.0
|
|||
|
|
#2026/5/7修正公式
|
|||
|
|
if y < (180): # 区间1:
|
|||
|
|
m = (y + 179.46) / 0.0974
|
|||
|
|
elif y > (180): # 区间2:
|
|||
|
|
m = (y - 180) / 0.0973
|
|||
|
|
else: # m=1840
|
|||
|
|
m = 0.0
|
|||
|
|
# 组帧需要整数,返回四舍五入
|
|||
|
|
return float(round(m))
|
|||
|
|
elif method == "电压2,数值拟合":
|
|||
|
|
"""
|
|||
|
|
逆运算,先反解数值拟合,再反推电压2
|
|||
|
|
"""
|
|||
|
|
a, b = map(float, param_str.split(','))
|
|||
|
|
x = (y - b) / a
|
|||
|
|
D = (x + 5) * 409.6## 电压2
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
elif method == "电压1,数值拟合":
|
|||
|
|
"""
|
|||
|
|
逆运算,先反解数值拟合,再反推电压2
|
|||
|
|
"""
|
|||
|
|
a, b = map(float, param_str.split(','))
|
|||
|
|
x = (y - b) / a
|
|||
|
|
D = x * 255.0 / 5.1## 电压1
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
elif method == "电压1,数值拟合5":
|
|||
|
|
"""
|
|||
|
|
逆运算,先反解数值拟合(5次方程),再反推电压2
|
|||
|
|
"""
|
|||
|
|
x = inverse_poly4_fit(y) ##2分法求解5次方程
|
|||
|
|
|
|||
|
|
D = x * 255.0 / 5.1## 电压1
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
|
|||
|
|
elif method == "电阻拟合1,MF501(电阻)":
|
|||
|
|
x = calc_V_from_t(y) #2分法
|
|||
|
|
R = x
|
|||
|
|
Vref = 5.0
|
|||
|
|
Rr = 10000.0
|
|||
|
|
|
|||
|
|
# 逆推 V
|
|||
|
|
if R <= 0.0:
|
|||
|
|
V = 0.0
|
|||
|
|
else:
|
|||
|
|
V = (R * Vref) / (R + Rr)
|
|||
|
|
|
|||
|
|
# 逆推 D
|
|||
|
|
D = V * 255.0 / 5.1
|
|||
|
|
return float(int(round(D)))
|
|||
|
|
elif method == "电压1,数值拟合3":
|
|||
|
|
a, b,c,y_min,y_max = map(float, param_str.split(','))
|
|||
|
|
coeffs = [a,b,c]
|
|||
|
|
return inverse_quadratic_fit(y, coeffs, y_min, y_max)
|
|||
|
|
|
|||
|
|
elif method == "电压6,数值拟合":
|
|||
|
|
"""
|
|||
|
|
逆运算,先反解数值拟合,再反推电压2
|
|||
|
|
"""
|
|||
|
|
a, b = map(float, param_str.split(','))
|
|||
|
|
x = (y - b) / a
|
|||
|
|
D = x * 65535.0 / 20.0 #电压6
|
|||
|
|
return float(int(round(D))) # 有符号整型
|
|||
|
|
except Exception as e:
|
|||
|
|
return result
|