Igor Pro实用教程——图表绘制、数据分析与程序设计 下载 pdf 百度网盘 epub 免费 2025 电子书 mobi 在线

Igor Pro实用教程——图表绘制、数据分析与程序设计精美图片
》Igor Pro实用教程——图表绘制、数据分析与程序设计电子书籍版权问题 请点击这里查看《

Igor Pro实用教程——图表绘制、数据分析与程序设计书籍详细信息

  • ISBN:9787302493181
  • 作者:暂无作者
  • 出版社:暂无出版社
  • 出版时间:2018-05
  • 页数:499
  • 价格:96.00
  • 纸张:胶版纸
  • 装帧:平装-胶订
  • 开本:16开
  • 语言:未知
  • 丛书:暂无丛书
  • TAG:暂无
  • 豆瓣评分:暂无豆瓣评分
  • 豆瓣短评:点击查看
  • 豆瓣讨论:点击查看
  • 豆瓣目录:点击查看
  • 读书笔记:点击查看
  • 原文摘录:点击查看
  • 更新时间:2025-01-20 17:57:33

寄语:

作者多年潜心研究Igor Pro的系统总结 Igor Pro的使用方法的工具图书 中国科学院物理研究所超导实验室主任周兴江研究员作序推荐 作者多年潜心研究Igor Pro的系统总结 Igor Pro的


内容简介:

本书介绍Igor Pro的基本使用技巧和数据分析处理的一般方法,全面涵盖Igor Pro基本操作、图表绘制、命令行、数据分析拟合和程序设计等方面内容。在内容设计上以实用性为目的,突出图表绘制、数据拟合和程序设计等数据处理中需要的内容模块。书中配有大量的示例代码,以便读者在学习的过程中参考和借鉴。 全书共分为7章和1个附录,第1章介绍Igor Pro的基本对象和基本使用,突出命令行的特色。第2章介绍图表的绘制和设置中涉及的概念和方法,包括曲线、二维数据和三维数据的绘制。第3章介绍数据拟合的技巧和方法,包括简单的调用菜单拟合到复杂的自定义函数拟合,并详细讨论Igor Pro的一些高级拟合技巧。第4章介绍一些常见的数据处理方法,如插值、傅里叶变换、解方程等。第5章介绍程序设计的基本概念、Igor Pro语法环境以及命令行程序的设计。第6章介绍窗口界面程序的设计方法以及窗口程序设计中可能用到的各种技巧。第7章介绍一些高级的程序设计方法,如多线程、钩子函数、计算机硬件操作等复杂用法。附录介绍本书所用术语、Igor Pro快捷键和*版本的特点。 本书可作为高等院校、科研机构等相关单位从事实验教学或者实验科学研究的教师、工程师的参考书籍,也可作为高年级本科生和研究生实验数据分析和处理的参考书籍。


书籍目录:

目录

第1章Igor Pro基本介绍

 

1.1Igor概述

 

1.1.1特色定位

 

1.1.2安装和使用

 

1.1.3基本界面

 

1.1.4菜单

 

1.1.5数据浏览器

 

1.1.6数据表格

 

1.1.7命令行窗口

 

1.2Igor中的基本对象

 

1.2.1wave

 

1.2.2图(Graph)

 

1.2.3表格(Table)

 

1.2.4页面布局(Page Layout)

 

1.2.5变量(Variable)

 

1.2.6数据文件夹(Data Folder)

 

1.2.7记事本(Notebook)

 

1.2.8程序面板(Control Panel)

 

1.2.9三维图(3D Plot)

 

1.2.10程序(Procedure)

 

1.2.11命令和函数

 

第2章图表绘制

 

2.1曲线

 

2.1.1绘制曲线

 

2.1.2添加新曲线

 

2.2图表的设置和美化

 

2.2.1设置绘图区域

 

2.2.2设置外观

 

2.2.3设置坐标轴

 

2.2.4设置图注

 

2.2.5向曲线添加自定义形状

 

2.2.6样式脚本

 

2.3类别图

 

2.3.1类别图的绘制和设置

 

2.3.2类别图的设置

 

2.4二维wave绘制

 

2.4.1Image的绘制

 

2.4.2Image的设置

 

2.4.3Contour的绘制

 

2.4.4Contour的设置

 

2.4.5Waterfall的绘制

 

2.4.6Waterfall的设置

 

2.4.7Surface的绘制

 

2.4.8Surface的设置

 

2.5三维wave的绘制

 

2.5.1三维图形绘制的概念

 

2.5.2三维图形的绘制

 

2.6输出图片

 

第3章数据拟合

 

3.1拟合概述

 

3.1.1拟合的基本原理和步骤

 

3.1.2基本拟合

 

3.1.3快速拟合及结果查看

 

3.1.4自定义拟合

 

3.1.5数据拟合对话框详解

 

3.2拟合公式模型

 

3.2.1内置拟合公式

 

3.2.2普通自定义拟合函数

 

3.2.3保存自定义拟合函数

 

3.2.4自定义拟合函数的格式

 

3.3拟合命令详解

 

3.3.1拟合命令参数详解

 

3.3.2常用拟合命令选项

 

3.3.3限定拟合参数范围

 

3.4高级拟合技巧

 

3.4.1隐函数拟合

 

3.4.2复杂自定义拟合函数

 

3.4.3all at once拟合

 

3.4.4使用结构体类型变量参数的拟合函数

 

3.4.5拟合过程中的特殊变量

 

3.4.6多峰拟合

 

3.4.7拟合的几个例子

 

第4章数据处理

 

4.1插值

 

4.1.1基本插值方法

 

4.1.2插值与均匀数据

 

4.1.3逆插值

 

4.1.4曲线平滑

 

4.2数值计算与统计

 

4.2.1微分和积分

 

4.2.2wave统计信息

 

4.2.3求解数值方程

 

4.2.4微分方程求解

 

4.2.5直方图

 

4.2.6排序

 

4.3数学变换

 

4.3.1傅里叶变换

 

4.3.2傅里叶变换窗

 

4.3.3希尔伯特变换

 

4.3.4卷积

 

4.3.5相关

 

4.4图像分析

 

4.4.1Lookup Table方法

 

4.4.2直方图均衡化

 

4.5随机数生成

 

第5章程序设计

 

5.1程序设计概述

 

5.1.1程序窗口

 

5.1.2程序窗口说明

 

5.1.3编译程序

 

5.1.3程序代码构成

 

5.1.4程序类型

 

5.2基本语法

 

5.2.1表达式和命名规则

 

5.2.2变量和常量

 

5.2.3Structures

 

5.2.4流程控制语句

 

5.2.5函数

 

5.2.6程序子类型

 

5.2.7参数传递

 

5.2.8默认参数

 

5.2.9注释和代码风格

 

5.3程序设计技术

 

5.3.1Include指令

 

5.3.2Pragma参数

 

5.3.3IndependentModule

 

5.3.4Execute命令

 

5.3.5条件编译

 

5.3.6函数引用

 

5.3.7访问全局对象

 

5.3.8wave引用

 

5.3.9$运算符

 

5.3.10自动创建变量

 

5.3.11调试程序

 

第6章窗口程序设计

 

6.1窗口程序概述

 

6.1.1创建一个简单的窗口程序

 

6.1.2窗口程序构成

 

6.1.3窗口生成脚本

 

6.1.4控件命令

 

6.2窗口控件

 

6.2.1Button按钮

 

6.2.2CheckBox复选框

 

6.2.3SetVariable文本框

 

6.2.4ListBox列表框

 

6.2.5PopupMenu下拉列表框

 

6.2.6Slider滑动条控件

 

6.2.7ValDisplay数值显示控件

 

6.2.8TabControl控件

 

6.2.9CustomControl自定义控件

 

6.2.10TitleBox和GroupBox控件

 

6.2.11控件操作

 

6.2.12获取控件信息

 

6.2.13控件结构体变量类型应用

 

6.3窗口设计

 

6.3.1Pictures详解

 

6.3.2创建Pictures

 

6.3.3窗口设计

 

6.3.4Graph和Panel的区别

 

6.4菜单

 

6.4.1菜单概述

 

6.4.2创建动态菜单

 

6.4.3系统右键快捷菜单中添加菜单项

 

6.4.4特殊菜单项

 

6.4.5创建弹出式菜单

 

6.4.6菜单项中的特殊字符

 

第7章高级程序设计

 

7.1程序中的free对象

 

7.1.1free wave

 

7.1.2free data folder

 

7.2多线程技术

 

7.2.1简单多线程技术

 

7.2.2free对象与多线程

 

7.2.3多线程编程

 

7.2.4后台任务

 

7.2.5抢占式多任务

 

7.2.6定时器和多线程

 

7.3运行时交互

 

7.3.1简单的输入数据框

 

7.3.2利用PauseForUser创建输入对话框

 

7.3.3程序进度条

 

7.4钩子函数

 

7.4.1用户自定义钩子函数

 

7.4.2窗口钩子函数

 

7.4.3依赖

 

7.5数据采集

 

7.5.1FIFO与Charts

 

7.5.2串口读写

 

7.5.3XOP扩展

 

7.6多媒体

 

7.6.1播放声音

 

7.6.2视频播放和创建

 

7.7错误处理

 

7.7.1程序错误退出

 

7.7.2trycatchendtry

 

7.7.3Igor错误代码和描述

 

7.8文件读写

 

7.8.1文件读写函数和命令

 

7.8.2文件读写示例

 

7.9初始化技术

 

7.9.1新建实验文件时初始化

 

7.9.2打开窗口程序时初始化

 

7.10其他编程技术

 

7.10.1计时

 

7.10.2Cursor编程

 

