加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

第三章:IDL编程基础

(2018-03-18 11:58:00)
标签:

idl开发

编程基础

过程和函数

控制语句

参数和关键字

分类: IDL开发

3.1 过程和函数

1、过程(无返回)

PRO 过程名 [,参数1,参数2,...,参数n,][,关键字1,关键字2,...,关键字n,]

  命令序列

END

    过程需要先编译或保存后才能执行,且最好工程名与文件名相同。

例:角度转换为弧度:

1)无输入参数:

PRO radian

  deg=180

  radian=deg*!DTOR

  PRINT,radian

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\radian.pro'

% Compiled module: RADIAN.

IDL> radian

% Compiled module: RADIAN.

      3.14159

2)有输入参数:

PRO radian,deg

  radian=deg*!DTOR

  PRINT,radian

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\radian.pro'

% Compiled module: RADIAN.

IDL> radian,60

      1.04720

IDL> radian,150

      2.61799

IDL> radian,180

      3.14159

注意:在过程编译后,IDL进程中的任何语句和程序都可以调用该过程。但是,当IDL进程重启后需要重新编译到内存中,否则无法调用。

2、函数(有值返回)

FUNCTION 函数名 [,参数1,参数2,...,参数n][,关键字1,关键字2,...,关键字n]

  命令序列

  RETURN,表达式

END

调用方式为:

变量=函数名([,参数1,参数2,...,参数n][,关键字1,关键字2,...,关键字n])

例:角度转换为弧度:

FUNCTION radianf,deg

  radian=deg*!DTOR

  RETURN,radian

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\radianf.pro'

% Compiled module: RADIANF.

IDL> result1=radianf(60)

IDL> result1

       1.0471976

IDL> radianf(180)

       3.1415927

注意:在过程编译后,IDL进程中的任何语句和程序都可以调用该过程。但是,当IDL进程重启后需要重新编译到内存中,否则无法调用。

3、程序的相互调用

IDL的过程、函数之间可以相互调用,从而组合出更为复杂的应用。

例:计算长方体体积

PRO volumep

  x=3 & y=4 & z=5

  result=volumep(x,y,z)

  PRINT,'长方体体积',result

END

FUNCTION volumep,x,y,z

  RETURN,x*y*z

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\volumef.pro'

% Compiled module: VOLUMEF.

IDL> .compile -v 'D:\005-IDL\Default\my_pro\volumep.pro'

% Compiled module: VOLUMEP.

IDL> volumep

% Compiled module: VOLUMEP.

长方体体积      60

3.2控制语句

IDL有三种基本的程序结构:顺序结构、选择结构和循环结构。

1、选择结构

1IF语句

1)当if后面条件表达式为真时,执行语句序列。

IF 条件表达式 THEN 语句

或者

IF 条件表达式 THEN BEGIN

  语句序列

ENDIF

2)当if后面条件表达式为真时,执行语句序列;当条件表达式为假时,执行endelse后面的语句序列。

IF 条件表达式 THEN 语句1 ELSE 语句2

或者

IF 条件表达式 THEN BEGIN

  语句序列1

ENDIF ELSE BEGIN

  语句序列2

ENDELSE

3)当if后面条件表达式为真时,执行语句序列;当条件表达式为假时,执行endelse后面的语句序列;……;直到endelse为止。

IF 条件表达式1 THEN BEGIN

  语句序列1

ENDIF ELSE IF 条件表达式2 THEN BEGIN

  语句序列2

ENDIF ELSE IF 条件表达式3 THEN BEGIN

  语句序列3

  ......

ENDIF ELSE BEGIN

  语句序列n

ENDELSE

注意:在使用if语句时,需要注意ifendifelseendelse必须配对使用,else语句以endelse结束而不是endif

1if语句应用实例:

第三章:IDL编程基础 ,计算y值。

FUNCTION test1,x

  IF x GE 0 THEN BEGIN

    y=SQRT(x)

  ENDIF ELSE BEGIN

    y=SQRT(-x)

  ENDELSE

  RETURN,y

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\test1.pro'

% Compiled module: TEST1.

IDL> TEST1(25)

       5.0000000

IDL> TEST1(-25)

       5.0000000

2if语句嵌套应用实例:

第三章:IDL编程基础 ,计算y值。

FUNCTION test2,x

  IF x GE 1 THEN BEGIN

    y=SQRT(x)

  ENDIF ELSE BEGIN

    IF x LT -1 THEN BEGIN

      y=SQRT(-x)

    ENDIF ELSE BEGIN

      y=1

    ENDELSE

  ENDELSE

  RETURN,y

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\test2.pro'

