分类目录归档:技术博客

针对一些技术的展示

【Python】Streamlit 应用 “COMSOL 颜色表预览”

Streamlit APP “COMSOL 颜色表预览”

有些客户在拿到基于COMSOL的分析结果后,会提出“当前云图颜色配色不满意,需要拿到COMSOL文件自己进行进行调色”。但是大部分时候我是不提供COMSOL文件的。不提供文件的原因有如下几点:

  • 客户其实不会用这个软件,自己操作半天还是不会弄,最后还是返回来要我处理。
  • 对文件内些有独有技术的保护,不想外流。
  • 有些客户不懂有限元,看到文件内的操作不理解,会出现反复问询的情况,避免陷入反复自证吃了几碗粉的情况。
  • 有些客户拿到文件后自己的保密意识不到位,有外流风险。(以前出现客户拿到模型后毕业礼把模型文件卖给模型收集者,然后模型收集者又将文件挂到进行兜售交易。)

为了回绝客户的 “当前云图颜色配色不满意,需要拿到COMSOL文件自己进行进行调色”, 我开发一个在线的颜色表预览App,客户可以预览所有的COMSOL预置颜色表,选择好意向颜色表后进行反馈。

“COMSOL 颜色表预览” 应用入口

目前此APP仅对合作伙伴开放使用,如遇APP使用请及时联系我。欢迎各位给出宝贵意见~!

纯Python开发,使用了streamlit,pandas,pyvista等模块。

更新记录

2024年11月21日 V2.1

  • 增加了2D、3D默认视图的选择,方便对不同的维度的结果进行快速预览
  • 增加了颜色表的顺滑

2024年11月15日 V2.0上线

  • 增加COMSOL格式的colorbar渲染
  • 增加单个订单的多个场景预览选择
  • 在无查询订单状态下,增加了几个官方案例库里的后处理场景
  • 布局调整

COMSOL Matlab livelink多参数研究仿真 2

model = mphopen('1113.mph'); %打开文件

param_name = ["d1" "a3" "a2" "a1"]; % 参数名称
param_unit = ["um" "um" "um" "um"]; % 参数单位
param_Value = [0.1 0.3 0.5;...  %参数值
                50 75 100;...
                1 3 5;...
                0.1 1 2];

% For循环运行所有参数组
para_num=size(param_Value,2);
T_max=zeros(para_num^4,1);
Stress1=zeros(para_num^4,1);
Stress2=zeros(para_num^4,1);
para=ones(para_num^4,4);
i=1;
for para1=1:para_num % 循环研究参数名
    for para2=1:para_num
        for  para3=1:para_num
            for para4=1:para_num
                %记录输出
                tic;
                fprintf('Start simulation %d: %s=%.1f | %s=%.1f | %s=%.1f | %s=%.1f \n',i,...
                    param_name(1),param_Value(1,para1),...
                    param_name(2),param_Value(2,para2),...
                    param_name(3),param_Value(3,para3),...
                    param_name(4),param_Value(4,para4));
                %设定参数
                model.param.set(param_name(1),num2str(param_Value(1,para1)),param_unit(1));
                model.param.set(param_name(2),num2str(param_Value(2,para2)),param_unit(2));
                model.param.set(param_name(3),num2str(param_Value(3,para3)),param_unit(3));
                model.param.set(param_name(4),num2str(param_Value(4,para4)),param_unit(4));
                %运行计算
                model.sol('sol1').runAll;
                model.sol('sol2').runAll;
                model.sol('sol3').runAll;
                %记录数据
                para(i,:)=[param_Value(1,para1) param_Value(2,para2) param_Value(3,para3) param_Value(4,para4)];
                T_max(i) = mphglobal(model,'dom1','dataset','dset1','unit','degC'); %导出指定数据集的探针数据
                Stress1(i) = mphglobal(model,'dom2','dataset','dset3','unit','MPa');
                Stress2(i) = mphglobal(model,'dom6','dataset','dset4','unit','MPa');
                fprintf('Done simulation %d: T_max = %.2f | Stress1 = %.2f | Stress2 = %.2f\n',i,T_max(i),Stress1(i),Stress2(i));
                i=i+1;
                toc
            end
        end
    end
end
save('data.mat','para','T_max','Stress1','Stress2');

COMSOL Matlablive 多参数研究,批量化运行+导出+自动整理

