LAST PAGE  BACK TO INDEX  NEXT PAGE

[15.0] Programming Tricks (1)

[15.0] Programming Tricks (1)

v5.0 / 15 of 23 / 01 sep 99 / gvg

* This chapter discusses some interesting techniques in VEE programming.


[15.1] A SIMPLE VEE COMPARATOR PROGRAM
[15.2] PERFORMING BIN SORTS
[15.3] SEARCHING FOR MAXIMUM VALUES
[15.4] LIMIT TESTING
[15.5] BITMAP DISPLAY UPDATES
[15.6] CONTROLLING PLOT DISPLAYS
[15.7] CONVERTING 3852 HSDVM VALUES
[15.8] SIGNAL PROCESSING, FFTS, & VEE
[15.9] DYNAMICALLY REPROGRAMMING VEE FORMULA OBJECTS

 BACK TO INDEX

[15.1] A SIMPLE VEE COMPARATOR PROGRAM

* The following sample program demonstrates comparator operation. In this example, we're comparing an array of integers versus a scalar value. If we change the scalar value so that all the array values meet the condition, the PASSED! Message Box pops up. If we change the scalar value so that one or more array values don't meet the condition -- as the example shows (see xcmpartr.vee for the source) -- then the FAILED! Message Box pops up, and the failing array index and its value are displayed as an ordered pair.


   +---------+
   | Integer |
   +---------+           +-------------------------------+
   | 0000: 0 |           |          Comparator           |          
   | 0001: 1 |   +---+   +------+-------------+----------+  
   | 0002: 2 |   | 2 +-->| Ref  |             | Passed   +---------+
   | 0003: 3 |   +---+   |      | Test != Ref | Failed   +------+  |
   | 0004: 4 +---------->| Test |             | Failures +---+  |  |
   | 0005: 5 |           +------+-------------+----------+   |  |  |
   | 0006: 6 |                                               |  |  |
   | 0007: 7 |        +--------------------------------------+  |  |
   | 0008: 8 |        |                                         |  |
   | 0009: 9 |        |  +--------------+         +-------------+  |
   +---------+        |  | AlphaNumeric |         |                |
                      |  +--------------+  +------+------+  +------+------+
                      |  |              |  | Message Box |  | Message Box |
                      |  |              |  |  "FAILED!"  |  |  "PASSED!"  |
                      +->| 0: (2, 2)    |  +-------------+  +-------------+
                         |              |
                         |              |
                         |              |
                         +--------------+
 
Source for this example is in the file xcmpartr.vee.

Note that if you are attempting to compare two arrays with the Comparator, they both have to be the same size and shape.

 TOP OF PAGE

[15.2] PERFORMING BIN SORTS

* A user wanted to know the fastest way to perform a bin sort with VEE, and I went through considerable gyrations to figure it out. They turned out to be futile, since you can do this with one object. All you have to use is "AdvMath -> Freq Distribution -> magDist", as follows:


      +-------+            +----------------------------------------------+
      |-100   +-----+      |                    magDist                   |
      +-------+     |      +------+------------------------------+--------+
 data --------------|----->|  X   |                              |        |
      +-------+     |      |      |                              |        |
      | 100   +--+  +----->| From |                              |        |
      +-------+  |         |      | magDist(x, from, thru, step) | Result +-->
                 +-------->| Thru |                              |        |
      +-------+            |      |                              |        |
      | 40    +----------->| Step |                              |        |
      +-------+            +------+------------------------------+--------+
 
See xmagdist.vee for a fully-developed example.

 TOP OF PAGE

[15.3] SEARCHING FOR MAXIMUM VALUES

