[zaptel-commits] mattf: branch 1.2 r3640 - in /branches/1.2: fxotune.c fxotune.h

SVN commits to the Zaptel project zaptel-commits at lists.digium.com
Wed Jan 9 16:51:57 CST 2008


Author: mattf
Date: Wed Jan  9 16:51:57 2008
New Revision: 3640

URL: http://svn.digium.com/view/zaptel?view=rev&rev=3640
Log:
BIG fxotune update.  New version which uses fourier analysis for echo return loss measurement.  Much more accurate than the old version, and can penetrate through background noise that may be on the line as well as noise caused by tones in the background such as reorder or congestion if the timing parameters aren't exactly right in the setup.  If you have analog fxo modules, it is recommended that you run fxotune on them again with this latest version.  You will definitely see even better results

Modified:
    branches/1.2/fxotune.c
    branches/1.2/fxotune.h

Modified: branches/1.2/fxotune.c
URL: http://svn.digium.com/view/zaptel/branches/1.2/fxotune.c?view=diff&rev=3640&r1=3639&r2=3640
==============================================================================
--- branches/1.2/fxotune.c (original)
+++ branches/1.2/fxotune.c Wed Jan  9 16:51:57 2008
@@ -31,14 +31,16 @@
 #include "wctdm.h"
 #include "fxotune.h"
 
-#define TEST_DURATION 2000			/* 4000 samples (or 500 ms) of test */
-#define BUFFER_LENGTH (2 * TEST_DURATION)             /* 4000 sample buffers */
-#define SKIP_SAMPLES 800                      /* skip first 100 ms of test when computing echo powers - gives the system time to acquire data */
-
-static const float loudness = 16384.0;
+#define TEST_DURATION 2000
+#define BUFFER_LENGTH (2 * TEST_DURATION)
+#define SKIP_SAMPLES 800
+
+static const float amplitude = 16384.0;
 
 static char *zappath = "/dev/zap";
 static char *configfile = "/etc/fxotune.conf";
+
+static int audio_dump_fd = -1;
 
 static char *usage =
 "Usage: fxotune [-v[vv] (-s | -i <options> | -d <options>)\n"
@@ -52,7 +54,9 @@
 "		options : [-b <device>][-w <waveform>]\n"
 "		   [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
 "	-v : more output (-vv, -vvv also)\n"
-"       -c <config_file>\n"
+"	-o <path> : Write the received raw 16-bit signed linear audio that is\n"
+"	            used in processing to the file specified by <path>\n"
+"	-c <config_file>\n"
 "\n"
 "		<calibtype>      - type of calibration\n"
 "		                   (default 2, old method 1)\n"
@@ -68,8 +72,8 @@
 "		                   (default 1)\n"
 "		<waveform>       - -1 for multitone waveform, or frequency of\n"
 "		                   single tone (default -1)\n"
-"               <config_file>    - Alternative file to set from / calibrate to.\n"
-"                                  (Default: /etc/fxotune.conf)\n"
+"		<config_file>    - Alternative file to set from / calibrate to.\n"
+"				   (Default: /etc/fxotune.conf)\n"
 ;
 
 
@@ -92,6 +96,19 @@
 
 static FILE *debugoutfile = NULL;
 
+static int fxotune_read(int fd, void *buffer, int len)
+{
+	int res;
+
+	res = read(fd, buffer, len);
+
+	if ((res > 0) && (audio_dump_fd != -1)) {
+		write(audio_dump_fd, buffer, len);
+	}
+
+	return res;
+}
+
 /**
  * Makes sure that the line is clear.
  * Right now, we do this by relying on the user to specify how long after dialing the
@@ -178,8 +195,13 @@
  */
 static short inline gentone(int hz, int index)
 {
-	return loudness * sin((index * 2.0 * M_PI * hz)/8000);
-}
+	return amplitude * sin((index * 2.0 * M_PI * hz)/8000);
+}
+
+/* Using DTMF tones for now since they provide good mid band testing 
+ * while not being harmonics of each other */
+static int freqs[] = {697, 770, 941, 1209, 1336, 1633};
+static int freqcount = 6;
 
 /**
  * Generates a waveform of several frequencies.
@@ -192,8 +214,6 @@
  */
 static short inline genwaveform(int index)
 {
-	int freqs[] = {300, 600, 900, 1004, 1300, 1600}; /* chose 1004 Hz to include the milliwatt test tone frequency - but there was no particular reson to do so */
-	int freqcount = 6;
 	int i = 0;
 	float response = (float)0;
 	for (i = 0; i < freqcount; i++){
@@ -201,7 +221,7 @@
 	}
 	
 
-	return loudness * response / freqcount;
+	return amplitude * response / freqcount;
 }
 
 
