# HG changeset patch # User Mychaela Falconia # Date 1627880386 0 # Node ID 9b3e5be96bab89f64dad419c33cf3dd0fac41e4b # Parent 6057c98d11a9922ae13890405fcdc174ea88b0da fir2freq: a tool for analyzing captured FIR coefficient sets diff -r 6057c98d11a9 -r 9b3e5be96bab .hgignore --- 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$ diff -r 6057c98d11a9 -r 9b3e5be96bab fir/Makefile --- /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} diff -r 6057c98d11a9 -r 9b3e5be96bab fir/freqresp.c --- /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 +#include +#include + +#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); +} diff -r 6057c98d11a9 -r 9b3e5be96bab fir/rdcommon.c --- /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); +} diff -r 6057c98d11a9 -r 9b3e5be96bab fir/readfir.c --- /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 +#include +#include +#include +#include +#include + +#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); +}