COMSOL软件的研究求解模块其实提供了比较丰富的参数化运行结构,但是对不同参数的研究的结果导出方面,还是需要很多手动设置操作的才能导出批量化数据。

比如以下情况:研究对线是一个催化反应器,需要入口温度、入口流速、反应器尺寸、反应物初始孔隙率等四个不同的输入参数进行单变量的不同输入值的影响研究。那么如果直接使用COMSOL来做的话,就需要使用参数化扫描对单个参数进行扫描,然后导出动画进行分解,并保存四个不同的mph文件,用于分别研究四个参数。

针对这种情况,其实可以用Matlab livelink来进行批量的单个参数的修改,并运行求解导出相关结果(mph、图、报告、表数据)。

% 1、定义要运行的参数组
model = mphopen('param_run.mph');  % 打开模型
% 设定参数组
param_name = ["T_in" "U_in" "d_ball" "eps_init"]; % 参数名称
param_unit = ["degC" "m/s" "um" ""]; % 参数单位
param_Value = [600 650 700 750 800;...  %参数值
                0.1 0.2 0.3 0.4 0.5;...
                75 150 200 300 500;...
                0.03 0.05 0.1 0.15 0.2];

% 2、 For循环运行所有参数组
for name=1:length(param_name) % 循环研究参数名
   for value=1:size(param_Value,2) % 参数水平
       % 记录输出
       tic;
       fprintf('Start simulation: %s=%s [%s]\n',param_name(name),num2str(param_Value(name,value)),param_unit(name));
       % 设定参数
       model.param.set(param_name(name),num2str(param_Value(name,value)),param_unit(name));
       % 运行计算
       model.sol('sol1').runAll;
       % 导出数据
       model.result.report('rpt1').run; % 导出报告
       model.result.export('anim1').run; % 导出动画
       model.result.export('anim2').run;
       model.result.export('anim3').run;
       model.result.export('anim4').run;
       model.result.export('anim5').run;
       model.result.export('anim6').run;
       model.result.export('anim7').run;
       model.result.export('plot1').run; % 导出出图数据表
       model.result.export('plot2').run;
       model.result.export('plot3').run;
       % 整理导出数据
       movefile("export_dir", strcat(param_name(name),"_", num2str(param_Value(name,value))));
       copyfile("export_file",strcat(param_name(name),"_", num2str(param_Value(name,value))));
       % 完成
       toc
   end
   % 设定回原参数
   model.param.set(param_name(name),num2str(param_Value(name,1)),param_unit(name));
end

【Python】GifSpliter “GIF分割器”

“GifSpliter” GIF分割器

用PyQt5重写了一个“GIF分割器”的小应用:

功能:

  • 主要就是为了能快速分解GIF文件,将所有帧保存成PNG格式。
  • 支持文件拖拽进窗口,也是唯一的文件输入方式,就是简单暴力,直接方便,xD。
  • 可选择的输出位置:可以指定位置,也可以在原文件所在位置给你输出分割帧。
  • 可以拖拽文件夹输入,只要你文件夹里有gif,都给你处理了。
  • 支持混合输入模式。可以同时选中多个gif,或者gif+文件夹的多个文件输入。

现成的软件 GifSpliter_v3.2:

链接:https://pan.baidu.com/s/1JJLOF1vDYpd7pRzrtr93Xg?pwd=ucuo
提取码:ucuo
–来自百度网盘超级会员V6的分享

为什么做这个?

COMSOL仿真导出GIF图很方便,但是想要导出不同时刻参数下的多个图像很不方便。那……不如直接导出GIF后再分割?

但是网上没有这种轻量级的,简单暴力,合我需求的应用,那直接自己撸一个小工具!

现在,直接选中文件拖进去,等几秒就好了,多好?

Update History

v3.2 231031

  • 丰富了控制台打印信息,增加了彩色的控制台输出,并添加了处理进度条;

v3.1 230831

  • 保留了控制台窗口,并优化了控制台输出,现在可以通过控制台输出信息查看处理

    情况

v3.0 230631

  • PyQt5设计了全新的窗口;
  • 增加了文件夹模式;
  • 增加了多种输出模式的选择;

v2.0

  • 增加了多文件处理模式。

v1.0

  • Tinkter界面,单gif文件的处理方式,默认输出到exe所在文件夹。