@@ -257,6 +277,61 @@
 	return sqrtf(finalanswer);
 }
 
+/* 
+ * In an effort to eliminate as much as possible the effect of outside noise, we use principles
+ * from the Fourier Transform to attempt to calculate the return loss of our signal for each setting.
+ *
+ * To begin, we send our output signal out on the line.  We then receive back the reflected
+ * response.  In the Fourier Transform, each evenly distributed frequency within the window
+ * is correlated (multiplied against, then the resulting samples are added together) with
+ * the real (cos) and imaginary (sin) portions of that frequency base to detect that frequency.
+ * 
+ * Instead of doing a complete Fourier Transform, we solve the transform for only our signal
+ * by multiplying the received signal by the real and imaginary portions of our reference
+ * signal.  This then gives us the real and imaginary values that we can use to calculate
+ * the return loss of the sinusoids that we sent out on the line.  This is done by finding
+ * the magnitude (think polar form) of the vector resulting from the real and imaginary
+ * portions calculated above.
+ *
+ * This essentially filters out any other noise which maybe present on the line which is outside
+ * the frequencies used in our test multi-tone.
+ */
+static float db_loss(float measured, float reference)
+{
+	return 20 * (logf(measured/reference)/logf(10));
+}
+
+static void one_point_dft(const short *inbuf, int len, int frequency, float *real, float *imaginary)
+{
+	float myreal = 0, myimag = 0;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
+		myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
+	}
+
+	myimag *= -1;
+
+	*real = myreal / (float) len;
+	*imaginary = myimag / (float) len;
+}
+
+static float calc_magnitude(short *inbuf, int insamps)
+{
+	float real, imaginary, magnitude;
+	float totalmagnitude = 0;
+	int i;
+
+	for (i = 0; i < freqcount; i++) {
+		one_point_dft(inbuf, insamps, freqs[i], &real, &imaginary);
+		magnitude = sqrtf((real * real) + (imaginary * imaginary));
+		totalmagnitude += magnitude;
+	}
+
+	return totalmagnitude;
+}
+
 /**
  *  dumps input and output buffer contents for the echo test - used to see exactly what's going on
  */
@@ -334,7 +409,7 @@
 
 retry:
 		/* read return response */