% Compiled module: TEST2.

IDL> TEST2(25)

       5.0000000

IDL> TEST2(0)

       1

IDL> TEST2(-25)

       5.0000000

2CASE语句

CASE 表达式0 OF

  表达式1:语句1

  表达式2:语句2

  表达式3BEGIN

    语句序列1

  END

  ......

  表达式N:语句n

ELSE:语句n+1

ENDCASE

例:输入0-9数字,输出英语:

PRO number,n

  CASE n OF

    1:PRINT,'one'

    2:PRINT,'two'

    3:PRINT,'three'

    4:PRINT,'four'

    5:PRINT,'five'

    6:PRINT,'six'

    7:PRINT,'seven'

    8:PRINT,'eight'

    9:PRINT,'nine'

    ELSE:PRINT,'wrong'

  ENDCASE

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\number.pro'

% Compiled module: NUMBER.

IDL> number,1

one

IDL> number,5

five

IDL> number,9

nine

3SWITCH语句

SWITCH 表达式0 OF

  表达式1:语句1

  表达式2:语句2

  表达式3BEGIN

    语句序列1

  END

  ......

  表达式N:语句n

ELSE:语句n+1

elseswitch

注意:如果switch语句执行过程中想在某条语句执行完之后退出,需要在这一语句条后面加上break语句。Break语句能够直接跳出switch语句,转向endswitch语句后面的语句。

例:输入0-9数字,输出英语:

PRO snumb,n

  SWITCH n OF

    1:BEGIN

      PRINT,'one'

      BREAK

    END

    2:BEGIN

      PRINT,'two'

      BREAK

    END

    3:BEGIN

      PRINT,'three'

      BREAK

    END

    4:BEGIN

      PRINT,'four'

      BREAK

    END

    5:BEGIN

      PRINT,'five'

      BREAK

    END

    6:BEGIN

      PRINT,'six'

      BREAK

    END

    7:BEGIN

      PRINT,'seven'

      BREAK

    END

    8:BEGIN

      PRINT,'eight'

      BREAK

    END

    9:BEGIN

      PRINT,'nine'

      BREAK

    END

    ELSE:PRINT,'wrong'

  ENDSWITCH

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\snumb.pro'

% Compiled module: SNUMB.

IDL> SNUMB,1

one

IDL> SNUMB,5

five

IDL> SNUMB,7

seven

2、循环结构

1FOR语句

    用于循环次数已知的情况按照指定的次数来重复执行循环体。

FOR i=m,n DO 语句

或者

FOR i=m,n,inc DO 语句

或者

FOR i=m,n,inc DO BEGIN

  语句序列

ENDFOR

注:当im以步长inc(若不设置,默认为1)逐步变化到n时,循环执行语句。

例:计算1-100所有整数之和:

PRO total100

  total_value=0

  FOR i=1,100,1 DO BEGIN

    total_value=total_value+i

  ENDFOR

  PRINT,total_value

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\total100.pro'

% Compiled module: TOTAL100.

IDL> total100

% Compiled module: TOTAL100.

    5050

2WHILE语句

    一般在事先不能确定循环次数的情况,根据一个条件表达式的值来重复执行循环体。

WHILE 条件表达式 DO 语句

或者

WHILE 条件表达式 DO BEGIN

  语句序列

ENDWHILE

    当条件表达式的值为真时,while语句循环体执行语句序列,其特点是先判断循环条件,如果条件满足,再执行循环体。

    需要注意的是,循环过程中一定要能够改变条件表达式的值,或者使用其他方法来跳出循环,否则会陷入死循环。

例:计算1-100所有整数之和:

PRO total_while

  total_value=0

  i=1

  WHILE i LE 100 DO BEGIN

    total_value=total_value+i

    i=i+1

  ENDWHILE

  PRINT,total_value

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\total_while.pro'

% Compiled module: TOTAL_WHILE.

IDL> total_while

% Compiled module: TOTAL_WHILE.

    5050

3REPEAT语句

    先执行循环体,然后在判断条件表达式。哪怕是条件表达式为假,循环体也要执行一次。

REPEAT 条件表达式 UNTIL 语句

或者

REPEAT BEGIN

  语句序列

ENDREP UNTIL 条件表达式

例:计算1-100所有整数之和:

PRO total_rep

  total_value=0

  i=0

  REPEAT BEGIN

    total_value=total_value+i

    i=i+1

  ENDREP UNTIL (i Gt 100)

  PRINT,total_value

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\total_rep.pro'

