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:



Spectrum Analyzer

Signal Generator

(Absolutely FREE!)


Pitch Tracker


DaqMusiq Generator
(Free Music... Forever!)

Engine Simulator

LCR Meter

Remote Operation

DC Measurements

True RMS Voltmeter

Sound Level Meter

Frequency Counter
    Spectral Event

    MHz Frequencies

Data Logger

Waveform Averager


Post-Stimulus Time
Histogram (PSTH)

THD Meter

IMD Meter

Precision Phase Meter

Pulse Meter

Macro System

Multi-Trace Arrays

Trigger Controls


Spectral Peak Track

Spectrum Limit Testing

Direct-to-Disk Recording



Frequency response

Distortion measurement

Speech and music

Microphone calibration

Loudspeaker test

Auditory phenomena

Musical instrument tuning

Animal sound

Evoked potentials

Rotating machinery


Product test

Contact us about
your application!

Sound Card IMD Meter Mini-App


Note: Before using this automated IMD meter, you may want to review the fundamentals of distortion measurement.

IMD_Meter is a macro mini-app included with Daqarta that provides a resizeable meter showing Intermodulation Distortion. It generates various two-tone test signals and analyzes the distortion of amplifiers, speakers, microphones, or other systems.

You can run IMD_Meter by hitting the F8 key followed by the 'I' key, or hitting CTRL+F8 to open the Macro Dialog and double-clicking on IMD_Meter in the Macro List.

IMD_Meter uses a Custom Controls dialog that allows adjustment of various parameters. You can open this Help topic by right-clicking anywhere in the dialog, or on the separate meter itself.

The IMD_Meter macro sets Spectrum display mode and loads the IMDmeter.GEN Generator setup. It also opens the Custom Controls dialog, with an edit/slider control to set the F1 Frequency, a read-only control that shows the F2 Frequency, another read-only display of the F1/F2 Level Ratio, an adjustable time constant for the meter, a mode button that toggles between SMPTE, DIN, or CCIF / ITU-R modes, an Arbitrary / Spectral Line Lock frequency mode button, a channel select button, a Raw / Spectrum Average / Wave Average button, a time constant reset button, and a Percent / dB meter toggle button.

IMD_Meter was used for all measurements in the Intermodulation Distortion section of Sound Card Performance Tests.

Initial Set-Up:

The meter itself is a separate Custom Meter that shows both IMD and the selected channel it applies to. If that channel is not active, the meter shows "No Signal" plus the channel.

Note that IMD_Meter does not automatically toggle Input on (nor set Input Channels, Lines, or Levels), so the default Left In channel may show "No Signal" unless you do that manually.

It is important that you adjust output and input signal levels for best results. If the input signal is too high, it can overload the input and cause distortion. As the input approaches clipping, you will see a forest of spectrum peaks rise up. Reduce the level until you are satisfied that the system is not near clipping. (This is usually visible in the Spectrum display before it becomes audible, or visible in the waveform display.)

Note that clipping can be caused by excessive levels at the sound card input even when the amp (or other device under test) is not itself clipping. Some sound card outputs may have clipping or other increased distortion when run at maximum levels. And of course the device under test may distort when driven at high levels.

The meter continues to run after closing the control dialog, until it is closed separately.

When you close the IMD Meter Controls and IMD Meter windows, the IMDmeter.GEN Generator setup remains loaded and active. The setup includes current output volume settings, so if you have changed them and want to use those settings again in the future, save the setup. (Current input settings are always saved automatically when Daqarta is closed, and restored on the next restart.)

Note that IMD distortion measurements themselves do not require any system calibration, since they are always measured as a percentage of the primary amplitudes.

IMD Modes:

In SMPTE mode the Generator produces tones at 60 Hz (f1) and 7000 Hz (f2) in a 4:1 ratio. If there is intermodulation between these two tones, there will be distortion products at sum and difference frequencies such as f2+f1, f2-f1, f2+2*f1, f2-2*f1, etc. (See Distortion Orders for more details.)

These products will thus appear above and below the 7000 Hz tone at 60 Hz intervals: 7000+/-60, 7000+/-120, etc. IMD is determined by measuring the total energy in two bands, each approximately 1200 Hz wide on either side of the 7000 Hz tone, in order to capture the first 20 positive and negative products. This total distortion energy is then divided by the energy in the 7000 Hz tone itself.

DIN mode operates identically to SMPTE, except that the two tones are 250 and 8000 Hz.

