Spectra Wave Arithmetic - Match 1D/2D waves to calculate differences, sums etc.

This package provides a user interface and programming environment for aligning and comparing two 1D / 2D waves and calculate for each overlapping point: output = f(modified input data, reference data). The input is modified using the UI controls and compared against a reference wave. Available Modes are:

  • Subtraction (-)
  • Addition (+)
  • Multiplication (*)
  • Division (/)
  • Average
  • Percent difference (difference normalized by the average in %, i.e., (A-B)/(A+B) * 200)
  • Custom user equation

The input wave can be shifted, offset and scaled. The original purpose was to calculate differences, hence the name Difference Generator. Latre versions added support for addition, multiplication, division, percent difference and arbitrary equations. 

The source waves of both the data to be modified and the reference is never altered. The calculation is done on temporary data, and any modification (named with ending "_mod") and the result of the arithmetic operation are exported as separate output waves. The default ending for naming the output is "_dif" for subtraction, "_sum" for addition, "_mul" for multiplication, "_div" for division, "_pdif" for % difference and "_calc" for custom formulas. Settings are saved within the output wave's notes and will be reloaded automatically upon resuming with the same input. The UI is folder aware. 

I tried my best to test everything thoroughly, but you should verify the correct behavior yourself to be sure. Bug reports and suggestions for new features are always welcome.

Graphical User Interface (UI) controls - 1D data

Select one or two waves in the Data Browser and then navigate to 'Spectra Tools' → 'Compare and Modify Data....' in the main menu or use the command line:

WaveArithmeticUI(WaveToEdit)

or alternatively:

WaveArithmeticUI(WaveToEdit,refwave=ReferenceWave)

The second wave selected in the Data Browser or provided via the optional 'refwave' parameter is pre-selected as reference. This is an overview of the controls (here, for modifying 1D data):

The modified wave and the reference wave can be selected via the drop-down menu and their role switched via the ] button. If Extend to Full Overlap is active the reference data is extended by repeating the averaged endpoints to the range of the modified data (no effect if the data overlaps already fully). This is most useful when the edge values of the reference are close to zero so that the error is small. This feature is only available for calculations involving 1D data.

Operation Mode:

  • Choose a preset from the (▼) drop-down menu: M - R subtraction (- key), M + R addition (+ key), M * R multiplication (* key) or M / R division (/ key), (M + R) / 2 average or (M - R) / (M + R) * 200 percent difference.
  • Any custom equation may be entered directly using M (modified input data) and R (reference data).
  • The result can be inverted (flipped along the Y or Z axis) with the Invert checkbox (i key).

When you are done:

  • Export & Exit will export the result and modification as separate waves and then closes the UI.
    The exported waves are plotted in a graph when the Plot Exported checkbox is active. All previous graphs with the same data are updated as well to reflect the new settings. All settings are saved with the output and will be reapplied upon reloading. See further below for an explanation how the data is saved including the purpose of the 'Use Ref. Name' setting.
  • Exit will close the UI without saving anything.
  • Use the Add drop-down menu to select the type of post-processing: smoothing, integration or derivation of the result. Activating the Incl. Additional item will export this post-processed data as well (name ending '_smt', '_int' or '_der').

Applying Changes to the Input Data:

  • Shift in X / horizontal and Y / vertical directions using the arrow buttons (cursor keys on the keyboard).
  • Scale using the stretch (page up key) and shrink (page down key) controls.
  • The delta step of each modification can be set using the controls to the left.
  • Absolute Changes in the lower section of the UI can be used to dial in the desired values directly.
  • Use the Reset buttons for All modifications or individual changes of the X / Y shift or (*) scaling to undo modifications.

Smoothing:

  • Both waves can be Gaussian broadened by setting the respective control. Smoothing of the reference data is only temporary and not applied to the input reference data. This setting is saved with the output and will be reapplied upon reloading. Use the home / end keyboard shortcuts to increase / decrease the smoothing value (holding alt/option will change the value for the reference data).