% Compiled module: TOTAL_REP.

IDL> total_rep

% Compiled module: TOTAL_REP.

    5050

4)循环语句的嵌套

    Forwhilerepeat等循环控制语句可以彼此嵌套使用,但是要注意forendforwhileendwhilerepeatendrep的配对,尤其注意嵌套时不能出现交叉。

例:判断一个数字是否为素数。

PRO qiantao,num

  flag=0

  num1=FIX(SQRT(num))

  FOR i=2,num1 DO BEGIN

    IF num MOD i EQ 0 THEN flag=1

  ENDFOR

 

  IF flag EQ 0 THEN BEGIN

    PRINT,'该数字是素数'

  ENDIF ELSE BEGIN

    PRINT,'该数字是素数'

  ENDELSE

END

保存、编译并调用:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\qiantao.pro'

% Compiled module: QIANTAO.

IDL> QIANTAO,5

该数字是素数

IDL> QIANTAO,99

该数字是素数

IDL> QIANTAO,500

该数字是素数

3CONTINUEBREAK语句

    Continue语句只能用在forwhilerepeat等循环语句中,作用是终止当前次循环体运行,并跳转到判断循环条件的语句处,继续下一次的循环。

    Break语句用于在forwhilerepeat等循环语句或者caseswitch等选择语句中,强制结束循环或选择过程,将程序流程转换或者选择语句后的下一条语句。

    注意:如果break语句用于循环或选择语句的嵌套过程中,那么只能用于退出当前循环或者选择的层次结构,并不能终止多层循环或者选择。

例:continue举例:

PRO continue_test

  FOR i=1 , 2 DO BEGIN

    FOR j=1 , 3 DO BEGIN

      IF j EQ 2 THEN CONTINUE

      PRINT, i , j

    ENDFOR

  ENDFOR

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\continue_test.pro'

% Compiled module: CONTINUE_TEST.

IDL> continue_test

% Compiled module: CONTINUE_TEST.

            1

            3

            1

            3

例:break举例:

PRO break_test

  FOR i=1 , 2 DO BEGIN

    FOR j=1 , 3 DO BEGIN

      IF j EQ 2 THEN BREAK

      PRINT, i , j

    ENDFOR

  ENDFOR

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\break_test.pro'

% Compiled module: BREAK_TEST.

IDL> break_test

% Compiled module: BREAK_TEST.

            1

            1

4、综合举例

    81只米袋,由12匹马来驼。马分大、中、小三种马,每匹大马驼8袋米,每匹马驼7袋米,每匹小马驼5袋米,其中中马数量最多,问大、中、小马各几匹?

PRO computations

  result=BYTARR(3,100)

  ii=0

  FOR i=0,12 DO BEGIN

    FOR j=0,12 DO BEGIN

      FOR k=0,12 DO BEGIN

        IF 8*i+7*j+5*k EQ 81 AND i+j+k EQ 12 THEN BEGIN

          result [*,ii]=[i,j,k]

          ii=ii+1

          CONTINUE

        ENDIF

      ENDFOR

    ENDFOR

  ENDFOR

  result=result[*,0:ii-1]

  maxv=MAX(result[1,*],index)

  print,'大马:',result[0,index],';中马:',result[1,index],';小马:',result[2,index]

END

保存、编译与运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\computations.pro'

% Compiled module: COMPUTATIONS.

IDL> computations

% Compiled module: COMPUTATIONS.

大马  1;中马  9;小马  2

 

3.3参数和关键字

1、参数

IDL的参数主要用于程序相互调用过程中值的传递。

    参数的定义语法:

PRO/FUNCTION 过程名/函数名,参数1,参数2,...,参数n

例:

PRO canshu,a

  PRINT,a^2

END

保存、编译并运行:

% Compiled module: CANSHU.

IDL> canshu,5

      25

例:

IDL> systime()

Sat Mar 17 21:49:40 2018

IDL> systime(0)

Sat Mar 17 21:49:45 2018

IDL> systime(1)

       1521294605.7300000

2、关键字

    关键字是IDL除了参数以外,另一种在不同程序间传递数据的方式。

    定义语法结构:

PRO/FUNCTION  过程名/函数名,关键字1=关键字变量1,...,关键字n=关键字变量n

注:等号左边是关键字名,仅起标识作用,而右边的关键字变量才是过程/函数运行时真正正使用的变量。

    关键字也必须先定义再使用。调用的时候,应先写出关键字名,然后在等号右边给出对应的关键字变量。

    除了用于传递数据,关键字还可以用于环境或功能设置选项的“开关”,即使使其生效或者失效。关键字在这种用途时具有二进制的特性,仅仅具有真和假两种开关状态,可以用“/关键字”来简化表达“关键字=1”的意思。