CCIF / ITU-R mode uses two equal-amplitude primary tones at 19000 Hz (f1) and 20000 Hz (f2). It reports two types of IMD values. The first (f2-f1) divides the distortion product at 1000 Hz by the total energy in the two primaries.

The second IMD value (4 term) finds the energy of the first 2 products below f1 at 2*f1-f2 and 3*f1-2*f2 (18000 and 17000 Hz) plus the first 2 above f2 at 2*f2-f1 and 3*f2-2*f1 (21000 and 22000 Hz), and likewise divides by the total energy in the two primaries.

Spectral Line Lock:

The above mode descriptions use the frequencies specified in their respective standards. These frequencies don't happen to have an integer number of cycles in the 1024 samples used to compute the spectrum, so they don't fall exactly on spectral lines. That means they cause spectral leakage that produces "skirts" on the peaks, which adds to the apparent energy at distortion product frequencies. Although IMD_Meter uses a Blackman-Harris window function to greatly reduce this problem, the remaining leakage still limits the lowest IMD that can be resolved.

It is possible to eliminate the leakage entirely by choosing test frequencies that fall exactly on spectral lines, greatly improving the IMD resolution. To do this, toggle the frequency mode button from Arbitrary Frequency to Spectral Line Lock.

To see how significant this can be, toggle the channel control button from Left In, through Right In, to Left Out. This causes the meter to look at the original signal, as generated, without passing through the output D/A and the input A/D. No loopback cable is needed for this. This gives "best case" results, assuming perfect D/A and A/D and device under test. The table below shows IMD readings for the standard and line-locked modes. (For CCIF, only the 4-term result is shown. The f2-f1 result is near zero in both modes.)

    SMPTE - Standard       60.000, 7000.000     0.1310%
    SMPTE - Line Lock      93.750, 6984.375     0.0019

    DIN - Standard        250.000, 8000.000     0.1236
    DIN - Line Lock       234.375, 8015.625     0.0017

    CCIF - Standard     19000.000, 20000.000    0.0462
    CCIF - Line Lock    18984.375, 20015.625    0.0003

As you can see, a tiny change in the frequencies makes a huge difference in the measurement resolution. You should always use Line Lock mode when you want the most reliable IMD measurements. There is nothing special about the standard frequencies, except that they are the standards. If you have to use them to conform to a test specification, you should at least take Line Lock measurements as well for comparison. If both give similar results, the measured system has enough IMD that Line Lock doesn't matter and you can feel confident reporting the standard values.

Note that when you toggle to Line Lock the f1 and f1 frequencies change to the nearest spectral line, but when you toggle back to Arbitrary they don't automatically change back to the default standard values. You need to toggle the SMPTE / DIN / CCIF button back to the same mode to reset the standard values.

Besides the standard and closest Line Lock values, you are also free to set other f1 values in any mode. In SMPTE and DIN modes the f2 value doesn't change when you change f1, but in CCIF mode the f2 value will track at 1000 Hz above f1 (or 1031.25 Hz above with Line Lock).

Meter Time Constant:

For noisy signals, the Time Constant Exponent controls simple smoothing of jittery meter values. The control value ranges from 0 to 10 and is applied as a power of 2 to determine the actual time constant, which then ranges from 1 (no smoothing) to 1024 (about 10 seconds). The default exponent is 5, which yields a time constant of 32.

The smoothed value is reset with the current instantaneous value whenever you change any control that could affect the reading, such as the IMD mode or test frequencies.

You can use the TC Reset button to reset the smoothed value manually. You might want to do this when using a high time constant, if something changes in the system under test and you don't want to wait for the meter to settle. Note, however, that a reset just starts smoothing from the current value, which may happen to be high due to jitter.

Spectrum and Waveform Averaging:

You can toggle the Raw button to Spectrum Average to accomplish smoothing of the entire raw spectrum before the IMD measurement. This is an Exponential average with a 32-frame time constant, which is comparable to the default using the above-mentioned Time Constant Exponent control, but with improved results.

Spectral averaging smooths the noise floor to its average value without reducing it. But clicking the Spectrum Average button will advance to Wave Average, which actually reduces the noise floor for higher resolution of ultra-low IMD values.

Waveform averaging requires synchrony to identical waveforms, which happen infrequently when the frequencies are not harmonically related. You can't use a simple waveform trigger since the waveform is always changing. Instead, a special trigger signal is created by the Generator at the lowest common period.