SourceCode

import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from ui_GifSpliter import *
from spliter import GifSplitter
import res_rc

class MyGifSpliter(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数
        self.__ui = Ui_GifSpliter()
        self.__ui.setupUi(self)
        self.appDir = sys.path[0]
        print(self.appDir)
        self.gifDir = self.appDir
        self.gifDir = self.appDir
        self.specDir = self.appDir
        self.outDir = self.appDir
        self.__ui.textEdit_DirSpec.setText(self.appDir)
        # 调用Drops方法
        # self.drawn()
        self.__ui.radioButton_DirSpec.clicked.connect(self.do_setSpecDir)


    # 鼠标拖入事件
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    # 鼠标放开执行
    def dropEvent(self, event):
        """获取拖拽文件的路径"""
        files = []
        for url in event.mimeData().urls():
            path = url.toLocalFile()
            files.append(path)
        # 打印拖住进入窗口的文件路径
        self.gifDir = os.path.split(files[0])[0]
        # print(f'拖拽文件路径为:"{self.gifDir}"')

        # 判断输出模式
        if self.__ui.radioButton_DirGif.isEnabled():
            self.outDir = self.gifDir + '/分割后PNG'
            if not os.path.exists(self.outDir):
                os.mkdir(self.outDir)
        elif self.__ui.radioButton_DirApp.isEnabled():
            self.outDir = self.appDir
        elif self.__ui.radioButton_DirSpec.isEnabled():
            self.outDir = self.specDir
        # print(f'输出文件夹为:"{self.outDir}"')

        # 处理获取的文件
        for file in files:
            # 文件夹
            if os.path.isdir(file):
                # print(f'{file}是文件夹')
                self.gifDir = file
                self.outDir = self.gifDir + '/分割后PNG'
                if not os.path.exists(self.outDir):
                    os.mkdir(self.outDir)
                GifSplitter.split_gifs_in_folder(file, save_folder=self.outDir)
                print(f'\033[92m完成对文件夹:"{file}"的处理~~~\033[0m')
            # 文件
            else:
                # 判断扩展名是否为.gif
                if file.lower().endswith('.gif'):
                    # print(f'{file}是gif文件')
                    GifSplitter(file).export_frames(save_folder=self.outDir)
                else:
                    print(f'\033[91m! "{os.path.basename(file)}" 不是GIF文件~~~!\033[0m')
        if self.__ui.checkBox_openDirSpec.isChecked():
            os.startfile(self.outDir)

    #设定背景图片
    # def drawn(self):
    #     self.__ui.palette = QPalette()
    #     self.__ui.palette.setBrush(QPalette.Background, QBrush(QPixmap("BackGround1.png")))
    #     self.setPalette(self.__ui.palette)

    # 根据radioButton设定文件路径
    def do_setSpecDir(self):
        if self.__ui.radioButton_DirSpec.isChecked():
            self.specDir = QFileDialog.getExistingDirectory(None,"选取PNG输出文件夹","")
            self.__ui.textEdit_DirSpec.setText(self.specDir)
            print(f'设定指定输出路径为:{self.specDir}')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    e = MyGifSpliter()
    e.show()
    sys.exit(app.exec_())
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'ui_GifSpliter.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_GifSpliter(object):
    def setupUi(self, GifSpliter):
        GifSpliter.setObjectName("GifSpliter")
        GifSpliter.resize(640, 480)
        GifSpliter.setMinimumSize(QtCore.QSize(640, 480))
        GifSpliter.setMaximumSize(QtCore.QSize(640, 480))
        font = QtGui.QFont()
        font.setFamily("微软雅黑")
        font.setPointSize(11)
        font.setBold(True)
        font.setUnderline(False)
        font.setWeight(75)
        GifSpliter.setFont(font)
        GifSpliter.setAcceptDrops(True)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/icon/C cyn.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        GifSpliter.setWindowIcon(icon)
        GifSpliter.setStyleSheet("")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(GifSpliter)
        self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label = QtWidgets.QLabel(GifSpliter)
        self.label.setMinimumSize(QtCore.QSize(0, 0))
        font = QtGui.QFont()
        font.setFamily("微软雅黑")
        font.setBold(False)
        font.setWeight(50)
        self.label.setFont(font)
        self.label.setAcceptDrops(True)
        self.label.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.label.setFrameShadow(QtWidgets.QFrame.Plain)
        self.label.setLineWidth(1)
        self.label.setTextFormat(QtCore.Qt.AutoText)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setOpenExternalLinks(True)
        self.label.setObjectName("label")
        self.verticalLayout_2.addWidget(self.label)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.radioButton_DirGif = QtWidgets.QRadioButton(GifSpliter)
        self.radioButton_DirGif.setChecked(True)
        self.radioButton_DirGif.setObjectName("radioButton_DirGif")
        self.horizontalLayout.addWidget(self.radioButton_DirGif)
        self.radioButton_DirSpec = QtWidgets.QRadioButton(GifSpliter)
        self.radioButton_DirSpec.setChecked(False)
        self.radioButton_DirSpec.setObjectName("radioButton_DirSpec")
        self.horizontalLayout.addWidget(self.radioButton_DirSpec)
        self.radioButton_DirApp = QtWidgets.QRadioButton(GifSpliter)
        self.radioButton_DirApp.setChecked(False)
        self.radioButton_DirApp.setObjectName("radioButton_DirApp")
        self.horizontalLayout.addWidget(self.radioButton_DirApp)
        self.verticalLayout_2.addLayout(self.horizontalLayout)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.label_2 = QtWidgets.QLabel(GifSpliter)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout_2.addWidget(self.label_2)
        self.textEdit_DirSpec = QtWidgets.QTextEdit(GifSpliter)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Ignored)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textEdit_DirSpec.sizePolicy().hasHeightForWidth())
        self.textEdit_DirSpec.setSizePolicy(sizePolicy)
        font = QtGui.QFont()
        font.setPointSize(9)
        font.setBold(False)
        font.setWeight(50)
        self.textEdit_DirSpec.setFont(font)
        self.textEdit_DirSpec.setObjectName("textEdit_DirSpec")
        self.horizontalLayout_2.addWidget(self.textEdit_DirSpec)
        self.checkBox_openDirSpec = QtWidgets.QCheckBox(GifSpliter)
        self.checkBox_openDirSpec.setObjectName("checkBox_openDirSpec")
        self.horizontalLayout_2.addWidget(self.checkBox_openDirSpec)
        self.verticalLayout_2.addLayout(self.horizontalLayout_2)
        self.verticalLayout_2.setStretch(0, 1)

        self.retranslateUi(GifSpliter)
        QtCore.QMetaObject.connectSlotsByName(GifSpliter)

    def retranslateUi(self, GifSpliter):
        _translate = QtCore.QCoreApplication.translate
        GifSpliter.setWindowTitle(_translate("GifSpliter", "GIF文件分割器 v3.0"))
        self.label.setText(_translate("GifSpliter", "<html><head/><body><p align=\"center\">GIF文件分割器:   可以快速将GIF文件分割成逐帧PNG文件</p><p align=\"center\">-------------------------------------------------------------</p><p align=\"center\">使用方法:</p><p align=\"center\">将GIF文件或含有多个GIF的文件夹拖拽进此窗口即可</p><p align=\"center\">程序会自动分解所有拖拽进来的GIF并分解成单张PNG文件</p><p align=\"center\">可以在下面单选按钮中选择PNG文件输出位置</p><p align=\"center\">如果需要选择生成到特定文件夹,需要指定输出文件夹</p><p align=\"center\"><br/>-------------------------------------------------------------</p><p align=\"center\"><a href=\"https://guagefangzhen.cn/\"><span style=\" text-decoration: underline; color:#0000ff;\">更多分享:https://guagefangzhen.cn</span></a><br/></p></body></html>"))
        self.radioButton_DirGif.setText(_translate("GifSpliter", "生成到GIF所在目录"))
        self.radioButton_DirSpec.setText(_translate("GifSpliter", "生成到指定目录"))
        self.radioButton_DirApp.setText(_translate("GifSpliter", "生成到程序所在目录"))
        self.label_2.setText(_translate("GifSpliter", "指定输出目录:"))
        self.textEdit_DirSpec.setHtml(_translate("GifSpliter", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">指定分割帧文件输出路径</p></body></html>"))
        self.checkBox_openDirSpec.setText(_translate("GifSpliter", "分割后打开目录"))