Further keyboard shortcuts: 

  • Hold Cmd (Mac) / Ctrl (Win) for changes in steps of 0.5 times the current delta value.
  • Hold Shift for changes in steps of 10 times the current delta value.
  • Hold both Shift + Command / Ctrl for changes in steps of 0.1 times the current delta value.
  • r key to ‘Reset All'
  • p key to toggle ‘Pin Background’
  • Hold Cmd (Mac)/ Ctrl (Win) while pressing ‘Reset All’ and the reference wave will be set to none.
  • Hold Cmd (Mac)/ Ctrl (Win) while pressing ‘Export & Exit’ to export without closing the UI. This is useful to process many waves in quick succession by selecting the next one from the drop-down menu.
  • Hold Option (Mac) / Alt (Win) while pressing ‘Export & Exit’ to force the 'Use Ref. Name' setting (this has the same effect as activating the check box).

Graphical UI controls - 2D data

2D data is loaded and processed in the same way. The data is now displayed as two overlapping images, with the reference data plotted as a semi-transparent layer on top of the input data. There are additional controls specific to 2D data (see below), such as additional controls to modify the third (Z) dimension:

At the very bottom are additional controls to modify the image appearance:

  • Ref. Alpha: The transparency (alpha value) of the reference data. Choose between fully transparent (slider to the left) and fully visible (slider to the right).
  • Show (reference): Toggles the visibility of the reference image. Uncheck to hide. Can also be toggled with the s key on the keyboard.
  • Image color and Range controls: Choose the color mapping for each image and adjust the displayed z-range via sliders.

Showing Profiles and Setting Region-Of-Interest (ROI):

To aid with alignment, the intensity profiles (i.e., sum) in X / Y directions can be displayed via the Show Profiles button. A side-panel will appear with two graphs, one for X and one for Y. Profiles will update automatically, you can immediately see the effect of each modification.

To limit the range from which the profiles and displayed min. / max. values are calculate, drag a marquee across the image over the region of interest you want to work with. Then, use the Set / Clear ROI button. Pressing the button again without a marquee on the graph will clear the ROI. You can alternatively use the right-click menu after dragging a marquee to set / clear the ROI. Limiting the range makes it easier to align / match a specific sub-region of the data.

 

How the result is saved

The result is exported to the folder of the input as 'wavename' +  "_mod"' for the modified data and  'wavename' +  mode-specific extension for the result of the calculation. The mode-specific extensions are:

  • "_dif"' (subtraction)
  • "_sum" (addition)
  • "_mul" (multiplication)
  • "_div" (division)
  • "_avg" (average)
  • "_pdif" (percent difference)
  • "_calc" (custom formula)

All settings are saved inside the wave note of both of these output waves. Below is an example output, where 'first spectrum' was modified and 'second spectrum' was the reference:

Loading the UI with the same initial data ('first spectrum' in this case) will reload the last session from the '_mod' (or '_dif' wave, if '_mod' does not exist). Note that loading a '_dif' or '_mod' wave directly will just start a new session (this makes it possible to create differences of differences etc.). The input and reference data can be in different folders, but the '_mod' or '_dif' wave should stay with the respective input in the same folder.

If neither a 'dif' (or 'sum', 'mul', 'div') or 'mod' wave with the same name is found in the input wave's folder, then the default settings are loaded. It is thus recommended to keep the result and modified waves together with the input in the same folder to be able to reload the settings later. What will be reloaded if you have mixed result waves from different modes? The loading hierarchy is 'mod' > 'dif' > 'sum' > 'mul' > 'div' > 'pdif'. For example, without the '_mod' and '_dif' waves present in the folder will load the settings from the '_sum' wave if present.

What is the purpose of the 'Use Ref. Name' setting?

Imagine the following scenario: You have measured 'baseline' data and then several data sets in succession like this:

  1. baseline
  2. measurement1
  3. measurement2
  4. measurement3
  5. ...