Consider the SPMTE test using 60 Hz and 7000 Hz. Note that in an interval of 1 second we'd (obviously) have exactly 60 cycles of the 60 Hz waveform, and 7000 cycles of the 7000 Hz waveform. We want the biggest integer that divides exactly into 60 and 7000; we can clearly can divide both by 10 to get 6 and 700, and then divide by 2 to get 3 and 350. So the divisor will be 10 * 2 = 20, such that in 1/20 second we get 3 cycles of 60 Hz and 350 of 7000.

So Daqarta needs to sync to a 20 Hz signal for waveform averaging of a SMPTE test. To do that, Stream 2 of the Left Output channel is set to 20 Hz, but its Level is set to 0 so there is no actual output generated at that frequency. The Generator can nevertheless sync to this "signal" by using the Trigger Mode set to Gen Sync.

For DIN mode, the above special Stream 2 signal is not required, since f2 (8000 Hz) is the 32nd harmonic of f1 (125 Hz), so setting Gen Sync to f1 is all that is needed.

In CCIF / ITU-R mode f1 and f2 are 1000 Hz apart, so the Stream 2 frequency is set to 1000.

Regardless of the IMD mode, when Spectral Line Lock is active f1 and f2 fall exactly on spectral lines. Since all spectral lines are multiples of the sample rate divided by the number of samples used, the Stream 2 frequency is set to 48000 / 1024 = 46.875 Hz for perfect synchrony in any mode.

IMD_Meter Macro Listing:

The overall IMD_Meter actually consists of the initial IMD_Meter macro which launches both the Custom Controls dialog handler _IMD_Ctrls, and also the Custom Meter handler _IMD_Task.

Close=                     ;Close any open data file
A.LoadGEN="IMDmeter"       ;Load Gen setup
Ctrls="<<IMD Meter Controls"   ;Custom Controls title
Ctrl0="<<F1 Frequency"     ;Ctrl0 label
Ctrl1="<<F2  Frequency"
Ctrl2="<<F1/F2  Level Ratio"
Ctrl3="<<Time Constant Exponent"
Btn0="SMPTE"               ;Default Btn0 label
Btn1="Arbitrary Frequency"
Ch=0                       ;Left In default chan
Btn2=""+Ch(c)                  ;Label Btn2 w. chan
Btn3="Raw"                     ;Non-avg
Btn4="TC Reset"
UT=TrigMode                    ;Save trigger mode for exit
TrigMode=GenSync               ;Trigger on Gen Sync
Ctrl0="<S(40,20000)"           ;F1 freq range
Ctrl1="<R"                     ;F2 display is Read-Only
Ctrl2="<R"                     ;Ratio is Read-Only
Ctrl3="<S(0,10)"               ;TC Exponent range
Ctrl3="<p(0)"                  ;Integer display
Ctrl0=60                       ;SMPTE default F1
Ctrl1=7000                     ;SMPTE default F2
Ctrl2=4                        ;SMPTE default ratio
Ctrl3=5                        ;Time Constant Exp. default
QT=32                          ;TC default (2^Ctrl3)
UK=1                           ;Reset TC on next update
Btn0="<M(2)"                   ;Momentary, 0-2 posns
Btn1="<T"                      ;Toggle
Btn2="<M"                      ;Momentary
Btn0=0                         ;SMPTE default
Btn1=1                         ;Arb (non-Line) freq default
Btn2=0                         ;Line In default
Btn3=0                         ;Raw (non-avg) default
Btn5=0                         ;Percent default
Mtr0="<<IMD Meter - SMPTE"     ;Meter title
Mtr0="<C(0)"                   ;Black meter text
Mtr0="<B(hFFFFFF)"             ;White meter background
Mtr0="<H4901"                  ;Right-click opens this Help
Task="_IMD_Task"           ;Install task that does the work
@_IMD_Ctrls=Ctrls          ;Open Custom Controls dialog
;Mtr0=                  ;Uncomment for Mtr0 close
;Task="-_IMD_Task"      ; on Ctrls close

_IMD_Ctrls Macro Listing:

IF.Ctrls=0                     ;F1 Frequency change
    IF.Btn1=0                          ;Spectral Line Lock?
        IF.Ctrl0?u=!0              ;Inc/Decrement?
            L.0.ToneFreq=>Ctrl0?u      ;Add/sub Line step so
            L.0.ToneFreq=Ctrl0             ;Else line-limited direct
        L.0.ToneFreq=Ctrl0             ;Arb freq = direct set
    Ctrl0=L.0.ToneFreq                 ;Show (limited) Ctrl0 value
    IF.Btn0=2                          ;CCIF mode?
        L.1.ToneFreq=L.0.ToneFreq + 1000   ;F2 = F1 + 1000 if so
        Ctrl1=L.1.ToneFreq                 ;Show Ctrl1 value
    IF.U3=1                            ;Spectrum avg active?
        Avg=1                              ;Restart on change if so
    IF.U3=2                            ;Waveform avg active?
        IF.Btn0=2                          ;If so, is it CCIF mode?
            Avg=1                              ;Restart avg if so
            U3=0                           ;Else quit avg
    UK=10                              ;Reset TC on 10th update