import res_rc
# 用于定义gif分割程序
import os
import imageio


class GifSplitter:
    def __init__(self, gif_file):
        self.gif_file = gif_file
        self.gif = imageio.get_reader(gif_file)

    def get_gif_info(self):
        """获取gif信息"""
        info = {}
        info['file_name'] = os.path.basename(self.gif_file)
        info['folder_path'] = os.path.dirname(self.gif_file)
        info['total_frames'] = len(self.gif)
        return info

    def export_frames(self, save_folder=None):
        """导出gif所有帧为png图片"""
        if save_folder is None:
            save_folder = os.path.join(self.get_gif_info()['folder_path'],
                                       'splitted')
            if not os.path.exists(save_folder):
                os.mkdir(save_folder)

        for i, frame in enumerate(self.gif):
            imageio.imsave(os.path.join(save_folder, '{}-{:03d}.png'.format(
                self.get_gif_info()['file_name'], i)), frame)
        print(f'完成分割: "{(os.path.basename(self.gif_file))}" | 输出文件夹-->"{save_folder}"')


    @classmethod
    def split_gifs_in_folder(cls, folder_path, save_folder=None):
        """分割文件夹内所有的gif文件"""
        print(f'拖拽文件夹为:"{folder_path}"')
        print(f'输出文件夹为:"{save_folder}"')
        if save_folder is None:
            save_folder = os.path.join(folder_path, 'splitted')
            if not os.path.exists(save_folder):
                os.mkdir(save_folder)

        gif_files = [file for file in os.listdir(folder_path)
                     if file.endswith('.gif')]

        i = 1
        for gif_file in gif_files:
            gif_splitter = cls(os.path.join(folder_path, gif_file))
            gif_splitter.export_frames(save_folder)
            print(f'文件夹处理进度: {i}/{len(gif_files)}')
            i = i + 1

