Basics of the SpectraLab Scripting Language


Necessary Elements of Forth programming

The SpectraLab scripts should be written according to the general rules of the Forth programming with the use of either standard operators of Win32Forth or SpecrtraLab-specific operators (to be described below). The very basics principles of Forth programming, which SpectraLab user has to know in order to write SpectraLab scripts are briefly summarized below. More detailed information on Forth programming including several Forth tutorials, Win32Forth reference, and a description of ANS Forth standard may be found in "Forth Programming Guide" section of this Help. 

Besides arithmetic operators mentioned above, there are several operators on the stacks useful in writing mathematical expressions. The pairs of operators listed in the first and the second columns of the table below operate on the stacks of natural and floating-point numbers, respectively:

Stack of integers Floating-point stack Performed operation
SWAP FSWAP Swaps the top two layers of the stack: n1 n2 -> n2 n1
DROP FDROP Drops the top layer: n1 n2 -> n1
DUP FDUP Duplicates the top layer: n1 -> n1 n1
2DUP F2DUP Duplicates the two topmost layers: n1 n2 -> n1 n2 n1 n2
OVER FOVER Copies the second layer to the top: n1 n2 -> n1 n2 n1
ROT FROT Rotates the three top layers: n1 n2 n3 -> n2 n3 n1

