Daqarta
Data AcQuisition And Real-Time Analysis
Scope - Spectrum - Spectrogram - Signal Generator
Software for Windows
Science with your Sound Card!
The following is from the Daqarta Help system:

Features:

Oscilloscope

Spectrum Analyzer

8-Channel
Signal Generator

(Absolutely FREE!)

Spectrogram

Pitch Tracker

Pitch-to-MIDI

DaqMusiq Generator
(Free Music... Forever!)

Engine Simulator

LCR Meter

Remote Operation

DC Measurements

True RMS Voltmeter

Sound Level Meter

Frequency Counter
    Period
    Event
    Spectral Event

    Temperature
    Pressure
    MHz Frequencies

Data Logger

Waveform Averager

Histogram

Post-Stimulus Time
Histogram (PSTH)

THD Meter

IMD Meter

Precision Phase Meter

Pulse Meter

Macro System

Multi-Trace Arrays

Trigger Controls

Auto-Calibration

Spectral Peak Track

Spectrum Limit Testing

Direct-to-Disk Recording

Accessibility

Applications:

Frequency response

Distortion measurement

Speech and music

Microphone calibration

Loudspeaker test

Auditory phenomena

Musical instrument tuning

Animal sound

Evoked potentials

Rotating machinery

Automotive

Product test

Contact us about
your application!

Macro Loops


Macros: WHILE, WEND, LoopBreak

Introduction:

Daqarta offers two general approaches to creating repeating macros: WHILE/WEND loops and invoked macro loops.


WHILE/WEND Loops:

A WHILE/WEND loop is essentially an IF structure where the WHILE statement replaces the IF, and WEND replaces ENDIF. (There is no ELSE equivalent.) If the WHILE test is true, all the commands up to WEND are run, just like a normal IF/ENDIF. But then the WHILE test is run again and the process repeats. If the WHILE test is false, or becomes false on any pass, the commands are skipped and execution continues after the WEND.

WHILE and WEND (like IF and ENDIF) are regarded as macro prefixes, so each needs to be followed by a period.

As an example, the following uses a WHILE/WEND loop to create a simple 10-second countdown timer:

    A=10
    WHILE.A=>0
        Msg="Seconds remaining = " + A
        WaitSecs=1
        A=A-1
    WEND.
    Msg="Done"

In this example the A macro variable is initialized to 10, then the WHILE statement tests to see if A is above zero. If so, a message is displayed showing that value, followed by a delay of one second. Then A is decremented by one and the WHILE is repeated. Important: If you don't initialize this variable, or don't decrement it inside the loop, then it is easy to get stuck in a very long or even infinite loop. (If that happens, hit the Cancel button in the Macro Dialog.)

There is no requirement for a pre-defined number of counts; the WHILE can test for any arbitrary condition. You could repeat a set of operations until a certain key is pressed, or until a measured value exceeded a certain threshold, or until the result of some calculation converged to within a specified error limit.

A WHILE can use the same AND/OR/XOR operators as in an {\b IF} structure, such as:

    WHILE.A=>B
    AND.C=<D
        ...
    WEND.

You can also exit a WHILE loop early, based on a separate test or calculation within the loop itself that results in a LoopBreak=2 command.

Sometimes you may want an infinite loop which runs until cancelled manually, or until a LoopBreak=2 is given. You can do this by making the WHILE condition always true, such as WHILE.0=0.

WHILE loops can in principle contain nests up to 16 levels deeper (more indented) than the main WHILE. However, please note that this total includes invoked loops (see below), each of which acts as another level.

You can have an arbitrary number of WHILE statements at each level.


Invoked Macro Loops:

Invoked loops are easiest if you already have a named macro and want another macro to invoke it a certain number of times. Normally, a macro runs another macro by putting an '@' in front of it, so if you had a macro called _MyCount you could invoke it with:

    @_MyCount

If you want to run it 10 times, you would use:

    @_MyCount=10

So the WHILE/WEND countdown timer shown above could be implemented by creating a macro named _MyCount that consisted of all the commands between the WHILE and WEND. Then to invoke the timer from another macro, you would use:

    A=10
    @_MyCount=A
    Msg="Done"

If you later need a countdown with a different duration, just set A to the desired number of seconds and invoke again the same way.

Note that there is no testing going on here; the value or expression after the equal sign is evaluated only once, and that determines the number of times the @ macro is run. For example, if you used:

    A=10
    @_MyCount=5

The counter would still start at 10, but only count down to 6. Similarly, if you set the value after the equal larger than A, the counter could run to negative numbers.

Macros can include other macros that are themselves run as loops. These can be nested up 16 levels deep, with an arbitrary number of invoked macro loops at any level. (Note, however, that this total includes WHILE loops, each of which counts as a separate level if nested.)

Invoked macro loops can be exited early, on the basis of some test within the looped macro that results in a LoopBreak=1 command. For example, suppose you want to run _MyMacro up to 20 times, using @_MyMacro=20. Each time, _MyMacro will itself run another macro called _MyTest that collects some data and saves it to a file.

After each _MyTest finishes, _MyMacro must increment the Left Stream 0 Tone Frequency by 500 Hz using a preset frequency step size. However, you want to allow _MyMacro to be started from any arbitrary frequency, but never to go above 5000 Hz.

The definition of _MyMacro would look like:

    @_MyTest                ;Run user test
    L.0.ToneFreq=>1         ;Next frequency step
    IF.L.0.ToneFreq=>5000   ;Beyond limit?
        LoopBreak=1             ;Exit macro "loop" if so
    ENDIF.

If for some reason you want to keep track of how many times _MyMacro actually runs, you can include a command that increments a macro variable which you can then test with later IF statements, or display in a message or a Field.

The current loop counter is returned by reading LoopBreak as a variable. This value will count from the requested number of loop passes down to zero.

Please note that LoopBreak=1 causes the loop to exit after the current iteration, essentially by forcing the remaining count to zero. It does not force an immediate return. If the invoked macro contains commands after LoopBreak=1, they will be executed until the end of the macro; the macro then returns to the caller and is not run again.

LoopBreak=1 has no effect when given in an ordinary subroutine that is invoked without a loop count, like @_MySub.

However, you can use LoopBreak=0 to return early from any invoked macro subroutine, not just those run as loops. The invoked macro will ignore any subsequent commands and immediately return to the caller, likewise ignoring any invoked loop count.

Sometimes in a an ordinary subroutine this can be a simple way to avoid a nest of IF statements whose main function is simply to get all paths through the subroutine to converge to a conventional exit at the end of the code.

Alternatively, you can use LoopBreak=-1 to force the subroutine and its caller (and the caller of the caller, etc) to exit immediately. This is a more user-friendly way to abort than the Cancel= option, as long as you leave the user with a clear explanatory Msg or Mtr0-3 message, or perhaps a WaitMsg that requires confirmation.


LoopBreak Table:

    LoopBreak=-1   ;Subroutine and callers early exit
    LoopBreak=0    ;Subroutine early exit
    LoopBreak=1    ;Invoked macro early exit
    LoopBreak=2    ;WHILE loop early exit

    UN=LoopBreak   ;Read remaining invoked macro passes

See also Macro Overview

GO:

Questions? Comments? Contact us!

We respond to ALL inquiries, typically within 24 hrs.
INTERSTELLAR RESEARCH:
Over 35 Years of Innovative Instrumentation
© Copyright 2007 - 2023 by Interstellar Research
All rights reserved