
简介一套面向化工过程模拟工程师的 MATLAB 与 Aspen HYSYS 实时通信接口脚本集用于解决 HYSYS 二次开发中外部程序难以轻松驱动模拟流程、实时获取运行数据的问题。整个压缩包共包含 8 个 .m 文件体积仅 4KB属于典型的轻量级实用工具集。这些脚本功能覆盖重要连接初始化、物性参数设置、求解器启停切换、动态模拟触发与时间步长读取等环节可帮助使用者快速构建自己的控制逻辑。用户只要在 MATLAB 环境下调用相应函数即可向 HYSYS 模型发送指令并回收结果进而结合算法工具开展流程优化、灵敏度分析、动态仿真等高级应用减少手工重复操作提升研究效率。当前已有 635 人学习下载适合具备一定 HYSYS 与 MATLAB 基础、希望提升仿真自动化水平的设计研究人员。1. m文件连HYSYS-MATLAB联合仿真一次解决批量改工况与数据回读做流程模拟最磨人的不是建模型而是重复性的工况计算。我在 Aspen HYSYS 里搭好一个精馏塔模型后要扫进料温度的灵敏度六十个点手动改一次、跑一次、记一次数据大半天就没了。m 文件在这里就是 MATLAB 脚本靠它把 HYSYS 变成能听指令的执行单元改进料、触发求解、回读产品数据全部交给循环。这就是 HYSYS 与 MATLAB 联仿的基本玩法也是标题里 m 文件的真正用途。适合谁要在 HYSYS 上做批量工况扫描、参数寻优、回归标定的工程师和研究者。这套组合不算新但接口细节的坑比想象多值得一次讲透。2. 连接机制与选型为什么m文件ActiveX是HYSYS联仿的默认路线HYSYS 和 MATLAB 之间的连接工程上基本只有一条主路ActiveX。原理一句话MATLAB 当客户端Aspen HYSYS 当 COM 服务端两边的每次属性读写都是一次跨进程调用。m 文件里你写的stream.TemperatureValue 350背后其实是 MATLAB 把数据封好包、交给 Windows、再递进 HYSYS 进程里执行。理解这一点后面所有关于速度和稳定性的坑都好解释。2.1 HYSYS对外接口Aspen仿真软件的Automation对象长什么样先看 HYSYS 暴露给外部的对象结构从上到下依次是 Application、SimulationCase、Flowsheet然后是具体的流股和单元操作。Application 是根代表整个 HYSYS 程序一个打开的 .hsc 案例是一个 SimulationCase每个案例里有且只有一个活跃的 Flowsheet流股 MaterialStreams、单元操作 Operations、能量流 EnergyStreams 都挂在它下面。这个层次是 Aspen 系软件自动化接口的通用框架HYSYS 和 Aspen Plus 都遵循但暴露出来的入口名字不一样。HYSYS 的 COM 接口属性命名有一个习惯凡是返回数值的基本都带Value后缀。温度是TemperatureValue压力是PressureValue摩尔流量是MolarFlowValue质量流量是MassFlowValue。这套命名在 Aspen 的自动化文档里叫属性实际用起来就是 MATLAB 里直接读写的字段。你要拿某个流股的数值先MaterialStreams.Item(流股名)拿到流股对象再点后面的Value属性思路非常直。用一段最小代码把层次摸一遍能验证连接是否成功hy actxserver(HYSYS.Application); caseObj hy.ActiveCase; fs caseObj.Flowsheet; disp(fs.Tag);这段的逻辑是先创建 HYSYS 的 COM 句柄hy再从活动案例取流程表Flowsheet最后显示它的标签名。fs.Tag是案例的标识字符串如果这里能打出东西说明对象通道已经通了一半。参数说明里有个容易踩的命名坑MATLAB 的case是关键字不能当变量名用所以上面写成caseObj直接写case ...会报语法错误。装 Aspen Plus 的同事如果照搬这套代码会翻车因为 Aspen Plus 的 ProgID 命名和 HYSYS 不一样通常是AP加版本号再加.Application的形式换版本就变。HYSYS 则稳定在HYSYS.Application这也是为什么大家默认拿 HYSYS 做 MATLAB 联调接口命名省心。2.2 MATLAB侧建立连接actxserver与actxGetRunningServer的选型MATLAB 连 HYSYS 有两种启动姿势。一种是 HYSYS 还没打开用actxserver(HYSYS.Application)直接拉起一个进程另一种是 HYSYS 已经开着、案例也加载好了用actxGetRunningServer(HYSYS.Application)去复用现有进程。两种方式我都在用但使用场景完全不同。actxserver适合自动化批量运行的场景脚本从零拉起 HYSYS不依赖人肉准备工作。缺点是你不知道它拉起来的实例是不是带默认空案例还得额外调Open加载 .hsc 文件。actxGetRunningServer适合调试期先把 HYSYS 界面打开、案例加载好再让 MATLAB 去挂接眼睛能盯着每一步变化。try hy actxGetRunningServer(HYSYS.Application); catch hy actxserver(HYSYS.Application); end hy.Visible 1;逻辑说明优先复用已在运行的 HYSYS 实例如果找不到再新起一个最后强制显示界面。调试期这个Visible 1非常关键改完工况你能亲眼看到 HYSYS 界面里的数值跟着跳比只看脚本输出踏实得多。参数说明HYSYS.Application是 HYSYS 注册到系统的 ProgID正常情况下不能改改了就找不到 COM 对象。如果这里报错先别怀疑代码优先查位数匹配——MATLAB 和 HYSYS 必须是同一位数32 位对 32 位、64 位对 64 位否则注册表里根本看不见这个类。我的连接习惯是封装成独立函数不散落在各处脚本里连接时返回两个东西句柄hy和是否由脚本启动的标志。后者在收尾时很重要由脚本启动的实例可以顺手关掉复用别人的实例不能乱关否则把工程师手动开着的 HYSYS 给杀了那才是真翻车。2.3 m文件做胶水层的边界什么时候值得用脚本驱动m 文件在里面不是替代 HYSYS 做模拟而是做编排和数据搬运本质是一层胶水。判断要不要上这套方案标准很简单同样的操作你要重复几次。只算三五个工况界面点一点更快脚本的编写调试成本反而高要扫几十个点、要做优化迭代、要把结果喂给 MATLAB 的统计或绘图工具脚本的价值就出来了。我一般会把脚本拆成五个文件按职责分干净文件名职责对外接口conn_hysys.m建立连接、清理进程hy conn_hysys(casePath)read_stream.m读取流股变量到结构体data read_stream(hy, Feed)write_stream.m写回变量并触发求解flag write_stream(hy, Feed, spec)solve_and_wait.m等待求解收敛ok solve_and_wait(hy, timeout_s)sweep_case.m批量工况扫描入口result sweep_case(hy, ranges)这样拆分的好处是主脚本从不直接碰 COM 对象所有跟 HYSYS 相关的调用都封装在函数内部。将来换了 HYSYS 版本、改了单位制只动对应的一两个函数不用满项目改脚本。这层封装用普通函数文件就够不必上 OOP 包装流程模拟的脚本架构越直白越不容易在半年后回看时懵。3. 用m文件读HYSYS数据从建立连接到把流股变量拽进工作区数据读取是联仿的第一块基石。你连上了 HYSYS下一步就是能把流程里的关键变量搬到 MATLAB 工作区里做计算。这一章我给出一套可以直接抄的读取函数再把遍历对象和单位换算两个最容易出错的点单独拆开讲。3.1 最小可用的读取脚本拿流股的温度压力流量最常见的需求是把一条流股的温度、压力、流量和组成读回来。下面的函数接受 COM 句柄和流股名返回一个结构体字段名固定方便后续统一处理function data read_stream(hy, streamName) fs hy.ActiveCase.Flowsheet; stream fs.MaterialStreams.Item(streamName); data.Name stream.Name; data.Temperature stream.TemperatureValue; data.Pressure stream.PressureValue; data.MolarFlow stream.MolarFlowValue; data.MassFlow stream.MassFlowValue; n stream.Components.Count; data.Composition zeros(1, n); for i 1:n data.Composition(i) stream.Components.Item(i).MolarFractionValue; end end逻辑说明MaterialStreams.Item(streamName)按名字取流股对象句柄链是hy - ActiveCase - Flowsheet - MaterialStreams每一步都是 HYSYS Automation 的标准对象层次。Components.Count拿组分数然后循环把每个组分的摩尔分率装进预分配数组。参数说明TemperatureValue这些属性返回的数值跟随 HYSYS 当前单位集不是固定国际单位。如果你的 HYSYS 装着默认的 Field 单位集温度可能是摄氏、压力可能是 bar必须统一换算这在 3.3 节展开。Composition的预分配是有意为之不要在循环里用data.Composition(i)动态扩展数组COM 调用本来就慢循环里再频繁重建数组会让读取函数变成性能黑洞。3.2 不按名字取流股遍历Flowsheet的Operations和MaterialStreams有些场景下你不知道流股叫什么或者要把整个流程所有流股一次性导出来做对比。HYSYS 的集合对象支持按索引遍历和按名字取是同一套接口。下面这段把案例里所有流股的关键变量导出成 MATLAB table方便直接writetable落盘function T export_all_streams(hy) fs hy.ActiveCase.Flowsheet; n fs.MaterialStreams.Count; data cell(n, 5); for i 1:n s fs.MaterialStreams.Item(i); data{i, 1} s.Name; data{i, 2} s.TemperatureValue; data{i, 3} s.PressureValue; data{i, 4} s.MolarFlowValue; data{i, 5} s.MassFlowValue; end T cell2table(data, VariableNames, ... {Name, T, P, MolarFlow, MassFlow}); end逻辑说明集合的Item方法既能按名字也能按索引取值遍历用索引Item(i)最稳定不会因为流股名字拼写问题中断。最后用cell2table把单元格数组转成表格字段名一次性给定。参数说明MaterialStreams.Count在案例较大时可能包含一些内部辅助流股导出的表里会出现你没见过的名字这在带循环物流或塔内部物流的流程里很常见不用慌按名字过滤掉就好。如果你想拿的是塔、换热器这类单元操作对象要用fs.Operations遍历方式一样ops fs.Operations; for i 1:ops.Count op ops.Item(i); if contains(op.Name, T-100) fprintf(%s: %s\n, op.Name, op.Type); end end逻辑说明op.Name是你在 HYSYS 界面上给单元操作起的标签op.Type是对象类型字符串比如塔就是列类型。参数说明不同 HYSYS 版本里Type字符串可能有细微差异判断时别用直接比用contains做模糊匹配宁可多匹配几个也不漏掉。3.3 单位换算HYSYS返回值和MATLAB默认单位不一致的处理单位问题是联仿里最阴的坑因为 HYSYS 不报错只是给你一个带着当前单位集数值的普通数字。你以为读进来的是开尔文实际上是摄氏 350 度拿去一算全盘皆错。我踩过一次这个坑后定了一条规矩脚本里所有涉及 HYSYS 数值的地方先明确单位再进计算。常见做法是两条路一是在 HYSYS 里把单位集统一改成 SI脚本里不做任何换算二是在 MATLAB 侧做一层换算函数HYSYS 保持工程单位不变。我推荐第二种因为很多工程师的 HYSYS 案例是客户给的单位集不能乱动。换算表按最常见的 Field 单位集列如下变量HYSYS 常见返回单位MATLAB 侧标准换算关系温度°CKT_K T_C 273.15压力bar(g)kPa(a)p_kPa p_bar * 100再处理表绝压摩尔流量kgmole/hkmol/h数值一致注意别名差异质量流量kg/hkg/h一致焓值kcal/kgkJ/kg乘以 4.1868压力换算是另一个重灾区。HYSYS 里表压和绝压都叫压力但数值基准差一个大气压。真空系统里表压是负的直接乘 100 再参与计算会得到负的绝压明显荒谬。function P_kPa bar2kPa(P_bar, gauge) P_kPa P_bar * 100; if gauge P_kPa P_kPa 101.325; % 表压转绝压加当地大气压 end end逻辑说明gauge为 true 时代表 HYSYS 返回的是表压转绝压要加大气压false 则不加。参数说明101.325 kPa 是标准大气压如果你在现场高海拔地区用当地大气压更准否则这个常数够用。我的习惯是读数时顺手把单位属性和数值一起记录下来放结构体里比如data.TemperatureUnit C计算前先检查宁多写一个字段也不裸奔。4. 用m文件写回HYSYS改进料、触发求解、批量工况扫描的完整套路读数据只是单行道真正解决批量工况问题的是写回。这一章把改流股变量、触发求解、批量扫描三件事串成完整链路给出一套可以直接跑通的最小实现。4.1 改流股变量把MATLAB算好的值写进HYSYS写回和读取共用同一个流股对象区别只是把赋值方向反过来。下面这个函数接受一个结构体spec里面带哪个字段就改哪个不强制调用方都给全function flag write_stream(hy, streamName, spec) fs hy.ActiveCase.Flowsheet; stream fs.MaterialStreams.Item(streamName); if isfield(spec, Temperature) stream.TemperatureValue spec.Temperature; end if isfield(spec, Pressure) stream.PressureValue spec.Pressure; end if isfield(spec, MolarFlow) stream.MolarFlowValue spec.MolarFlow; end if isfield(spec, Composition) for i 1:stream.Components.Count stream.Components.Item(i).MolarFractionValue spec.Composition(i); end end flag true; end逻辑说明isfield判断让调用方只传想改的字段比如只调温度就只写spec.Temperature不需要构造一个含全部字段的字典。赋值语句直接走Value属性和读取是对称的。参数说明Composition的长度必须和 HYSYS 流股里组分顺序一致顺序写反不报错但结果全错这种错误最坑因为输出看着合理实际张冠李戴。少数老版本 HYSYS 接口不支持直接给Value属性赋值要用更底层的SetPropertyValue按字符串名写。如果你遇到赋值后界面上数值纹丝不动的情况换成下面这种写法试试stream.SetPropertyValue(Temperature, spec.Temperature, SI);逻辑说明SetPropertyValue的三个参数分别是属性名、数值、单位制名称相对繁琐但兼容性更好。参数说明第三个参数传SI可以顺带解决单位问题让 HYSYS 内部先做转换再写入。我把这行当成兜底方案遇到直接赋值无效时才启用。4.2 触发运行与等待收敛while轮询的写法改完数值不等于求解完成。HYSYS 默认开启自动解算但批量改多个变量时每改一个就触发一次求解很浪费。更稳的做法是先把求解器打开改完全部变量后统一等待收敛。等待不能写死pause(10)不同工况迭代步数差异很大固定等要么不够要么浪费。function ok solve_and_wait(hy, timeout_s) solver hy.ActiveCase.SolverControl; solver.CanSolve 1; elapse 0; while elapse timeout_s if solver.IsConverged ok true; return; end pause(0.5); elapse elapse 0.5; end ok false; warning(HYSYS 求解超时请检查当前工况); end逻辑说明SolverControl是案例的求解器控制对象CanSolve 1允许求解器运行IsConverged轮询收敛标志。每次查询间隔 0.5 秒超时后返回 false 并警告交给调用方决定是跳过还是重跑。参数说明timeout_s给 30 到 60 秒比较合理稳态流程模型大多数几秒内就收敛局部循环多的会给到两分钟。轮询间隔 0.5 秒是我试过的平衡点太短会让 MATLAB 的查询调用挤占 CPU反而拖慢 HYSYS 的求解速度这是跨进程通信的固有开销。如果你发现每次返回 false 但 HYSYS 界面上明明收敛了检查一下是不是求解器被设成了手动模式SolverControl里有个求解状态属性能看到当前模式。4.3 批量工况扫描双层循环与结果矩阵批量扫描是这套方案里最实用的一环。下面这个例子扫描进料温度固定压力每个点跑一次求解读回产品纯度和产品温度最后汇总成表格function result sweep_temperature(hy, feedName, productName, T_list, P_fixed) n length(T_list); result table(); for k 1:n spec struct(); spec.Temperature T_list(k) 273.15; spec.Pressure P_fixed; write_stream(hy, feedName, spec); ok solve_and_wait(hy, 60); if ~ok row {T_list(k), NaN, NaN}; result [result; row]; %#okAGROW continue; end data read_stream(hy, productName); row {T_list(k), data.Temperature, data.Composition(1)}; result [result; row]; %#okAGROW end result.Properties.VariableNames {FeedT_C, ProdT, Purity}; end逻辑说明每轮循环按「写回、求解、读回」三步走。写回时已经在这里做了摄氏转转开的换算调用侧只管用工程单位思考。求解失败的行用 NaN 占位保证结果表行数完整不至于后面统计时对不上号。参数说明Composition(1)假设你要盯的组分排在 HYSYS 组分列表第一位。这个索引在流程一变就容易错我现在的写法是把这个组分名也作为参数传进来在函数内部用名字找到对应索引。批量扫描前先手动把原始 .hsc 文件另存一份备份脚本跑崩了 HYSYS 案例已经被改得面目全非没有备份就只能重新搭模型这比任何报错都让人崩溃。5. 联调避坑接口连不上、值写不进去、收敛被跳过这类问题怎么排查这一章写我实际踩过的坑每一条按现象、原因、解决三步拆开。这些坑不会每次都出现但只要出现一次没有排查思路就会卡掉半天。我把它们集中记在这里当排查手册用。5.1 连不上HYSYS实例先看位数和注册表现象actxserver(HYSYS.Application)直接抛错或者actxGetRunningServer提示找不到指定对象但 HYSYS 明明开着。原因最常见的是位数不匹配。HYSYS 装的是 64 位MATLAB 是 32 位COM 注册表里两边互相看不见MATLAB 按 ProgID 去查就查不到。其次是 HYSYS 安装后被动过目录或者杀毒软件拦截了 COM 注册注册表里的 ProgID 条目丢了。解决第一步查位数任务管理器确认 HYSYS 进程的位数MATLAB 里用version看是 32 位还是 64 位两边必须一致。第二步查注册表在 MATLAB 命令行直接执行!reg query HKCR\HYSYS.Application逻辑说明这行调用 Windows 的 reg 命令去查询注册表里 HYSYS 的 ProgID 是否存在。如果不报错且能看到 CLSID 相关内容说明注册表没问题问题出在位数或调用方式。如果提示找不到说明注册信息确实丢了需要重新修复 HYSYS 安装。参数说明HKCR是注册表根键之一专门存 COM 类注册信息。修复注册比重装快常见做法是用 HYSYS 安装包做一次 Repair或者把安装目录加进杀毒软件白名单后重新注册 COM 组件。这类问题一旦遇到优先怀疑环境而不是代码因为代码可能是对的。5.2 写回的值没生效属性和单位制双重检查现象脚本不报错write_stream也返回了 true但 HYSYS 界面上的温度纹丝不动或者数值变了但明显不对比如本来想写 350 K界面上变成了 350 摄氏度。原因第一层是属性名写错。HYSYS 的 Automation 属性名和界面显示名字有差异比如某些版本里 Vapour 和 Vapor 拼写不统一写错了 MATLAB 不报错只是静默失败。第二层是单位制问题赋值进去的数值直接按当前单位集解释你以为是 K它当成 °C。解决先读后写做验证。写回后立刻用同一个属性读回来比较差值超过容差就报错stream.TemperatureValue 350; readback stream.TemperatureValue; if abs(readback - 350) 1e-3 error(温度写回验证失败写入 %.4f读回 %.4f, 350, readback); end逻辑说明利用 COM 接口读写对称的特性做闭环检查。如果赋值成功读回应该等于写入值如果不等于基本可以断定属性名写到了别的字段上或者 HYSYS 在赋值时做了单位换算。参数说明容差 1e-3 是我按工程习惯给的温度值本身量级大这个容差足够区分单位换算偏差。这个方法同样适用于压力、流量写成通用函数后每个变量写回前都过一遍。5.3 收敛判断被跳过结果不对但脚本说已经收敛现象solve_and_wait返回 true读回来的产品温度却和 HYSYS 界面手工重算对不上比如塔顶温度等于进料温度明显是求解中间态。原因IsConverged这个标志在特定时机并不可靠。你改完多个变量HYSYS 求解器可能还在迭代第一步此时读到的是上一个工况留下的收敛标志另一种可能是求解器处于手动模式根本没开始算而CanSolve 1只解除了禁止不等于触发了求解。解决连续两次采样都收敛才算数加一层防抖function ok wait_converged_stable(hy, timeout_s) solver hy.ActiveCase.SolverControl; last false; elapse 0; while elapse timeout_s cur solver.IsConverged; if cur last ok true; return; end last cur; pause(1); elapse elapse 1; end ok false; end逻辑说明只有当相邻两次采样都为收敛时才返回 true过滤掉求解器在收敛边界附近抖动的情况。每次轮询间隔拉长到 1 秒给 HYSYS 留足迭代时间。参数说明这个函数比第 4 章的版本更保守代价是每次工况多等一两秒但换来的是数据可信度。批量扫描时建议用这个稳定版本单个工况快速验证可以用旧版。5.4 批量工况越跑越慢别让界面刷新和历史记录拖后腿现象批量扫描前十几个点很快越往后越慢肉眼可见每个点耗时在增长有时甚至像卡死。原因两个因素叠加。一是 HYSYS 案例里累积了大量历史工况数据每次新求解都带着旧包袱二是脚本里每轮循环都在命令行输出日志disp在跨进程调用面前是隐形杀手。解决批量运行时把 HYSYS 界面隐藏hy.Visible 0减少图形渲染开销。日志改成每十个工况输出一行而不是每个工况都打。案例特别大时每跑完 N 个工况重新从原始 .hsc 加载一次用干净状态继续扫if mod(k, 10) 0 hy.Close(1); hy conn_hysys(casePath); end逻辑说明mod(k, 10)判断是否跑到第十个工况是则关掉当前案例重新加载原始文件摆脱历史累积。参数说明hy.Close(1)的 1 表示不保存直接关闭因为我们不想把中间结果写回原文件原始 .hsc 始终保持干净。重载频率取 10 是我在中等规模流程上的经验值流程小可以放宽到二十个流程复杂就收紧。5.5 HYSYS进程退不掉用try-finally保证清理现象脚本跑完MATLAB 变量清空了任务管理器里 HYSYS 还在后台挂着。下次再连时actxGetRunningServer拿到的是这个僵尸实例状态不可控。原因COM 句柄只是一个引用MATLAB 里清空变量不等于让 HYSYS 退出。尤其脚本中途报错或return提前返回清理段被跳过进程就留下来了。解决统一用 try-catch-finally 包主逻辑在 finally 里做清理hy []; try hy conn_hysys(casePath); % 主逻辑写在这里 catch ME disp(ME.message); finally if ~isempty(hy) hy.Quit(); delete(hy); end end逻辑说明finally块保证无论正常跑完还是中途报错都会执行清理。hy.Quit让 HYSYS 进程退出delete(hy)释放 MATLAB 侧句柄两个缺一都会留尾巴。参数说明如果这个 HYSYS 是用户手动打开的别调Quit只delete(hy)释放句柄就行判断依据就是连接函数返回的那个isOwned标志。6. 进阶技巧用matlab优化工具箱把HYSYS当黑匣子做操作条件寻优批量扫描把工况空间铺满之后下一步自然是让 MATLAB 自己找最优解。常见做法是用优化工具箱里的fmincon把 HYSYS 看成黑匣子目标函数内部跑一次完整的流程模拟优化器只负责迭代。function xopt optimize_column(hy, feedName, productName, x0, lb, ub) obj (x) objective(x, hy, feedName, productName); options optimoptions(fmincon, ... Algorithm, sqp, ... Display, iter, ... MaxFunctionEvaluations, 30); xopt fmincon(obj, x0, [], [], [], [], lb, ub, [], options); end function f objective(x, hy, feedName, productName) spec struct(); spec.Temperature x(1) 273.15; spec.Pressure x(2); write_stream(hy, feedName, spec); ok solve_and_wait(hy, 60); if ~ok f 1e6; return; end data read_stream(hy, productName); f -data.Purity; end为什么选sqp黑匣子目标函数存在数值噪声interior-point对噪声更敏感sqp在这种不光滑场景下迭代更稳。罚值1e6的作用是让优化器自动避开不收敛的区域如果 HYSYS 算不出来就给个大惩罚优化器下次就不往这边走了。MaxFunctionEvaluations给 30 是因为每一次评估都是一次完整流程模拟很烧时间先给紧一点跑通流程确认方向对了再放宽。验证方法我有一套固定动作把优化结果写回 HYSYS界面手动复核一次再把优化目标从纯度换成成本函数用同一套脚本重新跑两次最优解要在同一区域才敢往下走。这两步做完我才认为这个黑匣子寻优真的可信。这套组合真正跑通后HYSYS 就只是一台被 MATLAB 调用的模拟引擎m 文件才是沉淀下来的资产。批量扫描、寻优、回归标定都能复用同一套连接和读写函数投入一次后面所有工况计算项目都在吃这波红利。希望帮到你。本文还有配套的精品资源点击获取