Similar operators (#SWAP, #DUP, etc.) are also defined for the operations on the stack of traces (see below). Note that attempts to apply floating-point operations to integers and vice versa will result in a "Stack underflow" error.

SpectraLab-specific stack of traces and its use

In addition to the Forth-native stacks of integers and floating-point numbers, SpectraLab also uses its customary-defined stack of traces (spectra) for operations on the whole traces.

Glossary of SpectraLab-specific operators that can be used in command-line scripts

   #: ( n / -- ; -- / -- ; -- / #n)
     Places the  trace #n into the stack of traces
   #! ( n / -- ; -- / -- ; #A / -- )
     Places the trace from the top of the stack of traces into location #n
   Y:: ( n1 n2 / -- ; -- / Y[n1,n2] ; -- / -- )
     Returns the ordinate value of the point n2 from the trace n1. The result is placed at the top of the stack of reals.
   X:: ( n1 n2 / -- ; -- / X[n1,n2] ; -- / -- )
     Returns the abscissa value of the point n2 from the trace n1. The result is placed at the top of the stack of reals.
   Z: ( n1 / -- ; -- / Z ; -- / -- )
     Returns the "Z-value" associated with the trace n1. The result is placed at the top of the stack of reals.
   !Z: ( n1 / -- ; -- / Z ; -- / -- )
     Assigns the topmost value from the stack of reals to the "Z-value" associated with the trace n1.
   @Z ( -- / -- ; -- / Z ; -- / -- )
     Returns the "Z-value" associated with the current trace (trace under the cursor-line). The result is placed at the top of the stack of reals.
   !Z ( -- / -- ; Z / -- ; -- / -- )
     Assigns the topmost value from the stack of reals to the "Z-value" associated with the current trace (trace under the cursor-line).
   #X+ ( -- / -- ; <F1> / -- ; #A <#B> / #C)
     If the stack of reals is empty, this operation adds the abscissa of trace #A to the abscissa of trace #B.
     Otherwise, it adds the value taken from the stack of reals (F1) to the abscissa of the trace at the top of the stack.
   #Y+ ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation adds the ordinate of trace #A to the ordinate of trace #B.
     Otherwise, it adds the value taken from the stack of reals (F1) to the ordinate of the trace at the top of the stack.
   #X- ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation subtracts the abscissa of trace #A from the abscissa of trace #B.
     Otherwise, it subtracts the value taken from the stack of reals (F1) from the abscissa of the trace at the top of the stack.
   #Y- ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation subtracts the ordinate of trace #A from the ordinate of trace #B.
     Otherwise, it subtracts the value taken from the stack of reals (F1) from the ordinate of the trace at the top of the stack.
   #X* ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation multiples the abscisses of traces #A and #B.
     Otherwise, it multiplies the abscissa of the trace at the top of the stack by the value taken from the stack of reals (F1)
   #Y* ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation multiples the ordinates of traces #A and #B.
     Otherwise, it multiplies the ordinate of the trace at the top of the stack by the value taken from the stack of reals (F1)
   #X/ ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation divides the abscissa of trace #B by the abscissa of trace #A.
     Otherwise, it divides the abscissa of the trace at the top of the stack by the value taken from the stack of reals (F1)
   #Y/ ( -- / -- ; <F1> / -- ; #A <#B> / #C )
     If the stack of reals is empty, this operation multiplies the ordinata of trace #B by the ordinata of trace #A.
     Otherwise, it multiplies the ordinata of trace at the top of the stack by the value taken from the stack of reals (F1)
   #+
     An equivalent of #Y+
   #-
     An equivalent of #Y-
   #*
     An equivalent of #Y*
   #/
     An equivalent of #Y/
   #SWAP ( -- / -- ; -- / -- ; #A #B / #B #A )
     Swaps two traces at the top of the stack of traces
   #ROT  ( -- / -- ; -- / -- ; #A #B #C / #B #C #A)
     Rotates three traces at the top of the stack of traces
   #DROP ( -- / -- ; -- / -- ; #A / -- )
     Drops the topmost trace in the stack of traces
   #DUP ( -- / -- ; -- / -- ; #A / #A #A )
     Duplicates the trace at top of the stack of traces
   #OVER ( -- / -- ; -- / -- ; #A #B / #A #B #A )
     Copies the second trace from the top to the top of the stack
   #LOGX ( -- / -- ; -- / -- ; #A / #LOGX[#A] )
     Calculates the natural logarithm of abscissa of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #LOGY ( -- / -- ; -- / -- ; #A / #LOGY[#A] )
     Calculates the natural logarithm of ordinate of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #ABSX ( -- / -- ; -- / -- ; #A / #ABSX[#A] )
     Calculates the absolute value of abscissa of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #ABSY ( -- / -- ; -- / -- ; #A / #ABSY[#A] )
     Calculates the absolute value of ordinate of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #EXPX ( -- / -- ; -- / -- ; #A / #EXPX[#A] )
     Calculates the exponential function of abscissa of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #EXPY ( -- / -- ; -- / -- ; #A / #EXPY[#A] )
     Calculates the exponential function of ordinate of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #SMO ( <n> -- / -- ; -- / -- ; #A / #SMO[#A] )
     Performs polynomial smoothing of the trace at the top of the stack (the original trace is not changed).
     The size of the moving window is taken from the stack of integers.
     The window size may vary from 3 to 21 points. For the 3-points window, a second-order polynomial is used. In all other cases,
     the smoothing is with a 3-rd order polynomial.
     If the width of the smoothing window is not specified (the stack of integers is empty), the 5-point smoothing is applied.
     The result is placed at the top of the stack.
   #TRI ( <n> -- / -- ; -- / -- ; #A / #TRI[#A] )
     Performs "triadic" (Tukey) smoothing of the trace at the top of the stack (the original trace is not changed).
     The size of the moving window is taken from the stack of integers. The window size may vary from 3 to 7 points.
     If the width of the smoothing window is not specified (the stack of integers is empty), the window of three points is used.
     The result is placed at the top of the stack.
   #DER1 ( -- / -- ; -- / -- ; #A / #DER1[#A] )
     Calculates the first derivative of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #DER2 ( -- / -- ; -- / -- ; #A / #DER1[#A] )
     Calculates the second derivative of the trace at the top of the stack of traces (the original trace is not changed).
     The result is placed at the top of the stack.
   #DER
     DER is a synonym of #DER2
   #MEAN ( -- / -- ; -- / MEAN[#A] ; #A / -- )
     Calculates the arithmetic mean of ordinate values of a trace. The result is placed at the top of the stack of reals.
   #AREA ( -- / -- ; -- / AREA[#A] ; #A / -- )
     Calculates the area under the curve for a given trace. The result is placed at the top of the stack of reals.
   #MINX ( -- / -- ; -- / MINX[#A] ; #A / -- )
     Returns the minimal of all abscissa values of a given trace. The result is placed at the top of the stack of reals.
   #MINY ( -- / -- ; -- / MINY[#A] ; #A / -- )
     Returns the minimal of all ordinate values of a given trace. The result is placed at the top of the stack of reals.
   #MAXX ( -- / -- ; -- / MAXX[#A] ; #A / -- )
     Returns the maximal of all abscissa values of a given trace. The result is placed at the top of the stack of reals.
   #MAXY ( -- / -- ; -- / MAXY[#A] ; #A / -- )
     Returns the maximal of all ordinate values of a given trace. The result is placed at the top of the stack of reals.
   #TRUNC ( -- / -- ; FA / -- ; #A / #TRUNCY[#A,FA] )
     "Truncates" the ordinata of trace #A at the value taken from the stack of reals (FA) in the meaning that
     all values larger than FA will be replaced by FA

The following words do not operate with the stacks of reals and traces. Hence, the expressions in parentheses shows the content of the stack of natural numbers only:

   #DEPTH ( -- / n )
     Returns the depth of the stack of traces (a number of traces in the stack)
   LOGX ( -- / -- )
     Calculates the natural logarithm of abscissa of the current trace and REPLACES it with the result.
   LOGY ( -- / -- )
     Calculates the natural logarithm of ordinata of the current trace and REPLACES it with the result.
   EXPX ( -- / -- )
     Exponentiates the abscissa of the current trace and REPLACES it with the result.
   EXPY ( -- / -- )
     Exponentiates the ordinata of the current trace and REPLACES it with the result.
   DER1 ( -- / -- )
     Calculates the first derivative of the current trace and REPLACES it with the result.
   DER2 ( -- / -- )
     Calculates the second derivative of the current trace and REPLACES it with the result.
   DER  ( -- / -- )
     DER is a synonym of DER2
   @H ( -- / addr len )
     Returns the header string of the current trace (the trace under line-cursor) as a pair of its
     address and length
   !H ( addr len / -- )
     Replaces the Header of the current trace (the thrace under line-cursor) with the string
     taken from the stack. Example of usage: s" New title" !H
   !comment ( addr len / -- )
     Replaces the Comment string with the string taken from the stack. Example of usage: s" New comment" !comment
   @C ( n1 / --)
     Sets the color of the current trace to that specified by the value taken from the stack (n1)
   !C ( -- / n1)
     Returns the color of the current trace
   !INTR ( n1 / -- )
     Turns ON (n1<>0, or n1=TRUE) or OFF (n1=0 or n1=FALSE) interpolation between the points of the current trace
     in the SpectraLab graph window.
   @INTR ( -- / n1 )
     Returns the current settings of interpolation between the points of the current trace (0 if false, -1 if true).
     in the SpectraLab graph window.
   @CNCT ( -- / n1 )
     Returns the current settings of interpolation between the points of the current trace (0 if false, -1 if true).
     in the SpectraLab graph window.
   !CNCT ( n1 / -- )
     Turns ON (n1<>0, or n1=TRUE) or OFF (n1=0 or n1=FALSE) linear connection between the points of the current trace
     in the SpectraLab graph window.
   ?SEL ( -- / n1 )
     Returns TRUE (-1) if the current trace is selected for graphical display and FALSE (0) otherwise
   !SEL ( -- / -- )
     Marks the current trace as selected for graphical display
   #SEL ( -- / -- )
     Marks the current trace as deselected for graphical display (hidden on the graph)
   DESELECT ( n1 / -- )
     Marks n1 traces starting at the current position as deselected for graphical display (hidden in the graph)
   SELECT ( n1 / -- )
     Marks n1 traces starting at the current position as selected for graphical display
   @M ( n1 / --)
     Sets the graphical display symbol of the current trace to that specified by the value taken from the stack (n1)
   !M ( -- / n1 )
     Returns the graphical display symbol of the current trace
   !$ ( n / -- )
     Moves the cursor-line to location n ( making it the "current location" )
   CLEAR ( n / -- )
     Deletes the current trace (the trace under the cursor-line) )
   CLEARUP ( -- / -- )
     Deletes the current trace and all traces upwards of it
   clearall ( -- / -- )
     Deletes all traces in the memory
   ~clearall ( -- / -- )
     Deletes all traces in the memory

