- python是面向对象(每个对象包含标识、类型、值的信息)的,对象的本质就是:一个内存块,拥有特定的值,支持特定类型的相关操作 。变量:对象的引用。
- Python 中“一切皆对象”, 所有的赋值操作都是“引用的赋值”
【OOP】(Object-oriented programming )面向对象编程将数据和操作数据相关的方法封装到对象中,组织代码和数据的方式更加接近人的思维,从而大大提高了编程的效率。
简介
Tips操作:
- dir() :获得一个对象的所有属性和方法(print(dir(Student)),其中Student是一个类或者实例对象),它返回一个包含字符串的list;
- obj.__dict__ :返回对象的属性字典(print(Student.__dict__));
- pass 为空语句。就是表示什么都不做,只是作为一个占位符存在。当你写代码时,遇到暂时不知道往方法或者类中加入什么时,可以先用 pass 占位,后期再补上;
- isinstance :判断对象是不是指定类型,比如print(isinstance(xiaoming, Student))判断xiaoming是不是Student这个类的实例对象。
常用的概念
- 【类】(class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 【方法】:类中定义的函数。
- 【类变量】:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 【数据成员】:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 【方法重写】:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 【局部变量】:定义在方法中的变量,只作用于当前实例的类。
- 【实例变量】:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- 【继承】:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 【实例化】:创建一个类的实例,类的具体对象。
基础概念
对象的进化
- 简单数据:比如30.4,20等等(包含了加法、乘法等方法的对象);
- 数组:将同类型的数据放到一起。比如:整数数组[20,30,40],浮点数数组[10.2, 11.3, 12.4],字符串数组:["aa", "bb", "cc"]
- 结构体:将不同类型的数据放到一起,是C 语言中的数据结构(labview中的簇Cluster,python中的tuple)。比如:
struct resume{
int age;
char name[10];
double salary;
}; - 对象:将不同类型的数据、方法(即函数)放到一起,就是对象。相比结构体,对象不仅有数据,还有处理数据的方法。
一个Python对象包含如下部分:
- id (identity 识别码)
- type (对象类型)
- value (对象的值)
- 属性 (attribute)
- 方法 (method)
类对象、类属性和类方法
【类对象】(class object):当解释器执行class 语句时("class 类名:"),就会创建一个类对象。
- 两个数据成员——属性(类属性、实例属性)和方法(类方法、实例方法),类将行为和状态打包在一起;
- 属性 ⇔ 变量,方法 ⇔ 函数;
- 属性 + 方法 = 对象;
- 类对象——做饼干的模具,实例对象(类的实例)——根据这个"模具"制造出的"饼干";
# coding: gbk
class Student: # 类名一般首字母大写,多个单词采用驼峰原则
#class Student默认是class Student(object)
pass #空语句
print(type(Student)) # 输出<class 'type'>,类也是对象
print(id(Student)) # 输出2350587049000
Stu2 = Student # 指向相同的内存地址
s1 = Stu2() # 实例化对象
print(id(s1)) # 输出2350594853408
print(s1) # 输出<__main__.Student object at 0x000002234A5F0A20>
print(type(Stu2)) # 输出:<class 'type'>
print(type(s1)) # 输出:<class '__main__.Student'>
上述代码的要点:
- 对于一个实例化对象obj
- print(obj) 打印的是对象的字符串表示形式,通常是 <__main__.ClassName object at 0x000002234A5F0A20> 这样的形式,其中0x000002234A5F0A20就是对象在内存中的地址,000002234A5F0A20十六进制转为10进制即得到2350594853408。
- print(id(obj)) 打印的是对象的唯一标识符,它是一个整数值,用于标识对象在内存中的位置。
- 在Python中,每个对象都有一个唯一的ID,可以使用 id() 函数获取它。因此,和打印的信息不同,但都与对象在内存中的位置有关。
- type类(模具类) → Student类 → s1
- 其中Student类是type类的实例对象,s1是Student类的实例对象。
- 在Python中,所有的类都是由 type 这个【元类】(metaclass)创建的。一个元类是用来创建类的类。 因此,任何类的类型都是 type。
- 当你创建一个类时,如 class Student: ...,Python实际上在后台执行 Student = type('Student', (object,), {...}),这意味着 type 是用来创建类的。
- print(type(Stu2)) # 输出:<class 'type'>表明Student类是type类的实例对象;
- print(type(s1)) # 输出:<class '__main__.Student'>表明s1是由 Student 类创建的实例对象;
【类属性】(class attributes)是从属于"类对象"(class object)的属性,也称为"类变量"。由于类属性从属于类对象,可以被所有实例对象共享。类属性的定义方式如下,在类中或类的外面,我们可以通过:类名.类变量名来读写
class 类名:
类变量名 = 初始值
类属性的3种修改方法:
# coding: utf-8
# 方法1:通过类本身修改
class Student:
company = "SXT" # 类属性
Student.company = "NewCompany" # 修改类属性
print(Student.company) # 输出: NewCompany
"""--------------------------------------------------"""
# coding: utf-8
# 方法2:通过类方法修改
class Student:
company = "SXT" # 类属性
@classmethod
def change_company(cls, new_company):
cls.company = new_company
Student.change_company("NewCompany") # 使用类方法修改类属性
print(Student.company) # # 打印修改后的类属性: NewCompany
"""--------------------------------------------------"""
# coding: utf-8
# 方法3:通过类本身修改。
"""
Student.count = Student.count + 1
尽管这个语句位于实例方法中,但它明确地通过类名 Student 引用了类属性 count 并进行了修改
"""
class Student:
company = "尚学堂" # 类属性
count = 0 # 类属性
def __init__(self, name, score): # __int__表示构造方法,self必须位于第一个参数
self.name = name # 实例属性,传递参数,self表示当前对象本身
self.score = score
Student.count = Student.count + 1 # 计数器,每创建一个对象+1
s1 = Student("xiaoming", 82)
s2 = Student("xiahua ", 80)
s3 = Student("xiahua ", 95)
print(s2.count) # 输出3
【类方法】(class method)可以操作类属性,用法如下:
@classmethod
类方法名(cls [,形参列表])
# coding: gbk
class Student:
company = "SXT" # 类属性
@classmethod # 类方性,该句必须位于类方法的上一行
def printCompanys(cls,number_1,number_2): # 类方法名(cls [,形参列表])
print(cls.company)
print(number_1 + number_2)
Student.printCompanys(2,3)
# 输出 SXT 5
xiaoming = Student()
xiaoming.printCompanys(2,7) # 输出 SXT 9
xiaoming = Student(2,3) #报错 Student() takes no arguments
类方法中的 cls 代表类本身,而不是某个具体的实例。实例属性和实例方法属于具体的实例,因此在类方法中访问实例属性和实例方法会导致错误,因为类方法没有具体的实例可以操作,即还没有根据模具造出饼干,自然就无法访问饼干实例的属性和方法。
class Student:
company = "SXT"
def __init__(self, name):
self.name = name
@classmethod
def printDetails(cls):
# 错误:类方法中不能访问实例属性
print(cls.name)
def printName(self):
print(self.name)
# 创建实例
s = Student("John")
# 调用实例方法
s.printName() # 正常输出:John
# 调用类方法
Student.printDetails() # 报错:AttributeError: type object 'Student' has no attribute 'name'
子类继承父类方法时,传入cls是子类对象,而非父类对象。下面的例子中,虽然 identify_class 方法定义在 Parent 类中,但当 Child 类调用这个方法时,cls 会被绑定为 Child 类。这种行为确保了类方法在继承层次结构中的一致性和正确性。
class Parent:
@classmethod
def identify_class(cls):
print(f"This is {cls.__name__}")
class Child(Parent):
pass
# 调用父类的类方法
Parent.identify_class() # 输出:This is Parent
# 子类调用父类的类方法
Child.identify_class() # 输出:This is Child
cls 用于类方法: cls 是约定俗成的名字,表示类本身。它通常用于类方法(使用 @classmethod 装饰器的方法)。类方法第一个参数总是类对象本身。使用 cls 可以访问类属性和其他类方法。
self 用于实例方法: self 也是约定俗成的名字,表示实例本身。它用于实例方法(普通方法)。实例方法的第一个参数总是实例对象本身。使用 self 可以访问实例属性和实例方法。
实例属性、实例方法、内存
【实例属性】(instance attributes):从属于实例对象的属性。
- 实例属性一般在__init__()方法中通过如下代码定义:self.实例属性名 = 初始值
- 在本类的其他实例方法中,也是通过 self 进行访问:self.实例属性名
- 创建实例对象后,通过实例对象访问:
- obj01 = 类名() #创建对象,调用__init__()初始化属性
- obj01.实例属性名 = 值 #可以给已有属性赋值,也可以新加属性
【实例方法】(instance method):通常用来操作实例属性,是从属于实例对象的方法。实例方法的定义格式如下:
- def 方法名(self [,形参列表]),第一个参数必须为 self,self 指当前的实例对象。
- 调用实例方法时,不需要也不能给 self 传参,self 由解释器自动传参。
- 实例方法调用的本质:
- a = Student()
- a.say_score()
- 上面两句,解释器的翻译为:Student.say_score(a) # a就是self
- 实例方法和普通函数的区别:
- 方法调用时,通过对象来调用。方法从属于特定实例对象,普通函数没有这个特点;
- 直观上看,方法定义时需要传递 self,函数不需要;
类方法:
- 使用 @classmethod 装饰。
- 第一个参数是类本身,通常命名为 cls。
- 只能访问类属性和类方法,不能访问实例属性和实例方法。
实例方法:
- 没有装饰器,或者使用 @staticmethod 装饰。
- 第一个参数是实例本身,通常命名为 self。
- 可以访问实例属性、实例方法,以及类属性和类方法。
- __init__方法(构造方法,Constructor):
- 初始化创建好的对象,初始化指的是给实例属性赋值;
- 如果我们不定义__init__方法,系统会提供一个默认的__init__方法,如果我们定义了带参的__init__方法,系统不创建默认的__init__方法;
- __init__(self, argus)第一个参数固定为self,self指的就是刚刚创建好的实例对象(的地址),它可以在每个方法中使用,因为每个方法都有self;
- self
- Python中的 self相当于C++中的 self指针,JAVA和C#中的this关键字。Python中,self 必须为构造函数的第一个参数,名字可以任意修改。但一般遵守惯例,都叫做self。
- 类相当于图纸,类实例化后的对象才是能住人的房子。想一下如果有一排房子都是同一个图纸设计出来的,那么我们可以说这些房子属于同一个class类,但是房子的门牌号都不同,self就相当于门牌号码,用来区分每一个房子。
- Python面向对象的self究竟是什么?
- __new__方法:用于创建对象,但我们一般无需重定义该方法,先调用__new__方法创建对象,再用__init__方法初始化对象;
# coding: gbk
class Student:
company = "尚学堂" #类属性
count = 0 #类属性
def __init__(self,name,score):# __int__表示构造方法,self必须位于第一个参数
self.name = name # 实例属性,传递参数,self表示当前对象本身
self.score =score
Student.count = Student.count+1 #计数器,每创建一个对象+1
def say_score(self): # 实例方法,self必须位于第一个参数
print("我的公司是:",Student.company)
print(self.name,"的分数是",self.score)
#print("{0}的分数是:{1}".format(self.name,self.score))
aa = Student("高淇",18) # aa是实例对象,自动调用__init__()方法
aa.say_score()
# 输出: 我的公司是 尚学堂 高淇 的分数是 18
Student.say_score(aa)
# 输出: 我的公司是 尚学堂 高淇 的分数是 18
aa.salary = 10 #专门为aa添加新的属性-salary
print(aa.salary) # 输出: 10
print(dir(aa)) # 对象aa的所有属性、方法
print(aa.__dict__) #定义的属性字典
print(isinstance(aa,Student))
# 输出True,判断对象为aa是否为Student的实例对象
内存分析
其他
【静态方法】(static method):类里面定义一些与类对象无关的方法,不操作类的属性。静态方法和在模块中定义的普通函数没有区别,只不过静态方法放到了类的名字空间里,需要通过类调用。和类方法一样,静态方法无法调用实例属性和实例方法。用法如下:
@staticmethod
def 静态方法名([形参列表]) :
# coding: gbk
class Student:
company = "尚学堂" #类属性
count = 0 #类属性
@staticmethod # 必须位于静态方法上面一行
def add(a,b): # 静态方法
print("{0}+{1}={2}".format(a,b,(a+b)))
return a+b
Student.add(20,30) # 输出 20+30=50
私有属性和私有方法:
- Python 对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别;
- 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public);
- .类内部可以访问私有属性(方法);
- 类外部不能直接访问私有属性(方法);
- . 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
# coding: gbk
class Demo:
def __init__(self, name, uage):
self.uname = name
self.__uage = uage # 私有属性
def __age(self): # 私有方法
print("他的年纪是",self.__uage) #类内直接访问私有属性
d = Demo('Tom', 18)
print(d._Demo__uage) # 访问私有属性
d._Demo__age() # 调用私有方法
print(d.uage) # 直接方法私有属性,报错
print(d.Demo.uage) # 错误的方法访问私有属性,报错
类编码风格:
- 类名首字母大写,多个单词之间采用驼峰原则。
- 实例名、模块名采用小写,多个单词之间采用下划线隔开。
- 每个类,应紧跟“文档字符串”,说明这个类的作用。
- 可以用空行组织代码,但不能滥用。在类中,使用一个空行隔开方法;模块中,使用两个空行隔开多个类。
可能待补充:
- __del__方法(析构函数)和垃圾回收机制
- __call__方法和可调用对象
- 方法没有重载
- 私有属性和私有方法(实现封装)
- @property 装饰器
- 属性和方法命名总结
进阶
继承
- 继承可以让子类具有父类的特性,提高了代码的重用性;
- 从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法;
- 一个子类可以继承多个父类;
- 如果在类定义中没有指定父类,则默认父类是object类,也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,比如:__new__()
- 通过类的方法 mro()或者类的属性__mro__可以输出这个类的继承层次结构;
# coding: gbk
class Person:
def __init__(self,name,age):
self.name = name
self.__age = age
def say_age(self):
print(self.name,"的年龄是: ",self.__age)
class Student(Person):
def __init__(self,name,age,score):
self.score = score
Person.__init__(self,name,age)
s1 = Student("张三",18,85)
s1.say_age() # 输出:张三 的年龄是: 18
print(s1._Person__age) # 访问父类的私有属性,输出18
print(dir(s1)) #查看s1的所有属性方法
print(Student.mro()) # Method Resolution Order
# [<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
x
封装(隐藏)
隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只对外暴露"相关调用方法”。
通过前面学习的"私有属性、私有方法"的方式,实现“封装”。Python 追求简洁的语法,没有严格的语法级别的"访问控制符",更多的是依靠程序员自觉实现。
补充私有属性、私有方法
list是python的序列对象。list就是对象,它提供了若干种方法来让我们根据需求来调整整个列表(比如append,sort),但是我们不知道list对象里面的那些方法是如何实现的,也不知道list对象里面有哪些变量,这就是封装,只给我们需要的方法的名字。
多态
【多态】(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。在现实生活中,我们有很多例子。比如:同样是调用人的休息方法,张三的休息是睡觉,李四的休息是玩游戏,高淇老师是敲代码。同样是吃饭的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。 关于多态要注意以下 2 点: 1. 多态是方法的多态,属性没有多态。 2. 多态的存在有 2 个必要条件:继承、方法重写。
补充下面例子isinstance的介绍
# coding: gbk
# 多态
class Animal:
def shout(self):
print("动物叫了一声")
class Dog(Animal):
def shout(self):
print("小狗,汪汪汪")
class Cat(Animal):
def shout(self):
print("小猫,喵喵喵")
def animalShout(a):
if isinstance(a, Animal):
a.shout() # 传入的对象不同,shout方法对应的实际行动也不同
animalShout(Dog()) # 输出:小狗,汪汪汪
animalShout(Cat()) # 输出:小猫,喵喵喵
### 以下没有继承,所以不是多态
class A:
def fun(self):
print("我是小A")
class B:
def fun(self):
print("我是小B")
a = A()
b = B()
a.fun() #输出我是小A
b.fun() #输出我是小B,虽然函数名都是fun
材料科学(化学)中的多态:图中的材料都是C单质形成的物质,但是结构和性质不同,因而是不同的物质。
Some allotropes of carbon: 按顺序依次为:
- diamond
- graphite
- lonsdaleite
- C60
- C540
- C70
- amorphous carbon
- carbon nanotube
上面展示的其实就是C的同素异形体,从更大的概念上说,上面说的多态其实是【同质异形体】(polymorphism),比如Al2O3的多种晶型。进一步类比,OOP的多态前提是继承,其实就是保证我们这里化学组成相同,比如α-Al2O3和β-Al2O3都是继承自Al2O3,那么如果都调用space_group方法,得到的结果肯定不同。
仪器控制
海洋光学
注:这里给出了usb4000.py的驱动,可以学习一下,可能可以用pyvisa模块实现控制(类似labview)。
按照python-seabreeze以及对应的documentation的要求,安装相应的模块。我是在conda环境下运行的,python-seabreeze 默认为 cseabreeze 后端,于是可能存在找不到光谱仪的情况,参考github-#47。我的运行环境是pycharm-conda-python3.11。
实例-1-找到ocean optics设备
# coding: gbk
# 修改前
import seabreeze.spectrometers as sb
devices = sb.list_devices()
print(devices) # 无法找到设备,输出空[]
#%%
# 修改后
import seabreeze
seabreeze.use("pyseabreeze")
import seabreeze.spectrometers as sb
devices = sb.list_devices()
print(devices) # 能正确找到设备,输出 [<SeaBreezeDevice HR2000PLUS:HR+C0731>]
实例-2-光谱动态测量
可用,来自OceanOptics_spectrometer,我在我的环境下运行会出现问题:只有第一个图能正常测量,然后后面不断出新的图,但是没有任何内容。
解决办法:Pycharm-File-Setting-搜索"Show plots in tool window",选择不勾选。
import matplotlib.pyplot as plt
import numpy as np
import time
import seabreeze
seabreeze.use("pyseabreeze")
from seabreeze.spectrometers import Spectrometer, list_devices
devices = list_devices()
print(devices)
spec = Spectrometer(devices[0])
# Set integration time if needed
int_time = spec.integration_time_micros(10000)
wavelengths = spec.wavelengths()
intensities = spec.intensities()
# data = np.column_stack((wavelengths, intensities))
# fname = "bg_spectrum.txt"
# np.savetxt(fname, data, delimiter='\t')
# bg_data = np.loadtxt('bg_spectrum.txt')
# bg_signal = bg_data[:,1]
fig, ax = plt.subplots()
while True:
intensities = spec.intensities()
# intensities = intensities-bg_signal
ax.clear()
ax.plot(wavelengths,intensities,'r')
ax.set_xlabel('Wavelength (nm)')
ax.set_ylabel('Intensity (arb.unit)')
ax.set_xlim(200,1100)
# ax.set_ylim(0,7000)
plt.grid()
plt.pause(0.02)
if plt.waitforbuttonpress(timeout=0.1):
break
plt.show()
实例-3-光谱动态测量+保存
数据保存格式:第一列是测试的时间,第n行的[2:end]表示的是光谱强度。
# coding: gbk
import matplotlib.pyplot as plt
import numpy as np
import time
import seabreeze
seabreeze.use("pyseabreeze")
from seabreeze.spectrometers import Spectrometer, list_devices
devices = list_devices()
print(devices)
spec = Spectrometer(devices[0])
# Set integration time if needed
int_time = spec.integration_time_micros(500000)
wavelengths = spec.wavelengths()
intensities = spec.intensities()
# 初始化数据列表
data_list = []
fig, ax = plt.subplots()
while True:
intensities = spec.intensities()
data_list.append(intensities.tolist())
ax.clear()
ax.plot(wavelengths, intensities, 'r')
ax.set_xlabel('Wavelength (nm)')
ax.set_ylabel('Intensity (arb.unit)')
ax.set_xlim(200, 1100)
plt.grid()
plt.pause(0.1)
# 获取当前时间
current_time = time.strftime("%H:%M:%S", time.localtime())
data = [current_time, ' '.join(map(str, intensities))]
# 将数据保存到文件
with open("data.txt", "a") as file:
file.write(' '.join(map(str, data))+ "\n")
if plt.waitforbuttonpress(timeout=0.1):
break
plt.show()
Linkam冷热台T-96
利用python实现对T96的控制
前置步骤:从ZEISS下载MTB 2011,安装后即可然后找到LinkamSDK.dll和Linkam.lsk,然后根据github上的pylinkam项目的操作来。linkam-python资料—我的网盘。
第一版:存在的问题,温度控制和温度测试不是像labview那样的【多线程】multithreading。
import pandas as pd
import logging
import time
from pylinkam import interface, sdk
import matplotlib.pyplot as plt
logging.basicConfig(level=logging.DEBUG)
# 读取Excel文件
df = pd.read_excel('parameters.xlsx')
fig, ax = plt.subplots()
with sdk.SDKWrapper() as handle:
with handle.connect() as connection:
print(f"Name: {connection.get_controller_name()}")
print(f"Heater measurement: {connection.get_value(interface.StageValueType.HEATER1_TEMP)}")
print(f"Heater set-point before: {connection.get_value(interface.StageValueType.HEATER_SETPOINT)}")
time_aa = time.time()
for index, row in df.iterrows():
target_temperature = row['目标温度(摄氏度)']
ramp_rate = row['升温速率(度/min)']
hold_time = row['保温时间(min)']
# 设置目标温度为target_temperature
if not connection.set_value(interface.StageValueType.HEATER_SETPOINT, target_temperature):
raise Exception('Something broke')
connection.enable_heater(True)
# 设置升温速率为ramp_rate
if not connection.set_value(interface.StageValueType.HEATER_RATE, ramp_rate):
raise Exception('Something broke')
connection.enable_heater(True)
# 初始化x和y轴数据
x_data = []
y_data = []
# 在target_temperature保持hold_time
start_time = time.time()
while time.time() - start_time < hold_time * 60:
# 每隔1秒测一次实际温度
current_temperature = connection.get_value(interface.StageValueType.HEATER1_TEMP)
x_data.append(time.time() - time_aa)
y_data.append(current_temperature)
time.sleep(1)
# 实时显示温度和时间的x-y图
ax.plot(x_data, y_data)
plt.xlabel('Time (Seconds)')
plt.ylabel('Temperature (Celsius)')
plt.title(f'Temperature Profile for {target_temperature}°C')
plt.draw()
plt.pause(0.01)
connection.enable_heater(True)
print("Temperature has reached the target")
plt.show()
第二版:尝试多线程,失败,保温时间用RAMP_HOLD_TIME
import pandas as pd
import logging
import time
from pylinkam import interface, sdk
import matplotlib.pyplot as plt
import threading
logging.basicConfig(level=logging.DEBUG)
# 读取Excel文件
df = pd.read_excel('parameters.xlsx')
class TemperatureControlThread(threading.Thread):
def __init__(self, target_temperature, ramp_rate, hold_time, connection):
threading.Thread.__init__(self)
self.target_temperature = target_temperature
self.ramp_rate = ramp_rate
self.hold_time = hold_time
self.connection = connection
def run(self):
# 设置目标温度为target_temperature
if not self.connection.set_value(interface.StageValueType.HEATER_SETPOINT, self.target_temperature):
raise Exception('Something broke')
# 设置升温速率为ramp_rate
if not self.connection.set_value(interface.StageValueType.HEATER_RATE, self.ramp_rate):
raise Exception('Something broke')
# 设置保温时间为hold_time
if not self.connection.set_value(interface.StageValueType.RAMP_HOLD_TIME, self.hold_time):
raise Exception('Something broke')
# 启动加热器
self.connection.enable_heater(True)
# 等待保温结束
time.sleep(self.hold_time * 60)
# 关闭加热器
self.connection.enable_heater(False)
class TemperatureMeasurementThread(threading.Thread):
def __init__(self, connection):
threading.Thread.__init__(self)
self.connection = connection
self.x_data = []
self.y_data = []
def run(self):
while True:
# 每隔1秒测一次实际温度
current_temperature = self.connection.get_value(interface.StageValueType.HEATER1_TEMP)
self.x_data.append(time.time())
self.y_data.append(current_temperature)
time.sleep(1)
def get_data(self):
return self.x_data, self.y_data
with sdk.SDKWrapper() as handle:
with handle.connect() as connection:
print(f"Name: {connection.get_controller_name()}")
print(f"Heater measurement: {connection.get_value(interface.StageValueType.HEATER1_TEMP)}")
print(f"Heater set-point before: {connection.get_value(interface.StageValueType.HEATER_SETPOINT)}")
# 创建温度控制线程
control_threads = []
for index, row in df.iterrows():
target_temperature = row['目标温度(摄氏度)']
ramp_rate = row['升温速率(度/min)']
hold_time = row['保温时间(min)']
control_thread = TemperatureControlThread(target_temperature, ramp_rate, hold_time, connection)
control_threads.append(control_thread)
# 创建温度测量线程
measurement_thread = TemperatureMeasurementThread(connection)
measurement_thread.start()
# 启动温度控制线程
for control_thread in control_threads:
control_thread.start()
# 实时显示温度和时间的x-y图
while True:
x_data, y_data = measurement_thread.get_data()
plt.plot(x_data, y_data)
plt.xlabel('Time (Seconds)')
plt.ylabel('Temperature (Celsius)')
plt.title('Temperature Profile')
plt.draw()
plt.pause(0.01)
plt.show()