7.10.3字符串及正则表达式

 

附录A本书术语说明

 

附录BIgor常用快捷键

 

附录CIgor Pro 7新特性

 


作者介绍:

暂无相关内容,正在全力查找中


出版社信息:

暂无出版社相关信息,正在全力查找中!


书籍摘录:

第5章程序设计使用菜单以及各类对话框可以完成一般的数据处理工作,如果仅限于此,使用Igor的水平是比较低的,Igor强大的数据处理能力远远没有发挥出来。Igor是一个基于命令行的数据处理工具,通过编写程序才能彻底发挥其强大的数据分析威力。如光电子能谱数据,一次实验少则几十张图谱,多则上百张图谱,每张图谱都由好几百条曲线组成,仅靠菜单手动处理分析这些数据,几乎是不可能的。作为一款数据处理工具,程序设计应该满足几个基本准则: (1) 自由。程序设计的目的就是为了自由地设计各种新功能,这要求编程环境应该类似于普通的编程语言,具有的自由度,不仅仅能分析数据,还能访问操作计算机的系统资源,如文件、窗口、输入输出设备等。编程环境必须具有对任何对象的实时获取能力,而不是“硬编码”。(2) 简单。应和普通的程序设计语言区分开来,不能让语法的复杂性掩盖了服务数据处理需求的本质。程序设计的本质就是对各种数据对象的访问和操作,必须有一个简单、统一的获取基本数据对象的机制,好是按照人们对数据的直观认识去操作。(3) 高效。既然是编程,在速度上就不能太慢,至少和普通编程语言不能差太多。如果编程仅仅是对命令行的批量解释执行,这样的程序设计是不满足要求的,不能算作真正地支持程序设计。Igor在这3个方面都支持得非常好。Igor的图形界面提供的功能,几乎都可以通过它自身的编程环境实现。对数据对象的访问也非常简单,基本的对象都是全局对象,可以利用名字直接访问,同时提供了大量的函数和命令用于获取这些对象的基本信息。在效率方面,Igor里所有的程序都可以被编译成较底层的机器码,因此速度非常快。Igor下的程序设计具有以下特点: (1) 语法环境规范而完整。(2) 面向过程的程序设计语言,命令和函数被组织在一起形成一个功能相对独立的操作单位。(3) 有两种级别的程序模式: 脚本程序(Macro、Proc)和函数程序(Function)。前者语法规范宽松,速度慢,但使用简单;  后者语法规范严谨,编译为机器代码执行,速度极快,但使用相对复杂。(4) 有一个方便的编程环境和调试环境,可以方便地编写程序和调试代码。调试器可查看任意变量值,支持查看表达式。(5) 可以利用C/C 编程工具无缝扩展Igor功能,甚至控制硬件采集数据。扩充的功能作为动态运行库被Igor调用,和内置函数和命令没有任何区别。(6) 提供了近千个不同的函数和命令,涉及绘图、窗口、数据操作、数据分析、矩阵、信号处理、统计、文件读写、数学函数等多个方面,以供在程序设计中使用。(7) 程序必须在Igor环境下运行。不能编译脱离Igor运行的程序。虽然功能很强大,但是学习曲线并不是很陡峭。即使没有受过任何编程训练的人,通过本书的介绍,也能在很短的时间之内掌握Igor的编程方法。5.1程序设计概述5.1.1程序窗口

程序窗口是写程序的窗口。程序窗口相当于具有IDE的程序设计语言中的代码编辑器,在该窗口中可以完成输入代码、编译、运行和调试等工作。程序窗口具有语法高亮的功能,如系统关键字显示为蓝色,函数显示为深橙色,预编译指令显示为紫罗兰色,命令显示为暗青色,注释显示为红色等。除了编辑功能之外,程序窗口还可以查看帮助,查看某个函数(或程序),运行命令等。版本的Igor(Igor Pro7版本)还支持外置编辑器,如Vim。按Ctrl M键(或者利用菜单命令【Windows】|【Procedure Windows】|【Procedure Window】)就打开了一个程序窗口,这是一个内置的程序窗口,可以在该窗口中输入代码完成程序编写,如图51所示。

图51内置程序窗口

读者可以在程序窗口输入以下代码: 

Function myfun()

string s="This ia my first function in Igor\r"

s ="Please give two numbers, I'll calculate the sum."

doalert 0,s

Variable v1,v2

prompt v1,"Input the first number"

prompt v2,"Input the second number"

doprompt "Calculate Sum",v1,v2

string s1="The sum of " num2str(v1) " and " num2str(v2) " is " num2str(v1 v2)

doalert 0,s1

End

输入完毕,单击程序窗口下方的【Compile】按钮编译程序(注意Igor下的函数必须在编译后才能运行)。【Compile】按钮在单击后会消失,对应位置显示为空白,表示程序已经编译完毕,如图52所示。如果代码里包含错误,就会无法编译,此时会显示一个编译错误对话框。

图52程序窗口的编译

在命令行窗口输入myfun(),按回车键执行(注意不能省略圆括号)。还可以在程序窗口中选择myfun(),按Ctrl Enter键执行程序。程序首先显示一个对话框,然后提供一个输入对话框,输入两个数字,后显示一个对话框,显示输出结果。Ctrl M快捷键打开的程序窗口是Igor内置的程序窗口。Igor内置的程序窗口默认是全局的,也就是说所有的程序都可以访问内置窗口里的程序和变量。可以通过菜单命令【Window】|【New】|【Procedures】打开一个新的程序编辑窗口,此时可以给窗口起一个有意义的名字,如MyProc,如图53所示。

图53创建新程序窗口

新程序窗口有一个名字,如这里的MyProc,在程序设计里可以通过这个名字来访问该程序窗口,此时程序窗口相当于一个普通的窗口。内置程序窗口是Igor的一部分,保存实验文件后内置程序窗口里的内容都将被保存。非内置程序窗口如果没有保存到文件,也会随实验文件一起保存,但是一旦被保存到文件里,Igor就不会再保存整个程序文件,而只是保存程序文件的路径信息。内置程序也可以被保存在文件里,但是其内容仍然会在保存实验文件时被保存。如果不使用内置程序编辑窗口,例如将不同的函数放在不同的文件中,可以创建新的程序编辑窗口。5.1.2程序窗口说明1. 保存程序窗口中的程序习惯于VS或者其他编程环境的读者都知道,在IDE中创建代码时,需要首先创建一个代码文件,然后在IDE中修改或者编辑该文件。在Igor中稍稍不同,当利用快捷键Ctrl M或者Windows菜单创建一个新的程序编辑窗口,在其中编写代码时,代码是实验文件的一部分,并没有创建对应的文件(很好理解,因为这个过程中没有指定任何要保存的文件)。当保存实验文件时,程序窗口连同内部的代码会和数据一起保存,这样当下次打开实验文件时,里面的程序窗口及程序代码也会被同时打开。实际情况中,程序应该是通用的,而不是依赖于某个具体的实验文件,这就需要将程序窗口中的代码以文件形式单独存放于硬盘或者其他存储介质中。保存程序文件的方法很简单,保持需要被保存的程序窗口处于激活状态,执行菜单命令【File】|【Save Procedure As】,在弹出的保存对话框中浏览到合适位置保存即可。此时窗口中所有的内容都会被保存在一个扩展名为ipf的文件中,程序窗口的标题也被替换为保存时的名字。一般将经常用到的程序文件保存到Igor安装目录/User Procedures或者Igor安装目录/Igor Procedures下。当然可以不存放在这个文件夹里,此时使用Include指令包含程序文件时需要指明完整路径。保存程序文件如图54所示。

图54保存程序文件

图54(续)

当打开一个存放于硬盘上的程序文件(或者将程序文件保存在硬盘上)时,Igor会建立该文件与Igor中对应窗口的关联,但这种关联不是实时的。如果修改代码,代码并不会实时保存到程序文件中,编程者需要通过按Ctrl Shift S键来保存程序文件的内容(或者通过菜单命令【File】|【Save Procedure】)。每次按Ctrl Shift S键只保存当前程序窗口,如果有多个程序窗口,需要选择每个窗口并执行保存命令。当程序窗口被保存为独立文件时,Igor仅会在实验文件里保存该程序文件的路径信息,而不再保存其内容。下次打开实验文件时,Igor会自动根据路径信息打开该程序文件(并列出在【Windows】|【Procedures】菜单下)。如果程序文件不存在(这种情况很普遍,比如打开从别的地方复制的实验文件,程序文件被误删或者改名,程序文件的存放路径发生改变),Igor就会报错并显示一个对话框让用户提供正确的程序文件路径。本例中,读者可以先保存实验文件(按Ctrl S键)并关闭实验文件,在电脑里将MyProc1.ipf改为MyProc2.ipf,然后再打开已经保存的实验文件,就会看到如图55所示的错误提示。

图55找不到程序文件的错误

可以单击【Skip This File】按钮忽略错误,这种情况下程序文件就不能正常打开了,但不会影响实验数据或者其他程序的打开。程序文件没有打开,自然就不能使用程序文件里的程序,可以按【Look for File】按钮提供正确的程序文件。2. 设置程序字体对于中文语言字体的计算机,程序窗口默认字体为宋体,字体尺寸也往往比较小,看起来不太舒服,可以将其修改为常见的代码字体Courier New,并设置合适字号如12pt。设置方法如下: 选择一个程序窗口为当前窗口,主菜单栏会动态出现一个【Procedure】的菜单(利用该菜单可以设置程序编辑窗口的字体、字号等信息),执行菜单命令【Procedure】|【Set Text Format】,打开字体设置对话框,进行如图56(a)所示的设置,单击【OK】按钮,可以看到程序编辑窗口的字体变为常见的代码字体,如图56(b)所示。