IF.Ctrls=3                         ;Ctrl3 = Time Constant Exp.
    Q3=Ctrl3                           ;Integer Ctrl3
    Ctrl3=Q3                           ;Force Ctrl3 to integer
    QT=2^Q3                            ;Actual TC = 2^Ctrl3

IF.Ctrls=4                         ;Btn0 = IMD mode
        Mtr0=                      ;Resize Mtr0 after larger CCIF
        Mtr0="<<IMD Meter - SMPTE"
        L.1.ToneFreq=7000          ;F2
        IF.Btn1=1                  ;Arbitrary freq mode?
            L.0.ToneFreq=60            ;F1
            L.2.ToneFreq=20            ;Sync for wave avg
        ELSE.                      ;Else Spectral Line Lock
            L.0.ToneFreq=93.75                 ;Closest line
            L.2.ToneFreq=SmplRate?X / 1024     ;Sync to line
        L.2.ToneSync=1             ;Trigger sync to L.2.
        Mtr0="<<IMD Meter - DIN"
        L.0.ToneFreq=250           ;F1
        L.1.ToneFreq=8000          ;F2
        IF.Btn1=1                  ;Arb freq mode?
            L.0.ToneSync=1             ;Sync to F1 if so
        ELSE.                      ;Else sync to spectral line
            L.2.ToneFreq=SmplRate?X / 1024
        Btn0="CCIF / ITU-R"
        Mtr0="<<IMD Meter - CCIF / ITU-R"
        L.0.ToneFreq=19000         ;F1
        L.1.ToneFreq=20000         ;F2
        IF.Btn1=1                  ;Arb freq mode?
            L.2.ToneFreq=L.1.ToneFreq - L.0.ToneFreq   ;Sync = diff
            L.2.ToneFreq=SmplRate?X / 1024
    Ctrl0=L.0.ToneFreq             ;Update F1 control
    Ctrl1=L.1.ToneFreq             ;Update F2 display
    Ctrl2=L.0.Level / L.1.Level    ;Update ratio display
    IF.U3=!0                       ;Either avg mode active?
        Avg=1                          ;Restart if so
    UK=10                              ;Reset TC on 10th update

IF.Ctrls=5                         ;Btn1 = Arb/Locked freq mode
        Btn1="Arbitrary Frequency"
        Fstep=Dir                  ;Allow any freq entry
        Btn1="Spectral Line Lock"
        Fstep=Line                     ;Allow only Line freqs
        IF.Ctrl0=<93.75                        ;F1 too low?
            Ctrl0=93.75                            ;Min Line
        L.0.ToneFreq=Ctrl0                 ;Set F1 from Ctrl0
        Ctrl0=L.0.ToneFreq                 ;Set Ctrl0 from (limited) F1
        L.2.ToneFreq=SmplRate?X / 1024     ;Sync to line
    SpectWindOn=Btn1                       ;Use Window unless Line
    IF.U3=!0                       ;Either avg mode active?
        Avg=1                          ;Restart if so
    UK=10                              ;Reset TC on 10th update

IF.Ctrls=6                         ;Btn2 = Channel
    Ch=(Ch+1) & 3                  ;Next chan, 0-3 only
    Btn2="" + Ch(c)                    ;Show chan
    UK=1                               ;Reset TC on next update

IF.Ctrls=7                         ;Btn3 = Raw / Avg modes
    Trig=1                             ;Trigger for Avg
    U3=U3+1                            ;Next mode
    IF.U3=>2                           ;Limit to 0-2
    IF.U3=2                            ;Wave avg? (sync to std F1 only)
        IF.Btn1=1                          ;If so, Line Lock?
            IF.Btn0=0                          ;If so, SMPTE mode?
                IF.Ctrl0=!60                       ;Std freq?
                    U3=0                               ;No avg if not
            IF.Btn0=1                          ;DIN mode?
                IF.Ctrl0=!250                      ;Std freq?
                    U3=0                               ;No avg if not
    IF.U3=0                            ;Raw = no avg?
    IF.U3=1                            ;Spectrum average?
        Btn3="Spectrum Average"
        Avg=1                          ;Start the average
    IF.U3=2                            ;Wave average?
        Btn3="Wave Average"
        Avg=0                              ;(Spect) avg off
        Spect=0                            ;Spect display off
        Avg=1                              ;Start Wave avg
        Spect=1                            ;Display in Spect mode
    UK=10                              ;Reset TC on 10th update

