The SRS DS345 Function Generator can output arbitrary waveforms defined by a sequence of up to 16300 points with a max 40 MHz timebase. The manufacturer provides a Windows program called Arbitrary Waveform Composer (AWC, available here) to generate compatible waveforms and then transfer them to the instrument over RS-232 or GPIB. Unfortunately, the waveform-creation interface can be a bit cumbersome to use. awcgen (v1.1 available right here) is a Perl script which transforms a simple text file defining a piecewise-linear function into an AWC-compatible waveform. AWC is still needed for the transfer step.


>> awcgen --help

Usage: awcgen [input file] [output file] [flags]

  Flags:  t  'Test mode'    Produce two-column output for easy plotting.
          m  'More points'  Attempt to use ~16000 points instead of ~1600.
          f  'Full scale'   Produce a full-size waveform when driving a 50 Ohm load.

The input file should be a list of time periods τi (in seconds) and target voltages Vi (in Volts), separated by whitespace, one line per point. awcgen sets the initial value to 0 V, then ramps linearly to each Vi over τi in succession, as illustrated below. Abrupt jumps can be made by setting τi = 0.

waveform definition scheme

In preparing the waveform, awcgen attempts to choose a sample rate that meets three goals (in order of importance):

  1. Satisfies: fsamp = (40 MHz) / N where 1 ≤ N ≤ 234 - 1
  2. Produces about 1600 points (to reduce transfer time).
  3. Is a round number.

Complex waveforms, particularly those containing both large and small τi, may require more points to be faithfully reproduced. Supplying the 'm' flag will max out the number points available at the cost of a much longer transfer time. The output will be an AWC-compatible text file containing several lines of header information followed by a list of voltages Vj at times tj = {0, tsamp, 2 tsamp, ...} where tsamp = 1 / fsamp.

An example:

>> awcgen example_pwl.txt example_awc.txt

             Request       Actual
             ------------  ------------
Divider:     13750.000     15625
Frequency:   2.909e+03     2.560e+03
N_points:    1600          1409

Total time:  5.500e-01
Output:      AWC-compatible

The output file can then be opened in AWC, and would look like this. If you do not have AWC handy or wish to verify the output as a continuous function V(t) rather than Vj, use the 't' flag:

>> awcgen example_pwl.txt example_test.txt t
Output:      Plot-compatible

This output file can then be easily loaded by plotting software, such as matplotlib.

Impedance issues:

Notice that the amplitude in the previous example appears to be half that requested. The reason is related to the expected load impedance: The instrument provides a 50 Ω output, and expects a 50 Ω load, so it scales the internal source voltage Vs to produce the expected output Vout in that situation (below, left). In contrast, awcgen was written with a high-impedance load in mind (below, right), so by default it divides all voltages by two to counteract the above assumption. If you do plan to drive a 50 Ω load, simply supply the 'f' flag as mentioned in the usage.

matched impedance vs. high impedance


The Nanometer Pattern Generation System (NPGS) is used for electron-beam (or ion-beam) lithography which is often used for prototyping micro- and nano-sized devices. In a typical scenario, NPGS reads one or more patterns created in DesignCAD into memory. A "runfile" is then generated based on the contents of the patterns combined with information about location, alignment steps, and dosage supplied by the user. Finally, NPGS "writes" the pattern to the sample by rapidly modulating the beam deflection over high-speed X-Y inputs.

Though DesignCAD is conveniently integrated with NPGS, and is itself a pretty decent CAD program, some people (i.e., me) prefer a workflow based on AutoCAD or other programs which read and write DXFs. (My favorite is the snazzy, dual-licensed QCAD.) While DesignCAD is eminently capable of importing DXFs, the resulting patterns are not directly usable with NPGS because it has no way to know which shapes (typically closed "polylines") are to be written and which are merely alignment windows, etc.