* A user was having trouble figuring out how to write a VEE program that could obtain the maximum value of a sequence of inputs. This seemed straightforward, however, through use of the "max()" function, and I wrote the following program to demonstrate (see xgetmax.vee for the source):


          +-------------+                           +------+
          | Set Global  |                           | Quit +--+
  +---+   +-------------+                           +------+  |
  | 0 +-->|    maxval   | seed global variable                |
  +---+   +------+------+ with lowest possible value      +---+---+
                 |                                        | Stop  |
             +---+---+                                    +-------+
             | Until |
             | Break +--+
             +-------+  |
                        |            test for change in maxval
          +-------------+             +-------------------+
          |                           |    If/Then/Else   |
          |            +----------+   +---+--------+------+
   +------+-----+      |  Shift   +-->| A |[ A!=B ]| True +--+
   | Get Global |  +-->| Register +-->| B |        |      |  |
   +------------+  |   +----------+   +---+--------+------+  |
   |   maxval   +--+                                         | 
   +------+-----+  |                                 +-------+------+
          |        |                                 | AlphaNumeric |
          |        |                                 +--------------+
          |        +-------------------------------->| 75           |
          |                                          +--------------+
    +-----+-----+
    |[    75   ]|
    +-----------+                    test for slider change
    |[  100]  ^ |                     +-------------------+
    |         | |                     |    If/Then/Else   |
    |         | |      +----------+   +---+--------+------+
    |         H |      |  Shift   +-->| A |[ A!=B ]| True +--+
    |         | +--+-->| Register +-->| B |        |      |  |
    |         | |  |   +----------+   +---+--------+------+  |
    |         | |  |                                         |
    |         | |  |                   +---------------------+ 
    |         | |  |                   | 
    |[    0]  v |  |        +----------+----------+   +------------+
    +-----------+  |        |      Formula        |   | Set Global | 
                   |        +---+-----------------+   +------------+
                   +------->| A | max([maxval a]) +-->|    maxval  |
                            +---+-----------------+   +------+-----+
                            compare old value to             |  
                            new, store greater in        +---+---+
                            maxval                       | next  |  
                                                         +-------+
 
Of course, to figure out the minimum value, all you have to do is use "min()" instead (and initialize "maxval" to 100 instead of 0).

 TOP OF PAGE

[15.4] LIMIT TESTING

* A user asked us how to perform limit testing under VEE -- that is, how to determine if a waveform exceeds a particular limit and mark the points of it that exceed that limit.

As it turns out, this is easy to do. The following program (see xlimits.vee for the source) takes a sine wave from a Function Generator and does a limit test on it against a value from a Real Slider. It then displays the sine wave and limit line on an XY Trace object, with the values of the sine wave above the limit line marked in bright red:


   +-------------+                                                  |
   | Real Slider |    +-------------------------------------------->| Trace1
   +-------------+    |                                             |
   |          |  |    |                  +--------------------+     |
   |          |  |    |                  |      Formula       |     |
   |         [ ] |    |                  +---+----------------+     |
   |          |  +----|----------------->| A |[ ramp(B,A,A) ] +--+  |  
   |          |  |    |               +->| B |                |  |  |
   |          |  |    |  +---------+  |  +---+----------------+  |  |
   |          |  |    +->| totSize +--+                          |  |
   |          |  |    |  +---------+                             |  |
   +------+------+    |                                          |  |
          |           |  +---------------------------------------+->| Trace2
   +------+------+    |  |                                          |
   |  Function   |    |  |                                          |
   | Generator   +-+  |  |                                          |
   +-------------+ |  |  |                                          |
                   |  |  |                                          |
                   |  |  |  +-----------------------------------+   |
 +-----------------+  |  |  |           Comparator              |   |
 |                    |  |  +------+-----------------+----------+   |
 |  +----------+      |  +->| Ref  | Test [ <= ] Ref |          |   |
 +->| UnBuild  +------+---->| Test |                 | Failures +-->| Trace3
    | Waveform | Real       +------+-----------------+----------+   |
    +----------+ Array                                              |
 
The waveform data is converted to a real array by an UnBuild Waveform object. This real array is driven into the "Trace1" input of the XY Trace object and is displayed in yellow.