Let's assume you want to remove the baseline from all measurements but each measurement data itself should not be altered (e.g., to preserve their relative shift or intensity). You instead can modify (shift, scale etc.) the baseline while comparing to each measurement and then save the result next to each data set using the Use Ref. Name setting.

Load the baseline as Modify and one measurement as Reference, then apply modifications as necessary (to the baseline). Since the role of the modified and reference data is reversed, this usually means you need to activate 'Invert'. Before exporting, activate 'Use Ref. Name' to save the result next to each measurement set. This will create a unique output for each measurement:

  1. baseline
  2. baseline_mod
  3. measurement1
  4. measurement1_dif
  5. measurement2
  6. measurement2_dif
  7. measurement3
  8. measurement3_dif
  9. ...

What if you reload measurement1 but have conflicting settings in waves measurement1_mod and measurement1_dif? In this case, measurement1_mod is loaded according to the hierarchy 'mod' > 'dif' > 'sum' > 'mul' > 'div' > 'avg' > 'pdif'.

Running your own code:

You can generate comparisons of two waves using the function: 

doWaveArithmetic(WaveArithmeticStruct s)

The WaveArithmeticStruct structure looks like this:

Structure WaveArithmeticStruct
    variable mode       // 1: Subtr. (M-R) 2: Add (M+R) 3: Multiply (M*R) 4: Divide (M/R) 5: Avg 6: %Diff => (default 1)
    char formula[100]   // free-form arithmetic expression: M & R as stand-in for orgWave & refWave; use instead of mode
    Wave orgWave        // [mandatory] wave to compare 1 - will NOT be modified in any way
    Wave refWave        // [mandatory] wave to compare 2 - will NOT be modified in any way
    Wave cmpWave        // [optional] result of comparison between orgWave and refWave will be written here
    Wave modWave        // [optional] modified wave - saves the scaled and shifted version of orgWave
    Wave modRefWave     // [optional] modified reference wave - saves the smoothed version of refWave (if refSmooth > 0)
    // all below parameters are optional
    variable orgSmooth  // amount of smoothing for wave 1           (default 0)
    variable refSmooth  // amount of smoothing for wave 2           (default 0)
    variable baselineXval   // x position of baseline               (default NaN)
    variable baselineYval   // y value (1D) or position (2D)of baseline     (default 0)
    variable baselineZval   // for 2D: z value of baseline              (default 0)
    variable baselineFixed  // baseline is omitted from Y scaling if set to 1   (default 0)
    variable invert     // invert the output in Y               (default 0)
    variable xShift     // modify wave 1: x displacement (in wave's units)  (default 0)
    variable yShift     // modify wave 1: y displacement (in wave's units)  (default 0)
    variable valShift   // modify wave 1: intesity displacement (offset)    (default 0)     
    variable xScale     // modify wave 1: x scale               (default 1)
    variable yScale     // modify wave 1: y scale               (default 1)
    variable valScale   // modify wave 1: y / z scaling             (default 1)
    variable UIpinToggle    // options related to user interface; don't use     (default 0)
    variable UIoptions  // bit options related to user interface; don't use (default 0)
EndStructure

In your code, use the structure to pass the input waves and desired parameters to the function. You need to pass at least the two input (orgWave and refWave) and one output wave (cmpWave; this one will be overwritten). A simple example could look like this:

Function CompareTest(Wave wave1, Wave wave2)
    STRUCT WaveArithmeticStruct s
    WaveArithmeticInitialize(s) // initialize structure parameters with defaults
    Duplicate/O wave1, $(NameOfWave(wave1)+"_dif")
    Wave s.cmpWave = $(NameOfWave(wave1)+"_dif")
    Wave s.orgWave = wave1
    Wave s.refWave = wave2
    s.refSmooth = 0.5   // smooth wave2 (optional; data will not be altered)
    s.xshift = -0.02    // shift wave1 (optional; data will not be altered)
    String statusmsg = WaveArithmeticErrorMsg(doWaveArithmetic(s))
    Print statusmsg
End

