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

# Macro Data Unit Conversions

Macro: Range?0-3, Range?V

## Introduction:

Certain macro functions and operations use "raw" 16-bit sound card data (ADC or DAC "counts"), where +/-32767 represents a full-scale waveform.

These functions include data point functions Wv(), Sp(), and Av(). Macro array copy operations W, S, and A also read these raw-scaled values. (But see Buf0-Buf7 Spectrum Data Unit Conversions, below.)

In addition, the same underlying scaling is used for summation (sigma) functions wSig() and sSig().

To convert these values to volts or User Units, some math is needed. Note that each of the above functions or operations uses an explicit channel number:

```    0 = Left In
1 = Right In
2 = Left Out
3 = Right Out
```

Each channel may have a different full-scale range, input sensitivity or output volume (attenuation), external gain. You can obtain the current values of these for any channel from specific read-only variables, discussed below, as well as a single variable that combines all of these to get the overall range or gain that you must use to scale the raw data.

## Output Waveform Unit Conversions:

Let's begin by considering output channels 2 and 3. (See Input Waveform and Spectrum Unit Conversions, below, for input channels 0 and 1.)

Suppose you want to find the instantaneous output voltage of the waveform point under the solid trace cursor for the Left Out channel. Normally, you can read this directly via the CursY read-only macro, but this example shows the underlying math for more general applications.