if __name__ == '__main__':
    # 分割单个gif文件
    gif_splitter = GifSplitter('test.gif')
    gif_splitter.export_frames(save_folder="gif")

    # 分割文件夹内所有gif文件
    GifSplitter.split_gifs_in_folder('gif_folder')

【Python】Streamlit应用 “这个班上的值不值”

“这个班上的值不值” Web版

做了一个Streamlit的练手应用,用于测算“工作的性价比”。

非严谨计算,请勿认真对待,xD。

挂在服务器上了,比较轻量,应该不会下线,可以分享给朋友玩一下http://175.24.226.62:8501/

缘由

去年在某位群友的分享下,碰到一个很有意思的一个excel小应用。

一个挺有意思的小应用,一点职场人的茶余饭后的小话题。玩了两下后思考了一下,这个做成excel属实是不方便好友分享,如果做成一个web版的或者小程序版本,不是更好?这个想法就这样一直留在todo list里了。

最近工作太忙了,但是为了不被眼下的工作完全淹没自己,还是逼迫自己慢慢的完成一些todo list上的事。因为,我坚持认为,人除了要赚眼前的填饱肚子的月供之外,也要持续的坚持学习新东西,做一些对长远规划有用的东西。

五月份某天在学习调研dashboard和streamlit的时候,想起这个“这个班上的值不值”的应用,就把它当做一个学习练手的小task做了,并且部署到了我的轻量级服务器上。


做法分享:

简单来讲,就是分为两步:

1、基于python streamlit写脚本,开发一个应用。

2、将调试好的streamlit应用部署到服务器上。

主要要点:

1、我的开发环境是Anaconda+Pycharm,这也是主流的比较推荐的python科学研究的开发环境;

2、Streamlit相关的资料还是比较少,主要建议上官网看他的一些API说明:

Streamlit官方Documentation(推荐):https://docs.streamlit.io/

也有个国人做的学习手册(施工中):http://cw.hubwiz.com/card/c/streamlit-manual/

然后有了一些基础概念后,就可以面对AI编程了,哈哈。

3、我是梳理了一下应用,基本很快就确定了一个框架:siderbar作为参数输入,然后右边做输出和说明展示的。进而开始coding。

import streamlit as st