This real array is also input to a "totSize()" function, which returns the number of points in the array. This and the value from the Real Slider are fed to a "ramp()" function, which creates an array with that number of points but all of whose elements are set to the same input value. This constant array is driven into the "Trace2" input pin of the XY Trace object and displayed as a flat blue line.

Finally, a Comparator compares the real array against the constant array. If any elements of the real array are greater than the corresponding elements of the constant, they are returned as an array of coordinate pairs through the "Failures" pin. This array is fed to the "Trace3" input pin of the XY Trace object and displayed as a set of red diamonds, which blur to appear as thick red line segments.

 TOP OF PAGE

[15.5] BITMAP DISPLAY UPDATES

* A user had a VEE application that displayed a bitmap in a popup panel. the user was using it to view data from an external device. This worked fine, except that the VEE program would continue to show the same bitmap until it was rerun, even though new bitmaps were generated.

Obviously, VEE was loading the bitmap at prerun (or whatever) and did not need to load it again during the execution of the program. I wrote the following small program to test:


   +-------+
   | Until |
   | Break +------+
   +-------+      |
               +--+--+                 +-----+
               | OK  +-----+           | OK  +---+
               +-----+     |           +-----+   |
                           |                     |
                   +-------+-------+         +---+---+
                   | Call Function |         | Stop  |
                   +---------------+         +-------+
                   |   setpix()    |
                   +---------------+
 
The "setpix()" UserFunction was quite simple:

   +--------------------------------------+
   |              setpix()                |
   +--------------------------------------+
   |                    +---------+       |
   |                    | Picture |       |
   |                    +---------+       |
   |                    |         |       |
   |                    |         |       |
   |                    |         |       |
   |                    +----+----+       |
   |                         |            |
   |                      +--+--+         |
   |                      | OK  |         |
   |                      +-----+         |
   |                                      |
   +--------------------------------------+
 
I arranged it so that it would "Show Panel On Execute" and gave it the pop-up appearance:

   +-------------------+
   |    +---------+    |
   |    | Picture |    |
   |    +---------+    |
   |    |         |    |
   |    |         |    |
   |    |         |    |
   |    +---------+    |
   |                   |
   |      +-----+      |
   |      | OK  |      |
   |      +-----+      |
   +-------------------+
 
I gave the Picture object the filename "test.bmp" for a file to display ... I ran the program, displayed the bitmap, got rid of it, used PaintBrush to change the bitmap, displayed the bitmap again, and it was the same, as I expected.

The answer was to bring out the "file" data input pin and the "clear" control input pin on the Picture object:


   +--------------------------------------+
   |              setpix()                |
   +--------------------------------------+
   |  +----------+   +-----------------+  |
   |  |   Text   |   |     Picture     |  |
   |  +----------+   +-------+---------+  |
   |  | test.bmp +-->| file  |         |  |
   |  +----------+   |       |         |  |
   |                 |       |         |  |
   |             +-->| clear |         |  |
   |             |   +-------++--------+  |
   |             |            |           |
   |             |         +--+--+        |
   |             |         | OK  +--+     |
   |             |         +-----+  |     |
   |             |                  |     |
   |             +------------------+     |
   |                                      |
   +--------------------------------------+
 
This worked fine. I displayed the bitmap, got rid of it, changed it in PaintBrush, displayed it again, and got the new bitmap.

I originally designed the UserFunction to ping the "clear" pin first and then load the file name, but this generated a flicker when the object was first displayed, so I rewired it so that it would clear the Picture object when the UserFunction was exited, and then reload the bitmap the next time it was invoked. Other requirements may demand a different usage, but in any case the program must clear the Picture object and then load it again to allow the bitmap image to be updated.

 TOP OF PAGE

[15.6] CONTROLLING PLOT DISPLAYS

* A user called us up with a request: he wanted to use the VEE X vs Y Plot object to display a sequence of traces -- either one at a time, or as a cumulative set at once. That is, either he would view trace 1, then trace 2, then trace 3 ... or trace 1, then trace 1 and 2, then trace 1 and 2 and 3.

