You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import uuid
import os
import json
import struct
import hashlib
import random
import copy
from idlelib.iomenu import encoding
import psutil
import platform
import datetime
import numpy as np
from app.lib.Log import logger
from app.lib.AlchemyJsonEncoder import *
from app.conf.Setting import settings
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
system_name = platform.system()
"""通用工具类"""
class Utils(object):
def __init__(self, *args, **kwargs):
return super().__init__(*args, **kwargs)
#MD5加密
def MD5(str):
hl = hashlib.md5()
hl.update(str.encode(encoding='utf-8'))
return hl.hexdigest()
#获取uuid
def get_uuid():
return str(uuid.uuid1())
def str_to_time(str):
return datetime.datetime.strptime(str, '%Y-%m-%d %H:%M:%S')
#获取当前时间
def get_time():
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
#请求成功返回
def true_return(data='', desc='请求成功', code=200):
data = {
"code": code,
"desc": desc,
"data": data
}
return data
def get_md5(input_str: str, encoding: str = 'utf-8') -> str:
"""
获取字符串的 MD5 哈希值
Args:
input_str: 输入字符串
encoding: 编码方式默认UTF-8
Returns:
32位小写十六进制MD5哈希值
"""
# 创建MD5哈希对象
md5_hash = hashlib.md5()
# 将字符串编码为字节并更新哈希对象
md5_hash.update(input_str.encode(encoding))
# 返回十六进制哈希值
return md5_hash.hexdigest()
def get_db_path():
"""
Returns:
数据库文件路径
"""
# 获取当前文件所在目录的绝对路径(即 'app/api'
base_dir = os.path.dirname(os.path.abspath(__file__))
# 获取项目根目录(假设 'app' 目录在项目根目录下)
project_root = os.path.dirname(base_dir) # 这个将得到 'instrument_short_circuit'
# 拼接数据库文件路径
db_path = os.path.join(project_root, 'db', 'Data.db')
return db_path
#分页请求成功返回
def true_return_pagination(pagination=None, data=None, desc='请求成功', code=200):
data = {
"pagination": pagination,
"code": code,
"desc": desc,
"data": data
}
return data
#请求失败返回
def false_return(data='', desc='请求失败', code=-1):
data = {
"code": code,
"desc": desc,
"data": data
}
return data
#生成统一格式接口数据
def ResultData(status,message,data=""):
return json.dumps({"status":status,"message":message,"data":data},cls=AlchemyEncoder)
#按时间生成随机文件名
def getFileName():
nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
randomNum = random.randint(0,100)
if randomNum <= 10:
randomNum = str(0) + str(randomNum)
uniqueNum = str(nowTime) + str(randomNum)
return uniqueNum
#获取当前插入U盘路径
def getUDiskPath():
if system_name == 'Windows':
disk_list = psutil.disk_partitions()
# 获取U盘路径
u_path = [disk.device for disk in disk_list if disk.opts == 'rw,removable']
if u_path:
return u_path[0]
elif system_name == 'Linux':
import pyudev
context = pyudev.Context()
removable = [device for device in context.list_devices(subsystem='block', DEVTYPE='disk') if device.attributes.asstring('removable') == "1"]
for device in removable:
partitions = [device.device_node for device in context.list_devices(subsystem='block', DEVTYPE='partition', parent=device)]
for p in psutil.disk_partitions():
if p.device in partitions:
return p.mountpoint
return ""
#创建文件夹
def mkdir(path):
folder = os.path.exists(path)
if not folder:
os.makedirs(path)
#int列表转换为字节流
def int_list_to_bytes(int_list):
byte_stream = b''
for num in int_list:
byte_stream += struct.pack('>H', num)
return byte_stream
#字节流转换为int列表
def bytes_to_int_list(byte_stream):
int_list = []
for i in range(0, byte_stream.__len__(), 2):
int_list.append(struct.unpack('>H', byte_stream[i:i+2])[0])
return int_list
#获取某比特的值
def get_bit(data: int, bit: int) -> int:
if data & (1 << bit):
return 1
else:
return 0
#获取某比特的值,并转换为布尔值
def get_bit_bool(data: int, bit: int) -> bool:
if data & (1 << bit):
return True
else:
return False
#修改某比特的值,并返回新值
def set_bit(number: int, pos: int, value: int):
new_number = None
if value == 1:
new_number = number | (1 << pos)
elif value == 0:
new_number = number & ~(1 << pos)
return new_number
#获取温度数据
def str_to_list(str_list):
if str_list:
str_list = str_list[:-1].strip('[]')
result = [list(map(eval, sublist.split(','))) for sublist in str_list.split('],[')]
return result
return []
#上升速率,下降率,data数据列表,num时间间隔,tag(1罐体2炉体),t=0返回x轴为温度反之为时间
def calculate_temp_rate(data,num,tag,t=0):
result = []
x=[]
y1 = []
y2 = []
for i in range(0, len(data)-num, 30):
time_interval = data[i+num][0] - data[i][0]
if time_interval == 0:
continue
temp_rate = (data[i+num][1] - data[i][1]) / time_interval * 3600
if t==0:
result.append([data[i+num][tag],abs(temp_rate)])
else:
result.append([data[i+num][0],data[i+num][tag],abs(temp_rate)])
x.append(data[i+num][0])
y1.append(data[i+num][tag])
y2.append(abs(temp_rate))
p_fit = Utils.get_quadratic_curve(result)
return result,p_fit,x,y1,y2
# 定义二次函数模型
def quadratic_func(x, a, b, c):
return a * x**2 + b * x + c
#二次函数导出公式
def derivative_func(x, a, b):
return 2* a * x + b
#比热计算公式Cp2
def specific_heat_func(E2, K, C,M2,H):
return 3600*(E2+K)/C*M2-H/M2
#发热率计算公式
def heat_generation_rate_func(M2, Cp2, H, D ,K):
return ((M2*Cp2+H)*D/3600-K)/M2
#获取二次曲线p_fit为二次曲线系数
def get_quadratic_curve(data):
x_data = np.array([i[0] for i in data])
y_data = np.array([i[1] for i in data])
degree = 2 # 二次多项式拟合
p_fit = np.polyfit(x_data, y_data, degree)
y_fit = np.polyval(p_fit, x_data)
# plt.figure()
# plt.scatter(x_data, y_data, label='Original Data')
# plt.plot(x_data, y_fit, 'r-', label='Fitted Curve')
# plt.xlabel('x')
# plt.ylabel('y')
# plt.title('Polynomial Fitting')
# plt.legend()
# plt.grid()
# plt.show()
return p_fit
# 热容量计算公式
def heat_capacity_func(E1, A, B, M1,Cp1):
# print(type(E1), type(A), type(B), type(M1),type(Cp1))
return (3600*E1)/(A+B)-(M1*Cp1)
#热损失计算公式
def heat_loss_func(H, A, M1,Cp1):
return A*(H+M1*Cp1)/3600
# 计算杜瓦瓶热容量
def calculate_heat_capacity(data, data1, E1, M1, Cp1):
capacity = 0
result, p_fit, x, r1, r2 = Utils.calculate_temp_rate(data, 30, 2)
result1, p_fit1, x, r1, r2 = Utils.calculate_temp_rate(data1, 30, 2)
for i in range(len(result)):
A = abs(Utils.quadratic_func(result[i][0], p_fit[0], p_fit[1], p_fit[2]))
B = abs(Utils.quadratic_func(result[i][0], p_fit1[0], p_fit1[1], p_fit1[2]))
H = abs(Utils.heat_capacity_func(E1, A, B, M1, Cp1))
capacity += H
return round(capacity/len(result), 2)
# 计算热容量及热损失(上升数据与下降数据不等长)
def calculate_heat_capacity_loss(data,data1,E1,M1,Cp1):
capacity=[]
capacity_sum = 0
loss=[]
temp_data=[]#点位上升速率
temp_data1=[]#点位下降速率
result,p_fit,x,r1,r2 = Utils.calculate_temp_rate(data,30,1)
result1,p_fit1,x,r1,r2 = Utils.calculate_temp_rate(data1,30,1)
for i in range(len(result)):
A = abs(Utils.quadratic_func(result[i][0],p_fit[0],p_fit[1],p_fit[2]))
B = abs(Utils.quadratic_func(result[i][0],p_fit1[0],p_fit1[1],p_fit1[2]))
H = abs(Utils.heat_capacity_func(E1, A, B, M1,Cp1))
capacity.append([result[i][0],H])
loss.append([result[i][0],Utils.heat_loss_func(H, A, M1,Cp1)])
for n in settings.TEM:
A = abs(Utils.quadratic_func(n,p_fit[0],p_fit[1],p_fit[2]))
B = abs(Utils.quadratic_func(n,p_fit1[0],p_fit1[1],p_fit1[2]))
temp_data.append(round(A, 4))
temp_data1.append(round(B, 4))
H = abs(Utils.heat_capacity_func(E1, A, B, M1, Cp1))
capacity_sum += H
capacity_value = round(capacity_sum/len(settings.TEM), 2)
return result,p_fit,result1,p_fit1,capacity,loss,temp_data,temp_data1,capacity_value
#获取K热损失H热容量2次曲线
def get_K_func(loss,capacity):
p_fit = Utils.get_quadratic_curve(loss)
p_fit1 = Utils.get_quadratic_curve(capacity)
return p_fit,p_fit1
# 计算比热Cp2与发热率data加热data1自加热
def calculate_heat_generation_rate(data,data1,data2,E2,M2,loss,capacity):
Cp2_list=[]
Qt_list=[]
r2,p_fit2,x,r1,r2 = Utils.calculate_temp_rate(data1,30,1)#校准上升率曲线
r3,p_fit3,x,r1,r2 = Utils.calculate_temp_rate(data2,30,1)#试验自加热斜率曲线
p_fit,p_fit1 =Utils.get_K_func(loss,capacity)#热损失热容量2次曲线
# print(p_fit,p_fit1,p_fit2,p_fit3)
result = data2
for i in range(len(result)):
C =Utils.quadratic_func(result[i][0],p_fit2[0],p_fit2[1],p_fit2[2])
K =Utils.quadratic_func(result[i][0],p_fit[0],p_fit[1],p_fit[2])
H =Utils.quadratic_func(result[i][0],p_fit1[0],p_fit1[1],p_fit1[2])
D =Utils.quadratic_func(result[i][0],p_fit3[0],p_fit3[1],p_fit3[2])
Cp2 =Utils.specific_heat_func(E2, K, C,M2,H)
Qt =Utils.heat_generation_rate_func(M2, Cp2, H, D ,K)
Cp2_list.append([result[i][0],Cp2])
Qt_list.append([result[i][1],Qt])
return Cp2_list,Qt_list
def format_status_data(status_data):
result_data = copy.deepcopy(status_data)
# if "g_temp" in result_data:
# result_data["g_temp"] = round(status_data["g_temp"], 2)
#
# if "l_temp" in result_data:
# result_data["l_temp"] = round(status_data["l_temp"], 2)
#
# if "last_g_temp" in result_data:
# result_data["last_g_temp"] = round(status_data["last_g_temp"], 2)
return result_data
def sample_by_interval(arr, interval=30):
if len(arr) <= interval:
return arr
indices = range(0, len(arr), interval)
sampled_array = [arr[i] for i in indices]
return sampled_array
class AlgorithmUtils:
@staticmethod
def heat_loss_func(H, A, M1,Cp1):
return A*(H+M1*Cp1)/3600
@staticmethod
def heat_capacity_func(E1, A, B, M1,Cp1):
return (3600*E1)/(A+B)-(M1*Cp1)
# 定义二次函数模型
@staticmethod
def quadratic_func(x, a, b, c):
return a * x**2 + b * x + c
@staticmethod
def specific_heat_func(E2, K, C,M2,H):
return 3600*(E2+K)/C*M2-H/M2
@staticmethod
def heat_generation_rate_func(M2, Cp2, H, D ,K):
return ((M2*Cp2+H)*D/3600-K)/M2
@staticmethod
def get_quadratic_curve(data):
x_data = np.array([i[0] for i in data])
y_data = np.array([i[1] for i in data])
degree = 2 # 二次多项式拟合
return np.polyfit(x_data, y_data, degree)
def capacity_specify_temperature(self, jz_raw_data, rise_p_fit, drop_p_fit, E1, M1, Cp1):
"""计算特定温度下的值"""
capacity, loss, capacity_p_fit, loss_p_fit = self.capacity_loss(jz_raw_data, rise_p_fit, drop_p_fit, E1, M1, Cp1)
rise_temp_values = []
drop_temp_values = []
capacity_values = []
for t in [40, 60, 80, 100]:
B = self.quadratic_func(t, rise_p_fit[0], rise_p_fit[1], rise_p_fit[2]) # 升温速率
rise_temp_values.append(round(B, 4))
A = self.quadratic_func(t, drop_p_fit[0], drop_p_fit[1], drop_p_fit[2]) # 降温
drop_temp_values.append(round(A, 4))
H = self.heat_capacity_func(E1, A, B, M1, Cp1)
capacity_values.append(H) # 杜瓦瓶热容量
capacity_value = sum(capacity_values)/len(capacity_values)
return capacity, loss, rise_temp_values, drop_temp_values, capacity_value
def calculate_temp_rate(self, data, num=30):
result = []
for i in range(0, len(data)-num, num):
time_interval = int(data[i+num][0]) - int(data[i][0])
if time_interval == 0:
continue
temp_rate = (float(data[i+num][1]) - float(data[i][1])) / time_interval * 3600
result.append([float(data[i+num][1]), abs(temp_rate)])
return result
def time_temp_rate(self, raw_data, num=60):
r = []
x = []
y1 = []
y2 = []
for i in range(0, len(raw_data) - num, num):
time_interval = int(raw_data[i + num][0]) - int(raw_data[i][0])
if time_interval == 0:
continue
temp_rate = (float(raw_data[i + num][1]) - float(raw_data[i][1])) / time_interval * 3600
r.append([int(raw_data[i+num][0]), float(raw_data[i+num][1]), abs(temp_rate)])
x.append(int(raw_data[i + num][0]))
y1.append(float(raw_data[i + num][1]))
y2.append(abs(temp_rate))
return r, x, y1, y2
def capacity_loss(self, jz_raw_data, rise_p_fit, drop_p_fit, E1, M1, Cp1):
"""计算热容量和热损失曲线"""
capacity = []
loss = []
raw_data = self.calculate_temp_rate(jz_raw_data, num=60)
for item in raw_data:
B = self.quadratic_func(item[0], rise_p_fit[0], rise_p_fit[1], rise_p_fit[2]) # 升温速率
A = self.quadratic_func(item[0], drop_p_fit[0], drop_p_fit[1], drop_p_fit[2]) # 降温速率 TODO
H = abs(self.heat_capacity_func(E1, A, B, M1, Cp1)) # 杜瓦瓶热容量
K = self.heat_loss_func(H, A, M1, Cp1) # 热损失
capacity.append([item[0], H])
loss.append([item[0], K])
capacity_p_fit = self.get_quadratic_curve(capacity)
loss_p_fit = self.get_quadratic_curve(loss)
return capacity, loss, capacity_p_fit, loss_p_fit
def calculate_heat_generation_rate(self, zs_data, capacity_p_fit, loss_p_fit, E2, M2):
# 自加速
self_heatingTemp_data = zs_data.get("self_heatingTemp")
self_heatingTemp_rate = self.calculate_temp_rate(self_heatingTemp_data, num=2)
self_heatingTemp_p_fit = self.get_quadratic_curve(self_heatingTemp_rate)
# 样品
riseTemp_data = zs_data.get("riseTemp")
riseTemp_rate = self.calculate_temp_rate(riseTemp_data, num=60)
rise_p_fit = self.get_quadratic_curve(riseTemp_rate)
Cp2_list = []
Qt_list = []
for item in self_heatingTemp_rate:
C = self.quadratic_func(item[0],rise_p_fit[0],rise_p_fit[1],rise_p_fit[2])
K = self.quadratic_func(item[0],loss_p_fit[0],loss_p_fit[1],loss_p_fit[2])
H = self.quadratic_func(item[0],capacity_p_fit[0],capacity_p_fit[1],capacity_p_fit[2])
D = self.quadratic_func(item[0],self_heatingTemp_p_fit[0],self_heatingTemp_p_fit[1],self_heatingTemp_p_fit[2])
Cp2 = self.specific_heat_func(E2, K, C,M2,H)
Qt = self.heat_generation_rate_func(M2, Cp2, H, D,K)
Cp2_list.append([item[0],Cp2])
Qt_list.append([item[0],Qt])
return Cp2_list, Qt_list
class ChannelStatusError(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)