例:

IDL> arr=fltarr(10,20)

IDL> size(arr)

                   10          20                  200

IDL> size(arr,/dimensions)

          10          20

IDL> size(arr,dimensions=1)

          10          20

IDL> size(arr,dimensions=0)

                   10          20                  200

3、值传递和地址传递

    1值传递:指在调用过程/函数时,仅仅把参数/关键字变量的值传递给相应过程/函数的形参,过程/函数的执行不会影响参数/关键字变量的原值

    2按地址传递:指在调用过程/函数时,把参数/关键字变量的地址传递给相应过程/函数的形参,此时形参和实参指向同一个地址,过程/函数执行时对形参的操作实际上就是对实参的操作如果过程/函数执行时改变了形参的值,那么改变的值将替代参数/关键字变量的原值

注:IDL参数和关键字的类型决定了它是按照地址传递还是值传递。变量名、数组名、结构体名和指针代表着数据的地址,因为这些作为参数或关键字的时候其传递方式为地址传递;而常量、子数组、结构体的域和表达式作为参数或关键字的时候其传递方式为值传递。另外,系统变量因为不允许被改变,其作为参数或关键字的时候也是值传递

例:

IDL> data=[4,5,6]

IDL> data^2

      16      25      36

IDL> data

                 6

IDL> data[*]^2

      16      25      36

IDL> data

                 6

4、参数和关键字的检测

        为了保证过程/函数的顺利执行,在过程/函数的开头可以对参数和关键字进行检测。

函数n_params()用于统计参数的数目:

函数keyword_set()用于检测某参数/关键字是否被设定,如果该参数/关键字已经设定,返回值为1,否则为0.

例:

PRO setting_check,p1,p2,k1=k1

  PRINT,'参数数目:',N_PARAMS()

  PRINT,'参数p1是否被设定:',KEYWORD_SET(p1)

  PRINT,'参数p2是否被设定:',KEYWORD_SET(p2)

  PRINT, '参数k1是否被设定:',KEYWORD_SET(k1)

END

保存、编译并运行:

IDL> .compile -v 'D:\005-IDL\Default\my_pro\setting_check.pro'

% Compiled module: SETTING_CHECK.

IDL> setting_check

% Compiled module: SETTING_CHECK.

参数数目:           0

参数p1是否被设定:       0

参数p2是否被设定:       0

参数k1是否被设定:       0

3.4变量的作用域

1、局部变量

    局部变量仅仅在某个过程/函数内部起作用。也就是说,局部变量只能在定义它的过程/函数内部使用,而不能在其他过程/函数内使用。

    注意:若在程序中调用了另一个过程/函数,则在原程序中的局部变量在所调用的另一个过程/函数中是无效的。不同的过程/函数中可以使用相同的局部变量名,但它们属于不同过程/函数的变量,作用域是不同的,均在定义他们的过程/函数中起作用。

例:

PRO lob1

  a=1B & b=2B & c=3B

  HELP, a,b,c

  PRINT, 'lob1中的变量:','a=',a,', b=',b,', c=',c

  lob2

  PRINT, 'lob1中的变量:','a=',a,', b=',b,', c=',c

END

 

PRO lob2

  b=2.0

  PRINT, 'lob2中的变量:', 'b=',b

END

编译lob2、编译lob1并运行lob1

IDL> .compile -v 'D:\005-IDL\Default\my_pro\lob2.pro'

% Compiled module: LOB2.

IDL> .compile -v 'D:\005-IDL\Default\my_pro\lob1.pro'

% Compiled module: LOB1.

IDL> lob1

% Compiled module: LOB1.

              BYTE        1

              BYTE        2

              BYTE        3

lob1中的变量:a=   1, b=   2, c=   3

lob2中的变量:b=      2.00000

lob1中的变量:a=   1, b=   2, c=   3

2、全局变量

    全局变量在整个程序运行过程中始终有效,它可以被多个过程/函数所公用。IDL的全局变量包括系统变量公共变量

    1)系统变量包括常数变量、图形变量、系统配置变量和错误处理变量等,以!来开头与其他变量区分。

    2)公共变量通过commo语句进行定义和使用。

    注意:第一个引用common语句的过程/函数定义了该公共变量包含的变量数目。公共变量块定以后,就可以在任意过程/函数中引用。但是需要先声明再引用。声明的格式与定义时的格式相同。但是需要注意的是,公共变量块定义后其包含的变量数目不能改变,但是变量的类型和大学可以修改