with st.sidebar:
    st.title('输入参数')
    salary = st.number_input('平均日薪酬(RMB)', value=100, min_value=50, step=25)
    work_t = st.number_input('工作时长(单位:小时,下班时间-上班时间)', value=8.0, min_value=1.0, step=0.5)
    trans_t = st.number_input('通勤时长(单位:小时,上下班花在路上的通勤时间)',value=1.0,step=0.25)
    slack_t = st.number_input('摸鱼时间(单位:小时,吃饭+不干活+午休)',value=1.0,min_value=0.0,step=0.25)

    st.title('相关系数')
    edu = st.number_input('学历系数',value=1.0,step=0.2,min_value=0.8,max_value=2.0)
    with st.expander('系数说明'):
        st.text('专科及以下 0.8\n普通本科  1.0\n高级本科  1.2\n普通硕士  1.4\n高级硕士  1.6\n普通博士  1.8\n高级博士  2.0')
    env_working = st.number_input('工作环境系数',value=1.0,step=0.2,min_value=0.8,max_value=1.1)
    with st.expander('系数说明'):
        st.text('偏僻地区  0.8\n工厂户外  0.9\n普通     1.0\n体制内   1.1')
    env_female = st.number_input('异性环境指数',value=1.0,min_value=0.9,max_value=1.1,step=0.1)
    with st.expander('异性指数说明'):
        st.text('没有      0.9\n不多不少  1.0\n很多     1.1')
    env_coleg = st.number_input('同事环境系数', value=1.0, min_value=0.95, max_value=1.05, step=0.05)
    with st.expander('同事环境系数说明'):
        st.text('SB很多   0.95\n普通很多   1.0\n优秀很多  1.05')
    env_career = st.number_input('职业资格系数', value=1.0, min_value=1.0, max_value=1.15, step=0.05)
    with st.expander('职业资格系数说明'):
        st.text('无要求、二级    1.0\n建造造价监理    1.05\n建筑岩土结构    1.1\n主任医师、教授  1.15')
    early_working = st.number_input('是否在8:30前上班', value=1.0, min_value=0.95, max_value=1.0, step=0.05)
    st.text('是否8:30前上班? 是:0.95, 否:1.0')
    final_ratio = st.number_input('综合环境系数(不要改)', value=1.0, max_value=1.1, min_value=0.9, step=0.05)

point = salary*final_ratio/(35*(work_t+trans_t-0.5*slack_t)*edu*env_career)*early_working*env_coleg*env_female

st.title(':male-technologist:这个班上的值不值?')


st.caption(f"您的工作性价比指数为: _%.2f_" % point)
if point<=0.8:
    text_out = '参考评价:您的工作:green[很惨]~~~  :weary:'
elif point<=1.5:
    text_out = '参考评价:您的工作:blue[一般]. :expressionless:'
elif point<=2.0:
    text_out = "参考评价:您的工作:red[很爽]~~!  :stuck_out_tongue_winking_eye:"
else:
    text_out = "参考评价:您的工作:red[爽到爆炸]~~~!!!  :sunglasses:"
st.caption(text_out)
st.caption('_这是一个娱乐性APP,通过对在左侧侧边栏<-输入的几个参数进行计算,评估自己这个班上的值不值~_')
st.caption('_仅为博君一笑,请勿认真对待~!_')

with st.expander("计算公式说明:"):
    st.image('img.png')
st.write('[Powered by 瓜哥 using "streamlit"](https://guagefangzhen.cn)')

4、Streamlit的发布到服务器,我百度了看到的基本都是用Docker环境安装streamlit环境。我的想法更简单: 服务器上装了miniconda –> 在miniconda里装Streamlit环境 –> 在Streamlit虚拟环境中启动上传的 JobPerformanceCalculator.py

5、Streamlit中的启动,需要添加nohup命令。这样你就可以在运行后关闭这个命令窗口,而应用一直会在服务器后台运行了。

nohup streamlit run JobPerformanceCalculator.py

COMSOL 自动化脚本批量导出动画 内置JAVA脚本

1、设定好几个要导出的动画;

2、然后录制宏,并写好循环方法;

for (int i = 1; i <= 9; i++) {
  model.result().export("anim"+i).run();
}

3、同时做好COMSOL设置;

4、运行第二步的方法即可;

以上是装B操作。


以下是真正全民适用的简单操作。

好吧,我发现如果只是需要导出全部内容,可以用:


小广告:COMSOL相关问题可以加琳泓大佬的群去找群友讨论

新群:569822214

开放群:566811107
群一:836281296
群二:594368389
群三:1080606488
群四: 678357196

