Data AcQuisition And Real-Time AnalysisScope - Spectrum - Spectrogram - Signal Generator
Software for Windows
Science with your Sound Card!
Contact us about
Macro IF Statements
An optional ELSE block holds commands to be performed if the IF is false.
An ENDIF must be used to close each IF structure.
Note that IF, ELSE, and ENDIF are macro prefixes, so each must be followed by a period:
IF.L.0.StreamOn=1 Msg="Left Stream 0 is ON" ELSE. Msg="Left Stream 0 is OFF" ENDIF.
With values that could include decimal places, it may be better to test if a value is above or below specified limits, rather than testing for exact equality. That's because there may be hidden digits that are nonetheless used in the IF test. For example, if variable A is the result of a calculation and you display it with Msg=A(0.5), you might see a value like 6.54321. But that may have been rounded from an internal value like 6.543212345, so IF.A=6.54321 would fail.
This is a particular issue for Generator frequencies, since the value you see on the Tone Frequency control, for example, is the actual value generated, not ncessarily the value you entered. For example, if you enter 1000, the control may show 1000.00003. That's because Generator frequencies have a finite resolution, determined by the sample rate, which is considered in the display. But an IF test would compare this internal value to the value in the statement, which in this case would be 1000.00000.
The preceding StreamOn example shows the "true" and "false" branches indented for clarity. Indenting is not required, but it is strongly recommended. (You can use CTRL+Tab in the Macro Definition editor to move to the next tab stop.)
The example shows a single IF structure. IF statements can contain nests up to 16 levels deeper (more indented) than the main IF. You can have an arbitrary number of IF statements at each level.
IF.L.0.StreamOn=1 IF.R.0.StreamOn=1 Msg="Left and Right Streams 0 both ON" ELSE. Msg="Only Left Stream 0 is ON" ENDIF. ELSE. IF.R.0.StreamOn=1 Msg="Only Right Stream 0 is ON" ELSE. Msg="Left and Right Streams 0 both OFF" ENDIF. ENDIF.
You can test for various conditions besides equality, but the equal sign is always required... even for "greater than". A redundant equal sign is needed for "greater than or equal to", as shown below:
= Equal =! Not equal => Greater than =< Less than =>= Greater than or equal to =<= Less than or equal to =& Bit field test (see below)
It may be helpful to think of the first equal sign as "is", such that IF.A=>=B becomes "If A is greater than or equal to B".
You can have expressions on both sides of the IF statement, such as:
IF.(A^2 + B^2)=>(C^2 + D^2)
Expressions can include logical (True/False, or "Boolean") operators for AND (&&), OR (||), NOT (!), and XOR (##). Since True = 1 and False = 0, you can test if an overall logical expression is true by comparing it to 1:
IF.(A && B) || (C && D)=1
One thing you can not do is have multiple tests (multiple equal signs) in the same IF statement. For example, to test if A=4 OR B=5, this won't work:
WRONG: IF.(A=4) || (B=5)
One workaround (other than nested IFs) is to devise a chain of logical operations that gives the proper results. We note that A-4 is equal to 0 only when A=4, and likewise B-5 equals 0 only when B=5. So at first glance we might think we can just take the logical NOTs and combine terms: IF.!(A-4) || !(B-5)=1.
But this fails if A is less than 4 or B is less than 5 because the differences become negative, and a negative value is treated as 0 by the logical NOT. So we need an extra step to convert the negative values to positive. A binary AND with a positive "mask" having all bits set to 1 will do the job. If we know that the largest value that A can reach is less than (say) 8, we can use 7 as the mask (0111 binary). Parentheses are required so that the NOT applies to the masked result. The final form is then:
IF.!((A-4)&7) || !((B-5)&7)=1
Bitwise binary operations can be especially useful for testing if a single variable holds one of several values. This is commonly encountered in testing event codes in the Ctrls variable sent to a Custom Controls dialog handler. Possible Ctrls values are 0-7. To test if the value is either 4 or 5, note that the 4s bit (0100) must be set, but not the 2s bit (0010):
4 = 0100 5 = 0101 6 = 0110 7 = 0111
This can be tested via:
IF.(Ctrls&4) && !(Ctrls&2)=1
Here the first term is a logical 1 (value above 0) if the 4s bit is set, and the second term is a logical 1 if the 2s bit is not set. So if both terms are 1 then the test passes. This test is used in the _Beats_Ctrls handler for the Beats_Demo Monaural and Binaural Beats macro mini-app included with Daqarta.
Instead of value or logical comparisons, as shown in the preceding examples, you can use bit field tests by putting an & after the equal sign. Then the IF will pass if any bits that are set in test value are also set in the tested variable.
To make it easier to work with bit fields, the test value can be given in hexadecimal by preceding it with an h. For example, IF.VarA=&h80000001 will be true if VarA has either its most-significant or least-significant bit set. This type of test is particularly useful for Limits tests, where 4 different Pass/Fail test results are present in a single variable.
Many Daqarta controls are "radio buttons", consisting of two or more buttons where only one can be active (depressed) at a time. These buttons can be set or read via macros, either by name or by number. For example, the SpectWind macro is used for Spectrum window function select, which is a set of 6 buttons for Hann, Hamming, Blackman, Blackman Exact, Blackman-Harris, or Flat Top window type. You can use values 0-5 to refer to these, or you can use mnemonic names: Hann, Hamm, Bkmn, BkEx, BkHr, or Flat.
For example, either SpectWind=2 or SpectWind=Bkmn will set the Blackman window type. You can use any variable or expression in place of the immediate value, but if you use the name it must appear alone.
However, if you use the name (instead of a value or expression) in an IF statement you must put quotes around it, as in IF.SpectWind="Bkmn".
Buttons that toggle between two states must use 0 for off and 1 for on in IF statements, even though some buttons may allow alternate mnemonics when a macro sets a value directly. For example SmplSec=sec sets the units used in many dialogs (like Burst, Frequency Sweep, and Trigger) to seconds instead of samples. Alternatively, you could use SmplSec=1 to do the same thing, or use any variable or expression in place of the immediate value.
But in an IF statement, you must use numbers. Unlike the radio buttons discussed above, you can't use the mnemonic whether quoted or not.
See Macro Variables for an example that uses IF statements to provide a system of prompts for novice users, which can be toggled off by experienced users.
Use E.IF instead of IF to test if a control is enabled. You don't need a value after the equal sign. For example, to test if the Trigger Level control is enabled, use:
E.IF.TrigLevel= Msg="Enabled" ELSE. Msg="Disabled" ENDIF.
Trigger Level is disabled during Gen Sync trigger mode. (In this particular case you could have simply tested for Gen Sync mode with a normal IF, using IF.TrigMode=GenSync.)
If a macro tries to set a disabled control, the macro aborts with the message "Control disabled. Aborting macro". By testing first, you can take other action.
IF statements are intended to work with numerical values, but you can perform limited string tests since the first 4 or 8 characters of a string can be regarded as an integer made of their ASCII equivalents. For example, if you set UA="Test" then it can be displayed as Msg=UA(A) to see Test, but it can also be shown as its hexadecimal equivalent 54657374 via Msg=UA(h).
Thus, if you use IF.UA="Test", the IF will pass. Likewise, you can use IF.UA=UB and it will pass if UB holds the same string or equivalent integer.
If you use floating-point variables A-Z or 64-bit fixed-point variables Var0-VarZ, each can hold up to 8 ASCII characters by utilizing the fractional portion. For example, A="12345678" can be displayed in hex notation via Msg=A(H) to see that it is stored as 31323334.35363738 hex.
Although IF tests for equality are usually a bad idea for math results that involve computations and possible rounding, here they are no problem. It's perfectly reasonable to use these "fractional" values if they have only been obtained from text strings.
You can use IF tests with string arrays like Str0, but only the first 8 characters will be tested. For example, after Str0="Test1234ABCD", you can use IF.Str0="Test1234" and it will pass, as will IF.Str0="Test1234ABCD" or in fact IF.Str0="Test1234EFGH". But IF.Str0="Test123" will fail.
Buf0-7 arrays can be used for string storage, such as Buf0#a="Test1234", but these can't be tested with IF.Buf0(a)="Test1234" since the IF command won't accept output formatting like (a). Instead, you can copy to a string array using Str0=Buf0(a) and then use IF.Str0="Test1234". (Alternatively, you can set an intermediate floating point variable as in A=Str0 and then use IF.A="Test1234", but you can't directly set A=Buf0(a) due to the output formatting.)
You can also use string tests with Labels and Fields. When these are set with immediate data (not variables) they must use strings in quotes, as in Field1="ABCDEFG" or Field1="123.456", but can be read, and hence tested, as values. However, please note that while IF.Field1="ABCDEFG" (with quotes) is used to test the first case, the second case requires IF.Field1=123.456 without quotes. That's because in both cases the Field is read as a value, and the quotes are needed to tell Daqarta to regard "ABCDEFG" as a value and not some strange variable, which it can't find and so would report an error.
CAUTION: When reading a Label or Field, Daqarta defaults to attempting to interpret it as a numeric value, and only if that fails does it interpret it as an alphanumeric string "value". For example, if the original had been set with Field1="Mouse234", that would always be read as an alphanumeric string. But Field1="M234" would be read as a value of 123400, since the "M" would be interpreted as a Mega scientific prefix replacing the decimal point in a value using "European" notation.
To force the Field or Label to be read as an alphanumeric, use the ?A suffix as in IF.Field1?A="M234" or A=Field1?A. (You can't use A=Field1(A) here.)
You can also set Labels and Field with numeric variables, such as A=123.456 followed by Field1=A, which could be tested by IF.Field1=123.456 or by IF.Field1=A.
You can use IF.Field1=Field2, but only the first 8 characters are considered.
To determine if a Field is empty, use IF.Field1= with nothing on the right side. (You can not use IF.Field1="".)
To invert the logic so that the IF passes if Field1 is not empty, use IF.Field1=!
See the _Phase_Mtr_Ctrls macro listing in the Phase Meter mini-app for an example that tests to see if Field1 is empty, and if so prompts the user to enter a file name there.
See also Macro Overview
Questions? Comments? Contact us!We respond to ALL inquiries, typically within 24 hrs.
Over 30 Years of Innovative Instrumentation
© Copyright 2007 - 2017 by Interstellar Research
All rights reserved