例:

PRO comm1

  COMMON set_value,a

  a=10

END

 

PRO comm2

  COMMON set_value,a

  PRINT,'a=',a

END

 

IDL> .compile -v 'D:\005-IDL\Default\my_pro\comm1.pro'

% Compiled module: COMM1.

IDL> .compile -v 'D:\005-IDL\Default\my_pro\comm2.pro'

% Compiled module: COMM2.

IDL> comm1

% Compiled module: COMM1.

IDL> comm2

% Compiled module: COMM2.

a=      10

注:公共变量块就像一个纽带,将不同的过程/函数联系起来。但是使用公共变量会降低程序的通用型和可移植性。

3.5其他

1IDL程序优化

1)以数组为操作主体

IDL是面向数组的语言,能够对数组直接进行运算。在编程过程中要尽量对数组整体进行运算,而不要使用循环对数组元素进运算。

例:内存中有一个NDVI数据(1000行×1000列),要求计算所有大于等于0.3的像元NDVI值的平均值。

For循环实现:

PRO ndvi_test,ndvi_cal

  t1=SYSTIME(1)

 

  total_value=0.0

  count=0L

  FOR i=0 ,999 DO BEGIN

    FOR j=0 ,999 DO BEGIN

      IF ndvi_cal[i,j] GE 0.3 THEN BEGIN

        total_value=total_value+ndvi_cal[i,j]

        count=count+1

      ENDIF

    ENDFOR

  ENDFOR

  PRINT,total_value/count

 

  t2=SYSTIME(1)

  t=t2-t1

  PRINT,'耗时(秒):',t

END

Wheremean函数实现:

PRO ndvi_test2,ndvi_cal

  t1=SYSTIME(1)

  w=WHERE(ndvi_cal GE 0.3)

  PRINT,mean(ndvi_cal[w])

  t2=SYSTIME(1)

  t=t2-t1

  PRINT,'耗时(秒):',t

END

编译ndvi_testndvi_test2,调用:

IDL> ndvi_cal=randomu(undefinevar,1000,1000)

IDL> .compile -v 'D:\005-IDL\Default\my_pro\ndvi_test.pro'

% Compiled module: NDVI_TEST.

IDL> ndvi_test,ndvi_cal

     0.649629

耗时(秒):      0.15400004

IDL> .compile -v 'D:\005-IDL\Default\my_pro\ndvi_test2.pro'

% Compiled module: NDVI_TEST2.

IDL> ndvi_test2,ndvi_cal

     0.649585

耗时(秒):    0.0079998970

    从上可以看出,两者运行时间相差近20倍,可见数组整体运算的程序得到了显著优化。

2)内存管理

        编写IDL程序的过程中,定义的变量越少越好,并尽量可能少的使用全局变量,而通过参数和关键字传递数据。

        1)过程delvar 用于从内存中直接清除某个或者某几个变量并释放内存,但是仅适用于命令行方式。

用法:delvar,var1,var2,...,varn

例:

IDL> a=randomu(undefinevar,1000,1000)

IDL> help,a

              FLOAT     = Array[1000, 1000]

IDL> delvar,a

IDL> help,a

              UNDEFINED =

        2)函数temporary用于返回某个变量的临时备份,该条语句执行完之后即释放改变量对应的内存。

用法:temporary(var)

例:

IDL> a=randomu(undefinevar,1000,1000)

IDL> help,a

              FLOAT     = Array[1000, 1000]

IDL> b=temporary(a)*10

IDL> help,a,b

              UNDEFINED =

             FLOAT     = Array[1000, 1000]

    此外,IDL8.0以上版本提供了系统变量!NULL(未定义变量),额可以通过将某个变量直接赋值给!NULL来释放内存。

例:

IDL> a=randomu(undefinevar,1000,1000)

IDL> help,a

              FLOAT     = Array[1000, 1000]

IDL> a=!Null

IDL> help,a

              UNDEFINED = !NULL

2调用外部命令

        过程spawn用于调用外部程序,产生一个子进程来执行一个命令或者一系列命令。

语法:spawn[,command][,/hide]

参数command为待执行的命令,关键字hide用于隐藏命令行窗口。

例:

IDL> spawn,'start "" "D:spanw_test.txt"',/hide

http://s4/bmiddle/0070Uystzy7iZcU09Gzb3&690


     转载请注明博文地址: http://blog.sina.com.cn/gser2017 

     博主邮箱:zhangguoshunshzu@sina.com


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有