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# --------------------- IEC Intermodulation measurement ---------------------- 34# 35# Run jack_nonlin with arguments 0.01 0.01 0 36 37 38# We need a linear X axis for the bargraph. 39# 40LogF = np.linspace (2.7, 4.3, 17, endpoint = True) 41Freq = np.power (10.0, LogF) # 500 Hz to 20 kHz, 1/3 oct. 42Fdiff = 60 43Level = -20 44Mtime = 1.0 45 46# Create a Jacksignal object. 47# 48J = JackSignal("IMtest") 49if J.get_state() < 0: 50 print ("Failed to create JackSignal -- is the server running ?") 51 exit(1) 52 53# Get Jack info. 54# 55name, Fsamp, period = J.get_jack_info() 56 57# Create ports and connect 58# 59J.create_output (0, "out") 60J.create_input (0, "in") 61J.silence() 62J.connect_output (0, "jack_nonlin:in") 63J.connect_input (0, "jack_nonlin:out") 64 65# Length of test signals in samples. 66# 67siglen = int (Mtime * Fsamp + 0.5) 68margin = 1000 69buflen = siglen + margin 70 71# Input buffer. 72# 73Ainp = np.zeros ((buflen,), dtype = np.float32) 74 75 76# Run test. 77# 78N = Freq.shape [0] 79D2 = N * [0] 80D3 = N * [0] 81for i in range (N): 82 83 # Generate test signal, will be scaled for output. 84 # 85 Fcent = Freq [i] 86 Flo = Fcent - Fdiff / 2 87 Fhi = Fcent + Fdiff / 2 88 amp = pow (10.0, Level / 20.0) 89 Aout = ( gen_sinewave (amp, Flo, Fsamp, buflen) 90 + gen_sinewave (amp, Fhi, Fsamp, buflen)).astype (np.float32) 91 92 # Generate reference signals for selective measurement. 93 # 94 Mlo = gen_complex (Flo, Fsamp, siglen) 95 Mhi = gen_complex (Fhi, Fsamp, siglen) 96 M3a = gen_complex (2 * Flo - Fhi, Fsamp, siglen) 97 M3b = gen_complex (2 * Fhi - Flo, Fsamp, siglen) 98 M2 = gen_complex (Fdiff, Fsamp, siglen) 99 100 # Define signal buffers and run test. 101 # 102 J.set_output_data (0, Aout) 103 J.set_input_data (0, Ainp) 104 J.process() 105 J.wait() 106 107 # Skip margin samples and measure. 108 # We are not interested in the phase here. 109 # 110 T = Ainp [margin:] 111 Llo,p = sigdetect (T, Mlo) 112 Lhi,p = sigdetect (T, Mhi) 113 L2,p = sigdetect (T, M2) 114 L3a,p = sigdetect (T, M3a) 115 L3b,p = sigdetect (T, M3b) 116 117 # Print results. 118 # 119 dblo = 20 * log10 (Llo + 1e-20) 120 dbhi = 20 * log10 (Lhi + 1e-20) 121 D2 [i] = im2 = 100 * L2 / (Llo + Lhi) 122 D3 [i] = im3 = 100 * hypot (L3b, L3b) / (Llo + Lhi) 123 print ("Freq = %7.1f Al = %5.1f Ah = %5.1f im2 = %6.3f%% im3 = %6.3f%%" % (Fcent, dblo, dbhi, im2, im3)) 124 125# Stop the Jacksignal process. 126del J 127 128# Create a nice graph to present the results. 129# 130fig = plt.figure (figsize=(8,6), facecolor='white') 131ax = fig.add_axes ([0.07, 0.05, 0.86, 0.90]) 132ax.set_title ("% Intermodulation distortion (IEC)") 133ax.set_xlim (2.6, 4.4) 134ax.set_xticks ((2.7, 3.0, 3.3, 3.7, 4.0, 4.3)) 135ax.set_xticklabels (('500', '1k', '2k', '5k', '10k', '20k')) 136ax.set_ylim (1e-3, 1e1) 137ax.set_yscale ('log') 138ax.bar (LogF - 0.022, D2, 0.02, color = 'b') 139ax.bar (LogF + 0.002, D3, 0.02, color = 'g') 140ax.text (2.75, 5.0, 'IM2', size = 17, color = 'b') 141ax.text (2.95, 5.0, 'IM3', size = 17, color = 'g') 142ax.grid () 143plt.show () 144 145 146