图56设置程序窗口字体

注意,设置好的字体需要保存,否则当下次打开Igor后仍然为默认字体。保存设置的方法是执行菜单命令【Procedure】|【Capture Procedure Prefs】,选择相应的项,这里选中【Text Format】复选框,然后单击【Capture Prefs】按钮,就可以为这台计算机永久保存字体设置。读者可以试着创建一个新的程序编辑窗口并将字体设置为合适的字体。3. 打开并查看已有程序文件打开已有程序文件的方法非常简单,可以直接将已有程序文件拖入Igor或者执行菜单命令【File】|【Open File】|【Procedure】打开一个程序对话框,定位到程序文件处打开即可。如果在处理实验数据时打开了已有的程序文件,则在保存实验数据时会自动保存该程序文件的路径信息,下次打开实验文件时会自动打开程序文件。这要求程序文件存在且位置不能发生变化,否则就会出现打开文件错误。已经打开的程序文件可以修改其内容,如果修改时出现如图57所示提示则表示程序文件处于写保护状态。观察程序文件左下角,可以发现一个上面有一条斜线的铅笔状的小图标,表示当前程序文件处于不能编辑状态,如图58所示。单击该图标,即可解除不能编辑状态,再次单击则恢复不能编辑状态。

图57程序文件写保护警示

图58程序文件写保护状态

图59程序文件被其他程序打开或者被操作系统写保护,则不能修改

如果打开的程序文件已经被别的实验文件打开,或者是操作系统设置了写保护,则“小铅笔”对应位置处是一把小锁的图标,此时程序文件不能被修改,如图59所示。单击图59左端一个类似于文档的小图标,会显示当前程序文件的基本信息,如存放路径、当前光标所处行数等。小放大镜可以按比例对字体缩放。【Templates】下拉列表可以插入函数、命令模板或者各种流程控制语句,【Procedures】下拉列表可以查看自定义Macro或者函数。所有打开的程序文件都被列入【Windows】|【Procedure Windows】菜单内,可以在这个菜单中找到并查看已经打开的程序文件。但也有例外,当程序文件中指定Pragma的hide参数为1或者指定为IndependentModule或者是操作系统设置为隐藏时,虽然程序文件已经打开,但【Windows】|【Procedures Windows】菜单内并不列出。隐藏文件提供了一种保护代码不被修改的方法,但一般不建议采用。因为对于普通的使用者,即使文件不隐藏也一般也不会被修改,而对于程序开发者而言隐藏文件除了给自己制造一些麻烦之外没有什么别的用处。IndependentModule参数很有用,它可以指定一个程序文件单独编译,即使当前程序文件出现错误无法编译,IndependentModule中的程序仍然可以正常运行,这在使用Igor进行数据采集时非常重要,请参看5.3.2节。可以按Ctrl Alt M键在已经打开的程序文件窗口中切换查看,按Ctrl Alt Shift M键隐藏当前程序编辑窗口并自动显示下一个程序文件对应的程序编辑窗口。但这两个快捷键并不好用,好的办法还是利用【Windows】|【Procedures】菜单定位到指定的程序文件,也可以右击相应的对象(如控件、函数),然后【Go To】到指定的程序文件。

图510关闭程序窗口对话框

4. 关闭程序文件单击程序编辑窗口右上角的[×]按钮或者按Ctrl W快捷键,会调出关闭程序文件对话框,如图510所示。在这里有3个选项:  【Save and then kill】表示将程序编辑窗口中的程序保存到计算机存储设备,然后从Igor中彻底关闭,此时程序文件中的所有程序都将不能再使用。 【Kill】表示彻底关闭且不保存。 【Hide】表示隐藏程序编辑窗口,但是程序文件里的内容仍然留在内存里,可以通过菜单命令【Windows】|【Procedure Windows】查看并重新打开,或者利用其他方法如通过查找对话框等重新打开。一般在关闭程序编辑窗口时选择【Hide】按钮,既不影响程序文件中的函数的使用,同时又不会被程序编辑窗口遮挡影响数据处理。若【Macro】菜单中的【AutoCompile】为打开状态(默认)时,单击【Hide】按钮会自动编译程序。当打开一个写好的程序时,应该选择【Hide】按钮编译并隐藏程序文件,这样就可以像使用Igor内置的函数和命令一样使用程序文件中提供的程序。5. Adopt程序文件Adopt是保存程序文件的逆操作——将程序文件重新保存到实验文件里。在保存实验文件时,如果实验文件里的程序文件是存放于硬盘上的ipf文件,则程序文件里的内容不会被保存在实验文件里,而是保存了该程序文件的路径信息,这样当下一次打开实验文件时,Igor会根据路径信息自动打开该程序文件。但这样存在一个问题,如果实验文件在另外一台计算机上打开(比如与别人交流实验数据时),如果该计算机上不存在对应的程序文件,就会出现找不到程序文件的错误,实验文件也不能使用该程序文件中的程序。解决这个问题的方法是Adopt程序文件。要Adopt一个程序文件,先使该程序文件(外部打开的)处于显示状态,然后选择菜单命令【File】|【Adopt Procedure】,Igor会显示一个提示信息,提示用户会先复制一份程序文件放到当前实验文件,然后断开与源文件的关系。Adopt程序文件后,程序文件的内容将会成为实验文件的一部分,随实验文件保存,这样该实验文件在任何地方都可以使用程序而无须关心程序文件是否存在。5.1.3编译程序在第5.1.1节可看到程序只有在编译后才能运行。当然不是所有的代码都需要编译后才能运行,如果只是调用内置命令和函数的命令行,或者是proc和macro,无论是在命令行窗口还是程序窗口中运行都不需要编译。但注意,如果使用自定义函数,则必须编译自定义函数所在的程序文件。Igor的程序分为编译阶段和运行阶段。编译阶段,编译器会检查代码中的语法错误并将代码生成较低层次的机器语言。运行阶段,调用前面编译好的代码。编译后的机器代码执行速度要比直接解释执行快得多。Igor下程序文件的编译非常简单,当菜单命令【Macro】|【Auto Compile】处于被选状态时,单击程序编辑窗口以外的任何地方都会自动完成编译。第5.1.2节中提到的关闭程序文件选择【Hide】按钮编译程序文件就是这个原理。也可以主动编译程序文件,保持待编译的程序文件处于激活显示状态,选择菜单命令【Macro】|【Compile】

图511编译程序按钮

进行编译,或者按程序左下角的【Compile】按钮进行编译,如图511所示。

编译以后的程序文件【Compile】按钮处对应的地方为空白,否则会显示一个虚线状态的【Compile】按钮。【Macro】|【Auto Compile】即自动编译默认为打开状态,以方便程序自动编译。但有时需要关闭这个功能,在编写程序时这样做很有必要。在程序开发的过程中经常需要查看文件夹、wave、全局变量等信息,如果设置为自动编译,则在查看这些信息的过程中,Igor会自动编译还未完成的程序并报错,这会给程序的编写带来不便,此时就可以关闭自动编译。不同于普通的程序设计,Igor并不会生成独立的可执行程序,因此每次打开程序文件都需要执行编译过程。如果程序文件较大,编译会花费较长的时间,但一般都是很快的。如果程序文件随实验文件一起打开,则编译过程是自动的,不需要手动操作。5.1.3程序代码构成程序设计就是在程序编辑窗口中输入代码。按照代码在程序中的作用不同,可以将程序文件中的内容划分以下10个类型。 (1) 编译器指令,关键字为Pragma,一般位于程序文件开头,格式为#Pragma,并紧靠程序文件左侧,用于指定编译参数。(2) 程序文件包含指令,关键字为Include,一般位于程序文件开头,格式为#Include文件名或者#include “文件名”,和C语言程序设计类似,用于打开并包含一个已有的程序文件。(3) 常量声明,关键字为Constant,用于声明常量,类似于C语言的#DEFINE指令。(4) 结构体类型定义,关键字为Structure,定义的结构体变量类型可以在函数中使用。(5) 图片资源,关键字为Picture,以代码格式保存图片,类似于编程语言中的图形资源,这些图形资源可以作为图形按钮或者窗口程序的背景图片。(6) 菜单,关键字为Menu,定义菜单,可以向系统菜单添加菜单项,也可以创建自定义菜单。(7) 函数,关键字为Function,程序设计的主要内容,完成数据处理的功能单位,需要编译以后执行。(8) 脚本,关键字为Macro和Proc,功能类似于函数,但是并不需要编译,解释执行,类似于Windows下的批处理文件或者Linux下的bash文件。(9) 预编译指令,用于条件编译。(10) 注释,格式为以“//”开头,和C语言类似。请读者对照图512所示的程序代码示例理解上面的内容,其中用Include指令包含的文件内容如图513所示。

图512程序代码构成类型

图513被Include的程序文件

Proc0.ipf存放位置如图514所示。

图514被Include程序文件存放于计算机硬盘上

注意观察在菜单栏的后一项添加了一个名为mymenu的菜单,如图515所示。

图515自定义菜单

【Macros】菜单下面也添加了一个名为macro1的菜单项。【macro1】和【mymenu】菜单项的功能是相同的,即执行后在历史命令行窗口打印信息,如图516所示。

图516历史命令行窗口打印信息

上面没有包括Picture的例子,关于Picture在后面窗口程序设计时进行详细介绍。这些代码形式是Igor下语法结构的一部分,这里列出来主要是给读者一个整体印象,让读者了解一个完整的程序文件的基本组成。关于每个部分的详细介绍请参看接下来的内容。5.1.4程序类型Igor下可执行的程序类型有3种: Macro、Proc和Function。这些程序内容基本一样: 都包含变量声明和流程控制语句,通过调用其他程序处理数据或者对数据进行拟合,或者创建新的变量数据,实现一个具体的功能。3种程序形式的格式可描述如下: 

