mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-09-26 09:28:14 +00:00
The PlatformIO dep sh123/esp32_codec2_arduino@1.0.7 bundles codec2 v0.9.2. Mac-side pycodec2 v3.0.4 links libcodec2 v1.2.0. Years of codec2 development between those releases. Replace the upstream lib with a local vendor of drowe67/codec2 v1.2.0 under lib/codec2/. Trim the 191-file source tree down to the ~100 files actually needed for codec2 (drop FreeDV, OFDM, COHPSK, FSK, FM-FSK, LDPC, Horus, CLI tools — pyxis only uses codec2_create/destroy/encode/decode + samples_per_frame / bytes_per_frame). Carry over the v0.9 codebook .c files since the codebook contents matched (compared against v1.2's src/codebook/*.txt). Define __EMBEDDED__ so the codebooks land in flash (.const) rather than RAM. Without it the codebooks add ~127KB to BSS and the LVGL task fails to start (RAM was 65% full vs 27% with __EMBEDDED__). Provide trivial codec2_malloc/codec2_free wrappers in codec2_alloc_esp32.c (codec2 v1.2 expects them when __EMBEDDED__ is defined; ESP-IDF's malloc/free already pull from internal RAM). Also explicitly add SD/FS to lib_deps and #include <SD.h> in main.cpp — the previous esp32_codec2 dep transitively pulled SD which let SDArchiveFileSystem.h get away with depending on it implicitly. With chain+ ldf mode and no esp32_codec2 dep, we have to declare the framework lib explicitly. DOES NOT fix the ~30x speech-decode RMS asymmetry between pycodec2 self-tests (~5800) and pyxis decoding the same encoded bytes (~170). Sine waves and 3-formant synthesis pass clean both directions; only real TTS speech triggers it. Probably a separate codec-state divergence (the encoder/decoder are independent codec2 instances in pyxis, both fresh per call) or a wire-format quirk we still need to track down. v1.2 is the right baseline regardless — same bug class as several upstream fixes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
127 lines
3.8 KiB
C
127 lines
3.8 KiB
C
/*---------------------------------------------------------------------------*\
|
|
|
|
FILE........: modem_stats.c
|
|
AUTHOR......: David Rowe
|
|
DATE CREATED: June 2015
|
|
|
|
Common functions for returning demod stats from fdmdv and cohpsk modems.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
Copyright (C) 2015 David Rowe
|
|
|
|
All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License version 2.1, as
|
|
published by the Free Software Foundation. This program is
|
|
distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "modem_stats.h"
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
|
|
#include "codec2_fdmdv.h"
|
|
#include "kiss_fft.h"
|
|
|
|
void modem_stats_open(struct MODEM_STATS *f) {
|
|
int i;
|
|
|
|
/* zero out all the stats */
|
|
|
|
memset(f, 0, sizeof(struct MODEM_STATS));
|
|
|
|
/* init the FFT */
|
|
|
|
#ifndef __EMBEDDED__
|
|
for (i = 0; i < 2 * MODEM_STATS_NSPEC; i++) f->fft_buf[i] = 0.0;
|
|
f->fft_cfg = (void *)kiss_fft_alloc(2 * MODEM_STATS_NSPEC, 0, NULL, NULL);
|
|
assert(f->fft_cfg != NULL);
|
|
#endif
|
|
}
|
|
|
|
void modem_stats_close(struct MODEM_STATS *f) {
|
|
#ifndef __EMBEDDED__
|
|
KISS_FFT_FREE(f->fft_cfg);
|
|
#endif
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*\
|
|
|
|
FUNCTION....: modem_stats_get_rx_spectrum()
|
|
AUTHOR......: David Rowe
|
|
DATE CREATED: 9 June 2012
|
|
|
|
Returns the MODEM_STATS_NSPEC point magnitude spectrum of the rx signal in
|
|
dB. The spectral samples are scaled so that 0dB is the peak, a good
|
|
range for plotting is 0 to -40dB.
|
|
|
|
Note only the real part of the complex input signal is used at
|
|
present. A complex variable is used for input for compatibility
|
|
with the other rx signal processing.
|
|
|
|
Successive calls can be used to build up a waterfall or spectrogram
|
|
plot, by mapping the received levels to colours.
|
|
|
|
The time-frequency resolution of the spectrum can be adjusted by varying
|
|
MODEM_STATS_NSPEC. Note that a 2* MODEM_STATS_NSPEC size FFT is reqd to get
|
|
MODEM_STATS_NSPEC output points. MODEM_STATS_NSPEC must be a power of 2.
|
|
|
|
See octave/tget_spec.m for a demo real time spectral display using
|
|
Octave. This demo averages the output over time to get a smoother
|
|
display:
|
|
|
|
av = 0.9*av + 0.1*mag_dB
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef __EMBEDDED__
|
|
void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[],
|
|
COMP rx_fdm[], int nin) {
|
|
int i, j;
|
|
COMP fft_in[2 * MODEM_STATS_NSPEC];
|
|
COMP fft_out[2 * MODEM_STATS_NSPEC];
|
|
float full_scale_dB;
|
|
|
|
/* update buffer of input samples */
|
|
|
|
for (i = 0; i < 2 * MODEM_STATS_NSPEC - nin; i++)
|
|
f->fft_buf[i] = f->fft_buf[i + nin];
|
|
for (j = 0; j < nin; j++, i++) f->fft_buf[i] = rx_fdm[j].real;
|
|
assert(i == 2 * MODEM_STATS_NSPEC);
|
|
|
|
/* window and FFT */
|
|
|
|
for (i = 0; i < 2 * MODEM_STATS_NSPEC; i++) {
|
|
fft_in[i].real =
|
|
f->fft_buf[i] *
|
|
(0.5 - 0.5 * cosf((float)i * 2.0 * M_PI / (2 * MODEM_STATS_NSPEC)));
|
|
fft_in[i].imag = 0.0;
|
|
}
|
|
|
|
kiss_fft((kiss_fft_cfg)f->fft_cfg, (kiss_fft_cpx *)fft_in,
|
|
(kiss_fft_cpx *)fft_out);
|
|
|
|
/* FFT scales up a signal of level 1 FDMDV_NSPEC */
|
|
|
|
full_scale_dB = 20 * log10(MODEM_STATS_NSPEC * FDMDV_SCALE);
|
|
|
|
/* scale and convert to dB */
|
|
|
|
for (i = 0; i < MODEM_STATS_NSPEC; i++) {
|
|
mag_spec_dB[i] = 10.0 * log10f(fft_out[i].real * fft_out[i].real +
|
|
fft_out[i].imag * fft_out[i].imag + 1E-12);
|
|
mag_spec_dB[i] -= full_scale_dB;
|
|
}
|
|
}
|
|
#endif
|