Spectrum Lab's
Interpreter
Contents of this chapter:
There is a simple command interpreter in the program, used to define periodic,
scheduled, and conditional actions; macro buttons and other purposes. Multiple
commands can be entered in a single line using the ':'-character as separator
(like in the old BASIC programming language). An example:
capture:export.start("NewFile01.txt"):export.write(";-- new file segment
--")
For testing purposes, you can enter and run commands in the
periodic actions dialog, or you can enter them
in the command window.
Functions: A function is a subroutine which usually requires some kind of
input (passed in an argument list), and it always returns a value to the
caller. Function names are written in lower case to tell them from variable
names (do not mix functions with procedures. A procedure does
not return a value). Functions and numeric expressions can also be entered
in the watch window where they will be periodically
evaluated and displayed.
Note: Most (but not all) interpreter commands and -functions can be invoked
from a remote PC through SpecLab's integrated HTTP
server, using a piece of Java script which you can find in the examples
in the "server_pages" directory.
See also: Spectrum Lab's main index .
Command and Function
overview
Overview of procedures (a procedure does
not return a value. The difference between "procedure" and "command" is academic,
both are used here for the same thing) . Note: All these procedures can also
be invoked by other programs(!) using a message-based
protocol, or through the DOS
command line (even if the program is already running).
-
blackbox (abbrev'd as "bb")
modified parameters of the DSP blackbox components in the test circuit.
-
capture
Saves the current waterfall and/or spectrum plot
on the main window as a bitmap file. Filename and JPEG quality can be specified
in the command too, like this: capture("LowQual.jpg",30). If
the quality (2nd parameter) is omitted, it will be as
configured . More info on the capture
command is here.
-
cfg.xyz = XXX
Command to modify a component (xyz) in Spectrum Lab's configuration. Use
a formal assignment.
-
click
Generates a short clicking sound with the PC speaker. Used for debugging.
Works under Win95, Win98, NT and Win2000.
-
print
Prints some numeric or string values into one line of the interpreter's message
window. Used for debugging.
-
fo_cal.xxxx
Used to control the frequency offset calibrator.
-
fopen, fwrite, fprint, fclose
open, create and close text files, write strings or lines of text into a
file for special applications.
-
digimode (abbrev'd as "di")
Returns some settings and parameters of the digimode module, for example
the decoder's AFC'ed frequency.
-
exec
Used to run an external file, with optional passing of parameters in the
(DOS-) command line. Be careful with this command, because running other
programs may steal a lot of CPU power which may cause the loss of audio samples
!
-
export.xxx
A group of commands to start and stop the user-defined text
file export.
-
fft.export.xxx
A group of commands to control the export of FFTs into simple text files.
Only required if the normal (periodic) export of FFTs isn't sufficient.
-
filter.xxx
A group of commands to control the audio filters.
-
generator.xxx
A group of procedures to control the test signal generator. Use a formal
assignment ("=") to set a parameter.
-
circuit.xxx
A group of command to control other components of the test circuit, for example
the oscillator (NCO) for the frequency
converter.
-
plot.xxx
A group of procedures to control the real-time
plotter, including a screen capture
of the current diagram.
-
ptt_port.xxx
Access the COM-port used for PTT control (PTT="push-to-talk", to control
a transmitter).
-
rct.xxx
Remote Control for certain HF- and VHF radios. Allows changing the frequency
which the radio is tuned to, etc.
-
rec.xxx
Commands for the "triggered audio recorder"
-
send(<recipient>,<message>)
Sends a text message to another application.
-
sound(<freq>)
Can produce a tone ("beep") of any frequency in the PC speaker. Now even
runs under WinXP !
-
spa.xxx (spectrum analyser)
Access to a few parameters of the spectrum analysers, mainly the pre-processing
of data before the FFT.
-
spectrum.xxx (abbreviatable as "sp.xxx")
Several commands to save the current
spectrum (="FFT result") as a text file,
start/stop the spectrum display,
print into the spectrogram, etc.
-
sref.xxx (spectrum
reference)
Turn the spectrum reference on and off, pick it from the current spectrum,
load and save as disk file.
-
sr_cal.xxxx
Used to control the sampling rate calibrator.
-
terminate
Terminates Spectrum Lab. Can be sent as a command
to other instances too, to terminate them all.
-
timerX.start, timerX.restart,
timerX.periodic (X = 0..9)
Commands for the user-programmable timers, mostly used in the "Conditional
Actions" (to produce events, etc)
-
water.xxx
A few commands specifically to control the waterfall (spectrogram).
-
wave.xxx
A group of commands for recording and playing audio streams as wave files.
-
window.xxx
Allow setting the window size and -position of the main window. Components
(xxx): left, top, with, height .
-
<there will certainly be more commands here in future>
Overview of interpreter functions (a
function returns a value to the caller). Often used for the
text-based export function.
-
avrg(freq1, freq2), avrg_n(freq1, frequ2)
returns the (power-)average value in the specified frequency range
-
azim(freq1, freq2)
returns the angle-of-arrival (or "bearing") of a signal received in the specified
frequency range. Only works in RDF
mode.
-
blackbox (abbrev'd as "bb")
reads parameters and current values of the DSP blackbox components in the
test circuit.
-
cfg.Xyz
Can be used to access many components of Spectrum Lab's configuration parameters.
-
dB(voltage [,ref_value] )
Converts a linear ratio (or "voltage") into decibels. If the reference level
(2nd argument) is not specified, the reference value is assumed to be 1.0
(unity). Note that unlike dividing by ref_value in a formula, the dB-function
will handle reference values of zero without throwing an error (and return
+200 as a "very large" value). Examples:
dB( 2 ) = 6.021 ; dB(25,100) = -12.041
-
digimode
Returns some settings and parameters of the digimode module, for example
the decoder's AFC'ed frequency.
-
export.value[column]
returns the last calculated value in a particular column of
the export file. There are also some functions to read the contents of the
export file definition table with
the interpreter.
-
filter.xxx
A group of functions which return properties and settings of the audio filters.
-
fo_cal.xxxx
Used to query values from the frequency offset
calibrator. Can be (ab-)used for a precise measurement of a single
frequency.
-
generator.xxx
A group of functions to read parameters of the test signal generator.
-
int(X)
returns the integer part of X. For example, int(123.456) is 123 .
-
initialising, terminating
Used in the "IF"-column of the conditional
actions. The 'initialising'-flag is set once after starting Spectrum
Lab, or after loading a new configuration. The 'terminating' flag is set
shortly before SL terminates. It was used for automation, for example to
copy certain files to a website showing "spectrogram offline" or similar.
-
log(x)
returns the decade logarithm of x .
-
noise(freq1, freq2)
returns the noise level in a specified frequency range. Uses an algorithm
suggested by G4JNT (which is also used in SpecLab's ALERT module).
-
min(value1, value2, ..)
-
max(value1, value2, .. )
compares two or more numeric values (or expressions) and returns the smallest
(or largest) value.
-
now
returns the current time (including the date) in the internal format of the
program, which is a combination of date plus time as a floating point number.
-
peak_a(freq1, freq2)
returns the maximum amplitude in the specified frequency range.
Usually in decibels, if the FFT output is logarithmic.
-
peak_f(freq1, freq2)
returns the frequency of the highest peak in the specified frequency range.
-
ptt_port.xxx
Access the COM-port used for PTT control (PTT="push-to-talk", to control
a transmitter). Can be used to polling some signals on the serial port in
the conditional actions.
-
rct.xxx
Remote control commands and -functions for certain HF- and VHF radios.
-
sin(x), cos(x), sqrt(x), pi
some of the usual math functions and constants
-
sinad(#channel, f_center, notch_width, filter)
Calculates the SINAD value (SIgnal Noise And Distortion).
-
sigma( #channel, freq1, freq2 )
Calculates the standard deviation (greek sigma) in a certain spectrum (#channel)
within a certain frequency range.
-
spectrum.xxx (abbreviatable as "sp.xxx")
Query some properties of the current spectrum, "pause"-status, etc.
-
spa.xxx
Parameters and additional values of the spectrum analyser,
or the readout-cursor in the spectrum analyser.
-
sr_cal.xxxx
Used to query values from the sampling rate calibrator.
-
str(<format_string>, <value>)
turns a numeric value into a string. The format string defines how the number
shall be formatted.
-
system.info
Returns some "system info" as a string (including the number of free variables
and free string memories, etc). Used for debugging purposes.
-
tds.xxx
access the time-domain scope (current amplitude and phase value, depending
on the scope mode)
-
time
returns the time when the last line of the waterfall (FFT) has been calculated.
Depending on the scrolling speed, this can be different from "now". The internal
format is the same as for "now".
-
timerX.expired (X = 0..9)
Checks if one of the user-programmable timers is expired. Can be used to
generate events for the "conditional actions".
-
val(<string> [, <format string> ] )
turns a string into a numeric value. The <format
string> is optional, only really required if <string> represents
a time+date.
-
veff (freq1, freq2)
returns the effective voltage in a given frequency range (normalised to 1
Volt for 100% SINE WAVE at the ADC's input).
-
water.xxx
access to waterfall settings and -variables. Most affect the spectrum graph
too, but the name remains...
See also:
-
special functions for the
conditional
actions ("events")
-
numeric operators (in the next chapter)
back to top
Numeric expressions
The numeric interpreter described here is used to evaluate 'formulas' wherever
needed in the program. The main usage is the versatile text file export function.
The basic function is similar to a programmable ("basic") pocket
calculator, expressions are evaluated from left to right (with different
operator priorities: multiply before add etc).
Operators:
-
+ - * / % ^ (arithmetic: add, subtract, multiply, divide, modulo, X
power Y )
-
< <= == <> >= > (comparations: less than,
less or equal, equal, not equal, .... greater than; same priority as 'add')
-
|, || (pipe character, ALT-"<", boolean and bitwise OR, same priority
as 'add')
-
&, && (ampersand character, boolean and bitwise AND, same priority
as 'multiply')
-
! (boolean inversion, aka "NOT", like in the C programming language)
-
XOR bitwise exclusive OR, frequently used to "toggle" bits, for
example:
filter[0].fft.options = filter[0].fft.options XOR 16
The operands in a numeric expression can be simple numbers,
variables, or function calls.
Numeric expressions can be used as argument for some other commands (they
can be "nested"). Example:
1/(2*pi*sqrt(1.22e-3*1114e-12))
Some more examples can be found in the description of the
print command.
Note for German users / Hinweis für deutsche Anwender: Spectrum Lab
verwendet - wie die meisten Programmiersprachen - das Komma als
Aufzählungszeichen. Als Dezimaltrenner dient immer der international
übliche Dezimalpunkt, nicht das verfluchte Dezimalkomma
! Es ist daher nicht nötig, in irgendwelchen Windoze-Systemeinstellungen
herumzuwühlen um die "deutschen Besonderheiten" wie das Dezimalkomma
abzuschalten.
See also: overwiev ,
functions, procedures
, string expressions .
An interpreter variable can accept a single numeric value, or a single string.
It begins to exist by assigning a value to it, there is no need to declare
a variable (in contrast to the "C" programming language). Variables were
initially used to define conditional actions, etc, but they may be used in
a script-like language one day too.
The name of a variable must begin with an upper- or lower case letter,
the next characters may include decimals (0..9) and the underscore. Nothing
else !
Furthermore, be careful not to use built-in keywords as variable names. This
will usually result in a syntax error or similar.
Some examples for variables:
CurrentPeak = peak_a(300, 3000)
A=A+1
InfoString = "Oh, well"
InfoString = InfoString + " .. so what"
TimeString = str("hh:mm:ss",now)
Variables can help to reduce the CPU load. For example, if you need the result
of a complicated function (or subroutine) in many different places, it is
more efficient to calculate the function only once and store the
result in a variable, instead of computing the same result over and over
again. A good place to do this is in the
conditional action table. Since all
variables in SpecLab are "global" (up to now), you can read the value from
the variable wherever you need it, for example in the
watch window, on a
programmable button, etc.
Note: You can even access those variables from a Java script running in your
web browser ! The integrated HTTP server
allows any application, even on a remote PC, to communicate with SpecLab
- which includes read- and write access to the interpreter variables.
Functions
See also: Overview of interpreter
functions, overview of interpreter
procedures .
now, time (functions)
These functions return date- and time as a floating point value (which can
be converted into a string if required)
-
now
returns the current time (including the date) in the internal format of the
program (see below).
-
time
returns the time when the last line of the waterfall (FFT) has been calculated.
Depending on the scrolling speed, this can be different from "now".
The format is the same as used for "now".
The format of the values returned by these functions is defined as:
"seconds elapsed since Jan 1 1970, 00:00:00 UTC".
(Note: because it is a floating point value, the resuliton is much higher
than a second).
To display time and/or date, use the str-function which can turn numeric
values into strings . Example:
print("Date="+str("DD-MM-YYYY",now), "Time="+str("hh:mm:ss",now) )
See also: function overwiev ,
spectrum.time .
Most of the calculation functions explained in the following chapters accept
an options "spectrum analyser channel number".
-
Valid spectrum analyser/channel numbers are:
-
#1 = first channel of the first spectrum analyser ("main spectrum analyser
/ spectrogram")
#2 = second channel of the first spectrum analyser ("main spectrum analyser
/ spectrogram")
#3 = first channel of the second spectrum analyser ("second spectrogram
window")
#4 = reserved for the second channel of the second spectrum analyser (future
plan !)
#LTA1 = long-term average of the first channel in the first analyser (if
enabled)
If specified at all, the spectrum analyser/channel number must be the first
parameter in a function's argument list. If it is not specified (which will
often be the case), the first channel of the first analyser will be used
by default. This applies to the following interpreter functions:
-
avrg( #chn, freq1, freq2)
-
avrg_n( #chn, freq1, freq2)
-
noise( #chn, freq1, freq2)
-
noise_n( #chn, freq1, freq2)
-
peak_a( #chn, freq1, freq2)
-
peak_f( #chn, freq1, freq2)
-
sigma( #chn, freq1, freq2)
-
spectrum.save(#chn, "filename.txt")
-
sref.pick(#chn)
-
fft.export( #chn )
See also: peak detection functions,
noise calculation functions,
spectrum average functions,
interpreter function overwiev .
Peak detection functions
-
peak_a(freq1, freq2)
-
peak_a(#<channel>, freq1, freq2)
returns the maximum amplitude in the specified frequency range.
Usually in decibels, if the FFT output is logarithmic. The peak_a function
checks the contents of all FFT
bins(*) in the
specified frequency range, and returns the amplitude (magnitude) of the strongest
peak using an interpolation method which is described
here.
If the optional "channel" (number or name)
is not specicied as the first parameter, the function operates on the first
channel of the current spectrum of the first frequency analyser (a special
channel name accesses the long-term average).
-
peak_f(freq1, freq2)
returns the frequency of the highest peak in the specified frequency range.
-
azim(freq1, freq2)
returns the angle-of-arrival (or "bearing") of the strongest signal in the
specified frequency range. More information in the
documentation of the radio direction
finder.
If no channel number is specified, the peak detecting functions operate on
the 'latest' result from Spectrum Lab's main spectrum analyser, first channel
(= "#1"). Optionally, a spectrum analyser
/ channel number can be specified. Examples::
-
peak_a( 45, 1000) or peak_a(#1, 45, 1000) calculates the peak
amplitude for the first channel of the first spectrum analyser (=main
spectrogram) in the frequency range 45... 1000 Hz
-
peak_a(#2, 45, 1000) calculates the peak amplitude for the second channel
of the first spectrum analyser in the frequency range 45... 1000 Hz
-
peak_f(#3, 45, 1000) calculates the peak frequency for the FIRST channel
of the SECOND spectrogram analyser in the frequency range 45... 1000
Hz
The relation between input voltage into the A/D-converter and the FFT output
value in decibel (dB) is explained here.
back to the interpreter function overwiev
To increase the frequency-resolution of the peak detecting functions to a
fraction of an FFT bin width, an interpolation algorithm is used as explained
below. It is based on a recipe suggested by DF6NM.
First, the FFT bin with the strongest magnitude (dB) is searched in the frequency
range of interest. Next, from the magnitude of the strongest FFT bin and
it's strongest neighbour, the exact frequency and and amplitude of the bin
can be interpolated. This is possible, because the curvature of the
fourier-transform near the peak is known - it only depends on the windowing
function which was applied to the samples in the time domain, before the
FFT. This only works if the carrier is stable and quite strong, but under
such circumstances the result (the frequency accuracy) can be stunning:
It is often possible to measure the frequency of a carrier with a resolution
of a few milli-Hertz, though the FFT bin width is in the Hz-region ! This
way, you can measure frequencies quickly and accurately, which would otherwise
take an endless gate-time (consider this: a classic "frequency counter" needs
a tate time of 1000 seconds to measure a signal with a
1-mHz-resolution, which doesn't mean accuracy).
The frequency-interpolation subroutine is internally used by the
peak-detection functions and for the
readout-cursor on the main spectrum
display.
Average Functions
Syntax:
-
avrg(freq1, freq2)
-
avrg_n(freq1, freq2)
-
avrg( #<channel>, freq1, freq2)
The avrg functions work like this (in detail):
-
Add the values (converted into POWERs) from all FFT bins which belong to
the specified frequency range.
-
Divide the sum by the number of FFT bins.
-
Convert the result back into decibels, it the FFT used logarithmic scales.
-
(only for avrg_n)
Add or subtract a few decibels, depending on the current FFT settings. The
normalization procedure is explained here
in detail.
The avrg function can be used to determine the relative strength of (relatively)
broad-band signals with known modulation patterns. For example, there may
be a digital emission on 137.0kHz with a bandwidth of 100Hz. Assuming you
have an LF receiver tuned in USB to 135.0kHz, use an AF frequency range of
1950.0 to 2050.0 Hz for the avrg function. This will give an estimate for
the signal strength of that particular station.
To measure the signal-to-noise ratio of broadband signals, use the avrg-function
in combination with the noise-function. (Use a LARGER frequency range for
the noise function, at least 5 times the bandwidth used for "avrg").
The relation between input voltage into the A/D-converter and the FFT output
value in decibel (dB) is explained here.
Optionally, a spectrum analyser / channel
number can be specified if you don't want to use the 1st channel of the
1st spectrum analyser. Example: avrg(#2,200,1000)for the 2nd
channel of the 1st spectrum analyser.
See also: effective voltage,
SINAD, function
overwiev
-
Syntax:
-
veff(freq1, freq2)
This function returns the effective voltage in a given frequency range,
normalised to 1 Volt for 100% SINE WAVE at the ADC's input, based on the
latest spectrum calculated in the main spectrum analyser.
Notes:
-
The result is always proportional to a voltage, regardless of the amplitude
display unit of the spectrum analyser. If the analyser returns "dB"-values,
the veff-function converts these dB-values back to voltages internally.
-
Unlike a "true RMS" voltmeter, this function is frequency sensitive. It does
not operate on data in the time domain, but operates on the data in
the frequency domain (in fact, it uses the result from the main spectrum
analyser. If the main frequency anayser is "off", this function does not
work).
See also: "average" functions,
SINAD,
function overwiev
For some 'special' applications (or for debugging..), a function was implemented
to calculate the standard deviation (greek lower case sigma; german:
Standardabweichung).
-
Syntax:
-
sinad(#channel, frequ1, frequ2
)
The returned value is the standard deviation (sigma) in the spectrum of the
specified channel, between freq1 and freq2.
The frequency range must be specified because a part of the spectrum will
often be unusable, maybe due to filtering, 1/f-noise, or other reasons which
only you (and not SL) will know.
See also: function overwiev
The sinad function calculates the ratio betwen SIgnal, Noise
And Distortion to noise and distortion as a logarithmic value. It provides
a quantitative measurement for the quality of an audio signal.
-
Syntax:
-
sinad(#channel, center_freq, notch_width, filter_model)
where all these values are optional:
-
channel: defines the source of the data used for SINAD measurement.
In Spectrum Lab, this must be one of the spectrum analyzer channels.
#1 is the first channel, #2 is the second channel.
-
center_freq: the frequency of the audio test tone.
Usually 1000 Hz which is the recommended -and also the default- value.
-
notch_width: Width of the notch filter in Hertz.
The default value (if this parameter is not specified) is 30 Hz.
-
filter_model: Specifies the characteristic of the audio filter inside the
SINAD meter.
Possible values are:
0 = no filter (flat response), no bandwidth limit
1 = C-MESSAGE filter used in North America
2 = CCITT filter specified in ITU-T ("p53 filter")
Examples:
-
sinad(#1,1000,30,1)
-
Calculates the SINAD value in dB using the C-MESSAGE filter.
Notch width = 30 Hz is OK for FM receivers, but may be a bit too narrow for
SSB receivers with coarse tuning steps or drifting VFO's.
-
sinad(#1,1000,200,2)
-
Calculates the SINAD value in dB using the CCITT ("p53") filter.
Notch width = 200 Hz should be ok for VHF SSB receivers even if there is
some VFO drift.
Notes:
-
To get the most accurate results, use the lowest possible notch width. If
the notch is too wide, a lot of noise power will not be taken into account.
ITU-T Recommendation 0.132 describes a notch filter used with 1.02 kHz tones
with a maximum notch width of 400 Hz, and a minimum notch width of 25 Hz
with a depth of 50 dB. The notch in SpecLab is realized by simply leaving
away all FFT power bins within the notch width, the effecive notch is much
deeper than the required 50 dB.
-
If you make the notch too narrow, the test signal may be outside
the notch so it would erroneously be considered as "distortion". For more
info, read the extra document about SINAD
measurements and how the SINAD meter in SpecLab works internally. That
documents also describes some pitfalls which must be avoided when using the
a soundcard simultaneously as a sine generator and a SINAD meter.
-
There is a preconfigured settings file named
SINAD_1.USR in
the installation archive. It displays three SINAD values for the three different
filter models simultaneously on the programmable
macro buttons on SpecLab's
main screen. Be sure to watch also the spectrum when making SINAD measurements.
This helps to avoid false results when the signal from a VHF SSB receiver
'wanders' outside the notch range.
-
To display the SINAD value in one of the programmable macro buttons, use
a string expression like this (taken from sinad_1.usr):
"SINAD1="+str("00.00",sinad(#1,1000,100,1))+" dB"
See also: more about SINAD
measurements, average functions,
effective voltage,
function overwiev
Noise calculation functions
The noise functions calculate the noise level in a specified frequency range.
-
noise(freq1, freq2)
returns the noise floor in the specified frequency range. Uses an algorithm
suggested by G4JNT (which is also used in SpecLab's ALERT module).
-
noise_n(freq1, freq2)
Same as noise(), but noise_n additionally normalizes the result for a receiver
with exactly 1 Hertz bandwidth, to make the reading independent of the current
FFT settings. The normalization procedure is explained
here in detail.
The definition of noise levels is not easy. Here is the basic algorithm
of the 'noise' function:
-
An array of amplitudes (usually dB values) from the last FFT calculation
is sorted into order of increasing amplitude.
-
The amplitude of the lower quartile value (for example bin number 256 in
a sorted set of 1024 points) PLUS 3dB is then returned as an estimate of
the mean noise level.
This technique automatically throws away very high values (strong signals)
that would otherwise affect the result.
So the value returned by the noise()-function is very different from the
average value for the same frequency range (there is one special case where
both should be equal, see the notes below).
Optionally, a spectrum analyser / channel
number can be specified if you don't want to use the 1st channel of the
1st spectrum analyser. Example: noise_n(#2,200,1000) to retrieve
the noise level from the 2nd channel of the 1st analyser, between 200 and
1000 Hz.
Notes:
-
The values returned by the noise() function depend on the current FFT settings.
Because of the "FFT gain" and the additional gain from optional FFT averaging,
the noise()-result will become lower when the FFT size is increased.
When you double the FFT size, the noise will drop by 3dB. Examples:
FFT size = 1024 -> noise result = 59.5 [dB]
FFT size = 2048 -> noise result = 56.5 [dB]
FFT size = 65536 -> noise result = 31.5 [dB] (for the same WGN signal)
-
The value returned by the noise_n() function does NOT depend on the current
FFT settings (because the FFT- and decimation 'gain' are internally subtracted).
Therefore, the result of noise_n() may be very different from the noise 'floor'
which you see in the spectrum graph.
-
If the observed frequency contains 'white gaussian noise' (WGN), the values
returned by noise(f1,f2) and avrg(f1,f2) should be equal. You can verify
this with SpecLab's noise generator.
The relation between input voltage into the A/D-converter and the FFT output
value in decibel (dB) is explained here.
See also: average functions,
sigma( ), SINAD,
function overwiev
Noise normalised to 1Hz
bandwidth
The 'noise' level (and average value of noisy signals) calculated from a
spectrum with the "noise()"-function is influenced by some FFT settings (FFT
size, window function) and the soundcards sampling rate. But for some
applications it is desirable to have 'noise level' readings which do not
depend on the FFT settings and the sample rate.
Spectrum Lab offers the possibility to 'normalize' the result of the noise()
and avrg()-functions (then called noise_n and avrg_n) to make them independent
from the current FFT settings. To be precise: make them independent from
the effective FFT bin width, measured in Hz.
The noise (and average) value can be normalised for a receiver bandwidth
of 1 Hz, no matter if the currently used FFT bin width is 6 Hz or 0.0001
Hz or whatever. You can consider an FFT bin as a single receiver for a very
small frequency range, and all power in that frequency range is dumped into
the bin. The bin actually will contains an ENERGY because it collects the
power over a certain time, but don't care about that now. The FFT bin with
is called "frequency resolution" somewhere else in this manual.
Due to the nature of noise, if the bin width is halved (for example by doubling
the number of bins), the noise(-power) collected in every single bin is reduced
by 3 dB. One may call this phenomenon "FFT gain".
The formula used by Spectrum Lab to "normalize" a noise value (in decibels)
is this:
db_norm = db_calculated - 10 * log10( fft_bin_width_hz )
-
Example:
-
FFT bin width (~"RX bandwidth") = 0.5 Hz,
measured noise (db_calculated) = -80dB.
The noise measured with an RX-bandwidth of 0.5 Hz must be lower than it would
be with 1.0 Hz bandwith. The normalised "noise" value is:
db_norm = -80[dB] - 10*log10( 0.5Hz / 1.0Hz)
= -76.99 dB -77 dB , which -as expected- is 3dB MORE than the non-normalized
value noise.
Notes:
-
It does not make sense to normalize "Peak"-values, because the FFT gain only
lowers the 'noise floor' but it does not the absolute amplitude of a
single-frequency (monochromatic) signal.
-
The normalised noise calculation was implemented primarily for Spectrum Lab's
export function, to get comparable results for propagation experiments on
longwave, not depending on the FFT settings.
See also: average-function ,
noise-function ,
veff-function , dB-function
, function overwiev
Decibel conversions and the
'0-dB-point'
Usually, values from the ADC (analog/digital converter) are fed into an FFT
(fast fourier transform) which generates an amplitude spectrum at first.
The next (optional) stage of processing turns the amplitudes into decibels.
This page contains some background information how the dB conversion works,
and how it can be modified.
Logarithmic scales and the 'reference level'
If a pure sine wave A*sin(omega*t) is fed into the ADC's input, one of the
FFT bins will contain the peak value which is proportional to the input voltage.
The values from all FFT bins are then converted into decibel value. One of
them contains the peak value Pdb:
Pdb = 20 * log(A / R). (simplified, if the peak if in the "center" of an
FFT bin)
The value R is an "internal Reference parameter". It depends on the soundcard
and on the FFT size, but don't worry about it (the program cares for the
FFT size). The maximum value of PdB is 0 dB. Above this point, the ADC gets
overloaded by a single sine wave.
-
Note: Always stay below the clipping point. In case of doubt check the input
monitor to avoid overloading the ADC, especially while looking only at a
small part of the spectrum. The A/D converter may be overloaded from a signal
which you don't see in the displayed spectrum range !
For this reason, all internally stored dB values (and those returned by some
interpreter functions) are negative (they can go down to -90dB .. -140dB,
depending on the FFT size and decimation).
For display, you can add an offset to the internally stored dB value.
If you prefer to see positive dB values on the screen, or want to 'calibrate'
the dB values to have absolute values on the screen, read the next chapter.
User-defineable 'dB-display-offset'
This 'offset' will be added to the result of the 'PdB' formula
explained above. By default, the offset is 0.0 dB and you will only see negative
dB values on the SpecLab screen. Set the offset to +90 if you like to see
mostly positive values on the screen (and to be compatible with old versions
of Spectrum Lab before V1.65). If you have a calibrated AF source, you can
set the offset so that 1 Microvolt will be displayed as '0.0 dB'.
You may even enter a numeric expression ("formula") as the 'dB-offset'. This
formula will be evaluated once per second (or less frequent), but only
after the calculation of an FFT.
You can use this for a programmed AGC (etc..), using the noise- or avrg-function.
Note that the functions "noise", "avrg", "peak" etc are not affected by the
'dB-display-offset', but they can be used to affect the 'dB-display-offset'
!
An example: You want the noise level in the AF range from 500Hz to 2.5kHz
to appear at the '0dB' line in the spectrum plot. Enter the following expression
as "Offset" (Menu Options..Display Settings):
Set the range for the 'amplitude scale' to -10..+80dB for this example, because
most of the displayed dB values will now be positive.
See also: "dB"-function ,
function overwiev
String expressions
Some interpreter commands (like export.start or wave.record) require strings
in the argument list. These strings can be simple constants, like
Note that a string constant should be embedded in double-quotes as shown,
otherwise white spaces in a string would be impossible. You can also 'add'
strings like this:
-
"Test"+str("hh_mm",time)+".txt"
The second example is a bit tricky. The
'str'-function formats a numeric value (here: the
value of 'time') into a string, using the specified format string (here:
'hh_mm'). The result of the str-function will be a string, for example 16:45
if the last spectrum was calculated at 16:45 o'clock. Three strings are added,
the result is a filename containing the time, like:
More possibilities of the format-string are explained in the next chapter.
Without the format string, the 'str'-function generates the shortest possible
decimal representation for the numeric argument, truncated (to a few decimal
places after the comma). Example: If N were 123.456, str(N) would return
"123.5".
-
If you want to use an evaluated string expression (=the 'result'
of the evaluation of a string expression) where the program expects a simple
text string, use the '@' character before the string expression. Example:
In the "watch window", you want to use the same format string as in the "export
definition table". The program expects a string literal (a "simple text"
there), so instead of typing:
-
export.format[1] (in the "watch list", "format" column)
-
you must use
-
@export.format[1]
-
which forces the interpreter to evaluate this string expression. Complicated,
isn't it ? Without this, the interpreter would think "export.format[1]" is
the format string itself, instead of the evaluated result which may
be "####0.0##" (as defined in the "export" table). However, these special
cases are quite rare. Using the leading '@' character is -at the moment-
only required in
-
-
the "format string" column in the watch list or export definition table,
-
the "title" column in the watch list or export definition table,
-
if a cell does not contain the string itself but a reference to a
string defined in another table or cell.
The backslash character has a special function (like in the "C" programming
language). The reason for this is manifold, so -for a start- here only some
basic facts which you should observe when using strings with backslashed
in them - like in filenames !
One of the reasons why we need backslash sequences in string expressions
is this: Because the double quote is used as delimiter for string literals
(in many programming languages), we must replace the double quote character
with the backslash sequence \" (backslash-doublequote). So here are the basic
rules for backslash-characters in string expressions. More info can be found
in textbooks about the "C" programming language !
-
A backslash followed by a double-quote character in the sourcecode (\") will
be translated into a double-quote character (without the backslash)
-
A double-quote character which is NOT preceeded by a backslash marks the
begin and the end of a string constant, like in "C" and Java .
-
Depending on the context where the string is used (for example in the
"print"-commands), the backslash sequences
\n, \r, \t
will be translated into the control characters NL, CR, and TAB .
-
Two backslashes together (\\) will be converted into a single backslash.
Remember this when you specify path names.
-
If a single backslash is not followed by any of the special characters mentioned
above, it will be copied 1:1 from the string expression into the resulting
string. This feature was implemented to keep SpecLab compatible with "old"
applications, which used pathnames with single backslashes. See the
"fopen"-command for more info.
See also: formatting options ,
numeric expressions ,
interpreter commands .
Format String for numeric
values
The following formatting options are available:
-
Numerical Values
-
# = placeholder for an optional digit in a number
0 = placeholder for a non-optional digit in a number
. = placeholder for the decimal point in a number
(german users: please forget the decimal comma !)
-
Time+Date Values
-
YY = Year, two digits only
YYYY = Year, four digits
MM = Month, two digits
MMM = Month-NAME (Jan, Feb, Mar, Apr, ...)
DD = Day of month, two digits
hh = hour of day, two digits
mm = minute, two digits
ss = second, two digits
ss.s = seconds, three digits (two places before and one place after the comma)
Notes:
-
The internal representation of time+date are the Unix-style "seconds elapsed
since January 1st, 00:00 UTC, 1970" (leap-seconds are ignored).
-
To convert a number into a string, use the str function
-
To convert a string into a number, use the val function
Examples for valid format strings:
###0.##
-
Format a fixed-point number with up to 4 places before the decimal point
and up to two fractional places (IF NOT ZERO).
0000.00
-
Format a fixed-point number with exactly 4 places before and 2 places after
the decimal point.
-
ACHTUNG, deutsche User: Spectrum Lab verwendet intern IMMER den Dezimalpunkt,
niemals das verfluchte Dezimalkomma ! Irgendwo unter
"Systemsteuerung"/"Ländereinstellungen" kann man auch andere Programme
wie z.B. Excel dazu bringen, den PUNKT zu verwenden. Wenn Sie Textfiles mit
Dezimalkomma über den großen Teich mailen, wird sich der
Empfänger bestimmt darüber freuen !
hh:mm
-
Format a date-and-time value, so that only the hour and minute are displayed
DD.MM.YYYY hh:mm:ss
-
Date and time used in Germany. There are so many 'flavours' especially for
formatting a DATE worldwide, so it's up to you... apart from ALWAYS to use
UTC, I suggest the following date format...
YYYY-MM-DD hh:mm:ss
-
Date and time as suggested (required) by ISO 8601. This is the most "logical"
format, with the 'most significant value' (the year) first. Preferred by
most scientists, and becoming more and more widespread amongst programmers.
back to the overwiev
print (procedure)
Prints some numeric or string values into one line
of the interpreter's message window, or (one fine day) into a communication
channel. Used for debugging.
-
Syntax:
-
print( Argument1, Argument2, ...)
The arguments can be either numeric or
string expressions. All arguments must be separated by comma or semicolon
(not colon.. the colon character is used to separate commands - remember
the old BASIC programming language) . A comma between two arguments
inserts an additional space, a semicolon does not.
Like in the "C"-programming language, the print function replaces certain
backslash sequences into their equivalent ASCII control characters as explained
here. These sequences are: /n = new line,
/r = carriage return, /t = tab, // = single backslash, /" = double
quote character.
Examples:
-
print("date="+str("DD-MM-YYYY",now), "time="+str("hh:mm:ss",now) )
-
print(1/3):print("OK?")
-
print(str("0.#################",1/3),".. 17 decimal places !")
-
print("fo=",1/(2*pi*sqrt(1.22e-3*1114e-12)),"Hz")
-
print(val("2001-11-05 22:00:00","YYYY-MM-DD hh:mm:ss"))
Resulting text for the above examples:
-
date=17-09-2001 time=19:01:01.
-
0.333
OK?
-
0.33333333333333332 .. 17 decimal places !
-
fo= 136520.422 Hz
-
1004997600 (which is the number of seconds passed since Jan
1, 1970, 00:00:00)
Note: Very similar like print are the commands
fprint and fwrite, which write lines
of text into a file. See file commands.
See also: Numeric expressions,
string expressions, command
overwiev
Turns a numeric value into a string.
-
Syntax:
-
str( <format-string>, <numeric expression> )
Examples:
-
print("date="+str("DD-MM-YYYY",now), "time="+str("hh:mm:ss",now) )
-
export.start(str("YYMMDDhhmm",now)+".txt")
See also: Numeric expressions,
string expressions,
backslash sequences,
command overwiev,
val-function, format
string .
fopen( <filename>
[,<open-mode>] )
Opens or creates a disk file. The optional open-mode is a
single-letter-parameter with one of the following values:
-
r
-
Open for reading only. Does not make sense at the moment because there are
no file-read-routines yet !
-
w
-
Create for writing. If a file by that name already exists, it will be
overwritten.
-
a
-
Append; open for writing at end-of-file or create for writing if the file
does not exist.
The default open-mode is "w". If only the filename is specified, an old
(existing) file will be overwritten (truncated). Also the line printer can
be opened for plain text output with this routine, use fopen("LPT1") for
this purpose.
Since 2006-03, a third argument can be specified for shared files. The syntax
is
fopen( <filename>, <open-mode>, <share-mode> )
then. The share mode is a combination of flags which are explained in the
Win32 programmer's reference for the CreateFile function, parameter dwShareMode.
According to that source, the share modes can be combined if necessary:
-
d
-
Subsequent open operations on the file will succeed only if delete access
is requested (FILE_SHARE_DELETE).
-
r
-
Subsequent open operations on the file will succeed only if read access is
requested (FILE_SHARE_READ).
-
w
-
Subsequent open operations on the file will succeed only if write access
is requested (FILE_SHARE_WRITE).
Example for a file created for writing, granting read-access for other
applications:
fopen("c:\\share_test.txt",w,r) : REM Write new file, share for Read-access
fprint("Try to open the file with a text editor now,")
fprint("BEFORE closing it here, to see the effect of the read-share flag")
fclose
Note: Like in the "C" programming language, special care must be taken with
the backslash ! For example, a double backslash in the sourcecode will be
replaced with a single backslash in the filename. More details in the chapter
about backslash sequences .
fclose
Closes a file (a disk file, a printer, or something similar). Never forget
!
fprint( Argument1, Argument2, ...)
(abbreviated "fp")
fwrite( Argument1, Argument2, ...)
(abbreviated "fw")
These commands do almost the same as "print", exept that they write into
disk files instead of the command interpreter's output window.
The fprint command appends a carriage return and a new line
character after the text, fwrite does not. Use fwrite if many values must
be written into a single line of the output file. Control codes can be placed
in the output as in the "C" programming language, like \r for carriage
return and \n for new line (may be nice to have if you want
to send a formfeed to the printer).
-
If you need more than one file opened at the same time, append digits (0..9)
directly after the function names, like this:
-
fopen0("file_one.txt")
fopen1("file_two.txt")
fopen3("LPT1")
fp0("Hi, I am the first file.")
fp1("This is the second file!")
fp2("and this is the printer")
fclose0
fclose1
fclose2
An example for the file commands can be found under
"screen capture extension
macros" (which was the first application using file commands, but they
can be used for many other purposes).
See also: command overwiev,
str-function, print command
format string .
Sends a text message (string) to another window. Internally, a WM_COPYDATA
message is used for this purpose.
-
Syntax:
-
send(<recipient>,<message>)
-
Example:
-
send("RdfCalc","set brg1x="+str(azim(23350,23450)) )
Sends the measured azimuth angle of a signal near 23.4 kHz to a recipient
called "RdfCalc" (which is a utility for radio-direction calculation).
The recipient is the so-called class name of the main window of another
program running on the same computer. Sending a message to a program running
on a remote computer is not possible with this command.
For programmers: This command sends a string to the module "CL" (=command
line interpreter inside the receiving application), the
command-ID is "EC" (execute
command, don't send a response).
Note: Since version 2.7, it is possible to send messages between two instances
of SpecLab running on the same PC. Use recipient "SpecLab1" for the first
instance, and "SpecLab2" for the second instance, etc. The old class name
"TSpectrumLab" remains for backward compatibility, but it only works for
the first instance.
See also: Communication with external programs,
command overwiev
Converts a string into a numeric value.
-
Syntax:
-
val( <string>, <format-string> )
val( <string>, <format-string> )
Examples:
-
val("1.2345")
-
val("2001-11-05 22:00:00","YYYY-MM-DD hh:mm:ss")
The first example returns the value 1.2345 as a floating point value. Instead
of the string constant (or literal), also string expressions can be used
here (which makes more sense).
The second example returns the value 1004997600 (which is the
number of seconds passed between Jan 1, 1970, 00:00:00 and Nov 5, 2001,
22:00:00).
See also: Numeric expressions,
string expressions, command
overwiev, str-function,
format string .
min, max (functions)
These functions return the minimum or maximum value from a number of arguments.
Examples:
-
min(3,2,1,4)
-
returns 1
-
max(3,2,1,4)
-
returns 4
-
max( peak_a(200,500), peak_a(900,1000) )
-
returns the "highest peak amplitude" in the audio frequency ranges from 200..500
Hz and 900..1000 Hz.
See also: functions,
numeric expressions .
Can both produce some kind of acoustic signal with the PC's internal speaker
(not the soundcard!).
Syntax:
-
click
-
with no parameters produces the standard "Message Beep" using a windows API
routine (so chances are good this works on EVERY machine).
You can use this for debugging: Insert it whereever you like to check if
the program does what you expect. For example, with this command you can
*hear* if data is being written to a file from the export function, without
having the PC's monitor on.
-
sound( <frequency> [,<duration>] )
-
Expects the frequency in Hertz as parameter. The tone will be generated until
it is turned off by another sound-command or by "click". To turn the sound
off, use "sound(0)". Because this procedure uses direct port accesses, it
may cause problems under future Windows versions, but at the moment it runs
properly under Win95 / Win98, Win NT, Win ME and Win 2000 (thanks to A.Weitzman's
SmallPort utility). The sound command doesn't work if the SmallPort driver
is disabled in the system settings
!
The optional <duration> parameter may be used to turn the tone off
after a certain time, <duration> is a value in seconds.
This command was intended for debugging, with the ability to distinguish
between different "messages" (unlike the click-command).
Examples:
sound(1000) -> 1 kHz tone from the PC speaker, lasting
endless (until the next "sound" command)
sound(0) -> turns the sound from the PC speaker
off
sound(2000,3)-> 2kHz tone from the PC speaker for 3 seconds
back to the command verwiev
wave (procedure)
A group of commands for recording and playing audio streams as wave files.
-
wave.record
-
wave.record("filename.wav")
-
wave.record("filename.wav", <option> )
Starts saving audio samples as a wave file. If this is already active, the
old file will be closed automatically. If the new file already exists, it
will be OVERWRITTEN (the old data in an existing file will be lost).
The filename can be a flexible string expression.
The <option> value defines what type of samples shall be recorded,
and the source of the samples. Possible values are (at least):
1 = input samples, using the 'internal' processing rate
2 = output samples; possibly from generator,digimode,mixer, or filter.
-
wave.play("filename.wav" [, <analysis_type>] )
Starts playing or analysing a wave file. The second parameter (analysis_type)
is optional:
p = play with output to the D/A-converter, through the DSP-chain (like
in real-time mode)
q = quick file analysis, no DSP, no output to the D/A-converter
-
wave.stop
Stops recording a wave file (or playing a wave file, if already
implemented).
Note: Do not use this command to stop the
Triggered Audio Recorder, because it
has its own set of commands !
See also : Wave file analysis (interactive)
back to the overwiev
Offer some access to spectrum Lab's configuration data. Most of them are
only implemented for "internal" use (fellow programmers will find them in
a different file). You read the values from your
own program using a simple message-based communication
protocol.
back to the overwiev
Control the waterfall display. Currently
implemented functions and parameters are:
-
water.avrg_cnt, water.avrg_max
-
Returns the current / the maximum number of FFTs which were added to the
average of a single waterfall line. Details about spectrum averaging can
be found here.
-
water.f_min, water.f_max
-
Sets or retrieves the visible frequency range for the waterfall (and possibly
the spectrum graph which uses the same range).
To modify these values (in Hertz), use a formal assignment like these:
water.f_min=600 : water.f_max=900
-
water.brt
-
Waterfall brightness value.
-
water.ctr
-
Waterfall contrast value.
-
water.clear
-
Command to clears the waterfall screen and the spectrogram buffer.
-
water.f_offset
-
Access the "frequency offset" for the spectrum display and the waterfall.
Unlike the following function, this one does not affect f_min and f_max.
-
water.f_offset2
-
Almost the same as above, but write-access to this value changes the min-
and max- frequencies too. In effect, the frequency scale will be redrawn,
but a 1-kHz-AUDIO frequency will remain at the same position in the waterfall
screen (and the spectrum graph, if visible).
On read, water.f_offset2 returns the same result as water.f_offset .
-
water.count
-
Returns the number of waterfall lines which have been calculated since the
program was started. Can be used in the
Conditional Actions to do something
"special" as soon as a certain amount of waterfall lines (alias FFT's) have
been calculated. Note: If the waterfall is turned off, its counter won't
count ! (joking aside, FFTs may be calculated for the spectrum graph even
if the waterfall display is turned off). See also:
water.line_nr .
-
water.sweeps
-
Returns the number of completed waterfall sweeps (scans across the waterfall
screen) since the program was started. Can be used in conditional actions,
similar like the function 'water.count' . By comparing the value returned
by this function with the previous value, you can -for example- upload a
capture of the waterfall to a website whenever a new screen is finished.
Note: If the waterfall runs in
multi-strip mode, the value
of water.sweeps will be incremented whenever a new strip is finished.
Doing a capture precisely at that time would contain an empty strip, because
in the moment your application recognizes that 'water.sweeps' was incremented,
the display routine has already scrolled the waterfall screen by one strip.
To circumvent this, use the function 'water.line_nr' - see below.
-
water.line_nr
-
Returns the waterfall's current line number (within the current sweep or
strip). This number counts DOWN from the maximum to zero. When water.line_nr
reaches zero, a new sweep begins, and the line number wraps from zero to
water.line_max (see below). You can use this function to test if a sweep
of the waterfall is "almost" complete (in that case, water.line_nr will be
very low. If the waterfall scrolls slowly, you may be able to catch the time
when water.line_nr is exactly zero. Otherwise, don't expect to see every
step in water.line_nr ... in fact, if the waterfall scroll interval is less
than 50 ms, two or even more pixel lines are painted in a single over to
speed things up.
-
water.lines
-
Returns the number of lines in one complete sweep of the waterfall. Depending
on the orientation of the waterfall, this is the height (if the frequency
scale is horizontal) , or the width (if the frequency scale is vertical)
of the waterfall bitmap in pixels.
<there may be other interpreter commands to control the waterfall which
are not mentioned here>
back to the overwiev
For some 'special' applications, some parameters of the spectrum analysers
can be controlled "directly" through the interpreter, without affecting the
configuration data. There are at least the following
functions... some of them may be used as commands to assign new values to
these parameters, but most are "read-only" (so their value cannot be changed
by a formal assignment):
-
spa.ampl_max, spa.ampl_min
returns the displayed amplitude range in the spectrum graph (and the waterfall,
if visible).
-
spa.avrg_cnt
returns the current average counter of the "long-term average spectrum" (which
was implemented for the Earth-Venus-Earth
experiment, to dig extremely weak and uncoherent signals out of the noise).
-
spa.cursor.freq ,
spa.cursor[N].freq , .. .ampl, ..
.time
spa.cursor.freq returns the frequency of the 'readout cursor' in Hertz, including
the optional offset (VFO frequency or similar). cursor[0] is
the first cursor (shown as "red ball" in the spectrum graph, which usually
follows the mouse pointer there), cursor[1] is the second
cursor (the "green ball", which is usually fixed somewhere via mouse-click).
spa.cursor.ampl returns the amplitude or magnitude (depending on the display
settings); spa.cursor.time returns the time of acquisition (number of seconds
passed since the birthdate of UNIX, as a floating point number).
Details about the readout-cursor are
here.
-
spa.decimator
returns the current decimation ratio between "input" to the spectrum analyser,
and the FFT. This parameter is READ-ONLY. To change the decimation
ratio, use the configuration (dialog or control commands).
-
spa.inp_rate
returns the current input sample rate into the spectrum analyser. READ-ONLY
(to change this parameter, change the audio sample rate). But, in contrast
to the soundcard sampling rate, this value takes the optional decimation
ratio into account.
-
spa.lo_freq
returns the current L.O. (local oscillator)- frequency of the spectrum analyser.
Only has an effect if decimation and a complex FFT is used (like some other,
L.O.-related parameters too)
-
spa.sweep_rate
is the sweep rate for the local oscillator in "Hz per second" (or s^-2).
This value can be modified by a formal assignment, like:
spa.sweep_rate=-17m : REM set doppler shift rate to -17 mHz /
second
-
spa.sweep_offs
Momentary frequency offset for the local oscillator in Hz. This value is
*not* included in spa.lo_freq. In contrast to spa.lo_freq, which is usually
constant, this value changes permanently as soon as spa.sweep_rate is non-zero.
The momentary oscillator frequency may be calculated as spa.lo_freq +
spa.sweep_offs. To "reset" a sweep (for example, shortly before the moon
enters the NavSpaSur radar fence ;-) , use a command like this:
spa.sweep_offs=0 : REM reset doppler shift for new moon pass
If no index in square brackets after the keyword "spa" is given, the above
commands apply to the first channel of the first spectrum analyser. Otherwise,
use...
-
spa[0].xxx : 1st spectrum analyser, 1st input
-
spa[1].xxx : 1st spectrum analyser, 2nd input
-
spa[2].xxx : 2nd spectrum analyser (only has one input)
-
spa[3].xxx : time domain scope, 1st input
(ok, not really a "spectrum analyser"... )
-
spa[4].xxx : time domain scope, 2nd
input
Notes:
-
Try to avoid
spa[3] and spa[4]because they may
change in future versions.
-
To stop, start, or restart the L.O. sweep, especially when analysing audio
files in loop mode, the 'replay_started'-event in the
conditional action table may be helpful.
Alternatively use the
spa.sweep_offs function to reset the sweep
if the offset gets too large.
See also: spectrum.xxx,
fft.xxx, overview of
interpreter-commands and
-functions .
Procedures and Functions to control or export the latest calculated
spectrum (= "Result of the latest FFT calculation for the spectrum
analyser"). To control the spectrum analyser (which produces
these spectra), use the spa-commands/functions. Some
additional, FFT-related commands are described further below.
Implemented up to now:
-
spectrum.time
-
returns the time of the calculation of the lastest spectrum, using the UNIX
time format (number of seconds passed since 1970-01-01 00:00:00). The result
may be slightly different from "now". See
notes below.
-
spectrum.pause
-
reads or sets the "pause"-flag of the spectrum analyzer. You can use this
to pause/restart the analyzer on a programmable event, for example a button
to toggle the pause flag. pause=0 means "not paused", pause=1 means "paused".
Example for toggling the pause flag:
spectrum.pause = !spectrum.pause
-
spectrum.save(#<channel_nr>,
"filename.txt" )
-
saves the current spectrum ("FFT results") as a textfile. Includes a header
and -after the header- one line of text for every FFT bin.
Example:
spectrum.save(#1, "my_spectrum.txt")
saves the latest spectrum for the first channel of the first spectrum analyser
as a textfile.
Note: The file format is the same as for the spectrum
reference curve. But there may be some command-options in future to leave
some parts of the spectrum away to save disk space. In addition to this command,
SpecLab allows to export the FFTs for the main spectrum analyser periodically,
using the FFT export function described
here.
-
spectrum.print( [#<channel_nr>,]
[f=<frequency of interest>,] <string> )
-
Prints a label (or a small text message) into the spectrogram, which is scrolled
together with the lines of the waterfall. Can be used to mark special "points
of interest" in a waterfall, either manually or automated. If
<channel_nr> is not specified, the command prints into both
channels of the first spectrum analyzer, #1 prints into the first (left)
channel, #2 prints into the second (right) channel. If
f=<frequency_of_interest> is not specified, the label will appear
on the left (or lower) edge of the spectrogram, as close to "0 Hz" as
possible.
Examples:
sp.print("Meteor Nr "+str(MsBurst)):MsBurst:=MsBurst+1
The example could be used in one of the
programmable buttons, or
in the automated spectrum alert function.
sp.print(f=peak_f(500,2000),"* Peak
"+str("hh:mm:ss",sp.time))
This example prints a label into the spectrogram close to a certain frequency,
here: near the "peak" between 500 and 2000 Hz.
Notes:
-
The '
spectrum' token can be abbreviated as
sp to save space.
-
The
spectrum.print commands are temporarily stored in
a buffer, before SL can print them to the screen for technical reasons. The
size of this 'command stack' is limited (four entries or so). So wait a few
hundred milliseconds before printing into the spectrogram again, otherwise
some entries may get lost.
-
Use the function
sp.time, not the function
now, to retrieve the timestamp
of the current spectrogram line.
When analyzing files, sp.time may be very different from
now ! When running in real-time, the difference is usually small.
-
To retrieve the timestamp of the readout cursor in the spectrum analyser,
use the function spa.cursor.time instead .
See also: command verwiev,
fft.xxx, export
functions, spa.xxx (spectrum
analyser), channel numbers
for the spectrum analyser
Functions to control the export of FFTs as text files (one FFT per line in
the file), in addition to the options on the FFT export panel.
-
fft.export.xyz :
All commands and functions beginning with "fft.export", or (abbreviated)
"fft.expt", are explained here
(in an extra document).
To control the
exec (procedure)
Formats:
-
exec(<progname>)
-
exec(<options>,<waitflags>,<progname>, <argument1>,
<argument2>, ...)
This interpreter command is used to launch or run an other application. In
its simplest form, you just have to supply the name of the program which
shall be run. Example:
Usually, the interpreter will continue to operate while the operating system
is still initializing the other program. Most windows applications will never
terminate themselves, while many 'console' applications will be ready sooner
or later.
(future plans: The numeric parameters <options> and <waitflags>
can let the interpreter wait until the called program is ready.)
Many console applications (and DOS commands) need a list of arguments passed
in a command line. These arguments follow as <argument1>,
<argument2> after the name of the executable program. You may also
pass all arguments in a single string. Example:
-
exec("cw.exe alarm alarm")
will do quite the same as
exec("cw.exe", "alarm", "alarm")
Notes on exec:
-
Like other commands (print, fopen, etc), the exec function translates certain
backslash sequences ! Because of this,
single backslash characters (as often found in directory paths) must be
duplicated - see example below.
-
OS commands like "copy" and a few other internal functions of the DOS-style
command line interpreter do not work under Windows XP etc. To copy files,
you may use "xcopy", but beware of the stupid question if the target is a
file or a directory. If the target is a file, there is no annoying question
if the target file already exists, but you must specify the /y switch to
suppress the question of the target file may be overwritten. Example:
exec("xcopy last_min_"+str("mm",now-60)+".wav c:\audio.wav /y")
-
A quite ugly workaround to run the "internal" DOS commands under WinXP is
to invoke the to invoke command processor (Cmd.exe) and its internal commands.
So instead of writing something like
exec("copy c:\\test\\source.txt c:\\test\\copied.txt") < deliberately
wrong !
(which does not work under XP because CreateProcess does not recognize it),
enter the command
exec("cmd /C copy c:\\test\\source.txt
c:\\test\\copied.txt")
which did work when I tested it under Win XP. Don't ask me what the
/C switch is for; I found it somewhere on the web. It may mean "execute a
single command and terminate after that". Under Win 98, "command.com" does
a similar job like "Cmd" - but don't forget the extension.
-
Another workaround for the problem described above is to use batchfiles like
this one (call it "copyjob.bat", located in c:\test):
cd c:\test
copy source.txt copied.txt
To launch this batchfile, use:
exec("c:\\test\\copyjob.bat")
Beware, the current directory is not automatically changed, for this reason
use the "cd" (change directory) command in your batchfile if the batch is
not located in the Spectrum Lab directory.
About space characters in file- or directory names:
Avoid spaces in directory- and filenames wherever possible ! They only leads
to problems, because you need additional quotes to get the syntax for the
command line arguments right. Because someone (!) once decided to allow spaces
in filename, it gets terribly complicated now. If you don't use spaces in
any of your data directories, skip this paragraphs. If you do, the punishment
follows because you have to read on !
Because the double quote is used as delimiter for string literals (in many
programming languages), we must replace the double quote character with the
backslash sequence \" in into a double quote character. So here are the rules
for embedding spaces in filenames (pathnames) without breaking up a single
argument:
-
A backslash followed by a double-quote character in the sourcecode (\") will
be translated into a double-quote character (without the backslash) in the
argument list of the exec command.
-
A backslash followed by anything else than a double-quote character will
not be translated, but be copied 1:1 into the resulting string. (Note: This
is different than in the "C" programming language, where a backslash followed
by certain letters will be translated into special control characters. Not
here in SpecLab's exec()-command !).
-
A double-quote character which is NOT preceeded by a backslash is still used
as a delimiter of a string constant, like in most programming languages including
"C".
-
Unlike the "C" programming language, the backslash sequences
\n,
\r, \t are not translated into the control characters NL, CR,
and TAB when used in the argument list of the exec command. These
sequences will only be translated when it makes sense, for example in the
print command (more details in the chapter String Expressions,
"Backslash sequences" ).
Phew ! Time to present an example to make this a bit clearer. Lets assume
you have an executable file named "cw.exe" in the directory c:\test\ugly
space\, which you want to launch via SpecLab's exec command, and passing
the string "hello" to it in the command line. You may be tempted to write
something like..
exec("c:\\test\\ugly space\\cw.exe hello")
<<<< deliberately wrong
Thanks to Mr B.G. this is totally legal under windoze (it was not under pure
DOS). But after parsing the string expression, we'll find THREE arguments
(separated by space characters): c:\test\ugly,
separation, space\cw.exe, separation, and
hello . To concatenate the path+name of the executable
into a single parameter for the command line, double quotes must be used.
But double quotes are already used here as delimiters for the string constant
in Spectrum Lab's primitive interpreter language. We cannot simply add more
double-quote characters like this:
exec(""c:\\test\\ugly space\\cw.exe"
hello") <<<< also deliberately
wrong
because this doesn't make sense to the interpreter in Spectrum Lab. The
interpreter would see an empty string enclosed with double-quotes, and something
strange which is not a string constant after that. The correct way to achieve
what we want is:
exec("\"c:\\test\\ugly space\\cw.exe\" hello")
Note that the very first and the very last double-quote character in the
above example is the string limiter, which indicates a "string constant".
The string expression in this interpreter-command-line will be translated
to:
"c:\test\ugly space\cw.exe" hello
before passing it a windows API function named CreateProcess (all we need
to know here is CreateProcess can be used to launch a program from another
program, and that's what SpecLab's exec command is used for).
Note: Your browser may be irritated by all those backslashes and double-quotes
above. You will find a few examples for the exec-function in the file testcmd.txt
which was used for testing purposes when developing Spectrum Lab.
back to the overwiev
export (procedures and
functions)
A group of commands for exporting data as text files. Intended to be used
for monitoring applications, but can also be used elsewhere.
Note: The export file may contain whatever you like. It is very flexible
but not easy to understand how it works for occasional use. For many
applications, the settings "export control window"
has all you need.
Interpreter commands to control the user-defined text export
function (not for the FFT-export) are:
-
export.start
export.start("filename.txt")
export.start(#<file_nr>, "filename.txt")
Starts writing to an export file. May also be
used to change the NAME of the export file. If exporting to a file is already
active, the old file will be closed automatically. If the new file already
exists, data will be appended (an existing file will not be truncated, already
existing data will not be destroyed).
In combination with the scheduled action definitions, it is possible for
example to export into a "new" file every hour, or triggered by other events.
The filename can be a flexible string
expression.
The optional parameter #<file_nr> (#1 or #2) defines, which of the
two possible export files shall be started with a new name. If
#<file_nr> is not specified, the command applies only to the 1st export
file. Examples:
export.start
starts the 1st export file without changing the name
export.start(#2,"alan"+str("YYMMDD_hhmm",now)+".txt")
(re)starts the 2nd export file with a new name which
includes the current date and time.
-
export.stop
Stops writing to an export file. An existing export file will be closed (so
it can be analyzed by an other program after this). Without parameters, both
export files are stopped and closed (#1 and #2).
export.stop(#1) stops only the first export file,
export.stop(#2) stops only the second export file.
-
export.print( <text-line> )
Appends a "special" line of text to the export file if opened. This is only
required if strangely formatted output shall be written. You don't need this
to write a "normal" export file.
Note that the <text-line> in the argument can also be a flexible string
expression like in the standard print-command.
The following export- functions return numeric or string values:
-
export.value[<column index>]
returns the last value which has been calculated by the export function (to
be precise, by an expression in the export
file definition table). The column index runs from 1 to the number of
columns defined in the export definition dialog.
Example 1: export.value[2] returns the latest value which has been calculated
during the evaluation of the expression for the second column of the export
file... phew !
For very special applications, you can use this to modify the value as a
command:
Syntax: export.value[<column_index>] = <new_value>
Example: export.value[2]=0 clears the value. Only
makes sense, if export.value is evaluated in the expression
for export column 2 itself.
Another example can be found in the application
"Measuring the signal strength of low-duty-cycle
beacons". The export.value function can also be used to plot the exported
values by SpecLab itself, in "almost real-time", using the
watch list / plot window.
-
export.title[<column index>]
returns or sets the title of a column in the exported file.
-
export.format[<column index>]
returns or sets the format string for a column in the exported file.
-
export.expression[<column index>]
returns or sets the expression ("formula") which defines the contents in
a column in the exported file. Usually, you define the contents for the export
file in the export control dialog.
See also: saving a single spectrum in a
textfile, command overwiev ,
function overview, string
expressions .
Many components of the configuration data can be accessed from the interpreter.
From a programmer's point of view, all configuration data are organized in
a large structure (here: "cfg"), some of its components can be read and modified.
Examples:
-
print( cfg.Wat1ClContrast )
-
shows the current "color contrast" setting for the first waterfall display
-
cfg.Wat1ClContrast = 127
-
sets the "color contrast" setting for the first waterfall display. Note:
This is a formal assignment.
An overview of all accessable components of the configuration can be found
here ("subject to change").
When Spectrum Lab controls the PTT function of a transmitter (usually from
the "digimode terminal"), there is no need to use the following interpreter
commands. But in some cases, someone else (a human operator, or another program)
controls the transmitter and SpecLab shall behave differently depending on
the current transmitter status. The following functions can be used to sense
the current transmitter status. They will often be used for event definitions
in the conditional action table.
The following functions poll inputs on the serial port :
-
ptt_port.cts
Senses the current state of the CTS line. This is one of the inputs(!) of
the COM port configured for "PTT Control" (!) in SpecLab's
system configuration .
0 Volts (or negative voltages) on the CTS line will be signalled as ptt_port.cts
= 0 (zero); high levels (+ 3 V or more) are returned as 1 (one). Note
that these are not the "logic" states of the RS232 standard, because RS232
defines the signals as Active LOW (no problem since we don't use this port
in a standard manner anyway..).
On a 9-pin serial port connector, CTS is on pin 8, and ground on pin 5.
-
ptt_port.dsr
Similar as "ptt_port.cts" (see above), but this function returns the current
state of the DSR line.
On a 9-pin serial port connector, DSR is on pin 7.
-
ptt_port.dcd
Similar as above... this function returns the current state of the DCD line
(Data Carrier Detect, geeks call it "RLSD" = receive-line-signal-detect ).
On a 9-pin serial port connector, DCD is on pin 1. Caution, some cheap
USB<->RS-232 adapters don't support this signal (or their drivers are
faulty).
-
ptt_port.ri
Similar as above... this function returns the current state of the RI line
(RI=Ring Indicator).
On a 9-pin serial port connector, RI is on pin 9.
With the interpreter, you can also switch some of the output signals on the
serial port. Be careful not to interfere with the signals controlled
automatically from the digimode terminal. The following commands
can be used to set output signals on the serial port. If <new_state>
is zero (= "FALSE"), an output will be cleared (negative voltage on the serial
port); if <new_value> is non-zero (="TRUE"), the output will be set
(typically +10 to 12 V on the serial port).
-
ptt_port.rts = <new_state>
Sets the RTS output (Request To Send, often used as the PTT line). On a 9-pin
serial port connector, RTS is on pin 7.
-
ptt_port.dtr = <new_state>
Sets the DTR output (Data Terminal Ready, pin 4 on a 9-pin serial port
connector).
-
ptt_port.txd = <new_state>
Sets the TxD output (Transmit Data) to a permanent negative or positive level,
as long as no data are sent through the serial port. In fact, this is the
"Break"-flag in the modem control register. On a 9-pin serial port connector,
TxD is on pin 3.
The functions ptt_port.rts, ptt_port.dtr, and ptt_port.txd can also
be used to retrieve the last state written to the port. For example, the
following command line toggles the state of the RTS output ( "!" = negation
) :
ptt_port.rts = ! ptt_port.rts // toggle RTS
See also: command overwiev ,
function overview ,
numeric expressions ,
configuration of the PTT control
port .
For some special application (shortwave propagation studies), it was necessary
to control an HF receiver through the serial port. First, Icom's CI-V protocol
was implemented (by the time you read this, other manufacturer's protocols
may be supported too).
Please note that before using these interpreter functions and -commands,
the serial port must be configured to match the settings of your receiver
(like baudrate, serial data format, "address" of the radio, etc). This can
be done in Spectrum Lab's main menu, select "Options".."System
Settings".."Tx/Rx Interface settings".
The prefix "rct" means "remote control". The following functions / commands
are implemented (possibly more) :
-
rct.freq
Retrieve or change the frequency which the radio is tuned to. Use a formal
assignment to set a new frequency like in the examples below.
rct.freq = 144.300MHz : REM tune to 2m SSB calling frequency
Note that the "MHz" must not not be separated from the number, because
it's an alternative form of the scientific notation "144.300E6" (the 'M'
is 10 power 6, 'k' is 10 power 3, and so on).
Hint: ICOM radios autonomously report the new frequency through the serial
port when the VFO knob is turned. Spectrum Lab receives and parses such messages.
So the frequency can be displayed without much overhead on one of the
programmable buttons of the main window, using the following interpreter
code ("string expression" for the button text):
str("###0.000 kHz",1e-3*rct.freq)
A simple example for this can be found in the settings file "CI_V_tst.usr",
and a more sophisticated example in the Conditional Action file
"ncdxf_4u1un_tracker.txt" (which periodically switches the frequency of a
receiver, like shortwave beacons operated by the Northern California DX
Foundation).
The command window can be used to enter and execute any interpreter command.
Enter a few lines with interpreter commands in the upper part of the window.
To execute a single command line, press the F2 key. The command in that line
wil be executed, and after that the cursor jumps into the next line to be
executed (kind of "single-step" operation).
Alternatively, press F9 to run the whole "batch" of commands.
The lower part of the window shows the output from the
print command. Can be used for testing purposes,
as a simple calculator, or as a logging display (if you use the print command
in event-driven subroutines like periodic actions,
scheduled actions, etc.
See also: command overwiev ,
function overview .
See also: Spectrum Lab's main index .
Last changes (YYYY-MM-DD):
2005-10-26: Documented the new "spa"-functions (spectrum analyser control
functions)
2006-09-16: Added a few new commands, and the option to run multiple commands
like a "batch" (in the command window)