This was an interesting puzzle and involved use of the optional "Next Curve" pin on the X vs Y Plot object. A sample program that illustrates the principles involved is shown below (see xmltrace.vee for source):


   +-------+                                       +------+ OK
   | Until |                                       | Quit +-----+
   | Break +--+                                    +------+     |
   +-------+  |                                             +---+---+
	      |                +--------------+             | Stop  |
              | Toggle to get  | If/Then/Else |             +-------+
     +--------+-------+ trace  +-------+------+ 
  +->| Get Next Trace +--+---->| A==1  | THEN +--+   +---------------------- 
  |  +--------+-------+  |     +-------+------+  |   |           X vs Y Plot
  |           |          |                       |   +------------+---------
  +-----------|----------+                +------+   |            |
	      |                           |          |            |
              |            These two +----+----+     |            |
              |            objects   |  ramp() +---->| XData      |
              |            produce   +----+----+     |            |
              |            dummy          |          |            |
              |            trace   +------+------+   |            |
              |            data.   | randomize() +-->| YData1     |
              |                    +-------------+   |            |
              | Toggle to                            |            |
              | select            +--------------+   |            |
              | plot mode         | If/Then/Else |   |            |
     +--------+--------+          +-------+------+   |            |
  +->|[x] Single Trace +--+------>| A==1  | THEN +-->| Next Curve |
  |  +--------+--------+  |       +-------+------+   |            |
  |           |           |                          |            |
  +-----------|-----------+                          |            |
              |                   +--------------+   |            |
              |     Toggle to     | If/Then/Else |   |            |
          +---+---+ clear plot    +-------+------+   |            |
       +->| Clear +--+----------->| A==1  | THEN +-->| Clear      |
       |  +-------+  |            +-------+------+   |            |
       |             |                               |            |
       +-------------+                           +-->| Auto Scale |
                                                 |   |            |
                                                 |   |            |
                                                 |   +------------+-----+---
                                                 |                      |
                                                 +----------------------+
                                                                        |
                                                                    +---+---+
                                                                    | Next  |
                                                                    +-------+
 
Anyway, there's not much to this program. Note that the "ramp()" function just generates an array with values from 0 to 5 to act as X-values, using the invocation:

   ramp(6, 0, 5)
 
-- and the "randomize()" function generates comparable Y-values as a set of six random numbers in the range of 0 to 100, using the invocation:

   randomize(ramp(6, 0, 5), 0, 100)
 
This is done simply to generate dummy data. In practice, you'd obtain the data from I/O or files or whatever.

Depending on the state of the Toggle button, the If/Then/Else object will either drive the "Next Trace" pin or not every time a trace is taken, controlling whether single or multiple traces are displayed.

Note that the Sequence Out pin on the X vs Y Plot object is fed back to the "Auto Scale" pin to ensure that the traces are displayed properly each time a new trace is provided.

 TOP OF PAGE

[15.7] CONVERTING 3852 HSDVM VALUES

* Two of HP's Amsterdam support people got to tinkering and came up with a way to convert the packed data values returned by the 3852's 44702A high-speed DVM.

The packed data is returned as 16 bit values, with the bits assigned as:


  00:11    count   (0:4095)
  12       sign    (0 = positive, 1 = negative)
  13:14    range   (0 = 1M, 1 = 8M, 2 = 64M, 3 = 256M, where M = 9.765625E-6)
  15       valid   (0 = invalid, 1 = valid)
 
This gives the voltage as:

   Voltage = Sign * Range * Count
 
The VEE Formula to convert the data to volts appears as follows (expanded to multiple lines for clarity):

  (100*(bit(A, 15)-1)) +
   (1-2*bit(A, 12)) *
     bitand(A,4095) * 
       (2^(clipupper(3*(bit(14,A)*2 + bit(13,A)), 8))) * 9.765625E-6
 