npgsfixer (v1.1 available right here, requires Hany's Dos2Unix) is a Perl script which converts a generic DesignCAD file into an NPGS-compatible one. Color is used to encode role information, which is then translated into the flags NPGS expects. While it's at it, the script will also fracture large patterns based on user-defined bounding boxes. (Yes, NPGS can fracture too, but not exactly the way I like . . .)


>> npgsfixer --help

Usage: npgsfixer [input file] [output file] [arguments]

  Arguments:  --fieldbase [file]  Specify base filename of sub-fields, if applicable. Default: "field"
              --runfile   [file]  Specify filename of runfile snippet, if applicable. Default: "runfile.txt"

The input file should be a DesignCAD file containing the color-coded elements that make up your pattern. Filled shapes should be closed polylines of one of six colors (to accommodate dose ranges): light blue, medium blue, dark blue, light green, medium green, and dark green. (The exact RGB values for these colors can be found in the script.)

npgsfixer has two modes:

  • Normal mode sets the appropriate flags on the elements in the pattern according to the color codes mentioned above. Unmatched elements are simply passed through unchanged.
  • Fracture mode is automatically activated when at least one layer containing a yellow bounding box is detected. The pattern is fractured into separate files, one per bounding-boxed layer. Coordinates are adjusted to place the origin of each sub-field in the center of its bounding box.

Note: The same translation as in normal mode occurs in fracture mode and un-boxed layers are simply written to the main output file.

A normal example:

pattern for normal mode example

>> npgsfixer example_normal_in.DC2 example_normal_out.DC2
Processing layer 1 "0":
  Fixed filled polyline. Vertices: 4 Color: (0,0,255)
  Skipped non-filled polyline. Vertices: 12 Color: (255,0,0)
Processing layer 5 "write":
  Fixed filled polyline. Vertices: 12 Color: (0,0,255)
  Fixed filled polyline. Vertices: 12 Color: (0,0,255)
  Fixed filled polyline. Vertices: 20 Color: (0,0,255)
  Fixed filled polyline. Vertices: 63 Color: (0,0,255)
(See the full output here.)

The input file was created by importing a DXF file containing the pattern shown at right into DesignCAD. The output file example_normal_out.DC2 can then be loaded into NPGS via a runfile. In this case, the runfile does manual alignment using layers 1-4 (see screenshot) before writing layer 5 (see screenshot) to the sample.

An example of fracture mode:

The test pattern (below, right) is a sparse alignment grid we want to write at higher magnification to get sharp features. npgsfixer will detect the yellow bounding boxes and fracture the pattern for us, generating a list of X-Y stage moves to stitch it back together during writing.

>> npgsfixer example_fracture_in.DC2 example_fracture_out.DC2 \
pattern for fracture mode example --fieldbase exfield --runfile exrun.txt
Scanning layer 1 "0":
  Found bounding box. Vertices: 4, Center: (220.0, 220.0)
Scanning layer 2 "1":
  Found bounding box. Vertices: 4, Center: (780.0, 220.0)
Scanning layer 3 "2":
  Found bounding box. Vertices: 4, Center: (780.0, 780.0)
Scanning layer 4 "3":
  Found bounding box. Vertices: 4, Center: (220.0, 780.0)
Processing layer 1 "0":
  Fixed filled polyline. Vertices: 12 Color: (0,0,255)
  Fixed filled polyline. Vertices: 12 Color: (0,0,255)
  Deleted bounding box.
(See the full output here.)

The input file was created by importing the original DXF file into DesignCAD. Given that all four layers include bounding boxes, the "main" output file contains no shapes and can be discarded. The fracture sub-fields were written to files exfield-{0,1,2,3}.DC2 and stage moves saved as a runfile snippet exrun.txt. A full-fledged runfile was then manually created based on the snippet, which writes the grid according to the scheme below:

alignment grid fracture scheme

The four fields are written in order at locations {r0, r1, r2, r3} (see screenshots: "0", "1", "2", "3").