Some examples of command-line scripts:

  • The following script subtracts the trace located next to the current from the current trace and places the results two lines below
                $ #: $ 1 + #: #Y- $ 2 + #! 
    Note that in this script, "#Y-" can be substituted with "#-" (these two words are synonims).
  • The following script calculates the average of three consecutive spectra starting at the current location, smooths the result with 7-point polynomial smoothing, deletes the original spectra, and places the result at the current location (i.e., replaces the original):
                $ #: $ 1 + #: $ 2 + #: #+ #+ 3.0 #/ 7 #SMO $ #! $ 1 + clear $ 2 + clear
    Below is another variant of a script performing the same operations:
                $ #: inc $ #: inc $ #: #+ #+ $ clear dec $ clear dec 3.0 #/ 7 #SMO $ #!
  • Suppose that the line cursor is at trace #1 and the memory contains 20 consecutive spectra taken during some process, and the Z-value of each spectrum is the time passed from the start of registration. In this case, the following script will produce a kinetic curve of the changes at a wavelength corresponding to point #50 of the spectra. The resulting curve will be placed at location #21
                do(20) $ 50 Y:: 21 $ !Y:: @Z 21 $ !X:: inc
    Another variant of the same script, where we use 2DUP operator (ANS Forth standard word, which duplicates the two tompost layers of the stack of integers):
                do(20) $ 50 Y:: 21 $ 2DUP !Y:: @Z !X:: inc
  • The following script converts the current trace (the one under the cursor line) into its double-reciprocal (Lineweaver-Burk) transform and places the result into the location next to the current:
                $ #: #LOGY -1.0 #Y* #EXPY #LOGX -1.0 #X* #EXPX $ 1 + #!
    Note that in this example, in order to obtain reciprocal values of the trace's points, we calculated a logarithm of each axis, multiplied it by -1 (should be entered as a real number: -1., -1.0 or -1E0), and exponentiated the result back. This is the only way to calculate reciprocal values of a trace (since there is no operator that divides a number by a trace defined in SpectraLab).