The first term in the Formula gives a strongly negative value to help distinguish invalid data from valid data:

  Valid = 100*(bit(A, 15)-1)       // 0 if valid, -100 if Invalid 
 
This works OK because the maximum absolute value the DVM can return is about 10.2 volts.

Now on to obtaining the actual value ... getting the sign is fairly straightforward:


  sign  = (1 - 2*bit(A, 12))
 
Getting the count is even simpler:

  count = bitand(A,4095)
 
However, getting the range multiplier is tricky. The values of the range almost correspond to a power of 2 taken to an exponent with a value of the range number times 3:

   2 ^ (0 * 3) = 2^0 = 1
   2 ^ (1 * 3) = 2^3 = 8
   2 ^ (2 * 3) = 2^6 = 64
 
In principle, then, we could get the numeric value of that field and multiply it by 3 to get the exponent we want:

   3*(bit(14,A)*2 + bit(13,A))
 
-- except that the last range value by this scheme is:

   2 ^ (3 * 3) = 2^9 = 512
 
The value is actually 256, not 512. But no worries, we can use the clipupper() function to limit the maximum exponent to 8 to give the proper value of 256:

   clipupper(3*(bit(14,A)*2 + bit(13,A)),8)
 
This gives the range as:

   (2^(clipupper(3*(bit(14,A)*2 + bit(13,A)), 8))) * 9.765625E-6
 
 TOP OF PAGE

[15.8] SIGNAL PROCESSING, FFTS, & VEE

* An Australian user contacted us with a problem: he was sampling a sine-type signal with a data-acquisition box and wanted to know how to use VEE to determine the signal amplitude, DC offset, phase, and frequency from the data returned.

The first temptation was to use a few simple Formula boxes to do the job. Given an array of data named "D", the amplitude could be given by:


   (max(D) - min(D))/2
 
-- and the DC offset (average value, really) could be given by:

   (max(D) + min(D))/2
 
However, figuring out the frequency leads to a nightmare consideration of zero-crossing detectors, and figuring out the phase is even worse. Such techniques are also very sensitive to noise.

This was clearly a job for VEE's Fast Fourier Transform (FFT) function, but the details on exactly how to use the FFT to get the job done are tricky. This section explains the issues involved.

* The first problem is understanding exactly what an FFT is and what it does. Most engineers have a simple understanding of the Fourier Transform in general: that it converts a signal represented as, say, a voltage over a period of time (a "time domain" signal) into a "spectrum" of sine functions of different amplitude and phase (a "frequency domain" signal).

This is perfectly accurate as far as it goes, but when you get into dealing with "discrete" data samples on a computer (instead of simply manipulating math equations on the chalkboard) then the details get a little murky.

In this case, you must use a Discrete (or "Digital", if you like) Fourier Transform (DFT). The elementary DFT algorithm is slow, so in practice we generally use a more complicated but much faster FFT, but as far as the user is concerned (with one catch that will be discussed at the end of this article) they are exactly the same thing, and so this discussion will refer to the DFT.

A DFT has some interesting properties. Let's consider a DFT on a sampled time domain data set of, say, 256 points, though the following comments apply to any other number of points just as well:

Having waded through all this headache, let me summarize briefly:

* So, to extract information from an input signal, you must first scale it. You can easily do this with the following UserFunction:


   +----------------------------------------------------------------------+
   |                       UserFunction:  ScaleFFT                        |
   +----+----------------------------------------------------------+------+
   |    |                                                          |      |
   |    |      +--------------------------+                        |      |
   |    |      |           Formula        |                        |      |
   |    |      +----+---------------------+                        |      |
   |    |  +-->| Td | fft(Td)/totsize(Td) +--+                     |      |
   |    |  |   +----+---------------------+  |                     |      |
   |    |  |                                 |                     |      |
   | Td +--+     +---------------------------+                 +-->| CpxD |
   |    |        |                                             |   |      |
   |    |        |   +--------------------------------------+  |   |      |
   |    |        |   |                Formula               |  |   |      |
   |    |        |   +---+----------------------------------+  |   |      |
   |    |        +-->| A | concat(A[0],2*A[1:totsize(A)-1]) +--+   |      |
   |    |            +---+----------------------------------+      |      |
   |    |                                                          |      |
   +----+----------------------------------------------------------+------+
 
