1#!/usr/bin/python
2
3# ----------------------------------------------------------------------------
4#
5#  Copyright (C) 2013-2020 Fons Adriaensen <fons@linuxaudio.org>
6#
7#  This program is free software; you can redistribute it and/or modify
8#  it under the terms of the GNU General Public License as published by
9#  the Free Software Foundation; either version 3 of the License, or
10#  (at your option) any later version.
11#
12#  This program is distributed in the hope that it will be useful,
13#  but WITHOUT ANY WARRANTY; without even the implied warranty of
14#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#  GNU General Public License for more details.
16#
17#  You should have received a copy of the GNU General Public License
18#  along with this program.  If not, see <http:#www.gnu.org/licenses/>.
19#
20# ----------------------------------------------------------------------------
21
22
23import sys
24import matplotlib.pyplot as plt
25import numpy as np
26from time import sleep
27from math import hypot, log10
28from jacktools.jacksignal import JackSignal
29sys.path.append ('..')
30from utils.sinewave import *
31
32
33# ---------------- SMPTE/DIN Intermodulation measurement --------------------
34#
35# Run jack_nonlin with arguments 0.01 0.01 0
36
37
38# SMPTE frequencies
39#
40#Flo = 60
41#Fhi = 7000
42
43# DIN frequencies
44#
45Flo = 250
46Fhi = 8000
47
48
49# Test levels (dB, level of low frequency)
50#
51Levels = [ -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0 ]
52Mtime = 1.0
53
54
55# Create a Jacksignal object.
56#
57J = JackSignal("IMtest")
58if J.get_state() < 0:
59    print ("Failed to create JackSignal -- is the server running ?")
60    exit(1)
61
62# Get Jack info.
63#
64name, Fsamp, period = J.get_jack_info()
65
66# Create ports and connect
67#
68J.create_output (0, "out")
69J.create_input (0, "in")
70J.silence()
71J.connect_output (0, "jack_nonlin:in")
72J.connect_input (0, "jack_nonlin:out")
73
74# Length of test signals in samples.
75#
76siglen = int (Mtime * Fsamp + 0.5)
77margin = 1000
78buflen = siglen + margin
79
80# Generate test signal, will be scaled for output.
81#
82Aout = (  gen_sinewave (1.00, Flo, Fsamp, buflen)
83        + gen_sinewave (0.25, Fhi, Fsamp, buflen)).astype (np.float32)
84
85# Input buffer.
86#
87Ainp = np.zeros ((buflen,), dtype = np.float32)
88
89# Generate reference signals for selective measurement.
90#
91Mlo = gen_complex (Flo, Fsamp, siglen)
92Mhi = gen_complex (Fhi, Fsamp, siglen)
93M3a = gen_complex (Fhi - 2 * Flo, Fsamp, siglen)
94M2a = gen_complex (Fhi - 1 * Flo, Fsamp, siglen)
95M2b = gen_complex (Fhi + 1 * Flo, Fsamp, siglen)
96M3b = gen_complex (Fhi + 2 * Flo, Fsamp, siglen)
97
98
99# Run test.
100#
101N = len (Levels)
102D2 = [ 0 for i in range (N) ]
103D3 = [ 0 for i in range (N) ]
104
105for i in range (N):
106
107    # Define signal buffers and run test.
108    amp = pow (10.0, Levels [i] / 20.0)
109    J.set_output_data (0, amp * Aout)
110    J.set_input_data (0, Ainp)
111    J.process()
112    J.wait()
113
114    # Skip margin samples and measure.
115    # We are not interested in the phase here.
116    #
117    T = Ainp [margin:]
118    Llo,p = sigdetect (T, Mlo)
119    Lhi,p = sigdetect (T, Mhi)
120    L3a,p = sigdetect (T, M3a)
121    L2a,p = sigdetect (T, M2a)
122    L2b,p = sigdetect (T, M2b)
123    L3b,p = sigdetect (T, M3b)
124
125    # Print results.
126    #
127    dblo = 20 * log10 (Llo + 1e-30)
128    dbhi = 20 * log10 (Lhi + 1e-30)
129    D2 [i] = im2 = 100 * hypot (L2a, L2b) / Lhi
130    D3 [i] = im3 = 100 * hypot (L3b, L3b) / Lhi
131    print ("Level = %5.1f    Al = %5.1f  Ah = %5.1f   im2 = %6.3f%%  im3 = %6.3f%%" % (Levels [i], dblo, dbhi, im2, im3))
132
133# Stop the Jacksignal process.
134del J
135
136# Create a nice graph to present the results.
137#
138Levels = np.array (Levels)
139fig = plt.figure (figsize=(8,5), facecolor='white')
140ax = fig.add_axes ([0.07, 0.05, 0.86, 0.90])
141ax.set_title ("% Intermodulation distortion (DIN)")
142ax.set_xlim (-55, 5)
143ax.set_ylim (1e-3, 1e1)
144ax.set_yscale ('log')
145ax.bar (Levels - 0.9, D2, 0.8, color = 'b')
146ax.bar (Levels + 0.1, D3, 0.8, color = 'g')
147ax.text (-51, 5.0, 'IM2', size = 17, color = 'b')
148ax.text (-46, 5.0, 'IM3', size = 17, color = 'g')
149ax.grid ()
150plt.show ()
151
152