The index (0-1023) of the solid cursor is given by CursN, so you can use Wv(2,CursN to obtain the raw-scaled (+/-32767) value of that point for the channel 2 (Left Out) waveform. That value can then be converted to an actual voltage.

You can obtain the full-scale range for channel 2 via RangeDlg?2, which gives the number of volts that are equivalent to a full-scale count of 32767. Note that for this to return a meaningful value, you must have previously performed a one-time auto-calibration followed by a full-scale output voltage calibration.

Alternatively, in place of the '2' channel number in RangeDlg?2 (and similar functions to be discussed below), you can first set the channel number via Ch=2 and then use RangeDlg?V.

Then, assuming no attenuation or external gain, you could convert the raw waveform point to volts V via:

V=Wv(2,CursN) * RangeDlg?2 / 32767

Thus, if the value of Wv(2,CursN) was 23170 and the full-scale range was 1.000 volts, then V would be equal to 23170 * 1.000 / 32767 = 0.707 volts.

Continuing to assume no attenuation (volume sliders fully up), suppose that the sound card output is connected to an external amplifier with a voltage gain of x20 (typical for a 50-watt/channel home stereo unit with its volume control at maximum). In the External Gain dialog you would set the Left Wave Out channel to 20.000, which can be read via GainDlg?2. Now the final output voltage from the amplifier at this single waveform point would be 20 times larger than the above 0.707 volts (20 * 0.707 = 14.142), given by:

V=Wv(2,CursN) * RangeDlg?2 * GainDlg?2 / 32767

Now suppose you reduce the level via the sound card output volume control, while leaving the external amplifier volume all the way up. You can find out the amount of attenuation on channel 2 via Atten_G?2, which returns a fractional "gain" of 1 or less. For example, if the attenuation is -6.02 dB then the return will be 0.05000. (You can obtain the value in dB via Atten_dB?2.)

So the attenuated voltage from the power amplifier at the CursN point of the channel 2 waveform is:

V=Wv(2,CursN) * RangeDlg?2 * GainDlg?2 * Atten_G?2 / 32767

Alternatively, you can use Range?2 that combines RangeDlg?2, GainDlg?2, and Atten_G?2 to get the overall range:

V=Wv(2,CursN) * Range?2 / 32767

Or, if you have previously set the channel (via Ch=2 here), you can use V=Wv(Ch,CursN) * Range?V / 32767. This allows the same code to work with either output.

The above would allow you to determine the actual voltage of the designated sample at the output of the external power amplifier. But you may be using this voltage to drive a transducer that produces some other quantity, such as sound pressure, force, or light output. In that case you would set User Units per volt, which can be read for channel 2 via UserFactor?2.

However, note that when UserFactor is obtained via this read-only format, is is always given in dB relative to 1 volt, not as a linear factor. Recall that dB can be converted to a ratio by:

Ratio = 10^(dB / 20)

You can then convert volts (V) to user units (U) via:

U=V * 10^(UserFactor?2 / 20)

## Output Spectrum Unit Conversions:

The above assumes that the transducer produces the same user units per volt at all frequencies being tested... in other words, a "flat frequency response". For most kinds of transducers, that will only be true over a limited frequency range. If you need to operate over a wider range you can provide Daqarta with a calibration (.CAL or .FRD) file for the transducer, which gives its actual frequency response. This allows Daqarta to correct the Spectrum display to show the true output.

Such frequency response correction is not applied to waveform displays, so here we'll discuss how to handle spectrum measurements. Instead of Wv(2,CursN used in the above example to get a raw waveform value, we will assume Sp(2,CursN) to get the raw magnitude value of the point under the trace cursor in the channel 2 (Left Out) spectrum. The range, external gain, and attenuation are dealt with just as shown above for waveform data:

V=Sp(2,CursN) * RangeDlg?2 * GainDlg?2 * Atten_G?2 / 32767

Or more simply:

V=Sp(2,CursN) * Range?2 / 32767

If you have previously set the channel (via Ch=2 here), you can use V=Sp(Ch,CursN) * Range?V / 32767. This allows the same code to work with either output.

A calibration file is a list of frequency and dB pairs, where each given dB value is the deviation from a stated common reference level at the given frequency. A transducer with a flat response would have the same dB value (usually zero) at each frequency.

Daqarta interpolates the raw file data to produce a working table of dB values for the specific frequencies at each point (spectral line) in the spectrum. (You can determine the frequency F at any spectrum point N via F=N * SmplRate / 1024.) It also normalizes the data by subtracting the most-positive dB value from each file entry, so that peak is stored as 0, and all other values are thus negative. The original peak value for channel 2 is available as UserSPL?2.

The reference level that all these dB values are relative to (the Sens: dB from the raw CAL file) is available as UserFactor?2.

The working table for channel 2 can be copied to a macro array buffer like Buf0 via Buf0="<=C2". Since in our example we are interested in the point (spectral line) at the solid cursor, we can obtain it via Buf0[CursN].

The overall dB at the CursN point is then obtained by adding UserSPL and UserFactor to this value. You can then convert volts (V) to user units (U) via:

U=V * 10^((UserSPL?2 + UserFactor?2 + Buf0[CursN]) / 20)

## Input Waveform and Spectrum Unit Conversions:

Unit conversions for input data (channels 0 and 1) differ from those for output data (channels 2 and 3) in the direction of scaling.

Here we'll begin by assuming you want to find the instantaneous input voltage of the waveform point under the solid trace cursor for the Left In channel (0).

As for the output channel 2 in the previous examples, the index (0-1023) of the solid cursor is given by CursN, so you can use Wv(0,CursN to obtain the raw-scaled (+/-32767) value of that point for the channel 0 (Left In) waveform. That value can then be converted to an actual voltage.

The full-scale range still gives the number of volts that are equivalent to a full-scale count of 32767, obtained via RangeDlg?0 for channel 0 (Left In), and RangeDlg?1 for channel 1 (Right In).

Likewise, you still must have previously performed a one-time auto-calibration followed by a full-scale input voltage calibration.

So, assuming no attenuation or external gain, you could convert a raw input waveform point to volts V via:

V=Wv(0,CursN) * RangeDlg?0 / 32767

The difference arises when we consider the effect of external gain. For outputs, when we apply external gain we are making the ultimate output voltage larger by the amount of the external gain.

But when we apply external gain to an input, that means that the voltage actually seen by the sound card is larger than the original external voltage that we want to measure. For example, if the card sees 1.00 V after the signal has passed through a gain of x10, then the original voltage must have been 0.100 V.

We thus need to scale the sound-card-measured voltage down by the amount of the external gain to obtain the true pre-gain voltage, which means dividing by GainDlg instead of multiplying:

V=Wv(0,CursN) * RangeDlg?0 / (GainDlg?0 * 32767)

Conversely, if we reduce the sensitivity of the sound card input via the Input range control, it means the original input voltage must have been larger. Again, we need to divide by Atten_G instead of multiplying:

V=Wv(0,CursN) * RangeDlg?0 / (GainDlg?0 * Atten_G?0 * 32767)

Or simply:

V=Wv(0,CursN) * Range?0 / 32767

If you have previously set the channel (via Ch=0 here), you can use V=Wv(Ch,CursN) * Range?V / 32767. This allows the same code to work with either input.

Conversion from volts to User Units works the same for input as for output when you have directly entered a consant User Units per volt, which can be read for channel 0 via UserFactor?0 to get the value in dB relative to unity:

U=V * 10^(UserFactor?0 / 20)

However, when you use a calibration (.CAL or .FRD) file you effectively apply a different factor at each frequency. A peak in the response of an input channel means that it is more sensitive at that frequency, which means that it takes less of the user units (Pascals of sound pressure, for example) to get a volt from the input source (such as a microphone).

In this sense a response peak is like an increased external gain, which means we will need to reduce the reported user units at that frequency.

As for an output channel, we first get the magnitude at the cursor position via Sp(0,CursN). We then find the uncorrected voltage V as for a waveform input, dividing (instead of multiplying) by the gain and attenuation:

V=Sp(0,CursN) * RangeDlg?0 / (GainDlg?0 * Atten_G?0 * 32767)

Or simply:

V=Sp(0,CursN) * Range?0 / 32767

If you have previously set the channel (via Ch=0 here), you can use V=Sp(Ch,CursN) * Range?V / 32767. This allows the same code to work with either input.

Likewise, we copy the working response table for channel 0 to a macro array buffer like Buf0 via Buf0="<=C2", and find the response at the cursor (in dB relative to the peak dB in the file) via Buf0[CursN]. But instead of adding this to the UserSPL and UserFactor dB values, we subtract it. The complete expression for user units U is then:

U=V * 10^((UserSPL?0 + UserFactor?0 - Buf0[CursN]) / 20)

## Buf0-Buf7 Spectrum Data Unit Conversions:

When Daqarta performs an FFT on 16-bit waveform data (which normally has a +/-32767 range), it first multiplies by 65536 to promote it to a 32-bit range. This insures maximum resolution from the 32-bit FFT algorithm.

The FFT algorithm returns values that are half as large, to allow for the fact that a spectral peak may have an amplitude that is larger than the input amplitude. (For example, the fundamental of a square wave is 1.27 times the peak amplitude of the square wave itself... see Making Waves via Sine Wave Synthesis.)

If you use Buf0-Buf7 spectrum operations you must allow for this additional scaling, by dividing by 32768 or equivalently by shifting down by 15 bits.

For example, instead of using Sp(2,CursN) to return the spectrum magnitude at the solid cursor position, you could use Buf0="<mS2" to fill Buf0 elements 0-511 with the magnitude values for the whole spectrum. Then to read only the CursN element you could use:

A=Buf0[CursN] >> 15

This will give exactly the same value as A=Sp(2,CursN). 