The first Formula box divides the FFT of the input data by the number of points in the original signal. The second multiplies all the harmonic components by 2 to generate the proper result.

* OK, given this, what sort of data can be extracted with it? For the problem we're supposed to address, we're trying to sort out a sine wave from sampled data and determine its amplitude, DC offset, phase, and frequency.

The following VEE objects can extract this data from the complex data output by the ScaleFFT() function above:


          +-------------+
   ---+-->| ScaleFFT(x) +--+              +-------------+
      |   +-------------+  |              |   Formula   |
      |                    |              +---+---------+
      |   +----------------+------------->| C | re(C[0] +--> DC offset
      |   |                               +---+---------+
      |   |
      |   |                   +---------------------------------+
      |   |                   |             Formula             |
      |   |   +--------+      +---------------------------------+
      |   +-->| mag(x) +--+-->| 1 + maxIndex(X[1:totsize(A)-1]) +--+
      |   |   +--------+  |   +---------------------------------+  |
      |   |               |                                        |
      |   |               |       +--------------------------------+
      |   |               |       |
      |   |               |       |          +----------+
      |   |               |       |          | Formula  |
      |   |               |       |          +---+------+
      |   |               +-------|--------->| M | M[I] +--> Amplitude
      |   |                       +--------->| I |      |
      |   |                       |          +---+------+
      |   |                       |
      |   |                       |   +-----------------+
      |   |                       |   |     Formula     |
      |   |                       |   +---+-------------+
      |   +-----------------------|-->| C | phase(C[I]) +--> Phase
      |                           +-->| I |             |
      |                           |   +---+-------------+
      |                           |
      |                           |   +-----------------+
      |                           |   |     Formula     |
      |   +------------+          |   +-----------------+
      +-->| totsize(x) +----------|-->| S | R * (I/S)   +--> Frequency
          +------------+          +-->| I |             |
                               +----->| R |             |
                               |      +---+-------------+
           sample frequency ---+
 
Some notes to explain how this stuff works:

Experiments with these tools show them to return highly accurate results -- as long as you have a set of samples that match an integer number of cycles. If the input contains a fractional number of cycles, it creates an apparent discontinuity in the signal that adds high-frequency components to the FFT spectrum, reducing the validity of the conclusions.

The DC offset value tends to remain stable under such variations, as does the frequency, but the signal amplitude varies considerable, and the phase varies widely. Further investigation did not resolve these problems and I can only suggest that the input waveform be trimmed to an integer number of cycles (using displays with marker inputs) to get the best results.

In principle, use of VEE windowing functions to filter the input data can help reduce the effects of such discontinuities, but my experiments with them showed them to be ineffectual in this case. I also discovered that if you want to get scaling to come out right, you have to multiply the output of the windowing function by 2 ... this didn't seem right, but I didn't have the background to investigate further.

* While I said earlier that an FFT was really just a version of the DFT that was much faster, it does have the peculiarity that it wants to perform computations on data sets whose number of elements is a integer power of two (2, 4, 8 , 16, 32, 64 ... ). VEE will use an FFT algorithm if the input data is this size; if it isn't, it really uses a slower DFT algorithm.

For N values, the time required to perform a DFT is proportional to N^2. For an FFT, it is proportional to N*LOG(N). For large values of N, the difference is one of days versus minutes, so you want to make sure your data is a power of two. All you have to do is add zero elements to the end of your array. It doesn't really affect the calculation.

The following function, PadZero(), does this for you:


   +--------------------------------------------------------------------+
   |                      UserFunction:  PadZero                        |
   +-+----------------------------------------------------------------+-+
   | |                                                                | |
   | |      +----------------------------------------+                | |
   | |      |                Formula                 |                | |
   | |      +---+------------------------------------+                | |
   | |  +-->| D | intPart(log(totsize(D)+0.1)/log(2) +--+             | |
   | |  |   +---+------------------------------------+  |             | |
   | |  |                                               |             | |
   | |  |  +--------------------------------------------+             | |
   | |  |  |                                                          | |
   | |  |  |   +--------------------------------------------------+   | |
   | |  |  |   |                      Formula                     |   | |
   | |  |  |   +---+----------------------------------------------+   | |
   | |  |  +-->| E |(S=2^E ? A : concat(D,ramp((2^(E+1)-S),0,0))) |   | |
   |D+--+----->| D |                                              +-->|R|
   | |  |  +-->| S |                                              |   | |
   | |  |  |   +---+----------------------------------------------+   | |
   | |  |  |                                                          | |
   | |  |  +---------------+                                          | |
   | |  |                  |                                          | |
   | |  |   +-----------+  |                                          | |
   | |  +-->| totsize() +--+                                          | |
   | |      +-----------+                                             | |
   | |                                                                | |
   | |                                                                | |
   +-+----------------------------------------------------------------+-+
 
The formula at top takes the number of elements of the input data, determines the power of two that gives that number, and then truncates it to an integer (note that I added a fudge-factor of 0.1 to ensure that roundoff error will not cause problems).

The formula on the bottom then determines if the number of elements in the input data is exactly the same as 2 raised to the integer power defined in the first formula. If so, it just passes on the array; if not, it concatenates the array with an array of zeroes long enough to make the number of elements the value of 2 raised to the next highest integer power. (Note how the ramp() function is used to generate this array.)

* A test function (xfftfunc.vee) showing off ScaleFFT() and PadZero() is available.

 TOP OF PAGE

[15.9] DYNAMICALLY REPROGRAMMING VEE FORMULA OBJECTS

* A user handed me an example program in which he was trying to extract a record field with an equation (roughly) of the form:


      +---------------------+
      |       Formula       |
      +-------+-------------+
   -->| Rec   | Rec.Field   +----
   -->| Field |             |
      +-------+-------------+
 
This would work OK if the input record actually had a field with the precise name "Field" -- but what he really wanted to do was put an arbitrary field name like "temp" or "pressure" in on the "Field" pin as a string and get the "Rec.temp" or "Rec.pressure" field as programmed.

As stated, this couldn't work because the formula above was specifying a literal name as its first half, but expected to obtain a value in the second (the Formula, of course, really just thinks it's a literal name all the way through, which is reasonable). However, there is a relatively easy workaround.

A "Formula" control pin (not a data pin, a control pin) can be added to a Formula box (and related objects) that allows the programmer to express a formula externally as a string and shove it in the pin. So, to get this to work, two objects would be needed, as follows:


                                        +-----------------+
   ---------------------------------+   |                 |
                                    |   |      +----------+---------+
       +------------------------+   |   |      |      Formula       |
       |         Formula        |   |   |      +---------+----------+
       +-------+----------------+   +---|----->| Rec     |          +--->
   --->| Field | "Rec." + Field +-------|--+-->| Formula |          |
       +-------+----+-----------+       |  |   +---------+----------+
                    |                   |  |
                    +-------------------+  |   +--------------+
                                           |   | AlphaNumeric |
                                           |   +--------------+
                                           +-->| Rec.pass     |
                                               +--------------+
 
The first object performs simple string operations to create the formula that actually to be executed. It shoves the formula into the second object, which then executes it.

Notice that since "Formula" is a control pin, it's asynchronous, and so to ensure synchronization the sequence-out pin of the first Formula box is wired to the sequence-in pin of the second.

This technique has obvious potential for elaboration. A sample program is available in the file xformpin.vee.

 TOP OF PAGE


 LAST PAGE  BACK TO INDEX  NEXT PAGE