当前位置: 首页 > news >正文

数学建模----拟合的实现

一次作业展示

我用的是Python编写程序。也就 Scipy 里的 curve_fit指令

curve_fit指令是由一点小问题的。

我们小看一下具体的问题

  • 引入相关包
from scipy.optimize import curve_fit
import matplotlib
import matplotlib.pyplot as plt

matplotlib.rcParams["font.sans-serif"] = ["SimHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
  • 定义需要你拟合的函数
def fun(t,a,b,c):
    return a + b*t + c*t**2
  • 定义界限
#bounds
bounds = [[0,0,0],[1,2,3]]
#表示 amin,bmin,cmin ; amax,bmax,cmax
  • 设置参数并开始拟合
x = [0.01 * i for i in range(1000)]
y = [0.7+1.5*i+2.1*i**2 for i in x]

p_fit,pcov = curve_fit(fun,x,y,bounds=bounds)
a,b,c = p_fit.tolist()
print("a "+str(a))
print("b "+str(b))
print("c "+str(c))

>>>a 0.7000000000000016
>>>b 1.4999999999999993
>>>c 2.1
  • tips  实际工作的时候,你会发现,这个工作绝对没有我这里展示得这么简单。
    • parameters
      • 你会发现,虽然它有很多个参数,但非数学学院的孩子可能已经发现,这个恐怕是略有难度的(请上官网阅读)
      • xdata
      • ydata
      • bounds
    • return 
      • popt  
        • 按照SSE最小的原则选出的最优参数
      • pcov
        • 协方差矩阵
    • Raises
      • ValueError
        • xdata 或 ydata 中含有 Not a Number
      • RuntimeError
        • 最小二乘法跑不动啦
      • OptimizeWarning
        • 协方差矩阵无法估计得出
  • 采样曲线

     

  •  数据先期处理
    • 前段数据明显有很大的偏差,是一个很不合理的数据。所以清洗掉前 50 个数据后我
      们得到图像,这个图像就合理多了。  

 

  • 我们最好使用一个指数函数来描述它的降落。但也许一个多项式函数也很有价值呢?所
以我们选择指数函数与多项式函数的叠加,但加上系数,例如V=f_1V_0exp(at)+f_2P(t^n)
我们很顺利得得到

 

        

 

  • 参数
    • V0

      10.999999999574499

      a

      -0.000498879687115049

      b

      -0.2948910057472579

      c

      0.00474997000539258

      d

      -8.960374326579795e-07

    • 残差 SSE=  0.8664783171803022
import xlrd as xl
import matplotlib.pyplot as plt
import matplotlib
import math
from scipy.optimize import curve_fit
matplotlib.rcParams["font.sans-serif"] = ["SimHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
data = xl.open_workbook("附件2 电池放电测试(30A)采样数据.xls")
work_sheet = data.sheets()[0]
all_rows = work_sheet.nrows
time,voltage = [0 for i in range(all_rows-1)],[0 for i in range(all_rows-1)]
for i in range(1,all_rows):
    time[i-1] = work_sheet.cell_value(i,0)
    voltage[i-1] = work_sheet.cell_value(i,1)
#plt.plot(time,voltage,label="电池放电")
#plt.xlabel("放电时间")
#plt.ylabel("电压",rotation=True)
#plt.legend()
#plt.savefig("电池放电原始记录,jpg")
#plt.cla()
#plt.plot(time[5:],voltage[5:],label="电池放电")
#plt.xlabel("放电时间")
#plt.ylabel("电压",rotation=True)
#plt.legend()
#plt.savefig("电池放电清洗后记录,jpg")
start = 50
time = time[start:]
voltage = voltage[start:]
plt.scatter(time,voltage,marker="o",c="red",s=0.5)
def fun(t,v0,a,b,c,d):
    #v0*math.e**(a*t)+
    #+(b*t+c*t**2+d*t**3)
    #return v0*math.e**(a*t)+(b+c*t+d*t**2)
    return v0*math.e**(a*t)+(b+c*t+d*t**2)
p_fit,pcov = curve_fit(fun,time,voltage,bounds=[[9,-2,-2,-2,-2],[11,2,2,2,2]])
v0,a,b,c,d = p_fit.tolist()
time0 = [i for i in range(start,int(time[-1]))]
plt.plot(time0,[fun(i,v0,a,b,c,d) for i in time0],linestyle="-.",c="b",linewidth=2)
SSE = sum([(fun(time[i],v0,a,b,c,d)-voltage[i])**2 for i in range(len(time))])
plt.xlabel("放电时间")
plt.ylabel("电压",rotation=True)
plt.savefig("电池放电拟合图.jpg")
plt.show()
print(SSE)
  • 为了缩减误差,我们将每个电压值减去9,做同样的操作后,得到

 

 

  • 参数
    • V0

      1.5999999999996954

      a

      -0.0011712982921128377

      b

      0.10761472318925852

      c

      0.0010752299243068316

      d

      -4.353127243058634e-07

    • 残差 SSE=  1.0248705943495118
import xlrd as xl
import matplotlib.pyplot as plt
import matplotlib
import math
from scipy.optimize import curve_fit
matplotlib.rcParams["font.sans-serif"] = ["SimHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
data = xl.open_workbook("附件2 电池放电测试(30A)采样数据.xls")
work_sheet = data.sheets()[0]
all_rows = work_sheet.nrows
time,voltage = [0 for i in range(all_rows-1)],[0 for i in range(all_rows-1)]
for i in range(1,all_rows):
    time[i-1] = work_sheet.cell_value(i,0)
    voltage[i-1] = work_sheet.cell_value(i,1)
start = 50
time = time[start:]
voltage = voltage[start:]
voltage = [i-9 for i in voltage]
plt.scatter(time,voltage,marker="o",c="red",s=0.5)
def fun(t,v0,a,b,c,d):
    #v0*math.e**(a*t)+
    #+(b*t+c*t**2+d*t**3)
    #return v0*math.e**(a*t)+(b+c*t+d*t**2)
    return v0*math.e**(a*t)+(b+c*t+d*t**2)
p_fit,pcov = curve_fit(fun,time,voltage,bounds=[[1.4,-10,-10,-10,-10],[1.6,10,10,10,10]])
v0,a,b,c,d = p_fit.tolist()
time0 = [i for i in range(start,int(time[-1]))]
plt.plot(time0,[fun(i,v0,a,b,c,d) for i in time0],linestyle="-.",c="b",linewidth=2)
SSE = sum([(fun(time[i],v0,a,b,c,d)-voltage[i])**2 for i in range(len(time))])
plt.xlabel("放电时间")
plt.ylabel("电压",rotation=True)
plt.savefig("电池放电拟合图.jpg")
plt.show()
print(SSE)
  • SSE变化不大,还行,说得过去。

    其实这个问题还可以用更高级的方法解决。函数的主体部分一定是一个指数函数。至于误差的话,可以用支持向量机估计。

    但是,最重要的问题是,电池电压的变化是有一定科学函数关系的。不太可能是随意给一个函数的。

    我们查阅文献。

    得到一个更好的方程V(T)=a+\sqrt{c-T}

a

8.775331053692842

b

0.03661353006471206

c

2600.000378465227

SSE

0.9081344248801957

import xlrd as xl
import matplotlib.pyplot as plt
import matplotlib
import math
from scipy.optimize import curve_fit
matplotlib.rcParams["font.sans-serif"] = ["SimHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
data = xl.open_workbook("附件2 电池放电测试(30A)采样数据.xls")
work_sheet = data.sheets()[0]
all_rows = work_sheet.nrows
time,voltage = [0 for i in range(all_rows-1)],[0 for i in range(all_rows-1)]
for i in range(1,all_rows):
    time[i-1] = work_sheet.cell_value(i,0)
    voltage[i-1] = work_sheet.cell_value(i,1)
start = 50
time = time[start:]
voltage = voltage[start:]
plt.scatter(time,voltage,marker="o",c="red",s=0.5)
def fun(t,v0,a,b,c,d):
    return a+b*(c-t)**0.5
p_fit,pcov = curve_fit(fun,time,voltage,bounds=[[9,0,0,2600,0],\
                                                [11,10,10,4600,10]])
v0,a,b,c,d = p_fit.tolist()
time0 = [i for i in range(start,int(time[-1]))]
plt.plot(time0,[fun(i,v0,a,b,c,d) for i in time0],linestyle="-.",c="b",linewidth=2)
SSE = sum([(fun(time[i],v0,a,b,c,d)-voltage[i])**2 for i in range(len(time))])
plt.xlabel("放电时间")
plt.ylabel("电压",rotation=True)
plt.savefig("电池放电拟合图.jpg")
plt.show()
print(SSE)


  • 这样的残差平方和事实上已经很小了,只是你要明白一点就是,电池的结构决定了电池的放电规律不太可能用一个初等函数来表示。更有可能是一个更复杂的方程,这是由电池决定的,而不是有观测值决定的。

    电池的放电规律与一般得分类问题不同,它是很难得到检验的。我们不能通过选取一个阶段的放电,将它与预测值比较来反映模型的准确性。即使考虑最简单的RLC电路,方程的解也不是严格得如我们的预测方程所示。

    我们的拟合最多能够给出电池的放电结束时间,而且不一定准确。我们的拟合使函数尽可能得符合曲线而不是趋近物理事实,这是不合理的。或者对于同样的一块电池,预估放电时间与电压的关系。

    研究物理过程不能只从现象观察,应该去研讨物理规律。当然,更加好的一个办法呢,还是使用分段函数来做它,在放电的最初阶段和最末阶段,电压的下降速率远远大于中间阶段,在物理过程不明晰的情况下,还是分段研究比较合理。

  • 如果从软件使用的角度来看,我们初始值的选取是十分重要的。Science Python的curve_fit和Mathematica 的智能程度远远低于matlab或者其他软件。即使是使用Matlab,初始值的选取也能大大得减少运算时间。对于初始值怎么选呢?慢慢调参吧。。

相关文章:

  • v-bind用法详解
  • Java实现随机人名抽取
  • 泰克TDS3012C数字荧光示波器TDS3012C
  • LSTM介绍理解
  • 深度学习——day27 class1 week3 神经网络概览及表示
  • 六级高频词汇——Group06
  • 云计算(一)-理解云计算
  • JavaEE——No.1 多线程案例
  • MySQL如何优化性能
  • 【C语言】自定义类型—位段、枚举、联合体
  • opencv从入门到精通 哦吼 05
  • 计算机毕业设计 基于HTML+CSS+JavaScript 大气的甜品奶茶美食餐饮文化网页设计与实现23页面
  • Gadmin企业级开发平台V5.0.9版本发布
  • Linux内核设计与实现 第十六章 页高速缓存与页回写
  • HttpServer 5 框架【自定义注解(1)-了解注解、使用第三方库】
  • 【Leetcode】101. 对称二叉树
  • 【前端学习】-粗谈选择器
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • Github访问慢解决办法
  • Gradle 5.0 正式版发布
  • gulp 教程
  • input实现文字超出省略号功能
  • JavaScript创建对象的四种方式
  • SQLServer之创建数据库快照
  • 服务器从安装到部署全过程(二)
  • 记一次用 NodeJs 实现模拟登录的思路
  • 看域名解析域名安全对SEO的影响
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 巧用 TypeScript (一)
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 入门级的git使用指北
  • 使用parted解决大于2T的磁盘分区
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • HanLP分词命名实体提取详解
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (3)(3.5) 遥测无线电区域条例
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (五)c52学习之旅-静态数码管
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • .htaccess配置重写url引擎
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET框架
  • .NET连接数据库方式
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • /etc/skel 目录作用
  • [1] 平面(Plane)图形的生成算法
  • [ACTF2020 新生赛]Include