Macro macroname(parameters list)

body

End

Proc procname(parameters list)

body

End

Function functionname(parameters list)

body

End

可以看到,3种程序形式也非常类似,功能也几乎完全相同。一般而言,能用Macro和Proc实现的功能,Function都可以做,反之亦然。但是它们的执行效率是不一样的,Macro和Proc是解释执行,而Function是编译执行。Igor是基于命令行的实验数据处理软件,在设计之初,为了执行命令的方便,引入了Macro的概念和方法,将命令以脚本方式组合起来,并扩充一些功能,如变量声明和流程控制等,辅助程序设计,这有点类似于Windows下的批处理以及Linux下的shell程序,其本质是批量执行多条命令。但缺点也很明显,由于是解释执行,当数据量比较大或者计算量比较大时,十分耗时。因此Igor后来的版本引入了函数的概念,并引入了自己的编译器。不同于Macro,函数并不是解释执行,而是先编译为低层次的机器指令,然后再执行,这就大大提高了程序运行的速度。下面比较Macro和Function二者在执行效率上的差异: 

Macro test1() 

Variable i

Variable t0,t1

t0=ticks

i=0

silent 1

do

i =1

while(i1e5)

t1=ticks

Print/D "Time used is ",(t1-t0)/60,"s"

End

Function test2()

Variable i

Variable t0,t1

t0=ticks

i=0

silent 1

do

i =1

while(i1e5)

t1=ticks

Print/D "Time used is ",(t1-t0)/60,"s"

End

图517脚本和函数执行的时间差异

在命令行输入test1()和test2()分别执行,结果如图517所示。完全相同的代码,test1()即Macro形式,执行时间约为11s,而test2()即Function形式执行时间在计算机数据精度范围内为0s,可见二者的效率差别之巨大。因此在编写程序时尽量使用Function而不使用Macro。Proc其实是另外一种形式的Macro。一般而言,使用Macro关键字声明的程序都会被默认添加在系统【Macro】菜单下,以方便执行,如果不希望这些程序出现在【Macro】菜单下,就可以使用Proc关键字声明程序。除此之外,二者完全相同。其实还可以利用Window关键字声明一个Macro,其执行方式和普通Macro一模一样。由于Macro和Function的这种差异,一般不建议在设计程序时使用Macro,而应该使用Function。Macro更多地是被Igor用来做一些自动化的操作,如自动生成程序面板创建代码、图表创建代码、样式风格创建代码等。除了执行效率和使用场合的区别之外,Macro和Function还有一些语法上的区别,Macro在使用上更自然方便一些,可以不需要声明而直接访问全局变量或者wave,但是有些语法不能使用,如不能使用for循环,不能使用switch语句等。而Function则相对严谨,全局变量必须在声明引用以后才能使用,语法格式也更加丰富多样。5.2基本语法作为一门完全可编程的语言,Igor具有系统而完整的语法环境,体现在以下几个方面: ,高度自治,不需要引进任何外部支持,原生支持脚本级别、编译级别的程序设计,并提供了很多普通编程语言才有的高级编程技术,如预编译指令、文件包含、条件编译、名称空间等。编译器支持的功能广阔,如字符串处理、结构体变量、函数指针、对所在平台系统资源的自由访问、线程安全函数设计及多线程编程等。这使得仅仅使用Igor,不借助任何外部专门的编程工具,就能够实现各种复杂的功能。第二,显著区别于普通的程序设计语言,将程序设计的复杂性做了包装,针对数据处理程序的设计做了大大简化,如变量仅包括数值型和字符串型两类变量(当然也可以指定更具体的变量类型,这会提高效率,但一般这两类就够了),没有普通编程语言“强类型数据”所带来的复杂性,所有的内置函数和命令(包括用户自定义函数)无须声明即可自由使用,提供极为通用的方式自由访问Igor的数据对象,如wave、变量、窗口等。第三,提供了相当方便的在线帮助系统,可随时查询函数及命令的使用并能够将示例直接插入代码处,几乎所有的对话框操作都能转化为对应的命令行并醒目显示,这些命令行都可以直接作为程序的代码。第四,提供了方便易用的扩展接口,可以利用C 等编程工具任意扩展其功能。

这4个方面的特性使得Igor非常适合于处理复杂且体积较为庞大的实验数据。在需要大批量重复的操作、在多变量中任意调整某变量随时观察数据变化和需要编写某一专门类型的数据处理工具时,Igor更是极好的选择。Igor下语法结构包括编译指令、文件包含、函数定义、变量定义,流程控制语句、注释等。本节重点介绍关于这些语法结构的基本含义。另外注意,Igor下的程序设计是面向过程的,主要通过函数和各种结构来构建程序体系。5.2.1表达式和命名规则表达式是代码的基本单位。变量声明语句、赋值语句、内置命令调用、用户自定义函数调用等都属于表达式: 

Variable v=sin(x)

Make/N=100 gsfun=gauss(x,50,1) gnoise(0.1)

CurveFit gauss,data/D

myfun()

表达式里可以包含任何内置函数、命令,或是用户自定义函数。每一行只包含一个表达式,表达式结尾不需要使用分号(当然加上分号编译器也不报错)。另外,Igor程序设计语言不区分大小写,这和很多程序设计语言完全不同,如make、Make、MAKE表示完全相同的命令。Igor下编程语言使用ASCII字符,Unicode字符(如中文字符)只能包含在字符串中或者注释中。Igor下的命名规则和普通编程语言类似,无论是变量、函数、wave、窗口,名字一般都由字母、数字、下画线组成,其中下画线和数字不能位于开头,不能包含空格、逗号、冒号等字符,名字不能和系统内置的关键字重名。如下面的名字都是不合法的: 

Variable sin

Make cos

newpanel/N=sin//系统会自动将sin改为sin0

Variable 1v, _v

注意,wave的命名条件稍微宽松一些,可以创建包含特殊字符的wave名字,如

Make ‘a wave’

这时wave名字需要用单引号括起来,Igor里把它叫作Liberal Name。这种命名方式会给wave的访问带来很大麻烦,因此不建议使用。5.2.2变量和常量变量包括数值型变量和字符串型变量。常量也可以理解为一种特殊的变量,只不过其值不能修改。常量同样包括数值型常量和字符串型常量。1. 数值型变量数值型变量的声明方式为

Variable [/C/D/G] varName [=numExpr][, varName[=numExpr ]]...

其中,Variable是关键字,varName是变量名。可以在声明时给变量赋值。如果声明后未赋值那么系统默认赋值0。Variable有3个选项,用于限定所声明变量的类型。(1) /C,表示声明一个复数型变量。(2) /D,表示声明一个双精度型变量,由于Igor下任何数值变量都默认为双精度,因此/D参数没有实际意义,主要是为了向前兼容(即和旧版本的Igor兼容)。(3) /G,表示声明一个全局变量,此变量会出现在当前数据文件夹下,并作为实验数据的一部分随实验数据永久保存。和一些强类型语言如C语言等不同,使用Variable声明的数值型变量没类型之分,所有的变量不管是整型还是浮点型甚至是Char型,其声明全部使用Variable关键字,在计算中全部使用双精度类型。这使得Igor下的变量定义和使用非常简单。变量名的命名规则和C语言相同,包括字母、数字和下画线,其中数字不能位于首位,变量名不能有空格等特殊字符,变量名也不能为系统关键字、函数名或者命令。由于Igor编程语言不区分大小写,所以num1和NUM1表示同一个变量。数值型变量主要用于程序设计,用来存放中间变量。全局的数值型变量主要用于保存控件状态以及在不同的程序之间传值。下面举几个变量定义的例子: 

Variable v1               //声明一个变量v1

Variable v1=0   //声明一个变量v1,并赋值为0

Variable pi   //错误,pi是系统函数,返回圆周率值

Variable sin   //错误,sin是系统数学函数

Variable/C c=cmplx(1,1)   //声明一个复数型变量,并赋值1 i

Variable/G v2   //声明一个全局变量v2

Variable _v3   //错误,不能以下画线开头

2. 字符串型变量字符串是字符的集合,在一般编程语言中经常用字符数组来表示。在Igor中字符串被简化为一个String型的变量,使用起来相当方便。字符串变量的声明方式为

String [/G] strName [=strExpr] [,strName[=strExpr]...]

其中,String是关键字,strName表示字符串变量名,/G选项和Variable含义一样,表示声明一个全局字符串。字符串变量名的命名规则和数值型变量相同。字符串变量名在声明时可以初始化。如果没有初始化,则系统会初始化为null,即空字符串。空字符串是不能使用的,否则会报错。在程序中一定要在声明字符串后对字符串赋值。字符串变量主要用于处理数据对象、图形对象以及其他Igor对象的名字,以方便在程序里对这些对象访问和处理。Igor对字符串处理的支持相当完善,提供大量的函数和命令用于对字符串的操作。下面举几个字符串声明的例子: 

String str1=""  //声明一个字符串str1,赋空值

String str1="hello,world"  //声明一个字符串str1,并赋值"hello,world"

String/G str1   //声明一个全局型字符串str1

3. 变量的作用域和寿命变量的作用域取决于声明变量的位置和声明时的选项。如果在函数体内声明(包括Function、Macro、Proc)且没有使用/G选项,则变量的作用域只局限于程序体内,此时变量又称为局域变量。如果在程序体外声明或者是在命令行窗口声明,或者虽然在程序体内声明但是使用了/G选项,则变量的作用域为全局的,所有的程序都可以访问该变量。局域变量的寿命在程序运行终止时即结束。全局变量的寿命则是永久的,除非被删除。4. 常量定义常量分为数值型常量和字符串型常量。数值型常量的定义方式为