-	res = read(whichzap, inbuf, BUFFER_LENGTH);
+	res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH);
 	if (res != BUFFER_LENGTH) {
 		int x;
 
@@ -382,7 +457,7 @@
  * impedence/coefficients configurations.
  *   
  * Note:  It may be possible to take this even further and do some pertubation analysis on the echo coefficients
- * 		 themselves (maybe use the 64 entry sweep to find some settings that are close to working well, then
+ * 		 themselves (maybe use the 72 entry sweep to find some settings that are close to working well, then
  * 		 deviate the coefficients a bit to see if we can improve things).  A better way to do this would be to
  * 		 use the optimization strategy from silabs.  For reference, here is an application note that describes
  * 		 the echo coefficients (and acim values):
@@ -399,7 +474,7 @@
 	float lowestecho = 999999999999.0;;
 	struct zt_bufferinfo bi;
 
-	short inbuf[TEST_DURATION];
+	short inbuf[TEST_DURATION * 2];
 
 	if (debug && !debugoutfile) {
 		if (!(debugoutfile = fopen("fxotune.vals", "w"))) {
@@ -453,12 +528,12 @@
 		outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if freq is negative, use a multi-frequency waveform */
 	
 	/* compute power of input (so we can later compute echo levels relative to input) */
-	float waveform_power = power_of(outbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1);
+	float waveform_power = calc_magnitude(outbuf, TEST_DURATION);
 	
 
 	/* sweep through the various coefficient settings and see how our responses look */
 
-	int echo_trys_size = 64;
+	int echo_trys_size = 72;
 	int trys = 0;
 	for (trys = 0; trys < echo_trys_size; trys++){
 		
@@ -489,19 +564,26 @@
 
 retry:
 		/* read return response */
-		res = read(whichzap, inbuf, BUFFER_LENGTH);
-		if (res != BUFFER_LENGTH) {
+		res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH * 2);
+		if (res != BUFFER_LENGTH * 2) {
 			int x;
 
 			ioctl(whichzap, ZT_GETEVENT, &x);
 			goto retry;
 		}
 
-		/* calculate RMS of response */
+		float freq_result = calc_magnitude(inbuf, TEST_DURATION * 2);
+		float echo = db_loss(freq_result, waveform_power);
 		
-		float freq_result = power_of(inbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1);
-		float echo = freq_result/waveform_power;
-		
+#if 0
+		if (debug > 0)
+			fprintf(stdout, "%3d,%d,%d,%d,%d,%d,%d,%d,%d: magnitude = %0.0f, echo = %0.4f dB\n", 
+					echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+					echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+					echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+					freq_result, echo);
+#endif
+
 		if (freq_result < lowesttryresult){
 			lowesttry = trys;
 			lowesttryresult = freq_result;
@@ -509,7 +591,7 @@
 		}
 		if (debug) {
 			char result[256];
-			snprintf(result, sizeof(result), "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f", 
+			snprintf(result, sizeof(result), "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%f,%f", 
 						echo_trys[trys].acim, 
 						echo_trys[trys].coef1, 
 						echo_trys[trys].coef2, 
@@ -519,19 +601,21 @@
 						echo_trys[trys].coef6, 
 						echo_trys[trys].coef7, 
 						echo_trys[trys].coef8, 
-						freq, 
 						freq_result,
 						echo
 					);
 			
 			fprintf(debugoutfile, "%s\n", result);
-			if (debug > 1)
-				fprintf(stdout, "%s\n", result);
+			fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n", 
+					echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+					echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+					echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+					freq_result, echo);
 		}
 	}
 
 	if (debug > 0)
-		fprintf(stdout, "Config with lowest response = %d, power = %0.0f, echo = %0.4f\n", lowesttry, lowesttryresult, lowestecho);
+		fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho);
 
 	memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs));
 
@@ -634,7 +718,7 @@
 			/* read return response */
 retry:
 			/* read return response */
-			res = read(whichzap, inbuf, BUFFER_LENGTH);
+			res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH);
 			if (res != BUFFER_LENGTH) {
 				int x;
 	
@@ -896,7 +980,7 @@
 	return problems;
 }	
 	
-int main (int argc , char **argv)
+int main(int argc , char **argv)
 {
 	int startdev = 1; /* -b */
 	int stopdev = 252; /* -e */
@@ -965,6 +1049,18 @@
 			case 'v':
 				debug = strlen(argv[i])-1;
 				break;
+			case 'o':
+				if (moreargs) {
+					audio_dump_fd = open(argv[++i], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+					if (audio_dump_fd == -1) {
+						fprintf(stdout, "Unable to open file %s: %s\n", argv[i], strerror(errno));
+						return -1;
+					}
+					break;
+				} else {
+					fprintf(stdout, "No path supplied to -o option!\n");
+					return -1;
+				}
 			default:
 				fprintf(stdout, "Unknown option : %s\n", argv[i]);
 				/* Show usage */
@@ -1008,7 +1104,6 @@
 			return -1;
 	}
 
-
 	fputs(usage, stdout);
 	return -1;
 }

Modified: branches/1.2/fxotune.h
URL: http://svn.digium.com/view/zaptel/branches/1.2/fxotune.h?view=diff&rev=3640&r1=3639&r2=3640
==============================================================================
--- branches/1.2/fxotune.h (original)
+++ branches/1.2/fxotune.h Wed Jan  9 16:51:57 2008
@@ -99,5 +99,14 @@
 	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
 	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
 	
+	/* Make sure we include the rest of the impedances */
+	{ 8, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 9, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 10, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 11, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 12, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 13, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 14, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 15, 0, 0, 0, 0, 0, 0, 0, 0},
 };
 




More information about the zaptel-commits mailing list