IF.Ctrls=8                         ;Btn4 = TC Reset
    UK=1                               ;Reset on next update

IF.Ctrls=9                         ;Btn5 = Percent/dB
    U5=Btn5                            ;Mode copy (use if Ctrls closed)

_IMD_Task Macro Listing:

X=SpectWindOn * 4              ;0 if Line Lock, 4 if Arb
Y=L.0.ToneFreq * 1024 / SmplRate       ;F1 line number
Z=L.1.ToneFreq * 1024 / SmplRate       ;F2 line number
I=cint(Z)                              ;Integer F2 line
A=Sp(Ch,I)                             ;Peak F2 magnitude
IF.A=0                                 ;No F2 peak?
    Mtr0="No Signal" +n + Ch(c)
ELSE.                                  ;Else got signal
    IF.U0=2                                ;CCIF mode?
        K=cint(Y)                              ;Int F1 line
        B=Sp(Ch,K)                             ;Peak F1 magnitude
        C=cint(Z - Y)                          ;F2-F1 (1 kHz) line
        L=sSig(C-X,C+X)                        ;F2-F1 energy
        U=0                                    ;Cumulative dist
        M=2                                    ;2 lines each side
            C=cint(Y - M*(Z-Y))                ;Neg side line number
            IF.C=>X                            ;Above zero?
                U=U + Sp(Ch,C)                 ;Add line magnitude
            C=cint(Z + M*(Z-Y))                ;Pos side line number
            IF.C=<=(511-X)                     ;In range?
                U=U + Sp(Ch,C)                 ;Add line magnitude
            M=M-1                              ;Next side line
        D=100 * L / sqrt(A^2 + B^2)            ;F2-F1 % of F1,F2
        E=100 * U / sqrt(A^2 + B^2)            ;4-term % of F1,F2
        IF.D=>50                               ;Noise only?
            Mtr0="No Signal" +n + Ch(c)
            UK=UK-1                            ;TC countdown after change
            IF.UK=0                            ;Reset if 0
                Q=D                                ;Accums = latest
            Q=Q + (D - Q) / QT                 ;Apply TC to disp values
            R=R + (E - R) / QT
            IF.U5=0                            ;Percent?
                Mtr0=Q(0.4) + "% IMD (f2-f1)" +n +R(0.4) +"% IMD (4 term)" +n + Ch(c)
            ELSE.                              ;Else dB
                D=20 * log10(Q/100)            ;Convert TC value to dB
                IF.D=<-200                     ;Limit -dB for 0 IMD
                E=20 * log10(R/100)            ;Convert TC value to dB
                Mtr0=D(0.2) + " dB IMD (f2-f1)" +n +E(0.2) +" dB IMD (4 term)" +n + Ch(c)
    ELSE.                                  ;SMPTE or DIN mode
        L=sSig(I-25,I-X-1)                     ;Energy below F2
        U=sSig(I+X+1,I+25)                     ;Energy above F2
        D=100*(sqrt(U^2 + L^2) / A)            ;Total as % of F2
        IF.D=>50                               ;Noise only?
            Mtr0="No Signal" +n + Ch(c)
            UK=UK-1                            ;TC countdown after change
            IF.UK=0                            ;Reset if 0
                P=D                                ;Accum = latest
            P=P + (D - P) / QT                     ;Apply TC to disp value
            IF.U5=0                                ;Percent?
                Mtr0=P(0.4) + "% IMD" +n + Ch(c)
            ELSE.                                  ;Else dB
                D=20 * log10(P/100)
                Mtr0=D(0.2) + " dB IMD" +n + Ch(c)

IF.Mtr0?E=1                        ;Meter close?
    Task="-_IMD_Task"                  ;Uninstall task
    Avg=0                              ;Average off
    TrigMode=UT                        ;Restore Trigger mode

See also Macro Examples and Mini-Apps


Questions? Comments? Contact us!

We respond to ALL inquiries, typically within 24 hrs.
Over 30 Years of Innovative Instrumentation
© Copyright 2007 - 2017 by Interstellar Research
All rights reserved