Constant kName = literalNumber

字符串型的常量定义方式为

Strconstant ksName="literal string"

常量一般在程序体外程序文件的开头定义,作为一个常量使用,类似于C语言的#DEFINE语句。如果没有用static修饰符修饰,其作用域是全局的。注意常量和变量不同,系统并不会分配内存空间储存常量,因此不能对常量修改或者赋值。5.2.3StructuresIgor支持结构体。一般在程序文件的开头、程序的外部定义结构体类型,在函数内部通过声明方式创建结构体类型的实例。结构体定义方式如下: 

Structure structurename

memtype memname [arraysize] [,memtype,memname [arraysize]]

EndStructure

Structure是关键字,structurename是要创建的结构体类型名字,memtype是Igor下支持的变量类型,包括variable、string、wave、nvar、svar、dfrer、funcref和结构体变量类型,除此之外,memtype还包括一些其他的数据类型,这些数据类型和C语言非常类似,如表51所示。

表51结构体支持的类C数据类型

变 量 类 型C语言对应类型字节数CharSigned char1UcharUnsigned char1Int16Short int2Uint16Unsigned short int2Int32Long int4Uint32Unsigned long int4FloatFloat4DoubleDouble8在结构体里可以声明数组,利用arraysize指定数组的长度,这个长度必须是常数或者常量,不能是变量。注意在函数中不能声明数组。创建好结构体类型后,可以使用如下的语法在函数中创建结构体变量: 

Struct structurename name

这里Struct是必需的,类似于C语言里的Structure关键字,structurename是结构体类型名,name是要创建的变量名。下面是一个可能的例子: 

Structure mystruct

Variable var1

Variable var2[10]

EndStructure

Function myfunc()

Struct mystruct ms

ms.var1=1

ms.var2[n]=20

End

上面的例子中,首先创建了一个结构体类型mystruct,然后在函数内利用Struct mystruct ms声明了该结构体类型的一个实例,即创建一个mystruct类型的变量ms,然后对ms赋值。这里看到访问结构体变量成员的方法: 变量名.成员名,这和C语言完全一样。给ms.var2数组赋值时,利用一个变量指定要赋值的位置,这是允许的。下面是一个更为复杂的结构体类型,当然这个结构体类型没什么实际作用,主要是为了让读者理解结构体的概念: 

Constant kCaSize= 5

Structure substruct

Variable v1

Variable v2

EndStructure

Structure mystruct

Variable var1

Variable var2[10]

String s1

Wave fred

Nvar globVar1

Svar globStr1

Funcref myDefaultFunc afunc

Struct substruct ss1[3]

char ca[kCaSize 1]

EndStructure

上面的结构体类型中几乎包含了Igor下所有的数据类型。当结构体类型中包括引用时,在创建结构体变量后必须对该引用赋值,指明引用的对象。

Struct mystruct ms

Wave ms.fred

Nvar ms.globvar1

Svar ms.globstr1

Funcref mydefaultfunc anotherfunc

这里假定当前文件夹下存在fred wave、globvar1和globstr1全局变量。注意为引用赋值时和在函数中声明引用的方法完全一样,这里不能省略wave、nvar和svar关键字。如不能写成如下形式: 

ms.fred=fred

也不能写成如下形式: 

Wave w=fred

Ms.fred=w

关于引用的详细介绍请参看5.3.6、5.3.7、5.3.8节内容。结构体变量在函数中传递时是按照引用传递的,因此被调用函数可以修改调用函数中结构体变量的值,这使得结构体变量既可以作为函数的输入参数,也可以作为函数的输出参数。当使用结构体变量作为参数时,语法如下: 

Function subfunc(s)

Struct structname &s

End

这里使用了&符号获取结构体变量的引用。Igor内置了一些预定义好的结构体类型,如Button控件对应的WMButtonAction结构体类型,CheckBox控件对应的WMCheckBoxAction结构体类型等。这些结构体里包含了关于该控件的各种状态和运行信息,以方便对控件进行控制和对控件的状态作出反应。关于控件结构体类型将在第7章图形用户界面程序的程序设计中详细介绍。5.2.4流程控制语句流程控制语句包括条件判断语句、分支语句和循环语句。1. 条件判断语句条件判断语句有两种形式: 

if (expression)

True Part

else

False Part

endif

if (expression)

True Part1

elseif

True Part2

else

False Part

endif

其中,expression是一个数值型表达式,非0表示真,0表示假。这里的数值型表达式可以是普通的数值型表达式,如a b,也可以是一个逻辑数值型表达式,如a==b。else可以省略,因此简单的条件判断语句为

if (expression)

True Part

endif

注意,不能忽略后面的Endif。Igor不使用大括号作为语句块的标识,而是使用End或者End作为前缀的关键字来作为一个语句块结束的标识,请读者注意体会这个特点。if语句可以嵌套,即if内部还可以包含if语句。下面是一个简单的条件判断的例子,其作用是比较两个数的大小: 

Function example()

Variable a=2,b=1

if(a  b)

Print a

else

Print b

endif

end

表52列出了常见的比较运算符。

表52常见的比较运算符

运算符含义运算符含义==相等<=小于或等于!=不等>大于<小于>=大于或等于当比较结果为真时返回1,否则返回0,如Print 2==2结果为1,Print 23结果为0。比较字符串的大小时需要使用相应的字符串函数,如CmpStr。CmpStr会根据字符串大小返回一个数字。总而言之,只要是运算结果为数字的都可以充当条件判断表达式,甚至是一个常量,如if(1)这样的语句也是可以的。表53列出了常见的逻辑运算符和位运算符。

表53逻辑运算和位运算符

运算符含义运算符含义~按位取反!逻辑取反&按位与&&逻辑与|按位或||逻辑或

逻辑运算符用于连接多个条件判断表达式。位运算符则常用于对比特变量按位进行设置。一些命令或者函数如TraceNameList使用比特变量作为参数,使用位运算符可以方便地对这些比特参数进行置位或取消置位。运算符之间存在优先级,圆括号可以改变优先级。为避免出错,建议读者在使用运算符时多使用圆括号,而不要依赖于对优先级的记忆,这样会避免很多错误。2. 分支语句分支(switch)语句也有两种形式: 

switch(numerical expression)

case literalnumber constant:

code

[break]

case literalconstant:

code

[break]

[default:

code]

Endswitch

strswitch(string expression)

case literalstring constant:

code

[break]

case literalstring constant:

code

[break]

[default:

code]

Endswitch

不同于C语言,switch语句有两种格式,分别对应数值型和字符串型。switch根据numberical expression或者string expression的值选择执行相应case分支对应的代码,如果有break关键字,则执行完后跳出swtich语句,否则顺序执行其后的case的代码,直至碰到break或者到结束为止。default如果存在且没有任何case被对应,则执行default语句后面的代码。注意case标识符后面只能是一个具体的数字(双引号括起来的字符串)或者是一个数值型常量(字符串型常量),而不能是变量。当判断分支很多,用if语句比较麻烦时,就可以选用switch语句,如使用window hook函数侦测键盘输入,用switch语句判断键码就非常方便。下面是一个switch语句的例子,其作用是输出两个数中较大的一个: 

switch(ab)

case 1:

Print a

break

case 0:

Print b

break

default:

break

endswitch

switch语句不能用于proc或者maro形式的程序中。3. 循环语句循环语句有两种形式,分别是for循环和dowhile循环,其格式为

do

loop body

while(experssion)

for(initialize;continue test;update)

loop body

endfor

其中,expression是一个表达式,当表达式非0时执行循环,表达式为0时停止循环。for循环先初始化条件,然后每次循环后先更新循环变量,接着计算循环条件表达式并进行判断,如果判断结果为真则执行循环,否则跳出循环。下面举一个例子: 

Function example()

Variable I=0,sum=0

do

sum =i

i =1

while(i=100)

Print sum

End

上面的例子用于计算从1到100的和,如果用for循环可写为

Function example()

Variable I,sum=0

for(i=0;i=100;i =1)

sum =i

endfor

Print sum

End

循环是可以嵌套的,但是对于一些计算量非常大的数据处理,应尽量避免将大量的计算放在内层的循环,否则会大大增加运算的时间。for循环只能用于Function程序类型,而dowhile循环则可以用于Function和Macro程序类型。这也是Function和Macro的区别之一。和C语言类似,在循环中可以使用break和continue语句用于跳出循环或者满足某些条件时不执行循环体而进入下一个循环。break和continue作用于包含它的近循环。如上面的例子用break可以写为

Function example()

Variable I=0,sum=0

for(;;)

sum =i

i =1

if(i100)

Break

endif

endfor

End

求1到100之间所有奇数的和例子用continue可以写为

Function example()

Variable i=0,sum=0

do

i =1

if(mod(i,2)==0)

continue

endif

sum =i

while(i=100)

Print sum

End

mod是一个系统内置函数,用于计算一个整数被另外一个整数除时的余数,这里用来计算i被2除时的余数,当余数为0时表示i是偶数,否则为奇数。5.2.5函数按照Igor规定的语法规则,将变量、命令、语句组合在一起,形成一个具有明确功能的代码块,就构成了函数。函数是Igor程序设计的功能单位,Igor程序就是由一个个函数构成的。一些命令和操作,如数据拟合、方程求解等,也需要使用由用户指定的函数。正如任何常见的编程语言,Igor的函数概念同样涉及函数声明、修饰符、函数名、参数类型及参数表、返回类型和返回值、函数体等。请看下面的例子: 