车灯仿真介绍04:车灯光学仿真

本站合作作者:柚子序

现在的汽车智能化越来越高,车灯不再像从前一样只是简单地路面照明和信号提示的作用,而是具有体现车体美学和智能的铺路效果,更多的交互体验的作用。随着光源的发展,LED正在慢慢替代传统的卤素灯泡,LED体积小,寿命长,光效高,促使车灯造型以及光学实现方式变得越来越丰富,这就需要去做更优光学设计及仿真。

车灯光学的设计分为两大类,一个是照明类,一个是成像类。 照明类的主流软件是lucid shape、speos;成像类的主流软件是zemax、codeV。成像类的主要包括抬头显示,投影logo灯,投影大灯;照明类的灯具,主要包括远近光,前雾灯,角灯,阅读灯等主要起照明作用的灯具;昼行灯,转向灯,位置灯,刹车灯等主要起信号指示类的灯具,以及内饰中起情感交互作用的氛围灯。

照明类灯具的发展越来越成熟,越来越朝着数字化、智能化发展。光学的实现方式也越来越多样化,从常规的反射镜,扩散片,到导光条,厚壁件,导光板或者几种方式的混合,再到各种微观透镜,微观薄膜的应用,让汽车灯具越来越成为汽车更重要的美学代表。这让光学设计,不只是简单的涉及法规达不达标,更重要的是点亮效果的均匀性要求,相同功能的协同性以及不同功能之间的协调性。光学设计是在有限的空间基础上,用最优的方式实现客户需要的效果,并提供效果图,分析其中的问题点与风险点,让客户在没有实灯的情况下能够立体地了解目前的造型和方案可以达到什么样的效果。

下面,简单地分享一下光学仿真设计的过程,以及效果图,向各位同行请教与交流。

首先,我们需要客户提供的输入:包括效果图,功能区域,初始数据(当然也可以指定配光方式);然后我们根据客户给定的空间进行配光分析及设计,通过反复修改及调整光学面或光学体以达到要求;然后出具配光报告,包括光强分布、各个视角的点亮效果图、问题点及建议。现在以导光条方式的高刹灯为例:

1、从结构工程师那里获取输入:地面线、是否安装在车内、玻璃的透过率、光导引导线、面罩及出光面区域等初始数据;校核安装高度及可视角是否满足法规,如若安装在车内且已知玻璃透过率,可以初步确认LED型号及功率。

2、按照给定的出光面及引导线开始配光,如果引导线不合理,适当进行调整并与结构工程师确认,再确定导光条的截面,然后调整导光条的起始角和结束角,对导光齿的宽度、间隙及半径等参数进行优化,在优化的过程中关注光斑的分布及部分角度的点亮效果。

考虑到加工以及入光端光斑的问题增加圆角以及混光结构

软件操作界面

3、将光学结构输出给结构工程师,加上安装结构再进行仿真,发现问题找到原因并提出建议修改后,再进行最终的仿真确认,提供多角度的分析,检查是否存在明显亮点。

HV
H20
H70

以上是分享导光条做高刹灯的简略情况,欢迎各位同行一起交流和探讨。

【Matlab】Matlab插值函数

当我们需要利用Matlab对某些二维表格进行插值函数的输入的时候,类似将下表的数据,编辑成一个插值函数的的时候。

代码如下:

function R_out = ROEM (T_in,SOC_in) % T_in, SOC_in分别为插值T、SOC数据
%% 输入待插值表格数据 t、soc、R
t=[273.15	288.15	298.15	308.15	318.15];
soc = [1 0.8	0.6	0.4	0.2	0.1	0];
R = [37.47	22.88	24.74	26.42	32.71	56.83	98.76;
26.15	18.02	13.85	12.76	16.32	43.76	72.5;
11.21	9.43	7.24	7.63	8.34	15.21	38.90;
10.08	8.78	6.78	7.29	10.21	16.15	33.22;
9.02	7.88	6.31	6.66	7.53	13.49	29.76];
%% 对T、SOC进行数据网格化
[SOC,T]=meshgrid(soc,t);
%% 展示出图
% surf(SOC,T,R);
%% 对输入数据进行插值
% T_in = 275;SOC_in = 0.5;
R_out=interp2(SOC,T,R,SOC_in,T_in,'linear');
end