WaveArithmeticErrorMsg() generates a human-readable error message in case there is a problem. If official name-end tags (e.g., "_dif") are used then the output is fully compatible with the UI, i.e., settings are parsed when using the UI with the generated waves.

Settings inside the procedure header

The header contains settings as static constants which are used by the UI, and can be edited here if needed (rather not mess with these settings unless really necessary). For example, the name-end tags ('_dif', '_mod' etc.) can be altered here, should there be a conflict with other names in your work-flow (in fact, Igor's own Differentiate function also uses '_dif'):

static StrConstant kModEnd  = "_mod"                    // label for modified data
static StrConstant kAuxEnd  = "_smt;_int;_der;"             // label for additional data
static StrConstant kOutEnd  = "_calc;_dif;_sum;_mul;_div;_avg;_pdif;"   // label for output data
static StrConstant kModePresets = "M - R;M + R;M * R;M / R;(M-R)/(M+R) * 200;"  // presets for the modes

Project Details

Current Project Release

Release File: Difference Generator_v5.22.zip (27.84 KB)
Version: IGOR.8.00.x-5.21
Version Date:
Version Major: 5
Version Patch Level: 22
OS Compatibility: Windows Mac-Intel
Release Notes:
  • Added preset for averages.
  • Slightly optimized panel style.
  • Code optimizations using the IPT tool from BytePhysics.
View All Releases

Nice looking, chozo! It has a lot of features that aren't in the Wave Arithmetic panel.

Thank you John! As the name suggests, this project started to make it possible to create differences with manual control and instant feedback for extracting even minute differences between measurements. But now that you mention it, it has indeed some things in common with the Wave Arithmetic package. This actually gives me the idea to add division and multiplication to the package for completeness.

EDIT: I have now updated the project to include four modes: Difference, sum, multiplication, and division.

I am seeing a pattern here: it seems that spectroscopists keep toolbags of useful packages that do similar things. I have a procedure ("wave scale and subtract") that does some of the things your panel can do, but as usual your panel is more sophisticated and does a lot more.

I will attach my little procedure here, just in case you are curious, but it doesn't do anything other than a small subset of what you do here.

ScaleSub106.zip (4.12 KB)

At one point in the mid- to late 90's (Igor 3 to 4), the toolbox was collected under the package SpXZeigR. I had an entire suite of features, help files, and tutorials. You won't find the original anymore (I have it somewhere on an archived CD). You will find a scattering of references to it, including a doi article that I did not even know about until just now.

I always wished to have had the time (and/or co-developers) to sustain the package.

Yes, I remember SpXZeigR, and I had that and other packages in mind when I wrote the comment. I had already developed a set of tools more specific to the techniques I was using at that time, so SpXZeigR never really entered my workflow.

RE SpXZeigR ... Sad as I am to see the package fade into the historical records, I am also glad to see a plethora of well-designed packages being provided to take its place.

I remember SpXZeigR. If tech support queries reflects popularity, it was fairly popular :)

John: The support that WaveMetrics provided to sustain SpXZeigR was greatly appreciated.

I didn't mean that it had lots of problems! No matter how well designed your package is, people will get into trouble. So any package that gets used a lot will generate some number of queries, regardless of its quality.

Tony, thank you for sharing your solution for this problem. It looks very nice and sufficient for the task (I would miss the shift in x, though). I hope the DiffGen project will be of use for you (and others) then. Yes, the problems and solutions of people in the community seem to be similar. Good thing, that there is a place to share. I am happy that I didn't have to come up with the ~10 projects I am using from the site (mostly your stuff, Tony). :)

By the way, I didn't know or use SpXZeigR. Must have been before my time. ;)

Tech Note 20 still exists in all its variants. And it still works!!! But the tools you folks have been making available are far superior.

My packages supports menu keyboard shortcuts which are loaded from a settings file. If you want to add keyboard shortcuts to common menu entries, place the content (Spectra Tools settings.dat) of the attached zip file in the same folder as the package procedure and edit as necessary.

Spectra Tools settings_1.zip (468 bytes)

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More