Function myFun(a,b)

Variable a,b

Variable c

C=sqrt(a^2 b^2)

Return c

End

这里Function可以理解为修饰符,定义函数必须以Function关键字开头。除了Function之外,函数修饰符还包括Static、Threadsafe,分别用于声明静态函数和线程安全函数。静态函数请参看本书第5.3.2节,线程安全函数请参看本书第7.2.1节。myFun是函数名,可以任意定义,但是必须满足Igor的命名规则,即字母 数字 下画线(数字和下画线不能位于首位)的要求。a和b是参数表,并用圆括号括起来。参数表里不指明参数的类型(Igor Pro7里可以指明),而是紧跟函数后利用相应的关键字声明。注意,可以省略参数,即定义无参数函数,但是圆括号不能省略。参数类型包括数值型、字符串型、wave型、结构体类型等。c是在函数体内定义的一个数值变量,由于没有使用/G选项,因此c是一个局部变量。return语句返回一个值,在这里将c值作为返回值返回给调用myFun的函数。注意,函数可以没有显式return语句,但函数仍有返回值,返回的值及其类型取决Function关键字的选项参数。一个函数体内可以有多个return语句。当执行到return语句时函数会立即停止执行并返回return后面的值。函数的返回类型是由Function的选项指定的,Function选项如下: 

Function [ /C /D /S /DF /WAVE ]方括号表示选项是可选参数,其含义为(1) /C,返回一个复数。(2) /D,返回一个双精度浮点型数值,默认返回类型。(3) /S,返回一个字符串。(4) /DF,返回一个文件夹引用。(5) /WAVE,返回一个wave引用。当返回类型指定以后,return语句后跟的返回值必须与返回类型相对应。例如返回类型是数值时,return后面只能跟数值型结果(不可以是复数),返回类型是字符串时,return后面只能跟字符串型结果。函数在定义后就可以在命令行中直接执行或者在其他函数中调用。在命令行中调用函数的例子如图518所示。

图518在命令行中调用自定义函数

在函数中调用函数的例子如图519所示。

图519在函数中调用函数

第2个例子定义了一个新的函数example,这个函数没有参数,在函数体内调用myFun并将返回值赋给变量v,然后利用print语句将v输出到历史命令行窗口。同样需要在命令行窗口中执行example()函数。注意不要忘记圆括号。再看下面的例子: 

Function/S gettracename()

String s,s1

s=tracenamelist("",";",1)

s1=stringfromlist(0,s)

Return s

End

上面的例子返回当前Graph中包含的曲线中条曲线的名字。读者可以在命令行窗口中执行下面的命令查看上面的例子,结果如图520所示。

Make data1

Display data1

Print gettracename()

图520返回字符串的函数

Igor提供了大量的内置函数,如数学函数sin()、cos()等,其功能和用户自定义函数类似,甚至完全相同,但注意用户自定义函数可以当作命令直接执行,而系统内置函数则必须位于赋值语句的右边或者是有一个变量(可能是非显式的)能接收其返回值的位置。例如直接执行sin(1)会提示错误,而c=sin(1),print sin(1)等则是正确的表达式。此外,用户自定义函数必须在编译后才能使用。5.2.6程序子类型为了方便管理和使用,Igor支持对程序进行分类,方法是在程序声明后用冒号指明程序的类型: 

Function functionname(parameter list):subtype

Window macroname(parameterlist):subtyp

Proc和Macro也可以指明子类型,但常见的都是Function和Window。注意,Window本质上是一个Macro。subtype是一个关键字,用于描述一个类型。当用subtype指明程序子类型后,编译器会记录这些类型,并在需要的场合列出这些程序供用户选择,如指定一个程序的子类型为GraphStyle,则当用户在修改图表外观时,外观设置对话框会自动列出该程序以供用户选择。注意,这些子类型关键字一般都是由Igor自动创建时加上去的,使用者一般不需要专门添加。当然如果需要,添加是可以的。手动添加和系统自动创建时添加的效果完全一样。表54列出了子类型关键字及其含义。

表54程序子类型及其含义

子类型含义适用程序类型Graph在【Windows】|【Graph Macros】下显示MacroGraphStyle在【Windows】|【Graph Macros】及其样式设置时显示MacroGraphMarquee在图表选择框(Marquee)中显示Macro/FunctionTable在【Windows】|【Table Macros】下显示MacroTableStyle在【Windows】|【Table Macros】及其样式设置时显示MacroLayout在【Windows】|【Layout Macros】下显示MacroLayoutStyle在【Windows】|【Layout Macros】及其样式设置时显示MacroListBoxControl给Listbox控件指定回调函数时显示Macro/Function

续表

子类型含义适用程序类型

Panel在【Windows】|【Panel Macros】下显示MacroFitFunc在选择拟合函数时显示FunctionButtonControl给按钮控件指定回调函数时显示Macro/FunctionCheckBoxControl给复选框控件指定回调函数时显示Macro/FunctionPopupMenuControl给弹出式菜单控件指定回调函数时显示Macro/FunctionSetVariableControl给文本框控件指定回调函数时显示Macro/FunctionGraphMarquee关键字提供了一种非常好的用户交互实现方法: 只需要给函数指明graphmarquee子类型,该函数就会出现在【Graphmarquee】菜单中。看下面的例子,结果如图521所示。

Function mymarqueefun():graphmarquee

getmarquee

Print V_left,V_right,V_top,V_bottom

End

Make/O data=x

Display data

图521利用GraphMarquee关键字将函数添加到【Graphmarquee】菜单

当然还有给【Graphmarquee】菜单添加菜单项的其他方法,但是这种方法是简单的。5.2.7参数传递Igor中,函数参数传递有两种方式: 按值传递和按引用传递。按值传递表示调用函数将变量的值传递给被调用函数,按引用传递表示调用函数将变量的引用传递给被调用函数。这类似于C语言中的传递值和传递地址,前者不能修改原变量的值,后者能修改原变量的值。来看一个按值传递的例子: 

Function mainFunc()

Variable v=1

String s="hello"

subroutine(v,s)

Print v,s

End

Function subroutine(v,s)

Variable v

String s

Print v,s

v=2

s="hello,IGOR"

End

在上面的例子中,函数mainFunc调用subroutine,将变量v和s按值传递给subroutine的两个参数v和s,subroutine打印v和s并修改了v和s,由于是按值传递,subroutine中的修改并不会影响mainFunc中的v和s。在这里,v和s是各自函数的局域变量,尽管名字相同,但是二者没有任何关系,读者可以将subroutine的参数起一个不同的名字,效果完全一样。接下来看一个按引用传递的例子。

Function mainFunc()

Variable v=1

String s="hello"

subroutine(v,2,s)

Print s,v

End

Function subroutine(num1.num2,s)

Variable &num1,num2

String &s

num1=num1 num2

S="The sum of the two num is"

Print s,num1

End

图522按引用传递的结果

在上面的例子中,函数subroutine有3个参数,其中第1个参数和第3个参数按照引用传递,由于subroutine获取的是被调用函数的变量的引用(地址),所以可以修改被调用函数中变量的值。在命令行中执行mainFunc(),结果如图522所示。如果是按值传递,则应该输出

Hello 1

The sum of the two num is 3

传递引用的语法格式非常简单,只需在声明函数参数时名称前面添加“&”符号即可,和C语言中引用的声明方式一样。结构体变量在作为参数传递时同样适用这种声明方式。对于使用引用变量作为参数的函数,在调用时还可以将引用变量作为参数,如

Function f1(v)

Variable &v

f2(v)//v是一个变量的引用,传递给f2

End

Function f2(v)

Variable &v

End

请注意,除了用于函数参数之外,不能直接使用“&”符号定义一个变量的引用,如下面的语句是错误的,这点和C语言不一样。另外,也不能将全局变量作为引用传递。

Variable v1

Variable &v=v1

引用的主要目的是一次返回多个函数值。一般而言,同全局变量一样,除非必要,不要使用引用传递参数,否则会增加程序之间的耦合程度,增大由于对某一函数中变量的修改而导致错误出现的概率,通常这些错误难以预测。如果函数的参数是wave,则传递方式全部为按引用传递,这和C语言完全类似。看下面的例子: 

Function routine()

Make/O wave0=x

subroutine(wave0)

End

Function subroutine(w)

Wave w

W=1234

End

上面的例子中,传递给subroutine的参数是wave0的引用,而非wave0里的值。因此在subroutine里对w修改就是对wave0的修改。引用实际上也是一个变量。因此对于wave作为参数的情况,“引用变量”本身是按值传递,而wave则是按引用传递。在subroutine中对引用变量本身的修改不会影响调用函数中引用变量。如在subroutine中执行

Waveclear w

原函数中对wave0的引用(就是wave0本身)并不会被清除,请读者注意体会。5.2.8默认参数很多编程语言支持默认参数。默认参数有两个好处: 支持多态性,可以通过提供不同的参数调用同一个函数,方便记忆; 简化代码,开发者无须为相同的功能编写重复的代码。Igor支持默认参数,定义如下: 

Function f(p1,p2,[p3,vout,s1,w1])

Variable p1,p2

Variable p3

Variable &vout

String s1

Wave w1

End

这里p3、vout、s1、w1都是默认参数。默认参数需要用中括号括起来,可以是任意的数据类型,包括结构体类型,还可以是变量的引用。在调用带有默认参数的函数时,使用“变量名=值”的方式提供默认参数值,变量名就是定义中使用的名字。可以只提供部分默认参数。如上面的函数可以按照下面的方式调用: 

f(1,2)

f(1,2,p3=3)

f(1,2,vout=v) //v是一个数值变量

