changeset 376:9b3e5be96bab

fir2freq: a tool for analyzing captured FIR coefficient sets
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 02 Aug 2021 04:59:46 +0000
parents 6057c98d11a9
children 34490934ff02
files .hgignore fir/Makefile fir/freqresp.c fir/rdcommon.c fir/readfir.c
diffstat 5 files changed, 240 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat Jul 31 10:18:34 2021 +0000
+++ b/.hgignore	Mon Aug 02 04:59:46 2021 +0000
@@ -25,6 +25,8 @@
 ^dspanal/char2coff$
 ^dspanal/patchanal$
 
+^fir/fir2freq$
+
 ^fluid-mnf/fluid-mnf$
 
 ^frbl/reconst/[A-Za-z_0-9]*\.disasm$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fir/Makefile	Mon Aug 02 04:59:46 2021 +0000
@@ -0,0 +1,12 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	fir2freq
+OBJS=	freqresp.o readfir.o
+
+all:	${PROG}
+
+${PROG}:	${OBJS}
+	${CC} -o $@ ${OBJS} -lm
+
+clean:
+	rm -f *.o ${PROG}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fir/freqresp.c	Mon Aug 02 04:59:46 2021 +0000
@@ -0,0 +1,81 @@
+/*
+ * This program computes the frequency response of a Calypso DSP FIR filter
+ * whose coefficients have been captured somewhere out in the wild.
+ * The math has been taken from section 2.2.2 of this article:
+ *
+ * https://dspguru.com/dsp/faqs/fir/properties/
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define	NCOEFF	31
+
+int coeff_int[NCOEFF];
+float coeff_float[NCOEFF];
+unsigned nsteps;
+float freq_step, omega_step;
+float freq, omega;
+
+static void
+coeff_to_float()
+{
+	unsigned n;
+
+	for (n = 0; n < NCOEFF; n++)
+		coeff_float[n] = coeff_int[n] / 16384.0f;
+}
+
+static void
+do_one_freq()
+{
+	unsigned n;
+	float angle_arg, rsum, isum;
+	float gain, db;
+
+	angle_arg = 0;
+	rsum = 0;
+	isum = 0;
+	for (n = 0; n < NCOEFF; n++) {
+		rsum += coeff_float[n] * cosf(angle_arg);
+		isum -= coeff_float[n] * sinf(angle_arg);
+		angle_arg += omega;
+	}
+	gain = hypotf(rsum, isum);
+	db = log10f(gain) * 20.0f;
+	printf("%.2f\t%f\t%.2f\n", freq, gain, db);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	unsigned n;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s coeff-file nsteps\n", argv[0]);
+		exit(1);
+	}
+	if (read_fir_coeff_table_int(argv[1], coeff_int) < 0)
+		exit(1);	/* error msg already printed */
+	coeff_to_float();
+	nsteps = strtoul(argv[2], 0, 0);
+	if (nsteps < 1) {
+		fprintf(stderr, "error: nsteps argument must be >= 1\n");
+		exit(1);
+	}
+	freq_step = 4000.0f / nsteps;
+	omega_step = M_PI / nsteps;
+	n = 0;
+	freq = 0;
+	omega = 0;
+	for (;;) {
+		do_one_freq();
+		if (n >= nsteps)
+			break;
+		n++;
+		freq += freq_step;
+		omega += omega_step;
+	}
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fir/rdcommon.c	Mon Aug 02 04:59:46 2021 +0000
@@ -0,0 +1,62 @@
+/*
+ * This C file is not a compilation unit in itself, but is the common piece
+ * (a set of static variables and functions) included in the librftab modules
+ * responsible for reading different kinds of ASCII tables.
+ */
+
+#define	MAX_FIELDS_PER_LINE	64
+
+static char *filename;
+static FILE *rdfile;
+static unsigned lineno;
+static char linebuf[256], *line_fields[MAX_FIELDS_PER_LINE];
+static unsigned line_nfields, line_field_ptr;
+
+static int
+read_line()
+{
+	char *cp;
+
+	if (!fgets(linebuf, sizeof linebuf, rdfile))
+		return(0);
+	lineno++;
+	cp = linebuf;
+	for (line_nfields = 0; ; ) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#')
+			break;
+		if (line_nfields >= MAX_FIELDS_PER_LINE) {
+			fprintf(stderr,
+				"%s line %d: too many fields on one line\n",
+				filename, lineno);
+			return(-1);
+		}
+		line_fields[line_nfields++] = cp;
+		while (*cp && !isspace(*cp))
+			cp++;
+		if (*cp)
+			*cp++ = '\0';
+	}
+	return(1);
+}
+
+static
+get_field(retp)
+	char **retp;
+{
+	int rc;
+
+	if (line_field_ptr < line_nfields) {
+		*retp = line_fields[line_field_ptr++];
+		return(1);
+	}
+	do {
+		rc = read_line();
+		if (rc <= 0)
+			return(rc);
+	} while (!line_nfields);
+	*retp = line_fields[0];
+	line_field_ptr = 1;
+	return(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fir/readfir.c	Mon Aug 02 04:59:46 2021 +0000
@@ -0,0 +1,83 @@
+/*
+ * Reading FIR coefficient tables from formatted ASCII files,
+ * modified version for host processing.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include "rdcommon.c"
+
+static int *writeptr;
+
+static
+process_number()
+{
+	char *field;
+	int rc, number;
+
+	rc = get_field(&field);
+	if (rc < 0)
+		return(rc);
+	if (!rc) {
+		printf("error: %s is too short for a FIR coefficient table\n",
+			filename);
+		return(-1);
+	}
+	number = strtol(field, 0, 0);
+	if (number >= 32768)
+		number -= 65536;
+	*writeptr++ = number;
+	return(0);
+}
+
+read_fir_coeff_table_int(filename_arg, rdbuf)
+	char *filename_arg;
+	int *rdbuf;
+{
+	char *field;
+	int rc, i;
+
+	filename = filename_arg;
+	rdfile = fopen(filename, "r");
+	if (!rdfile) {
+		perror(filename);
+		return(-1);
+	}
+	lineno = 0;
+	line_nfields = 0;
+	rc = get_field(&field);
+	if (rc <= 0) {
+not_valid_fir_table:
+		fprintf(stderr,
+			"error: %s is not a valid FIR coefficient table file\n",
+			filename);
+		fclose(rdfile);
+		return(-1);
+	}
+	if (strcmp(field, "fir-coeff-table"))
+		goto not_valid_fir_table;
+	writeptr = rdbuf;
+	for (i = 0; i < 31; i++) {
+		rc = process_number();
+		if (rc < 0) {
+			fclose(rdfile);
+			return(rc);
+		}
+	}
+	rc = get_field(&field);
+	fclose(rdfile);
+	if (rc < 0)
+		return(rc);
+	if (rc) {
+		fprintf(stderr,
+			"error: %s is too long for a FIR coefficient table\n",
+			filename);
+		return(-1);
+	}
+	return(0);
+}