f(1,2,p3=3,s1=s1) //s1是一个字符串变量 

f(1,2,w1=w) //w是一个wave引用

如果不提供默认参数值,数值型变量默认取0。字符串变量为null字符串。注意strlen函数以null字符串作为参数时返回null而非0。wave引用默认为null wave,即不指向任何wave。在程序中可以使用ParamIsDefault函数判断默认参数是否提供,如果没有提供可以在程序中提供合理的默认值。ParamIsDefault以默认参数名为参数,当默认参数没有提供时,ParamIsDefault返回非0值,否则返回0。

if(paramisdefault(p1))

p1=1

endif

看下面的例子: 

Function maxvalue(a,b,[c])

Variable a,b,c

if(paramisdefault(c))

Return max(a,b)

else

return max(max(a,b),c)

endif

End

在命令行窗口输入: 

Print maxvalue(1,2)

结果如图523所示。

图523默认参数函数调用示例

输入: 

Print maxvalue(1,2,c=3)//注意变量名c不能省略

结果如图524所示。

图524默认参数函数调用示例

5.2.9注释和代码风格良好的注释有助于程序的可读性,有助于理解程序代码,也有助于对程序的升级和维护。注释在程序调试中也很有用。Igor下的程序注释类似于C语言,使用“//”作为注释符号,跟在“//”后面同一行的内容将视作注释内容。不同于C语言里的“/*…*/”注释符号,Igor里没有能注释多行的注释符,需要注释多行时可以在每一行行首打入“//”符号。Igor提供了一个快捷的多行注释的方法,选择要注释的多行代码,然后执行菜单命令【Edit】|【Commentize】可以自动在每一行行首添加注释符,从而实现一次注释多行代码。如果同时取消多行注释可以执行菜单命令【Edit】|【Decommentize】。注释一定要有意义,不要为了注释而注释,比如下面的注释就完全没有必要: 

//计算a b

c=a b

一般应该在关键函数(如通用性非常高的函数)前面添加对函数功能的描述性注释,对函数参数的含义进行注释,如

//这个函数用来拟合×××格式的数据

Function lorf(x,cw):Fitfunc

Variable x//待拟合数据的x坐标值

Wave cw   //拟合参数(初始参数和拟合结果都存放在这个wave里)

//cw[0]: 拟合参数说明

//cw[1]: 拟合参数说明

function  body

End

良好的代码风格能使程序结构清晰,提高程序可读性,避免出错。特别是对于语句的多层嵌套,恰当的缩进显得尤为必要。在编写程序时应该有意识的使用缩进,如if语句可以缩进为如下格式: 

if(ab)

Num_max=a

else

Num_max=b

endif

if里语句块的内容相对于if关键字缩进一个制表符,这样程序看起来结构清晰,层次分明。【Edit】|【Adjust Indentation】可以自动调整缩进,方法是先选择要调整缩进的内容,然后执行该菜单命令。5.3程序设计技术前面详细介绍了Igor下程序设计的基本方法,利用这些知识已经可以编写具有实用性的程序。但是要使得程序功能强大,应用范围更广,则必须利用Igor提供的其他编程特性和技术。这些技术有些为Igor所特有,有些则借鉴了其他优秀编程语言的特点。掌握这些技术是掌握Igor程序设计的必需步骤,和掌握基本语法一样重要。建议读者仔细阅读,并在实践中加以应用。5.3.1Include指令Include指令用于将另外一个程序文件包含在当前程序文件之中。通常将具有类似功能或者通用功能的一组程序存放于一个程序文件之中,并将之另存为一个后缀名为ipf的程序文件。在后续的程序开发中,当需要已经编写好的程序时,就可以通过Include指令直接将包含该程序的文件包含进来,而不需要重新编写相同的代码。通过这种方法也可以很方便地使用他人已经写好的程序。Include指令是Igor下程序设计常使用的编译器指令,必须熟练掌握。Include指令的语法格式非常简单:

#Include procedurefilename

#Include "procedurefilename"

“#”号是必需的,且必须位于行首。#Include可以位于程序文件的任何地方,但是一般都位于程序文件的开头位置。procedurefilename是要被包含的程序文件名,该程序文件必须以ipf作为后缀名,但注意procedurefilename不包括“.ipf”,如被包含的程序文件全名为somename.ipf,则procedurefilename应为somename而不是somename.ipf。编译器会自动打开Include指令所指定的文件,一般可以在【Windows】|【Procedure Windows】里查看已经打开的程序文件。如果取消了Include指令,则被打开的程序文件将会在下一次编译的时候自动关闭。尖括号、引号、procedurefilename的具体形式表示了Include指令获取程序文件位置的4种情况: 1.  #Include filename这条指令用于包含一个名为filename.ipf的程序文件,该程序文件必须位于Igor Folder/WaveMetrics Procedures及其子文件夹下。这里“Igor Folder”指Igor安装目录(下同)。如没有专门强调,下面说的文件夹都是相对于Igor安装目录的。WaveMetrics Procedures文件夹位于Igor安装目录下,里面存放了大量由WaveMetrics提供的ipf程序。每个程序文件里都包含了一系列具有实用价值的的通用函数,程序文件名字描述了这些函数的大致功能,如Image Common.ipf里面包含了大量关于图像处理的通用函数,这些函数可以获取、创建和删除图像等。这些程序文件是在Igor下进行程序设计和开发的范例。当要写一个关于图像处理的程序时,就可以通过下述指令将Image Common.ipf包含进来,这样就不用再重复编写一些通用的函数代码,指令如下: 

#Include Image Common

2. #lnclude “filename”和种情况相比较,这里尖括号变成了双引号,用于包含一个名为filename.ipf的程序文件,该程序文件必须位于User Procedures目录或者Igor User Files/User Procedures目录及其子目录下。Igor User Files/User Procedures位于我的文档下,是Igor在安装时自动创建的一个文件夹。可以通过菜单命令【Help】|【Show Igor User Files】打开该文件夹。User Procedures和Igor User Files/User Procedures专门用于存放由用户开发的程序文件。到底存放在哪个目录下,则看个人习惯,推荐存放在Igor User Files/User Procedures中。当然不管存放于何处,对程序文件的备份都是必需的。假如要包含的程序文件名为proc0.ipf,则包含指令为

#Include "proc0"3. Include “full file path”前面两种情况要求被包含的程序文件必须位于特定的目录下,这并不是必需的。可以用双引号指定程序文件的完整路径,此时程序文件可以位于任何地方。例如,程序文件位于E盘下的tmp文件夹中,文件名为myproc.ipf,则包含指令可以为

#Include "E:tmp:myproc"

注意,这里文件路径格式是Igor下的文件路径格式,也可以使用E:\tmp\myproc这样的格式。4. Include “patial file name”除了指定程序文件的路径,还可以指定程序文件的相对路径,此时Igor首先从User Procedures文件夹中寻找,如果失败再从Igor User Files/User Procedures文件夹中寻找,如果再失败则从当前使用#Include指令的程序文件所在的文件夹中寻找。假如当前程序文件位于E:\tmp\myproc.ipf,要包含的程序文件位于E:\tmp\categary1\proc1.ipf,则包含指令为

#Include ":categary1:proc1"

如果要包含的程序文件位于E:\tmp\proc1.ipf,即和主程序文件myproc.ipf位于同一个目录下,则包含指令为

#Include":proc1"

这里冒号不能省略,否则会导致错误。常用的Include方法是第2种,第3种和第4种。由于包含路径信息,当程序文件的路径信息不小心被改变(如程序从一台计算机复制到另外一台计算机)时就会出现找不到文件而无法编译的错误,这种情况是非常容易出现的。因此除非必要,不建议读者采用后两种方法。使用第2种方法,只需要将程序文件放入User Procedures或Igor User Files/User Procedures文件夹中,就可以通过程序文件名方便地包含该文件。5.3.2Pragma参数在每一个程序编辑窗口前几行都有一个#Pragma的参数,如图525所示。

图525Pragma参数

这个参数的作用是设定编译器模式或者向编译器传递一些有用的信息。#Pragma参数一般位于程序文件之首,且#号不能与窗口左侧存在任何空格或者是制表符,其声明形式如下: 

#Pragma keyword [ = parameters ]

目前,Igor支持以下6种Pragma参数(Igor Pro 6.37及以前):

#pragma rtGlobals = value

#pragma version =  versionNumber

#pragma IgorVersion = versionNumber

#pragma ModuleName =  name

#pragma hide=1

#pragma IndependentModule =  name

#Pragmas参数只影响它所处的程序文件。下面介绍每一个参数的具体含义。1. rtGlobals参数rtGlobals参数用于指定编译器的行为和程序运行时对错误的处理方法。rtGlobals参数取值为数字0、1、2、3,其含义与Igor的发展有关。早期的Igor版本(早于Igor 3,本书Igor版本新于6.37),在函数中访问一个全局变量或者wave时,要求全局变量和wave必须在编译阶段就存在,否则无法编译。在Igor 3版本中引入了“运行时查找变量”的技术,即在编译阶段,编译器并不要求全局变量和wave存在,只是在运行时才将全局变量和与其引用(wave、nvar、svar)关联起来。在Igor 6.20以后又引入了对wave引用和wave长度的严格检查。rtGlobals不同取值就是反映了Igor这种版本演化的行为,其主要目的是实现不同版本之间的兼容性。

#pragma rtGlobals=0

这是Igor早期版本的编译器模式,不应该继续使用。

#pragma rtGlobals=1

打开“运行时查找变量”技术,使用此选项,编译器在编译时并不检查被引用的全局变量是否存在,一般是默认选项,本书中绝大多数例子都是在此模式下编写的



原文赏析:

暂无原文赏析,正在全力查找中!


其它内容:

编辑推荐

配套资源    本书配套提供源代码,下载地址为清华大学出版社网站本书页面。专家评论本书涉及的主题? Igor Pro的基本概念和使用? Igor Pro的基本对象? Igor Pro的图表绘制? Igor Pro数据拟合的方法和技巧? Igor Pro数据处理的基本方法? Igor Pro程序设计的基本概念? Igor Pro命令行程序的设计? Igor Pro窗口程序的设计? Igor Pro高级程序设计的技巧


书摘插图


前言

前言

《Igor Pro实用教程——图表绘制、数据分析与程序设计》终于要和读者见面了。此时,我内心非常激动。

这里首先介绍本书创作的缘由。

在笔者就读大学期间,还未听说过Igor Pro。当时,我处理数据用的是Turbo C 3.0。由于没有意识到数据处理软件这种工具的存在(比如基本的Excel),我觉得数据处理就是编程。以至于后来,我甚至构建了一个雄伟的计划: 利用Turbo C设计一个数据处理软件,基本功能是绘图和小二乘法,甚至连软件架构都写好了。遗憾的是,因为没有计算机,加之学校的机房上机费太贵,这个计划终被搁浅了(幸亏如此)。随着升入高年级,实验课结束,这个计划终于被彻底忘记了。不过,这种编程处理数据的思路终还是让我受益匪浅。本书介绍的Igor Pro就是适合通过编程处理数据的工具。

上研究生时,实验数据处理这个问题再次出现。不过我发现不能再继续用Turbo C 3.0了,因为实验室所有的人都在用Igor Pro,所以我开始了Igor Pro的学习和使用。学习Igor Pro的经历是值得回顾的。

记得次看到这个软件,感觉很茫然。

按照以往的经验,不懂的内容可以通过Google搜索。可是在Igor Pro的学习过程中,我从来没有用过一次Google或者百度,甚至连这种意识都没有(我想本书的读者和我也是一样的)。原因很简单,网上没有任何关于Igor Pro的学习资料。我能做的,就是向同实验室的人请教,自己在挫折中慢慢摸索; 阅读现有的代码,掌握Igor Pro的基本使用方法。这里我不得不感谢我的导师周兴江研究员,他不仅仅是一位在超导研究领域取得卓越成就的科学家,也是一位出色的Igor Pro编程大师。我今天关于Igor Pro的认识,应该说就是从研究他的代码开始的。

学习的经历是艰辛的。任何一个小问题的解决都不容易。现在回顾起来,我发现走了很多弯路,不仅仅是学习的弯路,还有使用的弯路。当时使用的很多方法其实非常笨拙,效率非常低。比如一个基本的问题,当时程序运行的速度比较慢,绘制一幅费米面的图需要半分钟左右,大家都认为是Igor Pro的问题。后来我发现不是,是我们没有理解Igor Pro下的程序设计机制,没有搞清楚Proc和Function的关系。在搞清楚这个问题后,我对所有的程序进行了一次彻底的升级。然后突然发现,以前几分钟的计算现在一眨眼就可以完成。很难想象我们一直在这种低效率的工作状态下使用Igor Pro很多年,仅仅是因为不了解Proc和Function所致!

诸如此类的问题非常多,如图表绘制、数据拟合、算法设计等,不胜枚举。很显然,要做好这些工作,需要很好地了解Igor Pro。

遗憾的是Igor Pro的学习资料太少了。Igor Pro其实是一款非常优秀的数据处理软件,特别是处于大数据时代的今天,它能将编程与数据可视化完美地融为一体,既具有Python、R等脚本编程语言的可扩展性,又具有Origin等数据可视化工具的方便易用性,十分难得。但由于软件的语言(英语)、需要编程的特性以及用户使用群体(主要集中在国外)等原因,Igor Pro一直未被广大用户所了解。这样造成的后果就是没有人去讨论和贡献自己对Igor Pro的心得和使用技巧。Igor Pro本身的软件文档写得非常好,但是作为一个手册,其实是不适合初学者的,只有在一定的基础上看软件文档,才有效果。初学者直接看文档,很容易感到迷茫。

由于学习资料的匮乏,很多人,特别是刚进入实验室的人员对Igor Pro望而生畏,转而去选择其他的工具。其实,Igor Pro更适合他们,更适合他们处理数据。于是,Igor Pro的潜在使用者就这么流失了。反过来,这又影响了后来的人去选择Igor Pro。

虽然有所谓酒香不怕巷子深的古训,但是,如果酒是香的,为什么不能将它放到浅一点的巷子里呢?好东西应该是被大众所共享的,而不应只属于个别“资深酒客”。

在这么多年使用Igor Pro的过程中,在帮助他人解决Igor Pro的一些问题时,我对Igor Pro的认识也越来越深刻。我发现,Igor Pro能做的其实远比我们想象的多。但是,很多人,包括在实验室里天天使用Igor Pro的人们,却没有意识到,其实他们使用Igor Pro的水平并不高(这当然是完全可以理解的,由于更专注于科学研究,他们不可能在这上面花太多精力)。

所有的这些,促使我决定编写一本关于Igor Pro使用的书籍,把我这么多年来对Igor Pro的使用心得和经验总结出来,公布于众。所谓授人以鱼,不如授人以渔。我的目的就是希望读者在使用Igor Pro遇到困惑时,能知道去哪儿找到解决问题的方法,少走一些弯路,而不是只寄希望于求助别人或者浪费很多的时间。同时,也更希望读者能利用本书中提到的知识提高数据处理效率,节约时间和精力。当然,我知道本书离这个目标还很远,但至少这是一个好的开始。

本书真正的写作始于两年前。这个过程和我学习Igor Pro的经历一样,也是艰辛的: 没有资助,缺乏参考资料只能利用业余时间创作。所有的一切都是靠兴趣、靠对Igor Pro的热爱在支撑。当然这很正常,任何一个新的领域在刚开始时都是这样的。既然还没人做这件事情,那么就从我开始吧。

本书的体例结构都是经过精心设计的,目的就是突出实用性。各章节结构具有相对的独立性,每一小节一般都对应于Igor Pro某个方面的使用。建议读者仔细阅读第1章和第5章,前者是Igor Pro工作原理的基础,后者是程序设计的基础。其他各章节可在需要的时候选择性阅读。另外,读者在阅读本书时,可结合Igor Pro自带的软件手册进行学习,这样会获得事半功倍的效果。

在完成本书的过程中,我曾与周兴江研究员、谢卓晋博士、物理所超导实验室SC7组进行过多次讨论,书中很多创作的灵感都来源于这些讨论,在此表示谢意。

清华大学出版社的盛东亮编辑在本书出版的过程中给了我很大的帮助。盛编辑对新事物的开放和支持态度,对教育科技知识推广的责任心,值得敬佩。这里表示谢意。

后,由于本书是此领域的本书,也限于我的水平,书中难免存在错误之处。在这里恳请读者在阅读过程中发现错误能及时指出,以便我及时修正。

贾小文

2018年1月于天津



书籍真实打分

  • 故事情节:8分

  • 人物塑造:8分

  • 主题深度:8分

  • 文字风格:7分

  • 语言运用:5分

  • 文笔流畅:9分

  • 思想传递:4分

  • 知识深度:3分

  • 知识广度:8分

  • 实用性:7分

  • 章节划分:3分

  • 结构布局:4分

  • 新颖与独特:9分

  • 情感共鸣:9分

  • 引人入胜:3分

  • 现实相关:8分

  • 沉浸感:7分

  • 事实准确性:5分

  • 文化贡献:3分


网站评分

  • 书籍多样性:4分

  • 书籍信息完全性:8分

  • 网站更新速度:7分

  • 使用便利性:4分

  • 书籍清晰度:4分

  • 书籍格式兼容性:8分

  • 是否包含广告:7分

  • 加载速度:7分

  • 安全性:7分

  • 稳定性:9分

  • 搜索功能:3分

  • 下载便捷性:8分


下载点评

  • 值得购买(232+)
  • 全格式(452+)
  • 三星好评(76+)
  • 中评(389+)
  • 情节曲折(538+)
  • 内容齐全(497+)
  • 博大精深(666+)
  • 体验满分(189+)
  • 内涵好书(428+)

下载评价

  • 网友 扈***洁: ( 2024-12-23 03:43:51 )

    还不错啊,挺好

  • 网友 寿***芳: ( 2025-01-15 05:15:08 )

    可以在线转化哦

  • 网友 冉***兮: ( 2024-12-30 07:11:33 )

    如果满分一百分,我愿意给你99分,剩下一分怕你骄傲

  • 网友 权***颜: ( 2024-12-28 06:16:25 )

    下载地址、格式选择、下载方式都还挺多的

  • 网友 瞿***香: ( 2024-12-21 12:05:18 )

    非常好就是加载有点儿慢。

  • 网友 通***蕊: ( 2025-01-11 01:33:24 )

    五颗星、五颗星,大赞还觉得不错!~~

  • 网友 相***儿: ( 2024-12-24 01:44:42 )

    你要的这里都能找到哦!!!

  • 网友 后***之: ( 2025-01-12 06:37:55 )

    强烈推荐!无论下载速度还是书籍内容都没话说 真的很良心!

  • 网友 康***溪: ( 2025-01-19 04:18:13 )

    强烈推荐!!!

  • 网友 宫***玉: ( 2024-12-26 23:58:54 )

    我说完了。

  • 网友 苍***如: ( 2025-01-12 16:22:13 )

    什么格式都有的呀。

  • 网友 游***钰: ( 2024-12-28 17:09:05 )

    用了才知道好用,推荐!太好用了


随机推荐