From 46003430f8435fa092cb28d479a91e831c0807b7 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 12 Oct 2022 17:44:51 -0400 Subject: [PATCH 001/334] adding dsssframe64gen object with example; needs appropriate sync --- examples/dsssframe64sync_example.c | 65 ++++++++++ include/liquid.h | 46 +++++++ makefile.in | 3 + src/framing/src/dsssframe64gen.c | 199 +++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 examples/dsssframe64sync_example.c create mode 100644 src/framing/src/dsssframe64gen.c diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c new file mode 100644 index 000000000..77592a0a6 --- /dev/null +++ b/examples/dsssframe64sync_example.c @@ -0,0 +1,65 @@ +// This example demonstrates the basic interface to the dsssframe64gen and +// dsssframe64sync objects. +#include +#include +#include +#include +#include +#include +#include + +#include "liquid.h" + +int main(int argc, char *argv[]) +{ + // options + unsigned int nfft=2400; + + // create dsssframe64gen object + dsssframe64gen fg = dsssframe64gen_create(); + + // generate the frame in blocks + unsigned int buf_len = dsssframe64gen_get_frame_len(fg); + float complex buf_tx[buf_len]; // transmit buffer + float complex buf_rx[buf_len]; // receive buffer (channel output) + + // create spectral periodogram for displaying spectrum + spgramcf periodogram = spgramcf_create_default(nfft); + + // generate in one step (for now) + dsssframe64gen_assemble(fg, NULL, NULL); + dsssframe64gen_write(fg, buf_tx, buf_len); + + // channel + memmove(buf_rx, buf_tx, buf_len*sizeof(float complex)); + + // push resulting sample through periodogram + spgramcf_write(periodogram, buf_tx, buf_len); + float psd[nfft]; + spgramcf_get_psd(periodogram, psd); + + // export results + const char * filename = "dsssframe64sync_example.m"; + FILE * fid = fopen(filename,"w"); + fprintf(fid,"%% %s : auto-generated file\n", filename); + fprintf(fid,"clear all; close all;\n"); + unsigned int i; +#if 0 + fprintf(fid,"n=%u; y=zeros(1,n);\n", buf_len); + for (i=0; i +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +struct dsssframe64gen_s { + qpacketmodem enc; // packet encoder/modulator + qpilotgen pilotgen; // pilot symbol generator + msequence ms; // spreading sequence generator + float complex pn_sequence[1024]; // 1024-symbol p/n sequence + unsigned char payload_dec[ 150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol + float complex payload_sym[ 600]; // modulated payload symbols + float complex payload_tx [ 630]; // modulated payload symbols with pilots + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor + firinterp_crcf interp; // pulse-shaping filter/interpolator + float complex buf_output[2]; // output sample buffer + // TODO: counters, etc. +}; + +// create dsssframe64gen object +dsssframe64gen dsssframe64gen_create() +{ + dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); + q->m = 7; + q->beta = 0.3f; + + unsigned int i; + + // generate p/n sequence + q->ms = msequence_create(11, 0x0805, 1); + for (i=0; i<1024; i++) { + q->pn_sequence[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); + q->pn_sequence[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; + } + + // create payload encoder/modulator object + int check = LIQUID_CRC_24; + int fec0 = LIQUID_FEC_NONE; + int fec1 = LIQUID_FEC_GOLAY2412; + int mod_scheme = LIQUID_MODEM_QPSK; + q->enc = qpacketmodem_create(); + qpacketmodem_configure(q->enc, 72, check, fec0, fec1, mod_scheme); + //qpacketmodem_print(q->enc); + assert( qpacketmodem_get_frame_len(q->enc)==600 ); + + // create pilot generator + q->pilotgen = qpilotgen_create(600, 21); + assert( qpilotgen_get_frame_len(q->pilotgen)==630 ); + + // create pulse-shaping filter (k=2) + q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,2,q->m,q->beta,0); + + // return main object + return q; +} + +// copy object +dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dsssframe64gen_copy(), object cannot be NULL"); + + // not yet implemented + return NULL; +} + +// destroy dsssframe64gen object +int dsssframe64gen_destroy(dsssframe64gen _q) +{ + // destroy internal objects + msequence_destroy (_q->ms); + qpacketmodem_destroy (_q->enc); + qpilotgen_destroy (_q->pilotgen); + firinterp_crcf_destroy(_q->interp); + + // free main object memory + free(_q); + return LIQUID_OK; +} + +// print dsssframe64gen object internals +int dsssframe64gen_print(dsssframe64gen _q) +{ + printf("\n", _q->m, _q->beta); + return LIQUID_OK; +} + +// assmeble frame +// _q : frame generator object +// _header : 8-byte header data, NULL for random +// _payload : 64-byte payload data, NULL for random +// _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1] +int dsssframe64gen_assemble(dsssframe64gen _q, + const unsigned char * _header, + const unsigned char * _payload) +{ + unsigned int i; + + // concatenate header and payload + for (i=0; i<8; i++) + _q->payload_dec[i] = _header==NULL ? rand() & 0xff : _header[i]; + for (i=0; i<64; i++) + _q->payload_dec[i+8] = _payload==NULL ? rand() & 0xff : _payload[i]; + + // run packet encoder and modulator + qpacketmodem_encode(_q->enc, _q->payload_dec, _q->payload_sym); + + // add pilot symbols + qpilotgen_execute(_q->pilotgen, _q->payload_sym, _q->payload_tx); + + // reset objects + firinterp_crcf_reset(_q->interp); + msequence_reset(_q->ms); + + // frame_assembled = 1 + return LIQUID_OK; +} + +// write samples to buffer +// _q : frame generator object +// _buf : output frame samples, shape: (_buf_len,) +// _buf_len : output frame buffer size +int dsssframe64gen_write(dsssframe64gen _q, + float complex * _buf, + unsigned int _buf_len) +{ + unsigned int i, j, n=0; + + // p/n sequence + for (i=0; i<1024; i++) { + firinterp_crcf_execute(_q->interp, _q->pn_sequence[i], &_buf[n]); + n+=2; + } + + // frame payload + for (i=0; i<630; i++) { + float complex sym = _q->payload_tx[i]; // strip out raw payload symbol + for (j=0; j<256; j++) { + // generate pseudo-random symbol + unsigned int p = msequence_generate_symbol(_q->ms, 2); + float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); + firinterp_crcf_execute(_q->interp, sym*s, &_buf[n]); + n+=2; + } + } + + // interpolator settling + for (i=0; i<2*_q->m; i++) { + firinterp_crcf_execute(_q->interp, 0.0f, &_buf[n]); + n+=2; + } + + assert(n==dsssframe64gen_get_frame_len(_q)); + return LIQUID_OK; +} + +// is frame generation complete? +int dsssframe64gen_complete(dsssframe64gen _q) +{ + return 1; +} + +// get full frame length [samples] +unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) +{ + return 2*(1024 + 630*256 + 2*_q->m); +} + From a63cd643b2e40596513dc8b822b8b4a700441919 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 12 Oct 2022 22:43:51 -0400 Subject: [PATCH 002/334] dsssframe64gen: dropping excess bandwidth, increasing filter length --- src/framing/src/dsssframe64gen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 9fd78c3e8..3532fec04 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -51,8 +51,8 @@ struct dsssframe64gen_s { dsssframe64gen dsssframe64gen_create() { dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); - q->m = 7; - q->beta = 0.3f; + q->m = 15; + q->beta = 0.20f; unsigned int i; From f7061f41654d07bea28bf01a4f70534f5af9d4dd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 14 Oct 2022 09:11:56 -0400 Subject: [PATCH 003/334] dsssframe64: adding sync method; really needs to be re-spun --- include/liquid.h | 14 +- makefile.in | 2 + src/framing/src/dsssframe64sync.c | 510 ++++++++++++++++++++++++++++++ 3 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 src/framing/src/dsssframe64sync.c diff --git a/include/liquid.h b/include/liquid.h index c4f91faa7..71c462f77 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5891,7 +5891,8 @@ framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q); // // Direct sequence/spread spectrum framing with fixed 64-byte payload // -// DS/SS frame generator object type + +// frame generator object type typedef struct dsssframe64gen_s * dsssframe64gen; // create dsssframe64gen object @@ -5934,6 +5935,17 @@ int dsssframe64gen_complete(dsssframe64gen _q); unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); +// frame synchronizer object type +typedef struct dsssframe64sync_s * dsssframe64sync; + +dsssframe64sync dsssframe64sync_create(framesync_callback _callback, void * _userdata); +int dsssframe64sync_destroy (dsssframe64sync _q); +int dsssframe64sync_print (dsssframe64sync _q); +int dsssframe64sync_reset (dsssframe64sync _q); +int dsssframe64sync_is_frame_open (dsssframe64sync _q); +int dsssframe64sync_reset_framedatastats(dsssframe64sync _q); +int dsssframe64sync_execute (dsssframe64sync _q, liquid_float_complex * _x, unsigned int _n); + // // OFDM flexframe generator // diff --git a/makefile.in b/makefile.in index abf7c2257..0017af192 100644 --- a/makefile.in +++ b/makefile.in @@ -630,6 +630,7 @@ framing_objects := \ src/framing/src/bsync_cccf.o \ src/framing/src/detector_cccf.o \ src/framing/src/dsssframe64gen.o \ + src/framing/src/dsssframe64sync.o \ src/framing/src/dsssframegen.o \ src/framing/src/dsssframesync.o \ src/framing/src/framedatastats.o \ @@ -665,6 +666,7 @@ src/framing/src/bsync_crcf.o : %.o : %.c $(include_headers) src/framing/s src/framing/src/bsync_cccf.o : %.o : %.c $(include_headers) src/framing/src/bsync.proto.c src/framing/src/detector_cccf.o : %.o : %.c $(include_headers) src/framing/src/dsssframe64gen.o : %.o : %.c $(include_headers) +src/framing/src/dsssframe64sync.o : %.o : %.c $(include_headers) src/framing/src/dsssframegen.o : %.o : %.c $(include_headers) src/framing/src/dsssframesync.o : %.o : %.c $(include_headers) src/framing/src/framedatastats.o : %.o : %.c $(include_headers) diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c new file mode 100644 index 000000000..892251816 --- /dev/null +++ b/src/framing/src/dsssframe64sync.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// basic frame synchronizer with 8 bytes header and 64 bytes payload + +#include +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +#define dsssframe64sync_ENABLE_EQ 0 + +// push samples through detection stage +int dsssframe64sync_execute_seekpn(dsssframe64sync _q, + float complex _x); + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +// _y : output symbol +int dsssframe64sync_step(dsssframe64sync _q, + float complex _x, + float complex * _y); + +// push samples through synchronizer, saving received p/n symbols +int dsssframe64sync_execute_rxpreamble(dsssframe64sync _q, + float complex _x); + +// receive payload symbols +int dsssframe64sync_execute_rxpayload(dsssframe64sync _q, + float complex _x); + +// export debugging based on return value +// 0 : do not write file +// >0 : write specific number (hex) +// -1 : number of packets detected +// -2 : id using first 4 bytes of header +// -3 : write with random extension +int dsssframe64sync_debug_export(dsssframe64sync _q, int _code); + +// dsssframe64sync object structure +struct dsssframe64sync_s { + // callback + framesync_callback callback; // user-defined callback function + void * userdata; // user-defined data structure + framesyncstats_s framesyncstats; // frame statistic object (synchronizer) + framedatastats_s framedatastats; // frame statistic object (packet statistics) + + // synchronizer objects + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor + qdetector_cccf detector; // pre-demod detector + float tau_hat; // fractional timing offset estimate + float dphi_hat; // carrier frequency offset estimate + float phi_hat; // carrier phase offset estimate + float gamma_hat; // channel gain estimate + nco_crcf mixer; // coarse carrier frequency recovery + + // timing recovery objects, states + firpfb_crcf mf; // matched filter decimator + unsigned int npfb; // number of filters in symsync + int mf_counter; // matched filter output timer + unsigned int pfb_index; // filterbank index + + // preamble + float complex preamble_pn[64]; // known 64-symbol p/n sequence + float complex preamble_rx[64]; // received p/n symbols + + // payload decoder + float complex payload_rx [630]; // received payload symbols with pilots + float complex payload_sym[600]; // received payload symbols + unsigned char payload_dec[ 72]; // decoded payload bytes + qpacketmodem dec; // packet demodulator/decoder + qpilotsync pilotsync; // pilot extraction, carrier recovery + int payload_valid; // did payload pass crc? + + // status variables + enum { + dsssframe64sync_STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) + dsssframe64sync_STATE_RXPREAMBLE, // receive p/n sequence + dsssframe64sync_STATE_RXPAYLOAD, // receive payload data + } state; + unsigned int preamble_counter; // counter: num of p/n syms received + unsigned int payload_counter; // counter: num of payload syms received +}; + +// create dsssframe64sync object +// _callback : callback function invoked when frame is received +// _userdata : user-defined data object passed to callback +dsssframe64sync dsssframe64sync_create(framesync_callback _callback, + void * _userdata) +{ + dsssframe64sync q = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); + q->callback = _callback; + q->userdata = _userdata; + q->m = 7; // filter delay (symbols) + q->beta = 0.3f; // excess bandwidth factor + + unsigned int i; + + // generate p/n sequence + msequence ms = msequence_create(7, 0x0089, 1); + for (i=0; i<64; i++) { + q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); + q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; + } + msequence_destroy(ms); + + // create frame detector + unsigned int k = 2; // samples/symbol + q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta); + qdetector_cccf_set_threshold(q->detector, 0.5f); + + // create symbol timing recovery filters + q->npfb = 32; // number of filters in the bank + q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,k,q->m,q->beta); + + // create down-coverters for carrier phase tracking + q->mixer = nco_crcf_create(LIQUID_NCO); + + // create payload demodulator/decoder object + int check = LIQUID_CRC_24; + int fec0 = LIQUID_FEC_NONE; + int fec1 = LIQUID_FEC_GOLAY2412; + int mod_scheme = LIQUID_MODEM_QPSK; + q->dec = qpacketmodem_create(); + qpacketmodem_configure(q->dec, 72, check, fec0, fec1, mod_scheme); + //qpacketmodem_print(q->dec); + assert( qpacketmodem_get_frame_len(q->dec)==600 ); + + // create pilot synchronizer + q->pilotsync = qpilotsync_create(600, 21); + assert( qpilotsync_get_frame_len(q->pilotsync)==630); + + // reset global data counters + dsssframe64sync_reset_framedatastats(q); + + // reset state and return + dsssframe64sync_reset(q); + return q; +} + +// copy object +dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dsssframe64sync_copy(), object cannot be NULL"); + + // allocate memory for new object + dsssframe64sync q_copy = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); + + // copy entire memory space over and overwrite values as needed + memmove(q_copy, q_orig, sizeof(struct dsssframe64sync_s)); + + // set callback and userdata fields + q_copy->callback = q_orig->callback; + q_copy->userdata = q_orig->userdata; + + // copy objects + q_copy->detector = qdetector_cccf_copy(q_orig->detector); + q_copy->mixer = nco_crcf_copy (q_orig->mixer); + q_copy->mf = firpfb_crcf_copy (q_orig->mf); + q_copy->dec = qpacketmodem_copy (q_orig->dec); + q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); + + return q_copy; +} + +// destroy frame synchronizer object, freeing all internal memory +int dsssframe64sync_destroy(dsssframe64sync _q) +{ + // destroy synchronization objects + qdetector_cccf_destroy(_q->detector); // frame detector + firpfb_crcf_destroy (_q->mf); // matched filter + nco_crcf_destroy (_q->mixer); // coarse NCO + qpacketmodem_destroy (_q->dec); // payload demodulator + qpilotsync_destroy (_q->pilotsync); // pilot synchronizer + + // free main object memory + free(_q); + return LIQUID_OK; +} + +// print frame synchronizer object internals +int dsssframe64sync_print(dsssframe64sync _q) +{ + printf("dsssframe64sync:\n"); + return framedatastats_print(&_q->framedatastats); +} + +// reset frame synchronizer object +int dsssframe64sync_reset(dsssframe64sync _q) +{ + // reset binary pre-demod synchronizer + qdetector_cccf_reset(_q->detector); + + // reset carrier recovery objects + nco_crcf_reset(_q->mixer); + + // reset symbol timing recovery state + firpfb_crcf_reset(_q->mf); + + // reset state + _q->state = dsssframe64sync_STATE_DETECTFRAME; + _q->preamble_counter= 0; + _q->payload_counter = 0; + + // reset frame statistics + _q->framesyncstats.evm = 0.0f; + + return LIQUID_OK; +} + +// set the callback function +int dsssframe64sync_set_callback(dsssframe64sync _q, + framesync_callback _callback) +{ + _q->callback = _callback; + return LIQUID_OK; +} + +// set the user-defined data field (context) +int dsssframe64sync_set_userdata(dsssframe64sync _q, + void * _userdata) +{ + _q->userdata = _userdata; + return LIQUID_OK; +} + +// execute frame synchronizer +// _q : frame synchronizer object +// _x : input sample array [size: _n x 1] +// _n : number of input samples +int dsssframe64sync_execute(dsssframe64sync _q, + float complex * _x, + unsigned int _n) +{ + unsigned int i; + for (i=0; i<_n; i++) { + switch (_q->state) { + case dsssframe64sync_STATE_DETECTFRAME: + // detect frame (look for p/n sequence) + dsssframe64sync_execute_seekpn(_q, _x[i]); + break; + case dsssframe64sync_STATE_RXPREAMBLE: + // receive p/n sequence symbols + dsssframe64sync_execute_rxpreamble(_q, _x[i]); + break; + case dsssframe64sync_STATE_RXPAYLOAD: + // receive payload symbols + dsssframe64sync_execute_rxpayload(_q, _x[i]); + break; + default: + return liquid_error(LIQUID_EINT,"dsssframe64sync_exeucte(), unknown/unsupported state"); + } + } + return LIQUID_OK; +} + +// +// internal methods +// + +// execute synchronizer, seeking p/n sequence +// _q : frame synchronizer object +// _x : input sample +// _sym : demodulated symbol +int dsssframe64sync_execute_seekpn(dsssframe64sync _q, + float complex _x) +{ + // push through pre-demod synchronizer + float complex * v = qdetector_cccf_execute(_q->detector, _x); + + // check if frame has been detected + if (v != NULL) { + // get estimates + _q->tau_hat = qdetector_cccf_get_tau (_q->detector); + _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); + _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); + _q->phi_hat = qdetector_cccf_get_phi (_q->detector); + //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", + // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); + + // set appropriate filterbank index + if (_q->tau_hat > 0) { + _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; + _q->mf_counter = 0; + } else { + _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; + _q->mf_counter = 1; + } + + // output filter scale + firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); + + // set frequency/phase of mixer + nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); + nco_crcf_set_phase (_q->mixer, _q->phi_hat ); + + // update state + _q->state = dsssframe64sync_STATE_RXPREAMBLE; + + // run buffered samples through synchronizer + unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); + dsssframe64sync_execute(_q, v, buf_len); + } + return LIQUID_OK; +} + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +// _y : output symbol +int dsssframe64sync_step(dsssframe64sync _q, + float complex _x, + float complex * _y) +{ + // mix sample down + float complex v; + nco_crcf_mix_down(_q->mixer, _x, &v); + nco_crcf_step (_q->mixer); + + // push sample into filterbank + firpfb_crcf_push (_q->mf, v); + firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); + + // increment counter to determine if sample is available + _q->mf_counter++; + int sample_available = (_q->mf_counter >= 1) ? 1 : 0; + + // set output sample if available + if (sample_available) { + + // set output + *_y = v; + + // decrement counter by k=2 samples/symbol + _q->mf_counter -= 2; + } + + // return flag + return sample_available; +} + +// execute synchronizer, receiving p/n sequence +// _q : frame synchronizer object +// _x : input sample +// _sym : demodulated symbol +int dsssframe64sync_execute_rxpreamble(dsssframe64sync _q, + float complex _x) +{ + // step synchronizer + float complex mf_out = 0.0f; + int sample_available = dsssframe64sync_step(_q, _x, &mf_out); + + // compute output if timeout + if (sample_available) { + + // save output in p/n symbols buffer + unsigned int delay = 2*_q->m; // delay from matched filter + if (_q->preamble_counter >= delay) { + unsigned int index = _q->preamble_counter-delay; + + _q->preamble_rx[index] = mf_out; + } + + // update p/n counter + _q->preamble_counter++; + + // update state + if (_q->preamble_counter == 64 + delay) + _q->state = dsssframe64sync_STATE_RXPAYLOAD; + } + return LIQUID_OK; +} + +// execute synchronizer, receiving payload +// _q : frame synchronizer object +// _x : input sample +// _sym : demodulated symbol +int dsssframe64sync_execute_rxpayload(dsssframe64sync _q, + float complex _x) +{ + // step synchronizer + float complex mf_out = 0.0f; + int sample_available = dsssframe64sync_step(_q, _x, &mf_out); + + // compute output if timeout + if (sample_available) { + // save payload symbols (modem input/output) + _q->payload_rx[_q->payload_counter] = mf_out; + + // increment counter + _q->payload_counter++; + + if (_q->payload_counter == 630) { + // recover data symbols from pilots + qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); + + // decode payload + _q->payload_valid = qpacketmodem_decode(_q->dec, + _q->payload_sym, + _q->payload_dec); + + // update statistics + _q->framedatastats.num_frames_detected++; + _q->framedatastats.num_headers_valid += _q->payload_valid; + _q->framedatastats.num_payloads_valid += _q->payload_valid; + _q->framedatastats.num_bytes_received += _q->payload_valid ? 64 : 0; + + // invoke callback + if (_q->callback != NULL) { + // set framesyncstats internals + _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); + _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); + _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); + _q->framesyncstats.framesyms = _q->payload_sym; + _q->framesyncstats.num_framesyms = 600; + _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; + _q->framesyncstats.mod_bps = 2; + _q->framesyncstats.check = LIQUID_CRC_24; + _q->framesyncstats.fec0 = LIQUID_FEC_NONE; + _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; + + // invoke callback method + int rc = + _q->callback(&_q->payload_dec[0], // header is first 8 bytes + _q->payload_valid, + &_q->payload_dec[8], // payload is last 64 bytes + 64, + _q->payload_valid, + _q->framesyncstats, + _q->userdata); + } + + // reset frame synchronizer + return dsssframe64sync_reset(_q); + } + } + return LIQUID_OK; +} + +// DEPRECATED: enable debugging +int dsssframe64sync_debug_enable(dsssframe64sync _q) +{ + return LIQUID_OK; +} + +// DEPRECATED: disable debugging +int dsssframe64sync_debug_disable(dsssframe64sync _q) +{ + return LIQUID_OK; +} + +// DEPRECATED: print debugging information +int dsssframe64sync_debug_print(dsssframe64sync _q, + const char * _filename) +{ + return LIQUID_OK; +} + +// get detection threshold +float dsssframe64sync_get_threshold(dsssframe64sync _q) +{ + return qdetector_cccf_get_threshold(_q->detector); +} + +// set detection threshold +int dsssframe64sync_set_threshold(dsssframe64sync _q, + float _threshold) +{ + return qdetector_cccf_set_threshold(_q->detector, _threshold); +} + +// reset frame data statistics +int dsssframe64sync_reset_framedatastats(dsssframe64sync _q) +{ + return framedatastats_reset(&_q->framedatastats); +} + +// retrieve frame data statistics +framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q) +{ + return _q->framedatastats; +} + From 5191a9b7d4e30a5875d118adba24ca68090baf32 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Oct 2022 10:08:16 -0400 Subject: [PATCH 004/334] qdsync: adding new object to support both detection and tracking --- examples/qdsync_cccf_example.c | 86 +++++++++++++++++++ include/liquid.h | 46 ++++++++++ makefile.in | 2 + src/framing/src/qdsync_cccf.c | 150 +++++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 examples/qdsync_cccf_example.c create mode 100644 src/framing/src/qdsync_cccf.c diff --git a/examples/qdsync_cccf_example.c b/examples/qdsync_cccf_example.c new file mode 100644 index 000000000..12db10063 --- /dev/null +++ b/examples/qdsync_cccf_example.c @@ -0,0 +1,86 @@ +// This example demonstrates the functionality of the qdsync object to +// detect and synchronize an arbitrary signal in time in the presence of noise, +// carrier frequency/phase offsets, and fractional-sample timing offsets. +// offsets. +#include +#include +#include +#include +#include +#include +#include "liquid.h" + +#define OUTPUT_FILENAME "qdsync_cccf_example.m" + +// synchronization callback, return 0:continue, 1:reset +int callback(float complex * _buf, + unsigned int _buf_len, + void * _context) +{ printf("callback got %u samples\n", _buf_len); return 0; } + +int main(int argc, char*argv[]) +{ + // options + unsigned int sequence_len = 80; // number of sync symbols + unsigned int k = 2; // samples/symbol + unsigned int m = 7; // filter delay [symbols] + float beta = 0.3f; // excess bandwidth factor + int ftype = LIQUID_FIRFILT_ARKAISER; + float nstd = 0.1f; + + unsigned int i; + + // generate synchronization sequence (QPSK symbols) + unsigned int seq_len = k*(sequence_len + 2*m); + float complex seq[seq_len]; + firinterp_crcf interp = firinterp_crcf_create_prototype(ftype,k,m,beta,0); + for (i=0; i +#include +#include +#include +#include + +#include "liquid.internal.h" + +// main object definition +struct qdsync_cccf_s { + qdsync_callback callback; // + void * context; // + qdetector_cccf detector; // detector + // resampler +}; + +// create detector with generic sequence +// _s : sample sequence +// _s_len : length of sample sequence +qdsync_cccf qdsync_cccf_create(float complex * _s, + unsigned int _s_len, + qdsync_callback _callback, + void * _context) +{ + // validate input + if (_s_len == 0) + return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); + + // allocate memory for main object and set internal properties + qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); + + // create detector + q->detector = qdetector_cccf_create(_s, _s_len); + + // set callback and context values + qdsync_cccf_set_callback(q, _callback); + qdsync_cccf_set_context (q, _context ); + + // reset and return object + qdsync_cccf_reset(q); + return q; +} + +// copy object +qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); + + // create new object and copy base parameters + qdsync_cccf q_copy = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); + memmove(q_copy, q_orig, sizeof(struct qdsync_cccf_s)); + + // copy sub-objects + q_copy->detector = qdetector_cccf_copy(q_orig->detector); + + // return new object + return q_copy; +} + +int qdsync_cccf_destroy(qdsync_cccf _q) +{ + // destroy internal objects + qdetector_cccf_destroy(_q->detector); + + // free main object memory + free(_q); + return LIQUID_OK; +} + +int qdsync_cccf_print(qdsync_cccf _q) +{ + printf("\n"); + return LIQUID_OK; +} + +int qdsync_cccf_reset(qdsync_cccf _q) +{ + return LIQUID_OK; +} + +int qdsync_cccf_execute(qdsync_cccf _q, + liquid_float_complex * _buf, + unsigned int _buf_len) +{ + // TODO: switch based on state + unsigned int i; + for (i=0; i<_buf_len; i++) { + void * p = qdetector_cccf_execute(_q->detector, _buf[i]); + if (p != NULL) + _q->callback(NULL, 0, _q->context); + } + return LIQUID_OK; +} + +// get detection threshold +float qdsync_cccf_get_threshold(qdsync_cccf _q) +{ + return qdetector_cccf_get_threshold(_q->detector); +} + +// set detection threshold +int qdsync_cccf_set_threshold(qdsync_cccf _q, + float _threshold) +{ + return qdetector_cccf_set_threshold(_q->detector, _threshold); +} + +// set callback method +int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback) +{ + _q->callback = _callback; + return LIQUID_OK; +} + +// set context value +int qdsync_cccf_set_context (qdsync_cccf _q, void * _context) +{ + _q->context = _context; + return LIQUID_OK; +} + From 3777df4bdb3f9880341a8476353199eb2346b8af Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Oct 2022 11:33:01 -0400 Subject: [PATCH 005/334] qdsync: putting basic hooks to pass information back to caller --- examples/qdsync_cccf_example.c | 27 +++++++++++++++------------ src/framing/src/qdsync_cccf.c | 28 +++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/examples/qdsync_cccf_example.c b/examples/qdsync_cccf_example.c index 12db10063..5c98ac5b5 100644 --- a/examples/qdsync_cccf_example.c +++ b/examples/qdsync_cccf_example.c @@ -16,7 +16,13 @@ int callback(float complex * _buf, unsigned int _buf_len, void * _context) -{ printf("callback got %u samples\n", _buf_len); return 0; } +{ + printf("callback got %u samples\n", _buf_len); + unsigned int i; + for (i=0; i<_buf_len; i++) + fprintf((FILE*)_context, "y(end+1) = %12.8f + %12.8fj;\n", crealf(_buf[i]), cimagf(_buf[i])); + return 0; +} int main(int argc, char*argv[]) { @@ -26,7 +32,7 @@ int main(int argc, char*argv[]) unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; - float nstd = 0.1f; + float nstd = 0.01f; unsigned int i; @@ -41,13 +47,18 @@ int main(int argc, char*argv[]) } firinterp_crcf_destroy(interp); + // open file for storing results + FILE * fid = fopen(OUTPUT_FILENAME,"w"); + fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all; close all; y=[];\n"); + // create sync object - qdsync_cccf q = qdsync_cccf_create(seq, seq_len, callback, NULL); + qdsync_cccf q = qdsync_cccf_create(seq, seq_len, callback, fid); qdsync_cccf_print(q); // float complex buf[seq_len]; - for (i=0; i<200; i++) { + for (i=0; i<20; i++) { if (i==10) memmove(buf, seq, seq_len*sizeof(float complex)); else memset (buf, 0x00, seq_len*sizeof(float complex)); @@ -59,17 +70,9 @@ int main(int argc, char*argv[]) // run through synchronizer qdsync_cccf_execute(q, buf, seq_len); } - qdsync_cccf_destroy(q); // export results - FILE * fid = fopen(OUTPUT_FILENAME,"w"); - fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); - fprintf(fid,"clear all\n"); - fprintf(fid,"close all\n"); - //fprintf(fid,"sequence_len= %u;\n", sequence_len); - //fprintf(fid,"num_samples = %u;\n", num_samples); - fprintf(fid,"s = [];\n"); for (i=0; istate = QDSYNC_STATE_DETECT; return LIQUID_OK; } @@ -113,10 +120,25 @@ int qdsync_cccf_execute(qdsync_cccf _q, { // TODO: switch based on state unsigned int i; + void * p = NULL; for (i=0; i<_buf_len; i++) { - void * p = qdetector_cccf_execute(_q->detector, _buf[i]); - if (p != NULL) - _q->callback(NULL, 0, _q->context); + switch (_q->state) { + case QDSYNC_STATE_DETECT: + p = qdetector_cccf_execute(_q->detector, _buf[i]); + if (p != NULL) { + if (_q->callback != NULL) + _q->callback(NULL, 0, _q->context); + _q->state = QDSYNC_STATE_SYNC; + } + break; + case QDSYNC_STATE_SYNC: + if (_q->callback != NULL) { + _q->callback(_buf, _buf_len, _q->context); + return LIQUID_OK; + } + break; + default:; + } } return LIQUID_OK; } From bb2cef7a782ff3dc125b9611984075ff5c9316cb Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Oct 2022 15:57:35 -0400 Subject: [PATCH 006/334] qdsync: refactoring to work with linear modulated signals --- examples/qdsync_cccf_example.c | 56 ++++---- include/liquid.h | 12 +- src/framing/src/framesync64.c | 2 +- src/framing/src/qdsync_cccf.c | 226 +++++++++++++++++++++++++++++---- 4 files changed, 237 insertions(+), 59 deletions(-) diff --git a/examples/qdsync_cccf_example.c b/examples/qdsync_cccf_example.c index 5c98ac5b5..3b04f02e1 100644 --- a/examples/qdsync_cccf_example.c +++ b/examples/qdsync_cccf_example.c @@ -27,25 +27,20 @@ int callback(float complex * _buf, int main(int argc, char*argv[]) { // options - unsigned int sequence_len = 80; // number of sync symbols + unsigned int seq_len = 80; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float nstd = 0.01f; - unsigned int i; - // generate synchronization sequence (QPSK symbols) - unsigned int seq_len = k*(sequence_len + 2*m); float complex seq[seq_len]; - firinterp_crcf interp = firinterp_crcf_create_prototype(ftype,k,m,beta,0); - for (i=0; imixer = nco_crcf_create(LIQUID_NCO); - + // create payload demodulator/decoder object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 3013a5f3c..ad6c8668b 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -33,37 +33,94 @@ #include "liquid.internal.h" +// push samples through detection stage +int qdsync_cccf_execute_detect(qdsync_cccf _q, + float complex _x); + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +int qdsync_cccf_step(qdsync_cccf _q, + float complex _x); + +// append sample to output buffer +int qdsync_cccf_buf_append(qdsync_cccf _q, + float complex _x); + // main object definition struct qdsync_cccf_s { + unsigned int seq_len; // preamble sequence length + int ftype; // + unsigned int k; // + unsigned int m; // + float beta; // + qdsync_callback callback; // void * context; // qdetector_cccf detector; // detector + // status variables enum { QDSYNC_STATE_DETECT=0, // detect frame - QDSYNC_STATE_SYNC, // synchronize samples - } state; - // resampler - // nco + QDSYNC_STATE_SYNC, // + } state; // frame synchronization state + unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence + + // estimated offsets + float tau_hat; // + float gamma_hat; // + float dphi_hat; // + float phi_hat; // + + nco_crcf mixer; // coarse carrier frequency recovery + + // timing recovery objects, states + firpfb_crcf mf; // matched filter decimator + unsigned int npfb; // number of filters in symsync + int mf_counter; // matched filter output timer + unsigned int pfb_index; // filterbank index + + // symbol buffer + unsigned int buf_out_len;// output buffer length + float complex * buf_out; // output buffer + unsigned int buf_out_counter; // output counter }; // create detector with generic sequence -// _s : sample sequence -// _s_len : length of sample sequence -qdsync_cccf qdsync_cccf_create(float complex * _s, - unsigned int _s_len, - qdsync_callback _callback, - void * _context) +qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, + unsigned int _seq_len, + int _ftype, + unsigned int _k, + unsigned int _m, + float _beta, + qdsync_callback _callback, + void * _context) { // validate input - if (_s_len == 0) + if (_seq_len == 0) return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); - + // allocate memory for main object and set internal properties qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); + q->seq_len = _seq_len; + q->ftype = _ftype; + q->k = _k; + q->m = _m; + q->beta = _beta; // create detector - q->detector = qdetector_cccf_create(_s, _s_len); + q->detector = qdetector_cccf_create_linear(_seq, _seq_len, _ftype, _k, _m, _beta); + + // create down-coverters for carrier phase tracking + q->mixer = nco_crcf_create(LIQUID_NCO); + + // create symbol timing recovery filters + q->npfb = 256; // number of filters in the bank + q->mf = firpfb_crcf_create_rnyquist(q->ftype, q->npfb, q->k, q->m, q->beta); + + // allocate buffer for storing output samples + q->buf_out_len = 64; // TODO: make user-defined? + q->buf_out = (float complex*) malloc(q->buf_out_len*sizeof(float complex)); // set callback and context values qdsync_cccf_set_callback(q, _callback); @@ -77,6 +134,7 @@ qdsync_cccf qdsync_cccf_create(float complex * _s, // copy object qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) { +#if 0 // validate input if (q_orig == NULL) return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); @@ -90,12 +148,20 @@ qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) // return new object return q_copy; +#else + return liquid_error_config("qdsync_cccf_copy(), method not yet implemented"); +#endif } int qdsync_cccf_destroy(qdsync_cccf _q) { // destroy internal objects qdetector_cccf_destroy(_q->detector); + nco_crcf_destroy(_q->mixer); + firpfb_crcf_destroy(_q->mf); + + // free output buffer + free(_q->buf_out); // free main object memory free(_q); @@ -110,7 +176,11 @@ int qdsync_cccf_print(qdsync_cccf _q) int qdsync_cccf_reset(qdsync_cccf _q) { + qdetector_cccf_reset(_q->detector); _q->state = QDSYNC_STATE_DETECT; + _q->symbol_counter = 0; + _q->buf_out_counter = 0; + firpfb_crcf_reset(_q->mf); return LIQUID_OK; } @@ -118,26 +188,19 @@ int qdsync_cccf_execute(qdsync_cccf _q, liquid_float_complex * _buf, unsigned int _buf_len) { - // TODO: switch based on state unsigned int i; - void * p = NULL; for (i=0; i<_buf_len; i++) { switch (_q->state) { case QDSYNC_STATE_DETECT: - p = qdetector_cccf_execute(_q->detector, _buf[i]); - if (p != NULL) { - if (_q->callback != NULL) - _q->callback(NULL, 0, _q->context); - _q->state = QDSYNC_STATE_SYNC; - } + // detect frame (look for p/n sequence) + qdsync_cccf_execute_detect(_q, _buf[i]); break; case QDSYNC_STATE_SYNC: - if (_q->callback != NULL) { - _q->callback(_buf, _buf_len, _q->context); - return LIQUID_OK; - } + // receive preamble sequence symbols + qdsync_cccf_step(_q, _buf[i]); break; - default:; + default: + return liquid_error(LIQUID_EINT,"qdsync_cccf_exeucte(), unknown/unsupported state"); } } return LIQUID_OK; @@ -170,3 +233,114 @@ int qdsync_cccf_set_context (qdsync_cccf _q, void * _context) return LIQUID_OK; } +// +// internal methods +// + +// execute synchronizer, seeking preamble sequence +// _q : frame synchronizer object +// _x : input sample +// _sym : demodulated symbol +int qdsync_cccf_execute_detect(qdsync_cccf _q, + float complex _x) +{ + // push through pre-demod synchronizer + float complex * v = qdetector_cccf_execute(_q->detector, _x); + + // check if frame has been detected + if (v != NULL) { + // get estimates + _q->tau_hat = qdetector_cccf_get_tau (_q->detector); + _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); + _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); + _q->phi_hat = qdetector_cccf_get_phi (_q->detector); + //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", + // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); + + // set appropriate filterbank index + if (_q->tau_hat > 0) { + _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; + _q->mf_counter = 0; + } else { + _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; + _q->mf_counter = 1; + } + + // output filter scale + firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); + + // set frequency/phase of mixer + nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); + nco_crcf_set_phase (_q->mixer, _q->phi_hat ); + + // update state + _q->state = QDSYNC_STATE_SYNC; + + // run buffered samples through synchronizer + unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); + qdsync_cccf_execute(_q, v, buf_len); + } + return LIQUID_OK; +} + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +// _y : output symbol +int qdsync_cccf_step(qdsync_cccf _q, + float complex _x) +{ + // mix sample down + float complex v; + nco_crcf_mix_down(_q->mixer, _x, &v); + nco_crcf_step (_q->mixer); + + // push sample into filterbank + firpfb_crcf_push (_q->mf, v); + firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); + + // increment counter to determine if sample is available + _q->mf_counter++; + int sample_available = (_q->mf_counter >= 1) ? 1 : 0; + + // set output sample if available + if (sample_available) { + // decrement counter by k=2 samples/symbol + _q->mf_counter -= 2; + + // append to output + qdsync_cccf_buf_append(_q, v); + } + + // return flag + return LIQUID_OK; +} + +// append sample to output buffer +int qdsync_cccf_buf_append(qdsync_cccf _q, + float complex _x) +{ + // account for filter delay + _q->symbol_counter++; + if (_q->symbol_counter <= 2*_q->m) + return LIQUID_OK; + + // append sample to end of buffer + _q->buf_out[_q->buf_out_counter] = _x; + _q->buf_out_counter++; + + // check if buffer is full + if (_q->buf_out_counter == _q->buf_out_len) { + // reset counter + _q->buf_out_counter = 0; + + // invoke callback + if (_q->callback != NULL) { + int rc = _q->callback(_q->buf_out, _q->buf_out_len, _q->context); + if (rc) + return qdsync_cccf_reset(_q); + } + } + return LIQUID_OK; +} + From 56d237bf0329fe9cad1f71f5768cb7401f8acfb4 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 16 Oct 2022 12:18:11 -0400 Subject: [PATCH 007/334] dsssframe64sync: completing methods to decode frame; not yet valid --- examples/dsssframe64sync_example.c | 21 +- src/framing/src/dsssframe64gen.c | 8 +- src/framing/src/dsssframe64sync.c | 449 ++++++++++------------------- 3 files changed, 173 insertions(+), 305 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index 77592a0a6..7538a90c4 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -10,6 +10,20 @@ #include "liquid.h" +// static callback function +static int callback(unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata) +{ + printf("*** callback invoked (%s)***\n", _payload_valid ? "pass" : "FAIL"); + framesyncstats_print(&_stats); + return 0; +} + int main(int argc, char *argv[]) { // options @@ -30,9 +44,14 @@ int main(int argc, char *argv[]) dsssframe64gen_assemble(fg, NULL, NULL); dsssframe64gen_write(fg, buf_tx, buf_len); - // channel + // TODO: apply channel memmove(buf_rx, buf_tx, buf_len*sizeof(float complex)); + // run through sync + dsssframe64sync fs = dsssframe64sync_create(callback, NULL); + dsssframe64sync_execute(fs, buf_rx, buf_len); + dsssframe64sync_destroy(fs); + // push resulting sample through periodogram spgramcf_write(periodogram, buf_tx, buf_len); float psd[nfft]; diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 3532fec04..4f1fec8bb 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -36,7 +36,7 @@ struct dsssframe64gen_s { qpacketmodem enc; // packet encoder/modulator qpilotgen pilotgen; // pilot symbol generator msequence ms; // spreading sequence generator - float complex pn_sequence[1024]; // 1024-symbol p/n sequence + float complex preamble_pn[1024]; // 1024-symbol p/n sequence unsigned char payload_dec[ 150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol float complex payload_sym[ 600]; // modulated payload symbols float complex payload_tx [ 630]; // modulated payload symbols with pilots @@ -59,8 +59,8 @@ dsssframe64gen dsssframe64gen_create() // generate p/n sequence q->ms = msequence_create(11, 0x0805, 1); for (i=0; i<1024; i++) { - q->pn_sequence[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); - q->pn_sequence[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; + q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); + q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } // create payload encoder/modulator object @@ -159,7 +159,7 @@ int dsssframe64gen_write(dsssframe64gen _q, // p/n sequence for (i=0; i<1024; i++) { - firinterp_crcf_execute(_q->interp, _q->pn_sequence[i], &_buf[n]); + firinterp_crcf_execute(_q->interp, _q->preamble_pn[i], &_buf[n]); n+=2; } diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 892251816..b1f55d23d 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -31,72 +31,47 @@ #include "liquid.internal.h" -#define dsssframe64sync_ENABLE_EQ 0 - -// push samples through detection stage -int dsssframe64sync_execute_seekpn(dsssframe64sync _q, - float complex _x); - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -// _y : output symbol +// internal update int dsssframe64sync_step(dsssframe64sync _q, - float complex _x, - float complex * _y); - -// push samples through synchronizer, saving received p/n symbols -int dsssframe64sync_execute_rxpreamble(dsssframe64sync _q, - float complex _x); + float complex * _buf, + unsigned int _buf_len); -// receive payload symbols -int dsssframe64sync_execute_rxpayload(dsssframe64sync _q, - float complex _x); +// internal decode received frame, update statistics, invoke callback +int dsssframe64sync_decode(dsssframe64sync _q); -// export debugging based on return value -// 0 : do not write file -// >0 : write specific number (hex) -// -1 : number of packets detected -// -2 : id using first 4 bytes of header -// -3 : write with random extension -int dsssframe64sync_debug_export(dsssframe64sync _q, int _code); +// internal synchronization callback, return 0:continue, 1:reset +int dsssframe64sync_callback_internal(float complex * _buf, + unsigned int _buf_len, + void * _context) +{ return dsssframe64sync_step((dsssframe64sync) _context, _buf, _buf_len); } // dsssframe64sync object structure struct dsssframe64sync_s { // callback framesync_callback callback; // user-defined callback function - void * userdata; // user-defined data structure + void * context; // user-defined data structure + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor + framesyncstats_s framesyncstats; // frame statistic object (synchronizer) framedatastats_s framedatastats; // frame statistic object (packet statistics) - // synchronizer objects - unsigned int m; // filter delay (symbols) - float beta; // filter excess bandwidth factor - qdetector_cccf detector; // pre-demod detector - float tau_hat; // fractional timing offset estimate - float dphi_hat; // carrier frequency offset estimate - float phi_hat; // carrier phase offset estimate - float gamma_hat; // channel gain estimate - nco_crcf mixer; // coarse carrier frequency recovery - - // timing recovery objects, states - firpfb_crcf mf; // matched filter decimator - unsigned int npfb; // number of filters in symsync - int mf_counter; // matched filter output timer - unsigned int pfb_index; // filterbank index - // preamble - float complex preamble_pn[64]; // known 64-symbol p/n sequence - float complex preamble_rx[64]; // received p/n symbols - + float complex preamble_pn[1024]; // known 1024-symbol p/n sequence + float complex preamble_rx[1024]; // received p/n symbols + // payload decoder float complex payload_rx [630]; // received payload symbols with pilots float complex payload_sym[600]; // received payload symbols unsigned char payload_dec[ 72]; // decoded payload bytes + + qdsync_cccf detector; // frame detector + msequence ms; // spreading sequence generator + float complex sym_despread; // despread symbol + qpacketmodem dec; // packet demodulator/decoder qpilotsync pilotsync; // pilot extraction, carrier recovery - int payload_valid; // did payload pass crc? - + // status variables enum { dsssframe64sync_STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) @@ -104,43 +79,37 @@ struct dsssframe64sync_s { dsssframe64sync_STATE_RXPAYLOAD, // receive payload data } state; unsigned int preamble_counter; // counter: num of p/n syms received + unsigned int chip_counter; // counter: num of payload chips received for a single symbol unsigned int payload_counter; // counter: num of payload syms received }; // create dsssframe64sync object // _callback : callback function invoked when frame is received -// _userdata : user-defined data object passed to callback +// _context : user-defined data object passed to callback dsssframe64sync dsssframe64sync_create(framesync_callback _callback, - void * _userdata) + void * _context) { dsssframe64sync q = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); q->callback = _callback; - q->userdata = _userdata; - q->m = 7; // filter delay (symbols) - q->beta = 0.3f; // excess bandwidth factor + q->context = _context; + q->m = 15; // filter delay (symbols) + q->beta = 0.20f;// excess bandwidth factor unsigned int i; // generate p/n sequence - msequence ms = msequence_create(7, 0x0089, 1); - for (i=0; i<64; i++) { - q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); - q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; + q->ms = msequence_create(11, 0x0805, 1); + for (i=0; i<1024; i++) { + q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); + q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } - msequence_destroy(ms); // create frame detector - unsigned int k = 2; // samples/symbol - q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta); - qdetector_cccf_set_threshold(q->detector, 0.5f); - - // create symbol timing recovery filters - q->npfb = 32; // number of filters in the bank - q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,k,q->m,q->beta); + unsigned int k = 2; // samples/symbol + q->detector = qdsync_cccf_create_linear(q->preamble_pn, 1024, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta, + dsssframe64sync_callback_internal, (void*)q); + qdsync_cccf_set_threshold(q->detector, 0.5f); - // create down-coverters for carrier phase tracking - q->mixer = nco_crcf_create(LIQUID_NCO); - // create payload demodulator/decoder object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; @@ -154,7 +123,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, // create pilot synchronizer q->pilotsync = qpilotsync_create(600, 21); assert( qpilotsync_get_frame_len(q->pilotsync)==630); - + // reset global data counters dsssframe64sync_reset_framedatastats(q); @@ -166,6 +135,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, // copy object dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) { +#if 0 // validate input if (q_orig == NULL) return liquid_error_config("dsssframe64sync_copy(), object cannot be NULL"); @@ -176,29 +146,29 @@ dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) // copy entire memory space over and overwrite values as needed memmove(q_copy, q_orig, sizeof(struct dsssframe64sync_s)); - // set callback and userdata fields + // set callback and context fields q_copy->callback = q_orig->callback; - q_copy->userdata = q_orig->userdata; + q_copy->context = q_orig->context; // copy objects - q_copy->detector = qdetector_cccf_copy(q_orig->detector); - q_copy->mixer = nco_crcf_copy (q_orig->mixer); - q_copy->mf = firpfb_crcf_copy (q_orig->mf); + q_copy->detector = qdsync_cccf_copy(q_orig->detector); q_copy->dec = qpacketmodem_copy (q_orig->dec); q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); return q_copy; +#else + return liquid_error_config("dsssframe64sync_copy(), method not yet implemented"); +#endif } // destroy frame synchronizer object, freeing all internal memory int dsssframe64sync_destroy(dsssframe64sync _q) { // destroy synchronization objects - qdetector_cccf_destroy(_q->detector); // frame detector - firpfb_crcf_destroy (_q->mf); // matched filter - nco_crcf_destroy (_q->mixer); // coarse NCO - qpacketmodem_destroy (_q->dec); // payload demodulator - qpilotsync_destroy (_q->pilotsync); // pilot synchronizer + msequence_destroy (_q->ms); // + qdsync_cccf_destroy (_q->detector); // frame detector + qpacketmodem_destroy(_q->dec); // payload demodulator + qpilotsync_destroy (_q->pilotsync); // pilot synchronizer // free main object memory free(_q); @@ -208,27 +178,23 @@ int dsssframe64sync_destroy(dsssframe64sync _q) // print frame synchronizer object internals int dsssframe64sync_print(dsssframe64sync _q) { - printf("dsssframe64sync:\n"); - return framedatastats_print(&_q->framedatastats); + printf("\n"); + return LIQUID_OK; } // reset frame synchronizer object int dsssframe64sync_reset(dsssframe64sync _q) { // reset binary pre-demod synchronizer - qdetector_cccf_reset(_q->detector); + qdsync_cccf_reset(_q->detector); - // reset carrier recovery objects - nco_crcf_reset(_q->mixer); - - // reset symbol timing recovery state - firpfb_crcf_reset(_q->mf); - // reset state _q->state = dsssframe64sync_STATE_DETECTFRAME; _q->preamble_counter= 0; + _q->chip_counter = 0; _q->payload_counter = 0; - + _q->sym_despread = 0; + // reset frame statistics _q->framesyncstats.evm = 0.0f; @@ -236,7 +202,7 @@ int dsssframe64sync_reset(dsssframe64sync _q) } // set the callback function -int dsssframe64sync_set_callback(dsssframe64sync _q, +int dsssframe64sync_set_callback(dsssframe64sync _q, framesync_callback _callback) { _q->callback = _callback; @@ -244,10 +210,10 @@ int dsssframe64sync_set_callback(dsssframe64sync _q, } // set the user-defined data field (context) -int dsssframe64sync_set_userdata(dsssframe64sync _q, - void * _userdata) +int dsssframe64sync_set_context(dsssframe64sync _q, + void * _context) { - _q->userdata = _userdata; + _q->context= _context; return LIQUID_OK; } @@ -255,10 +221,11 @@ int dsssframe64sync_set_userdata(dsssframe64sync _q, // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples -int dsssframe64sync_execute(dsssframe64sync _q, - float complex * _x, - unsigned int _n) +int dsssframe64sync_execute(dsssframe64sync _q, + float complex * _buf, + unsigned int _buf_len) { +#if 0 unsigned int i; for (i=0; i<_n; i++) { switch (_q->state) { @@ -278,222 +245,23 @@ int dsssframe64sync_execute(dsssframe64sync _q, return liquid_error(LIQUID_EINT,"dsssframe64sync_exeucte(), unknown/unsupported state"); } } - return LIQUID_OK; -} - -// -// internal methods -// - -// execute synchronizer, seeking p/n sequence -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int dsssframe64sync_execute_seekpn(dsssframe64sync _q, - float complex _x) -{ - // push through pre-demod synchronizer - float complex * v = qdetector_cccf_execute(_q->detector, _x); - - // check if frame has been detected - if (v != NULL) { - // get estimates - _q->tau_hat = qdetector_cccf_get_tau (_q->detector); - _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); - _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); - _q->phi_hat = qdetector_cccf_get_phi (_q->detector); - //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", - // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); - - // set appropriate filterbank index - if (_q->tau_hat > 0) { - _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; - _q->mf_counter = 0; - } else { - _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; - _q->mf_counter = 1; - } - - // output filter scale - firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); - - // set frequency/phase of mixer - nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); - nco_crcf_set_phase (_q->mixer, _q->phi_hat ); - - // update state - _q->state = dsssframe64sync_STATE_RXPREAMBLE; - - // run buffered samples through synchronizer - unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); - dsssframe64sync_execute(_q, v, buf_len); - } - return LIQUID_OK; -} - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -// _y : output symbol -int dsssframe64sync_step(dsssframe64sync _q, - float complex _x, - float complex * _y) -{ - // mix sample down - float complex v; - nco_crcf_mix_down(_q->mixer, _x, &v); - nco_crcf_step (_q->mixer); - - // push sample into filterbank - firpfb_crcf_push (_q->mf, v); - firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); - - // increment counter to determine if sample is available - _q->mf_counter++; - int sample_available = (_q->mf_counter >= 1) ? 1 : 0; - - // set output sample if available - if (sample_available) { - - // set output - *_y = v; - - // decrement counter by k=2 samples/symbol - _q->mf_counter -= 2; - } - - // return flag - return sample_available; -} - -// execute synchronizer, receiving p/n sequence -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int dsssframe64sync_execute_rxpreamble(dsssframe64sync _q, - float complex _x) -{ - // step synchronizer - float complex mf_out = 0.0f; - int sample_available = dsssframe64sync_step(_q, _x, &mf_out); - - // compute output if timeout - if (sample_available) { - - // save output in p/n symbols buffer - unsigned int delay = 2*_q->m; // delay from matched filter - if (_q->preamble_counter >= delay) { - unsigned int index = _q->preamble_counter-delay; - - _q->preamble_rx[index] = mf_out; - } - - // update p/n counter - _q->preamble_counter++; - - // update state - if (_q->preamble_counter == 64 + delay) - _q->state = dsssframe64sync_STATE_RXPAYLOAD; - } - return LIQUID_OK; -} - -// execute synchronizer, receiving payload -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int dsssframe64sync_execute_rxpayload(dsssframe64sync _q, - float complex _x) -{ - // step synchronizer - float complex mf_out = 0.0f; - int sample_available = dsssframe64sync_step(_q, _x, &mf_out); - - // compute output if timeout - if (sample_available) { - // save payload symbols (modem input/output) - _q->payload_rx[_q->payload_counter] = mf_out; - - // increment counter - _q->payload_counter++; - - if (_q->payload_counter == 630) { - // recover data symbols from pilots - qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); - - // decode payload - _q->payload_valid = qpacketmodem_decode(_q->dec, - _q->payload_sym, - _q->payload_dec); - - // update statistics - _q->framedatastats.num_frames_detected++; - _q->framedatastats.num_headers_valid += _q->payload_valid; - _q->framedatastats.num_payloads_valid += _q->payload_valid; - _q->framedatastats.num_bytes_received += _q->payload_valid ? 64 : 0; - - // invoke callback - if (_q->callback != NULL) { - // set framesyncstats internals - _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); - _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); - _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); - _q->framesyncstats.framesyms = _q->payload_sym; - _q->framesyncstats.num_framesyms = 600; - _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; - _q->framesyncstats.mod_bps = 2; - _q->framesyncstats.check = LIQUID_CRC_24; - _q->framesyncstats.fec0 = LIQUID_FEC_NONE; - _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; - - // invoke callback method - int rc = - _q->callback(&_q->payload_dec[0], // header is first 8 bytes - _q->payload_valid, - &_q->payload_dec[8], // payload is last 64 bytes - 64, - _q->payload_valid, - _q->framesyncstats, - _q->userdata); - } - - // reset frame synchronizer - return dsssframe64sync_reset(_q); - } - } - return LIQUID_OK; -} - -// DEPRECATED: enable debugging -int dsssframe64sync_debug_enable(dsssframe64sync _q) -{ - return LIQUID_OK; -} - -// DEPRECATED: disable debugging -int dsssframe64sync_debug_disable(dsssframe64sync _q) -{ - return LIQUID_OK; -} - -// DEPRECATED: print debugging information -int dsssframe64sync_debug_print(dsssframe64sync _q, - const char * _filename) -{ +#else + qdsync_cccf_execute(_q->detector, _buf, _buf_len); +#endif return LIQUID_OK; } // get detection threshold float dsssframe64sync_get_threshold(dsssframe64sync _q) { - return qdetector_cccf_get_threshold(_q->detector); + return qdsync_cccf_get_threshold(_q->detector); } // set detection threshold int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold) { - return qdetector_cccf_set_threshold(_q->detector, _threshold); + return qdsync_cccf_set_threshold(_q->detector, _threshold); } // reset frame data statistics @@ -508,3 +276,84 @@ framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q) return _q->framedatastats; } +// internal update +int dsssframe64sync_step(dsssframe64sync _q, + float complex * _buf, + unsigned int _buf_len) +{ + // TODO: do this more efficiently? + unsigned int i; + for (i=0; i<_buf_len; i++) { + // receive preamble + if (_q->preamble_counter < 1024) { + _q->preamble_rx[_q->preamble_counter++] = _buf[i]; + continue; + } + + // generate pseudo-random symbol + unsigned int p = msequence_generate_symbol(_q->ms, 2); + float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); + _q->sym_despread += _buf[i] * conjf(s); + _q->chip_counter++; + + if (_q->chip_counter == 256) { + _q->payload_rx[_q->payload_counter] = _q->sym_despread / 256.0f; + _q->payload_counter++; + _q->chip_counter = 0; + if (_q->payload_counter == 630) { + dsssframe64sync_decode(_q); + return 1; // reset + } + } + } + + return 0; // need more data +} + +// internal decode received frame, update statistics, invoke callback +int dsssframe64sync_decode(dsssframe64sync _q) +{ + printf("dsssframe64sync: frame received!\n"); + + // recover data symbols from pilots + qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); + + // decode payload + int crc_pass = qpacketmodem_decode(_q->dec, _q->payload_sym, _q->payload_dec); + + // update statistics + _q->framedatastats.num_frames_detected++; + _q->framedatastats.num_headers_valid += crc_pass; + _q->framedatastats.num_payloads_valid += crc_pass; + _q->framedatastats.num_bytes_received += crc_pass ? 64 : 0; + + // invoke callback + int rc = 0; + if (_q->callback != NULL) { + // set framesyncstats internals + _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); + _q->framesyncstats.rssi = 0; //20*log10f(qdsync_cccf_get_gamma(_q->detector)); + _q->framesyncstats.cfo = 0; //qdsync_cccf_get_frequency(_q->detector); + _q->framesyncstats.framesyms = _q->payload_sym; + _q->framesyncstats.num_framesyms = 600; + _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; + _q->framesyncstats.mod_bps = 2; + _q->framesyncstats.check = LIQUID_CRC_24; + _q->framesyncstats.fec0 = LIQUID_FEC_NONE; + _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; + + // invoke callback method + rc = _q->callback(&_q->payload_dec[0], // header is first 8 bytes + crc_pass, + &_q->payload_dec[8], // payload is last 64 bytes + 64, + crc_pass, + _q->framesyncstats, + _q->context); + } + + // reset frame synchronizer and return + dsssframe64sync_reset(_q); + return rc; +} + From 4b4f5c42c29d03af204638823490984fcce6c4f1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 16 Oct 2022 16:13:09 -0400 Subject: [PATCH 008/334] dsssframe64sync: fixing frame synchronizer to properly recover data * qdetector clearly the limiting factor in speed, here * qdsync works exactly as expected, and greatly simplifies interface * can probably get away with smaller spreading rate (256) as detection with 1024-chip preamble limits packet decoding down to about -15 dB SNR * increasing preamble will likely slow down processing too much --- examples/dsssframe64sync_example.c | 56 ++++++++++++++++++------------ include/liquid.h | 22 +++++++++++- src/framing/src/dsssframe64gen.c | 1 - src/framing/src/dsssframe64sync.c | 56 +++++++++++++----------------- 4 files changed, 79 insertions(+), 56 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index 7538a90c4..981669af1 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -17,17 +17,27 @@ static int callback(unsigned char * _header, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, - void * _userdata) + void * _context) { printf("*** callback invoked (%s)***\n", _payload_valid ? "pass" : "FAIL"); framesyncstats_print(&_stats); + + // save recovered symbols to file + unsigned int i; + FILE * fid = (FILE*)_context; + for (i=0; i<_stats.num_framesyms; i++) { + fprintf(fid,"s(%3u) = %12.8f + %12.8fj;\n", i+1, + crealf(_stats.framesyms[i]), cimagf(_stats.framesyms[i])); + } return 0; } int main(int argc, char *argv[]) { // options - unsigned int nfft=2400; + unsigned int nfft = 2400; + float SNRdB = -15.0f; + const char * filename = "dsssframe64sync_example.m"; // create dsssframe64gen object dsssframe64gen fg = dsssframe64gen_create(); @@ -37,48 +47,50 @@ int main(int argc, char *argv[]) float complex buf_tx[buf_len]; // transmit buffer float complex buf_rx[buf_len]; // receive buffer (channel output) - // create spectral periodogram for displaying spectrum - spgramcf periodogram = spgramcf_create_default(nfft); + // export results to file + FILE * fid = fopen(filename,"w"); + fprintf(fid,"%% %s : auto-generated file\n", filename); + fprintf(fid,"clear all; close all;\n"); + fprintf(fid,"s=[];\n"); // generate in one step (for now) dsssframe64gen_assemble(fg, NULL, NULL); dsssframe64gen_write(fg, buf_tx, buf_len); - // TODO: apply channel - memmove(buf_rx, buf_tx, buf_len*sizeof(float complex)); + // apply channel (AWGN) + float nstd = powf(10.0f,-SNRdB/20.0f); + unsigned int i; + for (i=0; iinterp); - msequence_reset(_q->ms); // frame_assembled = 1 return LIQUID_OK; diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index b1f55d23d..417c643e3 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -108,7 +108,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, unsigned int k = 2; // samples/symbol q->detector = qdsync_cccf_create_linear(q->preamble_pn, 1024, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta, dsssframe64sync_callback_internal, (void*)q); - qdsync_cccf_set_threshold(q->detector, 0.5f); + qdsync_cccf_set_threshold(q->detector, 0.100f); // create payload demodulator/decoder object int check = LIQUID_CRC_24; @@ -201,6 +201,11 @@ int dsssframe64sync_reset(dsssframe64sync _q) return LIQUID_OK; } +int dsssframe64sync_is_frame_open(dsssframe64sync _q) +{ + return _q->preamble_counter > 0; +} + // set the callback function int dsssframe64sync_set_callback(dsssframe64sync _q, framesync_callback _callback) @@ -218,37 +223,15 @@ int dsssframe64sync_set_context(dsssframe64sync _q, } // execute frame synchronizer -// _q : frame synchronizer object -// _x : input sample array [size: _n x 1] -// _n : number of input samples +// _q : frame synchronizer object +// _buf : input sample array, shape: (_buf_len,) +// _buf_len : number of input samples int dsssframe64sync_execute(dsssframe64sync _q, float complex * _buf, unsigned int _buf_len) { -#if 0 - unsigned int i; - for (i=0; i<_n; i++) { - switch (_q->state) { - case dsssframe64sync_STATE_DETECTFRAME: - // detect frame (look for p/n sequence) - dsssframe64sync_execute_seekpn(_q, _x[i]); - break; - case dsssframe64sync_STATE_RXPREAMBLE: - // receive p/n sequence symbols - dsssframe64sync_execute_rxpreamble(_q, _x[i]); - break; - case dsssframe64sync_STATE_RXPAYLOAD: - // receive payload symbols - dsssframe64sync_execute_rxpayload(_q, _x[i]); - break; - default: - return liquid_error(LIQUID_EINT,"dsssframe64sync_exeucte(), unknown/unsupported state"); - } - } -#else - qdsync_cccf_execute(_q->detector, _buf, _buf_len); -#endif - return LIQUID_OK; + // run detector/synchronizer, invoking internal callback as needed + return qdsync_cccf_execute(_q->detector, _buf, _buf_len); } // get detection threshold @@ -259,7 +242,7 @@ float dsssframe64sync_get_threshold(dsssframe64sync _q) // set detection threshold int dsssframe64sync_set_threshold(dsssframe64sync _q, - float _threshold) + float _threshold) { return qdsync_cccf_set_threshold(_q->detector, _threshold); } @@ -300,6 +283,7 @@ int dsssframe64sync_step(dsssframe64sync _q, _q->payload_rx[_q->payload_counter] = _q->sym_despread / 256.0f; _q->payload_counter++; _q->chip_counter = 0; + _q->sym_despread = 0; if (_q->payload_counter == 630) { dsssframe64sync_decode(_q); return 1; // reset @@ -313,14 +297,22 @@ int dsssframe64sync_step(dsssframe64sync _q, // internal decode received frame, update statistics, invoke callback int dsssframe64sync_decode(dsssframe64sync _q) { - printf("dsssframe64sync: frame received!\n"); - // recover data symbols from pilots qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); // decode payload int crc_pass = qpacketmodem_decode(_q->dec, _q->payload_sym, _q->payload_dec); - +#if 0 + // debug: export symbols to file + unsigned int i; + FILE * fid = fopen("dsssframe64sync_debug.m","w"); + fprintf(fid,"clear all; close all; r=zeros(1,630); s=zeros(1,600);\n"); + for (i=0; i<630; i++) + fprintf(fid,"r(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_rx[i]), cimagf(_q->payload_rx[i])); + for (i=0; i<600; i++) + fprintf(fid,"s(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_sym[i]), cimagf(_q->payload_sym[i])); + fclose(fid); +#endif // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid += crc_pass; From ab8de5f73d00850f23bc463e6c71ff9a1053e9a5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 16 Oct 2022 17:11:45 -0400 Subject: [PATCH 009/334] qdsync: adding method to set carrier offset search range --- include/liquid.h | 4 ++++ src/framing/src/qdsync_cccf.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/include/liquid.h b/include/liquid.h index 82c29670c..9695774b4 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6276,6 +6276,10 @@ float qdsync_cccf_get_threshold(qdsync_cccf _q); // set detection threshold int qdsync_cccf_set_threshold(qdsync_cccf _q, float _threshold); +// set carrier offset search range +int qdsync_cccf_set_range(qdsync_cccf _q, + float _dphi_max); + // set callback method int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index ad6c8668b..d76a45166 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -219,6 +219,13 @@ int qdsync_cccf_set_threshold(qdsync_cccf _q, return qdetector_cccf_set_threshold(_q->detector, _threshold); } +// set carrier offset search range +int qdsync_cccf_set_range(qdsync_cccf _q, + float _dphi_max) +{ + return qdetector_cccf_set_range(_q->detector, _dphi_max); +} + // set callback method int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback) { From 93bc2514b8e3312b4d0c84a3574f0fa3e764027b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 16 Oct 2022 17:20:04 -0400 Subject: [PATCH 010/334] dsssframe64sync: allow setting for maximum carrier offset * causing majority of processing latency in frame detection * tightening up search range for now * run substantially faster with no frame present (nearly 10x) --- include/liquid.h | 4 ++++ src/framing/src/dsssframe64sync.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index d71af6cca..36be3cea3 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5960,6 +5960,10 @@ float dsssframe64sync_get_threshold(dsssframe64sync _q); int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold); +// set carrier offset search range +int dsssframe64sync_set_range(dsssframe64sync _q, + float _dphi_max); + // reset frame data statistics int dsssframe64sync_reset_framedatastats(dsssframe64sync _q); diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 417c643e3..1eda10091 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -108,7 +108,8 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, unsigned int k = 2; // samples/symbol q->detector = qdsync_cccf_create_linear(q->preamble_pn, 1024, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta, dsssframe64sync_callback_internal, (void*)q); - qdsync_cccf_set_threshold(q->detector, 0.100f); + qdsync_cccf_set_threshold(q->detector, 0.100f); // detection threshold + qdsync_cccf_set_range (q->detector, 0.006f); // frequency offset search range [radians/sample] // create payload demodulator/decoder object int check = LIQUID_CRC_24; @@ -247,6 +248,13 @@ int dsssframe64sync_set_threshold(dsssframe64sync _q, return qdsync_cccf_set_threshold(_q->detector, _threshold); } +// set carrier offset search range +int dsssframe64sync_set_range(dsssframe64sync _q, + float _dphi_max) +{ + return qdsync_cccf_set_range(_q->detector, _dphi_max); +} + // reset frame data statistics int dsssframe64sync_reset_framedatastats(dsssframe64sync _q) { From 50df9388fa4744139b91c5207ba23b13a043bc1e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 17 Oct 2022 08:24:24 -0400 Subject: [PATCH 011/334] qdsync: restricting samples per symbol to be just 2 for now --- src/framing/src/qdsync_cccf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index d76a45166..6af86c18f 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -99,6 +99,8 @@ qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, // validate input if (_seq_len == 0) return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); + if (_k != 2) + return liquid_error_config("qdsync_cccf_create(), samples per symbol fixed at 2 (temporarily)"); // allocate memory for main object and set internal properties qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); From f50b92f58250134016dd054c4084425a4db326ea Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 17 Oct 2022 08:29:44 -0400 Subject: [PATCH 012/334] dsssframe64: reseting sequence generator for each frame --- src/framing/src/dsssframe64gen.c | 1 + src/framing/src/dsssframe64sync.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 7b095af1f..4f1fec8bb 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -141,6 +141,7 @@ int dsssframe64gen_assemble(dsssframe64gen _q, // reset objects firinterp_crcf_reset(_q->interp); + msequence_reset(_q->ms); // frame_assembled = 1 return LIQUID_OK; diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 1eda10091..29152123e 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -186,8 +186,9 @@ int dsssframe64sync_print(dsssframe64sync _q) // reset frame synchronizer object int dsssframe64sync_reset(dsssframe64sync _q) { - // reset binary pre-demod synchronizer + // reset detector/synchronizer qdsync_cccf_reset(_q->detector); + msequence_reset(_q->ms); // reset state _q->state = dsssframe64sync_STATE_DETECTFRAME; From 6a8f3e78e1d9c0510296bd7591d0d033a94db52e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 17 Oct 2022 22:47:41 -0400 Subject: [PATCH 013/334] dsssframe64/autotest: adding basic autotest --- makefile.in | 1 + src/framing/tests/dsssframe64sync_autotest.c | 85 ++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/framing/tests/dsssframe64sync_autotest.c diff --git a/makefile.in b/makefile.in index 3ede9d924..cf8e15823 100644 --- a/makefile.in +++ b/makefile.in @@ -690,6 +690,7 @@ framing_autotests := \ src/framing/tests/bpacketsync_autotest.c \ src/framing/tests/bsync_autotest.c \ src/framing/tests/detector_autotest.c \ + src/framing/tests/dsssframe64sync_autotest.c \ src/framing/tests/dsssframesync_autotest.c \ src/framing/tests/flexframesync_autotest.c \ src/framing/tests/framesync64_autotest.c \ diff --git a/src/framing/tests/dsssframe64sync_autotest.c b/src/framing/tests/dsssframe64sync_autotest.c new file mode 100644 index 000000000..8e4a10fe4 --- /dev/null +++ b/src/framing/tests/dsssframe64sync_autotest.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "autotest/autotest.h" +#include "liquid.h" + +static int callback_dsssframe64sync_autotest( + unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata) +{ + //printf("callback invoked, payload valid: %s\n", _payload_valid ? "yes" : "no"); + int * frames_recovered = (int*) _userdata; + + *frames_recovered += _header_valid && _payload_valid ? 1 : 0; + return 0; +} + +// AUTOTEST : test simple recovery of frame in noise +void autotest_dsssframe64sync() +{ + unsigned int i; + int frames_recovered = 0; + + // create objects + dsssframe64gen fg = dsssframe64gen_create(); + dsssframe64sync fs = dsssframe64sync_create(callback_dsssframe64sync_autotest, + (void*)&frames_recovered); + dsssframe64sync_set_threshold(fs, 0.5f); + + // generate the frame + unsigned int frame_len = dsssframe64gen_get_frame_len(fg); + float complex frame[frame_len]; + dsssframe64gen_assemble(fg, NULL, NULL); + dsssframe64gen_write (fg, frame, frame_len); + + // add some noise + for (i=0; i Date: Mon, 17 Oct 2022 22:49:07 -0400 Subject: [PATCH 014/334] dsssframe64sync: cleaning up synchronizer, removing unused state enum --- examples/dsssframe64sync_example.c | 2 +- src/framing/src/dsssframe64sync.c | 27 +++++++++++---------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index 981669af1..c82c75adc 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -19,7 +19,7 @@ static int callback(unsigned char * _header, framesyncstats_s _stats, void * _context) { - printf("*** callback invoked (%s)***\n", _payload_valid ? "pass" : "FAIL"); + printf("*** callback invoked (%s) ***\n", _payload_valid ? "pass" : "FAIL"); framesyncstats_print(&_stats); // save recovered symbols to file diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 29152123e..70a6dca63 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -20,7 +20,8 @@ * THE SOFTWARE. */ -// basic frame synchronizer with 8 bytes header and 64 bytes payload +// basic direct sequence/spread spectrum frame synchronizer with 8 bytes header +// and 64 bytes payload #include #include @@ -50,34 +51,29 @@ struct dsssframe64sync_s { // callback framesync_callback callback; // user-defined callback function void * context; // user-defined data structure - unsigned int m; // filter delay (symbols) - float beta; // filter excess bandwidth factor + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor - framesyncstats_s framesyncstats; // frame statistic object (synchronizer) - framedatastats_s framedatastats; // frame statistic object (packet statistics) + framesyncstats_s framesyncstats;// frame statistic object (synchronizer) + framedatastats_s framedatastats;// frame statistic object (packet statistics) // preamble - float complex preamble_pn[1024]; // known 1024-symbol p/n sequence - float complex preamble_rx[1024]; // received p/n symbols + float complex preamble_pn[1024];// known 1024-symbol p/n sequence + float complex preamble_rx[1024];// received p/n symbols // payload decoder float complex payload_rx [630]; // received payload symbols with pilots float complex payload_sym[600]; // received payload symbols unsigned char payload_dec[ 72]; // decoded payload bytes - qdsync_cccf detector; // frame detector - msequence ms; // spreading sequence generator + qdsync_cccf detector; // frame detector + msequence ms; // spreading sequence generator float complex sym_despread; // despread symbol qpacketmodem dec; // packet demodulator/decoder qpilotsync pilotsync; // pilot extraction, carrier recovery // status variables - enum { - dsssframe64sync_STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) - dsssframe64sync_STATE_RXPREAMBLE, // receive p/n sequence - dsssframe64sync_STATE_RXPAYLOAD, // receive payload data - } state; unsigned int preamble_counter; // counter: num of p/n syms received unsigned int chip_counter; // counter: num of payload chips received for a single symbol unsigned int payload_counter; // counter: num of payload syms received @@ -166,7 +162,7 @@ dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) int dsssframe64sync_destroy(dsssframe64sync _q) { // destroy synchronization objects - msequence_destroy (_q->ms); // + msequence_destroy (_q->ms); // pseudo-random sequence generator qdsync_cccf_destroy (_q->detector); // frame detector qpacketmodem_destroy(_q->dec); // payload demodulator qpilotsync_destroy (_q->pilotsync); // pilot synchronizer @@ -191,7 +187,6 @@ int dsssframe64sync_reset(dsssframe64sync _q) msequence_reset(_q->ms); // reset state - _q->state = dsssframe64sync_STATE_DETECTFRAME; _q->preamble_counter= 0; _q->chip_counter = 0; _q->payload_counter = 0; From e96f991ed230de1707c5ee318fdb2c6e7648508f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 19 Oct 2022 07:32:34 -0400 Subject: [PATCH 015/334] qdsync: adding method to determine if object is 'open' (actively receiving) --- include/liquid.h | 3 +++ src/framing/src/qdsync_cccf.c | 49 +++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 9695774b4..527255b62 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6286,6 +6286,9 @@ int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); // set context value int qdsync_cccf_set_context (qdsync_cccf _q, void * _context); +// is synchronizer actively running? +int qdsync_cccf_is_open(qdsync_cccf _q); + // execute block of samples int qdsync_cccf_execute(qdsync_cccf _q, liquid_float_complex * _buf, diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 6af86c18f..cabe17f90 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -186,28 +186,6 @@ int qdsync_cccf_reset(qdsync_cccf _q) return LIQUID_OK; } -int qdsync_cccf_execute(qdsync_cccf _q, - liquid_float_complex * _buf, - unsigned int _buf_len) -{ - unsigned int i; - for (i=0; i<_buf_len; i++) { - switch (_q->state) { - case QDSYNC_STATE_DETECT: - // detect frame (look for p/n sequence) - qdsync_cccf_execute_detect(_q, _buf[i]); - break; - case QDSYNC_STATE_SYNC: - // receive preamble sequence symbols - qdsync_cccf_step(_q, _buf[i]); - break; - default: - return liquid_error(LIQUID_EINT,"qdsync_cccf_exeucte(), unknown/unsupported state"); - } - } - return LIQUID_OK; -} - // get detection threshold float qdsync_cccf_get_threshold(qdsync_cccf _q) { @@ -242,6 +220,33 @@ int qdsync_cccf_set_context (qdsync_cccf _q, void * _context) return LIQUID_OK; } +int qdsync_cccf_execute(qdsync_cccf _q, + liquid_float_complex * _buf, + unsigned int _buf_len) +{ + unsigned int i; + for (i=0; i<_buf_len; i++) { + switch (_q->state) { + case QDSYNC_STATE_DETECT: + // detect frame (look for p/n sequence) + qdsync_cccf_execute_detect(_q, _buf[i]); + break; + case QDSYNC_STATE_SYNC: + // receive preamble sequence symbols + qdsync_cccf_step(_q, _buf[i]); + break; + default: + return liquid_error(LIQUID_EINT,"qdsync_cccf_exeucte(), unknown/unsupported state"); + } + } + return LIQUID_OK; +} + +int qdsync_cccf_is_open(qdsync_cccf _q) +{ + return _q->state == QDSYNC_STATE_DETECT ? 0 : 1; +} + // // internal methods // From 10bf218faf746c1b0403006cdb0f9fe6e4094c5a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 19 Oct 2022 17:05:27 -0400 Subject: [PATCH 016/334] dsssframe64: adding performance example --- .../dsssframe64sync_performance_example.c | 93 +++++++++++++++++++ makefile.in | 1 + 2 files changed, 94 insertions(+) create mode 100644 examples/dsssframe64sync_performance_example.c diff --git a/examples/dsssframe64sync_performance_example.c b/examples/dsssframe64sync_performance_example.c new file mode 100644 index 000000000..38f394b27 --- /dev/null +++ b/examples/dsssframe64sync_performance_example.c @@ -0,0 +1,93 @@ +// This example tests the performance for detecting and decoding frames +// with the dsssframe64gen and dsssframe64sync objects. +// SEE ALSO: dsssframe64sync_example.c +#include +#include +#include +#include "liquid.h" +#define OUTPUT_FILENAME "dsssframe64sync_performance_example.m" + +// add noise to channel +void frame64_add_noise(float complex * _buf, + unsigned int _buf_len, float _SNRdB) +{ + float nstd = powf(10.0f, -_SNRdB/20.0f) * M_SQRT1_2; + unsigned int i; + for (i=0; i<_buf_len; i++) + _buf[i] += nstd*( randnf() + _Complex_I*randnf() ); +} + +int main(int argc, char*argv[]) +{ + // create frame generator, synchronizer objects + dsssframe64gen fg = dsssframe64gen_create(); + dsssframe64sync fs = dsssframe64sync_create(NULL,NULL); + unsigned int min_errors = 10; + unsigned int min_trials = 10; + unsigned int max_trials = 800; + + // create buffer for the frame samples + unsigned int frame_len = dsssframe64gen_get_frame_len(fg); + float complex frame[frame_len]; + float SNRdB = -25.0f; + FILE* fid = fopen(OUTPUT_FILENAME, "w"); + fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all; close all;\n"); + fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); + printf("# %8s %6s %6s %6s\n", "SNR", "detect", "valid", "trials"); + while (SNRdB < -13.0f) { + dsssframe64sync_reset_framedatastats(fs); + unsigned int num_trials = 0, num_errors = 0; + while (1) { + unsigned int i; + for (i=0; i= min_errors) + break; + if (num_trials >= max_trials) + break; + } + // print results + framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); + printf(" %8.3f %6u %6u %6u\n", + SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials); + fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%g; pvalid(end+1)=%g;\n", + SNRdB, + (float)stats.num_frames_detected / (float)num_trials, + (float)stats.num_payloads_valid / (float)num_trials); + if (num_errors < min_errors) + break; + SNRdB += 1.0f; + } + fprintf(fid,"figure;\n"); + fprintf(fid,"hold on;\n"); + fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); + fprintf(fid," semilogy(SNR, 1-pvalid +eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); + fprintf(fid,"hold off;\n"); + fprintf(fid,"xlabel('SNR [dB]');\n"); + fprintf(fid,"ylabel('Prob. of Error');\n"); + fprintf(fid,"legend('detect','decoding','location','northeast');\n"); + fprintf(fid,"axis([-25 0 1e-3 1]);\n"); + fprintf(fid,"grid on;\n"); + fclose(fid); + printf("results written to %s\n", OUTPUT_FILENAME); + + // clean up allocated objects + dsssframe64gen_destroy(fg); + dsssframe64sync_destroy(fs); + return 0; +} diff --git a/makefile.in b/makefile.in index cf8e15823..749dac040 100644 --- a/makefile.in +++ b/makefile.in @@ -1518,6 +1518,7 @@ example_programs := \ examples/cvsd_example \ examples/detector_cccf_example \ examples/dds_cccf_example \ + examples/dsssframe64sync_performance_example \ examples/dsssframe64sync_example \ examples/dsssframesync_example \ examples/dotprod_rrrf_example \ From 06a1374e08c8b4c90b313e7c9174b39d39686a9f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 19 Oct 2022 17:51:19 -0400 Subject: [PATCH 017/334] dsssframe64: increasing number of pilots from 30 to 50 * dramatically improves decoding performance for low SNRs * with 30 pilots: 1% PER at -12 dB SNR * with 50 pilots: 1% PER at -17 dB SNR * showing 5 dB improvement with only about 3% loss in spectral efficiency --- src/framing/src/dsssframe64gen.c | 10 +++++----- src/framing/src/dsssframe64sync.c | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 4f1fec8bb..6732a1f0d 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -39,7 +39,7 @@ struct dsssframe64gen_s { float complex preamble_pn[1024]; // 1024-symbol p/n sequence unsigned char payload_dec[ 150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol float complex payload_sym[ 600]; // modulated payload symbols - float complex payload_tx [ 630]; // modulated payload symbols with pilots + float complex payload_tx [ 650]; // modulated payload symbols with pilots unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor firinterp_crcf interp; // pulse-shaping filter/interpolator @@ -74,8 +74,8 @@ dsssframe64gen dsssframe64gen_create() assert( qpacketmodem_get_frame_len(q->enc)==600 ); // create pilot generator - q->pilotgen = qpilotgen_create(600, 21); - assert( qpilotgen_get_frame_len(q->pilotgen)==630 ); + q->pilotgen = qpilotgen_create(600, 13); + assert( qpilotgen_get_frame_len(q->pilotgen)==650 ); // create pulse-shaping filter (k=2) q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,2,q->m,q->beta,0); @@ -164,7 +164,7 @@ int dsssframe64gen_write(dsssframe64gen _q, } // frame payload - for (i=0; i<630; i++) { + for (i=0; i<650; i++) { float complex sym = _q->payload_tx[i]; // strip out raw payload symbol for (j=0; j<256; j++) { // generate pseudo-random symbol @@ -194,6 +194,6 @@ int dsssframe64gen_complete(dsssframe64gen _q) // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) { - return 2*(1024 + 630*256 + 2*_q->m); + return 2*(1024 + 650*256 + 2*_q->m); } diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 70a6dca63..fbd3a8201 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -62,7 +62,7 @@ struct dsssframe64sync_s { float complex preamble_rx[1024];// received p/n symbols // payload decoder - float complex payload_rx [630]; // received payload symbols with pilots + float complex payload_rx [650]; // received payload symbols with pilots float complex payload_sym[600]; // received payload symbols unsigned char payload_dec[ 72]; // decoded payload bytes @@ -118,8 +118,8 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, assert( qpacketmodem_get_frame_len(q->dec)==600 ); // create pilot synchronizer - q->pilotsync = qpilotsync_create(600, 21); - assert( qpilotsync_get_frame_len(q->pilotsync)==630); + q->pilotsync = qpilotsync_create(600, 13); + assert( qpilotsync_get_frame_len(q->pilotsync)==650); // reset global data counters dsssframe64sync_reset_framedatastats(q); @@ -288,7 +288,7 @@ int dsssframe64sync_step(dsssframe64sync _q, _q->payload_counter++; _q->chip_counter = 0; _q->sym_despread = 0; - if (_q->payload_counter == 630) { + if (_q->payload_counter == 650) { dsssframe64sync_decode(_q); return 1; // reset } @@ -310,8 +310,8 @@ int dsssframe64sync_decode(dsssframe64sync _q) // debug: export symbols to file unsigned int i; FILE * fid = fopen("dsssframe64sync_debug.m","w"); - fprintf(fid,"clear all; close all; r=zeros(1,630); s=zeros(1,600);\n"); - for (i=0; i<630; i++) + fprintf(fid,"clear all; close all; r=zeros(1,650); s=zeros(1,600);\n"); + for (i=0; i<650; i++) fprintf(fid,"r(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_rx[i]), cimagf(_q->payload_rx[i])); for (i=0; i<600; i++) fprintf(fid,"s(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_sym[i]), cimagf(_q->payload_sym[i])); From 03164dabeb8a7702dbfb92e6c9eceb79d94f99a1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 19 Oct 2022 07:42:33 -0400 Subject: [PATCH 018/334] qdsync: adding autotest for detection, payload recovery --- makefile.in | 1 + src/framing/tests/qdsync_cccf_autotest.c | 141 +++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 src/framing/tests/qdsync_cccf_autotest.c diff --git a/makefile.in b/makefile.in index ec6b1cbb5..4d46007c8 100644 --- a/makefile.in +++ b/makefile.in @@ -694,6 +694,7 @@ framing_autotests := \ src/framing/tests/ofdmflexframe_autotest.c \ src/framing/tests/qdetector_cccf_autotest.c \ src/framing/tests/qdetector_cccf_copy_autotest.c \ + src/framing/tests/qdsync_cccf_autotest.c \ src/framing/tests/qpacketmodem_autotest.c \ src/framing/tests/qpilotsync_autotest.c \ src/framing/tests/qsource_autotest.c \ diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c new file mode 100644 index 000000000..a5cbfcdbd --- /dev/null +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2007 - 2018 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "autotest/autotest.h" +#include "liquid.h" + +// common structure for relaying information to/from callback +typedef struct { + unsigned int seq_len; + float complex * buf; + unsigned int buf_len; + unsigned int count; +} autotest_qdsync_s; + +// synchronization callback, return 0:continue, 1:reset +int autotest_qdsync_callback(float complex * _buf, + unsigned int _buf_len, + void * _context) +{ + // save samples to buffer as appropriate + autotest_qdsync_s * q = (autotest_qdsync_s *) _context; + unsigned int i; + for (i=0; i<_buf_len; i++) { + if (q->count < q->seq_len) { + // preamble sequence + } else if (q->count < q->seq_len + q->buf_len) { + // payload + q->buf[q->count - q->seq_len] = _buf[i]; + } if (q->count == q->seq_len + q->buf_len) { + // buffer full; reset synchronizer + return 1; + } + q->count++; + } + return 0; +} + +void autotest_qdsync() +{ + // options + unsigned int seq_len = 80; // number of sync symbols + unsigned int payload_len = 200; // number of payload symbols + unsigned int k = 2; // samples/symbol + unsigned int m = 7; // filter delay [symbols] + float beta = 0.3f; // excess bandwidth factor + int ftype = LIQUID_FIRFILT_ARKAISER; + float nstd = 0.001f; + + // generate synchronization sequence (QPSK symbols) + float complex seq[seq_len]; + unsigned int i; + for (i=0; i Date: Thu, 20 Oct 2022 20:48:14 -0400 Subject: [PATCH 019/334] qdsync: adding methods to get metrics, offset estimates --- include/liquid.h | 13 ++++++++++--- src/framing/src/qdsync_cccf.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 527255b62..1af8a9c52 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6286,14 +6286,21 @@ int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); // set context value int qdsync_cccf_set_context (qdsync_cccf _q, void * _context); -// is synchronizer actively running? -int qdsync_cccf_is_open(qdsync_cccf _q); - // execute block of samples int qdsync_cccf_execute(qdsync_cccf _q, liquid_float_complex * _buf, unsigned int _buf_len); +// is synchronizer actively running? +int qdsync_cccf_is_open(qdsync_cccf _q); + +// get detection metrics and offsets +float qdsync_cccf_get_rxy (qdsync_cccf _q); // correlator output +float qdsync_cccf_get_tau (qdsync_cccf _q); // fractional timing offset estimate +float qdsync_cccf_get_gamma(qdsync_cccf _q); // channel gain +float qdsync_cccf_get_dphi (qdsync_cccf _q); // carrier frequency offset estimate +float qdsync_cccf_get_phi (qdsync_cccf _q); // carrier phase offset estimate + // // Pre-demodulation detector // diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index cabe17f90..c9737ae11 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -247,6 +247,36 @@ int qdsync_cccf_is_open(qdsync_cccf _q) return _q->state == QDSYNC_STATE_DETECT ? 0 : 1; } +// correlator output +float qdsync_cccf_get_rxy(qdsync_cccf _q) +{ + return qdetector_cccf_get_rxy(_q->detector); +} + +// fractional timing offset estimate +float qdsync_cccf_get_tau(qdsync_cccf _q) +{ + return qdetector_cccf_get_tau(_q->detector); +} + +// channel gain +float qdsync_cccf_get_gamma(qdsync_cccf _q) +{ + return qdetector_cccf_get_gamma(_q->detector); +} + +// carrier frequency offset estimate +float qdsync_cccf_get_dphi(qdsync_cccf _q) +{ + return qdetector_cccf_get_dphi(_q->detector); +} + +// carrier phase offset estimate +float qdsync_cccf_get_phi(qdsync_cccf _q) +{ + return qdetector_cccf_get_phi(_q->detector); +} + // // internal methods // From a8b6415f5ae0c153036088b2a11b3e61f45534e0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 20 Oct 2022 20:52:39 -0400 Subject: [PATCH 020/334] qdsync: removing internal offsets; no need to store extra copy --- src/framing/src/qdsync_cccf.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index c9737ae11..fec0df56e 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -66,12 +66,6 @@ struct qdsync_cccf_s { } state; // frame synchronization state unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence - // estimated offsets - float tau_hat; // - float gamma_hat; // - float dphi_hat; // - float phi_hat; // - nco_crcf mixer; // coarse carrier frequency recovery // timing recovery objects, states @@ -294,28 +288,28 @@ int qdsync_cccf_execute_detect(qdsync_cccf _q, // check if frame has been detected if (v != NULL) { // get estimates - _q->tau_hat = qdetector_cccf_get_tau (_q->detector); - _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); - _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); - _q->phi_hat = qdetector_cccf_get_phi (_q->detector); - //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", - // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); + float tau_hat = qdetector_cccf_get_tau (_q->detector); + float gamma_hat = qdetector_cccf_get_gamma(_q->detector); + float dphi_hat = qdetector_cccf_get_dphi (_q->detector); + float phi_hat = qdetector_cccf_get_phi (_q->detector); + //printf("*** qdsync frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", + // tau_hat, dphi_hat, 20*log10f(gamma_hat)); // set appropriate filterbank index - if (_q->tau_hat > 0) { - _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; + if (tau_hat > 0) { + _q->pfb_index = (unsigned int)( tau_hat * _q->npfb) % _q->npfb; _q->mf_counter = 0; } else { - _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; + _q->pfb_index = (unsigned int)((1.0f+tau_hat) * _q->npfb) % _q->npfb; _q->mf_counter = 1; } // output filter scale - firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); + firpfb_crcf_set_scale(_q->mf, 0.5f / gamma_hat); // set frequency/phase of mixer - nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); - nco_crcf_set_phase (_q->mixer, _q->phi_hat ); + nco_crcf_set_frequency(_q->mixer, dphi_hat); + nco_crcf_set_phase (_q->mixer, phi_hat ); // update state _q->state = QDSYNC_STATE_SYNC; From d57d6eca4fc5b68885d2d06e231c87e85d29f879 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 22 Oct 2022 07:54:05 -0400 Subject: [PATCH 021/334] dsssframe64sync: adding carrier offset estimate to callback * initial carrier offset based on preamble detection * refined carrier offset from qpilotsync object * combined estimate returned to callback --- src/framing/src/dsssframe64sync.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index fbd3a8201..b986a99f8 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -326,10 +326,14 @@ int dsssframe64sync_decode(dsssframe64sync _q) // invoke callback int rc = 0; if (_q->callback != NULL) { + // offset estimates + float dphi_hat = qdsync_cccf_get_dphi(_q->detector) + + qpilotsync_get_dphi(_q->pilotsync) / 256.0f; + // set framesyncstats internals _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); _q->framesyncstats.rssi = 0; //20*log10f(qdsync_cccf_get_gamma(_q->detector)); - _q->framesyncstats.cfo = 0; //qdsync_cccf_get_frequency(_q->detector); + _q->framesyncstats.cfo = dphi_hat; _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = 600; _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; From 7361ee9c58418ec14d6d377370c342629e37127e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 22 Oct 2022 08:45:48 -0400 Subject: [PATCH 022/334] dsssframe64sync: adding RSSI measurement to callback --- src/framing/src/dsssframe64sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index b986a99f8..a1c8a2855 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -332,7 +332,7 @@ int dsssframe64sync_decode(dsssframe64sync _q) // set framesyncstats internals _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); - _q->framesyncstats.rssi = 0; //20*log10f(qdsync_cccf_get_gamma(_q->detector)); + _q->framesyncstats.rssi = 20*log10f(qdsync_cccf_get_gamma(_q->detector)); _q->framesyncstats.cfo = dphi_hat; _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = 600; From 4069c4daf715909c42690efeb4f6ba41ad04d402 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 23 Oct 2022 07:30:40 -0400 Subject: [PATCH 023/334] dsssframe64gen: replacing assemble() and write() with execute() * frame is fixed size * makes consistent with framegen64 methods * frame length should probably be defined statically somewhere --- examples/dsssframe64sync_example.c | 3 +- .../dsssframe64sync_performance_example.c | 3 +- include/liquid.h | 33 ++++--------- src/framing/src/dsssframe64gen.c | 46 ++++++++----------- src/framing/tests/dsssframe64sync_autotest.c | 3 +- 5 files changed, 32 insertions(+), 56 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index c82c75adc..161403462 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -54,8 +54,7 @@ int main(int argc, char *argv[]) fprintf(fid,"s=[];\n"); // generate in one step (for now) - dsssframe64gen_assemble(fg, NULL, NULL); - dsssframe64gen_write(fg, buf_tx, buf_len); + dsssframe64gen_execute(fg, NULL, NULL, buf_tx); // apply channel (AWGN) float nstd = powf(10.0f,-SNRdB/20.0f); diff --git a/examples/dsssframe64sync_performance_example.c b/examples/dsssframe64sync_performance_example.c index 38f394b27..8e89e99d7 100644 --- a/examples/dsssframe64sync_performance_example.c +++ b/examples/dsssframe64sync_performance_example.c @@ -45,8 +45,7 @@ int main(int argc, char*argv[]) dsssframe64sync_reset(fs); // generate the frame with random header and payload - dsssframe64gen_assemble(fg, NULL, NULL); - dsssframe64gen_write (fg, frame, frame_len); + dsssframe64gen_execute(fg, NULL, NULL, frame); // add channel effects frame64_add_noise(frame, frame_len, SNRdB); diff --git a/include/liquid.h b/include/liquid.h index 3ceadac2c..821793932 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5904,37 +5904,22 @@ int dsssframe64gen_destroy(dsssframe64gen _q); // print dsssframe64gen object internals int dsssframe64gen_print(dsssframe64gen _q); -int dsssframe64gen_print(dsssframe64gen _q); - -// reset dsssframe64gen object internals -//int dsssframe64gen_reset(dsssframe64gen _q); - -// is frame assembled? -//int dsssframe64gen_is_assembled(dsssframe64gen _q); - // get length of assembled frame (samples) unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); -// assemble a frame from an array of data -// _q : frame generator object -// _props : frame properties -// _payload : payload data [size: _payload_len x 1] -// _payload_len : payload data length -int dsssframe64gen_assemble(dsssframe64gen _q, - const unsigned char * _header, - const unsigned char * _payload); - -int dsssframe64gen_write(dsssframe64gen _q, - liquid_float_complex * _buf, - unsigned int _buf_len); - -// is frame generation complete? -int dsssframe64gen_complete(dsssframe64gen _q); +// generate a frame +// _q : frame generator object +// _header : 8-byte header data, NULL for random +// _payload : 64-byte payload data, NULL for random +// _frame : output frame samples, [size: dsssframegen64gen_get_frame_len() x 1] +int dsssframe64gen_execute(dsssframe64gen _q, + const unsigned char * _header, + const unsigned char * _payload, + liquid_float_complex * _buf); // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); - // frame synchronizer object type typedef struct dsssframe64sync_s * dsssframe64sync; diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 6732a1f0d..afc42af58 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -32,6 +32,9 @@ #include "liquid.internal.h" +// write samples to buffer +int dsssframe64gen_write(dsssframe64gen _q, float complex * _buf); + struct dsssframe64gen_s { qpacketmodem enc; // packet encoder/modulator qpilotgen pilotgen; // pilot symbol generator @@ -43,8 +46,6 @@ struct dsssframe64gen_s { unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor firinterp_crcf interp; // pulse-shaping filter/interpolator - float complex buf_output[2]; // output sample buffer - // TODO: counters, etc. }; // create dsssframe64gen object @@ -116,14 +117,21 @@ int dsssframe64gen_print(dsssframe64gen _q) return LIQUID_OK; } -// assmeble frame +// get full frame length [samples] +unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) +{ + return 2*(1024 + 650*256 + 2*_q->m); +} + +// generate a frame // _q : frame generator object // _header : 8-byte header data, NULL for random // _payload : 64-byte payload data, NULL for random -// _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1] -int dsssframe64gen_assemble(dsssframe64gen _q, - const unsigned char * _header, - const unsigned char * _payload) +// _frame : output frame samples, [size: dsssframegen64gen_get_frame_len() x 1] +int dsssframe64gen_execute(dsssframe64gen _q, + const unsigned char * _header, + const unsigned char * _payload, + float complex * _buf) { unsigned int i; @@ -143,17 +151,15 @@ int dsssframe64gen_assemble(dsssframe64gen _q, firinterp_crcf_reset(_q->interp); msequence_reset(_q->ms); - // frame_assembled = 1 - return LIQUID_OK; + // write frame to buffer + return dsssframe64gen_write(_q, _buf); } // write samples to buffer -// _q : frame generator object -// _buf : output frame samples, shape: (_buf_len,) -// _buf_len : output frame buffer size +// _q : frame generator object +// _buf : output frame samples (full frame) int dsssframe64gen_write(dsssframe64gen _q, - float complex * _buf, - unsigned int _buf_len) + float complex * _buf) { unsigned int i, j, n=0; @@ -185,15 +191,3 @@ int dsssframe64gen_write(dsssframe64gen _q, return LIQUID_OK; } -// is frame generation complete? -int dsssframe64gen_complete(dsssframe64gen _q) -{ - return 1; -} - -// get full frame length [samples] -unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) -{ - return 2*(1024 + 650*256 + 2*_q->m); -} - diff --git a/src/framing/tests/dsssframe64sync_autotest.c b/src/framing/tests/dsssframe64sync_autotest.c index 8e4a10fe4..b4b010700 100644 --- a/src/framing/tests/dsssframe64sync_autotest.c +++ b/src/framing/tests/dsssframe64sync_autotest.c @@ -58,8 +58,7 @@ void autotest_dsssframe64sync() // generate the frame unsigned int frame_len = dsssframe64gen_get_frame_len(fg); float complex frame[frame_len]; - dsssframe64gen_assemble(fg, NULL, NULL); - dsssframe64gen_write (fg, frame, frame_len); + dsssframe64gen_execute(fg, NULL, NULL, frame); // add some noise for (i=0; i Date: Wed, 26 Oct 2022 16:26:26 -0400 Subject: [PATCH 024/334] qdsync: allowing other than 2 samples per symbol, extending test * needs further investigation for offset correction * works reasonably well for k in {2,4} but for k=3 occasionally fails * needs more testing of edge cases and resiliency --- src/framing/src/qdsync_cccf.c | 27 +++++++++-------- src/framing/tests/qdsync_cccf_autotest.c | 38 +++++++++++++++++------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index fec0df56e..ed19eef64 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -93,8 +93,8 @@ qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, // validate input if (_seq_len == 0) return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); - if (_k != 2) - return liquid_error_config("qdsync_cccf_create(), samples per symbol fixed at 2 (temporarily)"); + //if (_k != 2) + // return liquid_error_config("qdsync_cccf_create(), samples per symbol fixed at 2 (temporarily)"); // allocate memory for main object and set internal properties qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); @@ -292,20 +292,21 @@ int qdsync_cccf_execute_detect(qdsync_cccf _q, float gamma_hat = qdetector_cccf_get_gamma(_q->detector); float dphi_hat = qdetector_cccf_get_dphi (_q->detector); float phi_hat = qdetector_cccf_get_phi (_q->detector); - //printf("*** qdsync frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", - // tau_hat, dphi_hat, 20*log10f(gamma_hat)); // set appropriate filterbank index - if (tau_hat > 0) { - _q->pfb_index = (unsigned int)( tau_hat * _q->npfb) % _q->npfb; - _q->mf_counter = 0; - } else { - _q->pfb_index = (unsigned int)((1.0f+tau_hat) * _q->npfb) % _q->npfb; - _q->mf_counter = 1; + _q->mf_counter = _q->k - 2; + _q->pfb_index = 0; + int index = (int)(tau_hat * _q->npfb); + if (index < 0) { + _q->mf_counter++; + index += _q->npfb; } + _q->pfb_index = index; + //printf("* qdsync detected! tau:%6.3f, dphi:%12.4e, phi:%6.3f, gamma:%6.2f dB, mf:%u, pfb idx:%u\n", + // tau_hat, dphi_hat, phi_hat, 20*log10f(gamma_hat), _q->mf_counter, _q->pfb_index); // output filter scale - firpfb_crcf_set_scale(_q->mf, 0.5f / gamma_hat); + firpfb_crcf_set_scale(_q->mf, 1.0f / (_q->k * gamma_hat)); // set frequency/phase of mixer nco_crcf_set_frequency(_q->mixer, dphi_hat); @@ -339,12 +340,12 @@ int qdsync_cccf_step(qdsync_cccf _q, // increment counter to determine if sample is available _q->mf_counter++; - int sample_available = (_q->mf_counter >= 1) ? 1 : 0; + int sample_available = (_q->mf_counter >= _q->k-1) ? 1 : 0; // set output sample if available if (sample_available) { // decrement counter by k=2 samples/symbol - _q->mf_counter -= 2; + _q->mf_counter -= _q->k; // append to output qdsync_cccf_buf_append(_q, v); diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index a5cbfcdbd..d7ab62e1c 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -38,6 +38,7 @@ int autotest_qdsync_callback(float complex * _buf, unsigned int _buf_len, void * _context) { + printf("qdsync callback got %u samples\n", _buf_len); // save samples to buffer as appropriate autotest_qdsync_s * q = (autotest_qdsync_s *) _context; unsigned int i; @@ -76,8 +77,8 @@ void autotest_qdsync() } // payload symbols - float complex payload_tx[payload_len]; - float complex payload_rx[payload_len]; + float complex payload_tx[payload_len]; // transmitted + float complex payload_rx[payload_len]; // received with initial correction for (i=0; i Date: Wed, 26 Oct 2022 16:51:22 -0400 Subject: [PATCH 025/334] qdsync: cleaning up text formatting and comments with object --- src/framing/src/qdsync_cccf.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index ed19eef64..047ab7a79 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -50,34 +50,34 @@ int qdsync_cccf_buf_append(qdsync_cccf _q, // main object definition struct qdsync_cccf_s { unsigned int seq_len; // preamble sequence length - int ftype; // - unsigned int k; // - unsigned int m; // - float beta; // + int ftype; // filter type + unsigned int k; // samples per symbol + unsigned int m; // filter semi-length + float beta; // excess bandwidth factor - qdsync_callback callback; // - void * context; // + qdsync_callback callback; // user-defined callback function + void * context; // user-defined context object qdetector_cccf detector; // detector // status variables enum { QDSYNC_STATE_DETECT=0, // detect frame - QDSYNC_STATE_SYNC, // + QDSYNC_STATE_SYNC, // apply carrier offset correction and matched filter } state; // frame synchronization state unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence - nco_crcf mixer; // coarse carrier frequency recovery + nco_crcf mixer; // coarse carrier frequency recovery // timing recovery objects, states - firpfb_crcf mf; // matched filter decimator - unsigned int npfb; // number of filters in symsync - int mf_counter; // matched filter output timer - unsigned int pfb_index; // filterbank index + firpfb_crcf mf; // matched filter/decimator + unsigned int npfb; // number of filters in symsync + int mf_counter; // matched filter output timer + unsigned int pfb_index; // filterbank index // symbol buffer - unsigned int buf_out_len;// output buffer length - float complex * buf_out; // output buffer - unsigned int buf_out_counter; // output counter + unsigned int buf_out_len;// output buffer length + float complex * buf_out; // output buffer + unsigned int buf_out_counter; // output counter }; // create detector with generic sequence From 4159366907eba40968c77539d5bca342b867d1fe Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 26 Oct 2022 17:03:49 -0400 Subject: [PATCH 026/334] qdsync/autotest: extending sequence and payload for more stable testing --- src/framing/tests/qdsync_cccf_autotest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index d7ab62e1c..9d155a3a6 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -60,8 +60,8 @@ int autotest_qdsync_callback(float complex * _buf, void autotest_qdsync() { // options - unsigned int seq_len = 80; // number of sync symbols - unsigned int payload_len = 200; // number of payload symbols + unsigned int seq_len = 240; // number of sync symbols + unsigned int payload_len = 800; // number of payload symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor @@ -135,8 +135,8 @@ void autotest_qdsync() rmse = 10*log10f( rmse / (float)payload_len ); if (liquid_autotest_verbose) printf("qdsync: dphi: %12.4e, phi: %12.8f, rmse: %12.3f\n", dphi_hat, phi_hat, rmse); - CONTEND_LESS_THAN( rmse, -20.0f ) - CONTEND_LESS_THAN( fabsf(dphi_hat), 4e-3f ) + CONTEND_LESS_THAN( rmse, -30.0f ) + CONTEND_LESS_THAN( fabsf(dphi_hat), 1e-3f ) CONTEND_LESS_THAN( fabsf( phi_hat), 0.4f ) // clean up objects From 3ce538e67308bef2091c05adbe217846ffafa0a0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 26 Oct 2022 17:05:56 -0400 Subject: [PATCH 027/334] qdsync: removing old (commented) error condition checking --- src/framing/src/qdsync_cccf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 047ab7a79..930e840bc 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -93,8 +93,6 @@ qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, // validate input if (_seq_len == 0) return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); - //if (_k != 2) - // return liquid_error_config("qdsync_cccf_create(), samples per symbol fixed at 2 (temporarily)"); // allocate memory for main object and set internal properties qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); From 7ab94836f2e492ea40df77d5b577587e951ef2ac Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 26 Oct 2022 17:12:14 -0400 Subject: [PATCH 028/334] qdsync: extending tests to vary samples per symbol --- src/framing/tests/qdsync_cccf_autotest.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index 9d155a3a6..39b252aa4 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -57,12 +57,12 @@ int autotest_qdsync_callback(float complex * _buf, return 0; } -void autotest_qdsync() +void testbench_qdsync(unsigned int _k) { // options unsigned int seq_len = 240; // number of sync symbols unsigned int payload_len = 800; // number of payload symbols - unsigned int k = 2; // samples/symbol + unsigned int k = _k; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; @@ -157,3 +157,8 @@ void autotest_qdsync() #endif } +// test specific configurations +void autotest_qdsync_k2() { testbench_qdsync(2); } +void autotest_qdsync_k3() { testbench_qdsync(3); } +void autotest_qdsync_k4() { testbench_qdsync(4); } + From bbc037692aa445492674ff59a6a8bb8c3ae18716 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 26 Oct 2022 17:35:32 -0400 Subject: [PATCH 029/334] qdsync: adding method to resize output buffer in callback * needs testing * should handle all cases: increasing/decreasing, buffer empty/full * will invoke callback as many times as needed * really intended to run at initial instantiation, but can be run any time * useful for framing synchronization where we need buffers of particular sizes * can hold either the entire frame, or relevant pieces --- include/liquid.h | 4 ++++ src/framing/src/qdsync_cccf.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/liquid.h b/include/liquid.h index 1af8a9c52..c82f5807a 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6286,6 +6286,10 @@ int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); // set context value int qdsync_cccf_set_context (qdsync_cccf _q, void * _context); +// Set callback buffer size (the number of symbol provided to the callback +// whenever it is invoked). +int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len); + // execute block of samples int qdsync_cccf_execute(qdsync_cccf _q, liquid_float_complex * _buf, diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 930e840bc..70995eb7b 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -212,6 +212,41 @@ int qdsync_cccf_set_context (qdsync_cccf _q, void * _context) return LIQUID_OK; } +// Set callback buffer size (the number of symbol provided to the callback +// whenever it is invoked). +int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len) +{ + if (_buf_len == 0) + return liquid_error(LIQUID_EICONFIG,"qdsync_cccf_set_buf_len(), buffer length must be greater than 0"); + + // check current state + if (_q->buf_out_counter < _buf_len) { + // buffer might not be empty, but we aren't resizing within this space; + // ok to resize so long as old samples are copied + _q->buf_out_len = _buf_len; + _q->buf_out = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + } else { + // we are shrinking the buffer below the number of samples it currently + // holds; invoke the callback as many times as needed to reduce its size + unsigned int index = 0; + while (_q->buf_out_counter >= _buf_len) { + if (_q->callback != NULL) + _q->callback(_q->buf_out + index, _buf_len, _q->context); + + // adjust counters + index += _buf_len; + _q->buf_out_counter -= _buf_len; + } + // now perform the reallocation, but we cannot use 'realloc' here because + // we are not copying values at the front of the buffer + float complex * buf_new = (float complex*)malloc(_buf_len * sizeof(float complex)); + memmove(buf_new, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); + free(_q->buf_out); + _q->buf_out = buf_new; + } + return LIQUID_OK; +} + int qdsync_cccf_execute(qdsync_cccf _q, liquid_float_complex * _buf, unsigned int _buf_len) From f86127ade747da3228923a18c8c15ea3ba9d265b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 22 Feb 2023 11:44:50 -0500 Subject: [PATCH 030/334] qdsync/autotest: making testbench specific to linear --- src/framing/tests/qdsync_cccf_autotest.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index 39b252aa4..826fbf74d 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -57,14 +57,16 @@ int autotest_qdsync_callback(float complex * _buf, return 0; } -void testbench_qdsync(unsigned int _k) +void testbench_qdsync_linear(unsigned int _k, + unsigned int _m, + float _beta) { // options unsigned int seq_len = 240; // number of sync symbols unsigned int payload_len = 800; // number of payload symbols unsigned int k = _k; // samples/symbol - unsigned int m = 7; // filter delay [symbols] - float beta = 0.3f; // excess bandwidth factor + unsigned int m = _m; // filter delay [symbols] + float beta = _beta; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float nstd = 0.001f; @@ -158,7 +160,7 @@ void testbench_qdsync(unsigned int _k) } // test specific configurations -void autotest_qdsync_k2() { testbench_qdsync(2); } -void autotest_qdsync_k3() { testbench_qdsync(3); } -void autotest_qdsync_k4() { testbench_qdsync(4); } +void autotest_qdsync_k2() { testbench_qdsync_linear(2, 7, 0.3f); } +void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } +void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } From 0aa0e87eea1fce7d0c7c0a36741c8e0695631ee0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 22 Feb 2023 12:21:16 -0500 Subject: [PATCH 031/334] qdsync/autotest: simplifying test to use entire sequence --- src/framing/tests/qdsync_cccf_autotest.c | 72 +++++++++--------------- 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index 826fbf74d..a3d8e0841 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -27,7 +27,6 @@ // common structure for relaying information to/from callback typedef struct { - unsigned int seq_len; float complex * buf; unsigned int buf_len; unsigned int count; @@ -43,16 +42,11 @@ int autotest_qdsync_callback(float complex * _buf, autotest_qdsync_s * q = (autotest_qdsync_s *) _context; unsigned int i; for (i=0; i<_buf_len; i++) { - if (q->count < q->seq_len) { - // preamble sequence - } else if (q->count < q->seq_len + q->buf_len) { - // payload - q->buf[q->count - q->seq_len] = _buf[i]; - } if (q->count == q->seq_len + q->buf_len) { - // buffer full; reset synchronizer - return 1; - } - q->count++; + if (q->count == q->buf_len) + return 1; // buffer full; reset synchronizer + + // save payload + q->buf[q->count++] = _buf[i]; } return 0; } @@ -62,8 +56,7 @@ void testbench_qdsync_linear(unsigned int _k, float _beta) { // options - unsigned int seq_len = 240; // number of sync symbols - unsigned int payload_len = 800; // number of payload symbols + unsigned int seq_len = 1200; // total number of sync symbols unsigned int k = _k; // samples/symbol unsigned int m = _m; // filter delay [symbols] float beta = _beta; // excess bandwidth factor @@ -71,24 +64,17 @@ void testbench_qdsync_linear(unsigned int _k, float nstd = 0.001f; // generate synchronization sequence (QPSK symbols) - float complex seq[seq_len]; + float complex seq_tx[seq_len]; // transmitted + float complex seq_rx[seq_len]; // received with initial correction unsigned int i; for (i=0; i Date: Wed, 22 Feb 2023 13:06:21 -0500 Subject: [PATCH 032/334] qdsync: adding copy() method, autotest --- src/framing/src/qdsync_cccf.c | 15 ++-- src/framing/tests/qdsync_cccf_autotest.c | 90 +++++++++++++++++++++++- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 70995eb7b..1469b4f9c 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -113,7 +113,7 @@ qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, q->mf = firpfb_crcf_create_rnyquist(q->ftype, q->npfb, q->k, q->m, q->beta); // allocate buffer for storing output samples - q->buf_out_len = 64; // TODO: make user-defined? + q->buf_out_len = 64; // user can re-size this later q->buf_out = (float complex*) malloc(q->buf_out_len*sizeof(float complex)); // set callback and context values @@ -128,7 +128,6 @@ qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, // copy object qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) { -#if 0 // validate input if (q_orig == NULL) return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); @@ -137,14 +136,20 @@ qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) qdsync_cccf q_copy = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); memmove(q_copy, q_orig, sizeof(struct qdsync_cccf_s)); + // set callback and userdata fields + q_copy->callback = q_orig->callback; + q_copy->context = q_orig->context; + // copy sub-objects q_copy->detector = qdetector_cccf_copy(q_orig->detector); + q_copy->mixer = nco_crcf_copy (q_orig->mixer); + q_copy->mf = firpfb_crcf_copy (q_orig->mf); + + // copy memory in new allocation + q_copy->buf_out = (float complex*)liquid_malloc_copy(q_orig->buf_out, q_orig->buf_out_len, sizeof(float complex)); // return new object return q_copy; -#else - return liquid_error_config("qdsync_cccf_copy(), method not yet implemented"); -#endif } int qdsync_cccf_destroy(qdsync_cccf _q) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index a3d8e0841..d8e0a78ad 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -22,11 +22,13 @@ #include #include +#include #include "autotest/autotest.h" #include "liquid.h" // common structure for relaying information to/from callback typedef struct { + int id; float complex * buf; unsigned int buf_len; unsigned int count; @@ -37,9 +39,9 @@ int autotest_qdsync_callback(float complex * _buf, unsigned int _buf_len, void * _context) { - printf("qdsync callback got %u samples\n", _buf_len); // save samples to buffer as appropriate autotest_qdsync_s * q = (autotest_qdsync_s *) _context; + printf("[%d] qdsync callback got %u samples\n", q->id, _buf_len); unsigned int i; for (i=0; i<_buf_len; i++) { if (q->count == q->buf_len) @@ -73,7 +75,7 @@ void testbench_qdsync_linear(unsigned int _k, } // create sync object, only using first few symbols - autotest_qdsync_s obj = {.buf=seq_rx, .buf_len=seq_len, .count=0}; + autotest_qdsync_s obj = {.id=0, .buf=seq_rx, .buf_len=seq_len, .count=0}; qdsync_cccf q = qdsync_cccf_create_linear(seq_tx, 240, ftype, k, m, beta, autotest_qdsync_callback, (void*)&obj); qdsync_cccf_set_range(q, 0.001f); @@ -148,3 +150,87 @@ void autotest_qdsync_k2() { testbench_qdsync_linear(2, 7, 0.3f); } void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } +// test copying from one object to another +void autotest_qdsync_cccf_copy() +{ + // options + unsigned int seq_len= 2400; // total number of symbols in sequence + unsigned int split = 1033; // cut-off point where object gets copied + unsigned int k = 2; // samples/symbol + unsigned int m = 12; // filter delay [symbols] + float beta = 0.25; // excess bandwidth factor + int ftype = LIQUID_FIRFILT_ARKAISER; + float nstd = 0.001f; + unsigned int i; + + // generate random frame sequence + float complex seq_tx [seq_len]; // transmitted + float complex seq_rx_orig[seq_len]; // received with initial correction (original) + float complex seq_rx_copy[seq_len]; // received with initial correction (original) + for (i=0; i Date: Wed, 22 Feb 2023 13:14:22 -0500 Subject: [PATCH 033/334] qdsync/autotest: cleaning up autotest, respecting verbosity flag --- src/framing/tests/qdsync_cccf_autotest.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index d8e0a78ad..c01555d9c 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,8 @@ int autotest_qdsync_callback(float complex * _buf, { // save samples to buffer as appropriate autotest_qdsync_s * q = (autotest_qdsync_s *) _context; - printf("[%d] qdsync callback got %u samples\n", q->id, _buf_len); + if (liquid_autotest_verbose) + printf("[%d] qdsync callback got %u samples\n", q->id, _buf_len); unsigned int i; for (i=0; i<_buf_len; i++) { if (q->count == q->buf_len) @@ -220,13 +221,12 @@ void autotest_qdsync_cccf_copy() CONTEND_EQUALITY(c_orig.count, seq_len); CONTEND_EQUALITY(c_copy.count, seq_len); // print values for visual comparison - /* - for (i=0; i Date: Wed, 22 Feb 2023 16:47:39 -0500 Subject: [PATCH 034/334] framesync64: using qdsync as internal detector type --- src/framing/src/framesync64.c | 446 ++++++----------------- src/framing/tests/framesync64_autotest.c | 6 + 2 files changed, 109 insertions(+), 343 deletions(-) diff --git a/src/framing/src/framesync64.c b/src/framing/src/framesync64.c index 256491752..6eca7a759 100644 --- a/src/framing/src/framesync64.c +++ b/src/framing/src/framesync64.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,27 +31,10 @@ #include "liquid.internal.h" -#define FRAMESYNC64_ENABLE_EQ 0 - -// push samples through detection stage -int framesync64_execute_seekpn(framesync64 _q, - float complex _x); - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -// _y : output symbol -int framesync64_step(framesync64 _q, - float complex _x, - float complex * _y); - -// push samples through synchronizer, saving received p/n symbols -int framesync64_execute_rxpreamble(framesync64 _q, - float complex _x); - -// receive payload symbols -int framesync64_execute_rxpayload(framesync64 _q, - float complex _x); +// synchronization callback, return 0:continue, 1:reset +int framesync64_callback_internal(float complex * _buf, + unsigned int _buf_len, + void * _context); // export debugging based on return value // 0 : do not write file @@ -59,55 +42,31 @@ int framesync64_execute_rxpayload(framesync64 _q, // -1 : number of packets detected // -2 : id using first 4 bytes of header // -3 : write with random extension -int framesync64_debug_export(framesync64 _q, int _code); +int framesync64_debug_export(framesync64 _q, int _code, float complex * _payload_rx); // framesync64 object structure struct framesync64_s { // callback - framesync_callback callback; // user-defined callback function - void * userdata; // user-defined data structure + framesync_callback callback; // user-defined callback function + void * userdata; // user-defined data structure framesyncstats_s framesyncstats; // frame statistic object (synchronizer) framedatastats_s framedatastats; // frame statistic object (packet statistics) // synchronizer objects - unsigned int m; // filter delay (symbols) - float beta; // filter excess bandwidth factor - qdetector_cccf detector; // pre-demod detector - float tau_hat; // fractional timing offset estimate - float dphi_hat; // carrier frequency offset estimate - float phi_hat; // carrier phase offset estimate - float gamma_hat; // channel gain estimate - nco_crcf mixer; // coarse carrier frequency recovery - - // timing recovery objects, states - firpfb_crcf mf; // matched filter decimator - unsigned int npfb; // number of filters in symsync - int mf_counter; // matched filter output timer - unsigned int pfb_index; // filterbank index -#if FRAMESYNC64_ENABLE_EQ - eqlms_cccf equalizer; // equalizer (trained on p/n sequence) -#endif + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor + qdsync_cccf sync; // sequence detector // preamble - float complex preamble_pn[64]; // known 64-symbol p/n sequence - float complex preamble_rx[64]; // received p/n symbols - + float complex preamble_pn[64]; // known 64-symbol p/n sequence + float complex preamble_rx[64]; // received p/n symbols + // payload decoder - float complex payload_rx [630]; // received payload symbols with pilots - float complex payload_sym[600]; // received payload symbols - unsigned char payload_dec[ 72]; // decoded payload bytes - qpacketmodem dec; // packet demodulator/decoder - qpilotsync pilotsync; // pilot extraction, carrier recovery - int payload_valid; // did payload pass crc? - - // status variables - enum { - FRAMESYNC64_STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) - FRAMESYNC64_STATE_RXPREAMBLE, // receive p/n sequence - FRAMESYNC64_STATE_RXPAYLOAD, // receive payload data - } state; - unsigned int preamble_counter; // counter: num of p/n syms received - unsigned int payload_counter; // counter: num of payload syms received + float complex payload_sym[600]; // received payload symbols + unsigned char payload_dec[ 72]; // decoded payload bytes + qpacketmodem dec; // packet demodulator/decoder + qpilotsync pilotsync; // pilot extraction, carrier recovery + int payload_valid; // did payload pass crc? windowcf buf_debug; // debug: raw input samples char * prefix; // debug: filename prefix @@ -137,24 +96,10 @@ framesync64 framesync64_create(framesync_callback _callback, } msequence_destroy(ms); - // create frame detector - unsigned int k = 2; // samples/symbol - q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta); - qdetector_cccf_set_threshold(q->detector, 0.5f); - - // create symbol timing recovery filters - q->npfb = 64; // number of filters in the bank - q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,k,q->m,q->beta); - -#if FRAMESYNC64_ENABLE_EQ - // create equalizer - unsigned int p = 3; - q->equalizer = eqlms_cccf_create_lowpass(2*k*p+1, 0.4f); - eqlms_cccf_set_bw(q->equalizer, 0.05f); -#endif - - // create down-coverters for carrier phase tracking - q->mixer = nco_crcf_create(LIQUID_NCO); + // create frame detector with callback to run frame sync in one step + q->sync = qdsync_cccf_create_linear(q->preamble_pn, 64, + LIQUID_FIRFILT_ARKAISER, 2, q->m, q->beta, framesync64_callback_internal, q); + qdsync_cccf_set_buf_len(q->sync, 64 + 630); // create payload demodulator/decoder object int check = LIQUID_CRC_24; @@ -163,13 +108,12 @@ framesync64 framesync64_create(framesync_callback _callback, int mod_scheme = LIQUID_MODEM_QPSK; q->dec = qpacketmodem_create(); qpacketmodem_configure(q->dec, 72, check, fec0, fec1, mod_scheme); - //qpacketmodem_print(q->dec); assert( qpacketmodem_get_frame_len(q->dec)==600 ); // create pilot synchronizer q->pilotsync = qpilotsync_create(600, 21); assert( qpilotsync_get_frame_len(q->pilotsync)==630); - + // reset global data counters framesync64_reset_framedatastats(q); @@ -199,22 +143,24 @@ framesync64 framesync64_copy(framesync64 q_orig) memmove(q_copy, q_orig, sizeof(struct framesync64_s)); // set callback and userdata fields - q_copy->callback = q_orig->callback; - q_copy->userdata = q_orig->userdata; + //q_copy->callback = q_orig->callback; + //q_copy->userdata = q_orig->userdata; // copy objects - q_copy->detector = qdetector_cccf_copy(q_orig->detector); - q_copy->mixer = nco_crcf_copy (q_orig->mixer); - q_copy->mf = firpfb_crcf_copy (q_orig->mf); - q_copy->dec = qpacketmodem_copy (q_orig->dec); - q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); - q_copy->buf_debug= windowcf_copy (q_orig->buf_debug); + q_copy->sync = qdsync_cccf_copy (q_orig->sync); + q_copy->dec = qpacketmodem_copy(q_orig->dec); + q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); + q_copy->buf_debug= windowcf_copy (q_orig->buf_debug); // set prefix value q_copy->prefix = NULL; q_copy->filename = NULL; framesync64_set_prefix(q_copy, q_orig->prefix); + // update the context for the sync object to that detected frames will + // apply to this new frame synchronizer object + qdsync_cccf_set_context(q_copy->sync, q_copy); + return q_copy; } @@ -222,15 +168,10 @@ framesync64 framesync64_copy(framesync64 q_orig) int framesync64_destroy(framesync64 _q) { // destroy synchronization objects - qdetector_cccf_destroy(_q->detector); // frame detector - firpfb_crcf_destroy (_q->mf); // matched filter - nco_crcf_destroy (_q->mixer); // coarse NCO - qpacketmodem_destroy (_q->dec); // payload demodulator - qpilotsync_destroy (_q->pilotsync); // pilot synchronizer -#if FRAMESYNC64_ENABLE_EQ - eqlms_cccf_destroy (_q->equalizer); // LMS equalizer -#endif - windowcf_destroy(_q->buf_debug); + qdsync_cccf_destroy (_q->sync); // frame detector/synchronizer + qpacketmodem_destroy(_q->dec); // payload demodulator + qpilotsync_destroy (_q->pilotsync); // pilot synchronizer + windowcf_destroy (_q->buf_debug); // free main object memory free(_q); @@ -247,23 +188,8 @@ int framesync64_print(framesync64 _q) // reset frame synchronizer object int framesync64_reset(framesync64 _q) { - // reset binary pre-demod synchronizer - qdetector_cccf_reset(_q->detector); - - // reset carrier recovery objects - nco_crcf_reset(_q->mixer); - - // reset symbol timing recovery state - firpfb_crcf_reset(_q->mf); - - // reset state - _q->state = FRAMESYNC64_STATE_DETECTFRAME; - _q->preamble_counter= 0; - _q->payload_counter = 0; - - // reset frame statistics - _q->framesyncstats.evm = 0.0f; - + // reset synchronizer + qdsync_cccf_reset(_q->sync); return LIQUID_OK; } @@ -291,233 +217,64 @@ int framesync64_execute(framesync64 _q, float complex * _x, unsigned int _n) { - unsigned int i; - for (i=0; i<_n; i++) { - // push sample into debug buffer - windowcf_push(_q->buf_debug, _x[i]); - - switch (_q->state) { - case FRAMESYNC64_STATE_DETECTFRAME: - // detect frame (look for p/n sequence) - framesync64_execute_seekpn(_q, _x[i]); - break; - case FRAMESYNC64_STATE_RXPREAMBLE: - // receive p/n sequence symbols - framesync64_execute_rxpreamble(_q, _x[i]); - break; - case FRAMESYNC64_STATE_RXPAYLOAD: - // receive payload symbols - framesync64_execute_rxpayload(_q, _x[i]); - break; - default: - return liquid_error(LIQUID_EINT,"framesync64_exeucte(), unknown/unsupported state"); - } - } - return LIQUID_OK; + return qdsync_cccf_execute(_q->sync, _x, _n); } -// +// // internal methods // -// execute synchronizer, seeking p/n sequence -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int framesync64_execute_seekpn(framesync64 _q, - float complex _x) -{ - // push through pre-demod synchronizer - float complex * v = qdetector_cccf_execute(_q->detector, _x); - - // check if frame has been detected - if (v != NULL) { - // get estimates - _q->tau_hat = qdetector_cccf_get_tau (_q->detector); - _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); - _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); - _q->phi_hat = qdetector_cccf_get_phi (_q->detector); - - // set appropriate filterbank index - if (_q->tau_hat > 0) { - _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; - _q->mf_counter = 0; - } else { - _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; - _q->mf_counter = 1; - } - //printf("***** frame detected! tau-hat:%8.4f(%u/%u), dphi-hat:%8.4f, gamma:%8.2f dB\n", - // _q->tau_hat, _q->pfb_index, _q->npfb, _q->dphi_hat, 20*log10f(_q->gamma_hat)); - - // output filter scale - firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); - - // set frequency/phase of mixer - nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); - nco_crcf_set_phase (_q->mixer, _q->phi_hat ); - - // update state - _q->state = FRAMESYNC64_STATE_RXPREAMBLE; - - // run buffered samples through synchronizer - unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); - framesync64_execute(_q, v, buf_len); - } - return LIQUID_OK; -} - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -// _y : output symbol -int framesync64_step(framesync64 _q, - float complex _x, - float complex * _y) +// synchronization callback, return 0:continue, 1:reset +int framesync64_callback_internal(float complex * _buf, + unsigned int _buf_len, + void * _context) { - // mix sample down - float complex v; - nco_crcf_mix_down(_q->mixer, _x, &v); - nco_crcf_step (_q->mixer); - - // push sample into filterbank - firpfb_crcf_push (_q->mf, v); - firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); - -#if FRAMESYNC64_ENABLE_EQ - // push sample through equalizer - eqlms_cccf_push(_q->equalizer, v); -#endif - - // increment counter to determine if sample is available - _q->mf_counter++; - int sample_available = (_q->mf_counter >= 1) ? 1 : 0; - - // set output sample if available - if (sample_available) { -#if FRAMESYNC64_ENABLE_EQ - // compute equalizer output - eqlms_cccf_execute(_q->equalizer, &v); -#endif - - // set output - *_y = v; - - // decrement counter by k=2 samples/symbol - _q->mf_counter -= 2; + // type cast context input as frame synchronizer object + framesync64 _q = (framesync64)_context; + + // recover data symbols from pilots (input buffer with 64-symbol preamble offset) + qpilotsync_execute(_q->pilotsync, _buf + 64, _q->payload_sym); + + // decode payload + _q->payload_valid = qpacketmodem_decode(_q->dec, + _q->payload_sym, + _q->payload_dec); + + // update statistics + _q->framedatastats.num_frames_detected++; + _q->framedatastats.num_headers_valid += _q->payload_valid; + _q->framedatastats.num_payloads_valid += _q->payload_valid; + _q->framedatastats.num_bytes_received += _q->payload_valid ? 64 : 0; + + // set framesyncstats internals + _q->framesyncstats.evm = qpacketmodem_get_demodulator_evm(_q->dec); + _q->framesyncstats.rssi = 20*log10f( qdsync_cccf_get_gamma(_q->sync) ); + _q->framesyncstats.cfo = qdsync_cccf_get_dphi(_q->sync) + qpilotsync_get_dphi(_q->pilotsync) / 2.0f; + _q->framesyncstats.framesyms = _q->payload_sym; + _q->framesyncstats.num_framesyms = 600; + _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; + _q->framesyncstats.mod_bps = 2; + _q->framesyncstats.check = LIQUID_CRC_24; + _q->framesyncstats.fec0 = LIQUID_FEC_NONE; + _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; + + // invoke callback + if (_q->callback != NULL) { + int rc = + _q->callback(&_q->payload_dec[0], // header is first 8 bytes + _q->payload_valid, + &_q->payload_dec[8], // payload is last 64 bytes + 64, + _q->payload_valid, + _q->framesyncstats, + _q->userdata); + + // export debugging based on return value + framesync64_debug_export(_q, rc, _buf+64); } - // return flag - return sample_available; -} - -// execute synchronizer, receiving p/n sequence -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int framesync64_execute_rxpreamble(framesync64 _q, - float complex _x) -{ - // step synchronizer - float complex mf_out = 0.0f; - int sample_available = framesync64_step(_q, _x, &mf_out); - - // compute output if timeout - if (sample_available) { - - // save output in p/n symbols buffer -#if FRAMESYNC64_ENABLE_EQ - unsigned int delay = 2*_q->m + 3; // delay from matched filter and equalizer -#else - unsigned int delay = 2*_q->m; // delay from matched filter -#endif - if (_q->preamble_counter >= delay) { - unsigned int index = _q->preamble_counter-delay; - - _q->preamble_rx[index] = mf_out; - -#if FRAMESYNC64_ENABLE_EQ - // train equalizer - eqlms_cccf_step(_q->equalizer, _q->preamble_pn[index], mf_out); -#endif - } - - // update p/n counter - _q->preamble_counter++; - - // update state - if (_q->preamble_counter == 64 + delay) - _q->state = FRAMESYNC64_STATE_RXPAYLOAD; - } - return LIQUID_OK; -} - -// execute synchronizer, receiving payload -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int framesync64_execute_rxpayload(framesync64 _q, - float complex _x) -{ - // step synchronizer - float complex mf_out = 0.0f; - int sample_available = framesync64_step(_q, _x, &mf_out); - - // compute output if timeout - if (sample_available) { - // save payload symbols (modem input/output) - _q->payload_rx[_q->payload_counter] = mf_out; - - // increment counter - _q->payload_counter++; - - if (_q->payload_counter == 630) { - // recover data symbols from pilots - qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); - - // decode payload - _q->payload_valid = qpacketmodem_decode(_q->dec, - _q->payload_sym, - _q->payload_dec); - - // update statistics - _q->framedatastats.num_frames_detected++; - _q->framedatastats.num_headers_valid += _q->payload_valid; - _q->framedatastats.num_payloads_valid += _q->payload_valid; - _q->framedatastats.num_bytes_received += _q->payload_valid ? 64 : 0; - - // invoke callback - if (_q->callback != NULL) { - // set framesyncstats internals - _q->framesyncstats.evm = qpacketmodem_get_demodulator_evm(_q->dec); //qpilotsync_get_evm(_q->pilotsync); - _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); - _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); - _q->framesyncstats.framesyms = _q->payload_sym; - _q->framesyncstats.num_framesyms = 600; - _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; - _q->framesyncstats.mod_bps = 2; - _q->framesyncstats.check = LIQUID_CRC_24; - _q->framesyncstats.fec0 = LIQUID_FEC_NONE; - _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; - - // invoke callback method - int rc = - _q->callback(&_q->payload_dec[0], // header is first 8 bytes - _q->payload_valid, - &_q->payload_dec[8], // payload is last 64 bytes - 64, - _q->payload_valid, - _q->framesyncstats, - _q->userdata); - - // export debugging based on return value - framesync64_debug_export(_q, rc); - } - - // reset frame synchronizer - return framesync64_reset(_q); - } - } - return LIQUID_OK; + // reset frame synchronizer + return framesync64_reset(_q); } // DEPRECATED: enable debugging @@ -542,14 +299,14 @@ int framesync64_debug_print(framesync64 _q, // get detection threshold float framesync64_get_threshold(framesync64 _q) { - return qdetector_cccf_get_threshold(_q->detector); + return qdsync_cccf_get_threshold(_q->sync); } // set detection threshold int framesync64_set_threshold(framesync64 _q, float _threshold) { - return qdetector_cccf_set_threshold(_q->detector, _threshold); + return qdsync_cccf_set_threshold(_q->sync, _threshold); } // set prefix for exporting debugging files, default: "framesync64" @@ -606,8 +363,9 @@ framedatastats_s framesync64_get_framedatastats(framesync64 _q) } // export debugging samples to file -int framesync64_debug_export(framesync64 _q, - int _code) +int framesync64_debug_export(framesync64 _q, + int _code, + float complex * _payload_rx) { // determine what to do based on callback return code if (_code == 0) { @@ -651,14 +409,16 @@ int framesync64_debug_export(framesync64 _q, //framesyncstats_export(_q->framesyncstats, fid); // export measured offsets - fwrite(&(_q->tau_hat), sizeof(float), 1, fid); - fwrite(&(_q->dphi_hat), sizeof(float), 1, fid); - fwrite(&(_q->phi_hat), sizeof(float), 1, fid); - fwrite(&(_q->gamma_hat),sizeof(float), 1, fid); - fwrite(&(_q->framesyncstats.evm), sizeof(float), 1, fid); + float tau_hat = 0.0f; + float phi_hat = 0.0f; + fwrite(&tau_hat, sizeof(float), 1, fid); + fwrite(&(_q->framesyncstats.cfo), sizeof(float), 1, fid); + fwrite(&phi_hat, sizeof(float), 1, fid); + fwrite(&(_q->framesyncstats.rssi), sizeof(float), 1, fid); + fwrite(&(_q->framesyncstats.evm), sizeof(float), 1, fid); // export payload values - fwrite(_q->payload_rx, sizeof(float complex), 630, fid); + fwrite(_payload_rx, sizeof(float complex), 630, fid); fwrite(_q->payload_sym, sizeof(float complex), 600, fid); fwrite(_q->payload_dec, sizeof(unsigned char), 72, fid); diff --git a/src/framing/tests/framesync64_autotest.c b/src/framing/tests/framesync64_autotest.c index ba495c99e..7a1b78cc7 100644 --- a/src/framing/tests/framesync64_autotest.c +++ b/src/framing/tests/framesync64_autotest.c @@ -121,6 +121,8 @@ void autotest_framesync64_copy() // copy object, but set different context framesync64 fs1 = framesync64_copy(fs0); framesync64_set_userdata(fs1, (void*)&frames_recovered_1); + framesync64_print(fs0); + framesync64_print(fs1); // try to receive the frame with each receiver for (i=0; i Date: Wed, 22 Feb 2023 17:16:27 -0500 Subject: [PATCH 035/334] qdsync: making macro in global header --- include/liquid.h | 150 ++++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 67 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 2773884f3..38f575cd9 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -6260,73 +6260,89 @@ float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate -// Frame detector and synchronizer; uses a novel correlation method to -// detect a synchronization pattern, estimate carrier frequency and -// phase offsets as well as timing phase, then correct for these -// impairments in a simple interface suitable for custom frame recovery. -typedef struct qdsync_cccf_s * qdsync_cccf; - -// synchronization callback, return 0:continue, 1:reset -typedef int (*qdsync_callback)(liquid_float_complex * _buf, - unsigned int _buf_len, - void * _context); -// metadata struct: -// - sample count since object was created -// - sample count since beginning of frame - -// create detector with generic sequence -// _s : sample sequence -// _s_len : length of sample sequence -qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _s, - unsigned int _s_len, - int _ftype, - unsigned int _k, - unsigned int _m, - float _beta, - qdsync_callback _callback, - void * _context); - -// Copy object recursively including all internal objects and state -qdsync_cccf qdsync_cccf_copy(qdsync_cccf _q); - -int qdsync_cccf_destroy(qdsync_cccf _q); -int qdsync_cccf_reset (qdsync_cccf _q); -int qdsync_cccf_print (qdsync_cccf _q); - -// get detection threshold -float qdsync_cccf_get_threshold(qdsync_cccf _q); - -// set detection threshold -int qdsync_cccf_set_threshold(qdsync_cccf _q, float _threshold); - -// set carrier offset search range -int qdsync_cccf_set_range(qdsync_cccf _q, - float _dphi_max); - -// set callback method -int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); - -// set context value -int qdsync_cccf_set_context (qdsync_cccf _q, void * _context); - -// Set callback buffer size (the number of symbol provided to the callback -// whenever it is invoked). -int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len); - -// execute block of samples -int qdsync_cccf_execute(qdsync_cccf _q, - liquid_float_complex * _buf, - unsigned int _buf_len); - -// is synchronizer actively running? -int qdsync_cccf_is_open(qdsync_cccf _q); +// +// qdsync +// +#define LIQUID_QDSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(qdsync_cccf,name) + +#define LIQUID_QDSYNC_DEFINE_API(QDSYNC,TO,TC,TI) \ + \ +/* Frame detector and synchronizer; uses a novel correlation method to */ \ +/* detect a synchronization pattern, estimate carrier frequency and */ \ +/* phase offsets as well as timing phase, then correct for these */ \ +/* impairments in a simple interface suitable for custom frame recovery.*/ \ +typedef struct QDSYNC(_s) * QDSYNC(); \ + \ +/* synchronization callback, return 0:continue, 1:reset */ \ +typedef int (*QDSYNC(_callback))(TO * _buf, \ + unsigned int _buf_len, \ + void * _context); \ + \ +/* create detector with generic sequence */ \ +/* _s : sample sequence */ \ +/* _s_len : length of sample sequence */ \ +/* _ftype : filter type */ \ +/* _k : samples per symbol */ \ +/* _m : filter semi-length */ \ +/* _beta : filter excess bandwidth factor */ \ +/* _callback : user-defined callback */ \ +/* _context : user-defined context */ \ +QDSYNC() QDSYNC(_create_linear)(TI * _s, \ + unsigned int _s_len, \ + int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + QDSYNC(_callback) _callback, \ + void * _context); \ + \ +/* Copy object recursively including all internal objects and state */ \ +QDSYNC() QDSYNC(_copy)(QDSYNC() _q); \ + \ +int QDSYNC(_destroy)(QDSYNC() _q); \ +int QDSYNC(_reset) (QDSYNC() _q); \ +int QDSYNC(_print) (QDSYNC() _q); \ + \ +/* get detection threshold */ \ +float QDSYNC(_get_threshold)(QDSYNC() _q); \ + \ +/* set detection threshold */ \ +int QDSYNC(_set_threshold)(QDSYNC() _q, \ + float _threshold); \ + \ +/* set carrier offset search range */ \ +int QDSYNC(_set_range)(QDSYNC() _q, \ + float _dphi_max); \ + \ +/* set callback method */ \ +int QDSYNC(_set_callback)(QDSYNC() _q, \ + QDSYNC(_callback) _callback); \ + \ +/* set context value */ \ +int QDSYNC(_set_context)(QDSYNC() _q, void * _context); \ + \ +/* Set callback buffer size (the number of symbol provided to the */ \ +/* callback whenever it is invoked). */ \ +int QDSYNC(_set_buf_len )(QDSYNC() _q, unsigned int _buf_len); \ + \ +/* execute block of samples */ \ +int QDSYNC(_execute)(QDSYNC() _q, \ + TI * _buf, \ + unsigned int _buf_len); \ + \ +/* Return flag indicating if synchronizer actively running. */ \ +int QDSYNC(_is_open)(QDSYNC() _q); \ + \ +float QDSYNC(_get_rxy) (QDSYNC() _q); \ +float QDSYNC(_get_tau) (QDSYNC() _q); \ +float QDSYNC(_get_gamma)(QDSYNC() _q); \ +float QDSYNC(_get_dphi) (QDSYNC() _q); \ +float QDSYNC(_get_phi) (QDSYNC() _q); \ -// get detection metrics and offsets -float qdsync_cccf_get_rxy (qdsync_cccf _q); // correlator output -float qdsync_cccf_get_tau (qdsync_cccf _q); // fractional timing offset estimate -float qdsync_cccf_get_gamma(qdsync_cccf _q); // channel gain -float qdsync_cccf_get_dphi (qdsync_cccf _q); // carrier frequency offset estimate -float qdsync_cccf_get_phi (qdsync_cccf _q); // carrier phase offset estimate +LIQUID_QDSYNC_DEFINE_API(LIQUID_QDSYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) // // Pre-demodulation detector From 32275d2817d156ea7038542047fbff95340d1e04 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 28 Feb 2023 17:42:24 -0500 Subject: [PATCH 036/334] ofdmframe: moving subcarrier verification check inside common function --- src/multichannel/src/ofdmframe.common.c | 8 ++++++++ src/multichannel/src/ofdmframegen.c | 10 ++-------- src/multichannel/src/ofdmframesync.c | 12 ++++-------- src/multichannel/tests/ofdmframe_autotest.c | 2 ++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/multichannel/src/ofdmframe.common.c b/src/multichannel/src/ofdmframe.common.c index cc30554c2..2d612eb15 100644 --- a/src/multichannel/src/ofdmframe.common.c +++ b/src/multichannel/src/ofdmframe.common.c @@ -294,6 +294,14 @@ int ofdmframe_validate_sctype(unsigned char * _p, } } + // validate subcarrier allocation + if ( (M_pilot + M_data) == 0) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one enabled subcarrier"); + if (M_data == 0) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one data subcarrier"); + if (M_pilot < 2) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least two pilot subcarriers"); + // set outputs *_M_null = M_null; *_M_pilot = M_pilot; diff --git a/src/multichannel/src/ofdmframegen.c b/src/multichannel/src/ofdmframegen.c index 8553ef538..e45719898 100644 --- a/src/multichannel/src/ofdmframegen.c +++ b/src/multichannel/src/ofdmframegen.c @@ -84,8 +84,8 @@ ofdmframegen ofdmframegen_create(unsigned int _M, unsigned char * _p) { // validate input - if (_M < 2) - return liquid_error_config("ofdmframegen_create(), number of subcarriers must be at least 2"); + if (_M < 8) + return liquid_error_config("ofdmframegen_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframegen_create(), number of subcarriers must be even"); if (_cp_len > _M) @@ -111,12 +111,6 @@ ofdmframegen ofdmframegen_create(unsigned int _M, // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframegen_create(), invalid subcarrier allocation"); - if ( (q->M_pilot + q->M_data) == 0) - return liquid_error_config("ofdmframegen_create(), must have at least one enabled subcarrier"); - if (q->M_data == 0) - return liquid_error_config("ofdmframegen_create(), must have at least one data subcarriers"); - if (q->M_pilot < 2) - return liquid_error_config("ofdmframegen_create(), must have at least two pilot subcarriers"); unsigned int i; diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 0e7ce5448..f69e35e6e 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -149,11 +149,13 @@ ofdmframesync ofdmframesync_create(unsigned int _M, // validate input if (_M < 8) - return liquid_error_config("ofdmframesync_create(), less than 8 subcarriers"); + return liquid_error_config("ofdmframesync_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframesync_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers"); + if (_taper_len > _cp_len) + return liquid_error_config("ofdmframesync_create(), taper length cannot exceed cyclic prefix"); q->M = _M; q->cp_len = _cp_len; @@ -172,12 +174,6 @@ ofdmframesync ofdmframesync_create(unsigned int _M, // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframesync_create(), invalid subcarrier allocation"); - if ( (q->M_pilot + q->M_data) == 0) - return liquid_error_config("ofdmframesync_create(), must have at least one enabled subcarrier"); - if (q->M_data == 0) - return liquid_error_config("ofdmframesync_create(), must have at least one data subcarriers"); - if (q->M_pilot < 2) - return liquid_error_config("ofdmframesync_create(), must have at least two pilot subcarriers"); // create transform object q->X = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index b949a8ece..1b1643888 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -159,6 +159,7 @@ void autotest_ofdmframegen_config() CONTEND_ISNULL(ofdmframegen_create( 7, 16, 4, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmframegen_create(65, 16, 4, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmframegen_create(64, 66, 4, NULL)) // cyclic prefix length too large + CONTEND_ISNULL(ofdmframegen_create(64, 16,24, NULL)) // taper length greater than cyclic prefix // create proper object and test configurations ofdmframegen q = ofdmframegen_create(64, 16, 4, NULL); @@ -183,6 +184,7 @@ void autotest_ofdmframesync_config() CONTEND_ISNULL(ofdmframesync_create( 7, 16, 4, NULL, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmframesync_create(65, 16, 4, NULL, NULL, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmframesync_create(64, 66, 4, NULL, NULL, NULL)) // cyclic prefix length too large + CONTEND_ISNULL(ofdmframesync_create(64, 16,24, NULL, NULL, NULL)) // taper length greater than cyclic prefix // create proper object and test configurations ofdmframesync q = ofdmframesync_create(64, 16, 4, NULL, NULL, NULL); From aee1ebf65fe1f5431bd7eb48a49a93ef0beb2617 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:08:47 -0500 Subject: [PATCH 037/334] ofdmframesync: using internal method to unwrap phase --- src/multichannel/src/ofdmframesync.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index f69e35e6e..2a482cd1b 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -951,12 +951,7 @@ int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase - for (i=1; i M_PI) - y_arg[i] -= 2*M_PI; - while ((y_arg[i] - y_arg[i-1]) < -M_PI) - y_arg[i] += 2*M_PI; - } + liquid_unwrap_phase(y_arg, N); // fit to polynomial polyf_fit(x_freq, y_abs, N, p_abs, _order+1); @@ -1032,12 +1027,7 @@ int ofdmframesync_rxsymbol(ofdmframesync _q) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase - for (i=1; i<_q->M_pilot; i++) { - while ((y_phase[i] - y_phase[i-1]) > M_PI) - y_phase[i] -= 2*M_PI; - while ((y_phase[i] - y_phase[i-1]) < -M_PI) - y_phase[i] += 2*M_PI; - } + liquid_unwrap_phase(y_phase, _q->M_pilot); // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(x_phase, y_phase, _q->M_pilot, p_phase, 2); From d75799c62dc06e919c9445ddb04e2a4913c1a9c0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:12:27 -0500 Subject: [PATCH 038/334] ofdmframesync: adding additional configuration tests --- src/multichannel/src/ofdmframesync.c | 3 +-- src/multichannel/tests/ofdmframe_autotest.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 2a482cd1b..3fcf1d953 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -413,8 +413,7 @@ float ofdmframesync_get_cfo(ofdmframesync _q) // set receiver carrier frequency offset estimate int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo) { - nco_crcf_set_frequency(_q->nco_rx, _cfo); - return LIQUID_OK; + return nco_crcf_set_frequency(_q->nco_rx, _cfo); } // diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index 1b1643888..2ca3ab93c 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -190,6 +190,8 @@ void autotest_ofdmframesync_config() ofdmframesync q = ofdmframesync_create(64, 16, 4, NULL, NULL, NULL); CONTEND_EQUALITY(LIQUID_OK, ofdmframesync_print(q)) + CONTEND_EQUALITY( 0, ofdmframesync_is_frame_open(q)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframesync_set_cfo(q,0.0f)) ofdmframesync_destroy(q); } From 2ebf1e034d6439957bbc8e633cc4626049a76db9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:17:09 -0500 Subject: [PATCH 039/334] ofdmframesync: moving internal funciton declarations from header --- include/liquid.internal.h | 45 ------------------------- src/multichannel/src/ofdmframesync.c | 49 +++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index e8e2e0d90..e5f32f0a8 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1486,51 +1486,6 @@ int ofdmframe_init_S1(unsigned char * _p, int ofdmframegen_gensymbol(ofdmframegen _q, float complex * _buffer); -int ofdmframesync_cpcorrelate(ofdmframesync _q); -int ofdmframesync_findrxypeak(ofdmframesync _q); -int ofdmframesync_rxpayload(ofdmframesync _q); - -int ofdmframesync_execute_seekplcp(ofdmframesync _q); -int ofdmframesync_execute_S0a(ofdmframesync _q); -int ofdmframesync_execute_S0b(ofdmframesync _q); -int ofdmframesync_execute_S1( ofdmframesync _q); -int ofdmframesync_execute_rxsymbols(ofdmframesync _q); - -int ofdmframesync_S0_metrics(ofdmframesync _q, - float complex * _G, - float complex * _s_hat); - -// estimate short sequence gain -// _q : ofdmframesync object -// _x : input array (time) -// _G : output gain (freq) -int ofdmframesync_estimate_gain_S0(ofdmframesync _q, - float complex * _x, - float complex * _G); - -// estimate long sequence gain -// _q : ofdmframesync object -// _x : input array (time) -// _G : output gain (freq) -int ofdmframesync_estimate_gain_S1(ofdmframesync _q, - float complex * _x, - float complex * _G); - -// estimate complex equalizer gain from G0 and G1 -// _q : ofdmframesync object -// _ntaps : number of time-domain taps for smoothing -int ofdmframesync_estimate_eqgain(ofdmframesync _q, - unsigned int _ntaps); - -// estimate complex equalizer gain from G0 and G1 using polynomial fit -// _q : ofdmframesync object -// _order : polynomial order -int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, - unsigned int _order); - -// recover symbol, correcting for gain, pilot phase, etc. -int ofdmframesync_rxsymbol(ofdmframesync _q); - // // MODULE : nco (numerically-controlled oscillator) // diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 3fcf1d953..a1e2f5ecf 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// ofdmframesync.c -// // OFDM frame synchronizer -// #include #include @@ -41,6 +37,49 @@ #define OFDMFRAMESYNC_ENABLE_SQUELCH 0 +// forward declaration of internal methods + +int ofdmframesync_execute_seekplcp(ofdmframesync _q); +int ofdmframesync_execute_S0a(ofdmframesync _q); +int ofdmframesync_execute_S0b(ofdmframesync _q); +int ofdmframesync_execute_S1( ofdmframesync _q); +int ofdmframesync_execute_rxsymbols(ofdmframesync _q); + +int ofdmframesync_S0_metrics(ofdmframesync _q, + float complex * _G, + float complex * _s_hat); + +// estimate short sequence gain +// _q : ofdmframesync object +// _x : input array (time) +// _G : output gain (freq) +int ofdmframesync_estimate_gain_S0(ofdmframesync _q, + float complex * _x, + float complex * _G); + +// estimate long sequence gain +// _q : ofdmframesync object +// _x : input array (time) +// _G : output gain (freq) +int ofdmframesync_estimate_gain_S1(ofdmframesync _q, + float complex * _x, + float complex * _G); + +// estimate complex equalizer gain from G0 and G1 +// _q : ofdmframesync object +// _ntaps : number of time-domain taps for smoothing +int ofdmframesync_estimate_eqgain(ofdmframesync _q, + unsigned int _ntaps); + +// estimate complex equalizer gain from G0 and G1 using polynomial fit +// _q : ofdmframesync object +// _order : polynomial order +int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, + unsigned int _order); + +// recover symbol, correcting for gain, pilot phase, etc. +int ofdmframesync_rxsymbol(ofdmframesync _q); + struct ofdmframesync_s { unsigned int M; // number of subcarriers unsigned int M2; // number of subcarriers (divided by 2) @@ -752,7 +791,7 @@ int ofdmframesync_execute_rxsymbols(ofdmframesync _q) } // compute S0 metrics -int ofdmframesync_S0_metrics(ofdmframesync _q, +int ofdmframesync_S0_metrics(ofdmframesync _q, float complex * _G, float complex * _s_hat) { From a7b1372f7c500b53bd2e766790d3302efcc3c6a5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:40:51 -0500 Subject: [PATCH 040/334] ofdmframesync: disabling debugging (preprocessor) --- src/multichannel/src/ofdmframesync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index a1e2f5ecf..bd88ff947 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -30,7 +30,7 @@ #include "liquid.internal.h" -#define DEBUG_OFDMFRAMESYNC 1 +#define DEBUG_OFDMFRAMESYNC 0 #define DEBUG_OFDMFRAMESYNC_PRINT 0 #define DEBUG_OFDMFRAMESYNC_FILENAME "ofdmframesync_internal_debug.m" #define DEBUG_OFDMFRAMESYNC_BUFFER_LEN (2048) From 50b51a0ec570e3b85ae0da40c0f5cfbc8fbab547 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:46:53 -0500 Subject: [PATCH 041/334] ofdmframesync: block-commenting unused method for estimating equalizer gain --- src/multichannel/src/ofdmframesync.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index bd88ff947..8a05e20b1 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -68,8 +68,7 @@ int ofdmframesync_estimate_gain_S1(ofdmframesync _q, // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing -int ofdmframesync_estimate_eqgain(ofdmframesync _q, - unsigned int _ntaps); +//int ofdmframesync_estimate_eqgain(ofdmframesync _q, unsigned int _ntaps); // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object @@ -879,6 +878,7 @@ int ofdmframesync_estimate_gain_S1(ofdmframesync _q, return LIQUID_OK; } +#if 0 // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing @@ -939,6 +939,7 @@ int ofdmframesync_estimate_eqgain(ofdmframesync _q, } return LIQUID_OK; } +#endif // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object From b9f927b1afd818140bb71d043707918b90a86d9d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:51:15 -0500 Subject: [PATCH 042/334] ofdmframegen: moving internal method declarations from header --- include/liquid.internal.h | 6 +----- src/multichannel/src/ofdmframegen.c | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index e5f32f0a8..d38648460 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1482,10 +1482,6 @@ int ofdmframe_init_S1(unsigned char * _p, float complex * _s1, unsigned int * _M_S1); -// generate symbol (add cyclic prefix/postfix, overlap) -int ofdmframegen_gensymbol(ofdmframegen _q, - float complex * _buffer); - // // MODULE : nco (numerically-controlled oscillator) // diff --git a/src/multichannel/src/ofdmframegen.c b/src/multichannel/src/ofdmframegen.c index e45719898..150cb8532 100644 --- a/src/multichannel/src/ofdmframegen.c +++ b/src/multichannel/src/ofdmframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,10 @@ #define DEBUG_OFDMFRAMEGEN 1 +// generate symbol (add cyclic prefix/postfix, overlap) +int ofdmframegen_gensymbol(ofdmframegen _q, + float complex * _buffer); + struct ofdmframegen_s { unsigned int M; // number of subcarriers unsigned int cp_len; // cyclic prefix length From 3acaf727fb6aade3fbaef834eb8ef88c640931a8 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 21:03:24 -0500 Subject: [PATCH 043/334] firpfbch2/autotest: adding configuration testing --- .../tests/firpfbch2_crcf_autotest.c | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/multichannel/tests/firpfbch2_crcf_autotest.c b/src/multichannel/tests/firpfbch2_crcf_autotest.c index c00a728b5..9c5f135ec 100644 --- a/src/multichannel/tests/firpfbch2_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch2_crcf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -97,7 +97,6 @@ void autotest_firpfbch2_crcf_n16() { firpfbch2_crcf_runtest( 16, 5, 60.0f); } void autotest_firpfbch2_crcf_n32() { firpfbch2_crcf_runtest( 32, 5, 60.0f); } void autotest_firpfbch2_crcf_n64() { firpfbch2_crcf_runtest( 64, 5, 60.0f); } - void autotest_firpfbch2_crcf_copy() { // create channelizer @@ -140,3 +139,36 @@ void autotest_firpfbch2_crcf_copy() firpfbch2_crcf_destroy(q_copy); } +void autotest_firpfbch2_crcf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firpfbch2_crcf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(firpfbch2_crcf_create( 77, 76, 12, NULL)) // invalid type + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 17, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser( 77, 76, 12, 60.0f)) // invalid type + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 0, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 17, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 76, 0, 60.0f)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch2_crcf_copy(NULL)) + + // create proper object and test configurations + firpfbch2_crcf q = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 76, 12, 60.0f); + + CONTEND_EQUALITY(LIQUID_OK, firpfbch2_crcf_print(q)) + CONTEND_EQUALITY(LIQUID_ANALYZER, firpfbch2_crcf_get_type(q)) + CONTEND_EQUALITY( 76, firpfbch2_crcf_get_M(q)) + CONTEND_EQUALITY( 12, firpfbch2_crcf_get_m(q)) + + firpfbch2_crcf_destroy(q); +} + From 77e3e634ce8773ea6c492d7db83a13c4f135bffd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 3 Mar 2023 08:21:20 -0500 Subject: [PATCH 044/334] firpfbch: adding configuration testing --- makefile.in | 1 + .../tests/firpfbch_crcf_autotest.c | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/multichannel/tests/firpfbch_crcf_autotest.c diff --git a/makefile.in b/makefile.in index 7e415d7c1..3c0246d9b 100644 --- a/makefile.in +++ b/makefile.in @@ -949,6 +949,7 @@ multichannel_autotests := \ src/multichannel/tests/firpfbch2_crcf_autotest.c \ src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c \ src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c \ + src/multichannel/tests/firpfbch_crcf_autotest.c \ src/multichannel/tests/ofdmframe_autotest.c \ # benchmarks diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c new file mode 100644 index 000000000..fb9deb967 --- /dev/null +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "autotest/autotest.h" +#include "liquid.h" + +void autotest_firpfbch_crcf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firpfbch_crcf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(firpfbch_crcf_create( 77, 76, 12, NULL)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + + //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) + + // create proper object and test configurations + firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 12, 60.0f); + + CONTEND_EQUALITY(LIQUID_OK, firpfbch_crcf_print(q)) + + firpfbch_crcf_destroy(q); +} + From 7d31ed82007528da000d528e2fa85deccdf33dd5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 07:48:33 -0500 Subject: [PATCH 045/334] firpfbch/autotest: adding more configuration tests --- src/multichannel/src/firpfbch.proto.c | 14 ++++++-------- src/multichannel/tests/firpfbch_crcf_autotest.c | 8 ++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 28826a2b5..1f147e795 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// firpfbch.c -// -// finite impulse response polyphase filterbank channelizer -// +// firpfbch : finite impulse response polyphase filterbank channelizer #include #include @@ -77,7 +73,7 @@ FIRPFBCH() FIRPFBCH(_create)(int _type, { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) - return liquid_error_config("firpfbch_%s_create(), invalid type %d", EXTENSION_FULL, _type); + return liquid_error_config("firpfbch_%s_create(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create(), number of channels must be greater than 0", EXTENSION_FULL); if (_p == 0) @@ -148,6 +144,8 @@ FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, float _as) { // validate input + if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) + return liquid_error_config("firpfbch_%s_create_kaiser(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create_kaiser(), number of channels must be greater than 0", EXTENSION_FULL); if (_m == 0) @@ -190,7 +188,7 @@ FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) - return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid type %d", EXTENSION_FULL, _type); + return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create_rnyquist(), number of channels must be greater than 0", EXTENSION_FULL); if (_m == 0) diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c index fb9deb967..55204b882 100644 --- a/src/multichannel/tests/firpfbch_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -38,6 +38,14 @@ void autotest_firpfbch_crcf_config() CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + CONTEND_ISNULL(firpfbch_crcf_create_kaiser( 77, 76, 12, 60.0f)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 0, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 0, 60.0f)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist( 77, 76, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 0, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 0, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid filter semi-length + //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) // create proper object and test configurations From 9328b18e2a28f8e9548ff71aadf78cca9de64bc7 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 08:10:57 -0500 Subject: [PATCH 046/334] firpfbch: using prototype filter generation for create_rnyquist() --- src/multichannel/src/firpfbch.proto.c | 22 ++----------------- .../tests/firpfbch_crcf_autotest.c | 2 ++ 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 1f147e795..0683c3a1a 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -197,26 +197,8 @@ FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, // design filter based on requested prototype unsigned int h_len = 2*_M*_m + 1; float h[h_len]; - switch (_ftype) { - case LIQUID_FIRFILT_ARKAISER: - // root-Nyquist Kaiser (approximate optimum) - liquid_firdes_arkaiser(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_RKAISER: - // root-Nyquist Kaiser (true optimum) - liquid_firdes_rkaiser(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_RRC: - // root raised-cosine - liquid_firdes_rrcos(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_hM3: - // harris-Moerder-3 filter - liquid_firdes_hM3(_M, _m, _beta, 0.0f, h); - break; - default: - return liquid_error_config("firpfbch_%s_create_rnyquist(), unknown/invalid prototype (%d)", EXTENSION_FULL, _ftype); - } + if (liquid_firdes_prototype(_ftype, _M, _m, _beta, 0.0f, h) != LIQUID_OK) + return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid filter type/configuration", EXTENSION_FULL); // copy coefficients to type-specfic array, reversing order if // channelizer is an analyzer, matched filter: g(-t) diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c index 55204b882..7ada5fd56 100644 --- a/src/multichannel/tests/firpfbch_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -45,6 +45,8 @@ void autotest_firpfbch_crcf_config() CONTEND_ISNULL(firpfbch_crcf_create_rnyquist( 77, 76, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid type CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 0, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 0, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid filter semi-length + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 77.f, LIQUID_FIRFILT_ARKAISER)) // invalid filter excess bandwidth + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 0.2f, LIQUID_FIRFILT_UNKNOWN )) // invalid filter type //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) From 7a624d6dd24f32bb658b721b4a90586c1024f489 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 08:38:20 -0500 Subject: [PATCH 047/334] ofdmframe/autotest: including configuration tests for common functions --- src/multichannel/src/ofdmframe.common.c | 8 +++--- src/multichannel/tests/ofdmframe_autotest.c | 32 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/multichannel/src/ofdmframe.common.c b/src/multichannel/src/ofdmframe.common.c index 2d612eb15..ab7e4d5b1 100644 --- a/src/multichannel/src/ofdmframe.common.c +++ b/src/multichannel/src/ofdmframe.common.c @@ -302,10 +302,10 @@ int ofdmframe_validate_sctype(unsigned char * _p, if (M_pilot < 2) return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least two pilot subcarriers"); - // set outputs - *_M_null = M_null; - *_M_pilot = M_pilot; - *_M_data = M_data; + // set outputs if requested + if (_M_null != NULL) *_M_null = M_null; + if (_M_pilot != NULL) *_M_pilot = M_pilot; + if (_M_data != NULL) *_M_data = M_data; return LIQUID_OK; } diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index 2ca3ab93c..bcb369d45 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -144,6 +144,38 @@ void autotest_ofdmframesync_acquire_n128() { ofdmframesync_acquire_test(128, 16 void autotest_ofdmframesync_acquire_n256() { ofdmframesync_acquire_test(256, 32, 0); } void autotest_ofdmframesync_acquire_n512() { ofdmframesync_acquire_test(512, 64, 0); } +void autotest_ofdmframe_common_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmframe common config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_default_sctype(0, NULL)) // too few subcarriers + + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range( 0, -0.4f, +0.4f, NULL)) // too few subcarriers + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.7f, +0.4f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.4f, +0.7f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.2f, -0.3f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, 0.3f, 0.2f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.02f,+0.02f,NULL)) // too few effective subcarriers + + // generate valid subcarrier allocation + unsigned int M = 120; + unsigned char p[M]; + + // default subcarrier allocation + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_default_sctype(M, p)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) + + // subcarrier allocation within an occupied frequency range + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(M, -0.4f,+0.4f,p)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) +} + void autotest_ofdmframegen_config() { #if LIQUID_STRICT_EXIT From 3cf3ceefcd58e8db8f0d22cbf4e403db40cd267e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 09:01:21 -0500 Subject: [PATCH 048/334] ofdmframe/autotest: testing edge cases for subcarrier allocations --- src/multichannel/tests/ofdmframe_autotest.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index bcb369d45..2e0aed52e 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -174,6 +174,18 @@ void autotest_ofdmframe_common_config() // subcarrier allocation within an occupied frequency range CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(M, -0.4f,+0.4f,p)) CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) + + // invalid subcarrier allocations + unsigned int i; + for (i=0; i Date: Sat, 11 Mar 2023 07:15:02 -0500 Subject: [PATCH 049/334] qpacketmodem/example: adjusting number of trials based on error performance --- examples/qpacketmodem_performance_example.c | 181 ++++++++------------ 1 file changed, 76 insertions(+), 105 deletions(-) diff --git a/examples/qpacketmodem_performance_example.c b/examples/qpacketmodem_performance_example.c index 300c516f3..607d36ab9 100644 --- a/examples/qpacketmodem_performance_example.c +++ b/examples/qpacketmodem_performance_example.c @@ -1,11 +1,6 @@ -// -// qpacketmodem_performance_example.c -// // This example demonstrates the performance of the qpacket modem // object to combine forward error-correction and modulation in one // simple interface. -// - #include #include #include @@ -21,39 +16,41 @@ void usage() { printf("qpacketmodem_performance_example [options]\n"); - printf(" h : print usage\n"); - printf(" p : payload length [bytes], default: 400\n"); - printf(" m : modulation scheme (qpsk default)\n"); + printf(" -h : print usage\n"); + printf(" -p : payload length [bytes], default: 400\n"); + printf(" -m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); - printf(" v : data integrity check: crc32 default\n"); + printf(" -v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); - printf(" c : coding scheme (inner): g2412 default\n"); - printf(" k : coding scheme (outer): none default\n"); + printf(" -c : coding scheme (inner): g2412 default\n"); + printf(" -k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); - printf(" s : SNR start [dB], default: -2\n"); - printf(" x : SNR max [dB], default: 13\n"); - printf(" n : number of SNR steps, default: 16\n"); - printf(" t : number of trials, default: 800\n"); + printf(" -s : SNR start [dB], default: -5\n"); + printf(" -x : SNR max [dB], default: 20\n"); + printf(" -d : SNR step [dB], default: 0.5\n"); + printf(" -e : minimum number of packet errors per step, default: 50\n"); + printf(" -t : minimum number of packet trials per step, default: 2000\n"); + printf(" -T : maximum number of packet trials per step, default: 40000\n"); } int main(int argc, char *argv[]) { - //srand( time(NULL) ); - - // options + // options (defaults to frame64 parameters) modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme - crc_scheme check = LIQUID_CRC_32; // data validity check - fec_scheme fec0 = LIQUID_FEC_GOLAY2412; // fec (inner) - fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) - unsigned int payload_len = 400; // payload length + crc_scheme check = LIQUID_CRC_24; // data validity check + fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) + fec_scheme fec1 = LIQUID_FEC_GOLAY2412; // fec (outer) + unsigned int payload_len = 72; // payload length float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) - float SNRdB_max = 10.0f; // signal-to-noise ratio (maximum) - unsigned int num_snr = 31; // number of SNR steps - unsigned int num_packet_trials = 800; // number of trials + float SNRdB_max = 20.0f; // signal-to-noise ratio (maximum) + float SNRdB_step = 0.5f; // signal-to-noise ratio (maximum) + unsigned int min_packet_errors = 50; // minimum errors to observe for each step + unsigned int min_packet_trials = 2000; // minimum number of packets for each step + unsigned int max_packet_trials =40000; // maximum number of packets for each step // get options int dopt; - while((dopt = getopt(argc,argv,"hp:m:v:c:k:s:x:n:t:")) != EOF){ + while((dopt = getopt(argc,argv,"hp:m:v:c:k:s:x:d:e:t:T:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'p': payload_len = atol(optarg); break; @@ -63,18 +60,16 @@ int main(int argc, char *argv[]) case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; - case 'n': num_snr = atoi(optarg); break; - case 't': num_packet_trials = atoi(optarg); break; + case 'd': SNRdB_step = atof(optarg); break; + case 'e': min_packet_errors = atoi(optarg); break; + case 't': min_packet_trials = atoi(optarg); break; + case 'T': max_packet_trials = atoi(optarg); break; default: exit(-1); } } - unsigned int i; - // derived values - float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); - // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, payload_len, check, fec0, fec1, ms); @@ -82,32 +77,27 @@ int main(int argc, char *argv[]) // get frame length unsigned int frame_len = qpacketmodem_get_frame_len(q); - unsigned int num_bit_trials = 8*num_packet_trials*payload_len; // initialize payload unsigned char payload_tx [payload_len]; // payload (transmitted) unsigned char payload_rx [payload_len]; // payload (received) float complex frame_tx [frame_len]; // frame samples (transmitted) float complex frame_rx [frame_len]; // frame samples (received) - unsigned int num_bit_errors [num_snr]; // bit errors for each SNR point - unsigned int num_packet_errors[num_snr]; // packet errors for each SNR point - float BER [num_snr]; // bit error rate - float PER [num_snr]; // packet error rate + + // output file + FILE* fid = fopen(OUTPUT_FILENAME, "w"); + fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all; close all; SNR=[]; ber=[]; per=[];\n"); printf(" %8s %8s %8s %12s %8s %8s %6s\n", "SNR [dB]", "errors", "bits", "BER", "errors", "packets", "PER"); - unsigned int s; - for (s=0; s= min_packet_errors) + break; + if (num_packet_trials >= max_packet_trials) + break; } - BER[s] = (float)num_bit_errors[s] / (float)num_bit_trials; - PER[s] = (float)num_packet_errors[s] / (float)num_packet_trials; + float BER = (float)num_bit_errors / (float)num_bit_trials; + float PER = (float)num_packet_errors / (float)num_packet_trials; printf(" %8.2f %8u %8u %12.4e %8u %8u %6.2f%%\n", SNRdB, - num_bit_errors[s], num_bit_trials, BER[s], - num_packet_errors[s], num_packet_trials, PER[s]*100.0f); + num_bit_errors, num_bit_trials, BER, + num_packet_errors, num_packet_trials, PER*100.0f); + fprintf(fid,"SNR(end+1)=%g; ber(end+1)=%g; per(end+1)=%g;\n", SNRdB, BER, PER); + if (num_packet_errors < min_packet_errors) + break; + SNRdB += SNRdB_step; } // destroy allocated objects qpacketmodem_destroy(q); - // - // export output file - // - FILE * fid = fopen(OUTPUT_FILENAME, "w"); - fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); - fprintf(fid,"\n\n"); - fprintf(fid,"clear all\n"); - fprintf(fid,"close all\n"); - fprintf(fid,"payload_len = %u; %% payload length [bytes]\n", payload_len); - fprintf(fid,"frame_len = %u; %% frame length [symbols]\n", frame_len); - fprintf(fid,"num_snr = %u;\n", num_snr); - fprintf(fid,"num_packet_trials = %u;\n", num_packet_trials); - fprintf(fid,"num_bit_trials = %u;\n", num_bit_trials); - fprintf(fid,"SNRdB_min = %8.2f;\n", SNRdB_min); - fprintf(fid,"SNRdB_max = %8.2f;\n", SNRdB_max); - fprintf(fid,"scheme = '%s/%s/%s';\n", - fec_scheme_str[fec0][1], - fec_scheme_str[fec1][1], - modulation_types[ms].name); - fprintf(fid,"rate = 8*payload_len / frame_len; %% true rate [bits/symbol]\n"); - for (i=0; i Date: Sat, 11 Mar 2023 08:33:53 -0500 Subject: [PATCH 050/334] setting noise correctly in framesync64 performance example --- examples/framesync64_performance_example.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/framesync64_performance_example.c b/examples/framesync64_performance_example.c index fc43291c3..c50234f36 100644 --- a/examples/framesync64_performance_example.c +++ b/examples/framesync64_performance_example.c @@ -10,10 +10,11 @@ // add noise to channel void frame64_add_noise(float complex * _buf, float _SNRdB) { - float nstd = powf(10.0f, -_SNRdB/20.0f) * M_SQRT1_2; + float nstd = powf(10.0f, -_SNRdB/20.0f); + nstd *= M_SQRT2; // scale noise to account for signal being over-sampled by 2 unsigned int i; for (i=0; i Date: Sat, 11 Mar 2023 08:37:23 -0500 Subject: [PATCH 051/334] framesync64: adding interpolated SNR estimate for target PER --- examples/framesync64_performance_example.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/framesync64_performance_example.c b/examples/framesync64_performance_example.c index c50234f36..7242ca563 100644 --- a/examples/framesync64_performance_example.c +++ b/examples/framesync64_performance_example.c @@ -25,15 +25,18 @@ int main(int argc, char*argv[]) unsigned int min_errors = 50; unsigned int min_trials = 500; unsigned int max_trials = 5000; + float per_target = 1e-2f; // create buffer for the frame samples float complex frame[LIQUID_FRAME64_LEN]; - float SNRdB = -6.0f; + float SNRdB = -3.0f; + float per_0 =-1.0f, per_1 = -1.0f; + float snr_0 = 0.0f, snr_1 = 0.0f; FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); - printf("# %8s %6s %6s %6s\n", "SNR", "detect", "valid", "trials"); + printf("# %8s %6s %6s %6s %12s\n", "SNR", "detect", "valid", "trials", "PER"); while (SNRdB < 10.0f) { framesync64_reset_framedatastats(fs); unsigned int num_trials = 0, num_errors = 0; @@ -61,8 +64,11 @@ int main(int argc, char*argv[]) } // print results framedatastats_s stats = framesync64_get_framedatastats(fs); - printf(" %8.3f %6u %6u %6u\n", - SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials); + float per = (float)(num_trials - stats.num_payloads_valid)/(float)num_trials; + if (per >= per_target) { per_0 = per; snr_0 = SNRdB; } + else if (per_1 < 0.0f ) { per_1 = per; snr_1 = SNRdB; } + printf(" %8.3f %6u %6u %6u %12.4e\n", + SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials,per); fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%g; pvalid(end+1)=%g;\n", SNRdB, (float)stats.num_frames_detected / (float)num_trials, @@ -71,6 +77,10 @@ int main(int argc, char*argv[]) break; SNRdB += 0.5f; } + float m = (logf(per_1) - logf(per_0)) / (snr_1 - snr_0); + float snr_target = snr_0 + (logf(per_target) - logf(per_0)) / m; + printf("per:{%12.4e,%12.4e}, snr:{%5.2f,%5.2f} => %.3f dB for PER %12.4e\n", + per_0, per_1, snr_0, snr_1, snr_target, per_target); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); @@ -89,3 +99,4 @@ int main(int argc, char*argv[]) framesync64_destroy(fs); return 0; } + From 0e31f7794ff42fd59dbfe7f81bd3d12e8051abbd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 11 Mar 2023 12:41:57 -0500 Subject: [PATCH 052/334] ofdmframesync: returning appropriate value with debugging macros --- src/multichannel/src/ofdmframesync.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 8a05e20b1..7f008b054 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -1152,7 +1152,7 @@ int ofdmframesync_debug_enable(ofdmframesync _q) _q->debug_objects_created = 1; return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_enable(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_enable(): compile-time debugging disabled"); #endif } @@ -1163,7 +1163,7 @@ int ofdmframesync_debug_disable(ofdmframesync _q) _q->debug_enabled = 0; return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_disable(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_disable(): compile-time debugging disabled"); #endif } @@ -1325,7 +1325,7 @@ int ofdmframesync_debug_print(ofdmframesync _q, printf("ofdmframesync/debug: results written to '%s'\n", _filename); return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_print(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_print(): compile-time debugging disabled"); #endif } From 60854477794411d19a6cd19e1bda80d25d295cd5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 12 Mar 2023 18:52:04 -0400 Subject: [PATCH 053/334] framesync64: respecting arguments with CLI, printing minimal info to screen --- scripts/framesync64_debug.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/framesync64_debug.py b/scripts/framesync64_debug.py index 27c09c0aa..47c455f4f 100755 --- a/scripts/framesync64_debug.py +++ b/scripts/framesync64_debug.py @@ -11,9 +11,9 @@ def main(argv=None): args = p.parse_args() for fname in args.sources: - filename = framesync64_plot(fname,args.export) + filename = framesync64_plot(fname,args.export,args.nodisplay) -def framesync64_plot(filename,export=None): +def framesync64_plot(filename,export=None,nodisplay=True): # open file and read values fid = open(filename,'rb') buf = np.fromfile(fid, count=1440, dtype=np.csingle) @@ -26,7 +26,7 @@ def framesync64_plot(filename,export=None): payload_sym = np.fromfile(fid, count= 600, dtype=np.csingle) payload_dec = np.fromfile(fid, count= 72, dtype=np.int8) - # compute filter response in dB + # compute smooth spectral response in dB nfft = 2400 f = np.arange(nfft)/nfft-0.5 psd = np.abs(np.fft.fftshift(np.fft.fft(buf, nfft)))**2 @@ -35,7 +35,6 @@ def framesync64_plot(filename,export=None): h = np.concatenate((w[m:], np.zeros(nfft-2*m-1), w[:m])) / (sum(w) * nfft) H = np.fft.fft(h) psd = 10*np.log10( np.real(np.fft.ifft(H * np.fft.fft(psd))) ) - #psd = 20*np.log10(np.abs(np.fft.fftshift(np.fft.fft(buf, nfft)))) # plot impulse and spectral responses fig, _ax = plt.subplots(2,2,figsize=(12,12)) @@ -58,11 +57,13 @@ def framesync64_plot(filename,export=None): _ax.set_ylabel('Imag') for _ax in ax: _ax.grid(True) - fig.suptitle('frame64, tau:%.6f, dphi:%.6f, phi:%.6f, rssi:%.3f dB, evm:%.3f' % \ - (tau_hat, dphi_hat, phi_hat, 20*np.log10(gamma_hat), evm)) - if export==None: + title = '%s, tau:%9.6f, dphi:%9.6f, phi:%9.6f, rssi:%6.3f dB, evm:%6.3f' % \ + (filename, tau_hat, dphi_hat, phi_hat, 20*np.log10(gamma_hat), evm) + print(title) + fig.suptitle(title) + if not nodisplay: plt.show() - else: + if export is not None: fig.savefig(os.path.splitext(filename)[0]+'.png',bbox_inches='tight') plt.close() From 65d20a1da8299e0686e7997b64daba2d355bfd8c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 16 Mar 2023 17:44:13 -0400 Subject: [PATCH 054/334] crc: adding simple tests for data validity checks --- include/liquid.h | 2 +- src/fec/src/crc.c | 10 ++++---- src/fec/tests/crc_autotest.c | 47 +++++++++++++++++++++++------------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 2773884f3..6d65c46f1 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1194,7 +1194,7 @@ typedef enum { extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2]; // Print compact list of existing and available CRC schemes -void liquid_print_crc_schemes(); +int liquid_print_crc_schemes(); // returns crc_scheme based on input string crc_scheme liquid_getopt_str2crc(const char * _str); diff --git a/src/fec/src/crc.c b/src/fec/src/crc.c index b3ee388ab..0b7ed7fa7 100644 --- a/src/fec/src/crc.c +++ b/src/fec/src/crc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,12 +46,12 @@ const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2] = { // Print compact list of existing and available crc schemes -void liquid_print_crc_schemes() +int liquid_print_crc_schemes() { unsigned int i; unsigned int len = 10; - // print all available MOD schemes + // print all available CRC schemes printf(" "); for (i=0; i Date: Sat, 18 Mar 2023 09:59:20 -0400 Subject: [PATCH 055/334] build: stripping version number off archive --- makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makefile.in b/makefile.in index 3c0246d9b..90decdbb6 100644 --- a/makefile.in +++ b/makefile.in @@ -1,4 +1,4 @@ -# Copyright (c) 2007 - 2022 Joseph Gaeddert +# Copyright (c) 2007 - 2023 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -1294,7 +1294,7 @@ install: all @echo "" mkdir -p $(DESTDIR)$(prefix)/include/liquid mkdir -p $(DESTDIR)$(libdir) - install -m 644 -p libliquid.${AR_LIB} $(DESTDIR)$(libdir)/libliquid.${AR_LIB}.${VERSION} + install -m 644 -p libliquid.${AR_LIB} $(DESTDIR)$(libdir)/libliquid.${AR_LIB} install -m 644 -p libliquid.${SH_LIB} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} install -m 644 -p include/liquid.h $(DESTDIR)$(prefix)/include/liquid/liquid.h ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB} @@ -1321,7 +1321,7 @@ install: all uninstall: @echo "uninstalling..." $(RM) $(DESTDIR)$(prefix)/include/liquid/liquid.h - $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB}.${VERSION} + $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.1 $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB} From 48b34d3000d1289191038271f6573c2eac89f216 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 23 Mar 2023 08:09:54 -0400 Subject: [PATCH 056/334] fec/hamming(31,26): checking symbol size edge cases --- src/fec/tests/fec_hamming3126_autotest.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/fec/tests/fec_hamming3126_autotest.c b/src/fec/tests/fec_hamming3126_autotest.c index a3731c0f4..7713eaa9d 100644 --- a/src/fec/tests/fec_hamming3126_autotest.c +++ b/src/fec/tests/fec_hamming3126_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,3 +65,16 @@ void autotest_hamming3126_codec() } } +void autotest_fec_hamming3126_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // symbols too large + CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) + CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) +} From 2661827103c5757b39f1b6da6451dbcf33a7aed2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 24 Mar 2023 07:56:07 -0400 Subject: [PATCH 057/334] fec: moving configuration tests to separte file --- makefile.in | 1 + src/fec/tests/fec_config_autotest.c | 51 ++++++++++++++++++++++++ src/fec/tests/fec_hamming3126_autotest.c | 13 ------ 3 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 src/fec/tests/fec_config_autotest.c diff --git a/makefile.in b/makefile.in index 90decdbb6..d92ca74c8 100644 --- a/makefile.in +++ b/makefile.in @@ -303,6 +303,7 @@ $(fec_objects) : %.o : %.c $(include_headers) fec_autotests := \ src/fec/tests/crc_autotest.c \ src/fec/tests/fec_autotest.c \ + src/fec/tests/fec_config_autotest.c \ src/fec/tests/fec_copy_autotest.c \ src/fec/tests/fec_soft_autotest.c \ src/fec/tests/fec_golay2412_autotest.c \ diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c new file mode 100644 index 000000000..729a5725e --- /dev/null +++ b/src/fec/tests/fec_config_autotest.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "autotest/autotest.h" +#include "liquid.internal.h" + +void autotest_fec_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // symbols too large + CONTEND_EQUALITY(fec_golay2412_encode_symbol(1u<<12), 0) + CONTEND_EQUALITY(fec_golay2412_decode_symbol(1u<<24), 0) + + CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) + CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) + + CONTEND_EQUALITY(fec_hamming1511_encode_symbol(1u<<11), 0) + CONTEND_EQUALITY(fec_hamming1511_decode_symbol(1u<<15), 0) + + CONTEND_EQUALITY(fec_hamming128_encode_symbol(1u<<8), 0) + CONTEND_EQUALITY(fec_hamming128_decode_symbol(1u<<12), 0) +} + diff --git a/src/fec/tests/fec_hamming3126_autotest.c b/src/fec/tests/fec_hamming3126_autotest.c index 7713eaa9d..4e0090fe9 100644 --- a/src/fec/tests/fec_hamming3126_autotest.c +++ b/src/fec/tests/fec_hamming3126_autotest.c @@ -65,16 +65,3 @@ void autotest_hamming3126_codec() } } -void autotest_fec_hamming3126_config() -{ -#if LIQUID_STRICT_EXIT - AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); - return; -#endif -#if !LIQUID_SUPPRESS_ERROR_OUTPUT - fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); -#endif - // symbols too large - CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) - CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) -} From 445c352d163008cba82d1aa8aefb55d881929360 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:17:12 +0000 Subject: [PATCH 058/334] asgram: filling entire ASCII buffer with zeros; avoid compiler warning --- src/fft/src/asgram.proto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fft/src/asgram.proto.c b/src/fft/src/asgram.proto.c index d8adcbc31..c4d62c596 100644 --- a/src/fft/src/asgram.proto.c +++ b/src/fft/src/asgram.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -256,7 +256,7 @@ int ASGRAM(_print)(ASGRAM() _q) float maxval; float maxfreq; char ascii[_q->nfft+1]; - ascii[_q->nfft] = '\0'; // append null character to end of string + memset(ascii, '\0', _q->nfft+1); // fill buffer with null characters // execute the spectrogram ASGRAM(_execute)(_q, ascii, &maxval, &maxfreq); From 05a0bdf171fc4c7f474ffffbb264eaaf0e7613f7 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:19:33 +0000 Subject: [PATCH 059/334] fskframesync: block-commenting unused section to avoid compiler warnings --- src/framing/src/fskframesync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c index f68c4cf4c..8d30274e6 100644 --- a/src/framing/src/fskframesync.c +++ b/src/framing/src/fskframesync.c @@ -465,6 +465,7 @@ int fskframesync_execute_detectframe(fskframesync _q, //printf("signal peaked! %12.8f %12.8f %12.8f\n", // _q->rxy[0], _q->rxy[1], _q->rxy[2]); +#if 0 // compute estimate, apply bias compensation float gamma = (_q->rxy[2] - _q->rxy[0]) / _q->rxy[1]; float p2 = 9.54907046918287e-01f; @@ -472,8 +473,9 @@ int fskframesync_execute_detectframe(fskframesync _q, float xf = fabsf(gamma); float tau_hat = copysignf(p2*xf*xf + p1*xf, gamma); int num_samples = round(tau_hat * _q->k); - //printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", - // gamma, tau_hat, num_samples); + printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", + gamma, tau_hat, num_samples); +#endif // TODO: set timer and filterbank index accordingly _q->timer = 2*_q->k; From 8f092ddcb9f12863c72c6579da7c99908946b3da Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:26:41 +0000 Subject: [PATCH 060/334] autoscript: using sprintf to avoid compiler warning --- scripts/autoscript.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/autoscript.c b/scripts/autoscript.c index fd669808e..14ca83be0 100644 --- a/scripts/autoscript.c +++ b/scripts/autoscript.c @@ -297,11 +297,7 @@ void autoscript_parsefile(autoscript _q, // generate tag (e.g. "void benchmark_"); unsigned int tag_len = 5 + strlen(_q->type) + 2; char tag[tag_len]; - strcpy(tag, "void "); - strcpy(tag+5, _q->type); - tag[tag_len-2] = '_'; - tag[tag_len-1] = '\0'; - //printf("// tag : '%s'\n", tag); + sprintf(tag, "void %s_", _q->type); // parse file, looking for key char buffer[1024]; // line buffer From 583cf31ca6f4aebae69c79e0f891de0c73647dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Sat, 19 Nov 2022 06:31:52 +0000 Subject: [PATCH 061/334] Stop using SIMD dot product instructions as they are way slower than mul and add Removing the dedicated dp instruction effectively makes the dotprod_rrrf SSE4 implementation redundant, remove it Rename MMX implementations to SSE since they do not use MMX instructions anyway Add loop unrolled implementation of sumsq Prepare for AVX-512 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 35 +- library.json | 3 +- ...{dotprod_cccf.mmx.c => dotprod_cccf.sse.c} | 30 +- src/dotprod/src/dotprod_crcf.avx.c | 20 +- ...{dotprod_crcf.mmx.c => dotprod_crcf.sse.c} | 61 ++-- src/dotprod/src/dotprod_rrrf.avx.c | 23 +- ...{dotprod_rrrf.mmx.c => dotprod_rrrf.sse.c} | 58 ++-- src/dotprod/src/dotprod_rrrf.sse4.c | 307 ------------------ src/dotprod/src/sumsq.avx.c | 85 ++++- src/dotprod/src/{sumsq.mmx.c => sumsq.sse.c} | 87 ++++- 10 files changed, 270 insertions(+), 439 deletions(-) rename src/dotprod/src/{dotprod_cccf.mmx.c => dotprod_cccf.sse.c} (95%) rename src/dotprod/src/{dotprod_crcf.mmx.c => dotprod_crcf.sse.c} (88%) rename src/dotprod/src/{dotprod_rrrf.mmx.c => dotprod_rrrf.sse.c} (86%) delete mode 100644 src/dotprod/src/dotprod_rrrf.sse4.c rename src/dotprod/src/{sumsq.mmx.c => sumsq.sse.c} (60%) diff --git a/configure.ac b/configure.ac index 12d4b7cd8..33742fcee 100644 --- a/configure.ac +++ b/configure.ac @@ -170,9 +170,18 @@ else # SSSE3 : tmmintrin.h # SSE4.1/2: smmintrin.h # AVX : immintrin.h + # AVX2 : immintrin.h + # AVX512 : immintrin.h AX_EXT - if [ test "$ax_cv_have_avx2_ext" = yes ]; then + if [ test "$ax_cv_have_avx512f_ext" = yes ]; then + # AVX512 extensions + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ + src/dotprod/src/dotprod_crcf.avx.o \ + src/dotprod/src/dotprod_rrrf.avx.o \ + src/dotprod/src/sumsq.avx.o" + ARCH_OPTION='-mavx512f' + elif [ test "$ax_cv_have_avx2_ext" = yes ]; then # AVX2 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ @@ -188,24 +197,24 @@ else ARCH_OPTION='-mavx' elif [ test "$ax_cv_have_sse41_ext" = yes ]; then # SSE4.1/2 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.sse4.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse4.1' elif [ test "$ax_cv_have_sse3_ext" = yes ]; then # SSE3 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.mmx.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse3' elif [ test "$ax_cv_have_sse2_ext" = yes ]; then # SSE2 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.mmx.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse2' else # portable C version diff --git a/library.json b/library.json index 6f14be837..753bb1a00 100644 --- a/library.json +++ b/library.json @@ -39,9 +39,8 @@ "-<.git/>", "-<*/src/*.proto.c>", "-<*/src/*.av.c>", - "-<*/src/*.mmx.c>", "-<*/src/*.neon.c>", - "-<*/src/*.sse4.c>", + "-<*/src/*.sse.c>", "-<*/src/*.avx.c>", "-<*/src/*.x86.s>" ] diff --git a/src/dotprod/src/dotprod_cccf.mmx.c b/src/dotprod/src/dotprod_cccf.sse.c similarity index 95% rename from src/dotprod/src/dotprod_cccf.mmx.c rename to src/dotprod/src/dotprod_cccf.sse.c index 6794bfcfe..6bfc10053 100644 --- a/src/dotprod/src/dotprod_cccf.mmx.c +++ b/src/dotprod/src/dotprod_cccf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -33,10 +33,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -49,14 +45,14 @@ #include // SSE3 #endif -#define DEBUG_DOTPROD_CCCF_MMX 0 +#define DEBUG_DOTPROD_CCCF_sse 0 // forward declaration of internal methods -int dotprod_cccf_execute_mmx(dotprod_cccf _q, +int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y); -int dotprod_cccf_execute_mmx4(dotprod_cccf _q, +int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y); @@ -104,7 +100,7 @@ int dotprod_cccf_run4(float complex * _h, // -// structured MMX dot product +// structured sse dot product // struct dotprod_cccf_s { @@ -177,7 +173,7 @@ dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_cccf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_cccf_copy().sse, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; @@ -206,7 +202,7 @@ int dotprod_cccf_destroy(dotprod_cccf _q) int dotprod_cccf_print(dotprod_cccf _q) { - printf("dotprod_cccf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_cccf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); @@ -223,12 +219,12 @@ int dotprod_cccf_execute(dotprod_cccf _q, { // switch based on size if (_q->n < 32) { - return dotprod_cccf_execute_mmx(_q, _x, _y); + return dotprod_cccf_execute_sse(_q, _x, _y); } - return dotprod_cccf_execute_mmx4(_q, _x, _y); + return dotprod_cccf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions +// use SSE extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // @@ -248,7 +244,7 @@ int dotprod_cccf_execute(dotprod_cccf _q, // x[1].real * h[1].imag, // x[1].imag * h[1].imag }; // -int dotprod_cccf_execute_mmx(dotprod_cccf _q, +int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y) { @@ -341,8 +337,8 @@ int dotprod_cccf_execute_mmx(dotprod_cccf _q, return LIQUID_OK; } -// use MMX/SSE extensions -int dotprod_cccf_execute_mmx4(dotprod_cccf _q, +// use SSE extensions +int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y) { diff --git a/src/dotprod/src/dotprod_crcf.avx.c b/src/dotprod/src/dotprod_crcf.avx.c index 6e14af3ad..525148210 100644 --- a/src/dotprod/src/dotprod_crcf.avx.c +++ b/src/dotprod/src/dotprod_crcf.avx.c @@ -274,10 +274,7 @@ int dotprod_crcf_execute_avx4(dotprod_crcf _q, __m256 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers - __m256 sum0 = _mm256_setzero_ps(); - __m256 sum1 = _mm256_setzero_ps(); - __m256 sum2 = _mm256_setzero_ps(); - __m256 sum3 = _mm256_setzero_ps(); + __m256 sum = _mm256_setzero_ps(); // r = 8*floor(n/32) unsigned int r = (n >> 5) << 3; @@ -304,22 +301,17 @@ int dotprod_crcf_execute_avx4(dotprod_crcf _q, s3 = _mm256_mul_ps(v3, h3); // parallel addition - sum0 = _mm256_add_ps( sum0, s0 ); - sum1 = _mm256_add_ps( sum1, s1 ); - sum2 = _mm256_add_ps( sum2, s2 ); - sum3 = _mm256_add_ps( sum3, s3 ); + sum = _mm256_add_ps( sum, s0 ); + sum = _mm256_add_ps( sum, s1 ); + sum = _mm256_add_ps( sum, s2 ); + sum = _mm256_add_ps( sum, s3 ); } - // fold down - sum0 = _mm256_add_ps( sum0, sum1 ); - sum2 = _mm256_add_ps( sum2, sum3 ); - sum0 = _mm256_add_ps( sum0, sum2 ); - // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array and perform manual sum - _mm256_store_ps(w, sum0); + _mm256_store_ps(w, sum); w[0] += w[2] + w[4] + w[6]; w[1] += w[3] + w[5] + w[7]; diff --git a/src/dotprod/src/dotprod_crcf.mmx.c b/src/dotprod/src/dotprod_crcf.sse.c similarity index 88% rename from src/dotprod/src/dotprod_crcf.mmx.c rename to src/dotprod/src/dotprod_crcf.sse.c index 4ba9d320d..182133d22 100644 --- a/src/dotprod/src/dotprod_crcf.mmx.c +++ b/src/dotprod/src/dotprod_crcf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -32,13 +32,28 @@ #include "liquid.internal.h" -#define DEBUG_DOTPROD_CRCF_MMX 0 +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#if HAVE_SSE +#include // SSE +#endif + +#if HAVE_SSE2 +#include // SSE2 +#endif + +#if HAVE_SSE3 +#include // SSE3 +#endif + +#define DEBUG_DOTPROD_CRCF_SSE 0 // forward declaration of internal methods -int dotprod_crcf_execute_mmx(dotprod_crcf _q, +int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y); -int dotprod_crcf_execute_mmx4(dotprod_crcf _q, +int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y); @@ -86,7 +101,7 @@ int dotprod_crcf_run4(float * _h, // -// structured MMX dot product +// structured SSE dot product // struct dotprod_crcf_s { @@ -153,7 +168,7 @@ dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_crcf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_crcf_copy().sse, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; @@ -181,7 +196,7 @@ int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) - printf("dotprod_crcf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_crcf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); @@ -195,13 +210,13 @@ int dotprod_crcf_execute(dotprod_crcf _q, { // switch based on size if (_q->n < 32) { - return dotprod_crcf_execute_mmx(_q, _x, _y); + return dotprod_crcf_execute_sse(_q, _x, _y); } - return dotprod_crcf_execute_mmx4(_q, _x, _y); + return dotprod_crcf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions -int dotprod_crcf_execute_mmx(dotprod_crcf _q, +// use SSE extensions +int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y) { @@ -257,8 +272,8 @@ int dotprod_crcf_execute_mmx(dotprod_crcf _q, return LIQUID_OK; } -// use MMX/SSE extensions -int dotprod_crcf_execute_mmx4(dotprod_crcf _q, +// use SSE extensions +int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y) { @@ -274,10 +289,7 @@ int dotprod_crcf_execute_mmx4(dotprod_crcf _q, __m128 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers - __m128 sum0 = _mm_setzero_ps(); - __m128 sum1 = _mm_setzero_ps(); - __m128 sum2 = _mm_setzero_ps(); - __m128 sum3 = _mm_setzero_ps(); + __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; @@ -304,22 +316,17 @@ int dotprod_crcf_execute_mmx4(dotprod_crcf _q, s3 = _mm_mul_ps(v3, h3); // parallel addition - sum0 = _mm_add_ps( sum0, s0 ); - sum1 = _mm_add_ps( sum1, s1 ); - sum2 = _mm_add_ps( sum2, s2 ); - sum3 = _mm_add_ps( sum3, s3 ); + sum = _mm_add_ps( sum, s0 ); + sum = _mm_add_ps( sum, s1 ); + sum = _mm_add_ps( sum, s2 ); + sum = _mm_add_ps( sum, s3 ); } - // fold down - sum0 = _mm_add_ps( sum0, sum1 ); - sum2 = _mm_add_ps( sum2, sum3 ); - sum0 = _mm_add_ps( sum0, sum2 ); - // aligned output array float w[4] __attribute__((aligned(16))); // unload packed array and perform manual sum - _mm_store_ps(w, sum0); + _mm_store_ps(w, sum); w[0] += w[2]; w[1] += w[3]; diff --git a/src/dotprod/src/dotprod_rrrf.avx.c b/src/dotprod/src/dotprod_rrrf.avx.c index 2af478375..08a87539c 100644 --- a/src/dotprod/src/dotprod_rrrf.avx.c +++ b/src/dotprod/src/dotprod_rrrf.avx.c @@ -219,12 +219,17 @@ int dotprod_rrrf_execute_avx(dotprod_rrrf _q, h = _mm256_load_ps(&_q->h[i]); // compute dot product - s = _mm256_dp_ps(v, h, 0xff); - + s = _mm256_mul_ps(v, h); + // parallel addition sum = _mm256_add_ps( sum, s ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array float w[8] __attribute__((aligned(32))); @@ -270,19 +275,23 @@ int dotprod_rrrf_execute_avxu(dotprod_rrrf _q, h3 = _mm256_load_ps(&_q->h[4*i+24]); // compute dot products - s0 = _mm256_dp_ps(v0, h0, 0xff); - s1 = _mm256_dp_ps(v1, h1, 0xff); - s2 = _mm256_dp_ps(v2, h2, 0xff); - s3 = _mm256_dp_ps(v3, h3, 0xff); + s0 = _mm256_mul_ps(v0, h0); + s1 = _mm256_mul_ps(v1, h1); + s2 = _mm256_mul_ps(v2, h2); + s3 = _mm256_mul_ps(v3, h3); // parallel addition - // FIXME: these additions are by far the limiting factor sum = _mm256_add_ps( sum, s0 ); sum = _mm256_add_ps( sum, s1 ); sum = _mm256_add_ps( sum, s2 ); sum = _mm256_add_ps( sum, s3 ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array float w[8] __attribute__((aligned(32))); diff --git a/src/dotprod/src/dotprod_rrrf.mmx.c b/src/dotprod/src/dotprod_rrrf.sse.c similarity index 86% rename from src/dotprod/src/dotprod_rrrf.mmx.c rename to src/dotprod/src/dotprod_rrrf.sse.c index 613eb707a..a9f4c58f1 100644 --- a/src/dotprod/src/dotprod_rrrf.mmx.c +++ b/src/dotprod/src/dotprod_rrrf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -34,10 +34,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -50,13 +46,13 @@ #include // SSE3 #endif -#define DEBUG_DOTPROD_RRRF_MMX 0 +#define DEBUG_DOTPROD_RRRF_SSE 0 // internal methods -int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, +int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y); -int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, +int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y); @@ -104,7 +100,7 @@ int dotprod_rrrf_run4(float * _h, // -// structured MMX dot product +// structured SSE dot product // struct dotprod_rrrf_s { @@ -167,7 +163,7 @@ dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_rrrf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_rrrf_copy().sse, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; @@ -191,7 +187,7 @@ int dotprod_rrrf_destroy(dotprod_rrrf _q) int dotprod_rrrf_print(dotprod_rrrf _q) { - printf("dotprod_rrrf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_rrrf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); @@ -205,13 +201,13 @@ int dotprod_rrrf_execute(dotprod_rrrf _q, { // switch based on size if (_q->n < 16) { - return dotprod_rrrf_execute_mmx(_q, _x, _y); + return dotprod_rrrf_execute_sse(_q, _x, _y); } - return dotprod_rrrf_execute_mmx4(_q, _x, _y); + return dotprod_rrrf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions -int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, +// use SSE extensions +int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y) { @@ -235,7 +231,7 @@ int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, // compute multiplication s = _mm_mul_ps(v, h); - + // parallel addition sum = _mm_add_ps( sum, s ); } @@ -267,8 +263,8 @@ int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, return LIQUID_OK; } -// use MMX/SSE extensions, unrolled loop -int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, +// use SSE extensions, unrolled loop +int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y) { @@ -278,10 +274,7 @@ int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, __m128 s0, s1, s2, s3; // load zeros into sum registers - __m128 sum0 = _mm_setzero_ps(); - __m128 sum1 = _mm_setzero_ps(); - __m128 sum2 = _mm_setzero_ps(); - __m128 sum3 = _mm_setzero_ps(); + __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (_q->n >> 4) << 2; @@ -308,32 +301,27 @@ int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, s3 = _mm_mul_ps(v3, h3); // parallel addition - sum0 = _mm_add_ps( sum0, s0 ); - sum1 = _mm_add_ps( sum1, s1 ); - sum2 = _mm_add_ps( sum2, s2 ); - sum3 = _mm_add_ps( sum3, s3 ); + sum = _mm_add_ps( sum, s0 ); + sum = _mm_add_ps( sum, s1 ); + sum = _mm_add_ps( sum, s2 ); + sum = _mm_add_ps( sum, s3 ); } - // fold down into single 4-element register - sum0 = _mm_add_ps( sum0, sum1 ); - sum2 = _mm_add_ps( sum2, sum3 ); - sum0 = _mm_add_ps( sum0, sum2); - // aligned output array float w[4] __attribute__((aligned(16))); #if HAVE_SSE3 // SSE3: fold down to single value using _mm_hadd_ps() __m128 z = _mm_setzero_ps(); - sum0 = _mm_hadd_ps(sum0, z); - sum0 = _mm_hadd_ps(sum0, z); + sum = _mm_hadd_ps(sum, z); + sum = _mm_hadd_ps(sum, z); // unload single (lower value) - _mm_store_ss(w, sum0); + _mm_store_ss(w, sum); float total = w[0]; #else // SSE2 and below: unload packed array and perform manual sum - _mm_store_ps(w, sum0); + _mm_store_ps(w, sum); float total = w[0] + w[1] + w[2] + w[3]; #endif diff --git a/src/dotprod/src/dotprod_rrrf.sse4.c b/src/dotprod/src/dotprod_rrrf.sse4.c deleted file mode 100644 index 5bddc12d5..000000000 --- a/src/dotprod/src/dotprod_rrrf.sse4.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// Floating-point dot product (SSE4.1/2) -// - -#include -#include -#include -#include - -#include "liquid.internal.h" - -// include proper SIMD extensions for x86 platforms -// NOTE: these pre-processor macros are defined in config.h - -#if 0 -#include // MMX -#include // SSE -#include // SSE2 -#include // SSE3 -#endif -#include // SSE4.1/2 - -#define DEBUG_DOTPROD_RRRF_SSE4 0 - -// internal methods -int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, - float * _x, - float * _y); -int dotprod_rrrf_execute_sse4u(dotprod_rrrf _q, - float * _x, - float * _y); - -// basic dot product (ordinal calculation) -int dotprod_rrrf_run(float * _h, - float * _x, - unsigned int _n, - float * _y) -{ - float r=0; - unsigned int i; - for (i=0; i<_n; i++) - r += _h[i] * _x[i]; - *_y = r; - return LIQUID_OK; -} - -// basic dot product (ordinal calculation) with loop unrolled -int dotprod_rrrf_run4(float * _h, - float * _x, - unsigned int _n, - float * _y) -{ - float r=0; - - // t = 4*(floor(_n/4)) - unsigned int t=(_n>>2)<<2; - - // compute dotprod in groups of 4 - unsigned int i; - for (i=0; in = _n; - - // allocate memory for coefficients, 16-byte aligned - q->h = (float*) _mm_malloc( q->n*sizeof(float), 16); - - // set coefficients - unsigned int i; - for (i=0; in; i++) - q->h[i] = _h[_rev ? q->n-i-1 : i]; - - // return object - return q; -} - -dotprod_rrrf dotprod_rrrf_create(float * _h, - unsigned int _n) -{ - return dotprod_rrrf_create_opt(_h, _n, 0); -} - -dotprod_rrrf dotprod_rrrf_create_rev(float * _h, - unsigned int _n) -{ - return dotprod_rrrf_create_opt(_h, _n, 1); -} - -// re-create the structured dotprod object -dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, - float * _h, - unsigned int _n) -{ - // completely destroy and re-create dotprod object - dotprod_rrrf_destroy(_q); - return dotprod_rrrf_create(_h,_n); -} - -// re-create the structured dotprod object, coefficients reversed -dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, - float * _h, - unsigned int _n) -{ - // completely destroy and re-create dotprod object - dotprod_rrrf_destroy(_q); - return dotprod_rrrf_create_rev(_h,_n); -} - -dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) -{ - // validate input - if (q_orig == NULL) - return liquid_error_config("dotprod_rrrf_copy().sse4, object cannot be NULL"); - - dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); - q_copy->n = q_orig->n; - - // allocate memory for coefficients, 16-byte aligned - q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 16 ); - - // copy coefficients array - memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); - - // return object - return q_copy; -} - -int dotprod_rrrf_destroy(dotprod_rrrf _q) -{ - _mm_free(_q->h); - free(_q); - return LIQUID_OK; -} - -int dotprod_rrrf_print(dotprod_rrrf _q) -{ - printf("dotprod_rrrf [sse4.1/4.2, %u coefficients]\n", _q->n); - unsigned int i; - for (i=0; i<_q->n; i++) - printf("%3u : %12.9f\n", i, _q->h[i]); - return LIQUID_OK; -} - -// -int dotprod_rrrf_execute(dotprod_rrrf _q, - float * _x, - float * _y) -{ - // switch based on size - if (_q->n < 16) { - return dotprod_rrrf_execute_sse4(_q, _x, _y); - } - return dotprod_rrrf_execute_sse4u(_q, _x, _y); -} - -// use MMX/SSE extensions -int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, - float * _x, - float * _y) -{ - __m128 v; // input vector - __m128 h; // coefficients vector - __m128 s; // dot product - __m128 sum = _mm_setzero_ps(); // load zeros into sum register - - // t = 4*(floor(_n/4)) - unsigned int t = (_q->n >> 2) << 2; - - // - unsigned int i; - for (i=0; ih[i]); - - // compute dot product - s = _mm_dp_ps(v, h, 0xff); - - // parallel addition - sum = _mm_add_ps( sum, s ); - } - - // aligned output array - float w[4] __attribute__((aligned(16))); - - // unload packed array - _mm_store_ps(w, sum); - float total = w[0]; - - // cleanup - for (; i<_q->n; i++) - total += _x[i] * _q->h[i]; - - // set return value - *_y = total; - return LIQUID_OK; -} - -// use MMX/SSE extensions (unrolled) -int dotprod_rrrf_execute_sse4u(dotprod_rrrf _q, - float * _x, - float * _y) -{ - __m128 v0, v1, v2, v3; - __m128 h0, h1, h2, h3; - __m128 s0, s1, s2, s3; - __m128 sum = _mm_setzero_ps(); // load zeros into sum register - - // t = 4*(floor(_n/16)) - unsigned int r = (_q->n >> 4) << 2; - - // - unsigned int i; - for (i=0; ih[4*i+ 0]); - h1 = _mm_load_ps(&_q->h[4*i+ 4]); - h2 = _mm_load_ps(&_q->h[4*i+ 8]); - h3 = _mm_load_ps(&_q->h[4*i+12]); - - // compute dot products - s0 = _mm_dp_ps(v0, h0, 0xff); - s1 = _mm_dp_ps(v1, h1, 0xff); - s2 = _mm_dp_ps(v2, h2, 0xff); - s3 = _mm_dp_ps(v3, h3, 0xff); - - // parallel addition - // FIXME: these additions are by far the limiting factor - sum = _mm_add_ps( sum, s0 ); - sum = _mm_add_ps( sum, s1 ); - sum = _mm_add_ps( sum, s2 ); - sum = _mm_add_ps( sum, s3 ); - } - - // aligned output array - float w[4] __attribute__((aligned(16))); - - // unload packed array - _mm_store_ps(w, sum); - float total = w[0]; - - // cleanup - for (i=4*r; i<_q->n; i++) - total += _x[i] * _q->h[i]; - - // set return value - *_y = total; - return LIQUID_OK; -} - diff --git a/src/dotprod/src/sumsq.avx.c b/src/dotprod/src/sumsq.avx.c index 76e3c59de..032903179 100644 --- a/src/dotprod/src/sumsq.avx.c +++ b/src/dotprod/src/sumsq.avx.c @@ -56,12 +56,12 @@ // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length -float liquid_sumsqf(float * _v, - unsigned int _n) +float liquid_sumsqf_avx(float * _v, + unsigned int _n) { // first cut: ... __m256 v; // input vector - __m256 s; // dot product + __m256 s; // product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) @@ -80,27 +80,94 @@ float liquid_sumsqf(float * _v, sum = _mm256_add_ps( sum, s ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array - float total; + float w[8] __attribute__((aligned(32))); + + _mm256_store_ps(w, sum); + float total = w[0] + w[4]; + + // cleanup + for (; i<_n; i++) + total += _v[i] * _v[i]; + + // set return value + return total; +} + +// sum squares, unrolled loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_avxu(float * _v, + unsigned int _n) +{ + // first cut: ... + __m256 v0, v1, v2, v3; // input vector + __m256 s0, s1, s2, s3; // product + __m256 sum = _mm256_setzero_ps(); // load zeros into sum register + + // t = 8*(floor(_n/32)) + unsigned int t = (_n >> 5) << 3; + + // + unsigned int i; + for (i=0; i @@ -33,10 +33,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -52,8 +48,8 @@ // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length -float liquid_sumsqf(float * _v, - unsigned int _n) +float liquid_sumsqf_sse(float * _v, + unsigned int _n) { // first cut: ... __m128 v; // input vector @@ -102,7 +98,82 @@ float liquid_sumsqf(float * _v, return total; } -// sum squares, basic loop +// sum squares, unrolled loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_sseu(float * _v, + unsigned int _n) +{ + // first cut: ... + __m128 v0, v1, v2, v3; // input vector + __m128 s0, s1, s2, s3; // product + __m128 sum = _mm_setzero_ps(); // load zeros into sum register + + // t = 4*(floor(_n/16)) + unsigned int t = (_n >> 4) << 2; + + // + unsigned int i; + for (i=0; i Date: Sat, 25 Mar 2023 21:42:21 +0000 Subject: [PATCH 062/334] Fix typo in sumsq.avx.c header Add sumsq AVX512-F implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 2 +- src/dotprod/src/sumsq.avx.c | 2 +- src/dotprod/src/sumsq.avx512f.c | 164 ++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/dotprod/src/sumsq.avx512f.c diff --git a/configure.ac b/configure.ac index 33742fcee..d9c1286ed 100644 --- a/configure.ac +++ b/configure.ac @@ -179,7 +179,7 @@ else MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ src/dotprod/src/dotprod_rrrf.avx.o \ - src/dotprod/src/sumsq.avx.o" + src/dotprod/src/sumsq.avx512f.o" ARCH_OPTION='-mavx512f' elif [ test "$ax_cv_have_avx2_ext" = yes ]; then # AVX2 extensions diff --git a/src/dotprod/src/sumsq.avx.c b/src/dotprod/src/sumsq.avx.c index 032903179..88685fca7 100644 --- a/src/dotprod/src/sumsq.avx.c +++ b/src/dotprod/src/sumsq.avx.c @@ -21,7 +21,7 @@ */ // -// sumsq.mmx.c : floating-point sum of squares (MMX) +// sumsq.avx.c : floating-point sum of squares (AVX) // #include diff --git a/src/dotprod/src/sumsq.avx512f.c b/src/dotprod/src/sumsq.avx512f.c new file mode 100644 index 000000000..ad9c75305 --- /dev/null +++ b/src/dotprod/src/sumsq.avx512f.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2007 - 2015 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// sumsq.avx512f.c : floating-point sum of squares (AVX512-F) +// + +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#if HAVE_MMX +#include // MMX +#endif + +#if HAVE_SSE +#include // SSE +#endif + +#if HAVE_SSE2 +#include // SSE2 +#endif + +#if HAVE_SSE3 +#include // SSE3 +#endif + +#if HAVE_AVX +#include // AVX +#endif + +// sum squares, basic loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_avx(float * _v, + unsigned int _n) +{ + // first cut: ... + __m512 v; // input vector + __m512 s; // product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (_n >> 4) << 4; + + // + unsigned int i; + for (i=0; i> 6) << 4; + + // + unsigned int i; + for (i=0; i Date: Sat, 25 Mar 2023 22:57:43 +0000 Subject: [PATCH 063/334] Add AVX512-F dotprod implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 6 +- library.json | 1 + src/dotprod/src/dotprod_cccf.avx512f.c | 406 +++++++++++++++++++++++++ src/dotprod/src/dotprod_crcf.avx512f.c | 324 ++++++++++++++++++++ src/dotprod/src/dotprod_rrrf.avx512f.c | 292 ++++++++++++++++++ 5 files changed, 1026 insertions(+), 3 deletions(-) create mode 100644 src/dotprod/src/dotprod_cccf.avx512f.c create mode 100644 src/dotprod/src/dotprod_crcf.avx512f.c create mode 100644 src/dotprod/src/dotprod_rrrf.avx512f.c diff --git a/configure.ac b/configure.ac index d9c1286ed..34ab3dfc3 100644 --- a/configure.ac +++ b/configure.ac @@ -176,9 +176,9 @@ else if [ test "$ax_cv_have_avx512f_ext" = yes ]; then # AVX512 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ - src/dotprod/src/dotprod_crcf.avx.o \ - src/dotprod/src/dotprod_rrrf.avx.o \ + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx512f.o \ + src/dotprod/src/dotprod_crcf.avx512f.o \ + src/dotprod/src/dotprod_rrrf.avx512f.o \ src/dotprod/src/sumsq.avx512f.o" ARCH_OPTION='-mavx512f' elif [ test "$ax_cv_have_avx2_ext" = yes ]; then diff --git a/library.json b/library.json index 753bb1a00..5a05e3128 100644 --- a/library.json +++ b/library.json @@ -42,6 +42,7 @@ "-<*/src/*.neon.c>", "-<*/src/*.sse.c>", "-<*/src/*.avx.c>", + "-<*/src/*.avx512f.c>", "-<*/src/*.x86.s>" ] }, diff --git a/src/dotprod/src/dotprod_cccf.avx512f.c b/src/dotprod/src/dotprod_cccf.avx512f.c new file mode 100644 index 000000000..abb7768c6 --- /dev/null +++ b/src/dotprod/src/dotprod_cccf.avx512f.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#include // AVX + +#define DEBUG_DOTPROD_CCCF_AVX 0 + +// forward declaration of internal methods +int dotprod_cccf_execute_avx512f(dotprod_cccf _q, + float complex * _x, + float complex * _y); + +int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, + float complex * _x, + float complex * _y); + +// basic dot product (ordinal calculation) +int dotprod_cccf_run(float complex * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_cccf_run4(float complex * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->hi = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + q->hq = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + + // set coefficients, repeated + // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} + // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} + unsigned int i; + for (i=0; in; i++) { + unsigned int k = _rev ? q->n-i-1 : i; + q->hi[2*i+0] = crealf(_h[k]); + q->hi[2*i+1] = crealf(_h[k]); + + q->hq[2*i+0] = cimagf(_h[k]); + q->hq[2*i+1] = cimagf(_h[k]); + } + + // return object + return q; +} + +dotprod_cccf dotprod_cccf_create(float complex * _h, + unsigned int _n) +{ + return dotprod_cccf_create_opt(_h, _n, 0); +} + +dotprod_cccf dotprod_cccf_create_rev(float complex * _h, + unsigned int _n) +{ + return dotprod_cccf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, + float complex * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_cccf_destroy(_q); + return dotprod_cccf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, + float complex * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_cccf_destroy(_q); + return dotprod_cccf_create_rev(_h,_n); +} + +dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_cccf_copy().avx512f, object cannot be NULL"); + + dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned (repeated) + q_copy->hi = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + q_copy->hq = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + + // copy coefficients array (repeated) + // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} + // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} + memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); + memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + +int dotprod_cccf_destroy(dotprod_cccf _q) +{ + _mm_free(_q->hi); + _mm_free(_q->hq); + free(_q); + return LIQUID_OK; +} + +int dotprod_cccf_print(dotprod_cccf _q) +{ + printf("dotprod_cccf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); + return LIQUID_OK; +} + +// execute structured dot product +// _q : dotprod object +// _x : input array +// _y : output sample +int dotprod_cccf_execute(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // switch based on size + if (_q->n < 128) { + return dotprod_cccf_execute_avx512f(_q, _x, _y); + } + return dotprod_cccf_execute_avx512f4(_q, _x, _y); +} + +// use AVX512-F extensions +// +// (a + jb)(c + jd) = (ac - bd) + j(ad + bc) +// +// mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag, x[2].real, x[2].imag, x[3].real, x[3].imag } +// mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real, h[2].real, h[2].real, h[3].real, h[3].real } +// mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag, h[2].imag, h[2].imag, h[3].imag, h[3].imag } +// +// mm_y0 = mm_x * mm_hi +// = { x[0].real * h[0].real, +// x[0].imag * h[0].real, +// x[1].real * h[1].real, +// x[1].imag * h[1].real, +// x[2].real * h[2].real, +// x[2].imag * h[2].real, +// x[3].real * h[3].real, +// x[3].imag * h[3].real }; +// +// mm_y1 = mm_x * mm_hq +// = { x[0].real * h[0].imag, +// x[0].imag * h[0].imag, +// x[1].real * h[1].imag, +// x[1].imag * h[1].imag, +// x[2].real * h[2].imag, +// x[2].imag * h[2].imag, +// x[3].real * h[3].imag, +// x[3].imag * h[3].imag }; +// +int dotprod_cccf_execute_avx512f(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // temporary buffers + __m512 v; // input vector + __m512 hi; // coefficients vector (real) + __m512 hq; // coefficients vector (imag) + __m512 ci; // output multiplication (v * hi) + __m512 cq; // output multiplication (v * hq) + + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + __m512 one = _mm512_set1_ps(1.0f); // load ones into register + + // t = 16*(floor(_n/16)) + unsigned int t = (n >> 4) << 4; + + // + unsigned int i; + for (i=0; ihi[i]); + hq = _mm512_load_ps(&_q->hq[i]); + + // compute parallel multiplications + ci = _mm512_mul_ps(v, hi); + cq = _mm512_mul_ps(v, hq); + + // shuffle values + cq = _mm512_shuffle_ps( cq, cq, _MM_SHUFFLE(2,3,0,1) ); + + // combine using addsub_ps() + s = _mm512_fmaddsub_ps( ci, one, cq ); + + // accumulate + sum = _mm512_add_ps(sum, s); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + //float complex total = *((float complex*)w); + float complex total = w[0] + w[1] * _Complex_I; + + // cleanup + for (i=t/2; i<_q->n; i++) + total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); + + // set return value + *_y = total; + return LIQUID_OK; +} + +// use AVX512-F extensions +int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v0, v1, v2, v3; // input vectors + __m512 hi0, hi1, hi2, hi3; // coefficients vectors (real) + __m512 hq0, hq1, hq2, hq3; // coefficients vectors (imag) + __m512 ci0, ci1, ci2, ci3; // output multiplications (v * hi) + __m512 cq0, cq1, cq2, cq3; // output multiplications (v * hq) + + // load zeros into sum registers + __m512 sumi = _mm512_setzero_ps(); + __m512 sumq = _mm512_setzero_ps(); + + + __m512 one = _mm512_set1_ps(1.0f); // load ones into register + + // r = 16*floor(n/64) + unsigned int r = (n >> 6) << 4; + + // + unsigned int i; + for (i=0; ihi[4*i+0]); + hi1 = _mm512_load_ps(&_q->hi[4*i+16]); + hi2 = _mm512_load_ps(&_q->hi[4*i+32]); + hi3 = _mm512_load_ps(&_q->hi[4*i+48]); + + // load real coefficients into registers (aligned) + hq0 = _mm512_load_ps(&_q->hq[4*i+0]); + hq1 = _mm512_load_ps(&_q->hq[4*i+16]); + hq2 = _mm512_load_ps(&_q->hq[4*i+32]); + hq3 = _mm512_load_ps(&_q->hq[4*i+48]); + + // compute parallel multiplications (real) + ci0 = _mm512_mul_ps(v0, hi0); + ci1 = _mm512_mul_ps(v1, hi1); + ci2 = _mm512_mul_ps(v2, hi2); + ci3 = _mm512_mul_ps(v3, hi3); + + // compute parallel multiplications (imag) + cq0 = _mm512_mul_ps(v0, hq0); + cq1 = _mm512_mul_ps(v1, hq1); + cq2 = _mm512_mul_ps(v2, hq2); + cq3 = _mm512_mul_ps(v3, hq3); + + // accumulate + sumi = _mm512_add_ps(sumi, ci0); sumq = _mm512_add_ps(sumq, cq0); + sumi = _mm512_add_ps(sumi, ci1); sumq = _mm512_add_ps(sumq, cq1); + sumi = _mm512_add_ps(sumi, ci2); sumq = _mm512_add_ps(sumq, cq2); + sumi = _mm512_add_ps(sumi, ci3); sumq = _mm512_add_ps(sumq, cq3); + } + + // shuffle values + sumq = _mm512_shuffle_ps( sumq, sumq, _MM_SHUFFLE(2,3,0,1) ); + + // combine using addsub_ps() + sumi = _mm512_fmaddsub_ps( sumi, one, sumq ); + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sumi); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sumi); + + float complex total = w[0] + w[1] * _Complex_I; + + // cleanup (note: n _must_ be even) + // TODO : clean this method up + for (i=2*r; i<_q->n; i++) { + total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); + } + + // set return value + *_y = total; + return LIQUID_OK; +} + diff --git a/src/dotprod/src/dotprod_crcf.avx512f.c b/src/dotprod/src/dotprod_crcf.avx512f.c new file mode 100644 index 000000000..fae077f3f --- /dev/null +++ b/src/dotprod/src/dotprod_crcf.avx512f.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +#define DEBUG_DOTPROD_CRCF_AVX 0 + +// forward declaration of internal methods +int dotprod_crcf_execute_avx512f(dotprod_crcf _q, + float complex * _x, + float complex * _y); +int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, + float complex * _x, + float complex * _y); + +// basic dot product (ordinal calculation) +int dotprod_crcf_run(float * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_crcf_run4(float * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->h = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + + // set coefficients, repeated + // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} + unsigned int i; + for (i=0; in; i++) { + unsigned int k = _rev ? q->n-i-1 : i; + q->h[2*i+0] = _h[k]; + q->h[2*i+1] = _h[k]; + } + + // return object + return q; +} + +dotprod_crcf dotprod_crcf_create(float * _h, + unsigned int _n) +{ + return dotprod_crcf_create_opt(_h, _n, 0); +} + +dotprod_crcf dotprod_crcf_create_rev(float * _h, + unsigned int _n) +{ + return dotprod_crcf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_crcf_destroy(_q); + return dotprod_crcf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_crcf_destroy(_q); + return dotprod_crcf_create_rev(_h,_n); +} + +dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_crcf_copy().avx512f, object cannot be NULL"); + + dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned (repeated) + q_copy->h = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + + // copy coefficients array (repeated) + // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} + memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + + +int dotprod_crcf_destroy(dotprod_crcf _q) +{ + _mm_free(_q->h); + free(_q); + return LIQUID_OK; +} + +int dotprod_crcf_print(dotprod_crcf _q) +{ + // print coefficients to screen, skipping odd entries (due + // to repeated coefficients) + printf("dotprod_crcf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf(" %3u : %12.9f\n", i, _q->h[2*i]); + return LIQUID_OK; +} + +// +int dotprod_crcf_execute(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // switch based on size + if (_q->n < 128) { + return dotprod_crcf_execute_avx512f(_q, _x, _y); + } + return dotprod_crcf_execute_avx512f4(_q, _x, _y); +} + +// use AVX512-F extensions +int dotprod_crcf_execute_avx512f(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v; // input vector + __m512 h; // coefficients vector + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (n >> 4) << 4; + + // + unsigned int i; + for (i=0; ih[i]); + + // compute multiplication + s = _mm512_mul_ps(v, h); + + // accumulate + sum = _mm512_add_ps(sum, s); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + // cleanup (note: n _must_ be even) + for (; ih[i ]; + w[1] += x[i+1] * _q->h[i+1]; + } + + // set return value + *_y = w[0] + _Complex_I*w[1]; + return LIQUID_OK; +} + +// use AVX512-F extensions +int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v0, v1, v2, v3; // input vectors + __m512 h0, h1, h2, h3; // coefficients vectors + __m512 s0, s1, s2, s3; // dot products [re, im, re, im] + + // load zeros into sum registers + __m512 sum = _mm512_setzero_ps(); + + // r = 16*floor(n/64) + unsigned int r = (n >> 6) << 4; + + // + unsigned int i; + for (i=0; ih[4*i+0]); + h1 = _mm512_load_ps(&_q->h[4*i+16]); + h2 = _mm512_load_ps(&_q->h[4*i+32]); + h3 = _mm512_load_ps(&_q->h[4*i+48]); + + // compute multiplication + s0 = _mm512_mul_ps(v0, h0); + s1 = _mm512_mul_ps(v1, h1); + s2 = _mm512_mul_ps(v2, h2); + s3 = _mm512_mul_ps(v3, h3); + + // parallel addition + sum = _mm512_add_ps( sum, s0 ); + sum = _mm512_add_ps( sum, s1 ); + sum = _mm512_add_ps( sum, s2 ); + sum = _mm512_add_ps( sum, s3 ); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + // cleanup (note: n _must_ be even) + for (i=4*r; ih[i ]; + w[1] += x[i+1] * _q->h[i+1]; + } + + // set return value + *_y = w[0] + w[1]*_Complex_I; + return LIQUID_OK; +} + diff --git a/src/dotprod/src/dotprod_rrrf.avx512f.c b/src/dotprod/src/dotprod_rrrf.avx512f.c new file mode 100644 index 000000000..c11a744a9 --- /dev/null +++ b/src/dotprod/src/dotprod_rrrf.avx512f.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#include // AVX + +#define DEBUG_DOTPROD_RRRF_AVX 0 + +// internal methods +int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, + float * _x, + float * _y); +int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, + float * _x, + float * _y); + +// basic dot product (ordinal calculation) +int dotprod_rrrf_run(float * _h, + float * _x, + unsigned int _n, + float * _y) +{ + float r=0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_rrrf_run4(float * _h, + float * _x, + unsigned int _n, + float * _y) +{ + float r=0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->h = (float*) _mm_malloc( q->n*sizeof(float), 64); + + // set coefficients + unsigned int i; + for (i=0; in; i++) + q->h[i] = _h[_rev ? q->n-i-1 : i]; + + // return object + return q; +} + +dotprod_rrrf dotprod_rrrf_create(float * _h, + unsigned int _n) +{ + return dotprod_rrrf_create_opt(_h, _n, 0); +} + +dotprod_rrrf dotprod_rrrf_create_rev(float * _h, + unsigned int _n) +{ + return dotprod_rrrf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_rrrf_destroy(_q); + return dotprod_rrrf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_rrrf_destroy(_q); + return dotprod_rrrf_create_rev(_h,_n); +} + +dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_rrrf_copy().avx512f, object cannot be NULL"); + + dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned + q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 64 ); + + // copy coefficients array + memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + +int dotprod_rrrf_destroy(dotprod_rrrf _q) +{ + _mm_free(_q->h); + free(_q); + return LIQUID_OK; +} + +int dotprod_rrrf_print(dotprod_rrrf _q) +{ + printf("dotprod_rrrf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf("%3u : %12.9f\n", i, _q->h[i]); + return LIQUID_OK; +} + +// +int dotprod_rrrf_execute(dotprod_rrrf _q, + float * _x, + float * _y) +{ + // switch based on size + if (_q->n < 64) { + return dotprod_rrrf_execute_avx512f(_q, _x, _y); + } + return dotprod_rrrf_execute_avx512fu(_q, _x, _y); +} + +// use AVX512-F extensions +int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, + float * _x, + float * _y) +{ + __m512 v; // input vector + __m512 h; // coefficients vector + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (_q->n >> 4) << 4; + + // + unsigned int i; + for (i=0; ih[i]); + + // compute dot product + s = _mm512_mul_ps(v, h); + + // parallel addition + sum = _mm512_add_ps( sum, s ); + } + + // fold down into single value + float total = _mm512_reduce_add_ps(sum); + + // cleanup + for (; i<_q->n; i++) + total += _x[i] * _q->h[i]; + + // set return value + *_y = total; + return LIQUID_OK; +} + +// use AVX512-F extensions (unrolled) +int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, + float * _x, + float * _y) +{ + __m512 v0, v1, v2, v3; + __m512 h0, h1, h2, h3; + __m512 s0, s1, s2, s3; + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/64)) + unsigned int r = (_q->n >> 6) << 4; + + // + unsigned int i; + for (i=0; ih[4*i+ 0]); + h1 = _mm512_load_ps(&_q->h[4*i+16]); + h2 = _mm512_load_ps(&_q->h[4*i+32]); + h3 = _mm512_load_ps(&_q->h[4*i+48]); + + // compute dot products + s0 = _mm512_mul_ps(v0, h0); + s1 = _mm512_mul_ps(v1, h1); + s2 = _mm512_mul_ps(v2, h2); + s3 = _mm512_mul_ps(v3, h3); + + // parallel addition + sum = _mm512_add_ps( sum, s0 ); + sum = _mm512_add_ps( sum, s1 ); + sum = _mm512_add_ps( sum, s2 ); + sum = _mm512_add_ps( sum, s3 ); + } + + // fold down into single value + float total = _mm512_reduce_add_ps(sum); + + // cleanup + for (i=4*r; i<_q->n; i++) + total += _x[i] * _q->h[i]; + + // set return value + *_y = total; + return LIQUID_OK; +} + From 15fcabc556c9b5776a0fd18b7f326d5043841bf3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 30 Mar 2023 17:17:14 -0400 Subject: [PATCH 064/334] benchmark compare: specifying argument type as float --- scripts/benchmark_compare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_compare.py b/scripts/benchmark_compare.py index 328e134c1..0fdc7295f 100755 --- a/scripts/benchmark_compare.py +++ b/scripts/benchmark_compare.py @@ -6,7 +6,7 @@ p = argparse.ArgumentParser(description=__doc__) p.add_argument('old', help='old benchmark file (.json)') p.add_argument('new', help='new benchmark file (.json)') -p.add_argument('-thresh', default=1.5, help='threshold for displaying deltas') +p.add_argument('-thresh', default=1.5, type=float, help='threshold for displaying deltas') args = p.parse_args() # load json files From 25a3cc7f60f5963ba82c29aef0100a7be8cdc54f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Apr 2023 16:03:03 -0400 Subject: [PATCH 065/334] fec/autotest: cleaning up warning when libfec is not installed --- src/fec/tests/fec_autotest.c | 40 +++++++++++++++---------------- src/fec/tests/fec_copy_autotest.c | 40 +++++++++++++++---------------- src/fec/tests/fec_soft_autotest.c | 40 +++++++++++++++---------------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/fec/tests/fec_autotest.c b/src/fec/tests/fec_autotest.c index df1bdfffa..d03712ce1 100644 --- a/src/fec/tests/fec_autotest.c +++ b/src/fec/tests/fec_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,25 +29,25 @@ void fec_test_codec(fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif diff --git a/src/fec/tests/fec_copy_autotest.c b/src/fec/tests/fec_copy_autotest.c index 34344eb5b..bcb2d1ca3 100644 --- a/src/fec/tests/fec_copy_autotest.c +++ b/src/fec/tests/fec_copy_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,25 +29,25 @@ void fec_test_copy(fec_scheme _fs) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif diff --git a/src/fec/tests/fec_soft_autotest.c b/src/fec/tests/fec_soft_autotest.c index 34c92803d..0ef350493 100644 --- a/src/fec/tests/fec_soft_autotest.c +++ b/src/fec/tests/fec_soft_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,25 +32,25 @@ void fec_test_soft_codec(fec_scheme _fs, void * _opts) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif From 41507de1872e8c56dcd3773b5dfed634ea37ac98 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Apr 2023 16:11:48 -0400 Subject: [PATCH 066/334] build: bumping date in global header --- include/liquid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index 6d65c46f1..ea16f3fb3 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From b3527e01431209b298570e395599deb6d6646b39 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 8 Feb 2023 23:03:03 -0500 Subject: [PATCH 067/334] gcd: fixing logic for stopping loop, adding more test cases --- src/math/src/modular_arithmetic.c | 2 +- src/math/tests/gcd_autotest.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/math/src/modular_arithmetic.c b/src/math/src/modular_arithmetic.c index 01d4b8a39..5146d73b5 100644 --- a/src/math/src/modular_arithmetic.c +++ b/src/math/src/modular_arithmetic.c @@ -131,7 +131,7 @@ unsigned int liquid_gcd(unsigned int _p, // dumb, slow method unsigned int gcd = 1; unsigned int r = 2; // root - while ( r*r <= _p ) { + while ( r <= _q ) { while ((_p % r)==0 && (_q % r) == 0) { _p /= r; _q /= r; diff --git a/src/math/tests/gcd_autotest.c b/src/math/tests/gcd_autotest.c index fd1fcb81f..2dfa81338 100644 --- a/src/math/tests/gcd_autotest.c +++ b/src/math/tests/gcd_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -63,5 +63,9 @@ void autotest_gcd_base() testbench_gcd( 2*2*3*5*7, 2*3, 17); testbench_gcd( 2*2*3*5*7, 2*3, 17*17); testbench_gcd( 2*2*3*5*7, 2*3, 17*17*17); + testbench_gcd( 11, 3, 1); + testbench_gcd( 3, 127, 131); + testbench_gcd( 131, 127, 3); + testbench_gcd( 127, 131, 3); } From 93e0c6008840743019701d2fe0811ced5460eac4 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 19 Feb 2023 16:53:21 -0500 Subject: [PATCH 068/334] ignoring auto-generated files from autotest --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 912b3441d..0898d51ea 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.gcno *.o *.so +*~ # ignore swap files for vim editing *.swp @@ -30,6 +31,9 @@ config.status makefile xautotest *.m +autotest.json +autotest/logs/*.bin +autotest/logs/*.gnu # miscellany octave-core From 8ab1740f990551aa2a0be0d61a368b54558f3d83 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 22 Feb 2023 19:22:37 -0500 Subject: [PATCH 069/334] qdsync/autotest: adding test to periodically change callback buf len --- src/framing/tests/qdsync_cccf_autotest.c | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index c01555d9c..f6a8fc5ea 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -151,6 +151,63 @@ void autotest_qdsync_k2() { testbench_qdsync_linear(2, 7, 0.3f); } void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } +// test different configurations +void autotest_qdsync_config() +{ + // options + unsigned int seq_len = 2400; // total number of sync symbols + unsigned int k = 2; // samples/symbol + unsigned int m = 12; // filter delay [symbols] + float beta = 0.3f; // excess bandwidth factor + int ftype = LIQUID_FIRFILT_ARKAISER; + + // generate synchronization sequence (QPSK symbols) + float complex seq_tx[seq_len]; // transmitted + float complex seq_rx[seq_len]; // received with initial correction + unsigned int i; + for (i=0; i Date: Thu, 23 Feb 2023 08:07:05 -0500 Subject: [PATCH 070/334] qdsync/autotest: disabling test to set buf len temporarily --- src/framing/tests/qdsync_cccf_autotest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index f6a8fc5ea..a067b026c 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -151,8 +151,8 @@ void autotest_qdsync_k2() { testbench_qdsync_linear(2, 7, 0.3f); } void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } -// test different configurations -void autotest_qdsync_config() +// test setting buffer length ot different sizes throughout run +void xautotest_qdsync_set_buf_len() { // options unsigned int seq_len = 2400; // total number of sync symbols From 9b74c1cccf80fba87ad21ad458c9ee9e094ba7db Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 14:16:56 +0000 Subject: [PATCH 071/334] qdsync: adjusting logic for resizing buffer to fix memory errors --- src/framing/src/qdsync_cccf.c | 19 +++++++++++++------ src/framing/tests/qdsync_cccf_autotest.c | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 1469b4f9c..2dcf01fbf 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -229,7 +229,10 @@ int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len) // buffer might not be empty, but we aren't resizing within this space; // ok to resize so long as old samples are copied _q->buf_out_len = _buf_len; - _q->buf_out = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + if (buf_new == NULL) + return liquid_error(LIQUID_EIMEM,"qdsync_cccf_set_buf_len(), could not allocate %u samples", _buf_len); + _q->buf_out = buf_new; } else { // we are shrinking the buffer below the number of samples it currently // holds; invoke the callback as many times as needed to reduce its size @@ -242,11 +245,15 @@ int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len) index += _buf_len; _q->buf_out_counter -= _buf_len; } - // now perform the reallocation, but we cannot use 'realloc' here because - // we are not copying values at the front of the buffer - float complex * buf_new = (float complex*)malloc(_buf_len * sizeof(float complex)); - memmove(buf_new, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); - free(_q->buf_out); + + // copy old values to front of buffer + memmove(_q->buf_out, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); + + // now resize the buffer appropriately + _q->buf_out_len = _buf_len; + float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + if (buf_new == NULL) + return liquid_error(LIQUID_EIMEM,"qdsync_cccf_set_buf_len(), could not allocate %u samples", _buf_len); _q->buf_out = buf_new; } return LIQUID_OK; diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index a067b026c..1af01ec9c 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -152,7 +152,7 @@ void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } // test setting buffer length ot different sizes throughout run -void xautotest_qdsync_set_buf_len() +void autotest_qdsync_set_buf_len() { // options unsigned int seq_len = 2400; // total number of sync symbols From ee962b4f54fd7218e2a0d16ffed96739699f743b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 11:42:32 -0500 Subject: [PATCH 072/334] qdsync/autotest: adding config() test, extending coverage of existing --- src/framing/tests/qdsync_cccf_autotest.c | 66 ++++++++++++++++++++---- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index 1af01ec9c..1e1c59eaf 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -65,6 +65,7 @@ void testbench_qdsync_linear(unsigned int _k, float beta = _beta; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float nstd = 0.001f; + float tau = 0.400f; // fractional sample timing offset // generate synchronization sequence (QPSK symbols) float complex seq_tx[seq_len]; // transmitted @@ -86,7 +87,7 @@ void testbench_qdsync_linear(unsigned int _k, // create delay object fdelay_crcf delay = fdelay_crcf_create_default(100); - fdelay_crcf_set_delay(delay, 10*k - 0.4); + fdelay_crcf_set_delay(delay, 10*k + tau); // run signal through sync object float complex buf[k]; @@ -108,8 +109,11 @@ void testbench_qdsync_linear(unsigned int _k, // run through synchronizer qdsync_cccf_execute(q, buf, k); } - float dphi_hat = qdsync_cccf_get_dphi(q); - float phi_hat = qdsync_cccf_get_phi(q); + float rxy_hat = qdsync_cccf_get_rxy (q); + float tau_hat = qdsync_cccf_get_tau (q); + float gamma_hat= qdsync_cccf_get_gamma(q); + float dphi_hat = qdsync_cccf_get_dphi (q); + float phi_hat = qdsync_cccf_get_phi (q); // compute error in terms of offset from unity; might be residual carrier phase/gain // TODO: perform residual carrier/phase error correction? @@ -119,11 +123,16 @@ void testbench_qdsync_linear(unsigned int _k, rmse += e*e; } rmse = 10*log10f( rmse / (float)seq_len ); - if (liquid_autotest_verbose) - printf("qdsync: dphi: %12.4e, phi: %12.8f, rmse: %12.3f\n", dphi_hat, phi_hat, rmse); - CONTEND_LESS_THAN( rmse, -30.0f ) - CONTEND_LESS_THAN( fabsf(dphi_hat), 1e-3f ) - CONTEND_LESS_THAN( fabsf( phi_hat), 0.4f ) + if (liquid_autotest_verbose) { + printf("qdsync: rxy:%5.3f, tau:%5.2f, gamma:%5.3f, dphi:%12.4e, phi:%8.5f, rmse:%5.2f\n", + rxy_hat, tau_hat, gamma_hat, dphi_hat, phi_hat, rmse); + } + CONTEND_LESS_THAN ( rmse, -30.0f ) + CONTEND_GREATER_THAN( rxy_hat, 0.75f ) + CONTEND_LESS_THAN ( fabsf(tau_hat-tau), 0.10f ) + CONTEND_GREATER_THAN( gamma_hat, 0.75f ) + CONTEND_LESS_THAN ( fabsf(dphi_hat), 1e-3f ) + CONTEND_LESS_THAN ( fabsf( phi_hat), 0.4f ) // clean up objects qdsync_cccf_destroy(q); @@ -147,9 +156,9 @@ void testbench_qdsync_linear(unsigned int _k, } // test specific configurations -void autotest_qdsync_k2() { testbench_qdsync_linear(2, 7, 0.3f); } -void autotest_qdsync_k3() { testbench_qdsync_linear(3, 7, 0.3f); } -void autotest_qdsync_k4() { testbench_qdsync_linear(4, 7, 0.3f); } +void autotest_qdsync_cccf_k2() { testbench_qdsync_linear(2, 7, 0.3f); } +void autotest_qdsync_cccf_k3() { testbench_qdsync_linear(3, 7, 0.3f); } +void autotest_qdsync_cccf_k4() { testbench_qdsync_linear(4, 7, 0.3f); } // test setting buffer length ot different sizes throughout run void autotest_qdsync_set_buf_len() @@ -291,3 +300,38 @@ void autotest_qdsync_cccf_copy() qdsync_cccf_destroy(q_copy); } +void autotest_qdsync_cccf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping qdsync_cccf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(qdsync_cccf_copy(NULL)); + CONTEND_ISNULL(qdsync_cccf_create_linear(NULL,0,LIQUID_FIRFILT_ARKAISER,4,12,0.25f,NULL,NULL)); + + // create proper object and test configurations + float complex seq[] = {+1,-1,+1,-1,-1,+1,-1,+1,-1,+1,-1,+1,+1,+1,-1,+1,-1,-1,-1,-1,}; + qdsync_cccf q = qdsync_cccf_create_linear(seq,20,LIQUID_FIRFILT_ARKAISER,4,12,0.25f,NULL,NULL); + + CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_print(q)) + CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_set_callback(q,autotest_qdsync_callback)) + CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_set_context(q,NULL)) + + // set/get threshold + CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_set_threshold(q,0.654321f)) + CONTEND_EQUALITY(0.654321f, qdsync_cccf_get_threshold(q)) + + // set invalid buffer length + CONTEND_INEQUALITY(LIQUID_OK, qdsync_cccf_set_buf_len(q,0)) + + // query properties + CONTEND_EQUALITY(0, qdsync_cccf_is_open(q)) + + // destroy object + qdsync_cccf_destroy(q); +} + From 2e496aa80ff87f8b351b0968d9f3e3458eac8229 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 15:22:19 -0500 Subject: [PATCH 073/334] gasearch: adding (basic) autotest on simple toy problem --- examples/gasearch_example.c | 112 ++++++++-------------------- makefile.in | 1 + src/optim/tests/gasearch_autotest.c | 96 ++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 79 deletions(-) create mode 100644 src/optim/tests/gasearch_autotest.c diff --git a/examples/gasearch_example.c b/examples/gasearch_example.c index 677bb3fba..ddc903651 100644 --- a/examples/gasearch_example.c +++ b/examples/gasearch_example.c @@ -1,7 +1,4 @@ -// -// gasearch_example.c -// - +// example demonstrating performance of GA search algorithm for finding basic function peak #include #include #include @@ -10,57 +7,59 @@ #define OUTPUT_FILENAME "gasearch_example.m" -// utility callback function -float utility_callback(void * _userdata, chromosome _c); - -// peak callback function; value nearest {0.5, 0.5, 0.5, ...} -float peak_callback(void * _userdata, chromosome _c); - -// rosenbrock callback function -float rosenbrock_callback(void * _userdata, chromosome _c); +// peak callback function; value nearest {p, p, p, ...} where p = 1/sqrt(2) +float peak_callback(void * _userdata, chromosome _c) +{ + unsigned int i, n = chromosome_get_num_traits(_c); + float u_global = 1.0f; + float sig = 0.2f; + float p = M_SQRT1_2; + for (i=0; i +#include +#include +#include +#include + +#include "liquid.internal.h" + +// peak callback function; value nearest {p, p, p, ...} where p = 1/sqrt(2) +float gasearch_autotest_peak_callback(void * _userdata, chromosome _c) +{ + unsigned int i, n = chromosome_get_num_traits(_c); + float u = 1.0f; + float sig = 0.2f; + float p = M_SQRT1_2; + for (i=0; i Date: Sat, 25 Feb 2023 16:37:57 -0500 Subject: [PATCH 074/334] gasearch/autotest: adding configuration tests --- src/optim/src/chromosome.c | 46 ++++++------ src/optim/src/gasearch.c | 12 +++- src/optim/tests/gasearch_autotest.c | 105 +++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 23 deletions(-) diff --git a/src/optim/src/chromosome.c b/src/optim/src/chromosome.c index 11dcc639b..ea1147a52 100644 --- a/src/optim/src/chromosome.c +++ b/src/optim/src/chromosome.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,32 +37,33 @@ // _bits_per_trait : array of bits/trait [size: _num_traits x 1] // _num_traits : number of traits in this chromosome chromosome chromosome_create(unsigned int * _bits_per_trait, - unsigned int _num_traits) + unsigned int _num_traits) { + // validate input + unsigned int i; + if (_num_traits < 1) + return liquid_error_config("chromosome_create(), must have at least one trait"); + for (i=0; i<_num_traits; i++) { + if (_bits_per_trait[i] > LIQUID_CHROMOSOME_MAX_SIZE) + return liquid_error_config("chromosome_create(), bits/trait cannot exceed %u", LIQUID_CHROMOSOME_MAX_SIZE); + } + chromosome q; q = (chromosome) malloc( sizeof(struct chromosome_s) ); q->num_traits = _num_traits; - // validate input - if (q->num_traits < 1) - return liquid_error_config("chromosome_create(), must have at least one trait"); - // initialize internal arrays q->bits_per_trait = (unsigned int *) malloc(q->num_traits*sizeof(unsigned int)); q->max_value = (unsigned long*) malloc(q->num_traits*sizeof(unsigned long)); q->traits = (unsigned long*) malloc(q->num_traits*sizeof(unsigned long)); // copy/initialize values - unsigned int i; q->num_bits = 0; for (i=0; inum_traits; i++) { q->bits_per_trait[i] = _bits_per_trait[i]; - if (q->bits_per_trait[i] > LIQUID_CHROMOSOME_MAX_SIZE) - return liquid_error_config("chromosome_create(), bits/trait cannot exceed %u", LIQUID_CHROMOSOME_MAX_SIZE); - - q->max_value[i] = 1 << q->bits_per_trait[i]; - q->traits[i] = 0; + q->max_value[i] = 1LU << q->bits_per_trait[i]; + q->traits[i] = 0LU; q->num_bits += q->bits_per_trait[i]; } @@ -79,6 +80,8 @@ chromosome chromosome_create_basic(unsigned int _num_traits, // validate input if (_num_traits == 0) return liquid_error_config("chromosome_create_basic(), must have at least one trait"); + if (_bits_per_trait == 0 || _bits_per_trait > 64) + return liquid_error_config("chromosome_create_basic(), bits per trait out of range"); unsigned int * bpt = (unsigned int *) malloc(_num_traits*sizeof(unsigned int)); unsigned int i; @@ -175,6 +178,7 @@ int chromosome_init(chromosome _c, { unsigned int i; for (i=0; i<_c->num_traits; i++) { + //printf("===> [%3u] bits:%3u, max:%12lu, value:%12lu\n", i, _c->bits_per_trait[i], _c->max_value[i], _v[i]); if (_v[i] >= _c->max_value[i]) return liquid_error(LIQUID_EIRANGE,"chromosome_init(), value exceeds maximum"); @@ -189,12 +193,14 @@ int chromosome_initf(chromosome _c, { unsigned int i; for (i=0; i<_c->num_traits; i++) { - if (_v[i] > 1.0f || _v[i] < 0.0f) + if (_v[i] < 0.0f || _v[i] > 1.0f) return liquid_error(LIQUID_EIRANGE,"chromosome_initf(), value must be in [0,1]"); // quantize sample - unsigned int N = 1 << _c->bits_per_trait[i]; - _c->traits[i] = (unsigned int) floorf( _v[i] * N ); + unsigned long N = 1LU << _c->bits_per_trait[i]; + _c->traits[i] = (unsigned long) floorf( _v[i] * N ); + //printf("===> [%3u] quantizing %8.2f, bits:%3u, N:%12lu, trait:%12lu/%12lu => %12.8f\n", + // i, _v[i], _c->bits_per_trait[i], N, _c->traits[i], _c->max_value[i], chromosome_valuef(_c,i)); } return LIQUID_OK; } @@ -212,10 +218,10 @@ int chromosome_mutate(chromosome _q, for (i=0; i<_q->num_traits; i++) { unsigned int b = _q->bits_per_trait[i]; if (t == _index) { - _q->traits[i] ^= (unsigned long)(1 << (b-1)); + _q->traits[i] ^= (unsigned long)(1LU << (b-1)); return LIQUID_OK; } else if (t > _index) { - _q->traits[i-1] ^= (unsigned long)(1 << (t-_index-1)); + _q->traits[i-1] ^= (unsigned long)(1LU << (t-_index-1)); return LIQUID_OK; } else { t += b; @@ -289,18 +295,18 @@ int chromosome_init_random(chromosome _q) { unsigned int i; for (i=0; i<_q->num_traits; i++) - _q->traits[i] = rand() & (_q->max_value[i]-1); + _q->traits[i] = rand() & (_q->max_value[i]-1LU); return LIQUID_OK; } -float chromosome_valuef(chromosome _q, +float chromosome_valuef(chromosome _q, unsigned int _index) { if (_index > _q->num_traits) { liquid_error(LIQUID_EIRANGE,"chromosome_valuef(), trait index exceeded"); return 0.0f; } - return (float) (_q->traits[_index]) / (float)(_q->max_value[_index] - 1); + return (float) (_q->traits[_index]) / (float)(_q->max_value[_index]-1LU); } unsigned int chromosome_value(chromosome _q, diff --git a/src/optim/src/gasearch.c b/src/optim/src/gasearch.c index 9ab3fb7ee..e33d190bd 100644 --- a/src/optim/src/gasearch.c +++ b/src/optim/src/gasearch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -66,8 +66,14 @@ gasearch gasearch_create_advanced(gasearch_utility _utility, gasearch ga; ga = (gasearch) malloc( sizeof(struct gasearch_s) ); + if (_utility == NULL) + return liquid_error_config("gasearch_create(), utility function cannot be NULL") + if (_parent == NULL) + return liquid_error_config("gasearch_create(), parent cannot be NULL") + if (_population_size < 2) + return liquid_error_config("gasearch_create(), population size exceeds minimum"); if (_population_size > LIQUID_GA_SEARCH_MAX_POPULATION_SIZE) - return liquid_error_config("gasearch_create(), population size exceeds maximum"); + return liquid_error_config("gasearch_create(), population size exceeds maximum (%u)",LIQUID_GA_SEARCH_MAX_POPULATION_SIZE); if (_mutation_rate < 0.0f || _mutation_rate > 1.0f) return liquid_error_config("gasearch_create(), mutation rate must be in [0,1]"); @@ -162,6 +168,8 @@ int gasearch_set_population_size(gasearch _g, // validate input if (_population_size < 2) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), population must be at least 2"); + if (_population_size > LIQUID_GA_SEARCH_MAX_POPULATION_SIZE) + return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), population exceeds maximum (%u)",LIQUID_GA_SEARCH_MAX_POPULATION_SIZE); if (_selection_size == 0) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), selection size must be greater than zero"); if (_selection_size >= _population_size) diff --git a/src/optim/tests/gasearch_autotest.c b/src/optim/tests/gasearch_autotest.c index e95afef36..77da5f9f3 100644 --- a/src/optim/tests/gasearch_autotest.c +++ b/src/optim/tests/gasearch_autotest.c @@ -82,7 +82,7 @@ void autotest_gasearch_peak() chromosome_printf(prototype); } - // destroy gradient descent search object + // destroy search object chromosome_destroy(prototype); gasearch_destroy(ga); @@ -94,3 +94,106 @@ void autotest_gasearch_peak() CONTEND_GREATER_THAN( optimum_utility, 0.70f ) } +// test chromosome configuration +void autotest_chromosome_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping chromosome config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test chromosome + unsigned int bits_per_trait_invalid[8] = {6,6,6,6,6,6,6,1000}; + unsigned int bits_per_trait_valid [8] = {6,6,6,6,6,6,6, 32}; + CONTEND_ISNULL(chromosome_create(bits_per_trait_invalid, 8)) + CONTEND_ISNULL(chromosome_create(bits_per_trait_valid, 0)) + CONTEND_ISNULL(chromosome_create_basic(0, 12)) // too few traits + CONTEND_ISNULL(chromosome_create_basic(8, 0)) // bits per trait too small + CONTEND_ISNULL(chromosome_create_basic(8, 99)) // bits per trait too large + + // create prototype chromosome using basic method + chromosome prototype = chromosome_create_basic(20, 5); + CONTEND_EQUALITY(LIQUID_OK, chromosome_print(prototype)) + chromosome_destroy(prototype); + + // create prototype chromosome using more specific method + prototype = chromosome_create(bits_per_trait_valid, 8); + CONTEND_EQUALITY(LIQUID_OK, chromosome_print(prototype)) + + // test initialization + unsigned int values_invalid[] = {999,12,11,13,63,17, 3,123456789}; // invalid because first trait is only 6 bits + unsigned int values_valid [] = { 0,12,11,13,63,17, 3,123456789}; + CONTEND_INEQUALITY(LIQUID_OK, chromosome_init (prototype, values_invalid)) + CONTEND_EQUALITY (LIQUID_OK, chromosome_init (prototype, values_valid )) + + // check individual values + CONTEND_EQUALITY( chromosome_value(prototype, 0), 0) + CONTEND_EQUALITY( chromosome_value(prototype, 1), 12) + CONTEND_EQUALITY( chromosome_value(prototype, 2), 11) + CONTEND_EQUALITY( chromosome_value(prototype, 3), 13) + CONTEND_EQUALITY( chromosome_value(prototype, 4), 63) + CONTEND_EQUALITY( chromosome_value(prototype, 5), 17) + CONTEND_EQUALITY( chromosome_value(prototype, 6), 3) + CONTEND_EQUALITY( chromosome_value(prototype, 7), 123456789) + + // test initialization (float values) + float valuesf_invalid[] = {0.0,0.1,0.2,0.3,0.4,0.5,0.6,999,}; + float valuesf_valid [] = {0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,}; + CONTEND_INEQUALITY(LIQUID_OK, chromosome_initf(prototype, valuesf_invalid)) + CONTEND_EQUALITY (LIQUID_OK, chromosome_initf(prototype, valuesf_valid )) + + // check individual values + CONTEND_DELTA( chromosome_valuef(prototype, 0), 0.0f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 1), 0.1f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 2), 0.2f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 3), 0.3f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 4), 0.4f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 5), 0.5f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 6), 0.6f, 0.02f ) + CONTEND_DELTA( chromosome_valuef(prototype, 7), 0.7f, 0.02f ) + + // destroy objects + chromosome_destroy(prototype); +} + +// test configuration +void autotest_gasearch_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping gasearch config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // create prototype chromosome + chromosome prototype = chromosome_create_basic(8, 12); + + // check invalid function calls + CONTEND_ISNULL(gasearch_create_advanced( NULL, NULL, prototype, LIQUID_OPTIM_MAXIMIZE, 16, 0.1f)) // bad utility function + CONTEND_ISNULL(gasearch_create_advanced(gasearch_autotest_peak_callback, NULL, NULL, LIQUID_OPTIM_MAXIMIZE, 0, 0.1f)) // bad parent chromosome + CONTEND_ISNULL(gasearch_create_advanced(gasearch_autotest_peak_callback, NULL, prototype, LIQUID_OPTIM_MAXIMIZE, 0, 0.1f)) // bad population size + CONTEND_ISNULL(gasearch_create_advanced(gasearch_autotest_peak_callback, NULL, prototype, LIQUID_OPTIM_MAXIMIZE, -1, 0.1f)) // bad population size + CONTEND_ISNULL(gasearch_create_advanced(gasearch_autotest_peak_callback, NULL, prototype, LIQUID_OPTIM_MAXIMIZE, 16,-1.0f)) // bad mutation rate + + // create proper object and test configurations + gasearch ga = gasearch_create(gasearch_autotest_peak_callback, NULL, prototype, LIQUID_OPTIM_MAXIMIZE); + CONTEND_EQUALITY(LIQUID_OK, gasearch_print(ga)) + + // test configurations + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_population_size(ga, 0, 8)) // population size too small + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_population_size(ga,-1, 8)) // population size too large + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_population_size(ga,24, 0)) // selection size too small + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_population_size(ga,24,24)) // selection size too large + CONTEND_EQUALITY (LIQUID_OK, gasearch_set_population_size(ga,24,12)) // ok + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_mutation_rate (ga,-1.0f)) // mutation rate out of range + CONTEND_INEQUALITY(LIQUID_OK, gasearch_set_mutation_rate (ga, 2.0f)) // mutation rate out of range + CONTEND_EQUALITY (LIQUID_OK, gasearch_set_mutation_rate (ga, 0.1f)) // ok + + // destroy objects + chromosome_destroy(prototype); + gasearch_destroy(ga); +} + From c9ef699261c50bdcbc105776461be113954f2323 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 16:46:13 -0500 Subject: [PATCH 075/334] chromosome/autotest: testing more edge cases in configuration --- src/optim/tests/gasearch_autotest.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/optim/tests/gasearch_autotest.c b/src/optim/tests/gasearch_autotest.c index 77da5f9f3..77ba6e2f8 100644 --- a/src/optim/tests/gasearch_autotest.c +++ b/src/optim/tests/gasearch_autotest.c @@ -120,13 +120,18 @@ void autotest_chromosome_config() // create prototype chromosome using more specific method prototype = chromosome_create(bits_per_trait_valid, 8); - CONTEND_EQUALITY(LIQUID_OK, chromosome_print(prototype)) + CONTEND_EQUALITY (LIQUID_OK, chromosome_print (prototype)) + CONTEND_EQUALITY (LIQUID_OK, chromosome_reset (prototype)) // test initialization unsigned int values_invalid[] = {999,12,11,13,63,17, 3,123456789}; // invalid because first trait is only 6 bits unsigned int values_valid [] = { 0,12,11,13,63,17, 3,123456789}; CONTEND_INEQUALITY(LIQUID_OK, chromosome_init (prototype, values_invalid)) CONTEND_EQUALITY (LIQUID_OK, chromosome_init (prototype, values_valid )) + CONTEND_EQUALITY ( 0, chromosome_value (prototype,999)) + CONTEND_EQUALITY ( 0.0f, chromosome_valuef (prototype,999)) + CONTEND_INEQUALITY(LIQUID_OK, chromosome_mutate (prototype,999)) + CONTEND_INEQUALITY(LIQUID_OK, chromosome_crossover(prototype,prototype,prototype,999)) // check individual values CONTEND_EQUALITY( chromosome_value(prototype, 0), 0) From 01a78ebecf32d94240693f268d038cbd84c46011 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 18:33:59 -0500 Subject: [PATCH 076/334] qnsearch: adding basic autotest script --- makefile.in | 1 + src/optim/src/qnsearch.c | 6 +-- src/optim/tests/qnsearch_autotest.c | 63 +++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 src/optim/tests/qnsearch_autotest.c diff --git a/makefile.in b/makefile.in index 4b8787448..555c90508 100644 --- a/makefile.in +++ b/makefile.in @@ -1014,6 +1014,7 @@ $(optim_objects) : %.o : %.c $(include_headers) optim_autotests := \ src/optim/tests/gasearch_autotest.c \ src/optim/tests/gradsearch_autotest.c \ + src/optim/tests/qnsearch_autotest.c \ src/optim/tests/qs1dsearch_autotest.c \ # benchmarks diff --git a/src/optim/src/qnsearch.c b/src/optim/src/qnsearch.c index 168ba3162..bf9260df2 100644 --- a/src/optim/src/qnsearch.c +++ b/src/optim/src/qnsearch.c @@ -192,9 +192,9 @@ int qnsearch_step(qnsearch _q) return LIQUID_OK; } -float qnsearch_run(qnsearch _q, - unsigned int _max_iterations, - float _target_utility) +float qnsearch_execute(qnsearch _q, + unsigned int _max_iterations, + float _target_utility) { unsigned int i=0; do { diff --git a/src/optim/tests/qnsearch_autotest.c b/src/optim/tests/qnsearch_autotest.c new file mode 100644 index 000000000..449413a3e --- /dev/null +++ b/src/optim/tests/qnsearch_autotest.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "autotest/autotest.h" +#include "liquid.h" + +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +void autotest_qnsearch_rosenbrock() +{ + float tol = 1e-2f; // error tolerance + unsigned int num_parameters = 6; // dimensionality of search (minimum 2) + unsigned int num_iterations = 4000; // number of iterations to run + + // initialize vector for optimization + float v_opt[num_parameters]; + unsigned int i; + for (i=0; i Date: Sat, 25 Feb 2023 18:54:50 -0500 Subject: [PATCH 077/334] gasearch: validating input before allocate memory in create() --- src/optim/src/gasearch.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/optim/src/gasearch.c b/src/optim/src/gasearch.c index e33d190bd..a846aabdf 100644 --- a/src/optim/src/gasearch.c +++ b/src/optim/src/gasearch.c @@ -63,9 +63,7 @@ gasearch gasearch_create_advanced(gasearch_utility _utility, unsigned int _population_size, float _mutation_rate) { - gasearch ga; - ga = (gasearch) malloc( sizeof(struct gasearch_s) ); - + // validate input if (_utility == NULL) return liquid_error_config("gasearch_create(), utility function cannot be NULL") if (_parent == NULL) @@ -77,7 +75,8 @@ gasearch gasearch_create_advanced(gasearch_utility _utility, if (_mutation_rate < 0.0f || _mutation_rate > 1.0f) return liquid_error_config("gasearch_create(), mutation rate must be in [0,1]"); - // initialize public values + // create object and initialize values + gasearch ga = (gasearch) malloc( sizeof(struct gasearch_s) ); ga->userdata = _userdata; ga->num_parameters = _parent->num_traits; ga->population_size = _population_size; From 9aa1d2913d52a9f5a1c031455aa178ed1bbc6d8d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 18:59:05 -0500 Subject: [PATCH 078/334] qnsearch: adding config() tests --- src/optim/src/qnsearch.c | 26 +++++++------------------- src/optim/tests/qnsearch_autotest.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/optim/src/qnsearch.c b/src/optim/src/qnsearch.c index bf9260df2..61bef0556 100644 --- a/src/optim/src/qnsearch.c +++ b/src/optim/src/qnsearch.c @@ -72,9 +72,14 @@ qnsearch qnsearch_create(void * _userdata, utility_function _u, int _minmax) { - qnsearch q = (qnsearch) malloc( sizeof(struct qnsearch_s) ); + // validate input + if (_u == NULL) + return liquid_error_config("qnsearch_create(), utility function cannot be NULL") + if (_num_parameters == 0) + return liquid_error_config("qnsearch_create(), number of parameters must be greater than zero"); - // initialize public values + // create object and initialize public values + qnsearch q = (qnsearch) malloc( sizeof(struct qnsearch_s) ); q->delta = 1e-6f; //_delta; q->gamma = 1e-3f; //_gamma; q->dgamma = 0.99f; @@ -146,7 +151,6 @@ int qnsearch_step(qnsearch _q) // compute normalized gradient vector qnsearch_compute_gradient(_q); - //qnsearch_normalize_gradient(_q); // TODO : perform line search to find optimal gamma @@ -231,22 +235,6 @@ int qnsearch_compute_gradient(qnsearch _q) return LIQUID_OK; } -// normalize gradient vector to unity -int qnsearch_normalize_gradient(qnsearch _q) -{ - // normalize gradient - float sig = 0.0f; - unsigned int i; - for (i=0; i<_q->num_parameters; i++) - sig += _q->gradient[i] * _q->gradient[i]; - - sig = 1.0f / sqrtf(sig/(float)(_q->num_parameters)); - - for (i=0; i<_q->num_parameters; i++) - _q->gradient[i] *= sig; - return LIQUID_OK; -} - // compute Hessian int qnsearch_compute_Hessian(qnsearch _q) { diff --git a/src/optim/tests/qnsearch_autotest.c b/src/optim/tests/qnsearch_autotest.c index 449413a3e..1a027c5be 100644 --- a/src/optim/tests/qnsearch_autotest.c +++ b/src/optim/tests/qnsearch_autotest.c @@ -59,5 +59,30 @@ void autotest_qnsearch_rosenbrock() // test value of utility (should be nearly 0) CONTEND_DELTA( liquid_rosenbrock(NULL, v_opt, num_parameters), 0.0f, tol ); + CONTEND_LESS_THAN( u_opt, tol ); +} + +// test configuration +void autotest_qnsearch_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping qnsearch config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + + // test configurations + float v[8] = {0,0,0,0,0,0,0,0}; + CONTEND_ISNULL(qnsearch_create(NULL, v, 0, liquid_rosenbrock, LIQUID_OPTIM_MINIMIZE)) // no parameters + CONTEND_ISNULL(qnsearch_create(NULL, v, 8, NULL, LIQUID_OPTIM_MINIMIZE)) // utility is null + + // create proper object and test configurations + qnsearch q = qnsearch_create(NULL, v, 8, liquid_rosenbrock, LIQUID_OPTIM_MINIMIZE); + CONTEND_EQUALITY(LIQUID_OK, qnsearch_print(q)) + + // destroy objects + qnsearch_destroy(q); } From 7645b1faba4dfb4893665066500cfa1b2eba3107 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 20:54:04 -0500 Subject: [PATCH 079/334] qs1dsearch/autotest: adding config test --- src/optim/tests/qs1dsearch_autotest.c | 32 ++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/optim/tests/qs1dsearch_autotest.c b/src/optim/tests/qs1dsearch_autotest.c index e293788d8..bcfc41326 100644 --- a/src/optim/tests/qs1dsearch_autotest.c +++ b/src/optim/tests/qs1dsearch_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -105,3 +105,33 @@ void autotest_qs1dsearch_max_11() { test_qs1dsearch(qs1dsearch_umax, 0, -20, 15, void autotest_qs1dsearch_max_12() { test_qs1dsearch(qs1dsearch_umax, 0, -10, 15, 1, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_13() { test_qs1dsearch(qs1dsearch_umax, 0, -.1, 15, 1, LIQUID_OPTIM_MAXIMIZE); } +// test configuration +void autotest_qs1dsearch_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping qs1dsearch config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(qs1dsearch_create(NULL, NULL, LIQUID_OPTIM_MAXIMIZE)) // utility is NULL + CONTEND_ISNULL(qs1dsearch_copy (NULL)) + + // create proper object and test configurations + float v_opt = 0; + qs1dsearch q = qs1dsearch_create(qs1dsearch_umax, &v_opt, LIQUID_OPTIM_MAXIMIZE); + CONTEND_EQUALITY(LIQUID_OK, qs1dsearch_print(q)) + + // test configurations + CONTEND_INEQUALITY(LIQUID_OK, qs1dsearch_step(q)) // object not yet initialized + qs1dsearch_init(q, 20); + + CONTEND_EQUALITY(LIQUID_OK, qs1dsearch_execute(q)) + CONTEND_EQUALITY( 0, qs1dsearch_get_num_steps(q)) + + // destroy objects + qs1dsearch_destroy(q); +} + From 2ae6966d60ed0a6af84588f61e3b7bc80247ce4d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Feb 2023 21:03:42 -0500 Subject: [PATCH 080/334] optim/autotest: adding utility tests --- makefile.in | 1 + src/optim/tests/utility_autotest.c | 56 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/optim/tests/utility_autotest.c diff --git a/makefile.in b/makefile.in index 555c90508..3fbf73e16 100644 --- a/makefile.in +++ b/makefile.in @@ -1016,6 +1016,7 @@ optim_autotests := \ src/optim/tests/gradsearch_autotest.c \ src/optim/tests/qnsearch_autotest.c \ src/optim/tests/qs1dsearch_autotest.c \ + src/optim/tests/utility_autotest.c \ # benchmarks optim_benchmarks := diff --git a/src/optim/tests/utility_autotest.c b/src/optim/tests/utility_autotest.c new file mode 100644 index 000000000..05ef49670 --- /dev/null +++ b/src/optim/tests/utility_autotest.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "autotest/autotest.h" +#include "liquid.h" + +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +void autotest_optim_rosenbrock() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping rosenbrock config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + + // optimum + float v_ones[8] = {1,1,1,1,1,1,1,1}; + CONTEND_DELTA( liquid_rosenbrock(NULL, v_ones, 8), 0.0f, 1e-6f ) + CONTEND_DELTA( liquid_rosenbrock(NULL, v_ones, 1), 0.0f, 1e-6f ) + + // very far from optimum + float v_misc[8] = {0.3, 1.0, 4.5,-2.2, 6.7,-0.2, 1.1,-0.9,}; + CONTEND_GREATER_THAN( liquid_rosenbrock(NULL, v_misc, 8), 1000.0f ) + + // invalid configuration + CONTEND_EQUALITY( liquid_rosenbrock(NULL, v_misc, 0), 0.0f ) +} + From 5f7c3c8627aa36e1a422b383f141ab60c99d7377 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 26 Feb 2023 08:21:52 -0500 Subject: [PATCH 081/334] fskframesync: adding (very) basic autotest * working copy until framing structure gets better definition * tests only that frame is recovered * should provide estimates of carrier offset, SNR, etc. * needs to support different payload lengths, coding rates, etc. --- examples/fskframesync_example.c | 5 - makefile.in | 1 + src/framing/src/fskframegen.c | 6 +- src/framing/src/fskframesync.c | 20 ++-- src/framing/tests/fskframesync_autotest.c | 113 ++++++++++++++++++++++ 5 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 src/framing/tests/fskframesync_autotest.c diff --git a/examples/fskframesync_example.c b/examples/fskframesync_example.c index c50c49b9f..52445cf0b 100644 --- a/examples/fskframesync_example.c +++ b/examples/fskframesync_example.c @@ -1,13 +1,8 @@ -// -// fskframesync_example.c -// // This example demonstrates the interfaces to the fskframegen and // fskframesync objects used to completely encapsulate data for // over-the-air transmission. // // SEE ALSO: flexframesync_example.c -// - #include #include #include diff --git a/makefile.in b/makefile.in index 3fbf73e16..71e5b16f1 100644 --- a/makefile.in +++ b/makefile.in @@ -694,6 +694,7 @@ framing_autotests := \ src/framing/tests/dsssframesync_autotest.c \ src/framing/tests/flexframesync_autotest.c \ src/framing/tests/framesync64_autotest.c \ + src/framing/tests/fskframesync_autotest.c \ src/framing/tests/gmskframe_autotest.c \ src/framing/tests/msource_autotest.c \ src/framing/tests/ofdmflexframe_autotest.c \ diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c index 8aac7cf34..90557e53c 100644 --- a/src/framing/src/fskframegen.c +++ b/src/framing/src/fskframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -321,7 +321,7 @@ int fskframegen_assemble(fskframegen _q, // encode payload symbols qpacketmodem_encode_syms(_q->payload_encoder, _payload, _q->payload_sym); -#if 1 +#if 0 printf("tx payload symbols (%u)\n", _q->payload_sym_len); unsigned int i; for (i=0; i<_q->payload_sym_len; i++) @@ -404,7 +404,7 @@ int fskframegen_encode_header(fskframegen _q, // run packet encoder, encoding into symbols qpacketmodem_encode_syms(_q->header_encoder, _q->header_dec, _q->header_sym); -#if 1 +#if 0 printf("tx header symbols (%u):\n", _q->header_sym_len); unsigned int i; for (i=0; i<_q->header_sym_len; i++) diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c index 47ec916a5..f68c4cf4c 100644 --- a/src/framing/src/fskframesync.c +++ b/src/framing/src/fskframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -456,14 +456,14 @@ int fskframesync_execute_detectframe(fskframesync _q, // NOTE: because this is a ratio of energies in frequency, we don't need // to take the absolute value here; only positive values should work if (rxy > 0.5f) { - printf("### fskframe detected! ###\n"); + //printf("### fskframe detected! ###\n"); _q->frame_detected = 1; } } else { // frame has already been detected; wait for signal to peak if (_q->rxy[1] > _q->rxy[2]) { - printf("signal peaked! %12.8f %12.8f %12.8f\n", - _q->rxy[0], _q->rxy[1], _q->rxy[2]); + //printf("signal peaked! %12.8f %12.8f %12.8f\n", + // _q->rxy[0], _q->rxy[1], _q->rxy[2]); // compute estimate, apply bias compensation float gamma = (_q->rxy[2] - _q->rxy[0]) / _q->rxy[1]; @@ -472,8 +472,8 @@ int fskframesync_execute_detectframe(fskframesync _q, float xf = fabsf(gamma); float tau_hat = copysignf(p2*xf*xf + p1*xf, gamma); int num_samples = round(tau_hat * _q->k); - printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", - gamma, tau_hat, num_samples); + //printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", + // gamma, tau_hat, num_samples); // TODO: set timer and filterbank index accordingly _q->timer = 2*_q->k; @@ -481,7 +481,7 @@ int fskframesync_execute_detectframe(fskframesync _q, // update state... _q->state = STATE_RXHEADER; } else { - printf("signal not yet peaked...\n"); + //printf("signal not yet peaked...\n"); } } return LIQUID_OK; @@ -524,7 +524,7 @@ int fskframesync_execute_rxheader(fskframesync _q, int header_valid = qpacketmodem_decode_syms(_q->header_decoder, _q->header_sym, _q->header_dec); -#if 1 +#if 0 printf("rx header symbols (%u):\n", _q->header_sym_len); unsigned int i; for (i=0; i<_q->header_sym_len; i++) @@ -612,7 +612,7 @@ int fskframesync_execute_rxpayload(fskframesync _q, // decode payload if appropriate if (_q->symbol_counter == _q->payload_sym_len) { -#if 1 +#if 0 printf("rx payload symbols (%u)\n", _q->payload_sym_len); unsigned int i; for (i=0; i<_q->payload_sym_len; i++) @@ -623,7 +623,7 @@ int fskframesync_execute_rxpayload(fskframesync _q, int payload_valid = qpacketmodem_decode_syms(_q->payload_decoder, _q->payload_sym, _q->payload_dec); - printf("payload: %s\n", payload_valid ? "valid" : "INVALID"); + //printf("payload: %s\n", payload_valid ? "valid" : "INVALID"); // invoke callback if (_q->callback != NULL) { diff --git a/src/framing/tests/fskframesync_autotest.c b/src/framing/tests/fskframesync_autotest.c new file mode 100644 index 000000000..9ffbef087 --- /dev/null +++ b/src/framing/tests/fskframesync_autotest.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "autotest/autotest.h" +#include "liquid.h" + +static int callback_fskframesync_autotest( + unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata) +{ + //printf("callback invoked, payload valid: %s\n", _payload_valid ? "yes" : "no"); + *((int*)(_userdata)) += _header_valid && _payload_valid ? 1 : 0; + return 0; +} + +// AUTOTEST : test simple recovery of frame in noise +void autotest_fskframesync() +{ + // options + float SNRdB = 20.0f; // signal-to-noise ratio + float noise_floor = -20.0f; // noise floor + //float dphi = 0.01f; // carrier frequency offset + //float theta = 0.0f; // carrier phase offset + //float dt = -0.2f; // fractional sample timing offset + + crc_scheme check = LIQUID_CRC_32; // data validity check + fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) + fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) + + // derived values + float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev. + float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain + + unsigned int i; + int frames_recovered = 0; + + // create objects + fskframegen fg = fskframegen_create(); + fskframesync fs = fskframesync_create(callback_fskframesync_autotest, + (void*)&frames_recovered); + + // assemble the frame + unsigned char header [ 8]; + unsigned char payload[200]; + for (i=0; i< 8; i++) header [i] = i; + for (i=0; i<200; i++) payload[i] = rand() & 0xff; + fskframegen_assemble(fg, header, payload, 200, check, fec0, fec1); + + // allocate memory for the frame samples + unsigned int buf_len = 256; + float complex buf_tx[buf_len]; // receive buffer + float complex buf_rx[buf_len]; // transmit buffer + + // try to receive the frame (operate in blocks) + int frame_complete = 0; + while (!frame_complete) + { + // generate frame samples + frame_complete = fskframegen_write_samples(fg, buf_tx, buf_len); + + // add noise, channel gain + for (i=0; i Date: Sun, 26 Feb 2023 10:34:53 -0500 Subject: [PATCH 082/334] qs1dsearch: resetting 'num_steps' counter --- src/optim/src/qs1dsearch.c | 1 + src/optim/tests/qs1dsearch_autotest.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/optim/src/qs1dsearch.c b/src/optim/src/qs1dsearch.c index 627fedcc1..35d051729 100644 --- a/src/optim/src/qs1dsearch.c +++ b/src/optim/src/qs1dsearch.c @@ -78,6 +78,7 @@ int qs1dsearch_print(qs1dsearch _q) int qs1dsearch_reset(qs1dsearch _q) { _q->init = 0; + _q->num_steps = 0; return LIQUID_OK; } diff --git a/src/optim/tests/qs1dsearch_autotest.c b/src/optim/tests/qs1dsearch_autotest.c index bcfc41326..495349f06 100644 --- a/src/optim/tests/qs1dsearch_autotest.c +++ b/src/optim/tests/qs1dsearch_autotest.c @@ -129,7 +129,13 @@ void autotest_qs1dsearch_config() qs1dsearch_init(q, 20); CONTEND_EQUALITY(LIQUID_OK, qs1dsearch_execute(q)) - CONTEND_EQUALITY( 0, qs1dsearch_get_num_steps(q)) + + // run a few steps + CONTEND_EQUALITY( 0, qs1dsearch_get_num_steps(q)) + qs1dsearch_step(q); + qs1dsearch_step(q); + qs1dsearch_step(q); + CONTEND_EQUALITY( 3, qs1dsearch_get_num_steps(q)) // destroy objects qs1dsearch_destroy(q); From de293b66cbb6865c12601a703d705e10d1b77952 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 27 Feb 2023 17:49:30 -0500 Subject: [PATCH 083/334] ofdmflexframesync/autotest: testing configurations --- src/framing/tests/ofdmflexframe_autotest.c | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/framing/tests/ofdmflexframe_autotest.c b/src/framing/tests/ofdmflexframe_autotest.c index eabde9d73..cf24e6bac 100644 --- a/src/framing/tests/ofdmflexframe_autotest.c +++ b/src/framing/tests/ofdmflexframe_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -90,3 +90,27 @@ void autotest_ofdmflexframe_07() { testbench_ofdmflexframe(1200, 40, 20, 1, L void autotest_ofdmflexframe_08() { testbench_ofdmflexframe(1200, 0, 0, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_09() { testbench_ofdmflexframe(1200, 40, 20, 8217, LIQUID_MODEM_QPSK); } +void autotest_ofdmflexframe_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmflexframe config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + //CONTEND_ISNULL(ofdmflexframesync_copy(NULL)); + CONTEND_ISNULL(ofdmflexframesync_create( 0, 16, 4, NULL, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmflexframesync_create( 7, 16, 4, NULL, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmflexframesync_create(65, 16, 4, NULL, NULL, NULL)) // odd-length subcarriers + CONTEND_ISNULL(ofdmflexframesync_create(64, 66, 4, NULL, NULL, NULL)) // cyclic prefix length too large + + // create proper object and test configurations + ofdmflexframesync q = ofdmflexframesync_create(64, 16, 4, NULL, NULL, NULL); + + CONTEND_EQUALITY(LIQUID_OK, ofdmflexframesync_print(q)) + + ofdmflexframesync_destroy(q); +} + From f734313856cf5a234c3f7e9b2056e5a49d504cb1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 27 Feb 2023 17:53:57 -0500 Subject: [PATCH 084/334] ofdmflexframegen/autotest: testing configurations --- src/framing/src/ofdmflexframegen.c | 8 ++++--- src/framing/src/ofdmflexframesync.c | 2 +- src/framing/tests/ofdmflexframe_autotest.c | 28 ++++++++++++++++++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/framing/src/ofdmflexframegen.c b/src/framing/src/ofdmflexframegen.c index 52a7a7fef..90191a814 100644 --- a/src/framing/src/ofdmflexframegen.c +++ b/src/framing/src/ofdmflexframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -157,10 +157,12 @@ ofdmflexframegen ofdmflexframegen_create(unsigned int _M, ofdmflexframegenprops_s * _fgprops) { // validate input - if (_M < 2) - return liquid_error_config("ofdmflexframegen_create(), number of subcarriers must be at least 2"); + if (_M < 8) + return liquid_error_config("ofdmflexframegen_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmflexframegen_create(), number of subcarriers must be even"); + if (_cp_len > _M) + return liquid_error_config("ofdmflexframegen_create(), cyclic prefix length cannot exceed number of subcarriers"); ofdmflexframegen q = (ofdmflexframegen) malloc(sizeof(struct ofdmflexframegen_s)); q->M = _M; // number of subcarriers diff --git a/src/framing/src/ofdmflexframesync.c b/src/framing/src/ofdmflexframesync.c index a18165eed..44f9fcedc 100644 --- a/src/framing/src/ofdmflexframesync.c +++ b/src/framing/src/ofdmflexframesync.c @@ -152,7 +152,7 @@ ofdmflexframesync ofdmflexframesync_create(unsigned int _M, // validate input if (_M < 8) - return liquid_error_config("ofdmflexframesync_create(), less than 8 subcarriers"); + return liquid_error_config("ofdmflexframesync_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmflexframesync_create(), number of subcarriers must be even"); if (_cp_len > _M) diff --git a/src/framing/tests/ofdmflexframe_autotest.c b/src/framing/tests/ofdmflexframe_autotest.c index cf24e6bac..814ab0b29 100644 --- a/src/framing/tests/ofdmflexframe_autotest.c +++ b/src/framing/tests/ofdmflexframe_autotest.c @@ -90,10 +90,34 @@ void autotest_ofdmflexframe_07() { testbench_ofdmflexframe(1200, 40, 20, 1, L void autotest_ofdmflexframe_08() { testbench_ofdmflexframe(1200, 0, 0, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_09() { testbench_ofdmflexframe(1200, 40, 20, 8217, LIQUID_MODEM_QPSK); } -void autotest_ofdmflexframe_config() +void autotest_ofdmflexframegen_config() { #if LIQUID_STRICT_EXIT - AUTOTEST_WARN("skipping ofdmflexframe config test with strict exit enabled\n"); + AUTOTEST_WARN("skipping ofdmflexframegen config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + //CONTEND_ISNULL(ofdmflexframegen_copy(NULL)); + CONTEND_ISNULL(ofdmflexframegen_create( 0, 16, 4, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmflexframegen_create( 7, 16, 4, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmflexframegen_create(65, 16, 4, NULL, NULL)) // odd-length subcarriers + CONTEND_ISNULL(ofdmflexframegen_create(64, 66, 4, NULL, NULL)) // cyclic prefix length too large + + // create proper object and test configurations + ofdmflexframegen q = ofdmflexframegen_create(64, 16, 4, NULL, NULL); + + CONTEND_EQUALITY(LIQUID_OK, ofdmflexframegen_print(q)) + + ofdmflexframegen_destroy(q); +} + +void autotest_ofdmflexframesync_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmflexframesync config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT From 21ca9473ce009e2ef7eb73f2b11686117b8ffe10 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 27 Feb 2023 18:27:38 -0500 Subject: [PATCH 085/334] ofdmframe/autotest: adding configuration tests --- makefile.in | 2 +- ...mesync_autotest.c => ofdmframe_autotest.c} | 53 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) rename src/multichannel/tests/{ofdmframesync_autotest.c => ofdmframe_autotest.c} (69%) diff --git a/makefile.in b/makefile.in index 71e5b16f1..7e415d7c1 100644 --- a/makefile.in +++ b/makefile.in @@ -949,7 +949,7 @@ multichannel_autotests := \ src/multichannel/tests/firpfbch2_crcf_autotest.c \ src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c \ src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c \ - src/multichannel/tests/ofdmframesync_autotest.c \ + src/multichannel/tests/ofdmframe_autotest.c \ # benchmarks multichannel_benchmarks := \ diff --git a/src/multichannel/tests/ofdmframesync_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c similarity index 69% rename from src/multichannel/tests/ofdmframesync_autotest.c rename to src/multichannel/tests/ofdmframe_autotest.c index 4d43d72a0..b949a8ece 100644 --- a/src/multichannel/tests/ofdmframesync_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2019 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,8 @@ int ofdmframesync_autotest_callback(float complex * _X, unsigned int _M, void * _userdata) { - printf("******** callback invoked!\n"); + if (liquid_autotest_verbose) + printf("******** callback invoked!\n"); // type cast _userdata as complex float array float complex * X = (float complex *)_userdata; @@ -143,3 +144,51 @@ void autotest_ofdmframesync_acquire_n128() { ofdmframesync_acquire_test(128, 16 void autotest_ofdmframesync_acquire_n256() { ofdmframesync_acquire_test(256, 32, 0); } void autotest_ofdmframesync_acquire_n512() { ofdmframesync_acquire_test(512, 64, 0); } +void autotest_ofdmframegen_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmframegen config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + //CONTEND_ISNULL(ofdmframegen_copy(NULL)); + CONTEND_ISNULL(ofdmframegen_create( 0, 16, 4, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmframegen_create( 7, 16, 4, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmframegen_create(65, 16, 4, NULL)) // odd-length subcarriers + CONTEND_ISNULL(ofdmframegen_create(64, 66, 4, NULL)) // cyclic prefix length too large + + // create proper object and test configurations + ofdmframegen q = ofdmframegen_create(64, 16, 4, NULL); + + CONTEND_EQUALITY(LIQUID_OK, ofdmframegen_print(q)) + + ofdmframegen_destroy(q); +} + +void autotest_ofdmframesync_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmframesync config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + //CONTEND_ISNULL(ofdmframesync_copy(NULL)); + CONTEND_ISNULL(ofdmframesync_create( 0, 16, 4, NULL, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmframesync_create( 7, 16, 4, NULL, NULL, NULL)) // too few subcarriers + CONTEND_ISNULL(ofdmframesync_create(65, 16, 4, NULL, NULL, NULL)) // odd-length subcarriers + CONTEND_ISNULL(ofdmframesync_create(64, 66, 4, NULL, NULL, NULL)) // cyclic prefix length too large + + // create proper object and test configurations + ofdmframesync q = ofdmframesync_create(64, 16, 4, NULL, NULL, NULL); + + CONTEND_EQUALITY(LIQUID_OK, ofdmframesync_print(q)) + + ofdmframesync_destroy(q); +} + From 503c232b873e37b5508ae4359de1b33484b0626e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 28 Feb 2023 17:42:24 -0500 Subject: [PATCH 086/334] ofdmframe: moving subcarrier verification check inside common function --- src/multichannel/src/ofdmframe.common.c | 8 ++++++++ src/multichannel/src/ofdmframegen.c | 10 ++-------- src/multichannel/src/ofdmframesync.c | 12 ++++-------- src/multichannel/tests/ofdmframe_autotest.c | 2 ++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/multichannel/src/ofdmframe.common.c b/src/multichannel/src/ofdmframe.common.c index cc30554c2..2d612eb15 100644 --- a/src/multichannel/src/ofdmframe.common.c +++ b/src/multichannel/src/ofdmframe.common.c @@ -294,6 +294,14 @@ int ofdmframe_validate_sctype(unsigned char * _p, } } + // validate subcarrier allocation + if ( (M_pilot + M_data) == 0) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one enabled subcarrier"); + if (M_data == 0) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one data subcarrier"); + if (M_pilot < 2) + return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least two pilot subcarriers"); + // set outputs *_M_null = M_null; *_M_pilot = M_pilot; diff --git a/src/multichannel/src/ofdmframegen.c b/src/multichannel/src/ofdmframegen.c index 8553ef538..e45719898 100644 --- a/src/multichannel/src/ofdmframegen.c +++ b/src/multichannel/src/ofdmframegen.c @@ -84,8 +84,8 @@ ofdmframegen ofdmframegen_create(unsigned int _M, unsigned char * _p) { // validate input - if (_M < 2) - return liquid_error_config("ofdmframegen_create(), number of subcarriers must be at least 2"); + if (_M < 8) + return liquid_error_config("ofdmframegen_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframegen_create(), number of subcarriers must be even"); if (_cp_len > _M) @@ -111,12 +111,6 @@ ofdmframegen ofdmframegen_create(unsigned int _M, // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframegen_create(), invalid subcarrier allocation"); - if ( (q->M_pilot + q->M_data) == 0) - return liquid_error_config("ofdmframegen_create(), must have at least one enabled subcarrier"); - if (q->M_data == 0) - return liquid_error_config("ofdmframegen_create(), must have at least one data subcarriers"); - if (q->M_pilot < 2) - return liquid_error_config("ofdmframegen_create(), must have at least two pilot subcarriers"); unsigned int i; diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 0e7ce5448..f69e35e6e 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -149,11 +149,13 @@ ofdmframesync ofdmframesync_create(unsigned int _M, // validate input if (_M < 8) - return liquid_error_config("ofdmframesync_create(), less than 8 subcarriers"); + return liquid_error_config("ofdmframesync_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframesync_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers"); + if (_taper_len > _cp_len) + return liquid_error_config("ofdmframesync_create(), taper length cannot exceed cyclic prefix"); q->M = _M; q->cp_len = _cp_len; @@ -172,12 +174,6 @@ ofdmframesync ofdmframesync_create(unsigned int _M, // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframesync_create(), invalid subcarrier allocation"); - if ( (q->M_pilot + q->M_data) == 0) - return liquid_error_config("ofdmframesync_create(), must have at least one enabled subcarrier"); - if (q->M_data == 0) - return liquid_error_config("ofdmframesync_create(), must have at least one data subcarriers"); - if (q->M_pilot < 2) - return liquid_error_config("ofdmframesync_create(), must have at least two pilot subcarriers"); // create transform object q->X = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index b949a8ece..1b1643888 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -159,6 +159,7 @@ void autotest_ofdmframegen_config() CONTEND_ISNULL(ofdmframegen_create( 7, 16, 4, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmframegen_create(65, 16, 4, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmframegen_create(64, 66, 4, NULL)) // cyclic prefix length too large + CONTEND_ISNULL(ofdmframegen_create(64, 16,24, NULL)) // taper length greater than cyclic prefix // create proper object and test configurations ofdmframegen q = ofdmframegen_create(64, 16, 4, NULL); @@ -183,6 +184,7 @@ void autotest_ofdmframesync_config() CONTEND_ISNULL(ofdmframesync_create( 7, 16, 4, NULL, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmframesync_create(65, 16, 4, NULL, NULL, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmframesync_create(64, 66, 4, NULL, NULL, NULL)) // cyclic prefix length too large + CONTEND_ISNULL(ofdmframesync_create(64, 16,24, NULL, NULL, NULL)) // taper length greater than cyclic prefix // create proper object and test configurations ofdmframesync q = ofdmframesync_create(64, 16, 4, NULL, NULL, NULL); From aeef3bf1f69c638f3b42f77094028f518232e2d9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:08:47 -0500 Subject: [PATCH 087/334] ofdmframesync: using internal method to unwrap phase --- src/multichannel/src/ofdmframesync.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index f69e35e6e..2a482cd1b 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -951,12 +951,7 @@ int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase - for (i=1; i M_PI) - y_arg[i] -= 2*M_PI; - while ((y_arg[i] - y_arg[i-1]) < -M_PI) - y_arg[i] += 2*M_PI; - } + liquid_unwrap_phase(y_arg, N); // fit to polynomial polyf_fit(x_freq, y_abs, N, p_abs, _order+1); @@ -1032,12 +1027,7 @@ int ofdmframesync_rxsymbol(ofdmframesync _q) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase - for (i=1; i<_q->M_pilot; i++) { - while ((y_phase[i] - y_phase[i-1]) > M_PI) - y_phase[i] -= 2*M_PI; - while ((y_phase[i] - y_phase[i-1]) < -M_PI) - y_phase[i] += 2*M_PI; - } + liquid_unwrap_phase(y_phase, _q->M_pilot); // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(x_phase, y_phase, _q->M_pilot, p_phase, 2); From 5d84fa9797b0952104c152da6abb13f1d17ff85b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:12:27 -0500 Subject: [PATCH 088/334] ofdmframesync: adding additional configuration tests --- src/multichannel/src/ofdmframesync.c | 3 +-- src/multichannel/tests/ofdmframe_autotest.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 2a482cd1b..3fcf1d953 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -413,8 +413,7 @@ float ofdmframesync_get_cfo(ofdmframesync _q) // set receiver carrier frequency offset estimate int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo) { - nco_crcf_set_frequency(_q->nco_rx, _cfo); - return LIQUID_OK; + return nco_crcf_set_frequency(_q->nco_rx, _cfo); } // diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index 1b1643888..2ca3ab93c 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -190,6 +190,8 @@ void autotest_ofdmframesync_config() ofdmframesync q = ofdmframesync_create(64, 16, 4, NULL, NULL, NULL); CONTEND_EQUALITY(LIQUID_OK, ofdmframesync_print(q)) + CONTEND_EQUALITY( 0, ofdmframesync_is_frame_open(q)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframesync_set_cfo(q,0.0f)) ofdmframesync_destroy(q); } From f4b5b338fbc32f9bb3470e01c670fc76a5a64df2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 18:17:09 -0500 Subject: [PATCH 089/334] ofdmframesync: moving internal funciton declarations from header --- include/liquid.internal.h | 45 ------------------------- src/multichannel/src/ofdmframesync.c | 49 +++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index e8e2e0d90..e5f32f0a8 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1486,51 +1486,6 @@ int ofdmframe_init_S1(unsigned char * _p, int ofdmframegen_gensymbol(ofdmframegen _q, float complex * _buffer); -int ofdmframesync_cpcorrelate(ofdmframesync _q); -int ofdmframesync_findrxypeak(ofdmframesync _q); -int ofdmframesync_rxpayload(ofdmframesync _q); - -int ofdmframesync_execute_seekplcp(ofdmframesync _q); -int ofdmframesync_execute_S0a(ofdmframesync _q); -int ofdmframesync_execute_S0b(ofdmframesync _q); -int ofdmframesync_execute_S1( ofdmframesync _q); -int ofdmframesync_execute_rxsymbols(ofdmframesync _q); - -int ofdmframesync_S0_metrics(ofdmframesync _q, - float complex * _G, - float complex * _s_hat); - -// estimate short sequence gain -// _q : ofdmframesync object -// _x : input array (time) -// _G : output gain (freq) -int ofdmframesync_estimate_gain_S0(ofdmframesync _q, - float complex * _x, - float complex * _G); - -// estimate long sequence gain -// _q : ofdmframesync object -// _x : input array (time) -// _G : output gain (freq) -int ofdmframesync_estimate_gain_S1(ofdmframesync _q, - float complex * _x, - float complex * _G); - -// estimate complex equalizer gain from G0 and G1 -// _q : ofdmframesync object -// _ntaps : number of time-domain taps for smoothing -int ofdmframesync_estimate_eqgain(ofdmframesync _q, - unsigned int _ntaps); - -// estimate complex equalizer gain from G0 and G1 using polynomial fit -// _q : ofdmframesync object -// _order : polynomial order -int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, - unsigned int _order); - -// recover symbol, correcting for gain, pilot phase, etc. -int ofdmframesync_rxsymbol(ofdmframesync _q); - // // MODULE : nco (numerically-controlled oscillator) // diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 3fcf1d953..a1e2f5ecf 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// ofdmframesync.c -// // OFDM frame synchronizer -// #include #include @@ -41,6 +37,49 @@ #define OFDMFRAMESYNC_ENABLE_SQUELCH 0 +// forward declaration of internal methods + +int ofdmframesync_execute_seekplcp(ofdmframesync _q); +int ofdmframesync_execute_S0a(ofdmframesync _q); +int ofdmframesync_execute_S0b(ofdmframesync _q); +int ofdmframesync_execute_S1( ofdmframesync _q); +int ofdmframesync_execute_rxsymbols(ofdmframesync _q); + +int ofdmframesync_S0_metrics(ofdmframesync _q, + float complex * _G, + float complex * _s_hat); + +// estimate short sequence gain +// _q : ofdmframesync object +// _x : input array (time) +// _G : output gain (freq) +int ofdmframesync_estimate_gain_S0(ofdmframesync _q, + float complex * _x, + float complex * _G); + +// estimate long sequence gain +// _q : ofdmframesync object +// _x : input array (time) +// _G : output gain (freq) +int ofdmframesync_estimate_gain_S1(ofdmframesync _q, + float complex * _x, + float complex * _G); + +// estimate complex equalizer gain from G0 and G1 +// _q : ofdmframesync object +// _ntaps : number of time-domain taps for smoothing +int ofdmframesync_estimate_eqgain(ofdmframesync _q, + unsigned int _ntaps); + +// estimate complex equalizer gain from G0 and G1 using polynomial fit +// _q : ofdmframesync object +// _order : polynomial order +int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, + unsigned int _order); + +// recover symbol, correcting for gain, pilot phase, etc. +int ofdmframesync_rxsymbol(ofdmframesync _q); + struct ofdmframesync_s { unsigned int M; // number of subcarriers unsigned int M2; // number of subcarriers (divided by 2) @@ -752,7 +791,7 @@ int ofdmframesync_execute_rxsymbols(ofdmframesync _q) } // compute S0 metrics -int ofdmframesync_S0_metrics(ofdmframesync _q, +int ofdmframesync_S0_metrics(ofdmframesync _q, float complex * _G, float complex * _s_hat) { From 9f97bee94f6aaf8d9a0cdf770f64c3ff4ff30584 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:40:51 -0500 Subject: [PATCH 090/334] ofdmframesync: disabling debugging (preprocessor) --- src/multichannel/src/ofdmframesync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index a1e2f5ecf..bd88ff947 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -30,7 +30,7 @@ #include "liquid.internal.h" -#define DEBUG_OFDMFRAMESYNC 1 +#define DEBUG_OFDMFRAMESYNC 0 #define DEBUG_OFDMFRAMESYNC_PRINT 0 #define DEBUG_OFDMFRAMESYNC_FILENAME "ofdmframesync_internal_debug.m" #define DEBUG_OFDMFRAMESYNC_BUFFER_LEN (2048) From 8ef84a93f56d3236d1140ce84963f9969c72211e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:46:53 -0500 Subject: [PATCH 091/334] ofdmframesync: block-commenting unused method for estimating equalizer gain --- src/multichannel/src/ofdmframesync.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index bd88ff947..8a05e20b1 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -68,8 +68,7 @@ int ofdmframesync_estimate_gain_S1(ofdmframesync _q, // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing -int ofdmframesync_estimate_eqgain(ofdmframesync _q, - unsigned int _ntaps); +//int ofdmframesync_estimate_eqgain(ofdmframesync _q, unsigned int _ntaps); // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object @@ -879,6 +878,7 @@ int ofdmframesync_estimate_gain_S1(ofdmframesync _q, return LIQUID_OK; } +#if 0 // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing @@ -939,6 +939,7 @@ int ofdmframesync_estimate_eqgain(ofdmframesync _q, } return LIQUID_OK; } +#endif // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object From d70516f140c6d41d66b6a62a9b672858b184a1ab Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 20:51:15 -0500 Subject: [PATCH 092/334] ofdmframegen: moving internal method declarations from header --- include/liquid.internal.h | 6 +----- src/multichannel/src/ofdmframegen.c | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index e5f32f0a8..d38648460 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1482,10 +1482,6 @@ int ofdmframe_init_S1(unsigned char * _p, float complex * _s1, unsigned int * _M_S1); -// generate symbol (add cyclic prefix/postfix, overlap) -int ofdmframegen_gensymbol(ofdmframegen _q, - float complex * _buffer); - // // MODULE : nco (numerically-controlled oscillator) // diff --git a/src/multichannel/src/ofdmframegen.c b/src/multichannel/src/ofdmframegen.c index e45719898..150cb8532 100644 --- a/src/multichannel/src/ofdmframegen.c +++ b/src/multichannel/src/ofdmframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,10 @@ #define DEBUG_OFDMFRAMEGEN 1 +// generate symbol (add cyclic prefix/postfix, overlap) +int ofdmframegen_gensymbol(ofdmframegen _q, + float complex * _buffer); + struct ofdmframegen_s { unsigned int M; // number of subcarriers unsigned int cp_len; // cyclic prefix length From 83d67ac1adf21e4074ef24b357a16601df660fe3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 1 Mar 2023 21:03:24 -0500 Subject: [PATCH 093/334] firpfbch2/autotest: adding configuration testing --- .../tests/firpfbch2_crcf_autotest.c | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/multichannel/tests/firpfbch2_crcf_autotest.c b/src/multichannel/tests/firpfbch2_crcf_autotest.c index c00a728b5..9c5f135ec 100644 --- a/src/multichannel/tests/firpfbch2_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch2_crcf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -97,7 +97,6 @@ void autotest_firpfbch2_crcf_n16() { firpfbch2_crcf_runtest( 16, 5, 60.0f); } void autotest_firpfbch2_crcf_n32() { firpfbch2_crcf_runtest( 32, 5, 60.0f); } void autotest_firpfbch2_crcf_n64() { firpfbch2_crcf_runtest( 64, 5, 60.0f); } - void autotest_firpfbch2_crcf_copy() { // create channelizer @@ -140,3 +139,36 @@ void autotest_firpfbch2_crcf_copy() firpfbch2_crcf_destroy(q_copy); } +void autotest_firpfbch2_crcf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firpfbch2_crcf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(firpfbch2_crcf_create( 77, 76, 12, NULL)) // invalid type + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 17, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser( 77, 76, 12, 60.0f)) // invalid type + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 0, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 17, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 76, 0, 60.0f)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch2_crcf_copy(NULL)) + + // create proper object and test configurations + firpfbch2_crcf q = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, 76, 12, 60.0f); + + CONTEND_EQUALITY(LIQUID_OK, firpfbch2_crcf_print(q)) + CONTEND_EQUALITY(LIQUID_ANALYZER, firpfbch2_crcf_get_type(q)) + CONTEND_EQUALITY( 76, firpfbch2_crcf_get_M(q)) + CONTEND_EQUALITY( 12, firpfbch2_crcf_get_m(q)) + + firpfbch2_crcf_destroy(q); +} + From 68983c26a300e7229d187ea10e1a87fbb7e812be Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 3 Mar 2023 08:21:20 -0500 Subject: [PATCH 094/334] firpfbch: adding configuration testing --- makefile.in | 1 + .../tests/firpfbch_crcf_autotest.c | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/multichannel/tests/firpfbch_crcf_autotest.c diff --git a/makefile.in b/makefile.in index 7e415d7c1..3c0246d9b 100644 --- a/makefile.in +++ b/makefile.in @@ -949,6 +949,7 @@ multichannel_autotests := \ src/multichannel/tests/firpfbch2_crcf_autotest.c \ src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c \ src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c \ + src/multichannel/tests/firpfbch_crcf_autotest.c \ src/multichannel/tests/ofdmframe_autotest.c \ # benchmarks diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c new file mode 100644 index 000000000..fb9deb967 --- /dev/null +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "autotest/autotest.h" +#include "liquid.h" + +void autotest_firpfbch_crcf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firpfbch_crcf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_ISNULL(firpfbch_crcf_create( 77, 76, 12, NULL)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + + //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) + + // create proper object and test configurations + firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 12, 60.0f); + + CONTEND_EQUALITY(LIQUID_OK, firpfbch_crcf_print(q)) + + firpfbch_crcf_destroy(q); +} + From 158a0252aefeb43e646cd1f05d4809f7ffbf85c3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 07:48:33 -0500 Subject: [PATCH 095/334] firpfbch/autotest: adding more configuration tests --- src/multichannel/src/firpfbch.proto.c | 14 ++++++-------- src/multichannel/tests/firpfbch_crcf_autotest.c | 8 ++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 28826a2b5..1f147e795 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// firpfbch.c -// -// finite impulse response polyphase filterbank channelizer -// +// firpfbch : finite impulse response polyphase filterbank channelizer #include #include @@ -77,7 +73,7 @@ FIRPFBCH() FIRPFBCH(_create)(int _type, { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) - return liquid_error_config("firpfbch_%s_create(), invalid type %d", EXTENSION_FULL, _type); + return liquid_error_config("firpfbch_%s_create(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create(), number of channels must be greater than 0", EXTENSION_FULL); if (_p == 0) @@ -148,6 +144,8 @@ FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, float _as) { // validate input + if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) + return liquid_error_config("firpfbch_%s_create_kaiser(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create_kaiser(), number of channels must be greater than 0", EXTENSION_FULL); if (_m == 0) @@ -190,7 +188,7 @@ FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) - return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid type %d", EXTENSION_FULL, _type); + return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create_rnyquist(), number of channels must be greater than 0", EXTENSION_FULL); if (_m == 0) diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c index fb9deb967..55204b882 100644 --- a/src/multichannel/tests/firpfbch_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -38,6 +38,14 @@ void autotest_firpfbch_crcf_config() CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length + CONTEND_ISNULL(firpfbch_crcf_create_kaiser( 77, 76, 12, 60.0f)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 0, 12, 60.0f)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 0, 60.0f)) // invalid filter semi-length + + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist( 77, 76, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid type + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 0, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid number of channels + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 0, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid filter semi-length + //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) // create proper object and test configurations From 40fab43ccb045b76f67b704c708ac1637ac455f7 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 08:10:57 -0500 Subject: [PATCH 096/334] firpfbch: using prototype filter generation for create_rnyquist() --- src/multichannel/src/firpfbch.proto.c | 22 ++----------------- .../tests/firpfbch_crcf_autotest.c | 2 ++ 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 1f147e795..0683c3a1a 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -197,26 +197,8 @@ FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, // design filter based on requested prototype unsigned int h_len = 2*_M*_m + 1; float h[h_len]; - switch (_ftype) { - case LIQUID_FIRFILT_ARKAISER: - // root-Nyquist Kaiser (approximate optimum) - liquid_firdes_arkaiser(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_RKAISER: - // root-Nyquist Kaiser (true optimum) - liquid_firdes_rkaiser(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_RRC: - // root raised-cosine - liquid_firdes_rrcos(_M, _m, _beta, 0.0f, h); - break; - case LIQUID_FIRFILT_hM3: - // harris-Moerder-3 filter - liquid_firdes_hM3(_M, _m, _beta, 0.0f, h); - break; - default: - return liquid_error_config("firpfbch_%s_create_rnyquist(), unknown/invalid prototype (%d)", EXTENSION_FULL, _ftype); - } + if (liquid_firdes_prototype(_ftype, _M, _m, _beta, 0.0f, h) != LIQUID_OK) + return liquid_error_config("firpfbch_%s_create_rnyquist(), invalid filter type/configuration", EXTENSION_FULL); // copy coefficients to type-specfic array, reversing order if // channelizer is an analyzer, matched filter: g(-t) diff --git a/src/multichannel/tests/firpfbch_crcf_autotest.c b/src/multichannel/tests/firpfbch_crcf_autotest.c index 55204b882..7ada5fd56 100644 --- a/src/multichannel/tests/firpfbch_crcf_autotest.c +++ b/src/multichannel/tests/firpfbch_crcf_autotest.c @@ -45,6 +45,8 @@ void autotest_firpfbch_crcf_config() CONTEND_ISNULL(firpfbch_crcf_create_rnyquist( 77, 76, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid type CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 0, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 0, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid filter semi-length + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 77.f, LIQUID_FIRFILT_ARKAISER)) // invalid filter excess bandwidth + CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 0.2f, LIQUID_FIRFILT_UNKNOWN )) // invalid filter type //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) From 8c7cc6009fa0127f816185ded3503904c7842c84 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 08:38:20 -0500 Subject: [PATCH 097/334] ofdmframe/autotest: including configuration tests for common functions --- src/multichannel/src/ofdmframe.common.c | 8 +++--- src/multichannel/tests/ofdmframe_autotest.c | 32 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/multichannel/src/ofdmframe.common.c b/src/multichannel/src/ofdmframe.common.c index 2d612eb15..ab7e4d5b1 100644 --- a/src/multichannel/src/ofdmframe.common.c +++ b/src/multichannel/src/ofdmframe.common.c @@ -302,10 +302,10 @@ int ofdmframe_validate_sctype(unsigned char * _p, if (M_pilot < 2) return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least two pilot subcarriers"); - // set outputs - *_M_null = M_null; - *_M_pilot = M_pilot; - *_M_data = M_data; + // set outputs if requested + if (_M_null != NULL) *_M_null = M_null; + if (_M_pilot != NULL) *_M_pilot = M_pilot; + if (_M_data != NULL) *_M_data = M_data; return LIQUID_OK; } diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index 2ca3ab93c..bcb369d45 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -144,6 +144,38 @@ void autotest_ofdmframesync_acquire_n128() { ofdmframesync_acquire_test(128, 16 void autotest_ofdmframesync_acquire_n256() { ofdmframesync_acquire_test(256, 32, 0); } void autotest_ofdmframesync_acquire_n512() { ofdmframesync_acquire_test(512, 64, 0); } +void autotest_ofdmframe_common_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping ofdmframe common config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid function calls + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_default_sctype(0, NULL)) // too few subcarriers + + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range( 0, -0.4f, +0.4f, NULL)) // too few subcarriers + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.7f, +0.4f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.4f, +0.7f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.2f, -0.3f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, 0.3f, 0.2f, NULL)) // frequency out of range + CONTEND_INEQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(64, -0.02f,+0.02f,NULL)) // too few effective subcarriers + + // generate valid subcarrier allocation + unsigned int M = 120; + unsigned char p[M]; + + // default subcarrier allocation + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_default_sctype(M, p)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) + + // subcarrier allocation within an occupied frequency range + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(M, -0.4f,+0.4f,p)) + CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) +} + void autotest_ofdmframegen_config() { #if LIQUID_STRICT_EXIT From 60afb3c2ef6f0f9a2c7421a427b14bbc7f87c127 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 4 Mar 2023 09:01:21 -0500 Subject: [PATCH 098/334] ofdmframe/autotest: testing edge cases for subcarrier allocations --- src/multichannel/tests/ofdmframe_autotest.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/multichannel/tests/ofdmframe_autotest.c b/src/multichannel/tests/ofdmframe_autotest.c index bcb369d45..2e0aed52e 100644 --- a/src/multichannel/tests/ofdmframe_autotest.c +++ b/src/multichannel/tests/ofdmframe_autotest.c @@ -174,6 +174,18 @@ void autotest_ofdmframe_common_config() // subcarrier allocation within an occupied frequency range CONTEND_EQUALITY(LIQUID_OK, ofdmframe_init_sctype_range(M, -0.4f,+0.4f,p)) CONTEND_EQUALITY(LIQUID_OK, ofdmframe_validate_sctype(p, M, NULL, NULL, NULL)) + + // invalid subcarrier allocations + unsigned int i; + for (i=0; i Date: Sat, 11 Mar 2023 07:15:02 -0500 Subject: [PATCH 099/334] qpacketmodem/example: adjusting number of trials based on error performance --- examples/qpacketmodem_performance_example.c | 181 ++++++++------------ 1 file changed, 76 insertions(+), 105 deletions(-) diff --git a/examples/qpacketmodem_performance_example.c b/examples/qpacketmodem_performance_example.c index 300c516f3..607d36ab9 100644 --- a/examples/qpacketmodem_performance_example.c +++ b/examples/qpacketmodem_performance_example.c @@ -1,11 +1,6 @@ -// -// qpacketmodem_performance_example.c -// // This example demonstrates the performance of the qpacket modem // object to combine forward error-correction and modulation in one // simple interface. -// - #include #include #include @@ -21,39 +16,41 @@ void usage() { printf("qpacketmodem_performance_example [options]\n"); - printf(" h : print usage\n"); - printf(" p : payload length [bytes], default: 400\n"); - printf(" m : modulation scheme (qpsk default)\n"); + printf(" -h : print usage\n"); + printf(" -p : payload length [bytes], default: 400\n"); + printf(" -m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); - printf(" v : data integrity check: crc32 default\n"); + printf(" -v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); - printf(" c : coding scheme (inner): g2412 default\n"); - printf(" k : coding scheme (outer): none default\n"); + printf(" -c : coding scheme (inner): g2412 default\n"); + printf(" -k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); - printf(" s : SNR start [dB], default: -2\n"); - printf(" x : SNR max [dB], default: 13\n"); - printf(" n : number of SNR steps, default: 16\n"); - printf(" t : number of trials, default: 800\n"); + printf(" -s : SNR start [dB], default: -5\n"); + printf(" -x : SNR max [dB], default: 20\n"); + printf(" -d : SNR step [dB], default: 0.5\n"); + printf(" -e : minimum number of packet errors per step, default: 50\n"); + printf(" -t : minimum number of packet trials per step, default: 2000\n"); + printf(" -T : maximum number of packet trials per step, default: 40000\n"); } int main(int argc, char *argv[]) { - //srand( time(NULL) ); - - // options + // options (defaults to frame64 parameters) modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme - crc_scheme check = LIQUID_CRC_32; // data validity check - fec_scheme fec0 = LIQUID_FEC_GOLAY2412; // fec (inner) - fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) - unsigned int payload_len = 400; // payload length + crc_scheme check = LIQUID_CRC_24; // data validity check + fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) + fec_scheme fec1 = LIQUID_FEC_GOLAY2412; // fec (outer) + unsigned int payload_len = 72; // payload length float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) - float SNRdB_max = 10.0f; // signal-to-noise ratio (maximum) - unsigned int num_snr = 31; // number of SNR steps - unsigned int num_packet_trials = 800; // number of trials + float SNRdB_max = 20.0f; // signal-to-noise ratio (maximum) + float SNRdB_step = 0.5f; // signal-to-noise ratio (maximum) + unsigned int min_packet_errors = 50; // minimum errors to observe for each step + unsigned int min_packet_trials = 2000; // minimum number of packets for each step + unsigned int max_packet_trials =40000; // maximum number of packets for each step // get options int dopt; - while((dopt = getopt(argc,argv,"hp:m:v:c:k:s:x:n:t:")) != EOF){ + while((dopt = getopt(argc,argv,"hp:m:v:c:k:s:x:d:e:t:T:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'p': payload_len = atol(optarg); break; @@ -63,18 +60,16 @@ int main(int argc, char *argv[]) case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; - case 'n': num_snr = atoi(optarg); break; - case 't': num_packet_trials = atoi(optarg); break; + case 'd': SNRdB_step = atof(optarg); break; + case 'e': min_packet_errors = atoi(optarg); break; + case 't': min_packet_trials = atoi(optarg); break; + case 'T': max_packet_trials = atoi(optarg); break; default: exit(-1); } } - unsigned int i; - // derived values - float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); - // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, payload_len, check, fec0, fec1, ms); @@ -82,32 +77,27 @@ int main(int argc, char *argv[]) // get frame length unsigned int frame_len = qpacketmodem_get_frame_len(q); - unsigned int num_bit_trials = 8*num_packet_trials*payload_len; // initialize payload unsigned char payload_tx [payload_len]; // payload (transmitted) unsigned char payload_rx [payload_len]; // payload (received) float complex frame_tx [frame_len]; // frame samples (transmitted) float complex frame_rx [frame_len]; // frame samples (received) - unsigned int num_bit_errors [num_snr]; // bit errors for each SNR point - unsigned int num_packet_errors[num_snr]; // packet errors for each SNR point - float BER [num_snr]; // bit error rate - float PER [num_snr]; // packet error rate + + // output file + FILE* fid = fopen(OUTPUT_FILENAME, "w"); + fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all; close all; SNR=[]; ber=[]; per=[];\n"); printf(" %8s %8s %8s %12s %8s %8s %6s\n", "SNR [dB]", "errors", "bits", "BER", "errors", "packets", "PER"); - unsigned int s; - for (s=0; s= min_packet_errors) + break; + if (num_packet_trials >= max_packet_trials) + break; } - BER[s] = (float)num_bit_errors[s] / (float)num_bit_trials; - PER[s] = (float)num_packet_errors[s] / (float)num_packet_trials; + float BER = (float)num_bit_errors / (float)num_bit_trials; + float PER = (float)num_packet_errors / (float)num_packet_trials; printf(" %8.2f %8u %8u %12.4e %8u %8u %6.2f%%\n", SNRdB, - num_bit_errors[s], num_bit_trials, BER[s], - num_packet_errors[s], num_packet_trials, PER[s]*100.0f); + num_bit_errors, num_bit_trials, BER, + num_packet_errors, num_packet_trials, PER*100.0f); + fprintf(fid,"SNR(end+1)=%g; ber(end+1)=%g; per(end+1)=%g;\n", SNRdB, BER, PER); + if (num_packet_errors < min_packet_errors) + break; + SNRdB += SNRdB_step; } // destroy allocated objects qpacketmodem_destroy(q); - // - // export output file - // - FILE * fid = fopen(OUTPUT_FILENAME, "w"); - fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); - fprintf(fid,"\n\n"); - fprintf(fid,"clear all\n"); - fprintf(fid,"close all\n"); - fprintf(fid,"payload_len = %u; %% payload length [bytes]\n", payload_len); - fprintf(fid,"frame_len = %u; %% frame length [symbols]\n", frame_len); - fprintf(fid,"num_snr = %u;\n", num_snr); - fprintf(fid,"num_packet_trials = %u;\n", num_packet_trials); - fprintf(fid,"num_bit_trials = %u;\n", num_bit_trials); - fprintf(fid,"SNRdB_min = %8.2f;\n", SNRdB_min); - fprintf(fid,"SNRdB_max = %8.2f;\n", SNRdB_max); - fprintf(fid,"scheme = '%s/%s/%s';\n", - fec_scheme_str[fec0][1], - fec_scheme_str[fec1][1], - modulation_types[ms].name); - fprintf(fid,"rate = 8*payload_len / frame_len; %% true rate [bits/symbol]\n"); - for (i=0; i Date: Sat, 11 Mar 2023 08:33:53 -0500 Subject: [PATCH 100/334] setting noise correctly in framesync64 performance example --- examples/framesync64_performance_example.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/framesync64_performance_example.c b/examples/framesync64_performance_example.c index fc43291c3..c50234f36 100644 --- a/examples/framesync64_performance_example.c +++ b/examples/framesync64_performance_example.c @@ -10,10 +10,11 @@ // add noise to channel void frame64_add_noise(float complex * _buf, float _SNRdB) { - float nstd = powf(10.0f, -_SNRdB/20.0f) * M_SQRT1_2; + float nstd = powf(10.0f, -_SNRdB/20.0f); + nstd *= M_SQRT2; // scale noise to account for signal being over-sampled by 2 unsigned int i; for (i=0; i Date: Sat, 11 Mar 2023 08:37:23 -0500 Subject: [PATCH 101/334] framesync64: adding interpolated SNR estimate for target PER --- examples/framesync64_performance_example.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/framesync64_performance_example.c b/examples/framesync64_performance_example.c index c50234f36..7242ca563 100644 --- a/examples/framesync64_performance_example.c +++ b/examples/framesync64_performance_example.c @@ -25,15 +25,18 @@ int main(int argc, char*argv[]) unsigned int min_errors = 50; unsigned int min_trials = 500; unsigned int max_trials = 5000; + float per_target = 1e-2f; // create buffer for the frame samples float complex frame[LIQUID_FRAME64_LEN]; - float SNRdB = -6.0f; + float SNRdB = -3.0f; + float per_0 =-1.0f, per_1 = -1.0f; + float snr_0 = 0.0f, snr_1 = 0.0f; FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); - printf("# %8s %6s %6s %6s\n", "SNR", "detect", "valid", "trials"); + printf("# %8s %6s %6s %6s %12s\n", "SNR", "detect", "valid", "trials", "PER"); while (SNRdB < 10.0f) { framesync64_reset_framedatastats(fs); unsigned int num_trials = 0, num_errors = 0; @@ -61,8 +64,11 @@ int main(int argc, char*argv[]) } // print results framedatastats_s stats = framesync64_get_framedatastats(fs); - printf(" %8.3f %6u %6u %6u\n", - SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials); + float per = (float)(num_trials - stats.num_payloads_valid)/(float)num_trials; + if (per >= per_target) { per_0 = per; snr_0 = SNRdB; } + else if (per_1 < 0.0f ) { per_1 = per; snr_1 = SNRdB; } + printf(" %8.3f %6u %6u %6u %12.4e\n", + SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials,per); fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%g; pvalid(end+1)=%g;\n", SNRdB, (float)stats.num_frames_detected / (float)num_trials, @@ -71,6 +77,10 @@ int main(int argc, char*argv[]) break; SNRdB += 0.5f; } + float m = (logf(per_1) - logf(per_0)) / (snr_1 - snr_0); + float snr_target = snr_0 + (logf(per_target) - logf(per_0)) / m; + printf("per:{%12.4e,%12.4e}, snr:{%5.2f,%5.2f} => %.3f dB for PER %12.4e\n", + per_0, per_1, snr_0, snr_1, snr_target, per_target); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); @@ -89,3 +99,4 @@ int main(int argc, char*argv[]) framesync64_destroy(fs); return 0; } + From 321093248e74dba332c1a3ec39817b39fd78495d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 11 Mar 2023 12:41:57 -0500 Subject: [PATCH 102/334] ofdmframesync: returning appropriate value with debugging macros --- src/multichannel/src/ofdmframesync.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 8a05e20b1..7f008b054 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -1152,7 +1152,7 @@ int ofdmframesync_debug_enable(ofdmframesync _q) _q->debug_objects_created = 1; return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_enable(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_enable(): compile-time debugging disabled"); #endif } @@ -1163,7 +1163,7 @@ int ofdmframesync_debug_disable(ofdmframesync _q) _q->debug_enabled = 0; return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_disable(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_disable(): compile-time debugging disabled"); #endif } @@ -1325,7 +1325,7 @@ int ofdmframesync_debug_print(ofdmframesync _q, printf("ofdmframesync/debug: results written to '%s'\n", _filename); return LIQUID_OK; #else - fprintf(stderr,"ofdmframesync_debug_print(): compile-time debugging disabled\n"); + return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_print(): compile-time debugging disabled"); #endif } From 3f9c9de99d4dcaf18c114755a009a5e34c401888 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 12 Mar 2023 18:52:04 -0400 Subject: [PATCH 103/334] framesync64: respecting arguments with CLI, printing minimal info to screen --- scripts/framesync64_debug.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/framesync64_debug.py b/scripts/framesync64_debug.py index 27c09c0aa..47c455f4f 100755 --- a/scripts/framesync64_debug.py +++ b/scripts/framesync64_debug.py @@ -11,9 +11,9 @@ def main(argv=None): args = p.parse_args() for fname in args.sources: - filename = framesync64_plot(fname,args.export) + filename = framesync64_plot(fname,args.export,args.nodisplay) -def framesync64_plot(filename,export=None): +def framesync64_plot(filename,export=None,nodisplay=True): # open file and read values fid = open(filename,'rb') buf = np.fromfile(fid, count=1440, dtype=np.csingle) @@ -26,7 +26,7 @@ def framesync64_plot(filename,export=None): payload_sym = np.fromfile(fid, count= 600, dtype=np.csingle) payload_dec = np.fromfile(fid, count= 72, dtype=np.int8) - # compute filter response in dB + # compute smooth spectral response in dB nfft = 2400 f = np.arange(nfft)/nfft-0.5 psd = np.abs(np.fft.fftshift(np.fft.fft(buf, nfft)))**2 @@ -35,7 +35,6 @@ def framesync64_plot(filename,export=None): h = np.concatenate((w[m:], np.zeros(nfft-2*m-1), w[:m])) / (sum(w) * nfft) H = np.fft.fft(h) psd = 10*np.log10( np.real(np.fft.ifft(H * np.fft.fft(psd))) ) - #psd = 20*np.log10(np.abs(np.fft.fftshift(np.fft.fft(buf, nfft)))) # plot impulse and spectral responses fig, _ax = plt.subplots(2,2,figsize=(12,12)) @@ -58,11 +57,13 @@ def framesync64_plot(filename,export=None): _ax.set_ylabel('Imag') for _ax in ax: _ax.grid(True) - fig.suptitle('frame64, tau:%.6f, dphi:%.6f, phi:%.6f, rssi:%.3f dB, evm:%.3f' % \ - (tau_hat, dphi_hat, phi_hat, 20*np.log10(gamma_hat), evm)) - if export==None: + title = '%s, tau:%9.6f, dphi:%9.6f, phi:%9.6f, rssi:%6.3f dB, evm:%6.3f' % \ + (filename, tau_hat, dphi_hat, phi_hat, 20*np.log10(gamma_hat), evm) + print(title) + fig.suptitle(title) + if not nodisplay: plt.show() - else: + if export is not None: fig.savefig(os.path.splitext(filename)[0]+'.png',bbox_inches='tight') plt.close() From fdd737ec65511fee87b084ff3c944e0fced2f43b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 16 Mar 2023 17:44:13 -0400 Subject: [PATCH 104/334] crc: adding simple tests for data validity checks --- include/liquid.h | 2 +- src/fec/src/crc.c | 10 ++++---- src/fec/tests/crc_autotest.c | 47 +++++++++++++++++++++++------------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 38f575cd9..a5927130d 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1194,7 +1194,7 @@ typedef enum { extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2]; // Print compact list of existing and available CRC schemes -void liquid_print_crc_schemes(); +int liquid_print_crc_schemes(); // returns crc_scheme based on input string crc_scheme liquid_getopt_str2crc(const char * _str); diff --git a/src/fec/src/crc.c b/src/fec/src/crc.c index b3ee388ab..0b7ed7fa7 100644 --- a/src/fec/src/crc.c +++ b/src/fec/src/crc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,12 +46,12 @@ const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2] = { // Print compact list of existing and available crc schemes -void liquid_print_crc_schemes() +int liquid_print_crc_schemes() { unsigned int i; unsigned int len = 10; - // print all available MOD schemes + // print all available CRC schemes printf(" "); for (i=0; i Date: Sat, 18 Mar 2023 09:59:20 -0400 Subject: [PATCH 105/334] build: stripping version number off archive --- makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makefile.in b/makefile.in index 3c0246d9b..90decdbb6 100644 --- a/makefile.in +++ b/makefile.in @@ -1,4 +1,4 @@ -# Copyright (c) 2007 - 2022 Joseph Gaeddert +# Copyright (c) 2007 - 2023 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -1294,7 +1294,7 @@ install: all @echo "" mkdir -p $(DESTDIR)$(prefix)/include/liquid mkdir -p $(DESTDIR)$(libdir) - install -m 644 -p libliquid.${AR_LIB} $(DESTDIR)$(libdir)/libliquid.${AR_LIB}.${VERSION} + install -m 644 -p libliquid.${AR_LIB} $(DESTDIR)$(libdir)/libliquid.${AR_LIB} install -m 644 -p libliquid.${SH_LIB} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} install -m 644 -p include/liquid.h $(DESTDIR)$(prefix)/include/liquid/liquid.h ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB} @@ -1321,7 +1321,7 @@ install: all uninstall: @echo "uninstalling..." $(RM) $(DESTDIR)$(prefix)/include/liquid/liquid.h - $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB}.${VERSION} + $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.1 $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB} From 1625eff62f1915625e0b31c3b8609189ce5f33a1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 23 Mar 2023 08:09:54 -0400 Subject: [PATCH 106/334] fec/hamming(31,26): checking symbol size edge cases --- src/fec/tests/fec_hamming3126_autotest.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/fec/tests/fec_hamming3126_autotest.c b/src/fec/tests/fec_hamming3126_autotest.c index a3731c0f4..7713eaa9d 100644 --- a/src/fec/tests/fec_hamming3126_autotest.c +++ b/src/fec/tests/fec_hamming3126_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,3 +65,16 @@ void autotest_hamming3126_codec() } } +void autotest_fec_hamming3126_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // symbols too large + CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) + CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) +} From c004a4659a1121d62885ef9549ca0e0e78bf9151 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 24 Mar 2023 07:56:07 -0400 Subject: [PATCH 107/334] fec: moving configuration tests to separte file --- makefile.in | 1 + src/fec/tests/fec_config_autotest.c | 51 ++++++++++++++++++++++++ src/fec/tests/fec_hamming3126_autotest.c | 13 ------ 3 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 src/fec/tests/fec_config_autotest.c diff --git a/makefile.in b/makefile.in index 90decdbb6..d92ca74c8 100644 --- a/makefile.in +++ b/makefile.in @@ -303,6 +303,7 @@ $(fec_objects) : %.o : %.c $(include_headers) fec_autotests := \ src/fec/tests/crc_autotest.c \ src/fec/tests/fec_autotest.c \ + src/fec/tests/fec_config_autotest.c \ src/fec/tests/fec_copy_autotest.c \ src/fec/tests/fec_soft_autotest.c \ src/fec/tests/fec_golay2412_autotest.c \ diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c new file mode 100644 index 000000000..729a5725e --- /dev/null +++ b/src/fec/tests/fec_config_autotest.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "autotest/autotest.h" +#include "liquid.internal.h" + +void autotest_fec_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // symbols too large + CONTEND_EQUALITY(fec_golay2412_encode_symbol(1u<<12), 0) + CONTEND_EQUALITY(fec_golay2412_decode_symbol(1u<<24), 0) + + CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) + CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) + + CONTEND_EQUALITY(fec_hamming1511_encode_symbol(1u<<11), 0) + CONTEND_EQUALITY(fec_hamming1511_decode_symbol(1u<<15), 0) + + CONTEND_EQUALITY(fec_hamming128_encode_symbol(1u<<8), 0) + CONTEND_EQUALITY(fec_hamming128_decode_symbol(1u<<12), 0) +} + diff --git a/src/fec/tests/fec_hamming3126_autotest.c b/src/fec/tests/fec_hamming3126_autotest.c index 7713eaa9d..4e0090fe9 100644 --- a/src/fec/tests/fec_hamming3126_autotest.c +++ b/src/fec/tests/fec_hamming3126_autotest.c @@ -65,16 +65,3 @@ void autotest_hamming3126_codec() } } -void autotest_fec_hamming3126_config() -{ -#if LIQUID_STRICT_EXIT - AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); - return; -#endif -#if !LIQUID_SUPPRESS_ERROR_OUTPUT - fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); -#endif - // symbols too large - CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) - CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) -} From dc7e3f020012e3aa3ef26bdff7801a2b43256776 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:17:12 +0000 Subject: [PATCH 108/334] asgram: filling entire ASCII buffer with zeros; avoid compiler warning --- src/fft/src/asgram.proto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fft/src/asgram.proto.c b/src/fft/src/asgram.proto.c index d8adcbc31..c4d62c596 100644 --- a/src/fft/src/asgram.proto.c +++ b/src/fft/src/asgram.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -256,7 +256,7 @@ int ASGRAM(_print)(ASGRAM() _q) float maxval; float maxfreq; char ascii[_q->nfft+1]; - ascii[_q->nfft] = '\0'; // append null character to end of string + memset(ascii, '\0', _q->nfft+1); // fill buffer with null characters // execute the spectrogram ASGRAM(_execute)(_q, ascii, &maxval, &maxfreq); From f51d83b8e703c50d8958b4a4c098ffa135c68b01 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:19:33 +0000 Subject: [PATCH 109/334] fskframesync: block-commenting unused section to avoid compiler warnings --- src/framing/src/fskframesync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c index f68c4cf4c..8d30274e6 100644 --- a/src/framing/src/fskframesync.c +++ b/src/framing/src/fskframesync.c @@ -465,6 +465,7 @@ int fskframesync_execute_detectframe(fskframesync _q, //printf("signal peaked! %12.8f %12.8f %12.8f\n", // _q->rxy[0], _q->rxy[1], _q->rxy[2]); +#if 0 // compute estimate, apply bias compensation float gamma = (_q->rxy[2] - _q->rxy[0]) / _q->rxy[1]; float p2 = 9.54907046918287e-01f; @@ -472,8 +473,9 @@ int fskframesync_execute_detectframe(fskframesync _q, float xf = fabsf(gamma); float tau_hat = copysignf(p2*xf*xf + p1*xf, gamma); int num_samples = round(tau_hat * _q->k); - //printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", - // gamma, tau_hat, num_samples); + printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", + gamma, tau_hat, num_samples); +#endif // TODO: set timer and filterbank index accordingly _q->timer = 2*_q->k; From fb94b233df8e00b4fba65c7afb7f1ac4de66bb7e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 25 Mar 2023 13:26:41 +0000 Subject: [PATCH 110/334] autoscript: using sprintf to avoid compiler warning --- scripts/autoscript.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/autoscript.c b/scripts/autoscript.c index fd669808e..14ca83be0 100644 --- a/scripts/autoscript.c +++ b/scripts/autoscript.c @@ -297,11 +297,7 @@ void autoscript_parsefile(autoscript _q, // generate tag (e.g. "void benchmark_"); unsigned int tag_len = 5 + strlen(_q->type) + 2; char tag[tag_len]; - strcpy(tag, "void "); - strcpy(tag+5, _q->type); - tag[tag_len-2] = '_'; - tag[tag_len-1] = '\0'; - //printf("// tag : '%s'\n", tag); + sprintf(tag, "void %s_", _q->type); // parse file, looking for key char buffer[1024]; // line buffer From 0c8aa65ca612cfcbdba269d9373eb191acc0c7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Sat, 19 Nov 2022 06:31:52 +0000 Subject: [PATCH 111/334] Stop using SIMD dot product instructions as they are way slower than mul and add Removing the dedicated dp instruction effectively makes the dotprod_rrrf SSE4 implementation redundant, remove it Rename MMX implementations to SSE since they do not use MMX instructions anyway Add loop unrolled implementation of sumsq Prepare for AVX-512 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 35 +- library.json | 3 +- ...{dotprod_cccf.mmx.c => dotprod_cccf.sse.c} | 30 +- src/dotprod/src/dotprod_crcf.avx.c | 20 +- ...{dotprod_crcf.mmx.c => dotprod_crcf.sse.c} | 61 ++-- src/dotprod/src/dotprod_rrrf.avx.c | 23 +- ...{dotprod_rrrf.mmx.c => dotprod_rrrf.sse.c} | 58 ++-- src/dotprod/src/dotprod_rrrf.sse4.c | 307 ------------------ src/dotprod/src/sumsq.avx.c | 85 ++++- src/dotprod/src/{sumsq.mmx.c => sumsq.sse.c} | 87 ++++- 10 files changed, 270 insertions(+), 439 deletions(-) rename src/dotprod/src/{dotprod_cccf.mmx.c => dotprod_cccf.sse.c} (95%) rename src/dotprod/src/{dotprod_crcf.mmx.c => dotprod_crcf.sse.c} (88%) rename src/dotprod/src/{dotprod_rrrf.mmx.c => dotprod_rrrf.sse.c} (86%) delete mode 100644 src/dotprod/src/dotprod_rrrf.sse4.c rename src/dotprod/src/{sumsq.mmx.c => sumsq.sse.c} (60%) diff --git a/configure.ac b/configure.ac index 12d4b7cd8..33742fcee 100644 --- a/configure.ac +++ b/configure.ac @@ -170,9 +170,18 @@ else # SSSE3 : tmmintrin.h # SSE4.1/2: smmintrin.h # AVX : immintrin.h + # AVX2 : immintrin.h + # AVX512 : immintrin.h AX_EXT - if [ test "$ax_cv_have_avx2_ext" = yes ]; then + if [ test "$ax_cv_have_avx512f_ext" = yes ]; then + # AVX512 extensions + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ + src/dotprod/src/dotprod_crcf.avx.o \ + src/dotprod/src/dotprod_rrrf.avx.o \ + src/dotprod/src/sumsq.avx.o" + ARCH_OPTION='-mavx512f' + elif [ test "$ax_cv_have_avx2_ext" = yes ]; then # AVX2 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ @@ -188,24 +197,24 @@ else ARCH_OPTION='-mavx' elif [ test "$ax_cv_have_sse41_ext" = yes ]; then # SSE4.1/2 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.sse4.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse4.1' elif [ test "$ax_cv_have_sse3_ext" = yes ]; then # SSE3 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.mmx.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse3' elif [ test "$ax_cv_have_sse2_ext" = yes ]; then # SSE2 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.mmx.o \ - src/dotprod/src/dotprod_crcf.mmx.o \ - src/dotprod/src/dotprod_rrrf.mmx.o \ - src/dotprod/src/sumsq.mmx.o" + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ + src/dotprod/src/dotprod_crcf.sse.o \ + src/dotprod/src/dotprod_rrrf.sse.o \ + src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse2' else # portable C version diff --git a/library.json b/library.json index 6f14be837..753bb1a00 100644 --- a/library.json +++ b/library.json @@ -39,9 +39,8 @@ "-<.git/>", "-<*/src/*.proto.c>", "-<*/src/*.av.c>", - "-<*/src/*.mmx.c>", "-<*/src/*.neon.c>", - "-<*/src/*.sse4.c>", + "-<*/src/*.sse.c>", "-<*/src/*.avx.c>", "-<*/src/*.x86.s>" ] diff --git a/src/dotprod/src/dotprod_cccf.mmx.c b/src/dotprod/src/dotprod_cccf.sse.c similarity index 95% rename from src/dotprod/src/dotprod_cccf.mmx.c rename to src/dotprod/src/dotprod_cccf.sse.c index 6794bfcfe..6bfc10053 100644 --- a/src/dotprod/src/dotprod_cccf.mmx.c +++ b/src/dotprod/src/dotprod_cccf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -33,10 +33,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -49,14 +45,14 @@ #include // SSE3 #endif -#define DEBUG_DOTPROD_CCCF_MMX 0 +#define DEBUG_DOTPROD_CCCF_sse 0 // forward declaration of internal methods -int dotprod_cccf_execute_mmx(dotprod_cccf _q, +int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y); -int dotprod_cccf_execute_mmx4(dotprod_cccf _q, +int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y); @@ -104,7 +100,7 @@ int dotprod_cccf_run4(float complex * _h, // -// structured MMX dot product +// structured sse dot product // struct dotprod_cccf_s { @@ -177,7 +173,7 @@ dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_cccf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_cccf_copy().sse, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; @@ -206,7 +202,7 @@ int dotprod_cccf_destroy(dotprod_cccf _q) int dotprod_cccf_print(dotprod_cccf _q) { - printf("dotprod_cccf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_cccf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); @@ -223,12 +219,12 @@ int dotprod_cccf_execute(dotprod_cccf _q, { // switch based on size if (_q->n < 32) { - return dotprod_cccf_execute_mmx(_q, _x, _y); + return dotprod_cccf_execute_sse(_q, _x, _y); } - return dotprod_cccf_execute_mmx4(_q, _x, _y); + return dotprod_cccf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions +// use SSE extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // @@ -248,7 +244,7 @@ int dotprod_cccf_execute(dotprod_cccf _q, // x[1].real * h[1].imag, // x[1].imag * h[1].imag }; // -int dotprod_cccf_execute_mmx(dotprod_cccf _q, +int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y) { @@ -341,8 +337,8 @@ int dotprod_cccf_execute_mmx(dotprod_cccf _q, return LIQUID_OK; } -// use MMX/SSE extensions -int dotprod_cccf_execute_mmx4(dotprod_cccf _q, +// use SSE extensions +int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y) { diff --git a/src/dotprod/src/dotprod_crcf.avx.c b/src/dotprod/src/dotprod_crcf.avx.c index 6e14af3ad..525148210 100644 --- a/src/dotprod/src/dotprod_crcf.avx.c +++ b/src/dotprod/src/dotprod_crcf.avx.c @@ -274,10 +274,7 @@ int dotprod_crcf_execute_avx4(dotprod_crcf _q, __m256 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers - __m256 sum0 = _mm256_setzero_ps(); - __m256 sum1 = _mm256_setzero_ps(); - __m256 sum2 = _mm256_setzero_ps(); - __m256 sum3 = _mm256_setzero_ps(); + __m256 sum = _mm256_setzero_ps(); // r = 8*floor(n/32) unsigned int r = (n >> 5) << 3; @@ -304,22 +301,17 @@ int dotprod_crcf_execute_avx4(dotprod_crcf _q, s3 = _mm256_mul_ps(v3, h3); // parallel addition - sum0 = _mm256_add_ps( sum0, s0 ); - sum1 = _mm256_add_ps( sum1, s1 ); - sum2 = _mm256_add_ps( sum2, s2 ); - sum3 = _mm256_add_ps( sum3, s3 ); + sum = _mm256_add_ps( sum, s0 ); + sum = _mm256_add_ps( sum, s1 ); + sum = _mm256_add_ps( sum, s2 ); + sum = _mm256_add_ps( sum, s3 ); } - // fold down - sum0 = _mm256_add_ps( sum0, sum1 ); - sum2 = _mm256_add_ps( sum2, sum3 ); - sum0 = _mm256_add_ps( sum0, sum2 ); - // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array and perform manual sum - _mm256_store_ps(w, sum0); + _mm256_store_ps(w, sum); w[0] += w[2] + w[4] + w[6]; w[1] += w[3] + w[5] + w[7]; diff --git a/src/dotprod/src/dotprod_crcf.mmx.c b/src/dotprod/src/dotprod_crcf.sse.c similarity index 88% rename from src/dotprod/src/dotprod_crcf.mmx.c rename to src/dotprod/src/dotprod_crcf.sse.c index 4ba9d320d..182133d22 100644 --- a/src/dotprod/src/dotprod_crcf.mmx.c +++ b/src/dotprod/src/dotprod_crcf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -32,13 +32,28 @@ #include "liquid.internal.h" -#define DEBUG_DOTPROD_CRCF_MMX 0 +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#if HAVE_SSE +#include // SSE +#endif + +#if HAVE_SSE2 +#include // SSE2 +#endif + +#if HAVE_SSE3 +#include // SSE3 +#endif + +#define DEBUG_DOTPROD_CRCF_SSE 0 // forward declaration of internal methods -int dotprod_crcf_execute_mmx(dotprod_crcf _q, +int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y); -int dotprod_crcf_execute_mmx4(dotprod_crcf _q, +int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y); @@ -86,7 +101,7 @@ int dotprod_crcf_run4(float * _h, // -// structured MMX dot product +// structured SSE dot product // struct dotprod_crcf_s { @@ -153,7 +168,7 @@ dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_crcf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_crcf_copy().sse, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; @@ -181,7 +196,7 @@ int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) - printf("dotprod_crcf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_crcf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); @@ -195,13 +210,13 @@ int dotprod_crcf_execute(dotprod_crcf _q, { // switch based on size if (_q->n < 32) { - return dotprod_crcf_execute_mmx(_q, _x, _y); + return dotprod_crcf_execute_sse(_q, _x, _y); } - return dotprod_crcf_execute_mmx4(_q, _x, _y); + return dotprod_crcf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions -int dotprod_crcf_execute_mmx(dotprod_crcf _q, +// use SSE extensions +int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y) { @@ -257,8 +272,8 @@ int dotprod_crcf_execute_mmx(dotprod_crcf _q, return LIQUID_OK; } -// use MMX/SSE extensions -int dotprod_crcf_execute_mmx4(dotprod_crcf _q, +// use SSE extensions +int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y) { @@ -274,10 +289,7 @@ int dotprod_crcf_execute_mmx4(dotprod_crcf _q, __m128 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers - __m128 sum0 = _mm_setzero_ps(); - __m128 sum1 = _mm_setzero_ps(); - __m128 sum2 = _mm_setzero_ps(); - __m128 sum3 = _mm_setzero_ps(); + __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; @@ -304,22 +316,17 @@ int dotprod_crcf_execute_mmx4(dotprod_crcf _q, s3 = _mm_mul_ps(v3, h3); // parallel addition - sum0 = _mm_add_ps( sum0, s0 ); - sum1 = _mm_add_ps( sum1, s1 ); - sum2 = _mm_add_ps( sum2, s2 ); - sum3 = _mm_add_ps( sum3, s3 ); + sum = _mm_add_ps( sum, s0 ); + sum = _mm_add_ps( sum, s1 ); + sum = _mm_add_ps( sum, s2 ); + sum = _mm_add_ps( sum, s3 ); } - // fold down - sum0 = _mm_add_ps( sum0, sum1 ); - sum2 = _mm_add_ps( sum2, sum3 ); - sum0 = _mm_add_ps( sum0, sum2 ); - // aligned output array float w[4] __attribute__((aligned(16))); // unload packed array and perform manual sum - _mm_store_ps(w, sum0); + _mm_store_ps(w, sum); w[0] += w[2]; w[1] += w[3]; diff --git a/src/dotprod/src/dotprod_rrrf.avx.c b/src/dotprod/src/dotprod_rrrf.avx.c index 2af478375..08a87539c 100644 --- a/src/dotprod/src/dotprod_rrrf.avx.c +++ b/src/dotprod/src/dotprod_rrrf.avx.c @@ -219,12 +219,17 @@ int dotprod_rrrf_execute_avx(dotprod_rrrf _q, h = _mm256_load_ps(&_q->h[i]); // compute dot product - s = _mm256_dp_ps(v, h, 0xff); - + s = _mm256_mul_ps(v, h); + // parallel addition sum = _mm256_add_ps( sum, s ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array float w[8] __attribute__((aligned(32))); @@ -270,19 +275,23 @@ int dotprod_rrrf_execute_avxu(dotprod_rrrf _q, h3 = _mm256_load_ps(&_q->h[4*i+24]); // compute dot products - s0 = _mm256_dp_ps(v0, h0, 0xff); - s1 = _mm256_dp_ps(v1, h1, 0xff); - s2 = _mm256_dp_ps(v2, h2, 0xff); - s3 = _mm256_dp_ps(v3, h3, 0xff); + s0 = _mm256_mul_ps(v0, h0); + s1 = _mm256_mul_ps(v1, h1); + s2 = _mm256_mul_ps(v2, h2); + s3 = _mm256_mul_ps(v3, h3); // parallel addition - // FIXME: these additions are by far the limiting factor sum = _mm256_add_ps( sum, s0 ); sum = _mm256_add_ps( sum, s1 ); sum = _mm256_add_ps( sum, s2 ); sum = _mm256_add_ps( sum, s3 ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array float w[8] __attribute__((aligned(32))); diff --git a/src/dotprod/src/dotprod_rrrf.mmx.c b/src/dotprod/src/dotprod_rrrf.sse.c similarity index 86% rename from src/dotprod/src/dotprod_rrrf.mmx.c rename to src/dotprod/src/dotprod_rrrf.sse.c index 613eb707a..a9f4c58f1 100644 --- a/src/dotprod/src/dotprod_rrrf.mmx.c +++ b/src/dotprod/src/dotprod_rrrf.sse.c @@ -21,7 +21,7 @@ */ // -// Floating-point dot product (MMX) +// Floating-point dot product (SSE) // #include @@ -34,10 +34,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -50,13 +46,13 @@ #include // SSE3 #endif -#define DEBUG_DOTPROD_RRRF_MMX 0 +#define DEBUG_DOTPROD_RRRF_SSE 0 // internal methods -int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, +int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y); -int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, +int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y); @@ -104,7 +100,7 @@ int dotprod_rrrf_run4(float * _h, // -// structured MMX dot product +// structured SSE dot product // struct dotprod_rrrf_s { @@ -167,7 +163,7 @@ dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("dotprod_rrrf_copy().mmx, object cannot be NULL"); + return liquid_error_config("dotprod_rrrf_copy().sse, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; @@ -191,7 +187,7 @@ int dotprod_rrrf_destroy(dotprod_rrrf _q) int dotprod_rrrf_print(dotprod_rrrf _q) { - printf("dotprod_rrrf [mmx, %u coefficients]\n", _q->n); + printf("dotprod_rrrf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); @@ -205,13 +201,13 @@ int dotprod_rrrf_execute(dotprod_rrrf _q, { // switch based on size if (_q->n < 16) { - return dotprod_rrrf_execute_mmx(_q, _x, _y); + return dotprod_rrrf_execute_sse(_q, _x, _y); } - return dotprod_rrrf_execute_mmx4(_q, _x, _y); + return dotprod_rrrf_execute_sse4(_q, _x, _y); } -// use MMX/SSE extensions -int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, +// use SSE extensions +int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y) { @@ -235,7 +231,7 @@ int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, // compute multiplication s = _mm_mul_ps(v, h); - + // parallel addition sum = _mm_add_ps( sum, s ); } @@ -267,8 +263,8 @@ int dotprod_rrrf_execute_mmx(dotprod_rrrf _q, return LIQUID_OK; } -// use MMX/SSE extensions, unrolled loop -int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, +// use SSE extensions, unrolled loop +int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y) { @@ -278,10 +274,7 @@ int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, __m128 s0, s1, s2, s3; // load zeros into sum registers - __m128 sum0 = _mm_setzero_ps(); - __m128 sum1 = _mm_setzero_ps(); - __m128 sum2 = _mm_setzero_ps(); - __m128 sum3 = _mm_setzero_ps(); + __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (_q->n >> 4) << 2; @@ -308,32 +301,27 @@ int dotprod_rrrf_execute_mmx4(dotprod_rrrf _q, s3 = _mm_mul_ps(v3, h3); // parallel addition - sum0 = _mm_add_ps( sum0, s0 ); - sum1 = _mm_add_ps( sum1, s1 ); - sum2 = _mm_add_ps( sum2, s2 ); - sum3 = _mm_add_ps( sum3, s3 ); + sum = _mm_add_ps( sum, s0 ); + sum = _mm_add_ps( sum, s1 ); + sum = _mm_add_ps( sum, s2 ); + sum = _mm_add_ps( sum, s3 ); } - // fold down into single 4-element register - sum0 = _mm_add_ps( sum0, sum1 ); - sum2 = _mm_add_ps( sum2, sum3 ); - sum0 = _mm_add_ps( sum0, sum2); - // aligned output array float w[4] __attribute__((aligned(16))); #if HAVE_SSE3 // SSE3: fold down to single value using _mm_hadd_ps() __m128 z = _mm_setzero_ps(); - sum0 = _mm_hadd_ps(sum0, z); - sum0 = _mm_hadd_ps(sum0, z); + sum = _mm_hadd_ps(sum, z); + sum = _mm_hadd_ps(sum, z); // unload single (lower value) - _mm_store_ss(w, sum0); + _mm_store_ss(w, sum); float total = w[0]; #else // SSE2 and below: unload packed array and perform manual sum - _mm_store_ps(w, sum0); + _mm_store_ps(w, sum); float total = w[0] + w[1] + w[2] + w[3]; #endif diff --git a/src/dotprod/src/dotprod_rrrf.sse4.c b/src/dotprod/src/dotprod_rrrf.sse4.c deleted file mode 100644 index 5bddc12d5..000000000 --- a/src/dotprod/src/dotprod_rrrf.sse4.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// Floating-point dot product (SSE4.1/2) -// - -#include -#include -#include -#include - -#include "liquid.internal.h" - -// include proper SIMD extensions for x86 platforms -// NOTE: these pre-processor macros are defined in config.h - -#if 0 -#include // MMX -#include // SSE -#include // SSE2 -#include // SSE3 -#endif -#include // SSE4.1/2 - -#define DEBUG_DOTPROD_RRRF_SSE4 0 - -// internal methods -int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, - float * _x, - float * _y); -int dotprod_rrrf_execute_sse4u(dotprod_rrrf _q, - float * _x, - float * _y); - -// basic dot product (ordinal calculation) -int dotprod_rrrf_run(float * _h, - float * _x, - unsigned int _n, - float * _y) -{ - float r=0; - unsigned int i; - for (i=0; i<_n; i++) - r += _h[i] * _x[i]; - *_y = r; - return LIQUID_OK; -} - -// basic dot product (ordinal calculation) with loop unrolled -int dotprod_rrrf_run4(float * _h, - float * _x, - unsigned int _n, - float * _y) -{ - float r=0; - - // t = 4*(floor(_n/4)) - unsigned int t=(_n>>2)<<2; - - // compute dotprod in groups of 4 - unsigned int i; - for (i=0; in = _n; - - // allocate memory for coefficients, 16-byte aligned - q->h = (float*) _mm_malloc( q->n*sizeof(float), 16); - - // set coefficients - unsigned int i; - for (i=0; in; i++) - q->h[i] = _h[_rev ? q->n-i-1 : i]; - - // return object - return q; -} - -dotprod_rrrf dotprod_rrrf_create(float * _h, - unsigned int _n) -{ - return dotprod_rrrf_create_opt(_h, _n, 0); -} - -dotprod_rrrf dotprod_rrrf_create_rev(float * _h, - unsigned int _n) -{ - return dotprod_rrrf_create_opt(_h, _n, 1); -} - -// re-create the structured dotprod object -dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, - float * _h, - unsigned int _n) -{ - // completely destroy and re-create dotprod object - dotprod_rrrf_destroy(_q); - return dotprod_rrrf_create(_h,_n); -} - -// re-create the structured dotprod object, coefficients reversed -dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, - float * _h, - unsigned int _n) -{ - // completely destroy and re-create dotprod object - dotprod_rrrf_destroy(_q); - return dotprod_rrrf_create_rev(_h,_n); -} - -dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) -{ - // validate input - if (q_orig == NULL) - return liquid_error_config("dotprod_rrrf_copy().sse4, object cannot be NULL"); - - dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); - q_copy->n = q_orig->n; - - // allocate memory for coefficients, 16-byte aligned - q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 16 ); - - // copy coefficients array - memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); - - // return object - return q_copy; -} - -int dotprod_rrrf_destroy(dotprod_rrrf _q) -{ - _mm_free(_q->h); - free(_q); - return LIQUID_OK; -} - -int dotprod_rrrf_print(dotprod_rrrf _q) -{ - printf("dotprod_rrrf [sse4.1/4.2, %u coefficients]\n", _q->n); - unsigned int i; - for (i=0; i<_q->n; i++) - printf("%3u : %12.9f\n", i, _q->h[i]); - return LIQUID_OK; -} - -// -int dotprod_rrrf_execute(dotprod_rrrf _q, - float * _x, - float * _y) -{ - // switch based on size - if (_q->n < 16) { - return dotprod_rrrf_execute_sse4(_q, _x, _y); - } - return dotprod_rrrf_execute_sse4u(_q, _x, _y); -} - -// use MMX/SSE extensions -int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, - float * _x, - float * _y) -{ - __m128 v; // input vector - __m128 h; // coefficients vector - __m128 s; // dot product - __m128 sum = _mm_setzero_ps(); // load zeros into sum register - - // t = 4*(floor(_n/4)) - unsigned int t = (_q->n >> 2) << 2; - - // - unsigned int i; - for (i=0; ih[i]); - - // compute dot product - s = _mm_dp_ps(v, h, 0xff); - - // parallel addition - sum = _mm_add_ps( sum, s ); - } - - // aligned output array - float w[4] __attribute__((aligned(16))); - - // unload packed array - _mm_store_ps(w, sum); - float total = w[0]; - - // cleanup - for (; i<_q->n; i++) - total += _x[i] * _q->h[i]; - - // set return value - *_y = total; - return LIQUID_OK; -} - -// use MMX/SSE extensions (unrolled) -int dotprod_rrrf_execute_sse4u(dotprod_rrrf _q, - float * _x, - float * _y) -{ - __m128 v0, v1, v2, v3; - __m128 h0, h1, h2, h3; - __m128 s0, s1, s2, s3; - __m128 sum = _mm_setzero_ps(); // load zeros into sum register - - // t = 4*(floor(_n/16)) - unsigned int r = (_q->n >> 4) << 2; - - // - unsigned int i; - for (i=0; ih[4*i+ 0]); - h1 = _mm_load_ps(&_q->h[4*i+ 4]); - h2 = _mm_load_ps(&_q->h[4*i+ 8]); - h3 = _mm_load_ps(&_q->h[4*i+12]); - - // compute dot products - s0 = _mm_dp_ps(v0, h0, 0xff); - s1 = _mm_dp_ps(v1, h1, 0xff); - s2 = _mm_dp_ps(v2, h2, 0xff); - s3 = _mm_dp_ps(v3, h3, 0xff); - - // parallel addition - // FIXME: these additions are by far the limiting factor - sum = _mm_add_ps( sum, s0 ); - sum = _mm_add_ps( sum, s1 ); - sum = _mm_add_ps( sum, s2 ); - sum = _mm_add_ps( sum, s3 ); - } - - // aligned output array - float w[4] __attribute__((aligned(16))); - - // unload packed array - _mm_store_ps(w, sum); - float total = w[0]; - - // cleanup - for (i=4*r; i<_q->n; i++) - total += _x[i] * _q->h[i]; - - // set return value - *_y = total; - return LIQUID_OK; -} - diff --git a/src/dotprod/src/sumsq.avx.c b/src/dotprod/src/sumsq.avx.c index 76e3c59de..032903179 100644 --- a/src/dotprod/src/sumsq.avx.c +++ b/src/dotprod/src/sumsq.avx.c @@ -56,12 +56,12 @@ // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length -float liquid_sumsqf(float * _v, - unsigned int _n) +float liquid_sumsqf_avx(float * _v, + unsigned int _n) { // first cut: ... __m256 v; // input vector - __m256 s; // dot product + __m256 s; // product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) @@ -80,27 +80,94 @@ float liquid_sumsqf(float * _v, sum = _mm256_add_ps( sum, s ); } + // fold down into single value + __m256 z = _mm256_setzero_ps(); + sum = _mm256_hadd_ps(sum, z); + sum = _mm256_hadd_ps(sum, z); + // aligned output array - float total; + float w[8] __attribute__((aligned(32))); + + _mm256_store_ps(w, sum); + float total = w[0] + w[4]; + + // cleanup + for (; i<_n; i++) + total += _v[i] * _v[i]; + + // set return value + return total; +} + +// sum squares, unrolled loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_avxu(float * _v, + unsigned int _n) +{ + // first cut: ... + __m256 v0, v1, v2, v3; // input vector + __m256 s0, s1, s2, s3; // product + __m256 sum = _mm256_setzero_ps(); // load zeros into sum register + + // t = 8*(floor(_n/32)) + unsigned int t = (_n >> 5) << 3; + + // + unsigned int i; + for (i=0; i @@ -33,10 +33,6 @@ // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h -#if HAVE_MMX -#include // MMX -#endif - #if HAVE_SSE #include // SSE #endif @@ -52,8 +48,8 @@ // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length -float liquid_sumsqf(float * _v, - unsigned int _n) +float liquid_sumsqf_sse(float * _v, + unsigned int _n) { // first cut: ... __m128 v; // input vector @@ -102,7 +98,82 @@ float liquid_sumsqf(float * _v, return total; } -// sum squares, basic loop +// sum squares, unrolled loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_sseu(float * _v, + unsigned int _n) +{ + // first cut: ... + __m128 v0, v1, v2, v3; // input vector + __m128 s0, s1, s2, s3; // product + __m128 sum = _mm_setzero_ps(); // load zeros into sum register + + // t = 4*(floor(_n/16)) + unsigned int t = (_n >> 4) << 2; + + // + unsigned int i; + for (i=0; i Date: Sat, 25 Mar 2023 21:42:21 +0000 Subject: [PATCH 112/334] Fix typo in sumsq.avx.c header Add sumsq AVX512-F implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 2 +- src/dotprod/src/sumsq.avx.c | 2 +- src/dotprod/src/sumsq.avx512f.c | 164 ++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/dotprod/src/sumsq.avx512f.c diff --git a/configure.ac b/configure.ac index 33742fcee..d9c1286ed 100644 --- a/configure.ac +++ b/configure.ac @@ -179,7 +179,7 @@ else MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ src/dotprod/src/dotprod_rrrf.avx.o \ - src/dotprod/src/sumsq.avx.o" + src/dotprod/src/sumsq.avx512f.o" ARCH_OPTION='-mavx512f' elif [ test "$ax_cv_have_avx2_ext" = yes ]; then # AVX2 extensions diff --git a/src/dotprod/src/sumsq.avx.c b/src/dotprod/src/sumsq.avx.c index 032903179..88685fca7 100644 --- a/src/dotprod/src/sumsq.avx.c +++ b/src/dotprod/src/sumsq.avx.c @@ -21,7 +21,7 @@ */ // -// sumsq.mmx.c : floating-point sum of squares (MMX) +// sumsq.avx.c : floating-point sum of squares (AVX) // #include diff --git a/src/dotprod/src/sumsq.avx512f.c b/src/dotprod/src/sumsq.avx512f.c new file mode 100644 index 000000000..ad9c75305 --- /dev/null +++ b/src/dotprod/src/sumsq.avx512f.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2007 - 2015 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// sumsq.avx512f.c : floating-point sum of squares (AVX512-F) +// + +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#if HAVE_MMX +#include // MMX +#endif + +#if HAVE_SSE +#include // SSE +#endif + +#if HAVE_SSE2 +#include // SSE2 +#endif + +#if HAVE_SSE3 +#include // SSE3 +#endif + +#if HAVE_AVX +#include // AVX +#endif + +// sum squares, basic loop +// _v : input array [size: 1 x _n] +// _n : input length +float liquid_sumsqf_avx(float * _v, + unsigned int _n) +{ + // first cut: ... + __m512 v; // input vector + __m512 s; // product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (_n >> 4) << 4; + + // + unsigned int i; + for (i=0; i> 6) << 4; + + // + unsigned int i; + for (i=0; i Date: Sat, 25 Mar 2023 22:57:43 +0000 Subject: [PATCH 113/334] Add AVX512-F dotprod implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- configure.ac | 6 +- library.json | 1 + src/dotprod/src/dotprod_cccf.avx512f.c | 406 +++++++++++++++++++++++++ src/dotprod/src/dotprod_crcf.avx512f.c | 324 ++++++++++++++++++++ src/dotprod/src/dotprod_rrrf.avx512f.c | 292 ++++++++++++++++++ 5 files changed, 1026 insertions(+), 3 deletions(-) create mode 100644 src/dotprod/src/dotprod_cccf.avx512f.c create mode 100644 src/dotprod/src/dotprod_crcf.avx512f.c create mode 100644 src/dotprod/src/dotprod_rrrf.avx512f.c diff --git a/configure.ac b/configure.ac index d9c1286ed..34ab3dfc3 100644 --- a/configure.ac +++ b/configure.ac @@ -176,9 +176,9 @@ else if [ test "$ax_cv_have_avx512f_ext" = yes ]; then # AVX512 extensions - MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ - src/dotprod/src/dotprod_crcf.avx.o \ - src/dotprod/src/dotprod_rrrf.avx.o \ + MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx512f.o \ + src/dotprod/src/dotprod_crcf.avx512f.o \ + src/dotprod/src/dotprod_rrrf.avx512f.o \ src/dotprod/src/sumsq.avx512f.o" ARCH_OPTION='-mavx512f' elif [ test "$ax_cv_have_avx2_ext" = yes ]; then diff --git a/library.json b/library.json index 753bb1a00..5a05e3128 100644 --- a/library.json +++ b/library.json @@ -42,6 +42,7 @@ "-<*/src/*.neon.c>", "-<*/src/*.sse.c>", "-<*/src/*.avx.c>", + "-<*/src/*.avx512f.c>", "-<*/src/*.x86.s>" ] }, diff --git a/src/dotprod/src/dotprod_cccf.avx512f.c b/src/dotprod/src/dotprod_cccf.avx512f.c new file mode 100644 index 000000000..abb7768c6 --- /dev/null +++ b/src/dotprod/src/dotprod_cccf.avx512f.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#include // AVX + +#define DEBUG_DOTPROD_CCCF_AVX 0 + +// forward declaration of internal methods +int dotprod_cccf_execute_avx512f(dotprod_cccf _q, + float complex * _x, + float complex * _y); + +int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, + float complex * _x, + float complex * _y); + +// basic dot product (ordinal calculation) +int dotprod_cccf_run(float complex * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_cccf_run4(float complex * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->hi = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + q->hq = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + + // set coefficients, repeated + // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} + // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} + unsigned int i; + for (i=0; in; i++) { + unsigned int k = _rev ? q->n-i-1 : i; + q->hi[2*i+0] = crealf(_h[k]); + q->hi[2*i+1] = crealf(_h[k]); + + q->hq[2*i+0] = cimagf(_h[k]); + q->hq[2*i+1] = cimagf(_h[k]); + } + + // return object + return q; +} + +dotprod_cccf dotprod_cccf_create(float complex * _h, + unsigned int _n) +{ + return dotprod_cccf_create_opt(_h, _n, 0); +} + +dotprod_cccf dotprod_cccf_create_rev(float complex * _h, + unsigned int _n) +{ + return dotprod_cccf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, + float complex * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_cccf_destroy(_q); + return dotprod_cccf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, + float complex * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_cccf_destroy(_q); + return dotprod_cccf_create_rev(_h,_n); +} + +dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_cccf_copy().avx512f, object cannot be NULL"); + + dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned (repeated) + q_copy->hi = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + q_copy->hq = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + + // copy coefficients array (repeated) + // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} + // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} + memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); + memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + +int dotprod_cccf_destroy(dotprod_cccf _q) +{ + _mm_free(_q->hi); + _mm_free(_q->hq); + free(_q); + return LIQUID_OK; +} + +int dotprod_cccf_print(dotprod_cccf _q) +{ + printf("dotprod_cccf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); + return LIQUID_OK; +} + +// execute structured dot product +// _q : dotprod object +// _x : input array +// _y : output sample +int dotprod_cccf_execute(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // switch based on size + if (_q->n < 128) { + return dotprod_cccf_execute_avx512f(_q, _x, _y); + } + return dotprod_cccf_execute_avx512f4(_q, _x, _y); +} + +// use AVX512-F extensions +// +// (a + jb)(c + jd) = (ac - bd) + j(ad + bc) +// +// mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag, x[2].real, x[2].imag, x[3].real, x[3].imag } +// mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real, h[2].real, h[2].real, h[3].real, h[3].real } +// mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag, h[2].imag, h[2].imag, h[3].imag, h[3].imag } +// +// mm_y0 = mm_x * mm_hi +// = { x[0].real * h[0].real, +// x[0].imag * h[0].real, +// x[1].real * h[1].real, +// x[1].imag * h[1].real, +// x[2].real * h[2].real, +// x[2].imag * h[2].real, +// x[3].real * h[3].real, +// x[3].imag * h[3].real }; +// +// mm_y1 = mm_x * mm_hq +// = { x[0].real * h[0].imag, +// x[0].imag * h[0].imag, +// x[1].real * h[1].imag, +// x[1].imag * h[1].imag, +// x[2].real * h[2].imag, +// x[2].imag * h[2].imag, +// x[3].real * h[3].imag, +// x[3].imag * h[3].imag }; +// +int dotprod_cccf_execute_avx512f(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // temporary buffers + __m512 v; // input vector + __m512 hi; // coefficients vector (real) + __m512 hq; // coefficients vector (imag) + __m512 ci; // output multiplication (v * hi) + __m512 cq; // output multiplication (v * hq) + + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + __m512 one = _mm512_set1_ps(1.0f); // load ones into register + + // t = 16*(floor(_n/16)) + unsigned int t = (n >> 4) << 4; + + // + unsigned int i; + for (i=0; ihi[i]); + hq = _mm512_load_ps(&_q->hq[i]); + + // compute parallel multiplications + ci = _mm512_mul_ps(v, hi); + cq = _mm512_mul_ps(v, hq); + + // shuffle values + cq = _mm512_shuffle_ps( cq, cq, _MM_SHUFFLE(2,3,0,1) ); + + // combine using addsub_ps() + s = _mm512_fmaddsub_ps( ci, one, cq ); + + // accumulate + sum = _mm512_add_ps(sum, s); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + //float complex total = *((float complex*)w); + float complex total = w[0] + w[1] * _Complex_I; + + // cleanup + for (i=t/2; i<_q->n; i++) + total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); + + // set return value + *_y = total; + return LIQUID_OK; +} + +// use AVX512-F extensions +int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v0, v1, v2, v3; // input vectors + __m512 hi0, hi1, hi2, hi3; // coefficients vectors (real) + __m512 hq0, hq1, hq2, hq3; // coefficients vectors (imag) + __m512 ci0, ci1, ci2, ci3; // output multiplications (v * hi) + __m512 cq0, cq1, cq2, cq3; // output multiplications (v * hq) + + // load zeros into sum registers + __m512 sumi = _mm512_setzero_ps(); + __m512 sumq = _mm512_setzero_ps(); + + + __m512 one = _mm512_set1_ps(1.0f); // load ones into register + + // r = 16*floor(n/64) + unsigned int r = (n >> 6) << 4; + + // + unsigned int i; + for (i=0; ihi[4*i+0]); + hi1 = _mm512_load_ps(&_q->hi[4*i+16]); + hi2 = _mm512_load_ps(&_q->hi[4*i+32]); + hi3 = _mm512_load_ps(&_q->hi[4*i+48]); + + // load real coefficients into registers (aligned) + hq0 = _mm512_load_ps(&_q->hq[4*i+0]); + hq1 = _mm512_load_ps(&_q->hq[4*i+16]); + hq2 = _mm512_load_ps(&_q->hq[4*i+32]); + hq3 = _mm512_load_ps(&_q->hq[4*i+48]); + + // compute parallel multiplications (real) + ci0 = _mm512_mul_ps(v0, hi0); + ci1 = _mm512_mul_ps(v1, hi1); + ci2 = _mm512_mul_ps(v2, hi2); + ci3 = _mm512_mul_ps(v3, hi3); + + // compute parallel multiplications (imag) + cq0 = _mm512_mul_ps(v0, hq0); + cq1 = _mm512_mul_ps(v1, hq1); + cq2 = _mm512_mul_ps(v2, hq2); + cq3 = _mm512_mul_ps(v3, hq3); + + // accumulate + sumi = _mm512_add_ps(sumi, ci0); sumq = _mm512_add_ps(sumq, cq0); + sumi = _mm512_add_ps(sumi, ci1); sumq = _mm512_add_ps(sumq, cq1); + sumi = _mm512_add_ps(sumi, ci2); sumq = _mm512_add_ps(sumq, cq2); + sumi = _mm512_add_ps(sumi, ci3); sumq = _mm512_add_ps(sumq, cq3); + } + + // shuffle values + sumq = _mm512_shuffle_ps( sumq, sumq, _MM_SHUFFLE(2,3,0,1) ); + + // combine using addsub_ps() + sumi = _mm512_fmaddsub_ps( sumi, one, sumq ); + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sumi); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sumi); + + float complex total = w[0] + w[1] * _Complex_I; + + // cleanup (note: n _must_ be even) + // TODO : clean this method up + for (i=2*r; i<_q->n; i++) { + total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); + } + + // set return value + *_y = total; + return LIQUID_OK; +} + diff --git a/src/dotprod/src/dotprod_crcf.avx512f.c b/src/dotprod/src/dotprod_crcf.avx512f.c new file mode 100644 index 000000000..fae077f3f --- /dev/null +++ b/src/dotprod/src/dotprod_crcf.avx512f.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +#define DEBUG_DOTPROD_CRCF_AVX 0 + +// forward declaration of internal methods +int dotprod_crcf_execute_avx512f(dotprod_crcf _q, + float complex * _x, + float complex * _y); +int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, + float complex * _x, + float complex * _y); + +// basic dot product (ordinal calculation) +int dotprod_crcf_run(float * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_crcf_run4(float * _h, + float complex * _x, + unsigned int _n, + float complex * _y) +{ + float complex r = 0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->h = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); + + // set coefficients, repeated + // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} + unsigned int i; + for (i=0; in; i++) { + unsigned int k = _rev ? q->n-i-1 : i; + q->h[2*i+0] = _h[k]; + q->h[2*i+1] = _h[k]; + } + + // return object + return q; +} + +dotprod_crcf dotprod_crcf_create(float * _h, + unsigned int _n) +{ + return dotprod_crcf_create_opt(_h, _n, 0); +} + +dotprod_crcf dotprod_crcf_create_rev(float * _h, + unsigned int _n) +{ + return dotprod_crcf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_crcf_destroy(_q); + return dotprod_crcf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_crcf_destroy(_q); + return dotprod_crcf_create_rev(_h,_n); +} + +dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_crcf_copy().avx512f, object cannot be NULL"); + + dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned (repeated) + q_copy->h = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); + + // copy coefficients array (repeated) + // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} + memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + + +int dotprod_crcf_destroy(dotprod_crcf _q) +{ + _mm_free(_q->h); + free(_q); + return LIQUID_OK; +} + +int dotprod_crcf_print(dotprod_crcf _q) +{ + // print coefficients to screen, skipping odd entries (due + // to repeated coefficients) + printf("dotprod_crcf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf(" %3u : %12.9f\n", i, _q->h[2*i]); + return LIQUID_OK; +} + +// +int dotprod_crcf_execute(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // switch based on size + if (_q->n < 128) { + return dotprod_crcf_execute_avx512f(_q, _x, _y); + } + return dotprod_crcf_execute_avx512f4(_q, _x, _y); +} + +// use AVX512-F extensions +int dotprod_crcf_execute_avx512f(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v; // input vector + __m512 h; // coefficients vector + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (n >> 4) << 4; + + // + unsigned int i; + for (i=0; ih[i]); + + // compute multiplication + s = _mm512_mul_ps(v, h); + + // accumulate + sum = _mm512_add_ps(sum, s); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + // cleanup (note: n _must_ be even) + for (; ih[i ]; + w[1] += x[i+1] * _q->h[i+1]; + } + + // set return value + *_y = w[0] + _Complex_I*w[1]; + return LIQUID_OK; +} + +// use AVX512-F extensions +int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, + float complex * _x, + float complex * _y) +{ + // type cast input as floating point array + float * x = (float*) _x; + + // double effective length + unsigned int n = 2*_q->n; + + // first cut: ... + __m512 v0, v1, v2, v3; // input vectors + __m512 h0, h1, h2, h3; // coefficients vectors + __m512 s0, s1, s2, s3; // dot products [re, im, re, im] + + // load zeros into sum registers + __m512 sum = _mm512_setzero_ps(); + + // r = 16*floor(n/64) + unsigned int r = (n >> 6) << 4; + + // + unsigned int i; + for (i=0; ih[4*i+0]); + h1 = _mm512_load_ps(&_q->h[4*i+16]); + h2 = _mm512_load_ps(&_q->h[4*i+32]); + h3 = _mm512_load_ps(&_q->h[4*i+48]); + + // compute multiplication + s0 = _mm512_mul_ps(v0, h0); + s1 = _mm512_mul_ps(v1, h1); + s2 = _mm512_mul_ps(v2, h2); + s3 = _mm512_mul_ps(v3, h3); + + // parallel addition + sum = _mm512_add_ps( sum, s0 ); + sum = _mm512_add_ps( sum, s1 ); + sum = _mm512_add_ps( sum, s2 ); + sum = _mm512_add_ps( sum, s3 ); + } + + // output array + float w[2]; + + // fold down I/Q components into single value + w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); + w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); + + // cleanup (note: n _must_ be even) + for (i=4*r; ih[i ]; + w[1] += x[i+1] * _q->h[i+1]; + } + + // set return value + *_y = w[0] + w[1]*_Complex_I; + return LIQUID_OK; +} + diff --git a/src/dotprod/src/dotprod_rrrf.avx512f.c b/src/dotprod/src/dotprod_rrrf.avx512f.c new file mode 100644 index 000000000..c11a744a9 --- /dev/null +++ b/src/dotprod/src/dotprod_rrrf.avx512f.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2007 - 2022 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// Floating-point dot product (AVX512-F) +// + +#include +#include +#include +#include + +#include "liquid.internal.h" + +// include proper SIMD extensions for x86 platforms +// NOTE: these pre-processor macros are defined in config.h + +#include // AVX + +#define DEBUG_DOTPROD_RRRF_AVX 0 + +// internal methods +int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, + float * _x, + float * _y); +int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, + float * _x, + float * _y); + +// basic dot product (ordinal calculation) +int dotprod_rrrf_run(float * _h, + float * _x, + unsigned int _n, + float * _y) +{ + float r=0; + unsigned int i; + for (i=0; i<_n; i++) + r += _h[i] * _x[i]; + *_y = r; + return LIQUID_OK; +} + +// basic dot product (ordinal calculation) with loop unrolled +int dotprod_rrrf_run4(float * _h, + float * _x, + unsigned int _n, + float * _y) +{ + float r=0; + + // t = 4*(floor(_n/4)) + unsigned int t=(_n>>2)<<2; + + // compute dotprod in groups of 4 + unsigned int i; + for (i=0; in = _n; + + // allocate memory for coefficients, 64-byte aligned + q->h = (float*) _mm_malloc( q->n*sizeof(float), 64); + + // set coefficients + unsigned int i; + for (i=0; in; i++) + q->h[i] = _h[_rev ? q->n-i-1 : i]; + + // return object + return q; +} + +dotprod_rrrf dotprod_rrrf_create(float * _h, + unsigned int _n) +{ + return dotprod_rrrf_create_opt(_h, _n, 0); +} + +dotprod_rrrf dotprod_rrrf_create_rev(float * _h, + unsigned int _n) +{ + return dotprod_rrrf_create_opt(_h, _n, 1); +} + +// re-create the structured dotprod object +dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_rrrf_destroy(_q); + return dotprod_rrrf_create(_h,_n); +} + +// re-create the structured dotprod object, coefficients reversed +dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, + float * _h, + unsigned int _n) +{ + // completely destroy and re-create dotprod object + dotprod_rrrf_destroy(_q); + return dotprod_rrrf_create_rev(_h,_n); +} + +dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("dotprod_rrrf_copy().avx512f, object cannot be NULL"); + + dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); + q_copy->n = q_orig->n; + + // allocate memory for coefficients, 64-byte aligned + q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 64 ); + + // copy coefficients array + memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); + + // return object + return q_copy; +} + +int dotprod_rrrf_destroy(dotprod_rrrf _q) +{ + _mm_free(_q->h); + free(_q); + return LIQUID_OK; +} + +int dotprod_rrrf_print(dotprod_rrrf _q) +{ + printf("dotprod_rrrf [avx512f, %u coefficients]\n", _q->n); + unsigned int i; + for (i=0; i<_q->n; i++) + printf("%3u : %12.9f\n", i, _q->h[i]); + return LIQUID_OK; +} + +// +int dotprod_rrrf_execute(dotprod_rrrf _q, + float * _x, + float * _y) +{ + // switch based on size + if (_q->n < 64) { + return dotprod_rrrf_execute_avx512f(_q, _x, _y); + } + return dotprod_rrrf_execute_avx512fu(_q, _x, _y); +} + +// use AVX512-F extensions +int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, + float * _x, + float * _y) +{ + __m512 v; // input vector + __m512 h; // coefficients vector + __m512 s; // dot product + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/16)) + unsigned int t = (_q->n >> 4) << 4; + + // + unsigned int i; + for (i=0; ih[i]); + + // compute dot product + s = _mm512_mul_ps(v, h); + + // parallel addition + sum = _mm512_add_ps( sum, s ); + } + + // fold down into single value + float total = _mm512_reduce_add_ps(sum); + + // cleanup + for (; i<_q->n; i++) + total += _x[i] * _q->h[i]; + + // set return value + *_y = total; + return LIQUID_OK; +} + +// use AVX512-F extensions (unrolled) +int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, + float * _x, + float * _y) +{ + __m512 v0, v1, v2, v3; + __m512 h0, h1, h2, h3; + __m512 s0, s1, s2, s3; + __m512 sum = _mm512_setzero_ps(); // load zeros into sum register + + // t = 16*(floor(_n/64)) + unsigned int r = (_q->n >> 6) << 4; + + // + unsigned int i; + for (i=0; ih[4*i+ 0]); + h1 = _mm512_load_ps(&_q->h[4*i+16]); + h2 = _mm512_load_ps(&_q->h[4*i+32]); + h3 = _mm512_load_ps(&_q->h[4*i+48]); + + // compute dot products + s0 = _mm512_mul_ps(v0, h0); + s1 = _mm512_mul_ps(v1, h1); + s2 = _mm512_mul_ps(v2, h2); + s3 = _mm512_mul_ps(v3, h3); + + // parallel addition + sum = _mm512_add_ps( sum, s0 ); + sum = _mm512_add_ps( sum, s1 ); + sum = _mm512_add_ps( sum, s2 ); + sum = _mm512_add_ps( sum, s3 ); + } + + // fold down into single value + float total = _mm512_reduce_add_ps(sum); + + // cleanup + for (i=4*r; i<_q->n; i++) + total += _x[i] * _q->h[i]; + + // set return value + *_y = total; + return LIQUID_OK; +} + From 2b27de22f957e2284b39f9c4c60d42d7d97fbcf5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 30 Mar 2023 17:17:14 -0400 Subject: [PATCH 114/334] benchmark compare: specifying argument type as float --- scripts/benchmark_compare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/benchmark_compare.py b/scripts/benchmark_compare.py index 328e134c1..0fdc7295f 100755 --- a/scripts/benchmark_compare.py +++ b/scripts/benchmark_compare.py @@ -6,7 +6,7 @@ p = argparse.ArgumentParser(description=__doc__) p.add_argument('old', help='old benchmark file (.json)') p.add_argument('new', help='new benchmark file (.json)') -p.add_argument('-thresh', default=1.5, help='threshold for displaying deltas') +p.add_argument('-thresh', default=1.5, type=float, help='threshold for displaying deltas') args = p.parse_args() # load json files From 05d93374ae4957d6da01168cb5f7dd4017c4efe9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 15 Apr 2023 16:03:03 -0400 Subject: [PATCH 115/334] fec/autotest: cleaning up warning when libfec is not installed --- src/fec/tests/fec_autotest.c | 40 +++++++++++++++---------------- src/fec/tests/fec_copy_autotest.c | 40 +++++++++++++++---------------- src/fec/tests/fec_soft_autotest.c | 40 +++++++++++++++---------------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/fec/tests/fec_autotest.c b/src/fec/tests/fec_autotest.c index df1bdfffa..d03712ce1 100644 --- a/src/fec/tests/fec_autotest.c +++ b/src/fec/tests/fec_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,25 +29,25 @@ void fec_test_codec(fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif diff --git a/src/fec/tests/fec_copy_autotest.c b/src/fec/tests/fec_copy_autotest.c index 34344eb5b..bcb2d1ca3 100644 --- a/src/fec/tests/fec_copy_autotest.c +++ b/src/fec/tests/fec_copy_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,25 +29,25 @@ void fec_test_copy(fec_scheme _fs) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif diff --git a/src/fec/tests/fec_soft_autotest.c b/src/fec/tests/fec_soft_autotest.c index 34c92803d..0ef350493 100644 --- a/src/fec/tests/fec_soft_autotest.c +++ b/src/fec/tests/fec_soft_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,25 +32,25 @@ void fec_test_soft_codec(fec_scheme _fs, void * _opts) { #if !LIBFEC_ENABLED - if ( _fs == LIQUID_FEC_CONV_V27 || - _fs == LIQUID_FEC_CONV_V29 || - _fs == LIQUID_FEC_CONV_V39 || - _fs == LIQUID_FEC_CONV_V615 || - _fs == LIQUID_FEC_CONV_V27P23 || - _fs == LIQUID_FEC_CONV_V27P34 || - _fs == LIQUID_FEC_CONV_V27P45 || - _fs == LIQUID_FEC_CONV_V27P56 || - _fs == LIQUID_FEC_CONV_V27P67 || - _fs == LIQUID_FEC_CONV_V27P78 || - _fs == LIQUID_FEC_CONV_V29P23 || - _fs == LIQUID_FEC_CONV_V29P34 || - _fs == LIQUID_FEC_CONV_V29P45 || - _fs == LIQUID_FEC_CONV_V29P56 || - _fs == LIQUID_FEC_CONV_V29P67 || - _fs == LIQUID_FEC_CONV_V29P78 || - _fs == LIQUID_FEC_RS_M8) - { - AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + switch (_fs) { + case LIQUID_FEC_CONV_V27: + case LIQUID_FEC_CONV_V29: + case LIQUID_FEC_CONV_V39: + case LIQUID_FEC_CONV_V615: + case LIQUID_FEC_CONV_V27P23: + case LIQUID_FEC_CONV_V27P34: + case LIQUID_FEC_CONV_V27P45: + case LIQUID_FEC_CONV_V27P56: + case LIQUID_FEC_CONV_V27P67: + case LIQUID_FEC_CONV_V27P78: + case LIQUID_FEC_CONV_V29P23: + case LIQUID_FEC_CONV_V29P34: + case LIQUID_FEC_CONV_V29P45: + case LIQUID_FEC_CONV_V29P56: + case LIQUID_FEC_CONV_V29P67: + case LIQUID_FEC_CONV_V29P78: + case LIQUID_FEC_RS_M8: + AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; } #endif From fed7a0178de8a2501ef213a76d0da3c4f13682e8 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 May 2023 16:06:29 -0400 Subject: [PATCH 116/334] migrating to macro/prototype pattern --- makefile.in | 9 +- src/framing/src/qdsync.proto.c | 423 +++++++++++++++++++++++++++++++++ src/framing/src/qdsync_cccf.c | 415 ++------------------------------ 3 files changed, 442 insertions(+), 405 deletions(-) create mode 100644 src/framing/src/qdsync.proto.c diff --git a/makefile.in b/makefile.in index d92ca74c8..12e6b5496 100644 --- a/makefile.in +++ b/makefile.in @@ -651,14 +651,14 @@ framing_objects := \ src/framing/src/ofdmflexframegen.o \ src/framing/src/ofdmflexframesync.o \ src/framing/src/presync_cccf.o \ - src/framing/src/symstreamcf.o \ - src/framing/src/symstreamrcf.o \ - src/framing/src/symtrack_cccf.o \ src/framing/src/qdetector_cccf.o \ src/framing/src/qdsync_cccf.o \ src/framing/src/qpacketmodem.o \ src/framing/src/qpilotgen.o \ src/framing/src/qpilotsync.o \ + src/framing/src/symstreamcf.o \ + src/framing/src/symstreamrcf.o \ + src/framing/src/symtrack_cccf.o \ # list explicit targets and dependencies here @@ -682,10 +682,11 @@ src/framing/src/msourcecf.o : %.o : %.c $(include_headers) src/framing/s src/framing/src/ofdmflexframegen.o : %.o : %.c $(include_headers) src/framing/src/ofdmflexframesync.o : %.o : %.c $(include_headers) src/framing/src/presync_cccf.o : %.o : %.c $(include_headers) src/framing/src/presync.proto.c -src/framing/src/qpacketmodem.o : %.o : %.c $(include_headers) src/framing/src/symstreamcf.o : %.o : %.c $(include_headers) src/framing/src/symstream.proto.c src/framing/src/symstreamrcf.o : %.o : %.c $(include_headers) src/framing/src/symstreamr.proto.c src/framing/src/symtrack_cccf.o : %.o : %.c $(include_headers) src/framing/src/symtrack.proto.c +src/framing/src/qdsync_cccf.o : %.o : %.c $(include_headers) src/framing/src/qdsync.proto.c +src/framing/src/qpacketmodem.o : %.o : %.c $(include_headers) framing_autotests := \ diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c new file mode 100644 index 000000000..12bbee5c0 --- /dev/null +++ b/src/framing/src/qdsync.proto.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Frame detector and synchronizer; uses a novel correlation method to +// detect a synchronization pattern, estimate carrier frequency and +// phase offsets as well as timing phase, then correct for these +// impairments in a simple interface suitable for custom frame recovery. + +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +// push samples through detection stage +int QDSYNC(_execute_detect)(QDSYNC() _q, float complex _x); + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +int QDSYNC(_step)(QDSYNC() _q, float complex _x); + +// append sample to output buffer +int QDSYNC(_buf_append)(QDSYNC() _q, float complex _x); + +// main object definition +struct QDSYNC(_s) { + unsigned int seq_len; // preamble sequence length + int ftype; // filter type + unsigned int k; // samples per symbol + unsigned int m; // filter semi-length + float beta; // excess bandwidth factor + + QDSYNC(_callback) callback; // user-defined callback function + void * context; // user-defined context object + QDETECTOR() detector; // detector + + // status variables + enum { + QDSYNC_STATE_DETECT=0, // detect frame + QDSYNC_STATE_SYNC, // apply carrier offset correction and matched filter + } state; // frame synchronization state + unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence + + nco_crcf mixer; // coarse carrier frequency recovery + + // timing recovery objects, states + firpfb_crcf mf; // matched filter/decimator + unsigned int npfb; // number of filters in symsync + int mf_counter; // matched filter output timer + unsigned int pfb_index; // filterbank index + + // symbol buffer + unsigned int buf_out_len;// output buffer length + float complex * buf_out; // output buffer + unsigned int buf_out_counter; // output counter +}; + +// create detector with generic sequence +QDSYNC() QDSYNC(_create_linear)(TI * _seq, + unsigned int _seq_len, + int _ftype, + unsigned int _k, + unsigned int _m, + float _beta, + QDSYNC(_callback) _callback, + void * _context) +{ + // validate input + if (_seq_len == 0) + return liquid_error_config("QDSYNC(_create)(), sequence length cannot be zero"); + + // allocate memory for main object and set internal properties + QDSYNC() q = (QDSYNC()) malloc(sizeof(struct QDSYNC(_s))); + q->seq_len = _seq_len; + q->ftype = _ftype; + q->k = _k; + q->m = _m; + q->beta = _beta; + + // create detector + q->detector = QDETECTOR(_create_linear)(_seq, _seq_len, _ftype, _k, _m, _beta); + + // create down-coverters for carrier phase tracking + q->mixer = nco_crcf_create(LIQUID_NCO); + + // create symbol timing recovery filters + q->npfb = 256; // number of filters in the bank + q->mf = firpfb_crcf_create_rnyquist(q->ftype, q->npfb, q->k, q->m, q->beta); + + // allocate buffer for storing output samples + q->buf_out_len = 64; // user can re-size this later + q->buf_out = (float complex*) malloc(q->buf_out_len*sizeof(float complex)); + + // set callback and context values + QDSYNC(_set_callback)(q, _callback); + QDSYNC(_set_context )(q, _context ); + + // reset and return object + QDSYNC(_reset)(q); + return q; +} + +// copy object +QDSYNC() QDSYNC(_copy)(QDSYNC() q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); + + // create new object and copy base parameters + QDSYNC() q_copy = (QDSYNC())malloc(sizeof(struct QDSYNC(_s))); + memmove(q_copy, q_orig, sizeof(struct QDSYNC(_s))); + + // set callback and userdata fields + q_copy->callback = q_orig->callback; + q_copy->context = q_orig->context; + + // copy sub-objects + q_copy->detector = QDETECTOR(_copy)(q_orig->detector); + q_copy->mixer = nco_crcf_copy (q_orig->mixer); + q_copy->mf = firpfb_crcf_copy (q_orig->mf); + + // copy memory in new allocation + q_copy->buf_out = (float complex*)liquid_malloc_copy(q_orig->buf_out, q_orig->buf_out_len, sizeof(float complex)); + + // return new object + return q_copy; +} + +int QDSYNC(_destroy)(QDSYNC() _q) +{ + // destroy internal objects + QDETECTOR(_destroy)(_q->detector); + nco_crcf_destroy(_q->mixer); + firpfb_crcf_destroy(_q->mf); + + // free output buffer + free(_q->buf_out); + + // free main object memory + free(_q); + return LIQUID_OK; +} + +int QDSYNC(_print)(QDSYNC() _q) +{ + printf("\n"); + return LIQUID_OK; +} + +int QDSYNC(_reset)(QDSYNC() _q) +{ + QDETECTOR(_reset)(_q->detector); + _q->state = QDSYNC_STATE_DETECT; + _q->symbol_counter = 0; + _q->buf_out_counter = 0; + firpfb_crcf_reset(_q->mf); + return LIQUID_OK; +} + +// get detection threshold +float QDSYNC(_get_threshold)(QDSYNC() _q) +{ + return QDETECTOR(_get_threshold)(_q->detector); +} + +// set detection threshold +int QDSYNC(_set_threshold)(QDSYNC() _q, float _threshold) +{ + return QDETECTOR(_set_threshold)(_q->detector, _threshold); +} + +// set carrier offset search range +int QDSYNC(_set_range)(QDSYNC() _q, float _dphi_max) +{ + return QDETECTOR(_set_range)(_q->detector, _dphi_max); +} + +// set callback method +int QDSYNC(_set_callback)(QDSYNC() _q, QDSYNC(_callback) _callback) +{ + _q->callback = _callback; + return LIQUID_OK; +} + +// set context value +int QDSYNC(_set_context)(QDSYNC() _q, void * _context) +{ + _q->context = _context; + return LIQUID_OK; +} + +// Set callback buffer size (the number of symbol provided to the callback +// whenever it is invoked). +int QDSYNC(_set_buf_len)(QDSYNC() _q, unsigned int _buf_len) +{ + if (_buf_len == 0) + return liquid_error(LIQUID_EICONFIG,"QDSYNC(_set_buf_len)(), buffer length must be greater than 0"); + + // check current state + if (_q->buf_out_counter < _buf_len) { + // buffer might not be empty, but we aren't resizing within this space; + // ok to resize so long as old samples are copied + _q->buf_out_len = _buf_len; + float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + if (buf_new == NULL) + return liquid_error(LIQUID_EIMEM,"QDSYNC(_set_buf_len)(), could not allocate %u samples", _buf_len); + _q->buf_out = buf_new; + } else { + // we are shrinking the buffer below the number of samples it currently + // holds; invoke the callback as many times as needed to reduce its size + unsigned int index = 0; + while (_q->buf_out_counter >= _buf_len) { + if (_q->callback != NULL) + _q->callback(_q->buf_out + index, _buf_len, _q->context); + + // adjust counters + index += _buf_len; + _q->buf_out_counter -= _buf_len; + } + + // copy old values to front of buffer + memmove(_q->buf_out, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); + + // now resize the buffer appropriately + _q->buf_out_len = _buf_len; + float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); + if (buf_new == NULL) + return liquid_error(LIQUID_EIMEM,"QDSYNC(_set_buf_len)(), could not allocate %u samples", _buf_len); + _q->buf_out = buf_new; + } + return LIQUID_OK; +} + +int QDSYNC(_execute)(QDSYNC() _q, + TI * _buf, + unsigned int _buf_len) +{ + unsigned int i; + for (i=0; i<_buf_len; i++) { + switch (_q->state) { + case QDSYNC_STATE_DETECT: + // detect frame (look for p/n sequence) + QDSYNC(_execute_detect)(_q, _buf[i]); + break; + case QDSYNC_STATE_SYNC: + // receive preamble sequence symbols + QDSYNC(_step)(_q, _buf[i]); + break; + default: + return liquid_error(LIQUID_EINT,"QDSYNC(_exeucte)(), unknown/unsupported state"); + } + } + return LIQUID_OK; +} + +int QDSYNC(_is_open)(QDSYNC() _q) +{ + return _q->state == QDSYNC_STATE_DETECT ? 0 : 1; +} + +// correlator output +float QDSYNC(_get_rxy)(QDSYNC() _q) +{ + return QDETECTOR(_get_rxy)(_q->detector); +} + +// fractional timing offset estimate +float QDSYNC(_get_tau)(QDSYNC() _q) +{ + return QDETECTOR(_get_tau)(_q->detector); +} + +// channel gain +float QDSYNC(_get_gamma)(QDSYNC() _q) +{ + return QDETECTOR(_get_gamma)(_q->detector); +} + +// carrier frequency offset estimate +float QDSYNC(_get_dphi)(QDSYNC() _q) +{ + return QDETECTOR(_get_dphi)(_q->detector); +} + +// carrier phase offset estimate +float QDSYNC(_get_phi)(QDSYNC() _q) +{ + return QDETECTOR(_get_phi)(_q->detector); +} + +// +// internal methods +// + +// execute synchronizer, seeking preamble sequence +// _q : frame synchronizer object +// _x : input sample +// _sym : demodulated symbol +int QDSYNC(_execute_detect)(QDSYNC() _q, + TI _x) +{ + // push through pre-demod synchronizer + float complex * v = QDETECTOR(_execute)(_q->detector, _x); + + // check if frame has been detected + if (v != NULL) { + // get estimates + float tau_hat = QDETECTOR(_get_tau) (_q->detector); + float gamma_hat = QDETECTOR(_get_gamma)(_q->detector); + float dphi_hat = QDETECTOR(_get_dphi) (_q->detector); + float phi_hat = QDETECTOR(_get_phi) (_q->detector); + + // set appropriate filterbank index + _q->mf_counter = _q->k - 2; + _q->pfb_index = 0; + int index = (int)(tau_hat * _q->npfb); + if (index < 0) { + _q->mf_counter++; + index += _q->npfb; + } + _q->pfb_index = index; + //printf("* qdsync detected! tau:%6.3f, dphi:%12.4e, phi:%6.3f, gamma:%6.2f dB, mf:%u, pfb idx:%u\n", + // tau_hat, dphi_hat, phi_hat, 20*log10f(gamma_hat), _q->mf_counter, _q->pfb_index); + + // output filter scale + firpfb_crcf_set_scale(_q->mf, 1.0f / (_q->k * gamma_hat)); + + // set frequency/phase of mixer + nco_crcf_set_frequency(_q->mixer, dphi_hat); + nco_crcf_set_phase (_q->mixer, phi_hat ); + + // update state + _q->state = QDSYNC_STATE_SYNC; + + // run buffered samples through synchronizer + unsigned int buf_len = QDETECTOR(_get_buf_len)(_q->detector); + QDSYNC(_execute)(_q, v, buf_len); + } + return LIQUID_OK; +} + +// step receiver mixer, matched filter, decimator +// _q : frame synchronizer +// _x : input sample +// _y : output symbol +int QDSYNC(_step)(QDSYNC() _q, TI _x) +{ + // mix sample down + float complex v; + nco_crcf_mix_down(_q->mixer, _x, &v); + nco_crcf_step (_q->mixer); + + // push sample into filterbank + firpfb_crcf_push (_q->mf, v); + firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); + + // increment counter to determine if sample is available + _q->mf_counter++; + int sample_available = (_q->mf_counter >= _q->k-1) ? 1 : 0; + + // set output sample if available + if (sample_available) { + // decrement counter by k=2 samples/symbol + _q->mf_counter -= _q->k; + + // append to output + QDSYNC(_buf_append)(_q, v); + } + + // return flag + return LIQUID_OK; +} + +// append sample to output buffer +int QDSYNC(_buf_append)(QDSYNC() _q, TO _x) +{ + // account for filter delay + _q->symbol_counter++; + if (_q->symbol_counter <= 2*_q->m) + return LIQUID_OK; + + // append sample to end of buffer + _q->buf_out[_q->buf_out_counter] = _x; + _q->buf_out_counter++; + + // check if buffer is full + if (_q->buf_out_counter == _q->buf_out_len) { + // reset counter + _q->buf_out_counter = 0; + + // invoke callback + if (_q->callback != NULL) { + int rc = _q->callback(_q->buf_out, _q->buf_out_len, _q->context); + if (rc) + return QDSYNC(_reset)(_q); + } + } + return LIQUID_OK; +} + diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c index 2dcf01fbf..28104f7a9 100644 --- a/src/framing/src/qdsync_cccf.c +++ b/src/framing/src/qdsync_cccf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,411 +20,24 @@ * THE SOFTWARE. */ -// Frame detector and synchronizer; uses a novel correlation method to -// detect a synchronization pattern, estimate carrier frequency and -// phase offsets as well as timing phase, then correct for these -// impairments in a simple interface suitable for custom frame recovery. - -#include -#include -#include -#include -#include - -#include "liquid.internal.h" - -// push samples through detection stage -int qdsync_cccf_execute_detect(qdsync_cccf _q, - float complex _x); - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -int qdsync_cccf_step(qdsync_cccf _q, - float complex _x); - -// append sample to output buffer -int qdsync_cccf_buf_append(qdsync_cccf _q, - float complex _x); - -// main object definition -struct qdsync_cccf_s { - unsigned int seq_len; // preamble sequence length - int ftype; // filter type - unsigned int k; // samples per symbol - unsigned int m; // filter semi-length - float beta; // excess bandwidth factor - - qdsync_callback callback; // user-defined callback function - void * context; // user-defined context object - qdetector_cccf detector; // detector - - // status variables - enum { - QDSYNC_STATE_DETECT=0, // detect frame - QDSYNC_STATE_SYNC, // apply carrier offset correction and matched filter - } state; // frame synchronization state - unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence - - nco_crcf mixer; // coarse carrier frequency recovery - - // timing recovery objects, states - firpfb_crcf mf; // matched filter/decimator - unsigned int npfb; // number of filters in symsync - int mf_counter; // matched filter output timer - unsigned int pfb_index; // filterbank index - - // symbol buffer - unsigned int buf_out_len;// output buffer length - float complex * buf_out; // output buffer - unsigned int buf_out_counter; // output counter -}; - -// create detector with generic sequence -qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _seq, - unsigned int _seq_len, - int _ftype, - unsigned int _k, - unsigned int _m, - float _beta, - qdsync_callback _callback, - void * _context) -{ - // validate input - if (_seq_len == 0) - return liquid_error_config("qdsync_cccf_create(), sequence length cannot be zero"); - - // allocate memory for main object and set internal properties - qdsync_cccf q = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); - q->seq_len = _seq_len; - q->ftype = _ftype; - q->k = _k; - q->m = _m; - q->beta = _beta; - - // create detector - q->detector = qdetector_cccf_create_linear(_seq, _seq_len, _ftype, _k, _m, _beta); - - // create down-coverters for carrier phase tracking - q->mixer = nco_crcf_create(LIQUID_NCO); - - // create symbol timing recovery filters - q->npfb = 256; // number of filters in the bank - q->mf = firpfb_crcf_create_rnyquist(q->ftype, q->npfb, q->k, q->m, q->beta); - - // allocate buffer for storing output samples - q->buf_out_len = 64; // user can re-size this later - q->buf_out = (float complex*) malloc(q->buf_out_len*sizeof(float complex)); - - // set callback and context values - qdsync_cccf_set_callback(q, _callback); - qdsync_cccf_set_context (q, _context ); - - // reset and return object - qdsync_cccf_reset(q); - return q; -} - -// copy object -qdsync_cccf qdsync_cccf_copy(qdsync_cccf q_orig) -{ - // validate input - if (q_orig == NULL) - return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); - - // create new object and copy base parameters - qdsync_cccf q_copy = (qdsync_cccf) malloc(sizeof(struct qdsync_cccf_s)); - memmove(q_copy, q_orig, sizeof(struct qdsync_cccf_s)); - - // set callback and userdata fields - q_copy->callback = q_orig->callback; - q_copy->context = q_orig->context; - - // copy sub-objects - q_copy->detector = qdetector_cccf_copy(q_orig->detector); - q_copy->mixer = nco_crcf_copy (q_orig->mixer); - q_copy->mf = firpfb_crcf_copy (q_orig->mf); - - // copy memory in new allocation - q_copy->buf_out = (float complex*)liquid_malloc_copy(q_orig->buf_out, q_orig->buf_out_len, sizeof(float complex)); - - // return new object - return q_copy; -} - -int qdsync_cccf_destroy(qdsync_cccf _q) -{ - // destroy internal objects - qdetector_cccf_destroy(_q->detector); - nco_crcf_destroy(_q->mixer); - firpfb_crcf_destroy(_q->mf); - - // free output buffer - free(_q->buf_out); - - // free main object memory - free(_q); - return LIQUID_OK; -} - -int qdsync_cccf_print(qdsync_cccf _q) -{ - printf("\n"); - return LIQUID_OK; -} - -int qdsync_cccf_reset(qdsync_cccf _q) -{ - qdetector_cccf_reset(_q->detector); - _q->state = QDSYNC_STATE_DETECT; - _q->symbol_counter = 0; - _q->buf_out_counter = 0; - firpfb_crcf_reset(_q->mf); - return LIQUID_OK; -} - -// get detection threshold -float qdsync_cccf_get_threshold(qdsync_cccf _q) -{ - return qdetector_cccf_get_threshold(_q->detector); -} - -// set detection threshold -int qdsync_cccf_set_threshold(qdsync_cccf _q, - float _threshold) -{ - return qdetector_cccf_set_threshold(_q->detector, _threshold); -} - -// set carrier offset search range -int qdsync_cccf_set_range(qdsync_cccf _q, - float _dphi_max) -{ - return qdetector_cccf_set_range(_q->detector, _dphi_max); -} - -// set callback method -int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback) -{ - _q->callback = _callback; - return LIQUID_OK; -} - -// set context value -int qdsync_cccf_set_context (qdsync_cccf _q, void * _context) -{ - _q->context = _context; - return LIQUID_OK; -} - -// Set callback buffer size (the number of symbol provided to the callback -// whenever it is invoked). -int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len) -{ - if (_buf_len == 0) - return liquid_error(LIQUID_EICONFIG,"qdsync_cccf_set_buf_len(), buffer length must be greater than 0"); - - // check current state - if (_q->buf_out_counter < _buf_len) { - // buffer might not be empty, but we aren't resizing within this space; - // ok to resize so long as old samples are copied - _q->buf_out_len = _buf_len; - float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); - if (buf_new == NULL) - return liquid_error(LIQUID_EIMEM,"qdsync_cccf_set_buf_len(), could not allocate %u samples", _buf_len); - _q->buf_out = buf_new; - } else { - // we are shrinking the buffer below the number of samples it currently - // holds; invoke the callback as many times as needed to reduce its size - unsigned int index = 0; - while (_q->buf_out_counter >= _buf_len) { - if (_q->callback != NULL) - _q->callback(_q->buf_out + index, _buf_len, _q->context); - - // adjust counters - index += _buf_len; - _q->buf_out_counter -= _buf_len; - } - - // copy old values to front of buffer - memmove(_q->buf_out, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); - - // now resize the buffer appropriately - _q->buf_out_len = _buf_len; - float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); - if (buf_new == NULL) - return liquid_error(LIQUID_EIMEM,"qdsync_cccf_set_buf_len(), could not allocate %u samples", _buf_len); - _q->buf_out = buf_new; - } - return LIQUID_OK; -} - -int qdsync_cccf_execute(qdsync_cccf _q, - liquid_float_complex * _buf, - unsigned int _buf_len) -{ - unsigned int i; - for (i=0; i<_buf_len; i++) { - switch (_q->state) { - case QDSYNC_STATE_DETECT: - // detect frame (look for p/n sequence) - qdsync_cccf_execute_detect(_q, _buf[i]); - break; - case QDSYNC_STATE_SYNC: - // receive preamble sequence symbols - qdsync_cccf_step(_q, _buf[i]); - break; - default: - return liquid_error(LIQUID_EINT,"qdsync_cccf_exeucte(), unknown/unsupported state"); - } - } - return LIQUID_OK; -} - -int qdsync_cccf_is_open(qdsync_cccf _q) -{ - return _q->state == QDSYNC_STATE_DETECT ? 0 : 1; -} - -// correlator output -float qdsync_cccf_get_rxy(qdsync_cccf _q) -{ - return qdetector_cccf_get_rxy(_q->detector); -} - -// fractional timing offset estimate -float qdsync_cccf_get_tau(qdsync_cccf _q) -{ - return qdetector_cccf_get_tau(_q->detector); -} - -// channel gain -float qdsync_cccf_get_gamma(qdsync_cccf _q) -{ - return qdetector_cccf_get_gamma(_q->detector); -} - -// carrier frequency offset estimate -float qdsync_cccf_get_dphi(qdsync_cccf _q) -{ - return qdetector_cccf_get_dphi(_q->detector); -} - -// carrier phase offset estimate -float qdsync_cccf_get_phi(qdsync_cccf _q) -{ - return qdetector_cccf_get_phi(_q->detector); -} - // -// internal methods +// API: floating-point // -// execute synchronizer, seeking preamble sequence -// _q : frame synchronizer object -// _x : input sample -// _sym : demodulated symbol -int qdsync_cccf_execute_detect(qdsync_cccf _q, - float complex _x) -{ - // push through pre-demod synchronizer - float complex * v = qdetector_cccf_execute(_q->detector, _x); - - // check if frame has been detected - if (v != NULL) { - // get estimates - float tau_hat = qdetector_cccf_get_tau (_q->detector); - float gamma_hat = qdetector_cccf_get_gamma(_q->detector); - float dphi_hat = qdetector_cccf_get_dphi (_q->detector); - float phi_hat = qdetector_cccf_get_phi (_q->detector); - - // set appropriate filterbank index - _q->mf_counter = _q->k - 2; - _q->pfb_index = 0; - int index = (int)(tau_hat * _q->npfb); - if (index < 0) { - _q->mf_counter++; - index += _q->npfb; - } - _q->pfb_index = index; - //printf("* qdsync detected! tau:%6.3f, dphi:%12.4e, phi:%6.3f, gamma:%6.2f dB, mf:%u, pfb idx:%u\n", - // tau_hat, dphi_hat, phi_hat, 20*log10f(gamma_hat), _q->mf_counter, _q->pfb_index); - - // output filter scale - firpfb_crcf_set_scale(_q->mf, 1.0f / (_q->k * gamma_hat)); - - // set frequency/phase of mixer - nco_crcf_set_frequency(_q->mixer, dphi_hat); - nco_crcf_set_phase (_q->mixer, phi_hat ); - - // update state - _q->state = QDSYNC_STATE_SYNC; - - // run buffered samples through synchronizer - unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); - qdsync_cccf_execute(_q, v, buf_len); - } - return LIQUID_OK; -} - -// step receiver mixer, matched filter, decimator -// _q : frame synchronizer -// _x : input sample -// _y : output symbol -int qdsync_cccf_step(qdsync_cccf _q, - float complex _x) -{ - // mix sample down - float complex v; - nco_crcf_mix_down(_q->mixer, _x, &v); - nco_crcf_step (_q->mixer); - - // push sample into filterbank - firpfb_crcf_push (_q->mf, v); - firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); - - // increment counter to determine if sample is available - _q->mf_counter++; - int sample_available = (_q->mf_counter >= _q->k-1) ? 1 : 0; - - // set output sample if available - if (sample_available) { - // decrement counter by k=2 samples/symbol - _q->mf_counter -= _q->k; - - // append to output - qdsync_cccf_buf_append(_q, v); - } - - // return flag - return LIQUID_OK; -} +#include "liquid.internal.h" -// append sample to output buffer -int qdsync_cccf_buf_append(qdsync_cccf _q, - float complex _x) -{ - // account for filter delay - _q->symbol_counter++; - if (_q->symbol_counter <= 2*_q->m) - return LIQUID_OK; +// naming extensions (useful for print statements) +#define EXTENSION "cccf" - // append sample to end of buffer - _q->buf_out[_q->buf_out_counter] = _x; - _q->buf_out_counter++; +#define TO float complex // output type +#define TC float complex // coefficients type +#define TI float complex // input type +#define T float // primitive type - // check if buffer is full - if (_q->buf_out_counter == _q->buf_out_len) { - // reset counter - _q->buf_out_counter = 0; +// object references +#define QDSYNC(name) LIQUID_CONCAT(qdsync_cccf,name) +#define QDETECTOR(name) LIQUID_CONCAT(qdetector_cccf,name) - // invoke callback - if (_q->callback != NULL) { - int rc = _q->callback(_q->buf_out, _q->buf_out_len, _q->context); - if (rc) - return qdsync_cccf_reset(_q); - } - } - return LIQUID_OK; -} +// prototypes +#include "qdsync.proto.c" From e6b6cfccdfb19961fff39a909f8229c7b23b3b61 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 May 2023 16:38:05 -0400 Subject: [PATCH 117/334] dsssframe64/example: fixing SNR calculation, adjusting trials --- .../dsssframe64sync_performance_example.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/dsssframe64sync_performance_example.c b/examples/dsssframe64sync_performance_example.c index 8e89e99d7..3d73139d4 100644 --- a/examples/dsssframe64sync_performance_example.c +++ b/examples/dsssframe64sync_performance_example.c @@ -11,10 +11,11 @@ void frame64_add_noise(float complex * _buf, unsigned int _buf_len, float _SNRdB) { - float nstd = powf(10.0f, -_SNRdB/20.0f) * M_SQRT1_2; + float nstd = powf(10.0f, -_SNRdB/20.0f); + nstd *= M_SQRT2; // scale noise to account for signal being over-sampled by 2 unsigned int i; for (i=0; i<_buf_len; i++) - _buf[i] += nstd*( randnf() + _Complex_I*randnf() ); + _buf[i] += nstd*( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; } int main(int argc, char*argv[]) @@ -22,9 +23,9 @@ int main(int argc, char*argv[]) // create frame generator, synchronizer objects dsssframe64gen fg = dsssframe64gen_create(); dsssframe64sync fs = dsssframe64sync_create(NULL,NULL); - unsigned int min_errors = 10; - unsigned int min_trials = 10; - unsigned int max_trials = 800; + unsigned int min_errors = 5; + unsigned int min_trials = 80; + unsigned int max_trials = 1000; // create buffer for the frame samples unsigned int frame_len = dsssframe64gen_get_frame_len(fg); @@ -35,7 +36,8 @@ int main(int argc, char*argv[]) fprintf(fid,"clear all; close all;\n"); fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); printf("# %8s %6s %6s %6s\n", "SNR", "detect", "valid", "trials"); - while (SNRdB < -13.0f) { + fclose(fid); + while (SNRdB < -5.0f) { dsssframe64sync_reset_framedatastats(fs); unsigned int num_trials = 0, num_errors = 0; while (1) { @@ -64,14 +66,17 @@ int main(int argc, char*argv[]) framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); printf(" %8.3f %6u %6u %6u\n", SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials); - fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%g; pvalid(end+1)=%g;\n", + fid = fopen(OUTPUT_FILENAME,"a"); + fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%12g; pvalid(end+1)=%12g;\n", SNRdB, (float)stats.num_frames_detected / (float)num_trials, (float)stats.num_payloads_valid / (float)num_trials); + fclose(fid); if (num_errors < min_errors) break; SNRdB += 1.0f; } + fid = fopen(OUTPUT_FILENAME,"a"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); @@ -80,7 +85,7 @@ int main(int argc, char*argv[]) fprintf(fid,"xlabel('SNR [dB]');\n"); fprintf(fid,"ylabel('Prob. of Error');\n"); fprintf(fid,"legend('detect','decoding','location','northeast');\n"); - fprintf(fid,"axis([-25 0 1e-3 1]);\n"); + fprintf(fid,"axis([-30 10 1e-3 1]);\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); From f50e166890fd0e3f914536906350b489edabd1fe Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 May 2023 16:44:38 -0400 Subject: [PATCH 118/334] dsssframe64: reducing spreading gain from 256 to 128 * the preamble detection (1024 chips) was the limiting factor * spreading to 256 provided no gain over 128 in this case * would need to increase the preamble to be on the order of 2048 * this would have increased the computational complexity for the qdetector beyond what makes sense * the partitioned detector could solve this, but it's not yet complete --- src/framing/src/dsssframe64gen.c | 8 ++++---- src/framing/src/dsssframe64sync.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index afc42af58..f3ac1bbf8 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,7 @@ */ // DS/SS frame generator with fixed fields: 8-byte header, 64-byte payload, -// 256-symbol spreading factor +// 128-symbol spreading factor #include #include @@ -120,7 +120,7 @@ int dsssframe64gen_print(dsssframe64gen _q) // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) { - return 2*(1024 + 650*256 + 2*_q->m); + return 2*(1024 + 650*128 + 2*_q->m); } // generate a frame @@ -172,7 +172,7 @@ int dsssframe64gen_write(dsssframe64gen _q, // frame payload for (i=0; i<650; i++) { float complex sym = _q->payload_tx[i]; // strip out raw payload symbol - for (j=0; j<256; j++) { + for (j=0; j<128; j++) { // generate pseudo-random symbol unsigned int p = msequence_generate_symbol(_q->ms, 2); float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index a1c8a2855..e5091a970 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -283,8 +283,8 @@ int dsssframe64sync_step(dsssframe64sync _q, _q->sym_despread += _buf[i] * conjf(s); _q->chip_counter++; - if (_q->chip_counter == 256) { - _q->payload_rx[_q->payload_counter] = _q->sym_despread / 256.0f; + if (_q->chip_counter == 128) { + _q->payload_rx[_q->payload_counter] = _q->sym_despread / 128.0f; _q->payload_counter++; _q->chip_counter = 0; _q->sym_despread = 0; @@ -303,7 +303,7 @@ int dsssframe64sync_decode(dsssframe64sync _q) { // recover data symbols from pilots qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); - + // decode payload int crc_pass = qpacketmodem_decode(_q->dec, _q->payload_sym, _q->payload_dec); #if 0 @@ -322,13 +322,13 @@ int dsssframe64sync_decode(dsssframe64sync _q) _q->framedatastats.num_headers_valid += crc_pass; _q->framedatastats.num_payloads_valid += crc_pass; _q->framedatastats.num_bytes_received += crc_pass ? 64 : 0; - + // invoke callback int rc = 0; if (_q->callback != NULL) { // offset estimates float dphi_hat = qdsync_cccf_get_dphi(_q->detector) + - qpilotsync_get_dphi(_q->pilotsync) / 256.0f; + qpilotsync_get_dphi(_q->pilotsync) / 128.0f; // set framesyncstats internals _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); @@ -341,7 +341,7 @@ int dsssframe64sync_decode(dsssframe64sync _q) _q->framesyncstats.check = LIQUID_CRC_24; _q->framesyncstats.fec0 = LIQUID_FEC_NONE; _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; - + // invoke callback method rc = _q->callback(&_q->payload_dec[0], // header is first 8 bytes crc_pass, @@ -351,7 +351,7 @@ int dsssframe64sync_decode(dsssframe64sync _q) _q->framesyncstats, _q->context); } - + // reset frame synchronizer and return dsssframe64sync_reset(_q); return rc; From f47e9cf6c949f39cfec548490d9150e84467be6f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 4 Jun 2023 14:57:58 -0400 Subject: [PATCH 119/334] cpfskmod: ensuring phase does not grow and lose precision --- src/modem/src/cpfskmod.c | 34 +++++++++-------- src/modem/tests/cpfskmodem_autotest.c | 53 +++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/modem/src/cpfskmod.c b/src/modem/src/cpfskmod.c index 51f553adb..843022c75 100644 --- a/src/modem/src/cpfskmod.c +++ b/src/modem/src/cpfskmod.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // continuous phase frequency-shift keying modulator -// #include #include @@ -61,7 +59,7 @@ struct cpfskmod_s { // phase integrator float * phase_interp; // phase interpolation buffer - iirfilt_rrrf integrator; // integrator + float b0, b1, a1, v0, v1; // integrator }; // create cpfskmod object (frequency modulator) @@ -105,8 +103,9 @@ cpfskmod cpfskmod_create(unsigned int _bps, q->M = 1 << q->bps; // constellation size // create object depending upon input type - float b[2] = {0.5f, 0.5f}; // integrator feed-forward coefficients - float a[2] = {1.0f, -1.0f}; // integrator feed-back coefficients + q->b0 = 0.5f; + q->b1 = 0.5f; + q->a1 = -1.0f; q->ht_len = 0; q->ht = NULL; unsigned int i; @@ -115,8 +114,8 @@ cpfskmod cpfskmod_create(unsigned int _bps, q->ht_len = q->k; q->symbol_delay = 1; // modify integrator - b[0] = 0.0f; - b[1] = 1.0f; + q->b0 = 0.0f; + q->b1 = 1.0f; break; case LIQUID_CPFSK_RCOS_FULL: q->ht_len = q->k; @@ -142,9 +141,8 @@ cpfskmod cpfskmod_create(unsigned int _bps, q->ht[i] *= M_PI * q->h; q->interp = firinterp_rrrf_create(q->k, q->ht, q->ht_len); - // create phase integrator + // allocate buffer for phase interpolation q->phase_interp = (float*) malloc(q->k*sizeof(float)); - q->integrator = iirfilt_rrrf_create(b,2,a,2); // reset modem object cpfskmod_reset(q); @@ -160,9 +158,6 @@ int cpfskmod_destroy(cpfskmod _q) free(_q->phase_interp); firinterp_rrrf_destroy(_q->interp); - // destroy phase integrator - iirfilt_rrrf_destroy(_q->integrator); - // free main object memory free(_q); return LIQUID_OK; @@ -200,7 +195,8 @@ int cpfskmod_reset(cpfskmod _q) firinterp_rrrf_reset(_q->interp); // reset phase integrator - iirfilt_rrrf_reset(_q->integrator); + _q->v0 = 0.0f; + _q->v1 = 0.0f; return LIQUID_OK; } @@ -227,7 +223,15 @@ int cpfskmod_modulate(cpfskmod _q, float theta; for (i=0; i<_q->k; i++) { // push phase through integrator - iirfilt_rrrf_execute(_q->integrator, _q->phase_interp[i], &theta); + _q->v0 = _q->phase_interp[i] - _q->v1*_q->a1; + theta = _q->v0*_q->b0 + _q->v1*_q->b1; + _q->v1 = _q->v0; + + // constrain state + if (_q->v1 > 2*M_PI) + _q->v1 -= 2*M_PI; + if (_q->v1 < -2*M_PI) + _q->v1 += 2*M_PI; // compute output _y[i] = liquid_cexpjf(theta); diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index 354144338..27f57c073 100644 --- a/src/modem/tests/cpfskmodem_autotest.c +++ b/src/modem/tests/cpfskmodem_autotest.c @@ -118,3 +118,56 @@ void autotest_cpfskmodem_bps2_h0p0250_k4_m3_square() { cpfskmodem_test_mod_de void autotest_cpfskmodem_bps3_h0p1250_k4_m3_square() { cpfskmodem_test_mod_demod( 3, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps4_h0p0625_k4_m3_square() { cpfskmodem_test_mod_demod( 4, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } +// test spectral response +void autotest_cpfskmodem_spectrum() +{ + // create modulator + unsigned int bps = 1; + float h = 0.5f; + unsigned int k = 4; + unsigned int m = 3; + float beta = 0.35f; + int type = LIQUID_CPFSK_RCOS_PARTIAL; + cpfskmod mod = cpfskmod_create(bps, h, k, m, beta, type); + + // spectral periodogram options + unsigned int nfft = 2400; // spectral periodogram FFT size + unsigned int num_symbols = 192000; // number of symbols to generate + float complex buf[k]; + unsigned int i; + + // modulate many, many symbols + for (i=0; i<(1U<<24U); i++) + cpfskmod_modulate(mod, 0, buf); + + // modulate several symbols and run result through spectral estimate + spgramcf periodogram = spgramcf_create_default(nfft); + for (i=0; i Date: Sun, 4 Jun 2023 17:11:43 -0400 Subject: [PATCH 120/334] build: removing unused variables --- sandbox/fec_spc2216_test.c | 17 ++++++++++------- scripts/autoscript.c | 1 + src/random/src/randgamma.c | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sandbox/fec_spc2216_test.c b/sandbox/fec_spc2216_test.c index edd5f27a1..9a66df79a 100644 --- a/sandbox/fec_spc2216_test.c +++ b/sandbox/fec_spc2216_test.c @@ -253,9 +253,9 @@ int main(int argc, char*argv[]) // // run SNR trials // - float SNRdB_min = -1.0f; // signal-to-noise ratio (minimum) - float SNRdB_max = 7.0f; // signal-to-noise ratio (maximum) - unsigned int num_snr = 33; // number of SNR steps + float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) + float SNRdB_max = 10.0f; // signal-to-noise ratio (maximum) + unsigned int num_snr = 31; // number of SNR steps unsigned int num_trials=10000; // number of trials // arrays @@ -484,14 +484,15 @@ void spc2216_decode(unsigned char * _msg_rec, spc2216_transpose_col(w, m_hat, parity_row); // compute syndromes on rows and decode +#if DEBUG_SPC2216 unsigned int num_uncorrected_errors = 0; +#endif for (i=0; i<16; i++) { sym_enc[0] = parity_row[i]; sym_enc[1] = m_hat[2*i+0]; sym_enc[2] = m_hat[2*i+1]; - int syndrome_flag = fec_secded2216_estimate_ehat(sym_enc, e_hat); - #if DEBUG_SPC2216 + int syndrome_flag = fec_secded2216_estimate_ehat(sym_enc, e_hat); if (syndrome_flag == 0) { printf("%3u : no errors detected\n", i); } else if (syndrome_flag == 1) { @@ -499,10 +500,10 @@ void spc2216_decode(unsigned char * _msg_rec, } else { printf("%3u : multiple errors detected\n", i); } -#endif if (syndrome_flag == 2) num_uncorrected_errors++; +#endif // apply error vector estimate to appropriate arrays parity_col[i] ^= e_hat[0]; @@ -510,7 +511,9 @@ void spc2216_decode(unsigned char * _msg_rec, m_hat[2*i+1] ^= e_hat[2]; } - //printf("number of uncorrected errors: %u\n", num_uncorrected_errors); +#if DEBUG_SPC2216 + printf("number of uncorrected errors: %u\n", num_uncorrected_errors); +#endif // copy decoded message to output memmove(_msg_dec, m_hat, 32*sizeof(unsigned char)); diff --git a/scripts/autoscript.c b/scripts/autoscript.c index 14ca83be0..f71533af8 100644 --- a/scripts/autoscript.c +++ b/scripts/autoscript.c @@ -339,6 +339,7 @@ void autoscript_parsefile(autoscript _q, package_added = 1; } autoscript_addscript(_q, _package_name, basename); + printf("// adding %s to package %s from %s:%u\n", basename, _package_name, _filename, n); } } while (!feof(fid)); diff --git a/src/random/src/randgamma.c b/src/random/src/randgamma.c index 43f819798..2faa8c18f 100644 --- a/src/random/src/randgamma.c +++ b/src/random/src/randgamma.c @@ -145,7 +145,7 @@ float randgammaf_delta(float _delta) float V1 = 0.0f; float V2 = 0.0f; - unsigned int m = 1; + //unsigned int m = 1; float xi = 0.0f; float eta = 0.0f; @@ -168,7 +168,7 @@ float randgammaf_delta(float _delta) // step 6 if ( eta > powf(xi,_delta-1.0f)*expf(-xi) ) { - m++; + //m++; } else { break; } From 2e76e501bd3576c686fb3c72fa0ba014af96241f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 10 Jun 2023 14:45:49 -0400 Subject: [PATCH 121/334] qpacketmodem: moving to pre-processor macro --- include/liquid.h | 186 +++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 88 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index ea16f3fb3..08c168373 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5217,96 +5217,106 @@ typedef int (*framesync_callback)(unsigned char * _header, // _userdata : user-defined data pointer typedef void (*framesync_csma_callback)(void * _userdata); -// -// packet encoder/decoder -// -typedef struct qpacketmodem_s * qpacketmodem; +#define LIQUID_QPACKETMODEM_MANGLE_RRRF(name) LIQUID_CONCAT(qpacketmodem,name) -// create packet encoder -qpacketmodem qpacketmodem_create (); -qpacketmodem qpacketmodem_copy (qpacketmodem _q); -int qpacketmodem_destroy(qpacketmodem _q); -int qpacketmodem_reset (qpacketmodem _q); -int qpacketmodem_print (qpacketmodem _q); - -int qpacketmodem_configure(qpacketmodem _q, - unsigned int _payload_len, - crc_scheme _check, - fec_scheme _fec0, - fec_scheme _fec1, - int _ms); - -// get length of encoded frame in symbols -unsigned int qpacketmodem_get_frame_len(qpacketmodem _q); - -// get unencoded/decoded payload length (bytes) -unsigned int qpacketmodem_get_payload_len(qpacketmodem _q); - -// regular access methods -unsigned int qpacketmodem_get_crc (qpacketmodem _q); -unsigned int qpacketmodem_get_fec0 (qpacketmodem _q); -unsigned int qpacketmodem_get_fec1 (qpacketmodem _q); -unsigned int qpacketmodem_get_modscheme(qpacketmodem _q); - -float qpacketmodem_get_demodulator_phase_error(qpacketmodem _q); -float qpacketmodem_get_demodulator_evm(qpacketmodem _q); - -// encode packet into un-modulated frame symbol indices -// _q : qpacketmodem object -// _payload : unencoded payload bytes -// _syms : encoded but un-modulated payload symbol indices -int qpacketmodem_encode_syms(qpacketmodem _q, - const unsigned char * _payload, - unsigned char * _syms); - -// decode packet from demodulated frame symbol indices (hard-decision decoding) -// _q : qpacketmodem object -// _syms : received hard-decision symbol indices, [size: frame_len x 1] -// _payload : recovered decoded payload bytes -int qpacketmodem_decode_syms(qpacketmodem _q, - unsigned char * _syms, - unsigned char * _payload); - -// decode packet from demodulated frame bits (soft-decision decoding) -// _q : qpacketmodem object -// _bits : received soft-decision bits, [size: bps*frame_len x 1] -// _payload : recovered decoded payload bytes -int qpacketmodem_decode_bits(qpacketmodem _q, - unsigned char * _bits, - unsigned char * _payload); - -// encode and modulate packet into modulated frame samples -// _q : qpacketmodem object -// _payload : unencoded payload bytes -// _frame : encoded/modulated payload symbols -int qpacketmodem_encode(qpacketmodem _q, - const unsigned char * _payload, - liquid_float_complex * _frame); - -// decode packet from modulated frame samples, returning flag if CRC passed -// NOTE: hard-decision decoding -// _q : qpacketmodem object -// _frame : encoded/modulated payload symbols -// _payload : recovered decoded payload bytes -int qpacketmodem_decode(qpacketmodem _q, - liquid_float_complex * _frame, - unsigned char * _payload); - -// decode packet from modulated frame samples, returning flag if CRC passed -// NOTE: soft-decision decoding -// _q : qpacketmodem object -// _frame : encoded/modulated payload symbols -// _payload : recovered decoded payload bytes -int qpacketmodem_decode_soft(qpacketmodem _q, - liquid_float_complex * _frame, - unsigned char * _payload); - -int qpacketmodem_decode_soft_sym(qpacketmodem _q, - liquid_float_complex _symbol); - -int qpacketmodem_decode_soft_payload(qpacketmodem _q, - unsigned char * _payload); +// Macro: +// QPACKETMODEM : name-mangling macro +// T : data type +#define LIQUID_QPACKETMODEM_DEFINE_API(QPACKETMODEM,T) \ + \ +/* Packet encoder/decoder */ \ +typedef struct QPACKETMODEM(_s) * QPACKETMODEM(); \ + \ +/* Create packet encoder */ \ +QPACKETMODEM() QPACKETMODEM(_create)(); \ + \ +QPACKETMODEM() QPACKETMODEM(_copy) (QPACKETMODEM() _q); \ +int QPACKETMODEM(_destroy)(QPACKETMODEM() _q); \ +int QPACKETMODEM(_reset) (QPACKETMODEM() _q); \ +int QPACKETMODEM(_print) (QPACKETMODEM() _q); \ + \ +int QPACKETMODEM(_configure)(QPACKETMODEM() _q, \ + unsigned int _payload_len, \ + crc_scheme _check, \ + fec_scheme _fec0, \ + fec_scheme _fec1, \ + int _ms); \ + \ +/* get length of encoded frame in symbols */ \ +unsigned int QPACKETMODEM(_get_frame_len)(QPACKETMODEM() _q); \ + \ +/* get unencoded/decoded payload length (bytes) */ \ +unsigned int QPACKETMODEM(_get_payload_len)(QPACKETMODEM() _q); \ + \ +/* regular access methods */ \ +unsigned int QPACKETMODEM(_get_crc )(QPACKETMODEM() _q); \ +unsigned int QPACKETMODEM(_get_fec0 )(QPACKETMODEM() _q); \ +unsigned int QPACKETMODEM(_get_fec1 )(QPACKETMODEM() _q); \ +unsigned int QPACKETMODEM(_get_modscheme)(QPACKETMODEM() _q); \ + \ +float QPACKETMODEM(_get_demodulator_phase_error)(QPACKETMODEM() _q); \ +float QPACKETMODEM(_get_demodulator_evm)(QPACKETMODEM() _q); \ + \ +/* encode packet into un-modulated frame symbol indices */ \ +/* _q : qpacketmodem object */ \ +/* _payload : unencoded payload bytes */ \ +/* _syms : encoded but un-modulated payload symbol indices */ \ +int QPACKETMODEM(_encode_syms)(QPACKETMODEM() _q, \ + const unsigned char * _payload, \ + unsigned char * _syms); \ + \ +/* decode packet from demodulated frame symbol indices (hard-decision */ \ +/* decoding) */ \ +/* _q : qpacketmodem object */ \ +/* _syms : received hard-decision symbol indices, */ \ +/* [size: frame_len x 1] */ \ +/* _payload : recovered decoded payload bytes */ \ +int QPACKETMODEM(_decode_syms)(QPACKETMODEM() _q, \ + unsigned char * _syms, \ + unsigned char * _payload); \ + \ +/* decode packet from demodulated frame bits (soft-decision decoding) */ \ +/* _q : qpacketmodem object */ \ +/* _bits : received soft-decision bits, [size: bps*frame_len x 1] */ \ +/* _payload : recovered decoded payload bytes */ \ +int QPACKETMODEM(_decode_bits)(QPACKETMODEM() _q, \ + unsigned char * _bits, \ + unsigned char * _payload); \ + \ +/* encode and modulate packet into modulated frame samples */ \ +/* _q : qpacketmodem object */ \ +/* _payload : unencoded payload bytes */ \ +/* _frame : encoded/modulated payload symbols */ \ +int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ + const unsigned char * _payload, \ + liquid_float_complex * _frame); \ + \ +/* decode packet from modulated frame samples, returning flag if CRC */ \ +/* passed using hard-decision decoding */ \ +/* _q : qpacketmodem object */ \ +/* _frame : encoded/modulated payload symbols */ \ +/* _payload : recovered decoded payload bytes */ \ +int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ + liquid_float_complex * _frame, \ + unsigned char * _payload); \ + \ +/* decode packet from modulated frame samples, returning flag if CRC */ \ +/* passed using soft-decision decoding */ \ +/* _q : qpacketmodem object */ \ +/* _frame : encoded/modulated payload symbols */ \ +/* _payload : recovered decoded payload bytes */ \ +int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ + liquid_float_complex * _frame, \ + unsigned char * _payload); \ + \ +int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ + liquid_float_complex _symbol); \ + \ +int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ + unsigned char * _payload); \ + +LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_RRRF, float) // // pilot generator/synchronizer for packet burst recovery From ab70c185d8ae397751246ae007303190066eb179 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 11 Jun 2023 11:19:22 -0400 Subject: [PATCH 122/334] build/framing: consolidating prototype sources --- makefile.in | 41 +++++++------- src/framing/src/bpresync_cccf.c | 53 ------------------- src/framing/src/bsync.proto.c | 30 +++++------ src/framing/src/bsync_cccf.c | 47 ---------------- src/framing/src/bsync_rrrf.c | 47 ---------------- .../src/{symtrack_cccf.c => framing_cccf.c} | 33 ++++++++---- .../src/{bsync_crcf.c => framing_crcf.c} | 35 ++++++++---- .../src/{presync_cccf.c => framing_rrrf.c} | 44 ++++++++------- .../src/{symstreamrcf.c => framingcf.c} | 22 ++++++-- src/framing/src/msourcecf.c | 49 ----------------- .../{qpacketmodem.c => qpacketmodem.proto.c} | 0 src/framing/src/symstreamcf.c | 45 ---------------- 12 files changed, 124 insertions(+), 322 deletions(-) delete mode 100644 src/framing/src/bpresync_cccf.c delete mode 100644 src/framing/src/bsync_cccf.c delete mode 100644 src/framing/src/bsync_rrrf.c rename src/framing/src/{symtrack_cccf.c => framing_cccf.c} (75%) rename src/framing/src/{bsync_crcf.c => framing_crcf.c} (60%) rename src/framing/src/{presync_cccf.c => framing_rrrf.c} (62%) rename src/framing/src/{symstreamrcf.c => framingcf.c} (68%) delete mode 100644 src/framing/src/msourcecf.c rename src/framing/src/{qpacketmodem.c => qpacketmodem.proto.c} (100%) delete mode 100644 src/framing/src/symstreamcf.c diff --git a/makefile.in b/makefile.in index d92ca74c8..d8d0ba37b 100644 --- a/makefile.in +++ b/makefile.in @@ -630,10 +630,6 @@ filter_benchmarks := \ framing_objects := \ src/framing/src/bpacketgen.o \ src/framing/src/bpacketsync.o \ - src/framing/src/bpresync_cccf.o \ - src/framing/src/bsync_rrrf.o \ - src/framing/src/bsync_crcf.o \ - src/framing/src/bsync_cccf.o \ src/framing/src/detector_cccf.o \ src/framing/src/dsssframegen.o \ src/framing/src/dsssframesync.o \ @@ -641,34 +637,46 @@ framing_objects := \ src/framing/src/framesyncstats.o \ src/framing/src/framegen64.o \ src/framing/src/framesync64.o \ + src/framing/src/framingcf.o \ + src/framing/src/framing_rrrf.o \ + src/framing/src/framing_crcf.o \ + src/framing/src/framing_cccf.o \ src/framing/src/flexframegen.o \ src/framing/src/flexframesync.o \ src/framing/src/fskframegen.o \ src/framing/src/fskframesync.o \ src/framing/src/gmskframegen.o \ src/framing/src/gmskframesync.o \ - src/framing/src/msourcecf.o \ src/framing/src/ofdmflexframegen.o \ src/framing/src/ofdmflexframesync.o \ - src/framing/src/presync_cccf.o \ - src/framing/src/symstreamcf.o \ - src/framing/src/symstreamrcf.o \ - src/framing/src/symtrack_cccf.o \ src/framing/src/qdetector_cccf.o \ src/framing/src/qdsync_cccf.o \ - src/framing/src/qpacketmodem.o \ src/framing/src/qpilotgen.o \ src/framing/src/qpilotsync.o \ # list explicit targets and dependencies here +framing_prototypes_gen := \ + src/framing/src/msource.proto.c \ + src/framing/src/qpacketmodem.proto.c \ + src/framing/src/qsource.proto.c \ + src/framing/src/symstream.proto.c \ + src/framing/src/symstreamr.proto.c \ + +framing_prototypes_sync := \ + src/framing/src/bpresync.proto.c \ + src/framing/src/bsync.proto.c \ + src/framing/src/presync.proto.c \ + src/framing/src/symtrack.proto.c \ + +src/framing/src/framingcf.o : %.o : %.c $(include_headers) ${framing_prototypes_gen} +src/framing/src/framing_rrrf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} +src/framing/src/framing_crcf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} +src/framing/src/framing_cccf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} + src/framing/src/bpacketgen.o : %.o : %.c $(include_headers) src/framing/src/bpacketsync.o : %.o : %.c $(include_headers) -src/framing/src/bpresync_cccf.o : %.o : %.c $(include_headers) src/framing/src/bpresync.proto.c -src/framing/src/bsync_rrrf.o : %.o : %.c $(include_headers) src/framing/src/bsync.proto.c -src/framing/src/bsync_crcf.o : %.o : %.c $(include_headers) src/framing/src/bsync.proto.c -src/framing/src/bsync_cccf.o : %.o : %.c $(include_headers) src/framing/src/bsync.proto.c src/framing/src/detector_cccf.o : %.o : %.c $(include_headers) src/framing/src/dsssframegen.o : %.o : %.c $(include_headers) src/framing/src/dsssframesync.o : %.o : %.c $(include_headers) @@ -678,14 +686,9 @@ src/framing/src/framegen64.o : %.o : %.c $(include_headers) src/framing/src/framesync64.o : %.o : %.c $(include_headers) src/framing/src/flexframegen.o : %.o : %.c $(include_headers) src/framing/src/flexframesync.o : %.o : %.c $(include_headers) -src/framing/src/msourcecf.o : %.o : %.c $(include_headers) src/framing/src/msource.proto.c src/framing/src/qsource.proto.c src/framing/src/ofdmflexframegen.o : %.o : %.c $(include_headers) src/framing/src/ofdmflexframesync.o : %.o : %.c $(include_headers) -src/framing/src/presync_cccf.o : %.o : %.c $(include_headers) src/framing/src/presync.proto.c src/framing/src/qpacketmodem.o : %.o : %.c $(include_headers) -src/framing/src/symstreamcf.o : %.o : %.c $(include_headers) src/framing/src/symstream.proto.c -src/framing/src/symstreamrcf.o : %.o : %.c $(include_headers) src/framing/src/symstreamr.proto.c -src/framing/src/symtrack_cccf.o : %.o : %.c $(include_headers) src/framing/src/symtrack.proto.c framing_autotests := \ diff --git a/src/framing/src/bpresync_cccf.c b/src/framing/src/bpresync_cccf.c deleted file mode 100644 index e1b3b987a..000000000 --- a/src/framing/src/bpresync_cccf.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// Binary pre-demod synchronizer -// - -#include "liquid.internal.h" - -// -#define BPRESYNC(name) LIQUID_CONCAT(bpresync_cccf,name) - -// print and naming extensions -#define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) -#define EXTENSION_SHORT "f" -#define EXTENSION_FULL "cccf" - -#define TO float complex -#define TC float complex -#define TI float complex - -#define ABS(X) cabsf(X) -#define REAL(X) crealf(X) -#define IMAG(X) cimagf(X) - -#define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) - -#define TO_COMPLEX -#define TC_COMPLEX -#define TI_COMPLEX - -// prototypes -#include "bpresync.proto.c" - diff --git a/src/framing/src/bsync.proto.c b/src/framing/src/bsync.proto.c index 22cc681a3..2246df36a 100644 --- a/src/framing/src/bsync.proto.c +++ b/src/framing/src/bsync.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,11 +36,11 @@ struct BSYNC(_s) { bsequence sync_i; // synchronization pattern (in-phase) bsequence sym_i; // received symbols (in-phase) -//#if defined TC_COMPLEX +//#if TC_COMPLEX==1 bsequence sync_q; // synchronization pattern (quadrature) //#endif -//#if defined TI_COMPLEX +//#if TI_COMPLEX==1 bsequence sym_q; // received symbols (quadrature) //#endif TO rxy; // cross correlation @@ -52,19 +52,19 @@ BSYNC() BSYNC(_create)(unsigned int _n, TC * _v) fs->n = _n; fs->sync_i = bsequence_create(fs->n); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 fs->sync_q = bsequence_create(fs->n); #endif fs->sym_i = bsequence_create(fs->n); -#ifdef TI_COMPLEX +#if TI_COMPLEX==1 fs->sym_q = bsequence_create(fs->n); #endif unsigned int i; for (i=0; in; i++) { bsequence_push(fs->sync_i, crealf(_v[i])>0); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 bsequence_push(fs->sync_q, cimagf(_v[i])>0); #endif } @@ -89,12 +89,12 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, unsigned int n = msequence_get_length(ms); fs->sync_i = bsequence_create(n * _k); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 fs->sync_q = bsequence_create(n * _k); #endif fs->sym_i = bsequence_create(n * _k); -#ifdef TI_COMPLEX +#if TI_COMPLEX==1 fs->sym_q = bsequence_create(n * _k); #endif @@ -102,7 +102,7 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, #if 0 bsequence_init_msequence(fs->sync_i,ms); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 msequence_reset(ms); bsequence_init_msequence(fs->sync_q,ms); #endif @@ -114,7 +114,7 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, for (j=0; j<_k; j++) { bsequence_push(fs->sync_i, bit); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 bsequence_push(fs->sync_q, bit); #endif } @@ -131,12 +131,12 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, void BSYNC(_destroy)(BSYNC() _fs) { bsequence_destroy(_fs->sync_i); -#ifdef TC_COMPLEX +#if TC_COMPLEX==1 bsequence_destroy(_fs->sync_q); #endif bsequence_destroy(_fs->sym_i); -#ifdef TI_COMPLEX +#if TI_COMPLEX==1 bsequence_destroy(_fs->sym_q); #endif free(_fs); @@ -151,12 +151,12 @@ void BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) { // push symbol into buffers bsequence_push(_fs->sym_i, crealf(_sym)>0.0 ? 1 : 0); -#ifdef TI_COMPLEX +#if TI_COMPLEX==1 bsequence_push(_fs->sym_q, cimagf(_sym)>0.0 ? 1 : 0); #endif // compute dotprod -#if defined TC_COMPLEX && defined TI_COMPLEX +#if TC_COMPLEX==1 && TI_COMPLEX==1 // cccx TO rxy_ii = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_i) - (float)(_fs->n); TO rxy_qq = 2.*bsequence_correlate(_fs->sync_q, _fs->sym_q) - (float)(_fs->n); @@ -164,7 +164,7 @@ void BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) TO rxy_qi = 2.*bsequence_correlate(_fs->sync_q, _fs->sym_i) - (float)(_fs->n); _fs->rxy = (rxy_ii - rxy_qq) + _Complex_I*(rxy_iq + rxy_qi); -#elif defined TI_COMPLEX +#elif TI_COMPLEX==1 // crcx float rxy_ii = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_i) - (float)(_fs->n); float rxy_iq = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_q) - (float)(_fs->n); diff --git a/src/framing/src/bsync_cccf.c b/src/framing/src/bsync_cccf.c deleted file mode 100644 index 4ac9fe834..000000000 --- a/src/framing/src/bsync_cccf.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// Framing API: floating-point -// - -#include "liquid.internal.h" - -// -#define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) - -#define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) - -#define TO float complex -#define TC float complex -#define TI float complex -#define ABS(X) cabsf(X) -#define WINDOW(name) LIQUID_CONCAT(windowcf,name) -#define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) - -#define TO_COMPLEX -#define TC_COMPLEX -#define TI_COMPLEX - -// prototypes -#include "bsync.proto.c" - diff --git a/src/framing/src/bsync_rrrf.c b/src/framing/src/bsync_rrrf.c deleted file mode 100644 index 39b9a82ce..000000000 --- a/src/framing/src/bsync_rrrf.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// Framing API: floating-point -// - -#include "liquid.internal.h" - -// -#define BSYNC(name) LIQUID_CONCAT(bsync_rrrf,name) - -#define PRINTVAL(x) printf("%12.4e", x) - -#define TO float -#define TC float -#define TI float -#define ABS(X) fabsf(X) -#define WINDOW(name) LIQUID_CONCAT(windowf,name) -#define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) - -#undef TO_COMPLEX -#undef TC_COMPLEX -#undef TI_COMPLEX - -// prototypes -#include "bsync.proto.c" - diff --git a/src/framing/src/symtrack_cccf.c b/src/framing/src/framing_cccf.c similarity index 75% rename from src/framing/src/symtrack_cccf.c rename to src/framing/src/framing_cccf.c index 26f863fe1..599e2b23a 100644 --- a/src/framing/src/symtrack_cccf.c +++ b/src/framing/src/framing_cccf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// Framing API: floating-point -// +// complex floating-point synchronization and supporting objects #include "liquid.internal.h" @@ -37,19 +35,32 @@ #define TC float complex #define TI float complex #define ABS(X) cabsf(X) +#define REAL(X) crealf(X) +#define IMAG(X) cimagf(X) -// object references -#define SYMTRACK(name) LIQUID_CONCAT(symtrack_cccf,name) +#define TO_COMPLEX 1 +#define TC_COMPLEX 1 +#define TI_COMPLEX 1 + +// supporting references #define AGC(name) LIQUID_CONCAT(agc_crcf,name) -#define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) +#define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) +#define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define EQLMS(name) LIQUID_CONCAT(eqlms_cccf,name) -#define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) +#define NCO(name) LIQUID_CONCAT(nco_crcf,name) +#define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) +#define WINDOW(name) LIQUID_CONCAT(windowf,name) -#define TO_COMPLEX 1 -#define TC_COMPLEX 1 -#define TI_COMPLEX 1 +// object references +#define BPRESYNC(name) LIQUID_CONCAT(bpresync_cccf,name) +#define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) +#define PRESYNC(name) LIQUID_CONCAT(presync_cccf,name) +#define SYMTRACK(name) LIQUID_CONCAT(symtrack_cccf,name) // prototypes +#include "bpresync.proto.c" +#include "bsync.proto.c" +#include "presync.proto.c" #include "symtrack.proto.c" diff --git a/src/framing/src/bsync_crcf.c b/src/framing/src/framing_crcf.c similarity index 60% rename from src/framing/src/bsync_crcf.c rename to src/framing/src/framing_crcf.c index b6b470784..330f6c188 100644 --- a/src/framing/src/bsync_crcf.c +++ b/src/framing/src/framing_crcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,27 +20,40 @@ * THE SOFTWARE. */ -// -// Framing API: floating-point -// +// complex floating-point synchronization and supporting objects #include "liquid.internal.h" -// -#define BSYNC(name) LIQUID_CONCAT(bsync_crcf,name) +// naming extensions (useful for print statements) +#define EXTENSION_SHORT "f" +#define EXTENSION_FULL "crcf" #define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) +#define T float #define TO float complex #define TC float #define TI float complex #define ABS(X) cabsf(X) -#define WINDOW(name) LIQUID_CONCAT(windowcf,name) -#define DOTPROD(name) LIQUID_CONCAT(dotprod_crcf,name) +#define REAL(X) crealf(X) +#define IMAG(X) cimagf(X) + +#define TO_COMPLEX 1 +#define TC_COMPLEX 0 +#define TI_COMPLEX 1 -#define TO_COMPLEX -#undef TC_COMPLEX -#define TI_COMPLEX +// supporting references +#define AGC(name) LIQUID_CONCAT(agc_crcf,name) +#define BSYNC(name) LIQUID_CONCAT(bsync_crcf,name) +#define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) +#define EQLMS(name) LIQUID_CONCAT(eqlms_crcf,name) +#define MODEM(name) LIQUID_CONCAT(modemcf,name) +#define NCO(name) LIQUID_CONCAT(nco_crcf,name) +#define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) +#define WINDOW(name) LIQUID_CONCAT(windowf,name) + +// object references +#define BSYNC(name) LIQUID_CONCAT(bsync_crcf,name) // prototypes #include "bsync.proto.c" diff --git a/src/framing/src/presync_cccf.c b/src/framing/src/framing_rrrf.c similarity index 62% rename from src/framing/src/presync_cccf.c rename to src/framing/src/framing_rrrf.c index 12ad70a19..361f343a6 100644 --- a/src/framing/src/presync_cccf.c +++ b/src/framing/src/framing_rrrf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,37 +20,41 @@ * THE SOFTWARE. */ -// -// Binary pre-demod synchronizer -// +// real floating-point synchronization and supporting objects #include "liquid.internal.h" -// -#define PRESYNC(name) LIQUID_CONCAT(presync_cccf,name) - -// print and naming extensions -#define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) +// naming extensions (useful for print statements) #define EXTENSION_SHORT "f" -#define EXTENSION_FULL "cccf" +#define EXTENSION_FULL "rrrf" -#define T float // primitive type -#define TO float complex // output type -#define TC float complex // coefficient type -#define TI float complex // input type +#define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) +#define T float +#define TO float +#define TC float +#define TI float #define ABS(X) cabsf(X) #define REAL(X) crealf(X) #define IMAG(X) cimagf(X) -#define WINDOW(name) LIQUID_CONCAT(windowf,name) +#define TO_COMPLEX 0 +#define TC_COMPLEX 0 +#define TI_COMPLEX 0 + +// supporting references +#define AGC(name) LIQUID_CONCAT(agc_rrrf,name) +#define BSYNC(name) LIQUID_CONCAT(bsync_rrrf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) -#define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) +#define EQLMS(name) LIQUID_CONCAT(eqlms_rrrf,name) +#define MODEM(name) LIQUID_CONCAT(modemcf,name) +#define NCO(name) LIQUID_CONCAT(nco_rrrf,name) +#define SYMSYNC(name) LIQUID_CONCAT(symsync_rrrf,name) +#define WINDOW(name) LIQUID_CONCAT(windowf,name) -#define TO_COMPLEX -#define TC_COMPLEX -#define TI_COMPLEX +// object references +#define BSYNC(name) LIQUID_CONCAT(bsync_rrrf,name) // prototypes -#include "presync.proto.c" +#include "bsync.proto.c" diff --git a/src/framing/src/symstreamrcf.c b/src/framing/src/framingcf.c similarity index 68% rename from src/framing/src/symstreamrcf.c rename to src/framing/src/framingcf.c index b1d2b91e7..aeb19f8b5 100644 --- a/src/framing/src/symstreamrcf.c +++ b/src/framing/src/framingcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// API: floating-point -// +// complex floating-point framing and signal generators #include "liquid.internal.h" @@ -35,11 +33,25 @@ #define TO_COMPLEX 1 #define T_COMPLEX 0 -// object references +// supporting references +#define FIRINTERP(name) LIQUID_CONCAT(firinterp_crcf,name) +#define IIRFILT(name) LIQUID_CONCAT(iirfilt_crcf, name) +#define MODEM(name) LIQUID_CONCAT(modemcf, name) #define MSRESAMP(name) LIQUID_CONCAT(msresamp_crcf,name) +#define NCO(name) LIQUID_CONCAT(nco_crcf, name) +#define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf, name) + +// object references +#define MSOURCE(name) LIQUID_CONCAT(msourcecf, name) +#define QPACKETMODEM(name) LIQUID_CONCAT(qpacketmodem, name) +#define QSOURCE(name) LIQUID_CONCAT(qsourcecf, name) #define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf, name) #define SYMSTREAMR(name) LIQUID_CONCAT(symstreamrcf, name) // prototypes +#include "msource.proto.c" +#include "qpacketmodem.proto.c" +#include "qsource.proto.c" +#include "symstream.proto.c" #include "symstreamr.proto.c" diff --git a/src/framing/src/msourcecf.c b/src/framing/src/msourcecf.c deleted file mode 100644 index 6013e826c..000000000 --- a/src/framing/src/msourcecf.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// API: floating-point -// - -#include "liquid.internal.h" - -// naming extensions (useful for print statements) -#define EXTENSION "cf" - -#define TO float complex // output type -#define T float // primitive type - -#define TO_COMPLEX 1 -#define T_COMPLEX 0 - -// object references -#define QSOURCE(name) LIQUID_CONCAT(qsourcecf,name) -#define MSOURCE(name) LIQUID_CONCAT(msourcecf,name) - -#define IIRFILT(name) LIQUID_CONCAT(iirfilt_crcf,name) -#define NCO(name) LIQUID_CONCAT(nco_crcf,name) -#define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf,name) - -// prototypes -#include "msource.proto.c" -#include "qsource.proto.c" - diff --git a/src/framing/src/qpacketmodem.c b/src/framing/src/qpacketmodem.proto.c similarity index 100% rename from src/framing/src/qpacketmodem.c rename to src/framing/src/qpacketmodem.proto.c diff --git a/src/framing/src/symstreamcf.c b/src/framing/src/symstreamcf.c deleted file mode 100644 index 780157f7b..000000000 --- a/src/framing/src/symstreamcf.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2007 - 2022 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// API: floating-point -// - -#include "liquid.internal.h" - -// naming extensions (useful for print statements) -#define EXTENSION "cf" - -#define TO float complex // output type -#define T float // primitive type - -#define TO_COMPLEX 1 -#define T_COMPLEX 0 - -// object references -#define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf,name) -#define MODEM(name) LIQUID_CONCAT(modemcf,name) -#define FIRINTERP(name) LIQUID_CONCAT(firinterp_crcf,name) - -// prototypes -#include "symstream.proto.c" - From 88edbda21c73b01aa7f05ea80c3724d750ebd1d0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 11 Jun 2023 11:36:07 -0400 Subject: [PATCH 123/334] qpacketmodem: extending prototype into macro --- src/framing/src/qpacketmodem.proto.c | 88 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/framing/src/qpacketmodem.proto.c b/src/framing/src/qpacketmodem.proto.c index 6b5a3e433..96ee3c0a9 100644 --- a/src/framing/src/qpacketmodem.proto.c +++ b/src/framing/src/qpacketmodem.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,9 +31,9 @@ #include "liquid.internal.h" -struct qpacketmodem_s { +struct QPACKETMODEM(_s) { // properties - modemcf mod_payload; // payload modulator/demodulator + MODEM() mod_payload; // payload modulator/demodulator packetizer p; // packet encoder/decoder unsigned int bits_per_symbol; // modulator bits/symbol unsigned int payload_dec_len; // number of decoded payload bytes @@ -47,13 +47,13 @@ struct qpacketmodem_s { }; // create packet encoder -qpacketmodem qpacketmodem_create() +QPACKETMODEM() QPACKETMODEM(_create)() { // allocate memory for main object - qpacketmodem q = (qpacketmodem) malloc(sizeof(struct qpacketmodem_s)); + QPACKETMODEM() q = (QPACKETMODEM()) malloc(sizeof(struct QPACKETMODEM(_s))); // create payload modem (initially QPSK, overridden by properties) - q->mod_payload = modemcf_create(LIQUID_MODEM_QPSK); + q->mod_payload = MODEM(_create)(LIQUID_MODEM_QPSK); q->bits_per_symbol = 2; // initial memory allocation for payload @@ -87,22 +87,22 @@ qpacketmodem qpacketmodem_create() } // copy object -qpacketmodem qpacketmodem_copy(qpacketmodem q_orig) +QPACKETMODEM() QPACKETMODEM(_copy)(QPACKETMODEM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qpacketmodem_copy(), object cannot be NULL"); // create new object - qpacketmodem q_copy = qpacketmodem_create(); + QPACKETMODEM() q_copy = QPACKETMODEM(_create)(); // configure identically as original unsigned int payload_len = q_orig->payload_dec_len; crc_scheme check = packetizer_get_crc (q_orig->p); fec_scheme fec0 = packetizer_get_fec0(q_orig->p); fec_scheme fec1 = packetizer_get_fec1(q_orig->p); - int ms = modemcf_get_scheme (q_orig->mod_payload); - qpacketmodem_configure(q_copy, payload_len, check, fec0, fec1, ms); + int ms = MODEM(_get_scheme )(q_orig->mod_payload); + QPACKETMODEM(_configure)(q_copy, payload_len, check, fec0, fec1, ms); // return new object return q_copy; @@ -110,11 +110,11 @@ qpacketmodem qpacketmodem_copy(qpacketmodem q_orig) // destroy object, freeing all internal arrays -int qpacketmodem_destroy(qpacketmodem _q) +int QPACKETMODEM(_destroy)(QPACKETMODEM() _q) { // free objects packetizer_destroy(_q->p); - modemcf_destroy(_q->mod_payload); + MODEM(_destroy)(_q->mod_payload); // free arrays free(_q->payload_enc); @@ -125,19 +125,19 @@ int qpacketmodem_destroy(qpacketmodem _q) } // reset object -int qpacketmodem_reset(qpacketmodem _q) +int QPACKETMODEM(_reset)(QPACKETMODEM() _q) { - return modemcf_reset(_q->mod_payload); + return MODEM(_reset)(_q->mod_payload); } // print object internals -int qpacketmodem_print(qpacketmodem _q) +int QPACKETMODEM(_print)(QPACKETMODEM() _q) { printf("qpacketmodem:\n"); printf(" check : %s\n", crc_scheme_str[packetizer_get_crc(_q->p)][1]); printf(" fec (inner) : %s\n", fec_scheme_str[packetizer_get_fec0(_q->p)][1]); printf(" fec (outer) : %s\n", fec_scheme_str[packetizer_get_fec1(_q->p)][1]); - printf(" modulation scheme : %s\n", modulation_types[modemcf_get_scheme(_q->mod_payload)].name); + printf(" modulation scheme : %s\n", modulation_types[MODEM(_get_scheme)(_q->mod_payload)].name); printf(" payload dec len : %u\n", _q->payload_dec_len); printf(" payload enc len : %u\n", _q->payload_enc_len); printf(" payload bit len : %u\n", _q->payload_bit_len); @@ -146,7 +146,7 @@ int qpacketmodem_print(qpacketmodem _q) } // -int qpacketmodem_configure(qpacketmodem _q, +int QPACKETMODEM(_configure)(QPACKETMODEM() _q, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, @@ -157,8 +157,8 @@ int qpacketmodem_configure(qpacketmodem _q, _q->payload_dec_len = _payload_len; // recreate modem object and get new bits per symbol - _q->mod_payload = modemcf_recreate(_q->mod_payload, _ms); - _q->bits_per_symbol = modemcf_get_bps(_q->mod_payload); + _q->mod_payload = MODEM(_recreate)(_q->mod_payload, _ms); + _q->bits_per_symbol = MODEM(_get_bps)(_q->mod_payload); // recreate packetizer object and compute new encoded payload length _q->p = packetizer_recreate(_q->p, _q->payload_dec_len, _check, _fec0, _fec1); @@ -185,44 +185,44 @@ int qpacketmodem_configure(qpacketmodem _q, } // get length of encoded frame in symbols -unsigned int qpacketmodem_get_frame_len(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_frame_len)(QPACKETMODEM() _q) { return _q->payload_mod_len; } // get unencoded/decoded payload length (bytes) -unsigned int qpacketmodem_get_payload_len(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_payload_len)(QPACKETMODEM() _q) { // number of decoded payload bytes return _q->payload_dec_len; } -unsigned int qpacketmodem_get_crc(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_crc)(QPACKETMODEM() _q) { return packetizer_get_crc(_q->p); } -unsigned int qpacketmodem_get_fec0(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_fec0)(QPACKETMODEM() _q) { return packetizer_get_fec0(_q->p); } -unsigned int qpacketmodem_get_fec1(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_fec1)(QPACKETMODEM() _q) { return packetizer_get_fec1(_q->p); } -unsigned int qpacketmodem_get_modscheme(qpacketmodem _q) +unsigned int QPACKETMODEM(_get_modscheme)(QPACKETMODEM() _q) { - return modemcf_get_scheme(_q->mod_payload); + return MODEM(_get_scheme)(_q->mod_payload); } -float qpacketmodem_get_demodulator_phase_error(qpacketmodem _q) +float QPACKETMODEM(_get_demodulator_phase_error)(QPACKETMODEM() _q) { - return modemcf_get_demodulator_phase_error(_q->mod_payload); + return MODEM(_get_demodulator_phase_error)(_q->mod_payload); } -float qpacketmodem_get_demodulator_evm(qpacketmodem _q) +float QPACKETMODEM(_get_demodulator_evm)(QPACKETMODEM() _q) { return _q->evm; } @@ -231,7 +231,7 @@ float qpacketmodem_get_demodulator_evm(qpacketmodem _q) // _q : qpacketmodem object // _payload : unencoded payload bytes // _syms : encoded but un-modulated payload symbol indices -int qpacketmodem_encode_syms(qpacketmodem _q, +int QPACKETMODEM(_encode_syms)(qpacketmodem _q, const unsigned char * _payload, unsigned char * _syms) { @@ -256,7 +256,7 @@ int qpacketmodem_encode_syms(qpacketmodem _q, // _q : qpacketmodem object // _syms : received hard-decision symbol indices // _payload : recovered decoded payload bytes -int qpacketmodem_decode_syms(qpacketmodem _q, +int QPACKETMODEM(_decode_syms)(qpacketmodem _q, unsigned char * _syms, unsigned char * _payload) { @@ -276,7 +276,7 @@ int qpacketmodem_decode_syms(qpacketmodem _q, // _q : qpacketmodem object // _bits : received soft-decision bits // _payload : recovered decoded payload bytes -int qpacketmodem_decode_bits(qpacketmodem _q, +int QPACKETMODEM(_decode_bits)(qpacketmodem _q, unsigned char * _bits, unsigned char * _payload) { @@ -288,17 +288,17 @@ int qpacketmodem_decode_bits(qpacketmodem _q, // _q : qpacketmodem object // _payload : unencoded payload bytes // _frame : encoded/modulated payload symbols -int qpacketmodem_encode(qpacketmodem _q, +int QPACKETMODEM(_encode)(qpacketmodem _q, const unsigned char * _payload, float complex * _frame) { // encode payload symbols into internal buffer - qpacketmodem_encode_syms(_q, _payload, _q->payload_mod); + QPACKETMODEM(_encode_syms)(_q, _payload, _q->payload_mod); // modulate symbols unsigned int i; for (i=0; i<_q->payload_mod_len; i++) - modemcf_modulate(_q->mod_payload, _q->payload_mod[i], &_frame[i]); + MODEM(_modulate)(_q->mod_payload, _q->payload_mod[i], &_frame[i]); return LIQUID_OK; } @@ -306,7 +306,7 @@ int qpacketmodem_encode(qpacketmodem _q, // _q : qpacketmodem object // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes -int qpacketmodem_decode(qpacketmodem _q, +int QPACKETMODEM(_decode)(qpacketmodem _q, float complex * _frame, unsigned char * _payload) { @@ -318,10 +318,10 @@ int qpacketmodem_decode(qpacketmodem _q, _q->evm = 0.0f; for (i=0; i<_q->payload_mod_len; i++) { // demodulate symbol - modemcf_demodulate(_q->mod_payload, _frame[i], &sym); + MODEM(_demodulate)(_q->mod_payload, _frame[i], &sym); // accumulate error vector magnitude estimate - float e = modemcf_get_demodulator_evm(_q->mod_payload); + float e = MODEM(_get_demodulator_evm)(_q->mod_payload); _q->evm += e*e; // pack decoded symbol into array @@ -343,7 +343,7 @@ int qpacketmodem_decode(qpacketmodem _q, // _q : qpacketmodem object // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes -int qpacketmodem_decode_soft(qpacketmodem _q, +int QPACKETMODEM(_decode_soft)(qpacketmodem _q, float complex * _frame, unsigned char * _payload) { @@ -356,11 +356,11 @@ int qpacketmodem_decode_soft(qpacketmodem _q, _q->evm = 0.0f; for (i=0; i<_q->payload_mod_len; i++) { // demodulate symbol - modemcf_demodulate_soft(_q->mod_payload, _frame[i], &sym, _q->payload_enc+n); + MODEM(_demodulate_soft)(_q->mod_payload, _frame[i], &sym, _q->payload_enc+n); n += _q->bits_per_symbol; // accumulate error vector magnitude estimate - float e = modemcf_get_demodulator_evm(_q->mod_payload); + float e = MODEM(_get_demodulator_evm)(_q->mod_payload); _q->evm += e*e; } //printf("received %u bits (expected %u)\n", n, _q->payload_mod_len * _q->bits_per_symbol); @@ -376,16 +376,16 @@ int qpacketmodem_decode_soft(qpacketmodem _q, // decode symbol from modulated frame samples, returning flag if all symbols received // _q : qpacketmodem object // _frame : encoded/modulated symbol -int qpacketmodem_decode_soft_sym(qpacketmodem _q, +int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, float complex _symbol) { unsigned int sym; - modemcf_demodulate_soft(_q->mod_payload, _symbol, &sym, _q->payload_enc + _q->n); + MODEM(_demodulate_soft)(_q->mod_payload, _symbol, &sym, _q->payload_enc + _q->n); _q->n += _q->bits_per_symbol; return _q->n == _q->payload_mod_len * _q->bits_per_symbol; } -int qpacketmodem_decode_soft_payload(qpacketmodem _q, +int QPACKETMODEM(_decode_soft_payload)(qpacketmodem _q, unsigned char * _payload) { assert( _q->n == _q->payload_mod_len * _q->bits_per_symbol); From fec8c7151705cfae32230595b76b7e05b16ec2d9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 10 Jun 2023 09:41:53 -0400 Subject: [PATCH 124/334] cpfskdem: adding warning to demodulation with h > 2/3 --- src/modem/src/cpfskdem.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/modem/src/cpfskdem.c b/src/modem/src/cpfskdem.c index 4e7fd3321..425400620 100644 --- a/src/modem/src/cpfskdem.c +++ b/src/modem/src/cpfskdem.c @@ -164,10 +164,10 @@ cpfskdem cpfskdem_create(unsigned int _bps, // coherent or non-coherent? // TODO: allow user to specify if (q->h > 0.66667f) { - cpfskdem_init_noncoherent(q); - } else { - cpfskdem_init_coherent(q); + //cpfskdem_init_noncoherent(q); + fprintf(stderr,"warning: cpfskdem_create(), coherent demodulation with h > 2/3 not recommended\n"); } + cpfskdem_init_coherent(q); // reset modem object cpfskdem_reset(q); @@ -235,6 +235,7 @@ int cpfskdem_init_coherent(cpfskdem _q) // initialize non-coherent demodulator int cpfskdem_init_noncoherent(cpfskdem _q) { +#if 0 // specify non-coherent receiver _q->demod_type = CPFSKDEM_NONCOHERENT; @@ -250,6 +251,9 @@ int cpfskdem_init_noncoherent(cpfskdem _q) break; } return LIQUID_OK; +#else + return liquid_error(LIQUID_EUMODE,"cpfskdem_init_noncoherent(), unsupported mode"); +#endif } // destroy modem object From d0ea8d8c1ea3d783228083cd5bc4aeace404d72f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 18 Jun 2023 16:20:01 -0400 Subject: [PATCH 125/334] msequence: adding config autotest --- src/sequence/tests/msequence_autotest.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index 21b62c9a7..4503de323 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -92,3 +92,27 @@ void autotest_msequence_m10() { msequence_test_autocorrelation(10); } // n void autotest_msequence_m11() { msequence_test_autocorrelation(11); } // n = 2047 void autotest_msequence_m12() { msequence_test_autocorrelation(12); } // n = 4095 +void autotest_msequence_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firfilt config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // check invalid configurations + CONTEND_ISNULL(msequence_create(100, 0, 0)) + CONTEND_ISNULL(msequence_create_genpoly(0)) + + // create proper object and test configurations + msequence q = msequence_create_genpoly(LIQUID_MSEQUENCE_GENPOLY_M11); + + CONTEND_EQUALITY(LIQUID_OK, msequence_print(q)) + CONTEND_EQUALITY(1<<10U, msequence_get_state(q)) + CONTEND_EQUALITY(LIQUID_OK, msequence_set_state(q, 0x8a)) + CONTEND_EQUALITY(0x8a, msequence_get_state(q)) + + msequence_destroy(q); +} + From 7cedc85ed7eb240d0ec5534ffdfa88fe6ae5876e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 18 Jun 2023 16:31:09 -0400 Subject: [PATCH 126/334] msequence: extending maximum sequence, divorcing from default validation --- src/sequence/src/msequence.c | 44 ++++++++++++------------- src/sequence/tests/msequence_autotest.c | 9 ++--- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index e0a98cbcf..56b380b82 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// m-sequence -// +// maximum-length sequence #include #include @@ -32,30 +30,30 @@ #include "liquid.internal.h" #define LIQUID_MIN_MSEQUENCE_M 2 -#define LIQUID_MAX_MSEQUENCE_M 15 +#define LIQUID_MAX_MSEQUENCE_M 31 // msequence structure // Note that 'g' is stored as the default polynomial shifted to the // right by one bit; this bit is implied and not actually used in // the shift register's feedback bit computation. struct msequence_s msequence_default[16] = { -// m, g, a, n, v, b - {0, 0, 1, 0, 1, 0}, // dummy placeholder - {0, 0, 1, 0, 1, 0}, // dummy placeholder - {2, 0x0003, 0x0002, 3, 0x0002, 0}, - {3, 0x0005, 0x0004, 7, 0x0004, 0}, - {4, 0x0009, 0x0008, 15, 0x0008, 0}, - {5, 0x0012, 0x0010, 31, 0x0010, 0}, - {6, 0x0021, 0x0020, 63, 0x0020, 0}, - {7, 0x0044, 0x0040, 127, 0x0040, 0}, - {8, 0x008E, 0x0080, 255, 0x0080, 0}, - {9, 0x0108, 0x0100, 511, 0x0100, 0}, - {10, 0x0204, 0x0200, 1023, 0x0200, 0}, - {11, 0x0402, 0x0400, 2047, 0x0400, 0}, - {12, 0x0829, 0x0800, 4095, 0x0800, 0}, - {13, 0x100d, 0x1000, 8191, 0x1000, 0}, - {14, 0x2015, 0x2000, 16383, 0x2000, 0}, - {15, 0x4001, 0x4000, 32767, 0x4000, 0} +// m, g, a, n, v, b + {0, 0, 1, 0, 1, 0}, // dummy placeholder + {0, 0, 1, 0, 1, 0}, // dummy placeholder + {2, 0x0003, 0x0002, (1<< 2U)-1, 0x0002, 0}, + {3, 0x0005, 0x0004, (1<< 3U)-1, 0x0004, 0}, + {4, 0x0009, 0x0008, (1<< 4U)-1, 0x0008, 0}, + {5, 0x0012, 0x0010, (1<< 5U)-1, 0x0010, 0}, + {6, 0x0021, 0x0020, (1<< 6U)-1, 0x0020, 0}, + {7, 0x0044, 0x0040, (1<< 7U)-1, 0x0040, 0}, + {8, 0x008E, 0x0080, (1<< 8U)-1, 0x0080, 0}, + {9, 0x0108, 0x0100, (1<< 9U)-1, 0x0100, 0}, + {10, 0x0204, 0x0200, (1<<10U)-1, 0x0200, 0}, + {11, 0x0402, 0x0400, (1<<11U)-1, 0x0400, 0}, + {12, 0x0829, 0x0800, (1<<12U)-1, 0x0800, 0}, + {13, 0x100d, 0x1000, (1<<13U)-1, 0x1000, 0}, + {14, 0x2015, 0x2000, (1<<14U)-1, 0x2000, 0}, + {15, 0x4001, 0x4000, (1<<15U)-1, 0x4000, 0} }; // create a maximal-length sequence (m-sequence) object with @@ -117,7 +115,7 @@ msequence msequence_create_genpoly(unsigned int _g) msequence msequence_create_default(unsigned int _m) { // validate input - if (_m > LIQUID_MAX_MSEQUENCE_M || _m < LIQUID_MIN_MSEQUENCE_M) + if (_m < LIQUID_MIN_MSEQUENCE_M || _m > 15) return liquid_error_config("msequence_create(), m not in range"); // allocate memory for msequence object diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index 4503de323..d379484df 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -102,16 +102,17 @@ void autotest_msequence_config() fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check invalid configurations - CONTEND_ISNULL(msequence_create(100, 0, 0)) - CONTEND_ISNULL(msequence_create_genpoly(0)) + CONTEND_ISNULL(msequence_create (100, 0, 0)) + CONTEND_ISNULL(msequence_create_default( 16)) + CONTEND_ISNULL(msequence_create_genpoly( 0)) // create proper object and test configurations msequence q = msequence_create_genpoly(LIQUID_MSEQUENCE_GENPOLY_M11); CONTEND_EQUALITY(LIQUID_OK, msequence_print(q)) - CONTEND_EQUALITY(1<<10U, msequence_get_state(q)) + CONTEND_EQUALITY(1<<10U, msequence_get_state(q)) CONTEND_EQUALITY(LIQUID_OK, msequence_set_state(q, 0x8a)) - CONTEND_EQUALITY(0x8a, msequence_get_state(q)) + CONTEND_EQUALITY(0x8a, msequence_get_state(q)) msequence_destroy(q); } From eb85ff76d0590dda454521601f8a32e50ea0ce32 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 09:07:12 -0400 Subject: [PATCH 127/334] msequence/autotest: adding test to find period of sequence --- src/sequence/tests/msequence_autotest.c | 63 +++++++++++++++++++------ 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index d379484df..8fc69179c 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ void autotest_bsequence_init_msequence() { // create and initialize m-sequence msequence ms = msequence_create_default(4); - + // create and initialize binary sequence on m-sequence bsequence bs; bs = bsequence_create( msequence_get_length(ms) ); @@ -48,7 +48,7 @@ void msequence_test_autocorrelation(unsigned int _m) // create and initialize m-sequence msequence ms = msequence_create_default(_m); unsigned int n = msequence_get_length(ms); - + // create and initialize first binary sequence on m-sequence bsequence bs1 = bsequence_create(n); bsequence_init_msequence(bs1, ms); @@ -80,17 +80,52 @@ void msequence_test_autocorrelation(unsigned int _m) msequence_destroy(ms); } -void autotest_msequence_m2() { msequence_test_autocorrelation(2); } // n = 3 -void autotest_msequence_m3() { msequence_test_autocorrelation(3); } // n = 7 -void autotest_msequence_m4() { msequence_test_autocorrelation(4); } // n = 15 -void autotest_msequence_m5() { msequence_test_autocorrelation(5); } // n = 31 -void autotest_msequence_m6() { msequence_test_autocorrelation(6); } // n = 63 -void autotest_msequence_m7() { msequence_test_autocorrelation(7); } // n = 127 -void autotest_msequence_m8() { msequence_test_autocorrelation(8); } // n = 255 -void autotest_msequence_m9() { msequence_test_autocorrelation(9); } // n = 511 -void autotest_msequence_m10() { msequence_test_autocorrelation(10); } // n = 1023 -void autotest_msequence_m11() { msequence_test_autocorrelation(11); } // n = 2047 -void autotest_msequence_m12() { msequence_test_autocorrelation(12); } // n = 4095 +void autotest_msequence_xcorr_m2() { msequence_test_autocorrelation(2); } // n = 3 +void autotest_msequence_xcorr_m3() { msequence_test_autocorrelation(3); } // n = 7 +void autotest_msequence_xcorr_m4() { msequence_test_autocorrelation(4); } // n = 15 +void autotest_msequence_xcorr_m5() { msequence_test_autocorrelation(5); } // n = 31 +void autotest_msequence_xcorr_m6() { msequence_test_autocorrelation(6); } // n = 63 +void autotest_msequence_xcorr_m7() { msequence_test_autocorrelation(7); } // n = 127 +void autotest_msequence_xcorr_m8() { msequence_test_autocorrelation(8); } // n = 255 +void autotest_msequence_xcorr_m9() { msequence_test_autocorrelation(9); } // n = 511 +void autotest_msequence_xcorr_m10() { msequence_test_autocorrelation(10); } // n = 1023 +void autotest_msequence_xcorr_m11() { msequence_test_autocorrelation(11); } // n = 2047 +void autotest_msequence_xcorr_m12() { msequence_test_autocorrelation(12); } // n = 4095 + +// helper function to test cyclic period of sequences +void msequence_test_period(unsigned int _m) +{ + // create and initialize m-sequence + msequence q = msequence_create_default(_m); + + unsigned int n = msequence_get_length(q); + unsigned int s = msequence_get_state(q); + + // cycle through sequence and look for initial state + unsigned int i; + unsigned int period = 0; + for (i=0; i Date: Mon, 19 Jun 2023 10:02:36 -0400 Subject: [PATCH 128/334] msequence: adding convenience methods for getting attributes --- include/liquid.h | 10 ++++++++-- src/sequence/src/msequence.c | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 08c168373..cf6096b4c 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9561,7 +9561,7 @@ unsigned int msequence_advance(msequence _ms); // advancing _bps bits and returning compacted symbol // _ms : m-sequence object // _bps : bits per symbol of output -unsigned int msequence_generate_symbol(msequence _ms, +unsigned int msequence_generate_symbol(msequence _ms, unsigned int _bps); // reset msequence shift register to original state, typically '1' @@ -9573,9 +9573,15 @@ int msequence_reset(msequence _ms); int bsequence_init_msequence(bsequence _bs, msequence _ms); -// get the length of the sequence +// get the length of the generator polynomial, g (m) +unsigned int msequence_get_genpoly_length(msequence _ms); + +// get the length of the sequence (n=2^m-1) unsigned int msequence_get_length(msequence _ms); +// get the generator polynomial, g +unsigned int msequence_get_genpoly(msequence _ms); + // get the internal state of the sequence unsigned int msequence_get_state(msequence _ms); diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index 56b380b82..4736418c4 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -208,12 +208,24 @@ int bsequence_init_msequence(bsequence _bs, return LIQUID_OK; } +// get the length of the generator polynomial, g (m) +unsigned int msequence_get_genpoly_length(msequence _ms) +{ + return _ms->m; +} + // get the length of the sequence unsigned int msequence_get_length(msequence _ms) { return _ms->n; } +// get the generator polynomial, g +unsigned int msequence_get_genpoly(msequence _ms) +{ + return _ms->g; +} + // get the internal state of the sequence unsigned int msequence_get_state(msequence _ms) { From 9f936ed957d41f1c30e25333a83933fd0ffc10fd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 10:04:28 -0400 Subject: [PATCH 129/334] msequence: moving structure definition to internal source file --- include/liquid.internal.h | 14 -------------- src/sequence/src/msequence.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index d38648460..4e2f448e0 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1645,20 +1645,6 @@ float randgammaf_delta(float _delta); // MODULE : sequence // -// maximal-length sequence -struct msequence_s { - unsigned int m; // length generator polynomial, shift register - unsigned int g; // generator polynomial - unsigned int a; // initial shift register state, default: 1 - - unsigned int n; // length of sequence, n = (2^m)-1 - unsigned int v; // shift register - unsigned int b; // return bit -}; - -// Default msequence generator objects -extern struct msequence_s msequence_default[16]; - // // MODULE : utility diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index 4736418c4..e1e41db1b 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -32,6 +32,17 @@ #define LIQUID_MIN_MSEQUENCE_M 2 #define LIQUID_MAX_MSEQUENCE_M 31 +// maximal-length sequence +struct msequence_s { + unsigned int m; // length generator polynomial, shift register + unsigned int g; // generator polynomial + unsigned int a; // initial shift register state, default: 1 + + unsigned int n; // length of sequence, n = (2^m)-1 + unsigned int v; // shift register + unsigned int b; // return bit +}; + // msequence structure // Note that 'g' is stored as the default polynomial shifted to the // right by one bit; this bit is implied and not actually used in From 5405b999d797af9b56d017d7c9abb3d233b0fbb3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 10:10:49 -0400 Subject: [PATCH 130/334] msequence: using global default generator polynomials as defaults --- src/sequence/src/msequence.c | 54 +++++++++---------------- src/sequence/tests/msequence_autotest.c | 5 ++- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index e1e41db1b..8625b7c8d 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -43,30 +43,6 @@ struct msequence_s { unsigned int b; // return bit }; -// msequence structure -// Note that 'g' is stored as the default polynomial shifted to the -// right by one bit; this bit is implied and not actually used in -// the shift register's feedback bit computation. -struct msequence_s msequence_default[16] = { -// m, g, a, n, v, b - {0, 0, 1, 0, 1, 0}, // dummy placeholder - {0, 0, 1, 0, 1, 0}, // dummy placeholder - {2, 0x0003, 0x0002, (1<< 2U)-1, 0x0002, 0}, - {3, 0x0005, 0x0004, (1<< 3U)-1, 0x0004, 0}, - {4, 0x0009, 0x0008, (1<< 4U)-1, 0x0008, 0}, - {5, 0x0012, 0x0010, (1<< 5U)-1, 0x0010, 0}, - {6, 0x0021, 0x0020, (1<< 6U)-1, 0x0020, 0}, - {7, 0x0044, 0x0040, (1<< 7U)-1, 0x0040, 0}, - {8, 0x008E, 0x0080, (1<< 8U)-1, 0x0080, 0}, - {9, 0x0108, 0x0100, (1<< 9U)-1, 0x0100, 0}, - {10, 0x0204, 0x0200, (1<<10U)-1, 0x0200, 0}, - {11, 0x0402, 0x0400, (1<<11U)-1, 0x0400, 0}, - {12, 0x0829, 0x0800, (1<<12U)-1, 0x0800, 0}, - {13, 0x100d, 0x1000, (1<<13U)-1, 0x1000, 0}, - {14, 0x2015, 0x2000, (1<<14U)-1, 0x2000, 0}, - {15, 0x4001, 0x4000, (1<<15U)-1, 0x4000, 0} -}; - // create a maximal-length sequence (m-sequence) object with // an internal shift register length of _m bits. // _m : generator polynomial length, sequence length is (2^m)-1 @@ -125,18 +101,28 @@ msequence msequence_create_genpoly(unsigned int _g) // creates a default maximal-length sequence msequence msequence_create_default(unsigned int _m) { - // validate input - if (_m < LIQUID_MIN_MSEQUENCE_M || _m > 15) - return liquid_error_config("msequence_create(), m not in range"); - - // allocate memory for msequence object - msequence ms = (msequence) malloc(sizeof(struct msequence_s)); - - // copy default sequence - memmove(ms, &msequence_default[_m], sizeof(struct msequence_s)); + unsigned int g = 0; + switch (_m) { + case 2: g = LIQUID_MSEQUENCE_GENPOLY_M2; break; + case 3: g = LIQUID_MSEQUENCE_GENPOLY_M3; break; + case 4: g = LIQUID_MSEQUENCE_GENPOLY_M4; break; + case 5: g = LIQUID_MSEQUENCE_GENPOLY_M5; break; + case 6: g = LIQUID_MSEQUENCE_GENPOLY_M6; break; + case 7: g = LIQUID_MSEQUENCE_GENPOLY_M7; break; + case 8: g = LIQUID_MSEQUENCE_GENPOLY_M8; break; + case 9: g = LIQUID_MSEQUENCE_GENPOLY_M9; break; + case 10: g = LIQUID_MSEQUENCE_GENPOLY_M10; break; + case 11: g = LIQUID_MSEQUENCE_GENPOLY_M11; break; + case 12: g = LIQUID_MSEQUENCE_GENPOLY_M12; break; + case 13: g = LIQUID_MSEQUENCE_GENPOLY_M13; break; + case 14: g = LIQUID_MSEQUENCE_GENPOLY_M14; break; + case 15: g = LIQUID_MSEQUENCE_GENPOLY_M15; break; + default: + return liquid_error_config("msequence_create_default(), m (%u) not in range", _m); + } // return - return ms; + return msequence_create_genpoly(g); } // destroy an msequence object, freeing all internal memory diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index 8fc69179c..bdce9b22f 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -98,7 +98,7 @@ void msequence_test_period(unsigned int _m) // create and initialize m-sequence msequence q = msequence_create_default(_m); - unsigned int n = msequence_get_length(q); + unsigned int n = (1U << _m) - 1; unsigned int s = msequence_get_state(q); // cycle through sequence and look for initial state @@ -126,6 +126,9 @@ void autotest_msequence_period_m9() { msequence_test_period(9); } void autotest_msequence_period_m10() { msequence_test_period(10); } void autotest_msequence_period_m11() { msequence_test_period(11); } void autotest_msequence_period_m12() { msequence_test_period(12); } +void autotest_msequence_period_m13() { msequence_test_period(13); } +void autotest_msequence_period_m14() { msequence_test_period(14); } +void autotest_msequence_period_m15() { msequence_test_period(15); } void autotest_msequence_config() { From 68287b29988d006908e187864d5737fb5f21ab6c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 10:21:06 -0400 Subject: [PATCH 131/334] msequence: adding methods to measure period of shift register --- include/liquid.h | 6 +++++ src/sequence/src/msequence.c | 33 +++++++++++++++++++++++++ src/sequence/tests/msequence_autotest.c | 15 +++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index cf6096b4c..7cd461c91 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9589,6 +9589,12 @@ unsigned int msequence_get_state(msequence _ms); int msequence_set_state(msequence _ms, unsigned int _a); +// measure the period the shift register (should be 2^m-1 with a proper generator polynomial) +unsigned int msequence_measure_period(msequence _ms); + +// measure the period of a generator polynomial +unsigned int msequence_genpoly_period(unsigned int _g); + // // MODULE : utility diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index 8625b7c8d..ea71ff625 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -240,3 +240,36 @@ int msequence_set_state(msequence _ms, return LIQUID_OK; } +// measure the period the shift register (should be 2^m-1 with a proper generator polynomial) +unsigned int msequence_measure_period(msequence _ms) +{ + // get current state + unsigned int s = msequence_get_state(_ms); + + // cycle through sequence and look for initial state + unsigned int i; + unsigned int period = 0; + for (i=0; i<_ms->n+1; i++) { + msequence_advance(_ms); + period++; + if (msequence_get_state(_ms)==s) + break; + } + + // assert that state has been returned + return period; +} + +// measure the period of a generator polynomial +unsigned int msequence_genpoly_period(unsigned int _g) +{ + msequence q = msequence_create_genpoly(_g); + if (q == NULL) { + liquid_error(LIQUID_EICONFIG,"msequence_genpoly_period(), invalid generator polynomial 0x%x\n", _g); + return 0; + } + unsigned int period = msequence_measure_period(q); + msequence_destroy(q); + return period; +} + diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index bdce9b22f..6c74711a4 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -98,19 +98,10 @@ void msequence_test_period(unsigned int _m) // create and initialize m-sequence msequence q = msequence_create_default(_m); + // measure period and compare to expected unsigned int n = (1U << _m) - 1; - unsigned int s = msequence_get_state(q); - - // cycle through sequence and look for initial state - unsigned int i; - unsigned int period = 0; - for (i=0; i Date: Mon, 19 Jun 2023 11:05:58 -0400 Subject: [PATCH 132/334] msequence: reversing order for generator polynomial in create methods * makes more consistent with literature * internal representation still reversed * simplifies instantiating new msequence objects with external polynomials --- examples/msequence_example.c | 1 - include/liquid.h | 30 ++++++++++++------------ src/sequence/src/msequence.c | 44 ++++++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/examples/msequence_example.c b/examples/msequence_example.c index df35a08ab..aa34c6ec8 100644 --- a/examples/msequence_example.c +++ b/examples/msequence_example.c @@ -100,7 +100,6 @@ int main(int argc, char*argv[]) fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); - return 0; } diff --git a/include/liquid.h b/include/liquid.h index 7cd461c91..6c394e077 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9515,21 +9515,21 @@ int bsequence_create_ccodes(bsequence _a, bsequence _b); #define LIQUID_MAX_MSEQUENCE_LENGTH 32767 -// default m-sequence generators: g (hex) m n g (oct) g (binary) -#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0007 // 2 3 7 111 -#define LIQUID_MSEQUENCE_GENPOLY_M3 0x000B // 3 7 13 1011 -#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0013 // 4 15 23 10011 -#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0025 // 5 31 45 100101 -#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0043 // 6 63 103 1000011 -#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0089 // 7 127 211 10001001 -#define LIQUID_MSEQUENCE_GENPOLY_M8 0x011D // 8 255 435 100101101 -#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0211 // 9 511 1021 1000010001 -#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0409 // 10 1023 2011 10000001001 -#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0805 // 11 2047 4005 100000000101 -#define LIQUID_MSEQUENCE_GENPOLY_M12 0x1053 // 12 4095 10123 1000001010011 -#define LIQUID_MSEQUENCE_GENPOLY_M13 0x201b // 13 8191 20033 10000000011011 -#define LIQUID_MSEQUENCE_GENPOLY_M14 0x402b // 14 16383 40053 100000000101011 -#define LIQUID_MSEQUENCE_GENPOLY_M15 0x8003 // 15 32767 100003 1000000000000011 +// default m-sequence generators: g (hex) m n +#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0003 // 2 3 +#define LIQUID_MSEQUENCE_GENPOLY_M3 0x0006 // 3 7 +#define LIQUID_MSEQUENCE_GENPOLY_M4 0x000c // 4 15 +#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0014 // 5 31 +#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0030 // 6 63 +#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0060 // 7 127 +#define LIQUID_MSEQUENCE_GENPOLY_M8 0x00b8 // 8 255 +#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0110 // 9 511 +#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0240 // 10 1023 +#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0500 // 11 2047 +#define LIQUID_MSEQUENCE_GENPOLY_M12 0x0e08 // 12 4095 +#define LIQUID_MSEQUENCE_GENPOLY_M13 0x1c80 // 13 8191 +#define LIQUID_MSEQUENCE_GENPOLY_M14 0x3802 // 14 16383 +#define LIQUID_MSEQUENCE_GENPOLY_M15 0x6000 // 15 32767 typedef struct msequence_s * msequence; diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index ea71ff625..6e8377a17 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -34,13 +34,15 @@ // maximal-length sequence struct msequence_s { - unsigned int m; // length generator polynomial, shift register - unsigned int g; // generator polynomial - unsigned int a; // initial shift register state, default: 1 - - unsigned int n; // length of sequence, n = (2^m)-1 - unsigned int v; // shift register - unsigned int b; // return bit + unsigned int m; // length generator polynomial, shift register + unsigned int g; // generator polynomial, form: { x^m + ... + 1 } + unsigned int a; // initial shift register state, default: 1 + + // derived values + unsigned int genpoly; // generator polynomial, bit-reversed from above + unsigned int n; // length of sequence, n = (2^m)-1 + unsigned int v; // shift register + unsigned int b; // return bit }; // create a maximal-length sequence (m-sequence) object with @@ -54,14 +56,17 @@ msequence msequence_create(unsigned int _m, { // validate input if (_m > LIQUID_MAX_MSEQUENCE_M || _m < LIQUID_MIN_MSEQUENCE_M) - return liquid_error_config("msequence_create(), m not in range"); + return liquid_error_config("msequence_create(), m (%u) not in range", _m); + //if (_a == 0) + // return liquid_error_config("msequence_create(), state 'a' cannot be 0"); // allocate memory for msequence object msequence ms = (msequence) malloc(sizeof(struct msequence_s)); // set internal values ms->m = _m; // generator polynomial length - ms->g = _g >> 1; // generator polynomial (clip off most significant bit) + ms->g = _g; // generator polynomial + //ms->g = _g >> 1; // generator polynomial (clip off most significant bit) // initialize state register, reversing order // 0001 -> 1000 @@ -73,6 +78,14 @@ msequence msequence_create(unsigned int _m, _a >>= 1; } + // initialize reverse-order generator polynomial, ignoring implied most-significant bit + ms->genpoly = 1; + for (i=0; im-1; i++) { + ms->genpoly <<= 1; + ms->genpoly |= (_g & 0x01); + _g >>= 1; + } + ms->n = (1<<_m)-1; // sequence length, (2^m)-1 ms->v = ms->a; // shift register ms->b = 0; // return bit @@ -85,14 +98,14 @@ msequence msequence_create(unsigned int _m, msequence msequence_create_genpoly(unsigned int _g) { unsigned int t = liquid_msb_index(_g); - + // validate input if (t < 2) return liquid_error_config("msequence_create_genpoly(), invalid generator polynomial: 0x%x", _g); // compute derived values - unsigned int m = t - 1; // m-sequence shift register length - unsigned int a = 1; // m-sequence initial state + unsigned int m = t; // m-sequence shift register length + unsigned int a = 1; // m-sequence initial state // generate object and return return msequence_create(m,_g,a); @@ -133,8 +146,10 @@ int msequence_destroy(msequence _ms) } // prints the sequence's internal state to the screen -int msequence_print(msequence _m) +int msequence_print(msequence _ms) { + printf("m, _ms->n, _ms->g, _ms->genpoly); +#if 0 unsigned int i; printf("msequence: m=%u (n=%u):\n", _m->m, _m->n); @@ -150,6 +165,7 @@ int msequence_print(msequence _m) for (i=0; i<_m->m; i++) printf("%c", ((_m->g) >> (_m->m-i-1)) & 0x01 ? '1' : '0'); printf("\n"); +#endif return LIQUID_OK; } @@ -158,7 +174,7 @@ unsigned int msequence_advance(msequence _ms) { // compute return bit as binary dot product between the // internal shift register and the generator polynomial - _ms->b = liquid_bdotprod( _ms->v, _ms->g ); + _ms->b = liquid_bdotprod( _ms->v, _ms->genpoly ); _ms->v <<= 1; // shift internal register _ms->v |= _ms->b; // push bit onto register From 9c5a16768ffdb706a01445f05d5f768630dc8636 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 11:27:51 -0400 Subject: [PATCH 133/334] msequence: extending default sequence lengths to m=31 --- include/liquid.h | 48 ++++++++++++++++--------- src/sequence/src/msequence.c | 16 +++++++++ src/sequence/tests/msequence_autotest.c | 18 +++++++++- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 6c394e077..5aed449dc 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9513,23 +9513,37 @@ int bsequence_create_ccodes(bsequence _a, bsequence _b); // M-Sequence -#define LIQUID_MAX_MSEQUENCE_LENGTH 32767 - -// default m-sequence generators: g (hex) m n -#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0003 // 2 3 -#define LIQUID_MSEQUENCE_GENPOLY_M3 0x0006 // 3 7 -#define LIQUID_MSEQUENCE_GENPOLY_M4 0x000c // 4 15 -#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0014 // 5 31 -#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0030 // 6 63 -#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0060 // 7 127 -#define LIQUID_MSEQUENCE_GENPOLY_M8 0x00b8 // 8 255 -#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0110 // 9 511 -#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0240 // 10 1023 -#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0500 // 11 2047 -#define LIQUID_MSEQUENCE_GENPOLY_M12 0x0e08 // 12 4095 -#define LIQUID_MSEQUENCE_GENPOLY_M13 0x1c80 // 13 8191 -#define LIQUID_MSEQUENCE_GENPOLY_M14 0x3802 // 14 16383 -#define LIQUID_MSEQUENCE_GENPOLY_M15 0x6000 // 15 32767 +// default m-sequence generators: g (hex) m n +#define LIQUID_MSEQUENCE_GENPOLY_M2 0x00000003 // 2 3 +#define LIQUID_MSEQUENCE_GENPOLY_M3 0x00000006 // 3 7 +#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0000000c // 4 15 +#define LIQUID_MSEQUENCE_GENPOLY_M5 0x00000014 // 5 31 +#define LIQUID_MSEQUENCE_GENPOLY_M6 0x00000030 // 6 63 +#define LIQUID_MSEQUENCE_GENPOLY_M7 0x00000060 // 7 127 +#define LIQUID_MSEQUENCE_GENPOLY_M8 0x000000b8 // 8 255 +#define LIQUID_MSEQUENCE_GENPOLY_M9 0x00000110 // 9 511 +#define LIQUID_MSEQUENCE_GENPOLY_M10 0x00000240 // 10 1,023 +#define LIQUID_MSEQUENCE_GENPOLY_M11 0x00000500 // 11 2,047 +#define LIQUID_MSEQUENCE_GENPOLY_M12 0x00000e08 // 12 4,095 +#define LIQUID_MSEQUENCE_GENPOLY_M13 0x00001c80 // 13 8,191 +#define LIQUID_MSEQUENCE_GENPOLY_M14 0x00003802 // 14 16,383 +#define LIQUID_MSEQUENCE_GENPOLY_M15 0x00006000 // 15 32,767 +#define LIQUID_MSEQUENCE_GENPOLY_M16 0x0000d008 // 16 65,535 +#define LIQUID_MSEQUENCE_GENPOLY_M17 0x00012000 // 17 131,071 +#define LIQUID_MSEQUENCE_GENPOLY_M18 0x00020400 // 18 262,143 +#define LIQUID_MSEQUENCE_GENPOLY_M19 0x00072000 // 19 524,287 +#define LIQUID_MSEQUENCE_GENPOLY_M20 0x00090000 // 20 1,048,575 +#define LIQUID_MSEQUENCE_GENPOLY_M21 0x00140000 // 21 2,097,151 +#define LIQUID_MSEQUENCE_GENPOLY_M22 0x00300000 // 22 4,194,303 +#define LIQUID_MSEQUENCE_GENPOLY_M23 0x00420000 // 23 8,388,607 +#define LIQUID_MSEQUENCE_GENPOLY_M24 0x00e10000 // 24 16,777,215 +#define LIQUID_MSEQUENCE_GENPOLY_M25 0x01000004 // 25 33,554,431 +#define LIQUID_MSEQUENCE_GENPOLY_M26 0x02000023 // 26 67,108,863 +#define LIQUID_MSEQUENCE_GENPOLY_M27 0x04000013 // 27 134,217,727 +#define LIQUID_MSEQUENCE_GENPOLY_M28 0x08000004 // 28 268,435,455 +#define LIQUID_MSEQUENCE_GENPOLY_M29 0x10000002 // 29 536,870,911 +#define LIQUID_MSEQUENCE_GENPOLY_M30 0x20000029 // 30 1,073,741,823 +#define LIQUID_MSEQUENCE_GENPOLY_M31 0x40000004 // 31 2,147,483,647 typedef struct msequence_s * msequence; diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index 6e8377a17..b296d0608 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -130,6 +130,22 @@ msequence msequence_create_default(unsigned int _m) case 13: g = LIQUID_MSEQUENCE_GENPOLY_M13; break; case 14: g = LIQUID_MSEQUENCE_GENPOLY_M14; break; case 15: g = LIQUID_MSEQUENCE_GENPOLY_M15; break; + case 16: g = LIQUID_MSEQUENCE_GENPOLY_M16; break; + case 17: g = LIQUID_MSEQUENCE_GENPOLY_M17; break; + case 18: g = LIQUID_MSEQUENCE_GENPOLY_M18; break; + case 19: g = LIQUID_MSEQUENCE_GENPOLY_M19; break; + case 20: g = LIQUID_MSEQUENCE_GENPOLY_M20; break; + case 21: g = LIQUID_MSEQUENCE_GENPOLY_M21; break; + case 22: g = LIQUID_MSEQUENCE_GENPOLY_M22; break; + case 23: g = LIQUID_MSEQUENCE_GENPOLY_M23; break; + case 24: g = LIQUID_MSEQUENCE_GENPOLY_M24; break; + case 25: g = LIQUID_MSEQUENCE_GENPOLY_M25; break; + case 26: g = LIQUID_MSEQUENCE_GENPOLY_M26; break; + case 27: g = LIQUID_MSEQUENCE_GENPOLY_M27; break; + case 28: g = LIQUID_MSEQUENCE_GENPOLY_M28; break; + case 29: g = LIQUID_MSEQUENCE_GENPOLY_M29; break; + case 30: g = LIQUID_MSEQUENCE_GENPOLY_M30; break; + case 31: g = LIQUID_MSEQUENCE_GENPOLY_M31; break; default: return liquid_error_config("msequence_create_default(), m (%u) not in range", _m); } diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index 6c74711a4..dac971973 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -120,6 +120,22 @@ void autotest_msequence_period_m12() { msequence_test_period(12); } void autotest_msequence_period_m13() { msequence_test_period(13); } void autotest_msequence_period_m14() { msequence_test_period(14); } void autotest_msequence_period_m15() { msequence_test_period(15); } +void autotest_msequence_period_m16() { msequence_test_period(16); } +void autotest_msequence_period_m17() { msequence_test_period(17); } +void autotest_msequence_period_m18() { msequence_test_period(18); } +void autotest_msequence_period_m19() { msequence_test_period(19); } +void autotest_msequence_period_m20() { msequence_test_period(20); } +void autotest_msequence_period_m21() { msequence_test_period(21); } +void autotest_msequence_period_m22() { msequence_test_period(22); } +void autotest_msequence_period_m23() { msequence_test_period(23); } +void autotest_msequence_period_m24() { msequence_test_period(24); } +void autotest_msequence_period_m25() { msequence_test_period(25); } +void autotest_msequence_period_m26() { msequence_test_period(26); } +void autotest_msequence_period_m27() { msequence_test_period(27); } +void autotest_msequence_period_m28() { msequence_test_period(28); } +void autotest_msequence_period_m29() { msequence_test_period(29); } +void autotest_msequence_period_m30() { msequence_test_period(30); } +void autotest_msequence_period_m31() { msequence_test_period(31); } void autotest_msequence_config() { @@ -132,7 +148,7 @@ void autotest_msequence_config() #endif // check invalid configurations CONTEND_ISNULL(msequence_create (100, 0, 0)) - CONTEND_ISNULL(msequence_create_default( 16)) + CONTEND_ISNULL(msequence_create_default( 32)) // too long CONTEND_ISNULL(msequence_create_genpoly( 0)) // create proper object and test configurations From 55cd1f2c852b19d35fed240eddc1f6c8b94e9b5c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 11:33:51 -0400 Subject: [PATCH 134/334] msequence: cleaning print() method --- src/sequence/src/msequence.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index b296d0608..d4d192edd 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -164,24 +164,8 @@ int msequence_destroy(msequence _ms) // prints the sequence's internal state to the screen int msequence_print(msequence _ms) { - printf("m, _ms->n, _ms->g, _ms->genpoly); -#if 0 - unsigned int i; - - printf("msequence: m=%u (n=%u):\n", _m->m, _m->n); - - // print shift register - printf(" shift register: "); - for (i=0; i<_m->m; i++) - printf("%c", ((_m->v) >> (_m->m-i-1)) & 0x01 ? '1' : '0'); - printf("\n"); - - // print generator polynomial - printf(" generator poly: "); - for (i=0; i<_m->m; i++) - printf("%c", ((_m->g) >> (_m->m-i-1)) & 0x01 ? '1' : '0'); - printf("\n"); -#endif + printf("\n", + _ms->m, _ms->n, _ms->g, _ms->v); return LIQUID_OK; } From 1bf047df31fbee7a3072e5bbc49c93a1a334df4d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 11:37:38 -0400 Subject: [PATCH 135/334] msequence: removing return bit from internal object --- src/sequence/src/msequence.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index d4d192edd..f1b943cc7 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -42,7 +42,6 @@ struct msequence_s { unsigned int genpoly; // generator polynomial, bit-reversed from above unsigned int n; // length of sequence, n = (2^m)-1 unsigned int v; // shift register - unsigned int b; // return bit }; // create a maximal-length sequence (m-sequence) object with @@ -88,8 +87,6 @@ msequence msequence_create(unsigned int _m, ms->n = (1<<_m)-1; // sequence length, (2^m)-1 ms->v = ms->a; // shift register - ms->b = 0; // return bit - return ms; } @@ -174,13 +171,12 @@ unsigned int msequence_advance(msequence _ms) { // compute return bit as binary dot product between the // internal shift register and the generator polynomial - _ms->b = liquid_bdotprod( _ms->v, _ms->genpoly ); + unsigned int b = liquid_bdotprod( _ms->v, _ms->genpoly ); _ms->v <<= 1; // shift internal register - _ms->v |= _ms->b; // push bit onto register + _ms->v |= b; // push bit onto register _ms->v &= _ms->n; // apply mask to register - - return _ms->b; // return result + return b; // return result } From 9d8788f94378c47ec349cbc31514cdcdcde981ba Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 11:38:53 -0400 Subject: [PATCH 136/334] msequence: changing variable name for clarity: v -> state --- src/sequence/src/msequence.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index f1b943cc7..7a7b57127 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -41,7 +41,7 @@ struct msequence_s { // derived values unsigned int genpoly; // generator polynomial, bit-reversed from above unsigned int n; // length of sequence, n = (2^m)-1 - unsigned int v; // shift register + unsigned int state; // shift register }; // create a maximal-length sequence (m-sequence) object with @@ -86,7 +86,7 @@ msequence msequence_create(unsigned int _m, } ms->n = (1<<_m)-1; // sequence length, (2^m)-1 - ms->v = ms->a; // shift register + ms->state = ms->a; // shift register state return ms; } @@ -162,7 +162,7 @@ int msequence_destroy(msequence _ms) int msequence_print(msequence _ms) { printf("\n", - _ms->m, _ms->n, _ms->g, _ms->v); + _ms->m, _ms->n, _ms->g, _ms->state); return LIQUID_OK; } @@ -171,12 +171,12 @@ unsigned int msequence_advance(msequence _ms) { // compute return bit as binary dot product between the // internal shift register and the generator polynomial - unsigned int b = liquid_bdotprod( _ms->v, _ms->genpoly ); + unsigned int b = liquid_bdotprod( _ms->state, _ms->genpoly ); - _ms->v <<= 1; // shift internal register - _ms->v |= b; // push bit onto register - _ms->v &= _ms->n; // apply mask to register - return b; // return result + _ms->state <<= 1; // shift internal register + _ms->state |= b; // push bit onto register + _ms->state &= _ms->n; // apply mask to register + return b; // return result } @@ -198,7 +198,7 @@ unsigned int msequence_generate_symbol(msequence _ms, // reset msequence shift register to original state, typically '1' int msequence_reset(msequence _ms) { - _ms->v = _ms->a; + _ms->state = _ms->a; return LIQUID_OK; } @@ -238,7 +238,7 @@ unsigned int msequence_get_genpoly(msequence _ms) // get the internal state of the sequence unsigned int msequence_get_state(msequence _ms) { - return _ms->v; + return _ms->state; } // set the internal state of the sequence @@ -248,7 +248,7 @@ int msequence_set_state(msequence _ms, // set internal state // NOTE: if state is set to zero, this will lock the sequence generator, // but let the user set this value if they wish - _ms->v = _a; + _ms->state = _a; return LIQUID_OK; } From 66350d2466eb5425005eb387ad451abea12fe4cd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 14:10:05 -0400 Subject: [PATCH 137/334] msequence: moving example for auto-correlation --- .../{msequence_example.c => msequence_autocorr_example.c} | 7 ++----- makefile.in | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) rename examples/{msequence_example.c => msequence_autocorr_example.c} (97%) diff --git a/examples/msequence_example.c b/examples/msequence_autocorr_example.c similarity index 97% rename from examples/msequence_example.c rename to examples/msequence_autocorr_example.c index aa34c6ec8..0ea736dda 100644 --- a/examples/msequence_example.c +++ b/examples/msequence_autocorr_example.c @@ -1,15 +1,12 @@ -// -// msequence_example.c -// // This example demonstrates the auto-correlation properties of a // maximal-length sequence (m-sequence). An m-sequence of a // certain length is used to generate two binary sequences // (buffers) which are then cross-correlated. The resulting // correlation produces -1 for all values except at index zero, // where the sequences align. +// // SEE ALSO: bsequence_example.c // - #include #include #include @@ -17,7 +14,7 @@ #include "liquid.h" -#define OUTPUT_FILENAME "msequence_example.m" +#define OUTPUT_FILENAME "msequence_autocorr_example.m" int main(int argc, char*argv[]) { diff --git a/makefile.in b/makefile.in index d8d0ba37b..dca224e2c 100644 --- a/makefile.in +++ b/makefile.in @@ -1614,7 +1614,7 @@ example_programs := \ examples/modem_soft_example \ examples/modular_arithmetic_example \ examples/msequence_generator_example \ - examples/msequence_example \ + examples/msequence_autocorr_example \ examples/msourcecf_example \ examples/msresamp_crcf_example \ examples/msresamp_crcf_noise_example \ From 5ce0fcdeef00d3171b6e2a75fe4bd20c397e7768 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 14:15:49 -0400 Subject: [PATCH 138/334] msequence: adding example to print all states in cycle --- examples/msequence_example.c | 27 +++++++++++++++++++++++++++ makefile.in | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 examples/msequence_example.c diff --git a/examples/msequence_example.c b/examples/msequence_example.c new file mode 100644 index 000000000..a0b299c17 --- /dev/null +++ b/examples/msequence_example.c @@ -0,0 +1,27 @@ +// This example demonstrates the property of maximal-length sequence +// (m-sequence) linear feedback shift registers (LFSR) where the state +// cycles through all permutations of integers from 1 to 2^m-1. +#include +#include +#include +#include + +#include "liquid.h" + +int main(int argc, char*argv[]) +{ + // create and initialize m-sequence + msequence q = msequence_create_default(5); + msequence_print(q); + + // cycle through values and print state + unsigned int i; + for (i=0; i Date: Mon, 19 Jun 2023 14:25:17 -0400 Subject: [PATCH 139/334] msequence: reversing cycle for processing, removing old members --- examples/msequence_example.c | 8 ++++++ src/sequence/src/msequence.c | 33 ++++++------------------- src/sequence/tests/msequence_autotest.c | 2 +- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/examples/msequence_example.c b/examples/msequence_example.c index a0b299c17..2045d9eeb 100644 --- a/examples/msequence_example.c +++ b/examples/msequence_example.c @@ -17,10 +17,18 @@ int main(int argc, char*argv[]) // cycle through values and print state unsigned int i; for (i=0; i 0 && msequence_get_state(q)==1) { + printf("invalid state!\n"); + break; + } printf("%u\n",msequence_get_state(q)); msequence_advance(q); } + // ensure final state is 1 (circled all the way back around) + printf("final state (should be 1): %u\n", msequence_get_state(q)); + msequence_destroy(q); return 0; } diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index 7a7b57127..ecad555ff 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -34,14 +34,13 @@ // maximal-length sequence struct msequence_s { - unsigned int m; // length generator polynomial, shift register - unsigned int g; // generator polynomial, form: { x^m + ... + 1 } - unsigned int a; // initial shift register state, default: 1 + unsigned int m; // length generator polynomial, shift register + unsigned int g; // generator polynomial, form: { x^m + ... + 1 } + unsigned int a; // initial shift register state, default: 1 // derived values - unsigned int genpoly; // generator polynomial, bit-reversed from above - unsigned int n; // length of sequence, n = (2^m)-1 - unsigned int state; // shift register + unsigned int n; // length of sequence, n = (2^m)-1 + unsigned int state; // shift register }; // create a maximal-length sequence (m-sequence) object with @@ -65,25 +64,7 @@ msequence msequence_create(unsigned int _m, // set internal values ms->m = _m; // generator polynomial length ms->g = _g; // generator polynomial - //ms->g = _g >> 1; // generator polynomial (clip off most significant bit) - - // initialize state register, reversing order - // 0001 -> 1000 - unsigned int i; - ms->a = 0; - for (i=0; im; i++) { - ms->a <<= 1; - ms->a |= (_a & 0x01); - _a >>= 1; - } - - // initialize reverse-order generator polynomial, ignoring implied most-significant bit - ms->genpoly = 1; - for (i=0; im-1; i++) { - ms->genpoly <<= 1; - ms->genpoly |= (_g & 0x01); - _g >>= 1; - } + ms->a = _a; // generator polynomial ms->n = (1<<_m)-1; // sequence length, (2^m)-1 ms->state = ms->a; // shift register state @@ -171,7 +152,7 @@ unsigned int msequence_advance(msequence _ms) { // compute return bit as binary dot product between the // internal shift register and the generator polynomial - unsigned int b = liquid_bdotprod( _ms->state, _ms->genpoly ); + unsigned int b = liquid_bdotprod( _ms->state, _ms->g); _ms->state <<= 1; // shift internal register _ms->state |= b; // push bit onto register diff --git a/src/sequence/tests/msequence_autotest.c b/src/sequence/tests/msequence_autotest.c index dac971973..2bb3dd72a 100644 --- a/src/sequence/tests/msequence_autotest.c +++ b/src/sequence/tests/msequence_autotest.c @@ -155,7 +155,7 @@ void autotest_msequence_config() msequence q = msequence_create_genpoly(LIQUID_MSEQUENCE_GENPOLY_M11); CONTEND_EQUALITY(LIQUID_OK, msequence_print(q)) - CONTEND_EQUALITY(1<<10U, msequence_get_state(q)) + CONTEND_EQUALITY(1, msequence_get_state(q)) CONTEND_EQUALITY(LIQUID_OK, msequence_set_state(q, 0x8a)) CONTEND_EQUALITY(0x8a, msequence_get_state(q)) From 7871087084635385854aaee12c86f04ed9cb2d9f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 14:50:19 -0400 Subject: [PATCH 140/334] build: removing tabs in global header --- include/liquid.h | 62 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 5aed449dc..35a74b062 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9513,37 +9513,37 @@ int bsequence_create_ccodes(bsequence _a, bsequence _b); // M-Sequence -// default m-sequence generators: g (hex) m n -#define LIQUID_MSEQUENCE_GENPOLY_M2 0x00000003 // 2 3 -#define LIQUID_MSEQUENCE_GENPOLY_M3 0x00000006 // 3 7 -#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0000000c // 4 15 -#define LIQUID_MSEQUENCE_GENPOLY_M5 0x00000014 // 5 31 -#define LIQUID_MSEQUENCE_GENPOLY_M6 0x00000030 // 6 63 -#define LIQUID_MSEQUENCE_GENPOLY_M7 0x00000060 // 7 127 -#define LIQUID_MSEQUENCE_GENPOLY_M8 0x000000b8 // 8 255 -#define LIQUID_MSEQUENCE_GENPOLY_M9 0x00000110 // 9 511 -#define LIQUID_MSEQUENCE_GENPOLY_M10 0x00000240 // 10 1,023 -#define LIQUID_MSEQUENCE_GENPOLY_M11 0x00000500 // 11 2,047 -#define LIQUID_MSEQUENCE_GENPOLY_M12 0x00000e08 // 12 4,095 -#define LIQUID_MSEQUENCE_GENPOLY_M13 0x00001c80 // 13 8,191 -#define LIQUID_MSEQUENCE_GENPOLY_M14 0x00003802 // 14 16,383 -#define LIQUID_MSEQUENCE_GENPOLY_M15 0x00006000 // 15 32,767 -#define LIQUID_MSEQUENCE_GENPOLY_M16 0x0000d008 // 16 65,535 -#define LIQUID_MSEQUENCE_GENPOLY_M17 0x00012000 // 17 131,071 -#define LIQUID_MSEQUENCE_GENPOLY_M18 0x00020400 // 18 262,143 -#define LIQUID_MSEQUENCE_GENPOLY_M19 0x00072000 // 19 524,287 -#define LIQUID_MSEQUENCE_GENPOLY_M20 0x00090000 // 20 1,048,575 -#define LIQUID_MSEQUENCE_GENPOLY_M21 0x00140000 // 21 2,097,151 -#define LIQUID_MSEQUENCE_GENPOLY_M22 0x00300000 // 22 4,194,303 -#define LIQUID_MSEQUENCE_GENPOLY_M23 0x00420000 // 23 8,388,607 -#define LIQUID_MSEQUENCE_GENPOLY_M24 0x00e10000 // 24 16,777,215 -#define LIQUID_MSEQUENCE_GENPOLY_M25 0x01000004 // 25 33,554,431 -#define LIQUID_MSEQUENCE_GENPOLY_M26 0x02000023 // 26 67,108,863 -#define LIQUID_MSEQUENCE_GENPOLY_M27 0x04000013 // 27 134,217,727 -#define LIQUID_MSEQUENCE_GENPOLY_M28 0x08000004 // 28 268,435,455 -#define LIQUID_MSEQUENCE_GENPOLY_M29 0x10000002 // 29 536,870,911 -#define LIQUID_MSEQUENCE_GENPOLY_M30 0x20000029 // 30 1,073,741,823 -#define LIQUID_MSEQUENCE_GENPOLY_M31 0x40000004 // 31 2,147,483,647 +// default m-sequence generators: g (hex) m n +#define LIQUID_MSEQUENCE_GENPOLY_M2 0x00000003 // 2 3 +#define LIQUID_MSEQUENCE_GENPOLY_M3 0x00000006 // 3 7 +#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0000000c // 4 15 +#define LIQUID_MSEQUENCE_GENPOLY_M5 0x00000014 // 5 31 +#define LIQUID_MSEQUENCE_GENPOLY_M6 0x00000030 // 6 63 +#define LIQUID_MSEQUENCE_GENPOLY_M7 0x00000060 // 7 127 +#define LIQUID_MSEQUENCE_GENPOLY_M8 0x000000b8 // 8 255 +#define LIQUID_MSEQUENCE_GENPOLY_M9 0x00000110 // 9 511 +#define LIQUID_MSEQUENCE_GENPOLY_M10 0x00000240 // 10 1,023 +#define LIQUID_MSEQUENCE_GENPOLY_M11 0x00000500 // 11 2,047 +#define LIQUID_MSEQUENCE_GENPOLY_M12 0x00000e08 // 12 4,095 +#define LIQUID_MSEQUENCE_GENPOLY_M13 0x00001c80 // 13 8,191 +#define LIQUID_MSEQUENCE_GENPOLY_M14 0x00003802 // 14 16,383 +#define LIQUID_MSEQUENCE_GENPOLY_M15 0x00006000 // 15 32,767 +#define LIQUID_MSEQUENCE_GENPOLY_M16 0x0000d008 // 16 65,535 +#define LIQUID_MSEQUENCE_GENPOLY_M17 0x00012000 // 17 131,071 +#define LIQUID_MSEQUENCE_GENPOLY_M18 0x00020400 // 18 262,143 +#define LIQUID_MSEQUENCE_GENPOLY_M19 0x00072000 // 19 524,287 +#define LIQUID_MSEQUENCE_GENPOLY_M20 0x00090000 // 20 1,048,575 +#define LIQUID_MSEQUENCE_GENPOLY_M21 0x00140000 // 21 2,097,151 +#define LIQUID_MSEQUENCE_GENPOLY_M22 0x00300000 // 22 4,194,303 +#define LIQUID_MSEQUENCE_GENPOLY_M23 0x00420000 // 23 8,388,607 +#define LIQUID_MSEQUENCE_GENPOLY_M24 0x00e10000 // 24 16,777,215 +#define LIQUID_MSEQUENCE_GENPOLY_M25 0x01000004 // 25 33,554,431 +#define LIQUID_MSEQUENCE_GENPOLY_M26 0x02000023 // 26 67,108,863 +#define LIQUID_MSEQUENCE_GENPOLY_M27 0x04000013 // 27 134,217,727 +#define LIQUID_MSEQUENCE_GENPOLY_M28 0x08000004 // 28 268,435,455 +#define LIQUID_MSEQUENCE_GENPOLY_M29 0x10000002 // 29 536,870,911 +#define LIQUID_MSEQUENCE_GENPOLY_M30 0x20000029 // 30 1,073,741,823 +#define LIQUID_MSEQUENCE_GENPOLY_M31 0x40000004 // 31 2,147,483,647 typedef struct msequence_s * msequence; From 698b8f7b1164dcd960d570f08f588ea91e0dbcf2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 16:09:55 -0400 Subject: [PATCH 141/334] build: updating readme to include notes on linking to external libs --- README.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7fa96418c..51c2b1123 100644 --- a/README.md +++ b/README.md @@ -233,11 +233,36 @@ lib_deps = https://github.com/jgaeddert/liquid-dsp.git ### License ### liquid projects are released under the X11/MIT license. +By default, this project will try to link to [FFTW](http://www.fftw.org) if it +is available on your build platform. +Because FFTW starting with version 1.3 is +[licensed](http://www.fftw.org/faq/section1.html) +under the [GNU General Public License v2](http://www.fftw.org/doc/License-and-Copyright.html) +this unfortunately means that (and I'm clearly not a lawyer, here) +you cannot distribute `liquid-dsp` without also distributing the source code +if you link to FFTW. +This is a similar situation with the classic +[libfec](https://github.com/quiet/libfec) +which uses the +[GNU Lesser GPL](https://www.gnu.org/licenses/licenses.html#LGPL). +Finally, `liquid-dsp` makes extensive use of GNU +[autoconf](https://www.gnu.org/software/autoconf/), +[automake](https://www.gnu.org/software/automake/), +and related tools. +These are fantastic libraires with amazing functionality and their authors +should be lauded for their efforts. +In a similar vain, much the software I write for a living I give away for +free; +however I believe in more permissive licenses to allow individuals the +flexibility to use software with more flexibility. +If these restrictions are not acceptible, `liquid-dsp` can be compiled and run +without use of these external libraries, albeit a bit slower and with limited +functionality. + Short version: this code is copyrighted to me (Joseph D. Gaeddert), I give you full permission to do whatever you want with it except remove my name from the credits. -Seriously, go nuts. -See the LICENSE file or -[https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT) -for specific terms. +Seriously, go nuts! but take caution when linking to other libraries with +different licenses. +See the [license](https://opensource.org/licenses/MIT) for specific terms. From 7ed1c3041cb54726150d6ef7ee887e206f388543 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 17:46:04 -0400 Subject: [PATCH 142/334] qdsync: cleaning duplicate interface --- include/liquid.h | 54 ----------------------------------- src/framing/src/qdsync_cccf.c | 43 ---------------------------- 2 files changed, 97 deletions(-) delete mode 100644 src/framing/src/qdsync_cccf.c diff --git a/include/liquid.h b/include/liquid.h index 92e34bdbd..c81b39389 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6284,60 +6284,6 @@ typedef int (*qdsync_callback)(liquid_float_complex * _buf, // - sample count since object was created // - sample count since beginning of frame -// create detector with generic sequence -// _s : sample sequence -// _s_len : length of sample sequence -qdsync_cccf qdsync_cccf_create_linear(liquid_float_complex * _s, - unsigned int _s_len, - int _ftype, - unsigned int _k, - unsigned int _m, - float _beta, - qdsync_callback _callback, - void * _context); - -// Copy object recursively including all internal objects and state -qdsync_cccf qdsync_cccf_copy(qdsync_cccf _q); - -int qdsync_cccf_destroy(qdsync_cccf _q); -int qdsync_cccf_reset (qdsync_cccf _q); -int qdsync_cccf_print (qdsync_cccf _q); - -// get detection threshold -float qdsync_cccf_get_threshold(qdsync_cccf _q); - -// set detection threshold -int qdsync_cccf_set_threshold(qdsync_cccf _q, float _threshold); - -// set carrier offset search range -int qdsync_cccf_set_range(qdsync_cccf _q, - float _dphi_max); - -// set callback method -int qdsync_cccf_set_callback(qdsync_cccf _q, qdsync_callback _callback); - -// set context value -int qdsync_cccf_set_context (qdsync_cccf _q, void * _context); - -// Set callback buffer size (the number of symbol provided to the callback -// whenever it is invoked). -int qdsync_cccf_set_buf_len (qdsync_cccf _q, unsigned int _buf_len); - -// execute block of samples -int qdsync_cccf_execute(qdsync_cccf _q, - liquid_float_complex * _buf, - unsigned int _buf_len); - -// is synchronizer actively running? -int qdsync_cccf_is_open(qdsync_cccf _q); - -// get detection metrics and offsets -float qdsync_cccf_get_rxy (qdsync_cccf _q); // correlator output -float qdsync_cccf_get_tau (qdsync_cccf _q); // fractional timing offset estimate -float qdsync_cccf_get_gamma(qdsync_cccf _q); // channel gain -float qdsync_cccf_get_dphi (qdsync_cccf _q); // carrier frequency offset estimate -float qdsync_cccf_get_phi (qdsync_cccf _q); // carrier phase offset estimate - // // qdsync // diff --git a/src/framing/src/qdsync_cccf.c b/src/framing/src/qdsync_cccf.c deleted file mode 100644 index 28104f7a9..000000000 --- a/src/framing/src/qdsync_cccf.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2007 - 2023 Joseph Gaeddert - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// -// API: floating-point -// - -#include "liquid.internal.h" - -// naming extensions (useful for print statements) -#define EXTENSION "cccf" - -#define TO float complex // output type -#define TC float complex // coefficients type -#define TI float complex // input type -#define T float // primitive type - -// object references -#define QDSYNC(name) LIQUID_CONCAT(qdsync_cccf,name) -#define QDETECTOR(name) LIQUID_CONCAT(qdetector_cccf,name) - -// prototypes -#include "qdsync.proto.c" - From b6707a8dadb0491111ec1665711b3c97aa2ec197 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 17:50:58 -0400 Subject: [PATCH 143/334] qdsync: cleaning up method descriptions --- include/liquid.h | 28 +++++++++++++++++++++------- src/framing/src/qdsync.proto.c | 13 +++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index c81b39389..b1ab242ae 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6323,14 +6323,19 @@ QDSYNC() QDSYNC(_create_linear)(TI * _s, \ /* Copy object recursively including all internal objects and state */ \ QDSYNC() QDSYNC(_copy)(QDSYNC() _q); \ \ +/* Destroy synchronizer object and free all internal memory */ \ int QDSYNC(_destroy)(QDSYNC() _q); \ -int QDSYNC(_reset) (QDSYNC() _q); \ -int QDSYNC(_print) (QDSYNC() _q); \ \ -/* get detection threshold */ \ +/* Reset synchronizer object's internal buffer */ \ +int QDSYNC(_reset)(QDSYNC() _q); \ + \ +/* Print synchronizer object information to stdout */ \ +int QDSYNC(_print)(QDSYNC() _q); \ + \ +/* Get detection threshold */ \ float QDSYNC(_get_threshold)(QDSYNC() _q); \ \ -/* set detection threshold */ \ +/* Set detection threshold */ \ int QDSYNC(_set_threshold)(QDSYNC() _q, \ float _threshold); \ \ @@ -6338,16 +6343,16 @@ int QDSYNC(_set_threshold)(QDSYNC() _q, \ int QDSYNC(_set_range)(QDSYNC() _q, \ float _dphi_max); \ \ -/* set callback method */ \ +/* Set callback method */ \ int QDSYNC(_set_callback)(QDSYNC() _q, \ QDSYNC(_callback) _callback); \ \ -/* set context value */ \ +/* Set context value */ \ int QDSYNC(_set_context)(QDSYNC() _q, void * _context); \ \ /* Set callback buffer size (the number of symbol provided to the */ \ /* callback whenever it is invoked). */ \ -int QDSYNC(_set_buf_len )(QDSYNC() _q, unsigned int _buf_len); \ +int QDSYNC(_set_buf_len)(QDSYNC() _q, unsigned int _buf_len); \ \ /* execute block of samples */ \ int QDSYNC(_execute)(QDSYNC() _q, \ @@ -6357,10 +6362,19 @@ int QDSYNC(_execute)(QDSYNC() _q, \ /* Return flag indicating if synchronizer actively running. */ \ int QDSYNC(_is_open)(QDSYNC() _q); \ \ +/* Get synchronizer correlator output after frame was detected */ \ float QDSYNC(_get_rxy) (QDSYNC() _q); \ + \ +/* Get synchronizer fractional timing offset after frame was detected */ \ float QDSYNC(_get_tau) (QDSYNC() _q); \ + \ +/* Get synchronizer channel gain after frame was detected */ \ float QDSYNC(_get_gamma)(QDSYNC() _q); \ + \ +/* Get synchronizer frequency offset estimate after frame was detected */ \ float QDSYNC(_get_dphi) (QDSYNC() _q); \ + \ +/* Get synchronizer phase offset estimate after frame was detected */ \ float QDSYNC(_get_phi) (QDSYNC() _q); \ LIQUID_QDSYNC_DEFINE_API(LIQUID_QDSYNC_MANGLE_CCCF, diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index 12bbee5c0..06f8fc0a0 100644 --- a/src/framing/src/qdsync.proto.c +++ b/src/framing/src/qdsync.proto.c @@ -164,12 +164,6 @@ int QDSYNC(_destroy)(QDSYNC() _q) return LIQUID_OK; } -int QDSYNC(_print)(QDSYNC() _q) -{ - printf("\n"); - return LIQUID_OK; -} - int QDSYNC(_reset)(QDSYNC() _q) { QDETECTOR(_reset)(_q->detector); @@ -180,6 +174,12 @@ int QDSYNC(_reset)(QDSYNC() _q) return LIQUID_OK; } +int QDSYNC(_print)(QDSYNC() _q) +{ + printf("\n"); + return LIQUID_OK; +} + // get detection threshold float QDSYNC(_get_threshold)(QDSYNC() _q) { @@ -254,6 +254,7 @@ int QDSYNC(_set_buf_len)(QDSYNC() _q, unsigned int _buf_len) return LIQUID_OK; } +// execute synchronizer on a block of samples int QDSYNC(_execute)(QDSYNC() _q, TI * _buf, unsigned int _buf_len) From 7da042924f93e11a08253075f9b83522cda42f9b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 15:42:38 -0400 Subject: [PATCH 144/334] build: adding release notes to HISTORY file --- HISTORY | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/HISTORY b/HISTORY index d1d7b6993..ded8d297a 100644 --- a/HISTORY +++ b/HISTORY @@ -1,8 +1,49 @@ ## Latest improvements ## +## Improvements for v1.6.0 ## + +Version 1.6.0 includes a new qdsync object to greatly simplify the frame +synchronization process in liquid, allowing for both detection and channel +impairment correction with a simplified interface. Additionally, code +coverage has been increased to 85% across the entire project, with numerous +bug fixes, stability improvements, and massive testing enhancements. From +an "architectural" standpoint, objects have been migrated to use standard +methods for consistency. + + * build + - increased code coverage to 85% globally across entire project. This + is the single largest effort included in this version and touches + most modules in some way, most particularly the framing objects + - cleaning build to remove compiler warnings (e.g. unused variables) + - stripped version number off archive + * dotprod + - added support for AVX512-F (thanks, @vankxr!) + * framing + - added numerous tests to increase coverage to 84% + - framesync64: using new qdsync object for simplified operation + - qdsync: new frame detector and synchronizer to much more easily + support frame processing. The object not only detects the frame, but + also provides an initial carrier frequency, phase, and timign offset, + and also corrects for these impairments, passing the results to the + user in a clean callback function. + * modem + - cpfskmod: increasing phase stability for long runs + * multichannel + - added numerous tests to increase coverage to 88% + * optim + - added numerous tests to increase coverage to 92% + * sequence + - msequence: extended support for state variables up to m=31, reversed + order for generator polynomial and internal state definition to be + more consistent with literature and readily-available genpolys + ## Improvements for v1.5.0 ## +This release includes substantially improved testing coverage, deep copy() +methods for nearly all objects, improved speed, and resolves a number of +issues and pull requests. + * build - added support for PlatformIO (https://platformio.org) for embeedded development (thanks, @jcw!) From b11b40c2653386894b5cf77d230f7916fbeea77d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 15:42:51 -0400 Subject: [PATCH 145/334] build: bumping version to 1.6.0 --- configure.ac | 4 ++-- include/liquid.h | 4 ++-- library.json | 2 +- scripts/config.h | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 34ab3dfc3..72518d1ce 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -# Copyright (c) 2007 - 2022 Joseph Gaeddert +# Copyright (c) 2007 - 2023 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ # Process with autoconf to generate configure script # -AC_INIT([liquid-dsp],[1.5],[joseph@liquidsdr.org]) +AC_INIT([liquid-dsp],[1.6],[joseph@liquidsdr.org]) AC_CONFIG_SRCDIR([src/libliquid.c]) AC_CONFIG_MACRO_DIR([scripts]) diff --git a/include/liquid.h b/include/liquid.h index b1ab242ae..f6758a9e8 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -51,8 +51,8 @@ extern "C" { // LIQUID_VERSION = "X.Y.Z" // LIQUID_VERSION_NUMBER = (X*1000000 + Y*1000 + Z) // -#define LIQUID_VERSION "1.5.0" -#define LIQUID_VERSION_NUMBER 1005000 +#define LIQUID_VERSION "1.6.0" +#define LIQUID_VERSION_NUMBER 1006000 // // Run-time library version numbers diff --git a/library.json b/library.json index 5a05e3128..d96b4a3f5 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "liquid-dsp", - "version": "1.5.0", + "version": "1.6.0", "description": "Software-defined radio digital signal processing library", "homepage": "https://liquidsdr.org", "keywords": diff --git a/scripts/config.h b/scripts/config.h index 3b81cd5e4..c7914ac07 100644 --- a/scripts/config.h +++ b/scripts/config.h @@ -169,7 +169,7 @@ #define PACKAGE_NAME "liquid-dsp" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "liquid-dsp 1.5.0" +#define PACKAGE_STRING "liquid-dsp 1.6.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "liquid-dsp" @@ -178,7 +178,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.5.0" +#define PACKAGE_VERSION "1.6.0" /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 From 6e29a7cc6e503320bc3a3066eba96d169cb36eb3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 17:57:10 -0400 Subject: [PATCH 146/334] build: bumping config.sub, config.guess --- scripts/config.guess | 6 +++--- scripts/config.sub | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/config.guess b/scripts/config.guess index 980b02083..69188da73 100644 --- a/scripts/config.guess +++ b/scripts/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-09-17' +timestamp='2023-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." diff --git a/scripts/config.sub b/scripts/config.sub index baf1512b3..de4259e40 100644 --- a/scripts/config.sub +++ b/scripts/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-09-17' +timestamp='2023-01-21' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1075,7 +1075,7 @@ case $cpu-$vendor in pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) cpu=i586 ;; - pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*) cpu=i686 ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) From 8bf87b6fe325d98c250d6911fa50518d14175d86 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 19 Jun 2023 18:04:12 -0400 Subject: [PATCH 147/334] fec/autotest: adding 'default' switch case to clear gcc warnings --- src/fec/tests/fec_autotest.c | 1 + src/fec/tests/fec_copy_autotest.c | 1 + src/fec/tests/fec_soft_autotest.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/fec/tests/fec_autotest.c b/src/fec/tests/fec_autotest.c index d03712ce1..e65fa110a 100644 --- a/src/fec/tests/fec_autotest.c +++ b/src/fec/tests/fec_autotest.c @@ -49,6 +49,7 @@ void fec_test_codec(fec_scheme _fs, unsigned int _n, void * _opts) case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; + default:; } #endif diff --git a/src/fec/tests/fec_copy_autotest.c b/src/fec/tests/fec_copy_autotest.c index bcb2d1ca3..a47addb78 100644 --- a/src/fec/tests/fec_copy_autotest.c +++ b/src/fec/tests/fec_copy_autotest.c @@ -49,6 +49,7 @@ void fec_test_copy(fec_scheme _fs) case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; + default:; } #endif unsigned int n_dec = 64; diff --git a/src/fec/tests/fec_soft_autotest.c b/src/fec/tests/fec_soft_autotest.c index 0ef350493..c0d2ef247 100644 --- a/src/fec/tests/fec_soft_autotest.c +++ b/src/fec/tests/fec_soft_autotest.c @@ -52,6 +52,7 @@ void fec_test_soft_codec(fec_scheme _fs, case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; + default:; } #endif From 89bffef859eec2d833eaa8052dbdbdd2c1cb4368 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 20 Jun 2023 18:10:34 -0400 Subject: [PATCH 148/334] qpacketmodem: adding more description to method definitions --- include/liquid.h | 92 ++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index f6758a9e8..58c9bf4f4 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5218,11 +5218,11 @@ typedef int (*framesync_callback)(unsigned char * _header, typedef void (*framesync_csma_callback)(void * _userdata); -#define LIQUID_QPACKETMODEM_MANGLE_RRRF(name) LIQUID_CONCAT(qpacketmodem,name) +#define LIQUID_QPACKETMODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(qpacketmodem,name) // Macro: // QPACKETMODEM : name-mangling macro -// T : data type +// T : primitive data type #define LIQUID_QPACKETMODEM_DEFINE_API(QPACKETMODEM,T) \ \ /* Packet encoder/decoder */ \ @@ -5231,38 +5231,62 @@ typedef struct QPACKETMODEM(_s) * QPACKETMODEM(); \ /* Create packet encoder */ \ QPACKETMODEM() QPACKETMODEM(_create)(); \ \ +/* Copy object including all internal objects and state */ \ QPACKETMODEM() QPACKETMODEM(_copy) (QPACKETMODEM() _q); \ -int QPACKETMODEM(_destroy)(QPACKETMODEM() _q); \ -int QPACKETMODEM(_reset) (QPACKETMODEM() _q); \ -int QPACKETMODEM(_print) (QPACKETMODEM() _q); \ \ +/* Destroy object, freeing all allocated memory */ \ +int QPACKETMODEM(_destroy)(QPACKETMODEM() _q); \ + \ +/* Print modem status to stdout */ \ +int QPACKETMODEM(_print)(QPACKETMODEM() _q); \ + \ +/* Reset internal state of modem object */ \ +int QPACKETMODEM(_reset)(QPACKETMODEM() _q); \ + \ +/* Configure object with particular parameters */ \ +/* _q : qpacketmodem object */ \ +/* _payload_len : length of payload message [bytes] */ \ +/* _check : data integrity check, e.g LIQUID_CRC_32 */ \ +/* _fec0 : forward error-correction scheme (inner), e.g. */ \ +/* LIQUID_FEC_GOLAY2412 */ \ +/* _fec1 : forward error-correction scheme (outer) */ \ +/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ int QPACKETMODEM(_configure)(QPACKETMODEM() _q, \ - unsigned int _payload_len, \ - crc_scheme _check, \ - fec_scheme _fec0, \ - fec_scheme _fec1, \ - int _ms); \ + unsigned int _payload_len, \ + crc_scheme _check, \ + fec_scheme _fec0, \ + fec_scheme _fec1, \ + int _ms); \ \ -/* get length of encoded frame in symbols */ \ +/* Get length of encoded frame in symbols */ \ unsigned int QPACKETMODEM(_get_frame_len)(QPACKETMODEM() _q); \ \ -/* get unencoded/decoded payload length (bytes) */ \ +/* Get unencoded/decoded payload length (bytes) */ \ unsigned int QPACKETMODEM(_get_payload_len)(QPACKETMODEM() _q); \ \ -/* regular access methods */ \ -unsigned int QPACKETMODEM(_get_crc )(QPACKETMODEM() _q); \ -unsigned int QPACKETMODEM(_get_fec0 )(QPACKETMODEM() _q); \ -unsigned int QPACKETMODEM(_get_fec1 )(QPACKETMODEM() _q); \ +/* Get data integrity check, e.g. LIQUID_CRC_32 */ \ +unsigned int QPACKETMODEM(_get_crc)(QPACKETMODEM() _q); \ + \ +/* Get inner forward error-correction scheme, e.g. LIQUID_GOLAY_2412 */ \ +unsigned int QPACKETMODEM(_get_fec0)(QPACKETMODEM() _q); \ + \ +/* Get outer forward error-correction scheme, e.g. LIQUID_GOLAY_2412 */ \ +unsigned int QPACKETMODEM(_get_fec1)(QPACKETMODEM() _q); \ + \ +/* Get modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ unsigned int QPACKETMODEM(_get_modscheme)(QPACKETMODEM() _q); \ \ +/* Get demodulator phase error (instantaneous) [radians] */ \ float QPACKETMODEM(_get_demodulator_phase_error)(QPACKETMODEM() _q); \ + \ +/* Get demodulator error-vector magnitude after frame was received */ \ float QPACKETMODEM(_get_demodulator_evm)(QPACKETMODEM() _q); \ \ /* encode packet into un-modulated frame symbol indices */ \ /* _q : qpacketmodem object */ \ /* _payload : unencoded payload bytes */ \ /* _syms : encoded but un-modulated payload symbol indices */ \ -int QPACKETMODEM(_encode_syms)(QPACKETMODEM() _q, \ +int QPACKETMODEM(_encode_syms)(QPACKETMODEM() _q, \ const unsigned char * _payload, \ unsigned char * _syms); \ \ @@ -5280,43 +5304,43 @@ int QPACKETMODEM(_decode_syms)(QPACKETMODEM() _q, \ /* _q : qpacketmodem object */ \ /* _bits : received soft-decision bits, [size: bps*frame_len x 1] */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode_bits)(QPACKETMODEM() _q, \ - unsigned char * _bits, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode_bits)(QPACKETMODEM() _q, \ + unsigned char * _bits, \ + unsigned char * _payload); \ \ /* encode and modulate packet into modulated frame samples */ \ /* _q : qpacketmodem object */ \ /* _payload : unencoded payload bytes */ \ /* _frame : encoded/modulated payload symbols */ \ -int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ - const unsigned char * _payload, \ - liquid_float_complex * _frame); \ +int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ + const unsigned char * _payload, \ + liquid_float_complex * _frame); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using hard-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ - liquid_float_complex * _frame, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ + liquid_float_complex * _frame, \ + unsigned char * _payload); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using soft-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ - liquid_float_complex * _frame, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ + liquid_float_complex * _frame, \ + unsigned char * _payload); \ \ -int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ - liquid_float_complex _symbol); \ +int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ + liquid_float_complex _symbol); \ \ -int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ + unsigned char * _payload); \ -LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_RRRF, float) +LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_FLOAT, float) // // pilot generator/synchronizer for packet burst recovery From 29dc259fc0a10e68ae32d05f4d3d7fe2e3647b70 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 20 Jun 2023 18:20:58 -0400 Subject: [PATCH 149/334] qpacketmodem: defining output type in macro, source --- include/liquid.h | 26 +++++++++++++------------- src/framing/src/qpacketmodem.proto.c | 17 +++++++++-------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 58c9bf4f4..15b136667 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5223,7 +5223,7 @@ typedef void (*framesync_csma_callback)(void * _userdata); // Macro: // QPACKETMODEM : name-mangling macro // T : primitive data type -#define LIQUID_QPACKETMODEM_DEFINE_API(QPACKETMODEM,T) \ +#define LIQUID_QPACKETMODEM_DEFINE_API(QPACKETMODEM,T,TC) \ \ /* Packet encoder/decoder */ \ typedef struct QPACKETMODEM(_s) * QPACKETMODEM(); \ @@ -5312,35 +5312,35 @@ int QPACKETMODEM(_decode_bits)(QPACKETMODEM() _q, \ /* _q : qpacketmodem object */ \ /* _payload : unencoded payload bytes */ \ /* _frame : encoded/modulated payload symbols */ \ -int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ - const unsigned char * _payload, \ - liquid_float_complex * _frame); \ +int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ + const unsigned char * _payload, \ + TC * _frame); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using hard-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ - liquid_float_complex * _frame, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ + TC * _frame, \ + unsigned char * _payload); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using soft-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ - liquid_float_complex * _frame, \ - unsigned char * _payload); \ +int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ + TC * _frame, \ + unsigned char * _payload); \ \ -int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ - liquid_float_complex _symbol); \ +int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ + TC _symbol); \ \ int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ unsigned char * _payload); \ -LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_FLOAT, float) +LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_FLOAT,float,liquid_float_complex) // // pilot generator/synchronizer for packet burst recovery diff --git a/src/framing/src/qpacketmodem.proto.c b/src/framing/src/qpacketmodem.proto.c index 96ee3c0a9..d883e8023 100644 --- a/src/framing/src/qpacketmodem.proto.c +++ b/src/framing/src/qpacketmodem.proto.c @@ -288,9 +288,9 @@ int QPACKETMODEM(_decode_bits)(qpacketmodem _q, // _q : qpacketmodem object // _payload : unencoded payload bytes // _frame : encoded/modulated payload symbols -int QPACKETMODEM(_encode)(qpacketmodem _q, +int QPACKETMODEM(_encode)(qpacketmodem _q, const unsigned char * _payload, - float complex * _frame) + TO * _frame) { // encode payload symbols into internal buffer QPACKETMODEM(_encode_syms)(_q, _payload, _q->payload_mod); @@ -307,8 +307,8 @@ int QPACKETMODEM(_encode)(qpacketmodem _q, // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode)(qpacketmodem _q, - float complex * _frame, - unsigned char * _payload) + TO * _frame, + unsigned char * _payload) { unsigned int i; @@ -344,8 +344,8 @@ int QPACKETMODEM(_decode)(qpacketmodem _q, // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode_soft)(qpacketmodem _q, - float complex * _frame, - unsigned char * _payload) + TO * _frame, + unsigned char * _payload) { unsigned int i; @@ -376,8 +376,8 @@ int QPACKETMODEM(_decode_soft)(qpacketmodem _q, // decode symbol from modulated frame samples, returning flag if all symbols received // _q : qpacketmodem object // _frame : encoded/modulated symbol -int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, - float complex _symbol) +int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, + TO _symbol) { unsigned int sym; MODEM(_demodulate_soft)(_q->mod_payload, _symbol, &sym, _q->payload_enc + _q->n); @@ -392,3 +392,4 @@ int QPACKETMODEM(_decode_soft_payload)(qpacketmodem _q, _q->n = 0; return packetizer_decode_soft(_q->p, _q->payload_enc, _payload); } + From 5cfff748678e3c9bf4cf5151e918318479345504 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 21 Jun 2023 19:16:41 -0400 Subject: [PATCH 150/334] qpacketmodem: adding even more description to method definitions --- README.md | 2 +- include/liquid.h | 26 +++++++++++++++++++------- src/framing/src/qpacketmodem.proto.c | 9 +++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 51c2b1123..947501531 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ should be lauded for their efforts. In a similar vain, much the software I write for a living I give away for free; however I believe in more permissive licenses to allow individuals the -flexibility to use software with more flexibility. +flexibility to use software with fewer limitations. If these restrictions are not acceptible, `liquid-dsp` can be compiled and run without use of these external libraries, albeit a bit slower and with limited functionality. diff --git a/include/liquid.h b/include/liquid.h index 15b136667..15db1a97a 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -5296,7 +5296,8 @@ int QPACKETMODEM(_encode_syms)(QPACKETMODEM() _q, \ /* _syms : received hard-decision symbol indices, */ \ /* [size: frame_len x 1] */ \ /* _payload : recovered decoded payload bytes */ \ -int QPACKETMODEM(_decode_syms)(QPACKETMODEM() _q, \ +/* _return : flag indicating if data integrity check passed */ \ +int QPACKETMODEM(_decode_syms)(QPACKETMODEM() _q, \ unsigned char * _syms, \ unsigned char * _payload); \ \ @@ -5318,25 +5319,36 @@ int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using hard-decision decoding */ \ -/* _q : qpacketmodem object */ \ -/* _frame : encoded/modulated payload symbols */ \ -/* _payload : recovered decoded payload bytes */ \ +/* _q : qpacketmodem object */ \ +/* _frame : encoded/modulated payload symbols */ \ +/* _payload : recovered decoded payload bytes */ \ +/* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ TC * _frame, \ unsigned char * _payload); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using soft-decision decoding */ \ -/* _q : qpacketmodem object */ \ -/* _frame : encoded/modulated payload symbols */ \ -/* _payload : recovered decoded payload bytes */ \ +/* _q : qpacketmodem object */ \ +/* _frame : encoded/modulated payload symbols */ \ +/* _payload : recovered decoded payload bytes */ \ +/* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ TC * _frame, \ unsigned char * _payload); \ \ +/* decode symbol from modulated frame samples, returning flag if all */ \ +/* symbols received */ \ +/* _q : qpacketmodem object */ \ +/* _symbol : input received symbol before demodulation */ \ +/* _return : flag indicating if all symbols were received */ \ int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ TC _symbol); \ \ +/* Decode entire packet, assuming that entire frame has been received. */ \ +/* _q : qpacketmodem object */ \ +/* _payload : output payload [bytes] */ \ +/* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ unsigned char * _payload); \ diff --git a/src/framing/src/qpacketmodem.proto.c b/src/framing/src/qpacketmodem.proto.c index d883e8023..6f4a1ef9e 100644 --- a/src/framing/src/qpacketmodem.proto.c +++ b/src/framing/src/qpacketmodem.proto.c @@ -374,8 +374,6 @@ int QPACKETMODEM(_decode_soft)(qpacketmodem _q, } // decode symbol from modulated frame samples, returning flag if all symbols received -// _q : qpacketmodem object -// _frame : encoded/modulated symbol int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, TO _symbol) { @@ -386,9 +384,12 @@ int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, } int QPACKETMODEM(_decode_soft_payload)(qpacketmodem _q, - unsigned char * _payload) + unsigned char * _payload) { - assert( _q->n == _q->payload_mod_len * _q->bits_per_symbol); + if ( _q->n != _q->payload_mod_len * _q->bits_per_symbol) { + liquid_error(LIQUID_ENOINIT,"qpacketmodem_decode_soft_payload(), insufficient number of symbols received"); + return 0; + } _q->n = 0; return packetizer_decode_soft(_q->p, _q->payload_enc, _payload); } From 77c255c75e4474ef1ba0fa0a619bf879e585f702 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 22 Jun 2023 07:54:50 -0400 Subject: [PATCH 151/334] qdsync: removing duplicate definitions in header --- include/liquid.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 15db1a97a..1069b9e0b 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6306,16 +6306,7 @@ float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate -// Frame detector and synchronizer; uses a novel correlation method to -// detect a synchronization pattern, estimate carrier frequency and -// phase offsets as well as timing phase, then correct for these -// impairments in a simple interface suitable for custom frame recovery. -typedef struct qdsync_cccf_s * qdsync_cccf; - -// synchronization callback, return 0:continue, 1:reset -typedef int (*qdsync_callback)(liquid_float_complex * _buf, - unsigned int _buf_len, - void * _context); + // metadata struct: // - sample count since object was created // - sample count since beginning of frame From c20d578ba848b8a4446488b09091f8df2216b220 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 22 Jun 2023 18:02:04 -0400 Subject: [PATCH 152/334] qdetector: making function declarations part of macro for consistency --- include/liquid.h | 200 ++++++++++++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 82 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 1069b9e0b..66cb54924 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6222,90 +6222,126 @@ LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF, // Frame detector // -typedef struct qdetector_cccf_s * qdetector_cccf; - -// create detector with generic sequence -// _s : sample sequence -// _s_len : length of sample sequence -qdetector_cccf qdetector_cccf_create(liquid_float_complex * _s, - unsigned int _s_len); - -// create detector from sequence of symbols using internal linear interpolator -// _sequence : symbol sequence -// _sequence_len : length of symbol sequence -// _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) -// _k : samples/symbol -// _m : filter delay -// _beta : excess bandwidth factor -qdetector_cccf qdetector_cccf_create_linear(liquid_float_complex * _sequence, - unsigned int _sequence_len, - int _ftype, - unsigned int _k, - unsigned int _m, - float _beta); - -// create detector from sequence of GMSK symbols -// _sequence : bit sequence -// _sequence_len : length of bit sequence -// _k : samples/symbol -// _m : filter delay -// _beta : excess bandwidth factor -qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, - unsigned int _sequence_len, - unsigned int _k, - unsigned int _m, - float _beta); - -// create detector from sequence of CP-FSK symbols (assuming one bit/symbol) -// _sequence : bit sequence -// _sequence_len : length of bit sequence -// _bps : bits per symbol, 0 < _bps <= 8 -// _h : modulation index, _h > 0 -// _k : samples/symbol -// _m : filter delay -// _beta : filter bandwidth parameter, _beta > 0 -// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, - unsigned int _sequence_len, - unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type); +#define LIQUID_QDETECTOR_MANGLE_CCCF(name) LIQUID_CONCAT(qdetector_cccf,name) -// Copy object including all internal objects and state -qdetector_cccf qdetector_cccf_copy(qdetector_cccf _q); - -int qdetector_cccf_destroy(qdetector_cccf _q); -int qdetector_cccf_print (qdetector_cccf _q); -int qdetector_cccf_reset (qdetector_cccf _q); - -// run detector, looking for sequence; return pointer to aligned, buffered samples -void * qdetector_cccf_execute(qdetector_cccf _q, - liquid_float_complex _x); - -// get detection threshold -float qdetector_cccf_get_threshold(qdetector_cccf _q); - -// set detection threshold (should be between 0 and 1, good starting point is 0.5) -int qdetector_cccf_set_threshold(qdetector_cccf _q, - float _threshold); - -// set carrier offset search range -int qdetector_cccf_set_range(qdetector_cccf _q, - float _dphi_max); - -// access methods -unsigned int qdetector_cccf_get_seq_len (qdetector_cccf _q); // sequence length -const void * qdetector_cccf_get_sequence(qdetector_cccf _q); // pointer to sequence -unsigned int qdetector_cccf_get_buf_len (qdetector_cccf _q); // buffer length -float qdetector_cccf_get_rxy (qdetector_cccf _q); // correlator output -float qdetector_cccf_get_tau (qdetector_cccf _q); // fractional timing offset estimate -float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain -float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate -float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate +#define LIQUID_QDETECTOR_DEFINE_API(QDETECTOR,TO,TC,TI) \ + \ +/* Frame detector and synchronizer; uses a novel correlation method to */ \ +/* detect a synchronization pattern, estimate carrier frequency and */ \ +/* phase offsets as well as timing phase, then correct for these */ \ +/* impairments in a simple interface suitable for custom frame recovery.*/ \ +typedef struct QDETECTOR(_s) * QDETECTOR(); \ + \ +typedef struct qdetector_cccf_s * qdetector_cccf; \ + \ +/* Create detector with generic sequence */ \ +/* _s : sample sequence */ \ +/* _s_len : length of sample sequence */ \ +QDETECTOR() QDETECTOR(_create)(TI * _s, \ + unsigned int _s_len); \ + \ +/* Create detector from sequence of symbols using internal linear */ \ +/* interpolator */ \ +/* _sequence : symbol sequence */ \ +/* _sequence_len : length of symbol sequence */ \ +/* _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples/symbol */ \ +/* _m : filter delay */ \ +/* _beta : excess bandwidth factor */ \ +QDETECTOR() QDETECTOR(_create_linear)(TI * _sequence, \ + unsigned int _sequence_len, \ + int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* create detector from sequence of GMSK symbols */ \ +/* _sequence : bit sequence */ \ +/* _sequence_len : length of bit sequence */ \ +/* _k : samples/symbol */ \ +/* _m : filter delay */ \ +/* _beta : excess bandwidth factor */ \ +QDETECTOR() QDETECTOR(_create_gmsk)(unsigned char * _sequence, \ + unsigned int _sequence_len, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* create detector from sequence of CP-FSK symbols (assuming one */ \ +/* bit/symbol) */ \ +/* _sequence : bit sequence */ \ +/* _sequence_len : length of bit sequence */ \ +/* _bps : bits per symbol, 0 < _bps <= 8 */ \ +/* _h : modulation index, _h > 0 */ \ +/* _k : samples/symbol */ \ +/* _m : filter delay */ \ +/* _beta : filter bandwidth parameter, _beta > 0 */ \ +/* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ +QDETECTOR() QDETECTOR(_create_cpfsk)(unsigned char * _sequence, \ + unsigned int _sequence_len, \ + unsigned int _bps, \ + float _h, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _type); \ + \ +/* Copy object including all internal objects and state */ \ +QDETECTOR() QDETECTOR(_copy)(QDETECTOR() _q); \ + \ +/* Destroy synchronizer object and free all internal memory */ \ +int QDETECTOR(_destroy)(QDETECTOR() _q); \ + \ +/* Reset synchronizer object's internal buffer */ \ +int QDETECTOR(_reset)(QDETECTOR() _q); \ + \ +/* Print synchronizer object information to stdout */ \ +int QDETECTOR(_print)(QDETECTOR() _q); \ + \ +/* run detector, looking for sequence; return pointer to aligned, */ \ +/* buffered samples */ \ +void * QDETECTOR(_execute)(QDETECTOR() _q, TI _x); \ + \ +/* get detection threshold */ \ +float QDETECTOR(_get_threshold)(QDETECTOR() _q); \ + \ +/* set detection threshold (should be between 0 and 1, good starting */ \ +/* point is 0.5) */ \ +int QDETECTOR(_set_threshold)(QDETECTOR() _q, \ + float _threshold); \ + \ +/* Set carrier offset search range */ \ +int QDETECTOR(_set_range)(QDETECTOR() _q, \ + float _dphi_max); \ + \ +/* Get sequence length */ \ +unsigned int QDETECTOR(_get_seq_len)(QDETECTOR() _q); \ + \ +/* Get pointer to sequence of detected frame */ \ +const void * QDETECTOR(_get_sequence)(QDETECTOR() _q); \ + \ +/* Get buffer length */ \ +unsigned int QDETECTOR(_get_buf_len)(QDETECTOR() _q); \ + \ +/* Get correlator output of detected frame */ \ +float QDETECTOR(_get_rxy)(QDETECTOR() _q); \ + \ +/* Get fractional timing offset estimate of detected frame */ \ +float QDETECTOR(_get_tau)(QDETECTOR() _q); \ + \ +/* Get channel gain of detected frame */ \ +float QDETECTOR(_get_gamma)(QDETECTOR() _q); \ + \ +/* Get carrier frequency offset estimateof detected frame */ \ +float QDETECTOR(_get_dphi)(QDETECTOR() _q); \ + \ +/* Get carrier phase offset estimate of detected frame */ \ +float QDETECTOR(_get_phi)(QDETECTOR() _q); \ +LIQUID_QDETECTOR_DEFINE_API(LIQUID_QDETECTOR_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) // metadata struct: // - sample count since object was created From 60769e36a9e52a1818111cd003923857735eb735 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 22 Jun 2023 18:08:38 -0400 Subject: [PATCH 153/334] qdetector: including as prototype in top-level framing source --- makefile.in | 2 +- src/framing/src/framing_cccf.c | 2 ++ src/framing/src/{qdetector_cccf.c => qdetector.proto.c} | 0 3 files changed, 3 insertions(+), 1 deletion(-) rename src/framing/src/{qdetector_cccf.c => qdetector.proto.c} (100%) diff --git a/makefile.in b/makefile.in index ca8d92205..ddac1ece7 100644 --- a/makefile.in +++ b/makefile.in @@ -649,7 +649,6 @@ framing_objects := \ src/framing/src/gmskframesync.o \ src/framing/src/ofdmflexframegen.o \ src/framing/src/ofdmflexframesync.o \ - src/framing/src/qdetector_cccf.o \ src/framing/src/qpilotgen.o \ src/framing/src/qpilotsync.o \ @@ -667,6 +666,7 @@ framing_prototypes_sync := \ src/framing/src/bpresync.proto.c \ src/framing/src/bsync.proto.c \ src/framing/src/presync.proto.c \ + src/framing/src/qdetector.proto.c \ src/framing/src/qdsync.proto.c \ src/framing/src/symtrack.proto.c \ diff --git a/src/framing/src/framing_cccf.c b/src/framing/src/framing_cccf.c index 6dc777ffc..8cdd68b92 100644 --- a/src/framing/src/framing_cccf.c +++ b/src/framing/src/framing_cccf.c @@ -57,6 +57,7 @@ #define BPRESYNC(name) LIQUID_CONCAT(bpresync_cccf,name) #define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) #define PRESYNC(name) LIQUID_CONCAT(presync_cccf,name) +#define QDETECTOR(name) LIQUID_CONCAT(qdetector_cccf,name) #define QDSYNC(name) LIQUID_CONCAT(qdsync_cccf,name) #define SYMTRACK(name) LIQUID_CONCAT(symtrack_cccf,name) @@ -64,6 +65,7 @@ #include "bpresync.proto.c" #include "bsync.proto.c" #include "presync.proto.c" +#include "qdetector.proto.c" #include "qdsync.proto.c" #include "symtrack.proto.c" diff --git a/src/framing/src/qdetector_cccf.c b/src/framing/src/qdetector.proto.c similarity index 100% rename from src/framing/src/qdetector_cccf.c rename to src/framing/src/qdetector.proto.c From 26494d9e67eb6286dd4c368d2342e3636485fbf2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 22 Jun 2023 18:15:13 -0400 Subject: [PATCH 154/334] qdetector: completing conversion of qdetector to macro --- src/framing/src/qdetector.proto.c | 197 +++++++++++++++--------------- 1 file changed, 97 insertions(+), 100 deletions(-) diff --git a/src/framing/src/qdetector.proto.c b/src/framing/src/qdetector.proto.c index f520b4a28..5c13f45eb 100644 --- a/src/framing/src/qdetector.proto.c +++ b/src/framing/src/qdetector.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,22 +35,22 @@ #define DEBUG_QDETECTOR_FILENAME "qdetector_cccf_debug.m" // seek signal (initial detection) -int qdetector_cccf_execute_seek(qdetector_cccf _q, float complex _x); +int QDETECTOR(_execute_seek)(QDETECTOR() _q, TI _x); // align signal in time, compute offset estimates -int qdetector_cccf_execute_align(qdetector_cccf _q, float complex _x); +int QDETECTOR(_execute_align)(QDETECTOR() _q, TI _x); // main object definition -struct qdetector_cccf_s { +struct QDETECTOR(_s) { unsigned int s_len; // template (time) length: k * (sequence_len + 2*m) - float complex * s; // template (time), [size: s_len x 1] - float complex * S; // template (freq), [size: nfft x 1] + TI * s; // template (time), [size: s_len x 1] + TI * S; // template (freq), [size: nfft x 1] float s2_sum; // sum{ s^2 } - float complex * buf_time_0; // time-domain buffer (FFT) - float complex * buf_freq_0; // frequence-domain buffer (FFT) - float complex * buf_freq_1; // frequence-domain buffer (IFFT) - float complex * buf_time_1; // time-domain buffer (IFFT) + TI * buf_time_0; // time-domain buffer (FFT) + TI * buf_freq_0; // frequence-domain buffer (FFT) + TI * buf_freq_1; // frequence-domain buffer (IFFT) + TI * buf_time_1; // time-domain buffer (IFFT) unsigned int nfft; // fft size FFT_PLAN fft; // FFT object: buf_time_0 > buf_freq_0 FFT_PLAN ifft; // IFFT object: buf_freq_1 > buf_freq_1 @@ -80,38 +80,38 @@ struct qdetector_cccf_s { // create detector with generic sequence // _s : sample sequence // _s_len : length of sample sequence -qdetector_cccf qdetector_cccf_create(float complex * _s, - unsigned int _s_len) +QDETECTOR() QDETECTOR(_create)(TI * _s, + unsigned int _s_len) { // validate input if (_s_len == 0) - return liquid_error_config("qdetector_cccf_create(), sequence length cannot be zero"); + return liquid_error_config("QDETECTOR(_create)(), sequence length cannot be zero"); // allocate memory for main object and set internal properties - qdetector_cccf q = (qdetector_cccf) malloc(sizeof(struct qdetector_cccf_s)); + QDETECTOR() q = (QDETECTOR()) malloc(sizeof(struct QDETECTOR(_s))); q->s_len = _s_len; // allocate memory and copy sequence - q->s = (float complex*) malloc(q->s_len * sizeof(float complex)); - memmove(q->s, _s, q->s_len*sizeof(float complex)); + q->s = (TI*) malloc(q->s_len * sizeof(TI)); + memmove(q->s, _s, q->s_len*sizeof(TI)); q->s2_sum = liquid_sumsqcf(q->s, q->s_len); // compute sum{ s^2 } // prepare transforms q->nfft = 1 << liquid_nextpow2( (unsigned int)( 2 * q->s_len ) ); // NOTE: must be even - q->buf_time_0 = (float complex*) FFT_MALLOC(q->nfft * sizeof(float complex)); - q->buf_freq_0 = (float complex*) FFT_MALLOC(q->nfft * sizeof(float complex)); - q->buf_freq_1 = (float complex*) FFT_MALLOC(q->nfft * sizeof(float complex)); - q->buf_time_1 = (float complex*) FFT_MALLOC(q->nfft * sizeof(float complex)); + q->buf_time_0 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); + q->buf_freq_0 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); + q->buf_freq_1 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); + q->buf_time_1 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); q->fft = FFT_CREATE_PLAN(q->nfft, q->buf_time_0, q->buf_freq_0, FFT_DIR_FORWARD, 0); q->ifft = FFT_CREATE_PLAN(q->nfft, q->buf_freq_1, q->buf_time_1, FFT_DIR_BACKWARD, 0); // create frequency-domain template by taking nfft-point transform on 's', storing in 'S' - q->S = (float complex*) malloc(q->nfft * sizeof(float complex)); - memset(q->buf_time_0, 0x00, q->nfft*sizeof(float complex)); - memmove(q->buf_time_0, q->s, q->s_len*sizeof(float complex)); + q->S = (TI*) malloc(q->nfft * sizeof(TI)); + memset(q->buf_time_0, 0x00, q->nfft*sizeof(TI)); + memmove(q->buf_time_0, q->s, q->s_len*sizeof(TI)); FFT_EXECUTE(q->fft); - memmove(q->S, q->buf_freq_0, q->nfft*sizeof(float complex)); + memmove(q->S, q->buf_freq_0, q->nfft*sizeof(TI)); // reset state variables q->counter = q->nfft/2; @@ -120,7 +120,7 @@ qdetector_cccf qdetector_cccf_create(float complex * _s, q->x2_sum_1 = 0.0f; q->state = QDETECTOR_STATE_SEEK; q->frame_detected = 0; - memset(q->buf_time_0, 0x00, q->nfft*sizeof(float complex)); + memset(q->buf_time_0, 0x00, q->nfft*sizeof(TI)); // reset estimates q->rxy = 0.0f; @@ -129,8 +129,8 @@ qdetector_cccf qdetector_cccf_create(float complex * _s, q->dphi_hat = 0.0f; q->phi_hat = 0.0f; - qdetector_cccf_set_threshold(q,0.5f); - qdetector_cccf_set_range (q,0.3f); // set initial range for higher detection + QDETECTOR(_set_threshold)(q,0.5f); + QDETECTOR(_set_range )(q,0.3f); // set initial range for higher detection // return object return q; @@ -144,26 +144,26 @@ qdetector_cccf qdetector_cccf_create(float complex * _s, // _k : samples/symbol // _m : filter delay // _beta : excess bandwidth factor -qdetector_cccf qdetector_cccf_create_linear(float complex * _sequence, - unsigned int _sequence_len, - int _ftype, - unsigned int _k, - unsigned int _m, - float _beta) +QDETECTOR() QDETECTOR(_create_linear)(TI * _sequence, + unsigned int _sequence_len, + int _ftype, + unsigned int _k, + unsigned int _m, + float _beta) { // validate input if (_sequence_len == 0) - return liquid_error_config("qdetector_cccf_create_linear(), sequence length cannot be zero"); + return liquid_error_config("QDETECTOR(_create_linear)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) - return liquid_error_config("qdetector_cccf_create_linear(), samples per symbol must be in [2,80]"); + return liquid_error_config("QDETECTOR(_create_linear)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) - return liquid_error_config("qdetector_cccf_create_linear(), filter delay must be in [1,100]"); + return liquid_error_config("QDETECTOR(_create_linear)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) - return liquid_error_config("qdetector_cccf_create_linear(), excess bandwidth factor must be in [0,1]"); + return liquid_error_config("QDETECTOR(_create_linear)(), excess bandwidth factor must be in [0,1]"); // create time-domain template unsigned int s_len = _k * (_sequence_len + 2*_m); - float complex * s = (float complex*) malloc(s_len * sizeof(float complex)); + TI * s = (TI*) malloc(s_len * sizeof(TI)); firinterp_crcf interp = firinterp_crcf_create_prototype(_ftype, _k, _m, _beta, 0); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) @@ -171,7 +171,7 @@ qdetector_cccf qdetector_cccf_create_linear(float complex * _sequence, firinterp_crcf_destroy(interp); // create main object - qdetector_cccf q = qdetector_cccf_create(s, s_len); + QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); @@ -186,25 +186,25 @@ qdetector_cccf qdetector_cccf_create_linear(float complex * _sequence, // _k : samples/symbol // _m : filter delay // _beta : excess bandwidth factor -qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, - unsigned int _sequence_len, - unsigned int _k, - unsigned int _m, - float _beta) +QDETECTOR() QDETECTOR(_create_gmsk)(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _k, + unsigned int _m, + float _beta) { // validate input if (_sequence_len == 0) - return liquid_error_config("qdetector_cccf_create_gmsk(), sequence length cannot be zero"); + return liquid_error_config("QDETECTOR(_create_gmsk)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) - return liquid_error_config("qdetector_cccf_create_gmsk(), samples per symbol must be in [2,80]"); + return liquid_error_config("QDETECTOR(_create_gmsk)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) - return liquid_error_config("qdetector_cccf_create_gmsk(), filter delay must be in [1,100]"); + return liquid_error_config("QDETECTOR(_create_gmsk)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) - return liquid_error_config("qdetector_cccf_create_gmsk(), excess bandwidth factor must be in [0,1]"); + return liquid_error_config("QDETECTOR(_create_gmsk)(), excess bandwidth factor must be in [0,1]"); // create time-domain template using GMSK modem unsigned int s_len = _k * (_sequence_len + 2*_m); - float complex * s = (float complex*) malloc(s_len * sizeof(float complex)); + TI * s = (TI*) malloc(s_len * sizeof(TI)); gmskmod mod = gmskmod_create(_k, _m, _beta); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) @@ -212,7 +212,7 @@ qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, gmskmod_destroy(mod); // create main object - qdetector_cccf q = qdetector_cccf_create(s, s_len); + QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); @@ -230,28 +230,28 @@ qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, // _m : filter delay // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, - unsigned int _sequence_len, - unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type) +QDETECTOR() QDETECTOR(_create_cpfsk)(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type) { // validate input if (_sequence_len == 0) - return liquid_error_config("qdetector_cccf_create_cpfsk(), sequence length cannot be zero"); + return liquid_error_config("QDETECTOR(_create_cpfsk)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) - return liquid_error_config("qdetector_cccf_create_cpfsk(), samples per symbol must be in [2,80]"); + return liquid_error_config("QDETECTOR(_create_cpfsk)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) - return liquid_error_config("qdetector_cccf_create_cpfsk(), filter delay must be in [1,100]"); + return liquid_error_config("QDETECTOR(_create_cpfsk)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) - return liquid_error_config("qdetector_cccf_create_cpfsk(), excess bandwidth factor must be in [0,1]"); + return liquid_error_config("QDETECTOR(_create_cpfsk)(), excess bandwidth factor must be in [0,1]"); // create time-domain template using GMSK modem - unsigned int s_len = _k * (_sequence_len + 2*_m); - float complex * s = (float complex*) malloc(s_len * sizeof(float complex)); + unsigned int s_len = _k * (_sequence_len + 2*_m); + TI * s = (TI*) malloc(s_len * sizeof(TI)); cpfskmod mod = cpfskmod_create(_bps, _h, _k, _m, _beta, _type); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) @@ -259,7 +259,7 @@ qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, cpfskmod_destroy(mod); // create main object - qdetector_cccf q = qdetector_cccf_create(s, s_len); + QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); @@ -269,20 +269,20 @@ qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, } // copy object -qdetector_cccf qdetector_cccf_copy(qdetector_cccf q_orig) +QDETECTOR() QDETECTOR(_copy)(QDETECTOR() q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); + return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create new object from internal sequence - qdetector_cccf q_copy = qdetector_cccf_create(q_orig->s, q_orig->s_len); + QDETECTOR() q_copy = QDETECTOR(_create)(q_orig->s, q_orig->s_len); // copy buffer contents - memmove(q_copy->buf_time_0, q_orig->buf_time_0, q_orig->nfft*sizeof(float complex)); - memmove(q_copy->buf_freq_0, q_orig->buf_freq_0, q_orig->nfft*sizeof(float complex)); - memmove(q_copy->buf_time_1, q_orig->buf_time_1, q_orig->nfft*sizeof(float complex)); - memmove(q_copy->buf_freq_1, q_orig->buf_freq_1, q_orig->nfft*sizeof(float complex)); + memmove(q_copy->buf_time_0, q_orig->buf_time_0, q_orig->nfft*sizeof(TI)); + memmove(q_copy->buf_freq_0, q_orig->buf_freq_0, q_orig->nfft*sizeof(TI)); + memmove(q_copy->buf_time_1, q_orig->buf_time_1, q_orig->nfft*sizeof(TI)); + memmove(q_copy->buf_freq_1, q_orig->buf_freq_1, q_orig->nfft*sizeof(TI)); // copy internal state q_copy->counter = q_orig->counter; @@ -300,7 +300,7 @@ qdetector_cccf qdetector_cccf_copy(qdetector_cccf q_orig) return q_copy; } -int qdetector_cccf_destroy(qdetector_cccf _q) +int QDETECTOR(_destroy)(QDETECTOR() _q) { // free allocated arrays free(_q->s); @@ -319,9 +319,9 @@ int qdetector_cccf_destroy(qdetector_cccf _q) return LIQUID_OK; } -int qdetector_cccf_print(qdetector_cccf _q) +int QDETECTOR(_print)(QDETECTOR() _q) { - printf("qdetector_cccf:\n"); + printf("qdetector_%s:\n", EXTENSION_FULL); printf(" template length (time): %-u\n", _q->s_len); printf(" FFT size : %-u\n", _q->nfft); printf(" search range (bins) : %-d\n", _q->range); @@ -330,23 +330,22 @@ int qdetector_cccf_print(qdetector_cccf _q) return LIQUID_OK; } -int qdetector_cccf_reset(qdetector_cccf _q) +int QDETECTOR(_reset)(QDETECTOR() _q) { return LIQUID_OK; } -void * qdetector_cccf_execute(qdetector_cccf _q, - float complex _x) +void * QDETECTOR(_execute)(QDETECTOR() _q, TI _x) { switch (_q->state) { case QDETECTOR_STATE_SEEK: // seek signal - qdetector_cccf_execute_seek(_q, _x); + QDETECTOR(_execute_seek)(_q, _x); break; case QDETECTOR_STATE_ALIGN: // align signal - qdetector_cccf_execute_align(_q, _x); + QDETECTOR(_execute_align)(_q, _x); break; } @@ -364,13 +363,13 @@ void * qdetector_cccf_execute(qdetector_cccf _q, } // get detection threshold -float qdetector_cccf_get_threshold(qdetector_cccf _q) +float QDETECTOR(_get_threshold)(QDETECTOR() _q) { return _q->threshold; } // set detection threshold (should be between 0 and 1, good starting point is 0.5) -int qdetector_cccf_set_threshold(qdetector_cccf _q, +int QDETECTOR(_set_threshold)(QDETECTOR() _q, float _threshold) { if (_threshold <= 0.0f || _threshold > 2.0f) @@ -382,7 +381,7 @@ int qdetector_cccf_set_threshold(qdetector_cccf _q, } // set carrier offset search range -int qdetector_cccf_set_range(qdetector_cccf _q, +int QDETECTOR(_set_range)(QDETECTOR() _q, float _dphi_max) { if (_dphi_max < 0.0f || _dphi_max > 0.5f) @@ -396,49 +395,49 @@ int qdetector_cccf_set_range(qdetector_cccf _q, } // get sequence length -unsigned int qdetector_cccf_get_seq_len(qdetector_cccf _q) +unsigned int QDETECTOR(_get_seq_len)(QDETECTOR() _q) { return _q->s_len; } // pointer to sequence -const void * qdetector_cccf_get_sequence(qdetector_cccf _q) +const void * QDETECTOR(_get_sequence)(QDETECTOR() _q) { return (const void*) _q->s; } // buffer length -unsigned int qdetector_cccf_get_buf_len(qdetector_cccf _q) +unsigned int QDETECTOR(_get_buf_len)(QDETECTOR() _q) { return _q->nfft; } // correlator output -float qdetector_cccf_get_rxy(qdetector_cccf _q) +float QDETECTOR(_get_rxy)(QDETECTOR() _q) { return _q->rxy; } // fractional timing offset estimate -float qdetector_cccf_get_tau(qdetector_cccf _q) +float QDETECTOR(_get_tau)(QDETECTOR() _q) { return _q->tau_hat; } // channel gain -float qdetector_cccf_get_gamma(qdetector_cccf _q) +float QDETECTOR(_get_gamma)(QDETECTOR() _q) { return _q->gamma_hat; } // carrier frequency offset estimate -float qdetector_cccf_get_dphi(qdetector_cccf _q) +float QDETECTOR(_get_dphi)(QDETECTOR() _q) { return _q->dphi_hat; } // carrier phase offset estimate -float qdetector_cccf_get_phi(qdetector_cccf _q) +float QDETECTOR(_get_phi)(QDETECTOR() _q) { return _q->phi_hat; } @@ -449,8 +448,7 @@ float qdetector_cccf_get_phi(qdetector_cccf _q) // // seek signal (initial detection) -int qdetector_cccf_execute_seek(qdetector_cccf _q, - float complex _x) +int QDETECTOR(_execute_seek)(QDETECTOR() _q, TI _x) { // write sample to buffer and increment counter _q->buf_time_0[_q->counter++] = _x; @@ -554,7 +552,7 @@ int qdetector_cccf_execute_seek(qdetector_cccf _q, // TODO: check for edge case where rxy_index is zero (signal already aligned) // copy last part of fft input buffer to front - memmove(_q->buf_time_0, _q->buf_time_0 + rxy_index, (_q->nfft - rxy_index)*sizeof(float complex)); + memmove(_q->buf_time_0, _q->buf_time_0 + rxy_index, (_q->nfft - rxy_index)*sizeof(TI)); _q->counter = _q->nfft - rxy_index; return LIQUID_OK; @@ -564,7 +562,7 @@ int qdetector_cccf_execute_seek(qdetector_cccf _q, #endif // copy last half of fft input buffer to front - memmove(_q->buf_time_0, _q->buf_time_0 + _q->nfft/2, (_q->nfft/2)*sizeof(float complex)); + memmove(_q->buf_time_0, _q->buf_time_0 + _q->nfft/2, (_q->nfft/2)*sizeof(TI)); // swap accumulated signal levels _q->x2_sum_0 = _q->x2_sum_1; @@ -573,8 +571,7 @@ int qdetector_cccf_execute_seek(qdetector_cccf _q, } // align signal in time, compute offset estimates -int qdetector_cccf_execute_align(qdetector_cccf _q, - float complex _x) +int QDETECTOR(_execute_align)(QDETECTOR() _q, TI _x) { // write sample to buffer and increment counter _q->buf_time_0[_q->counter++] = _x; @@ -611,7 +608,7 @@ int qdetector_cccf_execute_align(qdetector_cccf _q, // TODO: revise estimate of rxy here // copy buffer to preserve data integrity - memmove(_q->buf_time_1, _q->buf_time_0, _q->nfft*sizeof(float complex)); + memmove(_q->buf_time_1, _q->buf_time_0, _q->nfft*sizeof(TI)); // estimate carrier frequency offset for (i=0; i<_q->nfft; i++) @@ -670,7 +667,7 @@ int qdetector_cccf_execute_align(qdetector_cccf _q, // METHOD 2: compute metric by de-rotating signal and measuring resulting phase // NOTE: this is possibly more accurate than the above method but might also // be more computationally complex - float complex metric = 0; + TI metric = 0; for (i=0; i<_q->s_len; i++) metric += _q->buf_time_0[i] * cexpf(-_Complex_I*_q->dphi_hat*i); //printf("metric : %12.8f <%12.8f>\n", cabsf(metric), cargf(metric)); @@ -696,7 +693,7 @@ int qdetector_cccf_execute_align(qdetector_cccf _q, // reset state // copy saved buffer state (last half of buf_time_1 to front half of buf_time_0) - memmove(_q->buf_time_0, _q->buf_time_1 + _q->nfft/2, (_q->nfft/2)*sizeof(float complex)); + memmove(_q->buf_time_0, _q->buf_time_1 + _q->nfft/2, (_q->nfft/2)*sizeof(TI)); _q->state = QDETECTOR_STATE_SEEK; _q->x2_sum_0 = liquid_sumsqcf(_q->buf_time_0, _q->nfft/2); _q->x2_sum_1 = 0; From 1e4a9f94666332894ca1a4cb07b96ec5d2631e18 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 24 Jun 2023 11:03:38 -0400 Subject: [PATCH 155/334] build: removing duplicate struct pointer definition for qdetector_cccf --- include/liquid.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 66cb54924..d5b55a8d2 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6232,8 +6232,6 @@ LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF, /* impairments in a simple interface suitable for custom frame recovery.*/ \ typedef struct QDETECTOR(_s) * QDETECTOR(); \ \ -typedef struct qdetector_cccf_s * qdetector_cccf; \ - \ /* Create detector with generic sequence */ \ /* _s : sample sequence */ \ /* _s_len : length of sample sequence */ \ From 3390ddccb78f0fb8cefd00c65929dd2fd751e0ad Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 08:44:03 -0400 Subject: [PATCH 156/334] agc: replacing warning with internal error handling --- src/agc/src/agc.proto.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/agc/src/agc.proto.c b/src/agc/src/agc.proto.c index 60a3f5956..02eb6ef7f 100644 --- a/src/agc/src/agc.proto.c +++ b/src/agc/src/agc.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +35,7 @@ #define AGC_DEFAULT_BW (1e-2f) // internal method definition -void AGC(_squelch_update_mode)(AGC() _q); +int AGC(_squelch_update_mode)(AGC() _q); // agc structure object struct AGC(_s) { @@ -419,7 +419,7 @@ int AGC(_squelch_get_status)(AGC() _q) // // update squelch mode appropriately -void AGC(_squelch_update_mode)(AGC() _q) +int AGC(_squelch_update_mode)(AGC() _q) { // int threshold_exceeded = (AGC(_get_rssi)(_q) > _q->squelch_threshold); @@ -453,8 +453,9 @@ void AGC(_squelch_update_mode)(AGC() _q) break; case LIQUID_AGC_SQUELCH_UNKNOWN: default: - fprintf(stderr,"warning: agc_%s_execute(), invalid squelch mode: %d\n", + return liquid_error(LIQUID_EINT,"agc_%s_execute(), invalid/unsupported squelch mode: %d", EXTENSION_FULL, _q->squelch_mode); } + return LIQUID_OK; } From 0c94b1af9a3c938bea40ce34b685d9296c4a4be2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 09:18:34 -0400 Subject: [PATCH 157/334] eqlms: replacing warning with internal error handling --- src/equalization/src/eqlms.proto.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/equalization/src/eqlms.proto.c b/src/equalization/src/eqlms.proto.c index fc102abc3..9737adb44 100644 --- a/src/equalization/src/eqlms.proto.c +++ b/src/equalization/src/eqlms.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -485,7 +485,8 @@ int EQLMS(_train)(EQLMS() _q, { unsigned int p=_q->h_len; if (_n < _q->h_len) { - fprintf(stderr,"warning: eqlms_%s_train(), traning sequence less than filter order\n", EXTENSION_FULL); + return liquid_error(LIQUID_EICONFIG,"eqlms_%s_train(), traning sequence less than filter order", + EXTENSION_FULL); } unsigned int i; From 80ec7c2d6e7b91baf9b4b4e8134e9365cc55c074 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 09:24:19 -0400 Subject: [PATCH 158/334] fec: replacing warning with internal error handling --- src/fec/bench/fec_decode_benchmark.c | 4 ++-- src/fec/bench/fec_encode_benchmark.c | 4 ++-- src/fec/bench/fecsoft_decode_benchmark.c | 4 ++-- src/fec/src/crc.c | 2 +- src/fec/src/fec.c | 4 ++-- src/fec/tests/fec_reedsolomon_autotest.c | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/fec/bench/fec_decode_benchmark.c b/src/fec/bench/fec_decode_benchmark.c index 3262e5e80..d820dceda 100644 --- a/src/fec/bench/fec_decode_benchmark.c +++ b/src/fec/bench/fec_decode_benchmark.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ void fec_decode_bench( _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { - fprintf(stderr,"warning: convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; diff --git a/src/fec/bench/fec_encode_benchmark.c b/src/fec/bench/fec_encode_benchmark.c index c4f99ebd7..9841f1adb 100644 --- a/src/fec/bench/fec_encode_benchmark.c +++ b/src/fec/bench/fec_encode_benchmark.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ void fec_encode_bench( _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { - fprintf(stderr,"warning: convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; diff --git a/src/fec/bench/fecsoft_decode_benchmark.c b/src/fec/bench/fecsoft_decode_benchmark.c index b5b6f09da..f02cf0fa4 100644 --- a/src/fec/bench/fecsoft_decode_benchmark.c +++ b/src/fec/bench/fecsoft_decode_benchmark.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -67,7 +67,7 @@ void fecsoft_decode_bench( _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { - fprintf(stderr,"warning: convolutional, Reed-Solomon codes unavailable (install libfec)\n"); + liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; diff --git a/src/fec/src/crc.c b/src/fec/src/crc.c index 0b7ed7fa7..e0f19715e 100644 --- a/src/fec/src/crc.c +++ b/src/fec/src/crc.c @@ -79,7 +79,7 @@ crc_scheme liquid_getopt_str2crc(const char * _str) } } - liquid_error(LIQUID_EICONFIG,"warning: liquid_getopt_str2crc(), unknown/unsupported crc scheme : %s\n", _str); + liquid_error(LIQUID_EICONFIG,"liquid_getopt_str2crc(), unknown/unsupported crc scheme: %s", _str); return LIQUID_CRC_UNKNOWN; } diff --git a/src/fec/src/fec.c b/src/fec/src/fec.c index c212b8f9b..b62726ac7 100644 --- a/src/fec/src/fec.c +++ b/src/fec/src/fec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -102,7 +102,7 @@ fec_scheme liquid_getopt_str2fec(const char * _str) } } - fprintf(stderr,"warning: liquid_getopt_str2fec(), unknown/unsupported fec scheme : %s\n", _str); + liquid_error(LIQUID_EICONFIG,"liquid_getopt_str2fec(), unknown/unsupported crc scheme: %s", _str); return LIQUID_FEC_UNKNOWN; } diff --git a/src/fec/tests/fec_reedsolomon_autotest.c b/src/fec/tests/fec_reedsolomon_autotest.c index 7f15ab978..38f6c215e 100644 --- a/src/fec/tests/fec_reedsolomon_autotest.c +++ b/src/fec/tests/fec_reedsolomon_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ void autotest_reedsolomon_223_255() { #if !LIBFEC_ENABLED - printf("warning: Reed-Solomon codes unavailable\n"); + liquid_error(LIQUID_EUMODE,"Reed-Solomon codes unavailable (install libfec)"); return; #endif From a7e800963fff1ddf67ac1c97e64805c7c8535e34 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 09:32:26 -0400 Subject: [PATCH 159/334] fft: replacing warning with internal error handling --- src/fft/src/asgram.proto.c | 4 ++-- src/fft/src/fft_mixed_radix.proto.c | 4 ++-- src/fft/src/spgram.proto.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fft/src/asgram.proto.c b/src/fft/src/asgram.proto.c index c4d62c596..9bce5d171 100644 --- a/src/fft/src/asgram.proto.c +++ b/src/fft/src/asgram.proto.c @@ -134,7 +134,7 @@ int ASGRAM(_set_scale)(ASGRAM() _q, float _div) { if (_div <= 0.0f) - return liquid_error(LIQUID_EICONFIG,"ASGRAM(_set_scale)(), div must be greater than zero"); + return liquid_error(LIQUID_EICONFIG,"asgram%s_set_scale(), div must be greater than zero", EXTENSION); _q->ref = _ref; _q->div = _div; @@ -154,7 +154,7 @@ int ASGRAM(_set_display)(ASGRAM() _q, unsigned int i; for (i=0; i<10; i++) { if (_ascii[i] == '\0') { - fprintf(stderr,"warning: asgram%s_set_display(), invalid use of null character\n", EXTENSION); + liquid_error(LIQUID_EICONFIG,"asgram%s_display(), invalid use of null character", EXTENSION); _q->levelchar[i] = '?'; } else { _q->levelchar[i] = _ascii[i]; diff --git a/src/fft/src/fft_mixed_radix.proto.c b/src/fft/src/fft_mixed_radix.proto.c index 5d134985e..bd4751ce9 100644 --- a/src/fft/src/fft_mixed_radix.proto.c +++ b/src/fft/src/fft_mixed_radix.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -199,7 +199,7 @@ unsigned int FFT(_estimate_mixed_radix)(unsigned int _nfft) // check if _nfft is prime if (num_factors < 2) { - fprintf(stderr,"warning: fft_estimate_mixed_radix(), %u is prime\n", _nfft); + liquid_error(LIQUID_EICONFIG,"fft_estimate_mixed_radix(), %u is prime", _nfft); return 0; } diff --git a/src/fft/src/spgram.proto.c b/src/fft/src/spgram.proto.c index 68f7016e8..7b86dfc45 100644 --- a/src/fft/src/spgram.proto.c +++ b/src/fft/src/spgram.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -275,7 +275,7 @@ int SPGRAM(_set_alpha)(SPGRAM() _q, { // validate input if (_alpha != -1 && (_alpha < 0.0f || _alpha > 1.0f)) { - fprintf(stderr,"warning: spgram%s_set_alpha(), alpha must be in {-1,[0,1]}\n", EXTENSION); + liquid_error(LIQUID_EICONFIG,"spgram%s_set_alpha(), alpha must be in {-1,[0,1]}", EXTENSION); return -1; } From 36220845bbede0bbfeed6c6004c5946eb9b27653 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 09:53:56 -0400 Subject: [PATCH 160/334] build: adding LIQUID_ENOCONV error type * specifies that an algorithm could not converge or no solution could be found * example: finding roots of a polynomial can be unreliable * example: filter design with extremely tight constraints --- include/liquid.h | 7 ++++++- src/libliquid.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index d5b55a8d2..7dfe9dbe5 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -72,7 +72,7 @@ int liquid_libversion_number(void); } \ // basic error types -#define LIQUID_NUM_ERRORS 12 +#define LIQUID_NUM_ERRORS 13 typedef enum { // everything ok LIQUID_OK=0, @@ -123,6 +123,11 @@ typedef enum { // - could not parse line in file (improper formatting) LIQUID_EIO, + // algorithm could not converge or no solution could be found + // - try to find roots of polynomial can sometimes cause instability + // - filter design using Parks-McClellan with extremely tight constraints + LIQUID_ENOCONV, + } liquid_error_code; // error descriptions diff --git a/src/libliquid.c b/src/libliquid.c index 8effe6b87..3f8e68f7d 100644 --- a/src/libliquid.c +++ b/src/libliquid.c @@ -94,6 +94,7 @@ const char * liquid_error_str[LIQUID_NUM_ERRORS] = { "object has not been created or properly initialized", // LIQUID_ENOINIT "not enough memory allocated for operation", // LIQUID_EIMEM "file input/output", // LIQUID_EIO + "algorithm could not converge", // LIQUID_ENOCONV }; // get error string given code From aa0ef38e3b05374ee347417f925f07c71310cfcd Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 10:00:16 -0400 Subject: [PATCH 161/334] filter: replacing warning with internal error handling --- src/filter/src/firdes.c | 6 +++--- src/filter/src/fnyquist.c | 4 ++-- src/filter/src/msresamp2.proto.c | 20 +++++++------------- src/filter/src/resamp.proto.c | 2 +- src/filter/src/rkaiser.c | 15 +++++++++------ 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/filter/src/firdes.c b/src/filter/src/firdes.c index 6ce38fee9..72f554d51 100644 --- a/src/filter/src/firdes.c +++ b/src/filter/src/firdes.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -421,7 +421,7 @@ int liquid_firdes_prototype(liquid_firfilt_type _type, // Nyquist filter prototypes case LIQUID_FIRFILT_KAISER: return liquid_firdes_kaiser (h_len, fc, as, _dt, _h); case LIQUID_FIRFILT_PM: - // WARNING: input timing offset is ignored here + // NOTE: input timing offset is ignored here return firdespm_run(h_len, 3, bands, des, weights, wtype, LIQUID_FIRDESPM_BANDPASS, _h); case LIQUID_FIRFILT_RCOS: return liquid_firdes_rcos (_k, _m, _beta, _dt, _h); case LIQUID_FIRFILT_FEXP: return liquid_firdes_fexp (_k, _m, _beta, _dt, _h); @@ -721,7 +721,7 @@ int liquid_getopt_str2firfilt(const char * _str) } } - fprintf(stderr,"warning: liquid_getopt_str2firfilt(), unknown/unsupported type: %s\n", _str); + liquid_error(LIQUID_EICONFIG,"liquid_getopt_str2firfilt(), unknown/unsupported type: %s", _str); return LIQUID_FIRFILT_UNKNOWN; } diff --git a/src/filter/src/fnyquist.c b/src/filter/src/fnyquist.c index 56ab259dc..2a62d4454 100644 --- a/src/filter/src/fnyquist.c +++ b/src/filter/src/fnyquist.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -287,7 +287,7 @@ int liquid_firdes_rfarcsech(unsigned int _k, float liquid_asechf(float _z) { if (_z <= 0.0f || _z > 1.0f) { - fprintf(stderr,"warning: liquid_asechf(), input out of range\n"); + liquid_error(LIQUID_EICONFIG,"liquid_asechf(), input (_z=%g)out of range (0,1)", _z); return 0.0f; } diff --git a/src/filter/src/msresamp2.proto.c b/src/filter/src/msresamp2.proto.c index 2973409ab..bb46a2625 100644 --- a/src/filter/src/msresamp2.proto.c +++ b/src/filter/src/msresamp2.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -89,22 +89,16 @@ MSRESAMP2() MSRESAMP2(_create)(int _type, // validate input if (_num_stages > 16) return liquid_error_config("msresamp2_%s_create(), number of stages should not exceed 16", EXTENSION_FULL); - - // ensure cut-off frequency is valid - if ( _fc <= 0.0f || _fc >= 0.5f ) { + if ( _fc <= 0.0f || _fc >= 0.5f ) return liquid_error_config("msresamp2_%s_create(), cut-off frequency must be in (0,0.5)", EXTENSION_FULL); - } else if ( _fc > 0.499f ) { - fprintf(stderr,"warning: msresamp2_%s_create(), cut-off frequency greater than 0.499\n", EXTENSION_FULL); - fprintf(stderr," >> truncating to 0.499\n"); + if ( _f0 != 0. ) + return liquid_error_config("msresamp2_%s_create(), non-zero center frequency not yet supported", EXTENSION_FULL); + + // truncate cut-off frequency to avoid excessive filter response + if ( _fc > 0.499f ) _fc = 0.499f; - } // check center frequency - if ( _f0 != 0. ) { - fprintf(stderr,"warning: msresamp2_%s_create(), non-zero center frequency not yet supported\n", EXTENSION_FULL); - _f0 = 0.; - } - unsigned int i; // create object diff --git a/src/filter/src/resamp.proto.c b/src/filter/src/resamp.proto.c index 050e74fcf..3a7866968 100644 --- a/src/filter/src/resamp.proto.c +++ b/src/filter/src/resamp.proto.c @@ -297,7 +297,7 @@ int RESAMP(_adjust_timing_phase)(RESAMP() _q, unsigned int RESAMP(_get_num_output)(RESAMP() _q, unsigned int _num_input) { - fprintf(stderr,"warning: resamp_%s_get_num_output(), function not implemented\n",EXTENSION_FULL); + liquid_error(LIQUID_EINT,"resamp_%s_get_num_output(), function not implemented",EXTENSION_FULL); return 0; } diff --git a/src/filter/src/rkaiser.c b/src/filter/src/rkaiser.c index 983864d47..845439765 100644 --- a/src/filter/src/rkaiser.c +++ b/src/filter/src/rkaiser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -264,8 +264,10 @@ int liquid_firdes_rkaiser_bisection(unsigned int _k, #endif for (p=0; p y0 || y1 > y2) - fprintf(stderr,"warning: liquid_firdes_rkaiser_bisection(): bounding region is ill-conditioned\n"); + if (y1 > y0 || y1 > y2) { + liquid_error(LIQUID_ENOCONV,"liquid_firdes_rkaiser_bisection(): bounding region is ill-conditioned, y:{%g,%g,%g}", + y0, y1, y2); + } // choose midway points xa, xb and compute ISI xa = 0.5f*(x0 + x1); // bisect [x0,x1] @@ -424,7 +426,8 @@ int liquid_firdes_rkaiser_quadratic(unsigned int _k, // ensure x_hat is within boundary (this will fail if y1 > y0 || y1 > y2) if (x_hat < x0 || x_hat > x2) { - //fprintf(stderr,"warning: liquid_firdes_rkaiser_quadratic(), quadratic minimum outside boundary\n"); + //liquid_error(LIQUID_ENOCONV,"liquid_firdes_rkaiser_quadratic(): quadratic minimum outside boundary, y:{%g,%g,%g}, x-hat:%g,{%g,%g}", + // y0, y1, y2, x_hat, x0, x2); break; } @@ -474,9 +477,9 @@ float liquid_firdes_rkaiser_internal_isi(unsigned int _k, { // validate input if (_rho < 0.0f) { - fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho < 0\n"); + liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_internal_isi(), rho < 0"); } else if (_rho > 1.0f) { - fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho > 1\n"); + liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_internal_isi(), rho > 1"); } unsigned int n=2*_k*_m+1; // filter length From 94b5adfa77cd904794a5a2b0a4f3a8fd1aa7d5ef Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 11:51:53 -0400 Subject: [PATCH 162/334] firinterp: adding flush() method to run zeros through filter --- include/liquid.h | 7 ++++++ src/filter/src/firinterp.proto.c | 11 +++++++++- src/filter/tests/firinterp_autotest.c | 31 ++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 7dfe9dbe5..d468a288d 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -3846,6 +3846,13 @@ int FIRINTERP(_execute_block)(FIRINTERP() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ + \ +/* Execute interpolation with zero-valued input (e.g. flush internal */ \ +/* state) */ \ +/* _q : firinterp object */ \ +/* _y : output sample array, [size: M x 1] */ \ +int FIRINTERP(_flush)(FIRINTERP() _q, \ + TO * _y); \ LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_RRRF, float, diff --git a/src/filter/src/firinterp.proto.c b/src/filter/src/firinterp.proto.c index 1031a1467..98f605bc5 100644 --- a/src/filter/src/firinterp.proto.c +++ b/src/filter/src/firinterp.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -291,3 +291,12 @@ int FIRINTERP(_execute_block)(FIRINTERP() _q, return LIQUID_OK; } +// Execute interpolation with zero-valued input (e.g. flush internal state) +// _q : firinterp object +// _y : output sample array [size: M x 1] +int FIRINTERP(_flush)(FIRINTERP() _q, + TO * _y) +{ + return FIRINTERP(_execute)(_q, 0, _y); +} + diff --git a/src/filter/tests/firinterp_autotest.c b/src/filter/tests/firinterp_autotest.c index 6bfccc030..85da06a53 100644 --- a/src/filter/tests/firinterp_autotest.c +++ b/src/filter/tests/firinterp_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -249,3 +249,32 @@ void autotest_firinterp_copy() firinterp_crcf_destroy(q1); } +// test flush method(s) +void autotest_firinterp_flush() +{ + // create base object + unsigned int m = 7; + firinterp_crcf q = firinterp_crcf_create_kaiser(3, m, 60.0f); + + // run samples through filter + unsigned int i; + float complex buf[3]; + for (i=0; i<20; i++) { + float complex v = randnf() + _Complex_I*randnf(); + firinterp_crcf_execute(q, v, buf); + } + + // ensure buffer does not contain zeros + CONTEND_GREATER_THAN( liquid_sumsqcf(buf,3), 0.0f ); + + // flush buffer + for (i=0; i<2*m; i++) + firinterp_crcf_flush(q, buf); + + // ensure buffer contains only zeros + CONTEND_EQUALITY( liquid_sumsqcf(buf,3), 0.0f ); + + // destroy objects + firinterp_crcf_destroy(q); +} + From 07fa654334810597b8d77d0181d142b75614b0fc Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 14:24:24 -0400 Subject: [PATCH 163/334] bpacketsync: replacing warning with internal error handling --- src/framing/src/bpacketsync.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/framing/src/bpacketsync.c b/src/framing/src/bpacketsync.c index b3e6d19cf..7cbc5df25 100644 --- a/src/framing/src/bpacketsync.c +++ b/src/framing/src/bpacketsync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// bpacketsync -// // binary packet synchronizer/decoder -// #include #include @@ -436,8 +432,10 @@ int bpacketsync_decode_header(bpacketsync _q) (_q->header_dec[5] ); // check version number - if (version != BPACKET_VERSION) - fprintf(stderr,"warning: bpacketsync, version mismatch!\n"); + if (version != BPACKET_VERSION) { + return liquid_error(LIQUID_EICONFIG,"bpacketsync, version mismatch (received %d, expected %d)", + version, BPACKET_VERSION); + } // TODO : check crc, fec0, fec1 schemes return LIQUID_OK; From 1dc54e480a3ae147f21b5df74f2e64cc88c911e1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 14:27:12 -0400 Subject: [PATCH 164/334] bpacketsync: adding more appropriate error checking --- src/framing/src/bpacketsync.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/framing/src/bpacketsync.c b/src/framing/src/bpacketsync.c index 7cbc5df25..df403b7d0 100644 --- a/src/framing/src/bpacketsync.c +++ b/src/framing/src/bpacketsync.c @@ -432,12 +432,15 @@ int bpacketsync_decode_header(bpacketsync _q) (_q->header_dec[5] ); // check version number - if (version != BPACKET_VERSION) { - return liquid_error(LIQUID_EICONFIG,"bpacketsync, version mismatch (received %d, expected %d)", - version, BPACKET_VERSION); - } + if (version != BPACKET_VERSION) + return liquid_error(LIQUID_EICONFIG,"bpacketsync, version mismatch (received %d, expected %d)",version, BPACKET_VERSION); + if (_q->crc == LIQUID_CRC_UNKNOWN || _q->crc >= LIQUID_CRC_NUM_SCHEMES) + return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported crc: %u", _q->crc); + if (_q->fec0 == LIQUID_FEC_UNKNOWN || _q->fec0 >= LIQUID_FEC_NUM_SCHEMES) + return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported fec (inner): %u", _q->fec0); + if (_q->fec1 == LIQUID_FEC_UNKNOWN || _q->fec1 >= LIQUID_FEC_NUM_SCHEMES) + return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported fec (outer): %u", _q->fec1); - // TODO : check crc, fec0, fec1 schemes return LIQUID_OK; } From 449b9a5c1e2d3d194b0d070c3463289a7feae793 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 14:30:46 -0400 Subject: [PATCH 165/334] build: adding LIQUID_ENOIMP error type * specifies that a function or method has not yet been implemented * allows for placeholder function declaration with definition * there are only a few examples of this * might be worth including a pre-processor macro warning --- include/liquid.h | 5 ++++- src/libliquid.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index d468a288d..b784f9a35 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -72,7 +72,7 @@ int liquid_libversion_number(void); } \ // basic error types -#define LIQUID_NUM_ERRORS 13 +#define LIQUID_NUM_ERRORS 14 typedef enum { // everything ok LIQUID_OK=0, @@ -128,6 +128,9 @@ typedef enum { // - filter design using Parks-McClellan with extremely tight constraints LIQUID_ENOCONV, + // method or function declared but not yet implemented + LIQUID_ENOIMP, + } liquid_error_code; // error descriptions diff --git a/src/libliquid.c b/src/libliquid.c index 3f8e68f7d..d0ffd5800 100644 --- a/src/libliquid.c +++ b/src/libliquid.c @@ -95,6 +95,7 @@ const char * liquid_error_str[LIQUID_NUM_ERRORS] = { "not enough memory allocated for operation", // LIQUID_EIMEM "file input/output", // LIQUID_EIO "algorithm could not converge", // LIQUID_ENOCONV + "function or method not yet implemented", // LIQUID_ENOIMP }; // get error string given code From b9a6ec99e238ca3b8087d410dda3a94fec458eca Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 14:49:37 -0400 Subject: [PATCH 166/334] framing: replacing warning with internal error handling --- src/framing/src/fskframegen.c | 8 +++----- src/framing/src/gmskframegen.c | 4 ++-- src/framing/src/gmskframesync.c | 17 +++++++---------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c index 90557e53c..1c5df8e52 100644 --- a/src/framing/src/fskframegen.c +++ b/src/framing/src/fskframegen.c @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// fskframegen.c -// +// frequency-shift keying (FSK) frame generator #include #include @@ -289,7 +287,7 @@ int fskframegen_assemble(fskframegen _q, fec_scheme _fec1) { #if 1 - fprintf(stderr,"warning: fskframegen_assemble(), ignoring input parameters for now\n"); + liquid_error(LIQUID_ENOIMP,"fskframegen_assemble(), base functionality not implemented; ignoring input parameters for now"); #else // set properties _q->payload_dec_len = _payload_len; @@ -338,7 +336,7 @@ int fskframegen_assemble(fskframegen _q, unsigned int fskframegen_getframelen(fskframegen _q) { if (!_q->frame_assembled) { - fprintf(stderr,"warning: fskframegen_getframelen(), frame not assembled!\n"); + liquid_error(LIQUID_EICONFIG,"fskframegen_getframelen(), frame not assembled!"); return 0; } diff --git a/src/framing/src/gmskframegen.c b/src/framing/src/gmskframegen.c index a69220c3b..897bce6a7 100644 --- a/src/framing/src/gmskframegen.c +++ b/src/framing/src/gmskframegen.c @@ -228,7 +228,7 @@ int gmskframegen_set_header_len(gmskframegen _q, unsigned int _len) { if (_q->frame_assembled) - fprintf(stderr, "warning: gmskframegen_set_header_len(), frame is already assembled; must reset() first\n"); + return liquid_error(LIQUID_EICONFIG,"gmskframegen_set_header_len(), frame is already assembled; must reset() first"); _q->header_user_len = _len; unsigned int header_dec_len = GMSKFRAME_H_DEC + _q->header_user_len; @@ -315,7 +315,7 @@ int gmskframegen_assemble_default(gmskframegen _q, unsigned int gmskframegen_getframelen(gmskframegen _q) { if (!_q->frame_assembled) { - fprintf(stderr,"warning: gmskframegen_getframelen(), frame not assembled!\n"); + liquid_error(LIQUID_EICONFIG,"gmskframegen_getframelen(), frame not assembled"); return 0; } diff --git a/src/framing/src/gmskframesync.c b/src/framing/src/gmskframesync.c index 75d71a785..34c521f9d 100644 --- a/src/framing/src/gmskframesync.c +++ b/src/framing/src/gmskframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // gmskframesync.c -// #include #include @@ -787,7 +785,8 @@ int gmskframesync_decode_header(gmskframesync _q) // first byte is for expansion/version validation if (_q->header_dec[n+0] != GMSKFRAME_VERSION) { - fprintf(stderr,"warning: gmskframesync_decode_header(), invalid framing version\n"); + liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid framing version (received %u, expected %u)", + _q->header_dec[n+0], GMSKFRAME_VERSION); _q->header_valid = 0; return LIQUID_OK; } @@ -804,23 +803,22 @@ int gmskframesync_decode_header(gmskframesync _q) unsigned int fec1 = (_q->header_dec[n+4] ) & 0x1f; // validate properties - if (check >= LIQUID_CRC_NUM_SCHEMES) { - fprintf(stderr,"warning: gmskframesync_decode_header(), decoded CRC exceeds available\n"); + if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { + liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported crc: %u", check); check = LIQUID_CRC_UNKNOWN; _q->header_valid = 0; } if (fec0 >= LIQUID_FEC_NUM_SCHEMES) { - fprintf(stderr,"warning: gmskframesync_decode_header(), decoded FEC (inner) exceeds available\n"); + liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported fec (inner): %u", fec0); fec0 = LIQUID_FEC_UNKNOWN; _q->header_valid = 0; } if (fec1 >= LIQUID_FEC_NUM_SCHEMES) { - fprintf(stderr,"warning: gmskframesync_decode_header(), decoded FEC (outer) exceeds available\n"); + liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported fec (outer): %u", fec1); fec1 = LIQUID_FEC_UNKNOWN; _q->header_valid = 0; } - // print results // configure payload receiver if (_q->header_valid) { // set new packetizer properties @@ -847,4 +845,3 @@ int gmskframesync_decode_header(gmskframesync _q) return LIQUID_OK; } - From 675ed9758cbc07e0cb6c03e915de9dbe805c00c3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 14:55:54 -0400 Subject: [PATCH 167/334] math: replacing warning with internal error handling --- src/math/src/math.gamma.c | 2 +- src/math/src/poly.findroots.c | 2 +- src/math/src/poly.lagrange.proto.c | 4 ++-- src/math/src/windows.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/math/src/math.gamma.c b/src/math/src/math.gamma.c index aea4bf63e..ef046e0fa 100644 --- a/src/math/src/math.gamma.c +++ b/src/math/src/math.gamma.c @@ -83,7 +83,7 @@ float liquid_gammaf(float _z) float t0 = liquid_gammaf(1.0 - _z); float t1 = sinf(M_PI*_z); if (t0==0 || t1==0) - fprintf(stderr,"warning: liquid_gammaf(), divide by zero\n"); + liquid_error(LIQUID_EIVAL,"liquid_gammaf(), divide by zero"); return M_PI / (t0 * t1); } else { return expf( liquid_lngammaf(_z) ); diff --git a/src/math/src/poly.findroots.c b/src/math/src/poly.findroots.c index 014f79fa7..120135f7f 100644 --- a/src/math/src/poly.findroots.c +++ b/src/math/src/poly.findroots.c @@ -145,7 +145,7 @@ int liquid_poly_findroots_bairstow(double * _p, // initial estimates for u, v if (p[n-1] == 0) { - fprintf(stderr,"warning: poly_findroots_bairstow(), irreducible polynomial"); + liquid_error(LIQUID_EIVAL,"poly_findroots_bairstow(), irreducible polynomial"); p[n-1] = 1e-12; } u = p[n-2] / p[n-1]; diff --git a/src/math/src/poly.lagrange.proto.c b/src/math/src/poly.lagrange.proto.c index b794bf444..4a75e3fe5 100644 --- a/src/math/src/poly.lagrange.proto.c +++ b/src/math/src/poly.lagrange.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -118,7 +118,7 @@ int POLY(_fit_lagrange_barycentric)(T * _x, _w[j] = 1. / _w[j]; } - // normalize by _w[0], add minuscule margin to avoid divide-by-zero warning + // normalize by _w[0], add minuscule margin to avoid division by zero T w0 = _w[0] + 1.0e-9f; for (j=0; j<_n; j++) _w[j] /= w0; diff --git a/src/math/src/windows.c b/src/math/src/windows.c index 892c98523..79e73f162 100644 --- a/src/math/src/windows.c +++ b/src/math/src/windows.c @@ -91,7 +91,7 @@ liquid_window_type liquid_getopt_str2window(const char * _str) } } - fprintf(stderr,"warning: liquid_getopt_str2window(), unknown/unsupported window scheme : %s\n", _str); + liquid_error(LIQUID_EICONFIG,"liquid_getopt_str2window(), unknown/unsupported window scheme: %s", _str); return LIQUID_WINDOW_UNKNOWN; } From 1d2199baf9ffee3a296640c9ab44f6b10a16fb84 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 15:01:38 -0400 Subject: [PATCH 168/334] modem: replacing warning with internal error handling --- include/liquid.h | 2 +- src/modem/src/fskdem.c | 4 ++-- src/modem/src/gmskdem.c | 4 ++-- src/modem/src/modem_utilities.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index b784f9a35..2285b7882 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -128,7 +128,7 @@ typedef enum { // - filter design using Parks-McClellan with extremely tight constraints LIQUID_ENOCONV, - // method or function declared but not yet implemented + // method or function declared but not implemented or disabled LIQUID_ENOIMP, } liquid_error_code; diff --git a/src/modem/src/fskdem.c b/src/modem/src/fskdem.c index 385ef2eaf..eb95aea0a 100644 --- a/src/modem/src/fskdem.c +++ b/src/modem/src/fskdem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -264,7 +264,7 @@ float fskdem_get_symbol_energy(fskdem _q, { // validate input if (_s >= _q->M) { - fprintf(stderr,"warning: fskdem_get_symbol_energy(), input symbol (%u) exceeds maximum (%u)\n", + liquid_error(LIQUID_EICONFIG,"fskdem_get_symbol_energy(), input symbol (%u) exceeds maximum (%u)", _s, _q->M); _s = 0; } diff --git a/src/modem/src/gmskdem.c b/src/modem/src/gmskdem.c index 2bddf9be4..f837d29be 100644 --- a/src/modem/src/gmskdem.c +++ b/src/modem/src/gmskdem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -212,7 +212,7 @@ int gmskdem_set_eq_bw(gmskdem _q, // set internal equalizer bandwidth eqlms_rrrf_set_bw(_q->eq, _bw); #else - fprintf(stderr,"warning: gmskdem_set_eq_bw(), equalizer is disabled\n"); + return liquid_error(LIQUID_ENOIMP,"gmskdem_set_eq_bw(), equalizer is disabled"); #endif return LIQUID_OK; } diff --git a/src/modem/src/modem_utilities.c b/src/modem/src/modem_utilities.c index be0e6dd64..881768a71 100644 --- a/src/modem/src/modem_utilities.c +++ b/src/modem/src/modem_utilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -114,7 +114,7 @@ modulation_scheme liquid_getopt_str2mod(const char * _str) if (strcmp(_str,modulation_types[i].name)==0) return i; } - fprintf(stderr,"warning: liquid_getopt_str2mod(), unknown/unsupported mod scheme : %s\n", _str); + liquid_error(LIQUID_EICONFIG,"liquid_getopt_str2mod(), unknown/unsupported mod scheme: %s", _str); return LIQUID_MODEM_UNKNOWN; } From 5ea4ef7b5fd21bb3b1321199ac81bbeb9469c392 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 15:03:32 -0400 Subject: [PATCH 169/334] multichannel/optim: replacing warning with internal error handling --- src/multichannel/src/ofdmframesync.c | 4 ++-- src/optim/src/gradsearch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 7f008b054..515c5c7df 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -475,7 +475,7 @@ int ofdmframesync_execute_seekplcp(ofdmframesync _q) // estimate gain unsigned int i; - // start with a reasonably small number to avoid divide-by-zero warning + // start with a reasonably small number to avoid division by zero float g = 1.0e-9f; for (i=_q->cp_len; i<_q->M + _q->cp_len; i++) { // compute |rc[i]|^2 efficiently @@ -932,7 +932,7 @@ int ofdmframesync_estimate_eqgain(ofdmframesync _q, // eliminate divide-by-zero issues if (cabsf(w0) < 1e-4f) { - fprintf(stderr,"warning: ofdmframesync_estimate_eqgain(), weighting factor is zero\n"); + liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain(), weighting factor is zero"); w0 = 1.0f; } _q->G[i] = G_hat / w0; diff --git a/src/optim/src/gradsearch.c b/src/optim/src/gradsearch.c index 1cea9dbbf..d079f4b9c 100644 --- a/src/optim/src/gradsearch.c +++ b/src/optim/src/gradsearch.c @@ -136,7 +136,7 @@ float gradsearch_step(gradsearch _q) } if (i == n) { - fprintf(stderr,"warning: gradsearch_step(), function ill-conditioned\n"); + liquid_error(LIQUID_ENOCONV,"gradsearch_step(), function ill-conditioned"); return _q->utility(_q->userdata, _q->v, _q->num_parameters); } From 4cd5c455e8f22d3f3b8439b55aefefd225797bce Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 1 Jul 2023 15:05:49 -0400 Subject: [PATCH 170/334] build: making include path explicit --- makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.in b/makefile.in index ddac1ece7..11d70bbd2 100644 --- a/makefile.in +++ b/makefile.in @@ -54,7 +54,7 @@ exec_prefix := @exec_prefix@ VPATH := @srcdir@ srcdir := @srcdir@ libdir := @libdir@ -include_dirs := . include +include_dirs := . ./include # programs CC := @CC@ From 3c40acc46b0ce4dca9d719085bc101c118d97a50 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 4 Jul 2023 15:46:45 -0400 Subject: [PATCH 171/334] qdetector/autotest: consolidating testing with common function --- include/liquid.h | 2 +- src/framing/tests/qdetector_cccf_autotest.c | 194 +++++--------------- 2 files changed, 42 insertions(+), 154 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 2285b7882..e6b2caf10 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6330,7 +6330,7 @@ int QDETECTOR(_set_range)(QDETECTOR() _q, \ /* Get sequence length */ \ unsigned int QDETECTOR(_get_seq_len)(QDETECTOR() _q); \ \ -/* Get pointer to sequence of detected frame */ \ +/* Get pointer to original sequence */ \ const void * QDETECTOR(_get_sequence)(QDETECTOR() _q); \ \ /* Get buffer length */ \ diff --git a/src/framing/tests/qdetector_cccf_autotest.c b/src/framing/tests/qdetector_cccf_autotest.c index 3b073788e..d86da43ab 100644 --- a/src/framing/tests/qdetector_cccf_autotest.c +++ b/src/framing/tests/qdetector_cccf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,9 +30,8 @@ void qdetector_cccf_runtest_linear(unsigned int _sequence_len); void qdetector_cccf_runtest_gmsk (unsigned int _sequence_len); -// -// AUTOTESTS -// +// run test given initialized object +void qdetector_cccf_runtest(qdetector_cccf _q); // linear tests void autotest_qdetector_cccf_linear_n64() { qdetector_cccf_runtest_linear( 64); } @@ -66,123 +65,25 @@ void qdetector_cccf_runtest_linear(unsigned int _sequence_len) unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; // filter type - float gamma = 1.0f; // channel gain - float tau = -0.3f; // fractional sample timing offset - float dphi = -0.000f; // carrier frequency offset (zero for now) - float phi = 0.5f; // carrier phase offset - - unsigned int i; - - // derived values - unsigned int num_symbols = 8*_sequence_len + 2*m; - unsigned int num_samples = k * num_symbols; - - // arrays - float complex x[num_samples]; // transmitted signal - float complex y[num_samples]; // received signal // generate synchronization sequence (QPSK symbols) + unsigned int i; float complex sequence[_sequence_len]; for (i=0; i<_sequence_len; i++) { sequence[i] = (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 + (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 * _Complex_I; } - // generate transmitted signal - firinterp_crcf interp = firinterp_crcf_create_prototype(ftype, k, m, beta, -tau); - unsigned int n = 0; - for (i=0; i Date: Fri, 7 Jul 2023 07:51:36 -0400 Subject: [PATCH 172/334] benchmark: recording number of attempts to reach target runtime --- bench/bench.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/bench/bench.c b/bench/bench.c index a3998510a..4089313dd 100644 --- a/bench/bench.c +++ b/bench/bench.c @@ -45,14 +45,15 @@ typedef void(benchmark_function_t) ( // define benchmark_t typedef struct { - unsigned int id; - benchmark_function_t * api; - const char* name; - unsigned int name_len; - unsigned int num_trials; - float extime; - float rate; - float cycles_per_trial; + unsigned int id; // identification of benchmark + benchmark_function_t * api; // function interface + const char * name; // name of function + unsigned int name_len; + unsigned int num_trials; + float extime; + float rate; + float cycles_per_trial;// + unsigned int num_attempts; // number of attempts to reach target time } benchmark_t; // define package_t @@ -292,12 +293,13 @@ int main(int argc, char *argv[]) fprintf(fid," \"num_trials\" : %lu,\n", num_base_trials); fprintf(fid," \"benchmarks\" : [\n"); for (i=0; inum_trials = num_trials; + _benchmark->num_attempts = num_attempts; _benchmark->rate = _benchmark->extime==0 ? 0 : (float)(_benchmark->num_trials) / _benchmark->extime; _benchmark->cycles_per_trial = _benchmark->extime==0 ? 0 : cpu_clock / (_benchmark->rate); @@ -448,8 +451,8 @@ void print_benchmark_results(benchmark_t* _b) float cycles_format = _b->cycles_per_trial; char cycles_units = convert_units(&cycles_format); - printf(" %-3u: %-30s: %6.2f %c trials / %6.2f %cs (%6.2f %c t/s, %6.2f %c c/t)\n", - _b->id, _b->name, + printf(" %-3u: [%2u] %-30s: %6.2f %c trials / %6.2f %cs (%6.2f %c t/s, %6.2f %c c/t)\n", + _b->id, _b->num_attempts, _b->name, trials_format, trials_units, extime_format, extime_units, rate_format, rate_units, From 5c5e327140071995b19b998f16422c94bc32c48b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 7 Jul 2023 08:01:55 -0400 Subject: [PATCH 173/334] rresamp/bench: adjusting trials to be more consistent --- src/filter/bench/rresamp_crcf_benchmark.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/filter/bench/rresamp_crcf_benchmark.c b/src/filter/bench/rresamp_crcf_benchmark.c index ed15f284d..d18198368 100644 --- a/src/filter/bench/rresamp_crcf_benchmark.c +++ b/src/filter/bench/rresamp_crcf_benchmark.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2019 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,8 +31,8 @@ void rresamp_crcf_bench(struct rusage * _start, unsigned int _P, unsigned int _Q) { - // adjust number of iterations: cycles/trial ~ 160 + 50 Q - *_num_iterations /= (160 + 50*_Q); + // adjust number of iterations + *_num_iterations = *_num_iterations * liquid_nextpow2(_Q+1) / (4*_Q); // create resampling object unsigned int m = 12; From d1bbc133291bd7ec5334433b773b04837e6228c2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 7 Jul 2023 08:07:25 -0400 Subject: [PATCH 174/334] smatrix/bench: adjusting trials to be more consistent --- src/matrix/bench/smatrixf_mul_benchmark.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/matrix/bench/smatrixf_mul_benchmark.c b/src/matrix/bench/smatrixf_mul_benchmark.c index e19372b7a..1d510cc05 100644 --- a/src/matrix/bench/smatrixf_mul_benchmark.c +++ b/src/matrix/bench/smatrixf_mul_benchmark.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,8 +33,7 @@ void smatrixf_mul_bench(struct rusage * _start, { // normalize number of iterations // time ~ _n ^ 3 - *_num_iterations /= _n * _n * _n; - if (*_num_iterations < 1) *_num_iterations = 1; + *_num_iterations = 1 + *_num_iterations * 8192 / (_n * _n * _n + 1); unsigned long int i; From 392fb31f562aca6ddd390770561d9aa21359b6c4 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 7 Jul 2023 08:15:38 -0400 Subject: [PATCH 175/334] spgram/bench: adjusting trials to be more consistent --- src/fft/bench/spgramcf_benchmark.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fft/bench/spgramcf_benchmark.c b/src/fft/bench/spgramcf_benchmark.c index 7fe85a2c5..40aee4a41 100644 --- a/src/fft/bench/spgramcf_benchmark.c +++ b/src/fft/bench/spgramcf_benchmark.c @@ -33,12 +33,16 @@ void spgramcf_runbench(struct rusage * _start, unsigned long int * _num_iterations, unsigned int _nfft) { + // scale number of iterations to keep execution time + // relatively linear + *_num_iterations = (*_num_iterations) * liquid_nextpow2(1+_nfft) / _nfft; + // create object spgramcf q = spgramcf_create_default(_nfft); // initialize buffer with random values unsigned long int i; - unsigned int buf_len = 17*_nfft + 31; + unsigned int buf_len = 2400; float complex * buf = (float complex*) malloc(buf_len*sizeof(float complex)); for (i=0; i Date: Fri, 21 Jul 2023 08:11:54 -0400 Subject: [PATCH 176/334] build: removing extraneous 'error' strings in messages --- src/buffer/src/buffer.proto.c | 12 +++++------- src/dotprod/src/dotprod.proto.c | 4 ++-- src/fft/src/fft_utilities.c | 2 +- src/filter/src/butter.c | 4 ++-- src/filter/src/fdelay.proto.c | 4 ++-- src/filter/tests/firdespm_autotest.c | 6 +++--- src/filter/tests/firfilt_copy_autotest.c | 4 ++-- src/framing/src/gmskframegen.c | 2 +- src/framing/tests/qpilotsync_autotest.c | 4 ++-- src/framing/tests/symstreamrcf_delay_autotest.c | 4 ++-- .../tests/firpfbch_crcf_synthesizer_autotest.c | 4 ++-- src/random/src/rand.c | 8 ++++---- src/random/src/randexp.c | 8 ++++---- 13 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/buffer/src/buffer.proto.c b/src/buffer/src/buffer.proto.c index 853e095ee..c735d686c 100644 --- a/src/buffer/src/buffer.proto.c +++ b/src/buffer/src/buffer.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -142,14 +142,12 @@ void BUFFER(_read)(BUFFER() _b, T ** _v, unsigned int *_n) void BUFFER(_c_read)(BUFFER() _b, T ** _v, unsigned int *_n) { //printf("buffer_read() trying to read %u elements (%u available)\n", *_n, _b->num_elements); -#if 0 if (*_n > _b->num_elements) { - printf("error: buffer_read(), cannot read more elements than are available\n"); + liquid_error(LIQUID_EIRANGE,"buffer%s_read(), cannot read more elements than are available", EXTENSION); *_v = NULL; *_n = 0; return; } else -#endif if (*_n > (_b->len - _b->read_index)) { // BUFFER(_linearize)(_b); @@ -178,7 +176,7 @@ void BUFFER(_c_release)(BUFFER() _b, unsigned int _n) { // advance read_index by _n making sure not to step on write_index if (_n > _b->num_elements) { - printf("error: buffer_c_release(), cannot release more elements in buffer than exist\n"); + liquid_error(LIQUID_EIRANGE,"buffer%s_c_release(), cannot release more elements in buffer than exist", EXTENSION); return; } @@ -204,7 +202,7 @@ void BUFFER(_c_write)(BUFFER() _b, T * _v, unsigned int _n) { // if (_n > (_b->len - _b->num_elements)) { - printf("error: buffer_write(), cannot write more elements than are available\n"); + liquid_error(LIQUID_EIRANGE,"buffer%s_write(), cannot write more elements than are available", EXTENSION); return; } @@ -227,7 +225,7 @@ void BUFFER(_c_write)(BUFFER() _b, T * _v, unsigned int _n) void BUFFER(_s_write)(BUFFER() _b, T * _v, unsigned int _n) { if (_n > (_b->len - _b->num_elements)) { - printf("error: buffer_s_write(), cannot write more elements than are available\n"); + liquid_error(LIQUID_EIRANGE,"buffer%s_s_write(), cannot write more elements than are available", EXTENSION); return; } diff --git a/src/dotprod/src/dotprod.proto.c b/src/dotprod/src/dotprod.proto.c index d5be913b3..059644e18 100644 --- a/src/dotprod/src/dotprod.proto.c +++ b/src/dotprod/src/dotprod.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -189,7 +189,7 @@ DOTPROD() DOTPROD(_copy)(DOTPROD() q_orig) { // validate input if (q_orig == NULL) - return liquid_error_config("error: dotprod_%s_copy(), window object cannot be NULL", "xxxt"); + return liquid_error_config("dotprod_%s_copy(), window object cannot be NULL", "xxxt"); // create new base object and copy parameters DOTPROD() q_copy = (DOTPROD()) malloc(sizeof(struct DOTPROD(_s))); diff --git a/src/fft/src/fft_utilities.c b/src/fft/src/fft_utilities.c index 0a11de20b..bba04890f 100644 --- a/src/fft/src/fft_utilities.c +++ b/src/fft/src/fft_utilities.c @@ -35,7 +35,7 @@ liquid_fft_method liquid_fft_estimate_method(unsigned int _nfft) { if (_nfft == 0) { // invalid length - fprintf(stderr,"error: liquid_fft_estimate_method(), fft size must be > 0\n"); + liquid_error(LIQUID_EIRANGE,"liquid_fft_estimate_method(), fft size must be > 0"); return LIQUID_FFT_METHOD_UNKNOWN; } else if (_nfft <= 8 || _nfft==11 || _nfft==13 || _nfft==16 || _nfft==17) { diff --git a/src/filter/src/butter.c b/src/filter/src/butter.c index fd85b20bf..ff8d6a418 100644 --- a/src/filter/src/butter.c +++ b/src/filter/src/butter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -60,7 +60,7 @@ int butter_azpkf(unsigned int _n, if (r) _pa[k++] = -1.0f; if (k != _n) - return liquid_error(LIQUID_EINT,"butter_azpkf(), internal error: filter order mismatch"); + return liquid_error(LIQUID_EINT,"butter_azpkf(), filter order mismatch"); *_ka = 1.0; return LIQUID_OK; diff --git a/src/filter/src/fdelay.proto.c b/src/filter/src/fdelay.proto.c index 16c7439bd..3a5af351a 100644 --- a/src/filter/src/fdelay.proto.c +++ b/src/filter/src/fdelay.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -142,7 +142,7 @@ int FDELAY(_set_delay)(FDELAY() _q, // ensure valid range; clip if needed. Note that w_index can be equal // to nmax because the window was provisioned for nmax+1 if (_q->w_index > _q->nmax) - return liquid_error(LIQUID_EINT,"fdelay_%s_set_delay(), logic error: window index exceeds maximum", EXTENSION_FULL); + return liquid_error(LIQUID_EINT,"fdelay_%s_set_delay(), window index exceeds maximum", EXTENSION_FULL); #if 0 // debug printf("delay:%f -> offset:%f -> %d + %f -> %d + (%u/%u)\n", diff --git a/src/filter/tests/firdespm_autotest.c b/src/filter/tests/firdespm_autotest.c index a959b5f0f..e40380838 100644 --- a/src/filter/tests/firdespm_autotest.c +++ b/src/filter/tests/firdespm_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -334,7 +334,7 @@ void autotest_firdespm_differentiator() liquid_firdespm_wtype wtype[2] = {LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT}; liquid_firdespm_btype btype = LIQUID_FIRDESPM_DIFFERENTIATOR; firdespm q = firdespm_create(n, 2, bands, des, w, wtype, btype); - // error: unsupported configuration + // unsupported configuration CONTEND_EQUALITY( LIQUID_EINT, firdespm_execute(q,h) ) firdespm_destroy(q); } @@ -358,7 +358,7 @@ void autotest_firdespm_hilbert() liquid_firdespm_wtype wtype[2] = {LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT}; liquid_firdespm_btype btype = LIQUID_FIRDESPM_HILBERT; firdespm q = firdespm_create(n, 2, bands, des, w, wtype, btype); - // error: unsupported configuration + // unsupported configuration CONTEND_EQUALITY( LIQUID_EINT, firdespm_execute(q,h) ) firdespm_destroy(q); } diff --git a/src/filter/tests/firfilt_copy_autotest.c b/src/filter/tests/firfilt_copy_autotest.c index cd5f42c12..be5858d19 100644 --- a/src/filter/tests/firfilt_copy_autotest.c +++ b/src/filter/tests/firfilt_copy_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,7 +53,7 @@ void autotest_firfilt_crcf_copy() if (liquid_autotest_verbose) { float error = cabsf( y_orig - y_copy ); - printf(" [%3u] orig: %12.8f + j%12.8f, copy: %12.8f + j%12.8f, error: %8g\n", + printf(" [%3u] orig: %12.8f + j%12.8f, copy: %12.8f + j%12.8f, err: %8g\n", i+n, crealf(y_orig), cimagf(y_orig), crealf(y_copy), cimagf(y_copy), diff --git a/src/framing/src/gmskframegen.c b/src/framing/src/gmskframegen.c index 897bce6a7..aee09a8a9 100644 --- a/src/framing/src/gmskframegen.c +++ b/src/framing/src/gmskframegen.c @@ -340,7 +340,7 @@ int gmskframegen_gen_symbol(gmskframegen _q) case STATE_PAYLOAD: gmskframegen_write_payload (_q); break; case STATE_TAIL: gmskframegen_write_tail (_q); break; default: - return liquid_error(LIQUID_EINT,"error: gmskframegen_writesymbol(), invalid internal state"); + return liquid_error(LIQUID_EINT,"gmskframegen_writesymbol(), invalid internal state"); } /* diff --git a/src/framing/tests/qpilotsync_autotest.c b/src/framing/tests/qpilotsync_autotest.c index 2c52ec802..d0d8702c8 100644 --- a/src/framing/tests/qpilotsync_autotest.c +++ b/src/framing/tests/qpilotsync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -140,7 +140,7 @@ void qpilotsync_test(modulation_scheme _ms, sprintf(filename,"autotest/logs/qpilotsync_autotest_%u_%u_debug.m", _payload_len, _pilot_spacing); FILE * fid = fopen(filename,"w"); if (!fid) { - fprintf(stderr,"error: could not open '%s' for writing\n", filename); + liquid_error(LIQUID_EIO,"could not open '%s' for writing", filename); return; } fprintf(fid,"%% %s : auto-generated file\n", filename); diff --git a/src/framing/tests/symstreamrcf_delay_autotest.c b/src/framing/tests/symstreamrcf_delay_autotest.c index 5446502f7..3bfd88e70 100644 --- a/src/framing/tests/symstreamrcf_delay_autotest.c +++ b/src/framing/tests/symstreamrcf_delay_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -68,7 +68,7 @@ void testbench_symstreamrcf_delay(float _bw, // print results if (liquid_autotest_verbose) { - printf("expected delay: %.6f, measured: %.6f, error: %.6f (tol= %.3f)\n", + printf("expected delay: %.6f, measured: %.6f, err: %.6f (tol= %.3f)\n", delay, delay_meas, delay-delay_meas,tol); } diff --git a/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c b/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c index 038b2380f..ab279fcb1 100644 --- a/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c +++ b/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -130,7 +130,7 @@ void autotest_firpfbch_crcf_synthesis() // print channelizer outputs if (liquid_autotest_verbose) { - printf("%3u: old:%8.5f+j%8.5f, firpfbch:%8.5f+j%8.5f, error:%12.4e+j%12.4e\n", + printf("%3u: old:%8.5f+j%8.5f, firpfbch:%8.5f+j%8.5f, err:%12.4e+j%12.4e\n", i, crealf(y0[i]), cimagf(y0[i]), crealf(y1[i]), cimagf(y1[i]), diff --git a/src/random/src/rand.c b/src/random/src/rand.c index e1d75781f..acc214cf7 100644 --- a/src/random/src/rand.c +++ b/src/random/src/rand.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,7 +58,7 @@ float randuf(float _a, float _b) { // check bounds if (_a >= _b) { - fprintf(stderr,"error: %s:%u, randuf() has invalid range\n", __FILE__, __LINE__); + liquid_error(LIQUID_EIRANGE,"randuf(%g,%g) has invalid range", _a, _b); return 0; } @@ -72,7 +72,7 @@ float randuf_pdf(float _x, { // check bounds if (_a >= _b) { - fprintf(stderr,"error: %s:%u, randuf_pdf() has invalid range\n", __FILE__, __LINE__); + liquid_error(LIQUID_EIRANGE,"randuf_pdf(%g,%g,%g) has invalid range", _x, _a, _b); return 0; } @@ -86,7 +86,7 @@ float randuf_cdf(float _x, { // check bounds if (_a >= _b) { - fprintf(stderr,"error: %s:%u, randuf_cdf() has invalid range\n", __FILE__, __LINE__); + liquid_error(LIQUID_EIRANGE,"randuf_cdf(%g,%g,%g) has invalid range", _x, _a, _b); return 0; } diff --git a/src/random/src/randexp.c b/src/random/src/randexp.c index 12d6ac295..a3442ed9d 100644 --- a/src/random/src/randexp.c +++ b/src/random/src/randexp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +35,7 @@ float randexpf(float _lambda) { // validate input if (_lambda <= 0) { - fprintf(stderr,"error: randexpf(), lambda must be greater than zero\n"); + liquid_error(LIQUID_EIRANGE,"randexpf(%g) has invalid range", _lambda); return 0.0f; } @@ -55,7 +55,7 @@ float randexpf_pdf(float _x, { // validate input if (_lambda <= 0) { - fprintf(stderr,"error: randexpf(), lambda must be greater than zero\n"); + liquid_error(LIQUID_EIRANGE,"randexpf_pdf(%g,%g) has invalid range", _x, _lambda); return 0.0f; } @@ -71,7 +71,7 @@ float randexpf_cdf(float _x, { // validate input if (_lambda <= 0) { - fprintf(stderr,"error: randexpf(), lambda must be greater than zero\n"); + liquid_error(LIQUID_EIRANGE,"randexpf_cdf(%g,%g) has invalid range", _x, _lambda); return 0.0f; } From 9653f64dc6603156c51f31b2f57c9eda4bb97a4c Mon Sep 17 00:00:00 2001 From: Sean Nowlan Date: Thu, 7 Sep 2023 14:09:25 -0400 Subject: [PATCH 177/334] qs1dsearch: free object in _destroy --- src/optim/src/qs1dsearch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/optim/src/qs1dsearch.c b/src/optim/src/qs1dsearch.c index 35d051729..16600b829 100644 --- a/src/optim/src/qs1dsearch.c +++ b/src/optim/src/qs1dsearch.c @@ -65,6 +65,7 @@ qs1dsearch qs1dsearch_copy(qs1dsearch _q) int qs1dsearch_destroy(qs1dsearch _q) { + free(_q); return LIQUID_OK; } From bcd2f088a3cec944413384edab383ca402737bfa Mon Sep 17 00:00:00 2001 From: Andreas Bombe Date: Sat, 9 Sep 2023 01:56:34 +0530 Subject: [PATCH 178/334] bessel: fix array out of bounds write in bessel_azpkf() --- src/filter/src/bessel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/filter/src/bessel.c b/src/filter/src/bessel.c index 8a63efd15..79c715921 100644 --- a/src/filter/src/bessel.c +++ b/src/filter/src/bessel.c @@ -68,9 +68,15 @@ int bessel_azpkf(unsigned int _n, float complex * _pa, float complex * _ka) { + // roots are computed with order _n+1 so we must use a longer array to + // prevent out-of-bounds write on the provided _pa array + float complex _tmp_pa[_n+1]; + // compute poles (roots to Bessel polynomial) - if (fpoly_bessel_roots(_n+1,_pa) != LIQUID_OK) + if (fpoly_bessel_roots(_n+1,_tmp_pa) != LIQUID_OK) return liquid_error(LIQUID_EICONFIG,"bessel_azpkf(), invalid configuration"); + for (int i = 0; i < _n; i++) + _pa[i] = _tmp_pa[i]; // analog Bessel filter prototype has no zeros From f7e937878b52a36018674d9d5a5e9ee21a4c7117 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 09:48:34 -0400 Subject: [PATCH 179/334] iirhilb: using error-handling interface --- include/liquid.h | 46 ++++++++++----------- src/filter/src/iirhilb.proto.c | 73 ++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 53 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index e6b2caf10..70b84c436 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -3175,21 +3175,21 @@ IIRHILB() IIRHILB(_create_default)(unsigned int _n); \ \ /* Destroy finite impulse response Hilbert transform, freeing all */ \ /* internally-allocted memory and objects. */ \ -void IIRHILB(_destroy)(IIRHILB() _q); \ +int IIRHILB(_destroy)(IIRHILB() _q); \ \ /* Print iirhilb object internals to stdout */ \ -void IIRHILB(_print)(IIRHILB() _q); \ +int IIRHILB(_print)(IIRHILB() _q); \ \ /* Reset iirhilb object internal state */ \ -void IIRHILB(_reset)(IIRHILB() _q); \ +int IIRHILB(_reset)(IIRHILB() _q); \ \ /* Execute Hilbert transform (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input sample */ \ /* _y : complex-valued output sample */ \ -void IIRHILB(_r2c_execute)(IIRHILB() _q, \ - T _x, \ - TC * _y); \ +int IIRHILB(_r2c_execute)(IIRHILB() _q, \ + T _x, \ + TC * _y); \ \ /* Execute Hilbert transform (real to complex) on a block of samples */ \ /* _q : Hilbert transform object */ \ @@ -3205,9 +3205,9 @@ int IIRHILB(_r2c_execute_block)(IIRHILB() _q, \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y : real-valued output sample */ \ -void IIRHILB(_c2r_execute)(IIRHILB() _q, \ - TC _x, \ - T * _y); \ +int IIRHILB(_c2r_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ \ /* Execute Hilbert transform (complex to real) on a block of samples */ \ /* _q : Hilbert transform object */ \ @@ -3223,9 +3223,9 @@ int IIRHILB(_c2r_execute_block)(IIRHILB() _q, \ /* _q : Hilbert transform object */ \ /* _x : real-valued input array, [size: 2 x 1] */ \ /* _y : complex-valued output sample */ \ -void IIRHILB(_decim_execute)(IIRHILB() _q, \ - T * _x, \ - TC * _y); \ +int IIRHILB(_decim_execute)(IIRHILB() _q, \ + T * _x, \ + TC * _y); \ \ /* Execute Hilbert transform decimator (real to complex) on a block of */ \ /* samples */ \ @@ -3233,18 +3233,18 @@ void IIRHILB(_decim_execute)(IIRHILB() _q, \ /* _x : real-valued input array, [size: 2*_n x 1] */ \ /* _n : number of output samples */ \ /* _y : complex-valued output array, [size: _n x 1] */ \ -void IIRHILB(_decim_execute_block)(IIRHILB() _q, \ - T * _x, \ - unsigned int _n, \ - TC * _y); \ +int IIRHILB(_decim_execute_block)(IIRHILB() _q, \ + T * _x, \ + unsigned int _n, \ + TC * _y); \ \ /* Execute Hilbert transform interpolator (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y : real-valued output array, [size: 2 x 1] */ \ -void IIRHILB(_interp_execute)(IIRHILB() _q, \ - TC _x, \ - T * _y); \ +int IIRHILB(_interp_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ \ /* Execute Hilbert transform interpolator (complex to real) on a block */ \ /* of samples */ \ @@ -3252,10 +3252,10 @@ void IIRHILB(_interp_execute)(IIRHILB() _q, \ /* _x : complex-valued input array, [size: _n x 1] */ \ /* _n : number of *input* samples */ \ /* _y : real-valued output array, [size: 2*_n x 1] */ \ -void IIRHILB(_interp_execute_block)(IIRHILB() _q, \ - TC * _x, \ - unsigned int _n, \ - T * _y); \ +int IIRHILB(_interp_execute_block)(IIRHILB() _q, \ + TC * _x, \ + unsigned int _n, \ + T * _y); \ LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_FLOAT, float, liquid_float_complex) //LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) diff --git a/src/filter/src/iirhilb.proto.c b/src/filter/src/iirhilb.proto.c index 443e3877c..51fcf6e22 100644 --- a/src/filter/src/iirhilb.proto.c +++ b/src/filter/src/iirhilb.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,6 @@ struct IIRHILB(_s) { // filter objects IIRFILT() filt_0; // upper filter branch IIRFILT() filt_1; // lower filter branch - unsigned int state; // bookkeeping state }; @@ -97,40 +96,48 @@ IIRHILB() IIRHILB(_copy)(IIRHILB() q_orig) } // destroy iirhilb object -void IIRHILB(_destroy)(IIRHILB() _q) +int IIRHILB(_destroy)(IIRHILB() _q) { // destroy window buffers - IIRFILT(_destroy)(_q->filt_0); - IIRFILT(_destroy)(_q->filt_1); + int rc_0 = IIRFILT(_destroy)(_q->filt_0); + int rc_1 = IIRFILT(_destroy)(_q->filt_1); // free main object memory free(_q); + + return (rc_0 == LIQUID_OK && rc_1 == LIQUID_OK) ? + LIQUID_OK : + liquid_error(LIQUID_EINT,"iirhilb%s_destroy(), could not destroy object", EXTENSION_SHORT); } // print iirhilb object internals -void IIRHILB(_print)(IIRHILB() _q) +int IIRHILB(_print)(IIRHILB() _q) { - printf("iir hilbert transform\n"); + printf("\n"); + return LIQUID_OK; } // reset iirhilb object internal state -void IIRHILB(_reset)(IIRHILB() _q) +int IIRHILB(_reset)(IIRHILB() _q) { // clear window buffers - IIRFILT(_reset)(_q->filt_0); - IIRFILT(_reset)(_q->filt_1); + int rc_0 = IIRFILT(_reset)(_q->filt_0); + int rc_1 = IIRFILT(_reset)(_q->filt_1); // reset state flag _q->state = 0; + return (rc_0 == LIQUID_OK && rc_1 == LIQUID_OK) ? + LIQUID_OK : + liquid_error(LIQUID_EINT,"iirhilb%s_reset(), could not reset object", EXTENSION_SHORT); } // execute Hilbert transform (real to complex) // _q : iirhilb object // _x : real-valued input sample // _y : complex-valued output sample -void IIRHILB(_r2c_execute)(IIRHILB() _q, - T _x, - T complex * _y) +int IIRHILB(_r2c_execute)(IIRHILB() _q, + T _x, + T complex * _y) { // compute relevant output depending on state T yi = 0; @@ -161,6 +168,7 @@ void IIRHILB(_r2c_execute)(IIRHILB() _q, // cycle through state _q->state = (_q->state + 1) & 0x3; + return LIQUID_OK; } // Execute Hilbert transform (real to complex) on a block of samples @@ -179,9 +187,9 @@ int IIRHILB(_r2c_execute_block)(IIRHILB() _q, // _q : iirhilb object // _y : complex-valued input sample // _x : real-valued output sample -void IIRHILB(_c2r_execute)(IIRHILB() _q, - T complex _x, - T * _y) +int IIRHILB(_c2r_execute)(IIRHILB() _q, + T complex _x, + T * _y) { // compute relevant output depending on state T yi = 0; @@ -212,6 +220,7 @@ void IIRHILB(_c2r_execute)(IIRHILB() _q, // cycle through state _q->state = (_q->state + 1) & 0x3; + return LIQUID_OK; } // Execute Hilbert transform (complex to real) on a block of samples int IIRHILB(_c2r_execute_block)(IIRHILB() _q, @@ -229,9 +238,9 @@ int IIRHILB(_c2r_execute_block)(IIRHILB() _q, // _q : iirhilb object // _x : real-valued input array [size: 2 x 1] // _y : complex-valued output sample -void IIRHILB(_decim_execute)(IIRHILB() _q, - T * _x, - T complex * _y) +int IIRHILB(_decim_execute)(IIRHILB() _q, + T * _x, + T complex * _y) { // mix down by Fs/4 T xi = _q->state ? -_x[0] : _x[0]; @@ -252,6 +261,7 @@ void IIRHILB(_decim_execute)(IIRHILB() _q, // toggle state flag _q->state = 1 - _q->state; + return LIQUID_OK; } // execute Hilbert transform decimator (real to complex) on @@ -260,24 +270,25 @@ void IIRHILB(_decim_execute)(IIRHILB() _q, // _x : real-valued input array [size: 2*_n x 1] // _n : number of *output* samples // _y : complex-valued output array [size: _n x 1] -void IIRHILB(_decim_execute_block)(IIRHILB() _q, - T * _x, - unsigned int _n, - T complex * _y) +int IIRHILB(_decim_execute_block)(IIRHILB() _q, + T * _x, + unsigned int _n, + T complex * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_decim_execute)(_q, &_x[2*i], &_y[i]); + return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) // _q : iirhilb object // _y : complex-valued input sample // _x : real-valued output array [size: 2 x 1] -void IIRHILB(_interp_execute)(IIRHILB() _q, - T complex _x, - T * _y) +int IIRHILB(_interp_execute)(IIRHILB() _q, + T complex _x, + T * _y) { // upper branch T yi0, yi1; @@ -298,6 +309,7 @@ void IIRHILB(_interp_execute)(IIRHILB() _q, // toggle state flag _q->state = 1 - _q->state; + return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) @@ -306,13 +318,14 @@ void IIRHILB(_interp_execute)(IIRHILB() _q, // _x : complex-valued input array [size: _n x 1] // _n : number of *input* samples // _y : real-valued output array [size: 2*_n x 1] -void IIRHILB(_interp_execute_block)(IIRHILB() _q, - T complex * _x, - unsigned int _n, - T * _y) +int IIRHILB(_interp_execute_block)(IIRHILB() _q, + T complex * _x, + unsigned int _n, + T * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_interp_execute)(_q, _x[i], &_y[2*i]); + return LIQUID_OK; } From be8456caea84f421e479b37dec1ed0dcbde35663 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 09:53:02 -0400 Subject: [PATCH 180/334] iirinterp: using error-handling interface --- include/liquid.h | 20 ++++++++++---------- src/filter/src/iirinterp.proto.c | 28 +++++++++++++++------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 70b84c436..6d9ff6d2d 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -3933,32 +3933,32 @@ IIRINTERP() IIRINTERP(_create_prototype)( \ IIRINTERP() IIRINTERP(_copy)(IIRINTERP() _q); \ \ /* Destroy interpolator object and free internal memory */ \ -void IIRINTERP(_destroy)(IIRINTERP() _q); \ +int IIRINTERP(_destroy)(IIRINTERP() _q); \ \ /* Print interpolator object internals to stdout */ \ -void IIRINTERP(_print)(IIRINTERP() _q); \ +int IIRINTERP(_print)(IIRINTERP() _q); \ \ /* Reset interpolator object */ \ -void IIRINTERP(_reset)(IIRINTERP() _q); \ +int IIRINTERP(_reset)(IIRINTERP() _q); \ \ /* Execute interpolation on single input sample and write \(M\) output */ \ /* samples (\(M\) is the interpolation factor) */ \ /* _q : iirinterp object */ \ /* _x : input sample */ \ /* _y : output sample array, [size: _M x 1] */ \ -void IIRINTERP(_execute)(IIRINTERP() _q, \ - TI _x, \ - TO * _y); \ +int IIRINTERP(_execute)(IIRINTERP() _q, \ + TI _x, \ + TO * _y); \ \ /* Execute interpolation on block of input samples */ \ /* _q : iirinterp object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : size of input array */ \ /* _y : output sample array, [size: _M*_n x 1] */ \ -void IIRINTERP(_execute_block)(IIRINTERP() _q, \ - TI * _x, \ - unsigned int _n, \ - TO * _y); \ +int IIRINTERP(_execute_block)(IIRINTERP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ \ /* Compute and return group delay of object */ \ /* _q : filter object */ \ diff --git a/src/filter/src/iirinterp.proto.c b/src/filter/src/iirinterp.proto.c index fbcb0d521..54345057a 100644 --- a/src/filter/src/iirinterp.proto.c +++ b/src/filter/src/iirinterp.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -124,31 +124,31 @@ IIRINTERP() IIRINTERP(_copy)(IIRINTERP() q_orig) } // destroy interpolator object -void IIRINTERP(_destroy)(IIRINTERP() _q) +int IIRINTERP(_destroy)(IIRINTERP() _q) { IIRFILT(_destroy)(_q->iirfilt); free(_q); + return LIQUID_OK; } // print interpolator state -void IIRINTERP(_print)(IIRINTERP() _q) +int IIRINTERP(_print)(IIRINTERP() _q) { - printf("interp():\n"); - printf(" M : %u\n", _q->M); - IIRFILT(_print)(_q->iirfilt); + printf("\n", EXTENSION_FULL, _q->M); + return LIQUID_OK; } // clear internal state -void IIRINTERP(_reset)(IIRINTERP() _q) +int IIRINTERP(_reset)(IIRINTERP() _q) { - IIRFILT(_reset)(_q->iirfilt); + return IIRFILT(_reset)(_q->iirfilt); } // execute interpolator // _q : interpolator object // _x : input sample // _y : output array [size: 1 x _M] -void IIRINTERP(_execute)(IIRINTERP() _q, +int IIRINTERP(_execute)(IIRINTERP() _q, TI _x, TO * _y) { @@ -156,6 +156,7 @@ void IIRINTERP(_execute)(IIRINTERP() _q, unsigned int i; for (i=0; i<_q->M; i++) IIRFILT(_execute)(_q->iirfilt, i==0 ? _x : 0.0f, &_y[i]); + return LIQUID_OK; } // execute interpolation on block of input samples @@ -163,16 +164,17 @@ void IIRINTERP(_execute)(IIRINTERP() _q, // _x : input array [size: _n x 1] // _n : size of input array // _y : output sample array [size: _M*_n x 1] -void IIRINTERP(_execute_block)(IIRINTERP() _q, - TI * _x, - unsigned int _n, - TO * _y) +int IIRINTERP(_execute_block)(IIRINTERP() _q, + TI * _x, + unsigned int _n, + TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute one input at a time with an output stride _M IIRINTERP(_execute)(_q, _x[i], &_y[i*_q->M]); } + return LIQUID_OK; } // get system group delay at frequency _fc From bac3546dc00e29ed4f039b6fa46336c33a1d8316 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 09:56:25 -0400 Subject: [PATCH 181/334] iirdecim: using error-handling interface --- include/liquid.h | 20 ++++++++++---------- src/filter/src/iirdecim.proto.c | 32 +++++++++++++++++--------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 6d9ff6d2d..fc0e187c5 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4155,31 +4155,31 @@ IIRDECIM() IIRDECIM(_create_prototype)( \ IIRDECIM() IIRDECIM(_copy)(IIRDECIM() _q); \ \ /* Destroy decimator object and free internal memory */ \ -void IIRDECIM(_destroy)(IIRDECIM() _q); \ +int IIRDECIM(_destroy)(IIRDECIM() _q); \ \ /* Print decimator object internals */ \ -void IIRDECIM(_print)(IIRDECIM() _q); \ +int IIRDECIM(_print)(IIRDECIM() _q); \ \ /* Reset decimator object */ \ -void IIRDECIM(_reset)(IIRDECIM() _q); \ +int IIRDECIM(_reset)(IIRDECIM() _q); \ \ /* Execute decimator on _M input samples */ \ /* _q : decimator object */ \ /* _x : input samples, [size: _M x 1] */ \ /* _y : output sample pointer */ \ -void IIRDECIM(_execute)(IIRDECIM() _q, \ - TI * _x, \ - TO * _y); \ +int IIRDECIM(_execute)(IIRDECIM() _q, \ + TI * _x, \ + TO * _y); \ \ /* Execute decimator on block of _n*_M input samples */ \ /* _q : decimator object */ \ /* _x : input array, [size: _n*_M x 1] */ \ /* _n : number of _output_ samples */ \ /* _y : output array, [_sze: _n x 1] */ \ -void IIRDECIM(_execute_block)(IIRDECIM() _q, \ - TI * _x, \ - unsigned int _n, \ - TO * _y); \ +int IIRDECIM(_execute_block)(IIRDECIM() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ \ /* Compute and return group delay of object */ \ /* _q : filter object */ \ diff --git a/src/filter/src/iirdecim.proto.c b/src/filter/src/iirdecim.proto.c index de2915e29..08e29e57d 100644 --- a/src/filter/src/iirdecim.proto.c +++ b/src/filter/src/iirdecim.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -126,24 +126,24 @@ IIRDECIM() IIRDECIM(_copy)(IIRDECIM() q_orig) } // destroy interpolator object -void IIRDECIM(_destroy)(IIRDECIM() _q) +int IIRDECIM(_destroy)(IIRDECIM() _q) { IIRFILT(_destroy)(_q->iirfilt); free(_q); + return LIQUID_OK; } // print interpolator state -void IIRDECIM(_print)(IIRDECIM() _q) +int IIRDECIM(_print)(IIRDECIM() _q) { - printf("interp():\n"); - printf(" M : %u\n", _q->M); - IIRFILT(_print)(_q->iirfilt); + printf("\n", EXTENSION_FULL, _q->M); + return LIQUID_OK; } // clear internal state -void IIRDECIM(_reset)(IIRDECIM() _q) +int IIRDECIM(_reset)(IIRDECIM() _q) { - IIRFILT(_reset)(_q->iirfilt); + return IIRFILT(_reset)(_q->iirfilt); } // execute decimator @@ -151,9 +151,9 @@ void IIRDECIM(_reset)(IIRDECIM() _q) // _x : input sample array [size: _M x 1] // _y : output sample pointer // _index : decimator output index [0,_M-1] -void IIRDECIM(_execute)(IIRDECIM() _q, - TI * _x, - TO * _y) +int IIRDECIM(_execute)(IIRDECIM() _q, + TI * _x, + TO * _y) { TO v; // output value unsigned int i; @@ -165,6 +165,7 @@ void IIRDECIM(_execute)(IIRDECIM() _q, if (i==0) *_y = v; } + return LIQUID_OK; } // execute decimator on block of _n*_M input samples @@ -172,16 +173,17 @@ void IIRDECIM(_execute)(IIRDECIM() _q, // _x : input array [size: _n*_M x 1] // _n : number of _output_ samples // _y : output array [_sze: _n x 1] -void IIRDECIM(_execute_block)(IIRDECIM() _q, - TI * _x, - unsigned int _n, - TO * _y) +int IIRDECIM(_execute_block)(IIRDECIM() _q, + TI * _x, + unsigned int _n, + TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute _M input samples computing just one output each time IIRDECIM(_execute)(_q, &_x[i*_q->M], &_y[i]); } + return LIQUID_OK; } // get system group delay at frequency _fc From a5e12b0934139010bf8b0aeced9f67bb155d1138 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:01:30 -0400 Subject: [PATCH 182/334] resamp2: using error-handling interface --- include/liquid.h | 42 ++++++++++---------- src/filter/src/resamp2.proto.c | 70 ++++++++++++++++------------------ 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index fc0e187c5..67f072a39 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4239,13 +4239,13 @@ RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \ RESAMP2() RESAMP2(_copy)(RESAMP2() _q); \ \ /* Destroy resampler, freeing all internally-allocated memory */ \ -void RESAMP2(_destroy)(RESAMP2() _q); \ +int RESAMP2(_destroy)(RESAMP2() _q); \ \ /* print resampler object's internals to stdout */ \ -void RESAMP2(_print)(RESAMP2() _q); \ +int RESAMP2(_print)(RESAMP2() _q); \ \ /* Reset internal buffer */ \ -void RESAMP2(_reset)(RESAMP2() _q); \ +int RESAMP2(_reset)(RESAMP2() _q); \ \ /* Get resampler filter delay (semi-length m) */ \ unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \ @@ -4259,8 +4259,8 @@ int RESAMP2(_set_scale)(RESAMP2() _q, \ /* Get output scaling for resampler */ \ /* _q : resampler object */ \ /* _scale : scaling factor applied to each output sample */ \ -void RESAMP2(_get_scale)(RESAMP2() _q, \ - TC * _scale); \ +int RESAMP2(_get_scale)(RESAMP2() _q, \ + TC * _scale); \ \ /* Execute resampler as half-band filter for a single input sample */ \ /* \(x\) where \(y_0\) is the output of the effective low-pass filter, */ \ @@ -4269,10 +4269,10 @@ void RESAMP2(_get_scale)(RESAMP2() _q, \ /* _x : input sample */ \ /* _y0 : output sample pointer (low frequency) */ \ /* _y1 : output sample pointer (high frequency) */ \ -void RESAMP2(_filter_execute)(RESAMP2() _q, \ - TI _x, \ - TO * _y0, \ - TO * _y1); \ +int RESAMP2(_filter_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y0, \ + TO * _y1); \ \ /* Execute resampler as half-band analysis filterbank on a pair of */ \ /* sequential time-domain input samples. */ \ @@ -4281,9 +4281,9 @@ void RESAMP2(_filter_execute)(RESAMP2() _q, \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output array, [size: 2 x 1] */ \ -void RESAMP2(_analyzer_execute)(RESAMP2() _q, \ - TI * _x, \ - TO * _y); \ +int RESAMP2(_analyzer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ \ /* Execute resampler as half-band synthesis filterbank on a pair of */ \ /* input samples. The low- and high-pass input samples are provided by */ \ @@ -4292,26 +4292,26 @@ void RESAMP2(_analyzer_execute)(RESAMP2() _q, \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output array, [size: 2 x 1] */ \ -void RESAMP2(_synthesizer_execute)(RESAMP2() _q, \ - TI * _x, \ - TO * _y); \ +int RESAMP2(_synthesizer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ \ /* Execute resampler as half-band decimator on a pair of sequential */ \ /* time-domain input samples. */ \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output sample pointer */ \ -void RESAMP2(_decim_execute)(RESAMP2() _q, \ - TI * _x, \ - TO * _y); \ +int RESAMP2(_decim_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ \ /* Execute resampler as half-band interpolator on a single input sample */ \ /* _q : resampler object */ \ /* _x : input sample */ \ /* _y : output array, [size: 2 x 1] */ \ -void RESAMP2(_interp_execute)(RESAMP2() _q, \ - TI _x, \ - TO * _y); \ +int RESAMP2(_interp_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y); \ LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_RRRF, float, diff --git a/src/filter/src/resamp2.proto.c b/src/filter/src/resamp2.proto.c index edd2c1c2b..0122ff4e5 100644 --- a/src/filter/src/resamp2.proto.c +++ b/src/filter/src/resamp2.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // Halfband resampler (interpolator/decimator) -// #include #include @@ -192,7 +190,7 @@ RESAMP2() RESAMP2(_copy)(RESAMP2() q_orig) } // destroy a resamp2 object, clearing up all allocated memory -void RESAMP2(_destroy)(RESAMP2() _q) +int RESAMP2(_destroy)(RESAMP2() _q) { // destroy dotprod object DOTPROD(_destroy)(_q->dp); @@ -207,35 +205,25 @@ void RESAMP2(_destroy)(RESAMP2() _q) // free main object memory free(_q); + return LIQUID_OK; } // print a resamp2 object's internals -void RESAMP2(_print)(RESAMP2() _q) +int RESAMP2(_print)(RESAMP2() _q) { - printf("fir half-band resampler: [%u taps, f0=%12.8f]\n", - _q->h_len, - _q->f0); - unsigned int i; - for (i=0; i<_q->h_len; i++) { - printf(" h(%4u) = ", i+1); - PRINTVAL_TC(_q->h[i],%12.8f); - printf(";\n"); - } - printf("---\n"); - for (i=0; i<_q->h1_len; i++) { - printf(" h1(%4u) = ", i+1); - PRINTVAL_TC(_q->h1[i],%12.8f); - printf(";\n"); - } + printf("\n", + EXTENSION_FULL, _q->h_len,_q->f0); + return LIQUID_OK; } // clear internal buffer -void RESAMP2(_reset)(RESAMP2() _q) +int RESAMP2(_reset)(RESAMP2() _q) { WINDOW(_reset)(_q->w0); WINDOW(_reset)(_q->w1); _q->toggle = 0; + return LIQUID_OK; } // get filter delay (samples) @@ -253,10 +241,11 @@ int RESAMP2(_set_scale)(RESAMP2() _q, } // get output scaling for filter -void RESAMP2(_get_scale)(RESAMP2() _q, +int RESAMP2(_get_scale)(RESAMP2() _q, TC * _scale) { *_scale = _q->scale; + return LIQUID_OK; } // execute resamp2 as half-band filter @@ -264,10 +253,10 @@ void RESAMP2(_get_scale)(RESAMP2() _q, // _x : input sample // _y0 : output sample pointer (low frequency) // _y1 : output sample pointer (high frequency) -void RESAMP2(_filter_execute)(RESAMP2() _q, - TI _x, - TO * _y0, - TO * _y1) +int RESAMP2(_filter_execute)(RESAMP2() _q, + TI _x, + TO * _y0, + TO * _y1) { TI * r; // buffer read pointer TO yi; // delay branch @@ -301,15 +290,16 @@ void RESAMP2(_filter_execute)(RESAMP2() _q, // set return values, normalizing gain, applying scaling factor *_y0 = 0.5f*(yi + yq)*_q->scale; // lower band *_y1 = 0.5f*(yi - yq)*_q->scale; // upper band + return LIQUID_OK; } // execute analysis half-band filterbank // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output array [size: 2 x 1] -void RESAMP2(_analyzer_execute)(RESAMP2() _q, - TI * _x, - TO * _y) +int RESAMP2(_analyzer_execute)(RESAMP2() _q, + TI * _x, + TO * _y) { TI * r; // buffer read pointer TO y0; // delay branch @@ -327,15 +317,16 @@ void RESAMP2(_analyzer_execute)(RESAMP2() _q, // set return value, applying scaling factor _y[0] = (y1 + y0) * _q->scale; _y[1] = (y1 - y0) * _q->scale; + return LIQUID_OK; } // execute synthesis half-band filterbank // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output array [size: 2 x 1] -void RESAMP2(_synthesizer_execute)(RESAMP2() _q, - TI * _x, - TO * _y) +int RESAMP2(_synthesizer_execute)(RESAMP2() _q, + TI * _x, + TO * _y) { TI * r; // buffer read pointer TI x0 = _x[0] + _x[1]; // delay branch input @@ -353,6 +344,7 @@ void RESAMP2(_synthesizer_execute)(RESAMP2() _q, // apply scaling factor _y[0] *= _q->scale; _y[1] *= _q->scale; + return LIQUID_OK; } @@ -360,9 +352,9 @@ void RESAMP2(_synthesizer_execute)(RESAMP2() _q, // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output sample pointer -void RESAMP2(_decim_execute)(RESAMP2() _q, - TI * _x, - TO * _y) +int RESAMP2(_decim_execute)(RESAMP2() _q, + TI * _x, + TO * _y) { TI * r; // buffer read pointer TO y0; // delay branch @@ -379,15 +371,16 @@ void RESAMP2(_decim_execute)(RESAMP2() _q, // set return value, applying scaling factor *_y = (y0 + y1) * _q->scale; + return LIQUID_OK; } // execute half-band interpolation // _q : resamp2 object // _x : input sample // _y : output array [size: 2 x 1] -void RESAMP2(_interp_execute)(RESAMP2() _q, - TI _x, - TO * _y) +int RESAMP2(_interp_execute)(RESAMP2() _q, + TI _x, + TO * _y) { TI * r; // buffer read pointer @@ -403,5 +396,6 @@ void RESAMP2(_interp_execute)(RESAMP2() _q, // apply scaling factor _y[0] *= _q->scale; _y[1] *= _q->scale; + return LIQUID_OK; } From b855d681e21d93892920f78b42d1e05c943361a3 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:07:02 -0400 Subject: [PATCH 183/334] rresamp: using error-handling interface --- include/liquid.h | 30 +++++++-------- src/filter/src/rresamp.proto.c | 70 ++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 67f072a39..4a3c6ee4b 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4400,25 +4400,25 @@ RRESAMP() RRESAMP(_create_default)(unsigned int _interp, \ RRESAMP() RRESAMP(_copy)(RRESAMP() _q); \ \ /* Destroy resampler object, freeing all internal memory */ \ -void RRESAMP(_destroy)(RRESAMP() _q); \ +int RRESAMP(_destroy)(RRESAMP() _q); \ \ /* Print resampler object internals to stdout */ \ -void RRESAMP(_print)(RRESAMP() _q); \ +int RRESAMP(_print)(RRESAMP() _q); \ \ /* Reset resampler object internals */ \ -void RRESAMP(_reset)(RRESAMP() _q); \ +int RRESAMP(_reset)(RRESAMP() _q); \ \ /* Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ -void RRESAMP(_set_scale)(RRESAMP() _q, \ +int RRESAMP(_set_scale)(RRESAMP() _q, \ TC _scale); \ \ /* Get output scaling for filter */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ -void RRESAMP(_get_scale)(RRESAMP() _q, \ - TC * _scale); \ +int RRESAMP(_get_scale)(RRESAMP() _q, \ + TC * _scale); \ \ /* Get resampler delay (filter semi-length \(m\)) */ \ unsigned int RRESAMP(_get_delay)(RRESAMP() _q); \ @@ -4451,8 +4451,8 @@ float RRESAMP(_get_rate)(RRESAMP() _q); \ /* internal state of the resampler. */ \ /* _q : resamp object */ \ /* _buf : input sample array, [size: decim x 1] */ \ -void RRESAMP(_write)(RRESAMP() _q, \ - TI * _buf); \ +int RRESAMP(_write)(RRESAMP() _q, \ + TI * _buf); \ \ /* Execute rational-rate resampler on a block of input samples and */ \ /* store the resulting samples in the output array. */ \ @@ -4472,19 +4472,19 @@ void RRESAMP(_write)(RRESAMP() _q, \ /* _q : resamp object */ \ /* _x : input sample array, [size: decim x 1] */ \ /* _y : output sample array, [size: interp x 1] */ \ -void RRESAMP(_execute)(RRESAMP() _q, \ - TI * _x, \ - TO * _y); \ +int RRESAMP(_execute)(RRESAMP() _q, \ + TI * _x, \ + TO * _y); \ \ /* Execute on a block of samples */ \ /* _q : resamp object */ \ /* _x : input sample array, [size: decim*n x 1] */ \ /* _n : block size */ \ /* _y : output sample array, [size: interp*n x 1] */ \ -void RRESAMP(_execute_block)(RRESAMP() _q, \ - TI * _x, \ - unsigned int _n, \ - TO * _y); \ +int RRESAMP(_execute_block)(RRESAMP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_RRRF, float, diff --git a/src/filter/src/rresamp.proto.c b/src/filter/src/rresamp.proto.c index 63a28bf61..daa3df0dd 100644 --- a/src/filter/src/rresamp.proto.c +++ b/src/filter/src/rresamp.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,9 +40,9 @@ struct RRESAMP(_s) { // internal: execute rational-rate resampler on a primitive-length block of // input samples and store the resulting samples in the output array. -void RRESAMP(_execute_primitive)(RRESAMP() _q, - TI * _x, - TO * _y); +int RRESAMP(_execute_primitive)(RRESAMP() _q, + TI * _x, + TO * _y); // Create rational-rate resampler object from external coefficients // _interp : interpolation factor @@ -190,45 +190,46 @@ RRESAMP() RRESAMP(_copy)(RRESAMP() q_orig) } // free resampler object -void RRESAMP(_destroy)(RRESAMP() _q) +int RRESAMP(_destroy)(RRESAMP() _q) { // free polyphase filterbank FIRPFB(_destroy)(_q->pfb); // free main object memory free(_q); + return LIQUID_OK; } // print resampler object -void RRESAMP(_print)(RRESAMP() _q) +int RRESAMP(_print)(RRESAMP() _q) { printf("resampler [rate: %u/%u=%.6f, block length=%u], m=%u\n", _q->P, _q->Q, (float)(_q->P) / (float)(_q->Q), _q->block_len, _q->m); } // reset resampler object -void RRESAMP(_reset)(RRESAMP() _q) +int RRESAMP(_reset)(RRESAMP() _q) { // clear filterbank - FIRPFB(_reset)(_q->pfb); + return FIRPFB(_reset)(_q->pfb); } // Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) // _q : resampler object // _scale : scaling factor to apply to each output sample -void RRESAMP(_set_scale)(RRESAMP() _q, - TC _scale) +int RRESAMP(_set_scale)(RRESAMP() _q, + TC _scale) { - FIRPFB(_set_scale)(_q->pfb, _scale); + return FIRPFB(_set_scale)(_q->pfb, _scale); } // Get output scaling for filter // _q : resampler object // _scale : scaling factor to apply to each output sample -void RRESAMP(_get_scale)(RRESAMP() _q, - TC * _scale) +int RRESAMP(_get_scale)(RRESAMP() _q, + TC * _scale) { - FIRPFB(_get_scale)(_q->pfb, _scale); + return FIRPFB(_get_scale)(_q->pfb, _scale); } // get resampler filter delay (semi-length m) @@ -278,10 +279,10 @@ unsigned int RRESAMP(_get_decim)(RRESAMP() _q) // internal state of the resampler. // _q : resamp object // _buf : input sample array, [size: Q x 1] -void RRESAMP(_write)(RRESAMP() _q, - TI * _buf) +int RRESAMP(_write)(RRESAMP() _q, + TI * _buf) { - FIRPFB(_write)(_q->pfb, _buf, _q->Q); + return FIRPFB(_write)(_q->pfb, _buf, _q->Q); } // Execute rational-rate resampler on a block of input samples and @@ -289,9 +290,9 @@ void RRESAMP(_write)(RRESAMP() _q, // _q : resamp object // _x : input sample array, [size: Q x 1] // _y : output sample array [size: P x 1] -void RRESAMP(_execute)(RRESAMP() _q, - TI * _x, - TO * _y) +int RRESAMP(_execute)(RRESAMP() _q, + TI * _x, + TO * _y) { // run in blocks unsigned int i; @@ -303,6 +304,7 @@ void RRESAMP(_execute)(RRESAMP() _q, _x += _q->Q; _y += _q->P; } + return LIQUID_OK; } // Execute on a block of samples @@ -310,10 +312,10 @@ void RRESAMP(_execute)(RRESAMP() _q, // _x : input sample array, [size: Q*n x 1] // _n : block size // _y : output sample array [size: P*n x 1] -void RRESAMP(_execute_block)(RRESAMP() _q, - TI * _x, - unsigned int _n, - TO * _y) +int RRESAMP(_execute_block)(RRESAMP() _q, + TI * _x, + unsigned int _n, + TO * _y) { unsigned int i; for (i=0; i<_n; i++) { @@ -321,12 +323,13 @@ void RRESAMP(_execute_block)(RRESAMP() _q, _x += _q->Q; _y += _q->P; } + return LIQUID_OK; } // internal -void RRESAMP(_execute_primitive)(RRESAMP() _q, - TI * _x, - TO * _y) +int RRESAMP(_execute_primitive)(RRESAMP() _q, + TI * _x, + TO * _y) { unsigned int index = 0; // filterbank index unsigned int i, n=0; @@ -344,10 +347,13 @@ void RRESAMP(_execute_primitive)(RRESAMP() _q, index -= _q->P; } -#if 0 - // error checking for now - assert(index == 0); - assert(n == _q->P); -#endif + if (index != 0) { + return liquid_error(LIQUID_EINT,"rresamp_%s_execute_primitive(), index=%u (expected 0)", + EXTENSION_FULL, index); + } else if (n != _q->P) { + return liquid_error(LIQUID_EINT,"rresamp_%s_execute_primitive(), n=%u (expected P=%u)", + EXTENSION_FULL, n, _q->P); + } + return LIQUID_OK; } From 2d17777e7ae92b24e2b2acdb581c763b9a6125d5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:09:11 -0400 Subject: [PATCH 184/334] bsync: using error-handling interface --- include/liquid.h | 10 +++++----- src/framing/src/bsync.proto.c | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 4a3c6ee4b..8ea0fb90b 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6142,19 +6142,19 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, \ \ /* Destroy binary synchronizer object, freeing all internal memory */ \ /* _q : bsync object */ \ -void BSYNC(_destroy)(BSYNC() _q); \ +int BSYNC(_destroy)(BSYNC() _q); \ \ /* Print object internals to stdout */ \ /* _q : bsync object */ \ -void BSYNC(_print)(BSYNC() _q); \ +int BSYNC(_print)(BSYNC() _q); \ \ /* Correlate input signal against internal sequence */ \ /* _q : bsync object */ \ /* _x : input sample */ \ /* _y : pointer to output sample */ \ -void BSYNC(_correlate)(BSYNC() _q, \ - TI _x, \ - TO * _y); \ +int BSYNC(_correlate)(BSYNC() _q, \ + TI _x, \ + TO * _y); \ LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_RRRF, float, diff --git a/src/framing/src/bsync.proto.c b/src/framing/src/bsync.proto.c index 2246df36a..ad271d163 100644 --- a/src/framing/src/bsync.proto.c +++ b/src/framing/src/bsync.proto.c @@ -128,7 +128,7 @@ BSYNC() BSYNC(_create_msequence)(unsigned int _g, return fs; } -void BSYNC(_destroy)(BSYNC() _fs) +int BSYNC(_destroy)(BSYNC() _fs) { bsequence_destroy(_fs->sync_i); #if TC_COMPLEX==1 @@ -140,14 +140,16 @@ void BSYNC(_destroy)(BSYNC() _fs) bsequence_destroy(_fs->sym_q); #endif free(_fs); + return LIQUID_OK; } -void BSYNC(_print)(BSYNC() _fs) +int BSYNC(_print)(BSYNC() _fs) { - + printf("\n", EXTENSION_FULL, _fs->n); + return LIQUID_OK; } -void BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) +int BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) { // push symbol into buffers bsequence_push(_fs->sym_i, crealf(_sym)>0.0 ? 1 : 0); @@ -177,5 +179,6 @@ void BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) // divide by sequence length *_y = _fs->rxy / (float)(_fs->n); + return LIQUID_OK; } From e5ac9e34086c1e7ef2a6209345602c599296a371 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:32:35 -0400 Subject: [PATCH 185/334] math/autotest: adding tests for configuration and error-handling --- src/math/tests/math_autotest.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/math/tests/math_autotest.c b/src/math/tests/math_autotest.c index 5243a8465..b9108e944 100644 --- a/src/math/tests/math_autotest.c +++ b/src/math/tests/math_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,9 +24,7 @@ #include "liquid.h" -// -// AUTOTEST: Q function -// +// Q function void autotest_Q() { float tol = 1e-6f; @@ -41,18 +39,14 @@ void autotest_Q() CONTEND_DELTA(liquid_Qf( 4.0f), 0.000031671f, tol); } -// -// AUTOTEST: sincf -// +// sincf void autotest_sincf() { float tol = 1e-3f; CONTEND_DELTA(sincf(0.0f), 1.0f, tol); } -// -// AUTOTEST: nextpow2 -// +// nextpow2 void autotest_nextpow2() { CONTEND_EQUALITY(liquid_nextpow2(1), 0); @@ -80,3 +74,19 @@ void autotest_nextpow2() CONTEND_EQUALITY(liquid_nextpow2(888), 10); } +// test math configuration and error handling +void autotest_math_config() +{ + //_liquid_error_downgrade_enable(); + CONTEND_EQUALITY(liquid_nextpow2(0), 0); + + CONTEND_EQUALITY(liquid_nchoosek(4, 5), 0.0f); + + CONTEND_EQUALITY(liquid_lngammaf(-1), 0.0f); + + CONTEND_EQUALITY(liquid_gcd(12, 0), 0); + CONTEND_EQUALITY(liquid_gcd( 0,12), 0); + CONTEND_EQUALITY(liquid_gcd( 0, 0), 0); + //_liquid_error_downgrade_disable(); +} + From 2cb6e09ac36eb26ee2bcf3249401652d102a2ae4 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:39:12 -0400 Subject: [PATCH 186/334] math/poly: returning ENOIMP (not implemented error) for complex findroots --- src/math/src/polyc.c | 4 ++-- src/math/src/polycf.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/math/src/polyc.c b/src/math/src/polyc.c index 0f0de4de4..e0020c218 100644 --- a/src/math/src/polyc.c +++ b/src/math/src/polyc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -52,6 +52,6 @@ int polyc_findroots(double complex * _p, unsigned int _k, double complex * _roots) { - return liquid_error(LIQUID_EUMODE,"polyc_findroots(), complex root-finding not yet supported"); + return liquid_error(LIQUID_ENOIMP,"polyc_findroots(), complex root-finding not yet supported"); } diff --git a/src/math/src/polycf.c b/src/math/src/polycf.c index 25d508775..9937ec38b 100644 --- a/src/math/src/polycf.c +++ b/src/math/src/polycf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -52,6 +52,6 @@ int polycf_findroots(float complex * _p, unsigned int _k, float complex * _roots) { - return liquid_error(LIQUID_EUMODE,"polycf_findroots(), complex root-finding not yet supported"); + return liquid_error(LIQUID_ENOIMP,"polycf_findroots(), complex root-finding not yet supported"); } From 6159bed321cf06fd1f3d1383de4c025aa4943deb Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 10:44:01 -0400 Subject: [PATCH 187/334] rresamp: returning 'LIQUID_OK' when printing --- src/filter/src/rresamp.proto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/filter/src/rresamp.proto.c b/src/filter/src/rresamp.proto.c index daa3df0dd..15035a7c3 100644 --- a/src/filter/src/rresamp.proto.c +++ b/src/filter/src/rresamp.proto.c @@ -203,8 +203,9 @@ int RRESAMP(_destroy)(RRESAMP() _q) // print resampler object int RRESAMP(_print)(RRESAMP() _q) { - printf("resampler [rate: %u/%u=%.6f, block length=%u], m=%u\n", + printf("\n", EXTENSION_FULL, _q->P, _q->Q, (float)(_q->P) / (float)(_q->Q), _q->block_len, _q->m); + return LIQUID_OK; } // reset resampler object From 09f111486f833ff29b6bbb2bd65f2d076f64b04c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 11:04:16 -0400 Subject: [PATCH 188/334] math/autotest: testing config and error-handling for windows --- include/liquid.h | 2 +- src/math/src/windows.c | 5 ++- src/math/tests/window_autotest.c | 63 +++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 8ea0fb90b..c657f9191 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -7068,7 +7068,7 @@ typedef enum { extern const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2]; // Print compact list of existing and available windowing functions -void liquid_print_windows(); +int liquid_print_windows(); // returns window type based on input string liquid_window_type liquid_getopt_str2window(const char * _str); diff --git a/src/math/src/windows.c b/src/math/src/windows.c index 79e73f162..25df38930 100644 --- a/src/math/src/windows.c +++ b/src/math/src/windows.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,7 +58,7 @@ const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2] = { }; // Print compact list of existing and available windowing functions -void liquid_print_windows() +int liquid_print_windows() { unsigned int i; unsigned int len = 10; @@ -78,6 +78,7 @@ void liquid_print_windows() } } printf("\n"); + return LIQUID_OK; } // returns modulation_scheme based on input string diff --git a/src/math/tests/window_autotest.c b/src/math/tests/window_autotest.c index e8897e05b..1d9ccbf77 100644 --- a/src/math/tests/window_autotest.c +++ b/src/math/tests/window_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -119,3 +119,64 @@ void autotest_kbd_n16() { liquid_kbd_window_test(16, 10.0f); } void autotest_kbd_n32() { liquid_kbd_window_test(32, 20.0f); } void autotest_kbd_n48() { liquid_kbd_window_test(48, 12.0f); } +// test window configuration and error handling +void autotest_window_config() +{ + //_liquid_error_downgrade_enable(); + CONTEND_EQUALITY(liquid_print_windows(), LIQUID_OK); + + // check normal cases + CONTEND_EQUALITY(liquid_getopt_str2window("unknown" ), LIQUID_WINDOW_UNKNOWN); // <- no error + CONTEND_EQUALITY(liquid_getopt_str2window("hamming" ), LIQUID_WINDOW_HAMMING); + CONTEND_EQUALITY(liquid_getopt_str2window("hann" ), LIQUID_WINDOW_HANN); + CONTEND_EQUALITY(liquid_getopt_str2window("blackmanharris" ), LIQUID_WINDOW_BLACKMANHARRIS); + CONTEND_EQUALITY(liquid_getopt_str2window("blackmanharris7"), LIQUID_WINDOW_BLACKMANHARRIS7); + CONTEND_EQUALITY(liquid_getopt_str2window("kaiser" ), LIQUID_WINDOW_KAISER); + CONTEND_EQUALITY(liquid_getopt_str2window("flattop" ), LIQUID_WINDOW_FLATTOP); + CONTEND_EQUALITY(liquid_getopt_str2window("triangular" ), LIQUID_WINDOW_TRIANGULAR); + CONTEND_EQUALITY(liquid_getopt_str2window("rcostaper" ), LIQUID_WINDOW_RCOSTAPER); + CONTEND_EQUALITY(liquid_getopt_str2window("kbd" ), LIQUID_WINDOW_KBD); + // check invalid cases + CONTEND_EQUALITY(liquid_getopt_str2window("invalid window" ), LIQUID_WINDOW_UNKNOWN); + + // invalid KBD window parameters + CONTEND_EQUALITY(liquid_kbd(12, 10, 10.0f), 0.0f); // index exceeds maximum + CONTEND_EQUALITY(liquid_kbd( 0, 0, 10.0f), 0.0f); // window length is zero + CONTEND_EQUALITY(liquid_kbd(12, 27, 10.0f), 0.0f); // window length is odd + + float w[20]; + CONTEND_INEQUALITY(liquid_kbd_window( 0, 10.0f, w), LIQUID_OK); // length is zero + CONTEND_INEQUALITY(liquid_kbd_window( 7, 10.0f, w), LIQUID_OK); // length is odd + CONTEND_INEQUALITY(liquid_kbd_window(20, -1.0f, w), LIQUID_OK); // beta value is negative + + // invalid Kaiser window parameters + CONTEND_EQUALITY(liquid_kaiser(12, 10, 10.0f), 0.0f); // index exceeds maximum + CONTEND_EQUALITY(liquid_kaiser(12, 20, -1.0f), 0.0f); // beta value is negative + + // Hamming + CONTEND_EQUALITY(liquid_hamming(12, 10), 0.0f); // index exceeds maximum + + // Hann + CONTEND_EQUALITY(liquid_hann(12, 10), 0.0f); // index exceeds maximum + + // Blackman-harris + CONTEND_EQUALITY(liquid_blackmanharris(12, 10), 0.0f); // index exceeds maximum + + // Blackman-harris 7 + CONTEND_EQUALITY(liquid_blackmanharris7(12, 10), 0.0f); // index exceeds maximum + + // flat-top + CONTEND_EQUALITY(liquid_flattop(12, 10), 0.0f); // index exceeds maximum + + // triangular + CONTEND_EQUALITY(liquid_triangular(12, 10, 10), 0.0f); // index exceeds maximum + CONTEND_EQUALITY(liquid_triangular( 7, 10, 15), 0.0f); // sub-length is out of range + CONTEND_EQUALITY(liquid_triangular( 1, 1, 0), 0.0f); // sub-length is zero + + // raised-cosine taper + CONTEND_EQUALITY(liquid_rcostaper_window(12, 10, 4), 0.0f); // index exceeds maximum + CONTEND_EQUALITY(liquid_rcostaper_window( 7, 10, 8), 0.0f); // taper length exceeds maximum + + //_liquid_error_downgrade_disable(); +} + From 29c404bfa0c4757de0309f380c6c9e8f6543cea9 Mon Sep 17 00:00:00 2001 From: Andreas Bombe Date: Sat, 9 Sep 2023 23:24:40 +0530 Subject: [PATCH 189/334] Fix SONAME not set in shared library A SONAME was introduced to libliquid and used in installation file names however the shared library was always compiled with 'libliquid.so' as the SONAME rather than 'libliquid.so.1' as was probably intended. Fix that and introduce a SOVERSION variable to the makefile so that it is defined in a single place only. --- makefile.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/makefile.in b/makefile.in index ca8d92205..43c880c65 100644 --- a/makefile.in +++ b/makefile.in @@ -47,6 +47,7 @@ VERSION := @PACKAGE_VERSION@ BUGREPORT := @PACKAGE_BUGREPORT@ AR_LIB := @AR_LIB@ SH_LIB := @SH_LIB@ +SOVERSION := 1 # paths prefix := @prefix@ @@ -1273,7 +1274,7 @@ libliquid.a : $(objects) ${RANLIB} $@ libliquid.so : libliquid.a - $(CC) $(CFLAGS) $(LDFLAGS) -shared -Xlinker -soname=$@ -o $@ -Wl,-whole-archive $^ -Wl,-no-whole-archive $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -shared -Xlinker -soname=libliquid.so.$(SOVERSION) -o $@ -Wl,-whole-archive $^ -Wl,-no-whole-archive $(LIBS) # static archive and library objects all: ${ARCHIVE_LIB} ${SHARED_LIB} @@ -1300,7 +1301,7 @@ install: all install -m 644 -p libliquid.${SH_LIB} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} install -m 644 -p include/liquid.h $(DESTDIR)$(prefix)/include/liquid/liquid.h ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB} - ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.1 + ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${SOVERSION} @echo "" @echo "---------------------------------------------------------" @echo " liquid-dsp was successfully installed. " @@ -1325,7 +1326,7 @@ uninstall: $(RM) $(DESTDIR)$(prefix)/include/liquid/liquid.h $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} - $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.1 + $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${SOVERSION} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB} @echo "done." From 553b4e2d9a94243b5af8ab9e32568b861c4bfb39 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 16:04:12 -0400 Subject: [PATCH 190/334] math/cargf: removing cargf approximation as it is very inaccurate --- include/liquid.internal.h | 2 +- src/math/src/math.complex.c | 7 ++- src/math/tests/math_complex_autotest.c | 67 ++++++++++++++++++-------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 4e2f448e0..1f9e027cd 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1153,7 +1153,7 @@ float complex liquid_cacosf(float complex _z); float complex liquid_catanf(float complex _z); // faster approximation to arg{*} -float liquid_cargf_approx(float complex _z); +//float liquid_cargf_approx(float complex _z); // internal trig helper functions diff --git a/src/math/src/math.complex.c b/src/math/src/math.complex.c index fc4aecf00..e9857a42b 100644 --- a/src/math/src/math.complex.c +++ b/src/math/src/math.complex.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -92,7 +92,9 @@ float complex liquid_catanf(float complex _z) return 0.5f*_Complex_I*liquid_clogf( t0 / t1 ); } -// approximation to cargf() but faster +#if 0 +// approximation to cargf() but faster(?) +// NOTE: this is not actually very accurate float liquid_cargf_approx(float complex _x) { float theta; @@ -113,4 +115,5 @@ float liquid_cargf_approx(float complex _x) theta = -M_PI_2; return theta; } +#endif diff --git a/src/math/tests/math_complex_autotest.c b/src/math/tests/math_complex_autotest.c index fab623f97..ac77cacf1 100644 --- a/src/math/tests/math_complex_autotest.c +++ b/src/math/tests/math_complex_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,9 +23,7 @@ #include "autotest/autotest.h" #include "liquid.internal.h" -// -// AUTOTEST: cexpf -// +// cexpf void autotest_cexpf() { float tol = 1e-3f; @@ -77,9 +75,7 @@ void autotest_cexpf() } -// -// AUTOTEST: clogf -// +// clogf void autotest_clogf() { float tol = 1e-3f; @@ -130,9 +126,7 @@ void autotest_clogf() } } -// -// AUTOTEST: csqrtf -// +// csqrtf void autotest_csqrtf() { float tol = 1e-3f; @@ -183,9 +177,7 @@ void autotest_csqrtf() } } -// -// AUTOTEST: casinf -// +// casinf void autotest_casinf() { float tol = 1e-3f; @@ -237,9 +229,7 @@ void autotest_casinf() } } -// -// AUTOTEST: cacosf -// +// cacosf void autotest_cacosf() { float tol = 1e-3f; @@ -292,9 +282,7 @@ void autotest_cacosf() } } -// -// AUTOTEST: catanf -// +// catanf void autotest_catanf() { float tol = 1e-3f; @@ -345,3 +333,44 @@ void autotest_catanf() CONTEND_DELTA(cimagf(t), cimagf(test[i]), tol); } } + +// cargf +#if 0 +void xautotest_cargf() +{ + float tol = 1e-3f; + CONTEND_DELTA( liquid_cargf_approx( 1.3608e+00+_Complex_I* -4.2247e-01), -0.30102262, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.1324e+00+_Complex_I* 1.1938e+00), 0.81178695, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.6466e+00+_Complex_I* -1.2098e+00), -0.63365394, tol); + CONTEND_DELTA( liquid_cargf_approx(-6.5911e-01+_Complex_I* 1.0729e+00), 2.12168288, tol); + CONTEND_DELTA( liquid_cargf_approx(-8.8890e-01+_Complex_I* 2.1588e-01), 2.90334344, tol); + CONTEND_DELTA( liquid_cargf_approx(-9.0412e-02+_Complex_I* 5.1548e-01), 1.74442410, tol); + CONTEND_DELTA( liquid_cargf_approx(-5.4086e-01+_Complex_I* 5.3604e-02), 3.04280639, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.8089e+00+_Complex_I* 1.6648e+00), 0.74393880, tol); + CONTEND_DELTA( liquid_cargf_approx( 5.4285e-01+_Complex_I* 8.6919e-01), 1.01252282, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.4336e+00+_Complex_I* 4.2788e-01), 2.85154438, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.9348e+00+_Complex_I* -1.0285e+00), -2.65300179, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.4511e+00+_Complex_I* 1.2167e+00), 2.44383216, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.3733e+00+_Complex_I* -3.9622e-01), -2.86070395, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.4808e+00+_Complex_I* -1.5648e+00), -2.32862067, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.9957e+00+_Complex_I* -1.1270e+00), -0.51406980, tol); + CONTEND_DELTA( liquid_cargf_approx( 5.1730e-02+_Complex_I* 1.3564e+00), 1.53267705, tol); + CONTEND_DELTA( liquid_cargf_approx( 4.5056e-01+_Complex_I* -8.1587e-01), -1.06623125, tol); + CONTEND_DELTA( liquid_cargf_approx( 5.5021e-01+_Complex_I* 9.7149e-02), 0.17476583, tol); + CONTEND_DELTA( liquid_cargf_approx(-2.5668e-02+_Complex_I* 1.8911e+00), 1.58436859, tol); + CONTEND_DELTA( liquid_cargf_approx(-8.2993e-01+_Complex_I* 1.0854e+00), 2.22359538, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.0698e-01+_Complex_I* 1.0797e+00), 1.47203565, tol); + CONTEND_DELTA( liquid_cargf_approx(-3.9909e-01+_Complex_I* 1.5661e+00), 1.82031608, tol); + CONTEND_DELTA( liquid_cargf_approx(-8.6674e-01+_Complex_I* -5.9017e-01), -2.54379559, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.2309e+00+_Complex_I* 1.6761e+00), 0.93736500, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.7210e+00+_Complex_I* 1.7973e+00), 2.33451128, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.0398e-01+_Complex_I* -1.6558e+00), -1.50808120, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.2311e+00+_Complex_I* 6.5291e-01), 2.65396333, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.5609e+00+_Complex_I* -6.0443e-01), -0.36945102, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.7433e+00+_Complex_I* -1.9199e+00), -2.30802250, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.6919e-01+_Complex_I* -1.7476e+00), -1.66730833, tol); + CONTEND_DELTA( liquid_cargf_approx(-1.0469e+00+_Complex_I* 1.8825e+00), 2.07832766, tol); + CONTEND_DELTA( liquid_cargf_approx( 1.6088e+00+_Complex_I* 1.4037e+00), 0.71742004, tol); +} +#endif + From ca646229246c827edd572dfd7f068d51d730aa69 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 16:16:34 -0400 Subject: [PATCH 191/334] math/autotest: checking (unique) factors method(s) --- src/math/tests/prime_autotest.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/math/tests/prime_autotest.c b/src/math/tests/prime_autotest.c index 659356a16..bb93a5b07 100644 --- a/src/math/tests/prime_autotest.c +++ b/src/math/tests/prime_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2017 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,9 +23,7 @@ #include "autotest/autotest.h" #include "liquid.h" -// -// AUTOTEST: test for small primes -// +// test for small primes void autotest_prime_small() { const int is_prime_array[2500] = { @@ -85,3 +83,25 @@ void autotest_prime_small() CONTEND_EQUALITY(is_prime_array[n], liquid_is_prime(n)); } +// test factoring +void autotest_factors() +{ + const unsigned int factors_280[5] = {2,2,2,5,7}; + const unsigned int factors_280_unique[3] = {2,5,7}; + + unsigned int factors[LIQUID_MAX_FACTORS]; + unsigned int num_factors = 0; + unsigned int i; + + // check factors of 280 + CONTEND_EQUALITY(liquid_factor(280,factors,&num_factors), LIQUID_OK); + CONTEND_EQUALITY(num_factors, 5); + for (i=0; i<5; i++) + CONTEND_EQUALITY(factors_280[i], factors[i]); + + // check unique factors of 280 + CONTEND_EQUALITY(liquid_unique_factor(280,factors,&num_factors), LIQUID_OK); + CONTEND_EQUALITY(num_factors, 3); + for (i=0; i<3; i++) + CONTEND_EQUALITY(factors_280_unique[i], factors[i]); +} From f0a8ae70ab1a88a49c6256d5ae7c4d83f31fa250 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 9 Sep 2023 19:02:35 -0400 Subject: [PATCH 192/334] math/autotest: adding tests for Euler's totient function --- src/math/tests/prime_autotest.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/math/tests/prime_autotest.c b/src/math/tests/prime_autotest.c index bb93a5b07..49b8ce673 100644 --- a/src/math/tests/prime_autotest.c +++ b/src/math/tests/prime_autotest.c @@ -105,3 +105,13 @@ void autotest_factors() for (i=0; i<3; i++) CONTEND_EQUALITY(factors_280_unique[i], factors[i]); } + +// test Euler's totient function +void autotest_totient() +{ + CONTEND_EQUALITY(liquid_totient( 9), 6) + CONTEND_EQUALITY(liquid_totient( 20), 8) + CONTEND_EQUALITY(liquid_totient( 100), 40) + CONTEND_EQUALITY(liquid_totient(1200), 320) + CONTEND_EQUALITY(liquid_totient(1201),1200) +} From 75fbee3fc6bc33b3fea644109c911a07ad490a1f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 24 Oct 2023 11:11:06 -0400 Subject: [PATCH 193/334] spgram/autotest: writing unique filenames to logging directory --- src/fft/tests/spgram_autotest.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/fft/tests/spgram_autotest.c b/src/fft/tests/spgram_autotest.c index ff06a198c..749b6e3a1 100644 --- a/src/fft/tests/spgram_autotest.c +++ b/src/fft/tests/spgram_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,8 +35,10 @@ void testbench_spgramcf_noise(unsigned int _nfft, unsigned int num_samples = 2000*_nfft; // number of samples to generate float nstd = powf(10.0f,_noise_floor/20.0f); // noise std. dev. float tol = 0.5f; // error tolerance [dB] - if (liquid_autotest_verbose) - printf(" spgramcf test (noise): nfft=%6u, wtype=%24s, noise floor=%6.1f\n", _nfft, liquid_window_str[_wtype][1], _noise_floor); + if (liquid_autotest_verbose) { + printf(" spgramcf test (noise): nfft=%6u, wtype=%24s, noise floor=%6.1f\n", + _nfft, liquid_window_str[_wtype][1], _noise_floor); + } // create spectral periodogram spgramcf q = NULL; @@ -92,8 +94,10 @@ void testbench_spgramcf_signal(unsigned int _nfft, int _wtype, float _fc, float float bw = 0.25f; // signal bandwidth (relative) unsigned int m = 25; float beta = 0.2f, n0 = -80.0f, tol = 0.5f; - if (liquid_autotest_verbose) - printf(" spgramcf test (signal): nfft=%6u, wtype=%24s, fc=%6.2f Fs, snr=%6.1f dB\n", _nfft, liquid_window_str[_wtype][1], _fc, _SNRdB); + if (liquid_autotest_verbose) { + printf(" spgramcf test (signal): nfft=%6u, wtype=%24s, fc=%6.2f Fs, snr=%6.1f dB\n", + _nfft, liquid_window_str[_wtype][1], _fc, _SNRdB); + } // create objects spgramcf q = spgramcf_create(_nfft, _wtype, _nfft/2, _nfft/4); @@ -131,8 +135,13 @@ void testbench_spgramcf_signal(unsigned int _nfft, int _wtype, float _fc, float {.fmin=_fc-0.4f*bw, .fmax=_fc+0.4f*bw, .pmin=sn-tol, .pmax=sn+tol, .test_lo=1, .test_hi=1}, {.fmin=_fc+0.6f*bw, .fmax=+0.5f, .pmin=n0-tol, .pmax=n0+tol, .test_lo=1, .test_hi=1}, }; + char filename[256]; + sprintf(filename,"autotest/logs/spgramcf_signal_%s_n%u_f%c%.0f_s%c%.0f.m", + liquid_window_str[_wtype][0], _nfft, + _fc < 0 ? 'm' : 'p', fabsf(_fc*1000), + _SNRdB < 0 ? 'm' : 'p', fabsf(_SNRdB*1000)); liquid_autotest_validate_spectrum(psd, _nfft, regions, 3, - liquid_autotest_verbose ? "autotest/logs/spgramcf_signal.m" : NULL); + liquid_autotest_verbose ? filename : NULL); // destroy objects spgramcf_destroy(q); From c803fccb68dd3046c596dd2cb0c2ec457e7f5580 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 24 Oct 2023 15:10:09 -0400 Subject: [PATCH 194/334] flexframesync: only incrementing decoded bytes if payload is valid --- src/framing/src/flexframesync.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/framing/src/flexframesync.c b/src/framing/src/flexframesync.c index 50aaf9c0e..4b0e513a1 100644 --- a/src/framing/src/flexframesync.c +++ b/src/framing/src/flexframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -779,8 +779,10 @@ int flexframesync_execute_rxpayload(flexframesync _q, // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid++; - _q->framedatastats.num_payloads_valid += _q->payload_valid; - _q->framedatastats.num_bytes_received += _q->payload_dec_len; + if (_q->payload_valid) { + _q->framedatastats.num_payloads_valid += 1; + _q->framedatastats.num_bytes_received += _q->payload_dec_len; + } // invoke callback if (_q->callback != NULL) { From 1f4544883121fffc1d0baac43b084e54c5f1ce3a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 24 Oct 2023 15:21:12 -0400 Subject: [PATCH 195/334] flexframesync: adding very basic debugging example --- examples/flexframesync_debug_example.c | 78 ++++++++++++++++++++++ makefile.in | 1 + src/framing/tests/flexframesync_autotest.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 examples/flexframesync_debug_example.c diff --git a/examples/flexframesync_debug_example.c b/examples/flexframesync_debug_example.c new file mode 100644 index 000000000..c955e972a --- /dev/null +++ b/examples/flexframesync_debug_example.c @@ -0,0 +1,78 @@ +// This example exports the output constellation to file for debugging. + +#include +#include +#include +#include +#include +#include +#include + +#include "liquid.h" + +// flexframesync callback function +static int callback(unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata) +{ + const char * filename = (const char*)_userdata; + FILE * fid = fopen(filename,"w"); + if (fid == NULL) { + printf("could not open '%s' for writing\n", filename); + return 0; + } + unsigned int i; + for (i=0; i<_stats.num_framesyms; i++) + fprintf(fid,"%12.8f %12.8f\n", crealf(_stats.framesyms[i]), cimagf(_stats.framesyms[i])); + fclose(fid); + return 0; +} + +int main(int argc, char *argv[]) +{ + // options + modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme + crc_scheme check = LIQUID_CRC_32; // data validity check + fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) + fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) + unsigned int payload_len = 480; // payload length + const char * filename = "flexframesync_debug_example.dat"; + + // create flexframegen object + flexframegenprops_s fgprops; + flexframegenprops_init_default(&fgprops); + fgprops.mod_scheme = ms; + fgprops.check = check; + fgprops.fec0 = fec0; + fgprops.fec1 = fec1; + flexframegen fg = flexframegen_create(&fgprops); + + // create flexframesync object + flexframesync fs = flexframesync_create(callback,(void*)filename); + + // assemble the frame (NULL pointers for default values) + flexframegen_assemble(fg, NULL, NULL, payload_len); + + // generate the frame in blocks + unsigned int buf_len = 256; + float complex buf[buf_len]; + + int frame_complete = 0; + while (!frame_complete) { + // write samples to buffer + frame_complete = flexframegen_write_samples(fg, buf, buf_len); + + // run through frame synchronizer + flexframesync_execute(fs, buf, buf_len); + } + + // destroy allocated objects + flexframegen_destroy(fg); + flexframesync_destroy(fs); + return 0; +} + diff --git a/makefile.in b/makefile.in index 1ca16bc3f..943819dbe 100644 --- a/makefile.in +++ b/makefile.in @@ -1571,6 +1571,7 @@ example_programs := \ examples/firpfbch_crcf_analysis_example \ examples/firpfbch_crcf_msource_example \ examples/firpfbch_crcf_synthesis_example \ + examples/flexframesync_debug_example \ examples/flexframesync_example \ examples/flexframesync_reconfig_example \ examples/framesync64_example \ diff --git a/src/framing/tests/flexframesync_autotest.c b/src/framing/tests/flexframesync_autotest.c index 588915ae2..f5e984ed4 100644 --- a/src/framing/tests/flexframesync_autotest.c +++ b/src/framing/tests/flexframesync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From e862b599f2206a57dffa428eec2f2567790d961c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 15:34:36 -0500 Subject: [PATCH 196/334] symtrack/autotest: relaxing constraints on test --- src/framing/tests/symtrack_cccf_autotest.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/framing/tests/symtrack_cccf_autotest.c b/src/framing/tests/symtrack_cccf_autotest.c index 480297a02..f845aaea7 100644 --- a/src/framing/tests/symtrack_cccf_autotest.c +++ b/src/framing/tests/symtrack_cccf_autotest.c @@ -30,10 +30,9 @@ void testbench_symtrack_cccf(unsigned int _k, unsigned int _m, float _beta, int { int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int num_symbols = 6000; // number of data symbols - //unsigned int hc_len = 4; // channel filter length float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] - float bandwidth = 0.10f; // loop filter bandwidth + float bandwidth = 0.15f; // loop filter bandwidth float dphi = 0.02f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] @@ -43,13 +42,14 @@ void testbench_symtrack_cccf(unsigned int _k, unsigned int _m, float _beta, int float complex buf_1[buf_len]; // recovered symbols buffer // create stream generator - symstreamcf gen = symstreamcf_create_linear(ftype,_k,_m,_beta,_ms); + symstreamcf gen = symstreamcf_create_linear(ftype,_k,2*_m,_beta,_ms); // create channel emulator and add impairments channel_cccf channel = channel_cccf_create(); channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); - //channel_cccf_add_multipath (channel, NULL, hc_len); + //float complex h[4] = {1.0f, 0, 0, 0.2f*cexpf(_Complex_I*1.4f)}; + //channel_cccf_add_multipath (channel, h, 4); // create symbol tracking synchronizer symtrack_cccf symtrack = symtrack_cccf_create(ftype,_k,_m,_beta,_ms); @@ -64,6 +64,8 @@ void testbench_symtrack_cccf(unsigned int _k, unsigned int _m, float _beta, int float evm = 0.0f; modemcf demod = modemcf_create(_ms); // for checking output EVM //FILE * fid = fopen("symtrack_test.dat","w"); + //fprintf(fid,"#v=load('symtrack_test.dat'); v=v(:,1)+j*v(:,2); plot(v,'x');\n"); + //fprintf(fid,"#axis([-1 1 -1 1]*1.5); axis square; grid on;\n"); while (total_samples < num_symbols * _k) { // write samples to buffer @@ -101,11 +103,11 @@ void testbench_symtrack_cccf(unsigned int _k, unsigned int _m, float _beta, int // verify output constellation EVM is reasonably high evm = 10*log10f(evm / (float)num_symbols_evm); printf("EVM: %12.8f, %u\n", evm, num_symbols_evm); - CONTEND_LESS_THAN(evm, -20.0f); + CONTEND_LESS_THAN(evm, -15.0f); } -void autotest_symtrack_cccf_00() { testbench_symtrack_cccf( 2, 7,0.20f,LIQUID_MODEM_BPSK); } -void autotest_symtrack_cccf_01() { testbench_symtrack_cccf( 2, 7,0.20f,LIQUID_MODEM_QPSK); } +void autotest_symtrack_cccf_bpsk() { testbench_symtrack_cccf( 2,12,0.25f,LIQUID_MODEM_BPSK); } +void autotest_symtrack_cccf_qpsk() { testbench_symtrack_cccf( 2,12,0.25f,LIQUID_MODEM_QPSK); } // invalid configuration tests void autotest_symtrack_cccf_config_invalid() From f9e6660a783efbf5341b0509bfd36f6ea2ac6f00 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 16:30:07 -0500 Subject: [PATCH 197/334] nco: patch to fix issue in nco_constrain * supposed to convert floating-point phase (frequency) to uint32_t * constrained to uint32_t to allow wrapping * causing issue where frequency was being set improperly, occasionally jumping up to pi (-pi) radians/sample * temporary patch is much slower, but should be functionally correct --- src/nco/src/nco.proto.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/nco/src/nco.proto.c b/src/nco/src/nco.proto.c index 41a898479..0853300a1 100644 --- a/src/nco/src/nco.proto.c +++ b/src/nco/src/nco.proto.c @@ -251,9 +251,12 @@ int NCO(_pll_set_bandwidth)(NCO() _q, int NCO(_pll_step)(NCO() _q, T _dphi) { + // TODO: clamp to prevent large changes? // increase frequency proportional to error NCO(_adjust_frequency)(_q, _dphi*_q->alpha); + // TODO: ensure frequency doesn't run away + // increase phase proportional to error NCO(_adjust_phase)(_q, _dphi*_q->beta); @@ -382,6 +385,10 @@ int NCO(_mix_block_down)(NCO() _q, // constrain phase (or frequency) and convert to fixed-point uint32_t NCO(_constrain)(float _theta) { +#if 0 + // NOTE: there seems to be an occasional issue with this causing tests to fail, + // namely randomly setting the frequency to be pi radians/sample. This + // results in nco_crcf_pll not locking // divide value by 2*pi and compute modulo float p = _theta * 0.159154943091895; // 1/(2 pi) ~ 0.159154943091895 @@ -394,6 +401,13 @@ uint32_t NCO(_constrain)(float _theta) // map to range of precision needed uint32_t retVal = (uint32_t)(fpart * 0xffffffff); return retVal >= UINT_MAX ? UINT_MAX : retVal; +#else + // NOTE: this is not efficient, but resolves the issue above + while (_theta >= 2*M_PI) _theta -= 2*M_PI; + while (_theta < 0) _theta += 2*M_PI; + + return (uint32_t) (_theta / (2*M_PI) * 0xffffffff); +#endif } // compute index for sine look-up table From c0c89534d0e7467fc53a66ebbda410df8c91c619 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 16:33:36 -0500 Subject: [PATCH 198/334] nco/example: adjusting plotting to help resolve previous issue --- examples/nco_pll_example.c | 2 +- examples/nco_pll_modem_example.c | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/examples/nco_pll_example.c b/examples/nco_pll_example.c index e347a29ff..aa2ab9185 100644 --- a/examples/nco_pll_example.c +++ b/examples/nco_pll_example.c @@ -119,7 +119,7 @@ int main(int argc, char*argv[]) fprintf(fid,"e(%4u) = %12.4e;\n", i+1, phase_error[i]); } fprintf(fid,"t=0:(n-1);\n"); - fprintf(fid,"figure;\n"); + fprintf(fid,"figure('color','white','position',[100 100 1200 600]);\n"); fprintf(fid,"subplot(3,1,1);\n"); fprintf(fid," hold on;\n"); fprintf(fid," plot(t,real(x),'Color',[1 1 1]*0.8);\n"); diff --git a/examples/nco_pll_modem_example.c b/examples/nco_pll_modem_example.c index 6efa0e820..05d3089fe 100644 --- a/examples/nco_pll_modem_example.c +++ b/examples/nco_pll_modem_example.c @@ -18,10 +18,10 @@ void usage() printf("nco_pll_modem_example [options]\n"); printf(" u/h : print usage\n"); printf(" s : signal-to-noise ratio, default: 30dB\n"); - printf(" b : pll bandwidth, default: 20e-3\n"); - printf(" n : number of symbols, default: 256\n"); + printf(" b : pll bandwidth, default: 0.002\n"); + printf(" n : number of symbols, default: 1200\n"); printf(" P : phase offset (radians), default: pi/10 ~ 0.3146\n"); - printf(" F : frequency offset (radians), default: 0.001\n"); + printf(" F : frequency offset (radians), default: 0.1\n"); printf(" m : modulation scheme, default: qpsk\n"); liquid_print_modulation_schemes(); } @@ -30,11 +30,11 @@ int main(int argc, char*argv[]) { srand( time(NULL) ); // parameters float phase_offset = M_PI/10; - float frequency_offset = 0.001f; + float frequency_offset = 0.10f; float SNRdB = 30.0f; - float pll_bandwidth = 0.02f; + float pll_bandwidth = 0.002f; modulation_scheme ms = LIQUID_MODEM_QPSK; - unsigned int n=256; // number of iterations + unsigned int n=1200; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhs:b:n:P:F:m:")) != EOF) { @@ -61,7 +61,7 @@ int main(int argc, char*argv[]) { FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid, "%% %s : auto-generated file\n", OUTPUT_FILENAME); - fprintf(fid, "clear all;\n"); + fprintf(fid, "clear all; close all;\n"); fprintf(fid, "phi=zeros(1,%u);\n",n); fprintf(fid, "r=zeros(1,%u);\n",n); @@ -123,11 +123,12 @@ int main(int argc, char*argv[]) { // print every line in a format that octave can read fprintf(fid, "phi(%u) = %10.6E;\n", i+1, phase_error); + fprintf(fid, "dphi(%u) = %10.6E;\n", i+1, nco_crcf_get_frequency(nco_rx)); fprintf(fid, "r(%u) = %10.6E + j*%10.6E;\n", i+1, crealf(v), cimagf(v)); if ((i+1)%d == 0 || i==n-1) { - printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %6.3f\n", + printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %12.9f\n", i+1, // iteration phase_error, // estimated phase error nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx),// true phase error @@ -145,21 +146,22 @@ int main(int argc, char*argv[]) { nco_crcf_step(nco_rx); } - fprintf(fid, "figure;\n"); + fprintf(fid, "figure('color','white','position',[100 100 1200 400]);\n"); + fprintf(fid, "subplot(1,3,1:2);\n"); fprintf(fid, "plot(1:length(phi),phi,'LineWidth',2,'Color',[0 0.25 0.5]);\n"); fprintf(fid, "xlabel('Symbol Index');\n"); fprintf(fid, "ylabel('Phase Error [radians]');\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "t0 = round(0.25*length(r));\n"); - fprintf(fid, "figure;\n"); - fprintf(fid, "plot(r(1:t0),'x','Color',[0.6 0.6 0.6],r(t0:end),'x','Color',[0 0.25 0.5]);\n"); + fprintf(fid, "subplot(1,3,3);\n"); + fprintf(fid, "plot(r(1:t0),'.','Color',[0.6 0.6 0.6],r(t0:end),'.','Color',[0 0.25 0.5]);\n"); fprintf(fid, "grid on;\n"); - fprintf(fid, "axis([-1.5 1.5 -1.5 1.5]);\n"); + fprintf(fid, "axis([-1 1 -1 1]*1.5);\n"); fprintf(fid, "axis('square');\n"); fprintf(fid, "xlabel('In-Phase');\n"); fprintf(fid, "ylabel('Quadrature');\n"); - fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n"); + //fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); From 2218671ba1b6af64b69b25f333a0005d02972995 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 18:13:07 -0500 Subject: [PATCH 199/334] nco: removing old data generation script --- src/nco/tests/gen_nco_data.m | 61 ------------------------------------ 1 file changed, 61 deletions(-) delete mode 100644 src/nco/tests/gen_nco_data.m diff --git a/src/nco/tests/gen_nco_data.m b/src/nco/tests/gen_nco_data.m deleted file mode 100644 index d43b3689d..000000000 --- a/src/nco/tests/gen_nco_data.m +++ /dev/null @@ -1,61 +0,0 @@ -% generate nco data for autotests - -% options -p = 7; % base frequency integer -f = 1/sqrt(p); % frequency -n = 256; % number of points - -% compute sincos data -v = exp(j*[0:(n-1)]*f); - -% print results - -basename = ['nco_sincos_fsqrt1_' num2str(p)]; -filename = ['data/' basename '.c']; -fid = fopen(filename,'w'); - -fprintf(fid,'/* Copyright (c) 2007 - 2015 Joseph Gaeddert\n'); -fprintf(fid,' *\n'); -fprintf(fid,' * Permission is hereby granted, free of charge, to any person obtaining a copy\n'); -fprintf(fid,' * of this software and associated documentation files (the "Software"), to deal\n'); -fprintf(fid,' * in the Software without restriction, including without limitation the rights\n'); -fprintf(fid,' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'); -fprintf(fid,' * copies of the Software, and to permit persons to whom the Software is\n'); -fprintf(fid,' * furnished to do so, subject to the following conditions:\n'); -fprintf(fid,' * \n'); -fprintf(fid,' * The above copyright notice and this permission notice shall be included in\n'); -fprintf(fid,' * all copies or substantial portions of the Software.\n'); -fprintf(fid,' *\n'); -fprintf(fid,' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n'); -fprintf(fid,' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n'); -fprintf(fid,' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n'); -fprintf(fid,' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n'); -fprintf(fid,' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n'); -fprintf(fid,' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n'); -fprintf(fid,' * THE SOFTWARE.\n'); -fprintf(fid,' */\n'); -fprintf(fid,'\n'); - -fprintf(fid,'//\n'); -fprintf(fid,'// autotest nco sincos data for f=%.12f\n', f); -fprintf(fid,'//\n'); - -fprintf(fid,'\n'); -fprintf(fid,'#include \n'); -fprintf(fid,'\n'); - -fprintf(fid,'float complex %s[%u] = {\n', basename, n); -for i=1:n, - %fprintf(fid,' {%16.12f, %16.12f}', real(v(i)), imag(v(i))); - fprintf(fid,' %16.12f + _Complex_I*%16.12f', real(v(i)), imag(v(i))); - if i==n, - fprintf(fid,'};\n'); - else, - fprintf(fid,',\n'); - end; -end; - -fprintf(fid,'\n'); - -fclose(fid); -printf('results written to %s\n', filename); From 2ef6b372026e9879a27664b99e76dc4239aa6e45 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 18:17:09 -0500 Subject: [PATCH 200/334] nco: moving test file to consolidate nco packages --- makefile.in | 2 +- .../tests/{nco_crcf_copy_autotest.c => nco_crcf_autotest.c} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/nco/tests/{nco_crcf_copy_autotest.c => nco_crcf_autotest.c} (95%) diff --git a/makefile.in b/makefile.in index 943819dbe..695d8ee45 100644 --- a/makefile.in +++ b/makefile.in @@ -981,7 +981,7 @@ src/nco/src/nco.utilities.o : %.o : %.c $(include_headers) # autotests nco_autotests := \ - src/nco/tests/nco_crcf_copy_autotest.c \ + src/nco/tests/nco_crcf_autotest.c \ src/nco/tests/nco_crcf_frequency_autotest.c \ src/nco/tests/nco_crcf_mix_autotest.c \ src/nco/tests/nco_crcf_phase_autotest.c \ diff --git a/src/nco/tests/nco_crcf_copy_autotest.c b/src/nco/tests/nco_crcf_autotest.c similarity index 95% rename from src/nco/tests/nco_crcf_copy_autotest.c rename to src/nco/tests/nco_crcf_autotest.c index 925516a27..2fc4f06bd 100644 --- a/src/nco/tests/nco_crcf_copy_autotest.c +++ b/src/nco/tests/nco_crcf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ #include "autotest/autotest.h" #include "liquid.h" -// test floating point precision nco phase +// test copying object void autotest_nco_crcf_copy() { // create and initialize object From 6f64bce31c70acaeeaec3b8682a5dea7a48c701a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 18:50:55 -0500 Subject: [PATCH 201/334] nco/autotest: checking nco_crcf_constrain --- src/nco/src/nco.proto.c | 2 +- src/nco/tests/nco_crcf_autotest.c | 37 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/nco/src/nco.proto.c b/src/nco/src/nco.proto.c index 0853300a1..c85bbf3da 100644 --- a/src/nco/src/nco.proto.c +++ b/src/nco/src/nco.proto.c @@ -406,7 +406,7 @@ uint32_t NCO(_constrain)(float _theta) while (_theta >= 2*M_PI) _theta -= 2*M_PI; while (_theta < 0) _theta += 2*M_PI; - return (uint32_t) (_theta / (2*M_PI) * 0xffffffff); + return (uint32_t) ((_theta/(2*M_PI)) * 0xffffffff); #endif } diff --git a/src/nco/tests/nco_crcf_autotest.c b/src/nco/tests/nco_crcf_autotest.c index 2fc4f06bd..77bae7f74 100644 --- a/src/nco/tests/nco_crcf_autotest.c +++ b/src/nco/tests/nco_crcf_autotest.c @@ -25,6 +25,43 @@ #include "autotest/autotest.h" #include "liquid.h" +// forward declaration of internal method to constrain phase +uint32_t nco_crcf_constrain(float _theta); + +// test phase constraint +void autotest_nco_crcf_constrain() +{ + float delta = (float)0x00001fff; + + // phase: 0 mod 2 pi + CONTEND_DELTA( nco_crcf_constrain( 0.0f), (float) 0, delta ); + CONTEND_DELTA( nco_crcf_constrain( 2*M_PI), (float) 0, delta ); + CONTEND_DELTA( nco_crcf_constrain( 4*M_PI), (float) 0, delta ); + CONTEND_DELTA( nco_crcf_constrain( 6*M_PI), (float) 0, delta ); + CONTEND_DELTA( nco_crcf_constrain( 20*M_PI), (float) 0, delta ); + + // phase: 0 mod 2 pi (negative) + //CONTEND_DELTA( nco_crcf_constrain( -0.0f), (float) 0, delta ); + //CONTEND_DELTA( nco_crcf_constrain( -2*M_PI), (float) 0, delta ); + //CONTEND_DELTA( nco_crcf_constrain( -4*M_PI), (float) 0, delta ); + //CONTEND_DELTA( nco_crcf_constrain( -6*M_PI), (float) 0, delta ); + //CONTEND_DELTA( nco_crcf_constrain(-20*M_PI), (float) 0, delta ); + + // phase: pi mod 2 pi + CONTEND_DELTA( nco_crcf_constrain( M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( 3*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( 5*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( 7*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( 27*M_PI), (float)0x80000000, delta ); + + // phase: pi mod 2 pi (negative) + CONTEND_DELTA( nco_crcf_constrain( -M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( -3*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( -5*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain( -7*M_PI), (float)0x80000000, delta ); + CONTEND_DELTA( nco_crcf_constrain(-27*M_PI), (float)0x80000000, delta ); +} + // test copying object void autotest_nco_crcf_copy() { From 2d05d9b169ca959a6905a41a06a0b420a4bd055d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 21 Nov 2023 18:55:02 -0500 Subject: [PATCH 202/334] nco/autotest: testing for values *near* boundaries --- src/nco/tests/nco_crcf_autotest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nco/tests/nco_crcf_autotest.c b/src/nco/tests/nco_crcf_autotest.c index 77bae7f74..09d0dc2a9 100644 --- a/src/nco/tests/nco_crcf_autotest.c +++ b/src/nco/tests/nco_crcf_autotest.c @@ -60,6 +60,10 @@ void autotest_nco_crcf_constrain() CONTEND_DELTA( nco_crcf_constrain( -5*M_PI), (float)0x80000000, delta ); CONTEND_DELTA( nco_crcf_constrain( -7*M_PI), (float)0x80000000, delta ); CONTEND_DELTA( nco_crcf_constrain(-27*M_PI), (float)0x80000000, delta ); + + // check phase near boundaries + CONTEND_DELTA( nco_crcf_constrain(+0.000001f), (float) 0, delta ); + //CONTEND_DELTA( nco_crcf_constrain(-0.000001f), (float) 0, delta ); } // test copying object From 5ba43b6846620f9334693562ff4df8508113b67a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 22 Nov 2023 08:25:55 -0500 Subject: [PATCH 203/334] nco/autotest: adding explicit checks for nco_constrain --- src/nco/tests/nco_crcf_autotest.c | 54 ++++++++++++++++++------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/nco/tests/nco_crcf_autotest.c b/src/nco/tests/nco_crcf_autotest.c index 09d0dc2a9..3b31ce47e 100644 --- a/src/nco/tests/nco_crcf_autotest.c +++ b/src/nco/tests/nco_crcf_autotest.c @@ -28,42 +28,50 @@ // forward declaration of internal method to constrain phase uint32_t nco_crcf_constrain(float _theta); +// compute phase-constrained error +uint32_t nco_crcf_constrain_error(float _theta, uint32_t _expected) +{ + uint32_t phase = nco_crcf_constrain(_theta); + uint32_t error = phase > _expected ? phase - _expected : _expected - phase; + return error < 0x80000000 ? error : 0xffffffff - error; +} + // test phase constraint void autotest_nco_crcf_constrain() { - float delta = (float)0x00001fff; + uint32_t tol = 0x00001fff; // phase: 0 mod 2 pi - CONTEND_DELTA( nco_crcf_constrain( 0.0f), (float) 0, delta ); - CONTEND_DELTA( nco_crcf_constrain( 2*M_PI), (float) 0, delta ); - CONTEND_DELTA( nco_crcf_constrain( 4*M_PI), (float) 0, delta ); - CONTEND_DELTA( nco_crcf_constrain( 6*M_PI), (float) 0, delta ); - CONTEND_DELTA( nco_crcf_constrain( 20*M_PI), (float) 0, delta ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 0.0f, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 2*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 4*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 6*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 20*M_PI, 0), tol ); // phase: 0 mod 2 pi (negative) - //CONTEND_DELTA( nco_crcf_constrain( -0.0f), (float) 0, delta ); - //CONTEND_DELTA( nco_crcf_constrain( -2*M_PI), (float) 0, delta ); - //CONTEND_DELTA( nco_crcf_constrain( -4*M_PI), (float) 0, delta ); - //CONTEND_DELTA( nco_crcf_constrain( -6*M_PI), (float) 0, delta ); - //CONTEND_DELTA( nco_crcf_constrain(-20*M_PI), (float) 0, delta ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -0.0f, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -2*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -4*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -6*M_PI, 0), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-20*M_PI, 0), tol ); // phase: pi mod 2 pi - CONTEND_DELTA( nco_crcf_constrain( M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( 3*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( 5*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( 7*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( 27*M_PI), (float)0x80000000, delta ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 3*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 5*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 7*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( 27*M_PI, 0x80000000), tol ); // phase: pi mod 2 pi (negative) - CONTEND_DELTA( nco_crcf_constrain( -M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( -3*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( -5*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain( -7*M_PI), (float)0x80000000, delta ); - CONTEND_DELTA( nco_crcf_constrain(-27*M_PI), (float)0x80000000, delta ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -3*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -5*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error( -7*M_PI, 0x80000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-27*M_PI, 0x80000000), tol ); // check phase near boundaries - CONTEND_DELTA( nco_crcf_constrain(+0.000001f), (float) 0, delta ); - //CONTEND_DELTA( nco_crcf_constrain(-0.000001f), (float) 0, delta ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.000001f, 0x00000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.000001f, 0x00000000), tol ); } // test copying object From 85965a43c570e843c20b44ba5e92ec56cc4264ff Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 22 Nov 2023 09:01:49 -0500 Subject: [PATCH 204/334] nco/autotest: adding more tests for constrain() --- src/nco/tests/nco_crcf_autotest.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/nco/tests/nco_crcf_autotest.c b/src/nco/tests/nco_crcf_autotest.c index 3b31ce47e..15a3212c3 100644 --- a/src/nco/tests/nco_crcf_autotest.c +++ b/src/nco/tests/nco_crcf_autotest.c @@ -69,6 +69,15 @@ void autotest_nco_crcf_constrain() CONTEND_LESS_THAN( nco_crcf_constrain_error( -7*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-27*M_PI, 0x80000000), tol ); + // check other values + CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.500*M_PI, 0x40000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.250*M_PI, 0x20000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.125*M_PI, 0x10000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.750*M_PI, 0x60000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.500*M_PI, 0xc0000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.250*M_PI, 0xe0000000), tol ); + CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.125*M_PI, 0xf0000000), tol ); + // check phase near boundaries CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.000001f, 0x00000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.000001f, 0x00000000), tol ); From 5bb0d782735a738e7bfa1913312a4c692f4ade83 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 24 Nov 2023 11:21:02 -0500 Subject: [PATCH 205/334] nco/autotest: checking for wider range of PLL synchronization * sweeping over phase and frequency offsets * varying loop bandwidths * adjusting number of steps to compensate --- src/nco/tests/nco_crcf_pll_autotest.c | 76 ++++++++++++++++----------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/nco/tests/nco_crcf_pll_autotest.c b/src/nco/tests/nco_crcf_pll_autotest.c index c3b1ef8cf..2a5e3aafc 100644 --- a/src/nco/tests/nco_crcf_pll_autotest.c +++ b/src/nco/tests/nco_crcf_pll_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -81,8 +81,11 @@ void nco_crcf_pll_test(int _type, CONTEND_DELTA(freq_error, 0, _tol); if (liquid_autotest_verbose) { - printf(" phase error : %12.4e, frequency error : %12.4e\n", + printf(" nco[bw:%6.4f,n=%6u], phase:%9.6f,e=%11.4e, freq:%9.6f,e=%11.4e\n", + _pll_bandwidth, _num_iterations, + _phase_offset, phase_error, + _freq_offset, freq_error); } @@ -91,40 +94,49 @@ void nco_crcf_pll_test(int _type, nco_crcf_destroy(nco_rx); } -// -// AUTOTEST: test frequency and phase offsets -// +// test phase offsets void autotest_nco_crcf_pll_phase() { - float bw = 0.1f; - unsigned int num_steps = 256; - float tol = 1e-2f; - - // test various phase offsets - nco_crcf_pll_test(LIQUID_NCO, -M_PI/1.1f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, -M_PI/2.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, -M_PI/4.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, -M_PI/8.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, M_PI/8.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, M_PI/4.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, M_PI/2.0f, 0.0f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, M_PI/1.1f, 0.0f, bw, num_steps, tol); + float bw[4] = {0.1f, 0.01f, 0.001f, 0.0001f}; + float tol = 1e-2f; + + unsigned int i; + for (i=0; i<4; i++) { + // adjust number of steps according to loop bandwidth + unsigned int num_steps = (unsigned int)(32.0f / bw[i]); + + // test various phase offsets + nco_crcf_pll_test(LIQUID_NCO, -M_PI/1.1f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, -M_PI/2.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, -M_PI/4.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, -M_PI/8.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, M_PI/8.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, M_PI/4.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, M_PI/2.0f, 0.0f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, M_PI/1.1f, 0.0f, bw[i], num_steps, tol); + } } - + +// test phase offsets void autotest_nco_crcf_pll_freq() { - float bw = 0.1f; - unsigned int num_steps = 256; - float tol = 1e-2f; - - // test various frequency offsets - nco_crcf_pll_test(LIQUID_NCO, 0.0f, -1.6f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.8f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.4f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.2f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.2f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.4f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.8f, bw, num_steps, tol); - nco_crcf_pll_test(LIQUID_NCO, 0.0f, 1.6f, bw, num_steps, tol); + float bw[4] = {0.1f, 0.05f, 0.02f, 0.01f}; + float tol = 1e-2f; + + unsigned int i; + for (i=0; i<4; i++) { + // adjust number of steps according to loop bandwidth + unsigned int num_steps = (unsigned int)(32.0f / bw[i]); + + // test various frequency offsets + nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.8f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.4f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.2f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.1f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.1f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.2f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.4f, bw[i], num_steps, tol); + nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.8f, bw[i], num_steps, tol); + } } From 413facbc9c873e7d392f2016b24a151ecf654a07 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 16:30:34 -0500 Subject: [PATCH 206/334] fec/autotest: checking configuration for printing schemes --- include/liquid.h | 2 +- src/fec/src/fec.c | 3 ++- src/fec/tests/fec_config_autotest.c | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index c657f9191..819c3f4eb 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1293,7 +1293,7 @@ typedef enum { extern const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2]; // Print compact list of existing and available FEC schemes -void liquid_print_fec_schemes(); +int liquid_print_fec_schemes(); // returns fec_scheme based on input string fec_scheme liquid_getopt_str2fec(const char * _str); diff --git a/src/fec/src/fec.c b/src/fec/src/fec.c index b62726ac7..af361f8f1 100644 --- a/src/fec/src/fec.c +++ b/src/fec/src/fec.c @@ -65,7 +65,7 @@ const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2] = { }; // Print compact list of existing and available fec schemes -void liquid_print_fec_schemes() +int liquid_print_fec_schemes() { unsigned int i; unsigned int len = 10; @@ -89,6 +89,7 @@ void liquid_print_fec_schemes() } } printf("\n"); + return LIQUID_OK; } diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c index 729a5725e..ce1c71a77 100644 --- a/src/fec/tests/fec_config_autotest.c +++ b/src/fec/tests/fec_config_autotest.c @@ -47,5 +47,7 @@ void autotest_fec_config() CONTEND_EQUALITY(fec_hamming128_encode_symbol(1u<<8), 0) CONTEND_EQUALITY(fec_hamming128_decode_symbol(1u<<12), 0) + + CONTEND_EQUALITY(liquid_print_fec_schemes(), LIQUID_OK); } From 4a93c4dabf09f3ebfc38d8961b6c09bfc45fcd73 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 16:39:00 -0500 Subject: [PATCH 207/334] fec/autotest: checking for string parsing --- src/fec/tests/fec_config_autotest.c | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c index ce1c71a77..853c5e118 100644 --- a/src/fec/tests/fec_config_autotest.c +++ b/src/fec/tests/fec_config_autotest.c @@ -48,6 +48,43 @@ void autotest_fec_config() CONTEND_EQUALITY(fec_hamming128_encode_symbol(1u<<8), 0) CONTEND_EQUALITY(fec_hamming128_decode_symbol(1u<<12), 0) + // check printing schemes CONTEND_EQUALITY(liquid_print_fec_schemes(), LIQUID_OK); } +void autotest_fec_str2fec() +{ + // start with invalid case + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); + CONTEND_EQUALITY(liquid_getopt_str2fec("invalid scheme"), LIQUID_MODEM_UNKNOWN); + + // check normal cases + CONTEND_EQUALITY( liquid_getopt_str2fec("none"), LIQUID_FEC_NONE); + CONTEND_EQUALITY( liquid_getopt_str2fec("rep3"), LIQUID_FEC_REP3); + CONTEND_EQUALITY( liquid_getopt_str2fec("rep5"), LIQUID_FEC_REP5); + CONTEND_EQUALITY( liquid_getopt_str2fec("h74"), LIQUID_FEC_HAMMING74); + CONTEND_EQUALITY( liquid_getopt_str2fec("h84"), LIQUID_FEC_HAMMING84); + CONTEND_EQUALITY( liquid_getopt_str2fec("h128"), LIQUID_FEC_HAMMING128); + CONTEND_EQUALITY( liquid_getopt_str2fec("g2412"), LIQUID_FEC_GOLAY2412); + CONTEND_EQUALITY( liquid_getopt_str2fec("secded2216"), LIQUID_FEC_SECDED2216); + CONTEND_EQUALITY( liquid_getopt_str2fec("secded3932"), LIQUID_FEC_SECDED3932); + CONTEND_EQUALITY( liquid_getopt_str2fec("secded7264"), LIQUID_FEC_SECDED7264); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27"), LIQUID_FEC_CONV_V27); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29"), LIQUID_FEC_CONV_V29); + CONTEND_EQUALITY( liquid_getopt_str2fec("v39"), LIQUID_FEC_CONV_V39); + CONTEND_EQUALITY( liquid_getopt_str2fec("v615"), LIQUID_FEC_CONV_V615); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p23"), LIQUID_FEC_CONV_V27P23); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p34"), LIQUID_FEC_CONV_V27P34); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p45"), LIQUID_FEC_CONV_V27P45); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p56"), LIQUID_FEC_CONV_V27P56); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p67"), LIQUID_FEC_CONV_V27P67); + CONTEND_EQUALITY( liquid_getopt_str2fec("v27p78"), LIQUID_FEC_CONV_V27P78); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p23"), LIQUID_FEC_CONV_V29P23); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p34"), LIQUID_FEC_CONV_V29P34); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p45"), LIQUID_FEC_CONV_V29P45); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p56"), LIQUID_FEC_CONV_V29P56); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p67"), LIQUID_FEC_CONV_V29P67); + CONTEND_EQUALITY( liquid_getopt_str2fec("v29p78"), LIQUID_FEC_CONV_V29P78); + CONTEND_EQUALITY( liquid_getopt_str2fec("rs8"), LIQUID_FEC_RS_M8); +} + From 69a3ac0f301604d67f4a0a0e65465ae42a0cbf4e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 16:43:14 -0500 Subject: [PATCH 208/334] fec/autotest: checking schemes are convolutional --- src/fec/tests/fec_config_autotest.c | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c index 853c5e118..c2f19f865 100644 --- a/src/fec/tests/fec_config_autotest.c +++ b/src/fec/tests/fec_config_autotest.c @@ -87,4 +87,33 @@ void autotest_fec_str2fec() CONTEND_EQUALITY( liquid_getopt_str2fec("v29p78"), LIQUID_FEC_CONV_V29P78); CONTEND_EQUALITY( liquid_getopt_str2fec("rs8"), LIQUID_FEC_RS_M8); } - +void autotest_fec_is_convolutional() +{ + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_NONE), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_REP3), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_REP5), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING74), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING84), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING128), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_GOLAY2412), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED2216), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED3932), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED7264), 0 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V39), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V615), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P23), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P34), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P45), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P56), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P67), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P78), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P23), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P34), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P45), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P56), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P67), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P78), 1 ); + CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_RS_M8), 0 ); +} From 9c52dab0977d71afdfb17aa628e2aa952971676b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 16:44:50 -0500 Subject: [PATCH 209/334] fec/autotest: checking that schemes are punctured --- src/fec/tests/fec_config_autotest.c | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c index c2f19f865..6cfadb55b 100644 --- a/src/fec/tests/fec_config_autotest.c +++ b/src/fec/tests/fec_config_autotest.c @@ -87,6 +87,7 @@ void autotest_fec_str2fec() CONTEND_EQUALITY( liquid_getopt_str2fec("v29p78"), LIQUID_FEC_CONV_V29P78); CONTEND_EQUALITY( liquid_getopt_str2fec("rs8"), LIQUID_FEC_RS_M8); } + void autotest_fec_is_convolutional() { CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_NONE), 0 ); @@ -117,3 +118,35 @@ void autotest_fec_is_convolutional() CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P78), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_RS_M8), 0 ); } + +void autotest_fec_is_punctured() +{ + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_NONE), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_REP3), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_REP5), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING74), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING84), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING128), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_GOLAY2412), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED2216), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED3932), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED7264), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V39), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V615), 0 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P23), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P34), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P45), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P56), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P67), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P78), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P23), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P34), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P45), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P56), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P67), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P78), 1 ); + CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_RS_M8), 0 ); +} + From 3dc9e47fdf8b216b3a4221df3052d6a7e5220413 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 19:35:03 -0500 Subject: [PATCH 210/334] fec/config: checking several more configurations --- src/fec/tests/fec_config_autotest.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/fec/tests/fec_config_autotest.c b/src/fec/tests/fec_config_autotest.c index 6cfadb55b..fd964fffe 100644 --- a/src/fec/tests/fec_config_autotest.c +++ b/src/fec/tests/fec_config_autotest.c @@ -150,3 +150,27 @@ void autotest_fec_is_punctured() CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_RS_M8), 0 ); } +void autotest_fec_is_reedsolomon() +{ + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_NONE), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_REP3), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_HAMMING74), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_GOLAY2412), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_SECDED2216), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_CONV_V27), 0 ); + CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_RS_M8), 1 ); +} + +void autotest_fec_is_hamming() +{ + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_NONE), 0 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_REP3), 0 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING74), 1 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING84), 1 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING128), 1 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_GOLAY2412), 0 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_SECDED2216), 0 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_CONV_V27), 0 ); + CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_RS_M8), 0 ); +} + From aa73b474caed3ecd001f970c456e4303074e9a1a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 2 Dec 2023 19:39:07 -0500 Subject: [PATCH 211/334] crc/autotest: checking length --- src/fec/tests/crc_autotest.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fec/tests/crc_autotest.c b/src/fec/tests/crc_autotest.c index 7e8991ad3..81787e8e1 100644 --- a/src/fec/tests/crc_autotest.c +++ b/src/fec/tests/crc_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -130,6 +130,16 @@ void autotest_crc_config() CONTEND_EQUALITY(LIQUID_CRC_16, liquid_getopt_str2crc("crc16")) CONTEND_EQUALITY(LIQUID_CRC_24, liquid_getopt_str2crc("crc24")) CONTEND_EQUALITY(LIQUID_CRC_32, liquid_getopt_str2crc("crc32")) + + // check length + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_UNKNOWN), 0); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_NONE), 0); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_CHECKSUM), 1); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_8), 1); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_16), 2); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_24), 3); + CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_32), 4); + CONTEND_EQUALITY(crc_get_length(-1), 0); } From a5a32611cfc3659d4048b5709c863323f6d6864f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Dec 2023 08:49:51 -0500 Subject: [PATCH 212/334] random/autotest: enabling testing for various distributions --- makefile.in | 3 +-- src/random/tests/random_autotest.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/makefile.in b/makefile.in index 695d8ee45..ef936ffde 100644 --- a/makefile.in +++ b/makefile.in @@ -1077,8 +1077,7 @@ $(random_objects) : %.o : %.c $(include_headers) # autotests random_autotests := \ src/random/tests/scramble_autotest.c \ - -# src/random/tests/random_autotest.c + src/random/tests/random_autotest.c \ # benchmarks diff --git a/src/random/tests/random_autotest.c b/src/random/tests/random_autotest.c index a9e389f5a..6c1a0e2cf 100644 --- a/src/random/tests/random_autotest.c +++ b/src/random/tests/random_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -109,8 +109,16 @@ void autotest_randweibf() m1 /= (float) N; m2 = (m2 / (float)N) - m1*m1; - CONTEND_DELTA(m1, 1.2533f+gamma, tol); - CONTEND_DELTA(m2, 0.42920f, tol); + // compute expected moments (closed-form solution) + float t0 = liquid_gammaf(1. + 1./alpha); + float t1 = liquid_gammaf(1. + 2./alpha); + float m1_exp = beta * t0 + gamma; + float m2_exp = beta*beta*( t1 - t0*t0 ); + //printf("m1: %12.8f (expected %12.8f)\n", m1, m1_exp); + //printf("m2: %12.8f (expected %12.8f)\n", m2, m2_exp); + + CONTEND_DELTA(m1, m1_exp, tol); + CONTEND_DELTA(m2, m2_exp, tol); } // Rice-K From bfa6312fd0667a31784985cde99233dd2f7a4fee Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Dec 2023 09:40:31 -0500 Subject: [PATCH 213/334] rand: adding autotest for exponential distribution --- src/random/tests/random_autotest.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/random/tests/random_autotest.c b/src/random/tests/random_autotest.c index 6c1a0e2cf..c95c0ebc7 100644 --- a/src/random/tests/random_autotest.c +++ b/src/random/tests/random_autotest.c @@ -143,3 +143,31 @@ void autotest_randricekf() CONTEND_DELTA(m2, omega, tol); } +// exponential +void autotest_randexpf() +{ + unsigned long int N = LIQUID_RANDOM_AUTOTEST_NUM_TRIALS; + unsigned long int i; + float x, m1=0.0f, m2=0.0f; + float tol = LIQUID_RANDOM_AUTOTEST_ERROR_TOL; + float lambda = 2.3f; + + // uniform + for (i=0; i Date: Sun, 3 Dec 2023 09:45:09 -0500 Subject: [PATCH 214/334] rand: testing input configurations, exp --- src/random/tests/random_autotest.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/random/tests/random_autotest.c b/src/random/tests/random_autotest.c index c95c0ebc7..bb73202da 100644 --- a/src/random/tests/random_autotest.c +++ b/src/random/tests/random_autotest.c @@ -171,3 +171,21 @@ void autotest_randexpf() CONTEND_DELTA(m2, m2_exp, tol); } +void autotest_random_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping random config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // exponential: lambda out of range + CONTEND_EQUALITY( randexpf ( -1.0f), 0.0f ); + CONTEND_EQUALITY( randexpf_pdf( 0.0f, -1.0f), 0.0f ); + CONTEND_EQUALITY( randexpf_cdf( 0.0f, -1.0f), 0.0f ); + // exponential: pdf, cdf with valid input, but negative variable + CONTEND_EQUALITY( randexpf_pdf(-2.0f, 2.3f), 0.0f ); + CONTEND_EQUALITY( randexpf_cdf(-2.0f, 2.3f), 0.0f ); +} + From 3a2357812165a0510372afb08d227291e9cf00a6 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Dec 2023 09:49:34 -0500 Subject: [PATCH 215/334] rand: testing input configurations, gamma --- src/random/tests/random_autotest.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/random/tests/random_autotest.c b/src/random/tests/random_autotest.c index bb73202da..ba0b4b097 100644 --- a/src/random/tests/random_autotest.c +++ b/src/random/tests/random_autotest.c @@ -21,7 +21,7 @@ */ #include "autotest/autotest.h" -#include "liquid.h" +#include "liquid.internal.h" #define LIQUID_RANDOM_AUTOTEST_NUM_TRIALS (100000) #define LIQUID_RANDOM_AUTOTEST_ERROR_TOL (0.1) @@ -187,5 +187,19 @@ void autotest_random_config() // exponential: pdf, cdf with valid input, but negative variable CONTEND_EQUALITY( randexpf_pdf(-2.0f, 2.3f), 0.0f ); CONTEND_EQUALITY( randexpf_cdf(-2.0f, 2.3f), 0.0f ); + + // gamma: parameters out of range (alpha) + CONTEND_EQUALITY( randgammaf ( -1.0f, 1.0f), 0.0f ); + CONTEND_EQUALITY( randgammaf_pdf( 0.0f, -1.0f, 1.0f), 0.0f ); + CONTEND_EQUALITY( randgammaf_cdf( 0.0f, -1.0f, 1.0f), 0.0f ); + // gamma: parameters out of range (beta) + CONTEND_EQUALITY( randgammaf ( 1.0f, -1.0f), 0.0f ); + CONTEND_EQUALITY( randgammaf_pdf( 0.0f, 1.0f, -1.0f), 0.0f ); + CONTEND_EQUALITY( randgammaf_cdf( 0.0f, 1.0f, -1.0f), 0.0f ); + // gamma: delta function parameter out of range + CONTEND_EQUALITY( randgammaf_delta(-1.0f), 0.0f ); + // gamma: pdf, cdf with valid input, but negative variable + CONTEND_EQUALITY( randgammaf_pdf(-2.0f, 1.2f, 2.3f), 0.0f ); + CONTEND_EQUALITY( randgammaf_cdf(-2.0f, 1.2f, 2.3f), 0.0f ); } From 5432e317e3c31f069e8223d185c28078fc41c8cc Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Dec 2023 09:52:36 -0500 Subject: [PATCH 216/334] rand: testing input configurations, nakagami-m --- src/random/tests/random_autotest.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/random/tests/random_autotest.c b/src/random/tests/random_autotest.c index ba0b4b097..afcf5f148 100644 --- a/src/random/tests/random_autotest.c +++ b/src/random/tests/random_autotest.c @@ -201,5 +201,17 @@ void autotest_random_config() // gamma: pdf, cdf with valid input, but negative variable CONTEND_EQUALITY( randgammaf_pdf(-2.0f, 1.2f, 2.3f), 0.0f ); CONTEND_EQUALITY( randgammaf_cdf(-2.0f, 1.2f, 2.3f), 0.0f ); + + // nakagami-m: parameters out of range (m) + CONTEND_EQUALITY( randnakmf ( 0.2f, 1.0f), 0.0f ); + CONTEND_EQUALITY( randnakmf_pdf( 0.0f, 0.2f, 1.0f), 0.0f ); + CONTEND_EQUALITY( randnakmf_cdf( 0.0f, 0.2f, 1.0f), 0.0f ); + // nakagami-m: parameters out of range (omega) + CONTEND_EQUALITY( randnakmf ( 1.0f, -1.0f), 0.0f ); + CONTEND_EQUALITY( randnakmf_pdf( 0.0f, 1.0f, -1.0f), 0.0f ); + CONTEND_EQUALITY( randnakmf_cdf( 0.0f, 1.0f, -1.0f), 0.0f ); + // nakagami-m: pdf, cdf with valid input, but negative variable + CONTEND_EQUALITY( randnakmf_pdf(-2.0f, 1.2f, 2.3f), 0.0f ); + CONTEND_EQUALITY( randnakmf_cdf(-2.0f, 1.2f, 2.3f), 0.0f ); } From 8772c5e896b10056739e66212613b37b7394586a Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Dec 2023 10:40:47 -0500 Subject: [PATCH 217/334] rand/autotest: adding separate test for distributions --- makefile.in | 1 + .../tests/random_distributions_autotest.c | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/random/tests/random_distributions_autotest.c diff --git a/makefile.in b/makefile.in index ef936ffde..bea18abd2 100644 --- a/makefile.in +++ b/makefile.in @@ -1078,6 +1078,7 @@ $(random_objects) : %.o : %.c $(include_headers) random_autotests := \ src/random/tests/scramble_autotest.c \ src/random/tests/random_autotest.c \ + src/random/tests/random_distributions_autotest.c \ # benchmarks diff --git a/src/random/tests/random_distributions_autotest.c b/src/random/tests/random_distributions_autotest.c new file mode 100644 index 000000000..d827bb3ea --- /dev/null +++ b/src/random/tests/random_distributions_autotest.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2007 - 2023 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "autotest/autotest.h" +#include "liquid.internal.h" + +// compute emperical distributions and compare to theoretical + +// add value to histogram +unsigned int _support_histogram_add(float _value, + float * _bins, + unsigned int _num_bins, + float _vmin, + float _vmax) +{ + float indexf = _num_bins * (_value - _vmin) / (_vmax - _vmin); + unsigned int index = 0; + if (indexf >= 0) + index = (unsigned int)indexf; + if (index >= _num_bins) + index = _num_bins - 1; + _bins[index]++; + return index; +} + +// noramlize histogram (area under curve) +float _support_histogram_normalize(float * _bins, + unsigned int _num_bins, + float _vmin, + float _vmax) +{ + float area = 0.0f; + unsigned int i; + for (i=0; i<_num_bins; i++) + area += _bins[i]; + area *= (_vmax - _vmin) / (float)_num_bins; + for (i=0; i<_num_bins; i++) + _bins[i] /= area; + return area; +} + +// log histogram +void _support_histogram_log(float * _bins, + unsigned int _num_bins, + float _vmin, + float _vmax) +{ + // find max(hist) + unsigned int i; + float hist_max = 0; + for (i=0; i<_num_bins; i++) + hist_max = _bins[i] > hist_max ? _bins[i] : hist_max; + + unsigned int num_chars = 72; + float _vstep = (_vmax - _vmin) / (float)(_num_bins-1); + printf("%8s : [%12s]\n", "v", "probability"); + for (i=0; i<_num_bins; i++) { + printf("%8.2f : [%12g]", _vmin + i*_vstep, _bins[i]); + + unsigned int k; + unsigned int n = round(num_chars * _bins[i] / hist_max); + for (k=0; k Date: Sun, 3 Dec 2023 10:52:38 -0500 Subject: [PATCH 218/334] rand/autotest: computing pdf, cdf for normal distribution --- .../tests/random_distributions_autotest.c | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/random/tests/random_distributions_autotest.c b/src/random/tests/random_distributions_autotest.c index d827bb3ea..66fe82563 100644 --- a/src/random/tests/random_distributions_autotest.c +++ b/src/random/tests/random_distributions_autotest.c @@ -79,7 +79,8 @@ void _support_histogram_log(float * _bins, unsigned int k; unsigned int n = round(num_chars * _bins[i] / hist_max); for (k=0; k Date: Sun, 3 Dec 2023 17:08:42 -0500 Subject: [PATCH 219/334] rand/autotest: checking PDF and CDF --- .../tests/random_distributions_autotest.c | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/random/tests/random_distributions_autotest.c b/src/random/tests/random_distributions_autotest.c index 66fe82563..5d5c5ca71 100644 --- a/src/random/tests/random_distributions_autotest.c +++ b/src/random/tests/random_distributions_autotest.c @@ -72,7 +72,7 @@ void _support_histogram_log(float * _bins, unsigned int num_chars = 72; float _vstep = (_vmax - _vmin) / (float)(_num_bins-1); - printf("%8s : [%12s]\n", "v", "probability"); + printf("%8s : [%12s]\n", "v", "bin value"); for (i=0; i<_num_bins; i++) { printf("%8.2f : [%12g]", _vmin + i*_vstep, _bins[i]); @@ -85,46 +85,71 @@ void _support_histogram_log(float * _bins, } } +// validate pdf and cdf +void _support_histogram_validate(float * _bins, + float * _pdf, + float * _cdf, + unsigned int _num_bins, + float _vmin, + float _vmax, + float _tol) +{ + // normalize histogram + _support_histogram_normalize(_bins, _num_bins, _vmin, _vmax); + + // compare pdf and cdf + unsigned int i; + for (i=0; i<_num_bins; i++) { + CONTEND_DELTA(_bins[i], _pdf[i], _tol); + } + + // accumulate and compare cdf + float _vstep = (_vmax - _vmin) / (float)(_num_bins); + float accum = 0.0f; + for (i=1; i<_num_bins; i++) { + // trapezoidal integration + accum += 0.5f * (_bins[i-1] + _bins[i]) * _vstep; + CONTEND_DELTA(accum, _cdf[i], _tol); + //printf("[%2u] : %12.8f (expected %12.8f), e:%12.8f\n", i, accum, _cdf[i], accum-_cdf[i]); + } +} + // normal distribution void autotest_distribution_randnf() { - unsigned long int num_trials = 96000; - unsigned long int i; - float v; + unsigned long int num_trials = 248000; float eta = 0.0f, sig = 1.0f; + float tol = 0.05f; unsigned int num_bins = 31; float bins[num_bins]; + unsigned long int i; for (i=0; i Date: Sun, 3 Dec 2023 17:25:39 -0500 Subject: [PATCH 220/334] rand/autotest: adding exponential test, disabled for now --- .../tests/random_distributions_autotest.c | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/random/tests/random_distributions_autotest.c b/src/random/tests/random_distributions_autotest.c index 5d5c5ca71..c27be7abd 100644 --- a/src/random/tests/random_distributions_autotest.c +++ b/src/random/tests/random_distributions_autotest.c @@ -153,3 +153,42 @@ void autotest_distribution_randnf() _support_histogram_validate(bins, pdf, cdf, num_bins, vmin, vmax, tol); } +// exponential distribution +void xautotest_distribution_randexpf() +{ + unsigned long int num_trials = 248000; + float lambda = 1.3f; + float tol = 0.05f; + + unsigned int num_bins = 21; + float bins[num_bins]; + unsigned long int i; + for (i=0; i Date: Sun, 21 Jan 2024 10:17:02 -0500 Subject: [PATCH 221/334] freqmodem/example: cleaning up top-level description in file --- examples/freqmodem_example.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/freqmodem_example.c b/examples/freqmodem_example.c index e7d89354b..e55421567 100644 --- a/examples/freqmodem_example.c +++ b/examples/freqmodem_example.c @@ -1,9 +1,4 @@ -// file: freqmodem_test.c -// -// Tests simple modulation/demodulation without noise or phase -// offset -// - +// Tests simple frequency modulation/demodulation #include #include #include From 7d2a5db4e2175ed469febe6ee11830cbc90cec71 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 11 Feb 2024 17:57:52 -0500 Subject: [PATCH 222/334] build: renaming target to 'check-doc' for consistency --- makefile.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/makefile.in b/makefile.in index bea18abd2..4dbeb64bc 100644 --- a/makefile.in +++ b/makefile.in @@ -1395,7 +1395,7 @@ clean-check: $(RM) autotest/logs/*.bin autotest/logs/*.gnu autotest/logs/*.png ## -## TARGET : doc-check - build and run basic documentation checks +## TARGET : check-doc - build and run basic documentation checks ## readme.c.example.c : README.md @@ -1416,9 +1416,9 @@ readme.cc.example.o : %.o : %.cc ${include_headers} readme.cc.example : % : %.o ${ARCHIVE_LIB} ${CXX} ${CXXFLAGS} ${LDFLAGS} $^ -o $@ ${LIBS} -doc-check : readme.c.example readme.cc.example ; ./readme.c.example && ./readme.cc.example +check-doc : readme.c.example readme.cc.example ; ./readme.c.example && ./readme.cc.example -clean-doc-check: +clean-check-doc: ${RM} readme.*.example* ## @@ -1859,7 +1859,7 @@ programs: all xautotest benchmark examples sandbox ## ## TARGET : world - build absolutely everything ## -world : all bench check doc-check examples sandbox +world : all bench check check-doc examples sandbox ## ## TARGET : clean - clean build (objects, dependencies, libraries, etc.) @@ -1872,7 +1872,7 @@ clean-modules: $(RM) src/*/src/*.o src/*/bench/*.o src/*/tests/*.o $(RM) src/libliquid.o -clean: clean-modules clean-autoscript clean-check clean-coverage clean-bench clean-examples clean-sandbox clean-doc-check +clean: clean-modules clean-autoscript clean-check clean-coverage clean-bench clean-examples clean-sandbox clean-check-doc $(RM) ${ARCHIVE_LIB} ${SHARED_LIB} $(extra_clean) ## From 3b92e757cf8d218a88d96230114dde1af11cfbc0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 17 Feb 2024 10:42:17 -0500 Subject: [PATCH 223/334] github/ci: fixing check-doc target --- .github/workflows/core.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 02fc5b825..06228c93f 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -30,8 +30,8 @@ jobs: - name: make run: make -j 2 - - name: make doc-check - run: make doc-check + - name: make check-doc + run: make check-doc - name: make check run: make -j 2 check From e59049df3b8744358304ce889d7e3e3bcd0c39cf Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 16 Dec 2023 20:34:15 -0500 Subject: [PATCH 224/334] sandbox/spc2216: fixing legend --- sandbox/fec_spc2216_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sandbox/fec_spc2216_test.c b/sandbox/fec_spc2216_test.c index 9a66df79a..59b542a45 100644 --- a/sandbox/fec_spc2216_test.c +++ b/sandbox/fec_spc2216_test.c @@ -379,7 +379,7 @@ int main(int argc, char*argv[]) fprintf(fid," EbN0dB, bit_errors_hard / num_bit_trials + 1e-12, '-x',\n"); fprintf(fid," EbN0dB, bit_errors_soft / num_bit_trials + 1e-12, '-x');\n"); fprintf(fid,"axis([%f (%f-10*log10(r)) 1e-6 1]);\n", SNRdB_min, SNRdB_max); - fprintf(fid,"legend('uncoded','hard','soft',1);\n"); + fprintf(fid,"legend('uncoded','hard','soft');\n"); fprintf(fid,"xlabel('E_b/N_0 [dB]');\n"); fprintf(fid,"ylabel('Bit Error Rate');\n"); fprintf(fid,"title('BER vs. E_b/N_0 for SPC(22,16)');\n"); From 506d2b85e8c19c928ca26a7ed7bb61d89629d9d2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 17 Feb 2024 13:40:39 -0500 Subject: [PATCH 225/334] gitlab/ci: fixing check-doc target --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d45f3fda..6301570ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,10 +42,10 @@ bench: paths: [benchmark.json] # compile and run documenation checks (e.g. example code in README.md) -doc-check: +check-doc: stage: test script: - - make doc-check + - make check-doc # compile and run all example programs, timing how long each takes to run examples: From 37b2950101efb6531598ce80912bc5965c96df86 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 17 Feb 2024 13:56:34 -0500 Subject: [PATCH 226/334] gitlab/ci: disabling strict compilation --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6301570ce..a2fecff94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ compile: stage: build script: - ./bootstrap.sh - - ./configure --enable-strict + - ./configure - make -j4 artifacts: # save output objects for test stages paths: [makefile, configure, config.h, config.h.in] From bbfa588ffa6c57ab1ff449172acb694d4c611749 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 3 Mar 2024 16:18:13 -0500 Subject: [PATCH 227/334] rresamp: adding note on bandwidth setting --- include/liquid.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index 819c3f4eb..f69e79f53 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4363,7 +4363,12 @@ RRESAMP() RRESAMP(_create)(unsigned int _interp, \ /* _interp : interpolation factor, _interp > 0 */ \ /* _decim : decimation factor, _decim > 0 */ \ /* _m : filter semi-length (delay), 0 < _m */ \ -/* _bw : filter bandwidth relative to sample rate, 0 < _bw <= 0.5 */ \ +/* _bw : filter bandwidth relative to sample rate. When the */ \ +/* the resampler is configured as an interpolator a value of */ \ +/* 0.5 (critically filtered) or less is recommended. */ \ +/* When the resampler is configured as a decimator, the */ \ +/* critical sampling rate is 0.5*_interp/_decim, */ \ +/* 0 < _bw <= 0.5 */ \ /* _as : filter stop-band attenuation [dB], 0 < _as */ \ RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, \ unsigned int _decim, \ From 978ddd3b33172b89b30ce8956c857039562ea30e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 09:08:27 -0500 Subject: [PATCH 228/334] build: ignoring auto-generated check-doc files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0898d51ea..30ec9d917 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ xautotest autotest.json autotest/logs/*.bin autotest/logs/*.gnu +readme.* # miscellany octave-core From a489d6d077a47a1a5973830c974be891238cfc52 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 09:24:07 -0500 Subject: [PATCH 229/334] rresamp: cleaning up example --- examples/rresamp_crcf_example.c | 73 +++++++++++++++------------------ 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/examples/rresamp_crcf_example.c b/examples/rresamp_crcf_example.c index f213d8088..430b3e42b 100644 --- a/examples/rresamp_crcf_example.c +++ b/examples/rresamp_crcf_example.c @@ -1,10 +1,5 @@ -// -// rresamp_crcf_example.c -// // Demonstration of rresamp object whereby an input signal -// is resampled at a rational rate Q/P. -// - +// is resampled at a rational rate P/Q = interp/decim. #include #include #include @@ -19,10 +14,10 @@ void usage() { printf("Usage: %s [OPTION]\n", __FILE__); - printf("Resample a signal at a rate P/Q\n"); + printf("Resample a signal at a rate interp/decim\n"); printf(" -h : print help\n"); - printf(" -P : decimation (output) rate, default: 3\n"); - printf(" -Q : interpolation (input) rate, default: 5\n"); + printf(" -P : interpolation rate, default: 5\n"); + printf(" -Q : decimation rate, default: 3\n"); printf(" -m : filter semi-length (delay), default: 12\n"); printf(" -w : filter bandwidth, default: 0.5f\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); @@ -31,46 +26,46 @@ void usage() int main(int argc, char*argv[]) { // options - unsigned int P = 3; // output rate (interpolation factor) - unsigned int Q = 5; // input rate (decimation factor) - unsigned int m = 12; // resampling filter semi-length (filter delay) - float bw = 0.5f; // resampling filter bandwidth - float As = 60.0f; // resampling filter stop-band attenuation [dB] + unsigned int interp = 3; // output rate (interpolation factor) + unsigned int decim = 5; // input rate (decimation factor) + unsigned int m = 12; // resampling filter semi-length (filter delay) + float bw = 0.5f; // resampling filter bandwidth + float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hP:Q:m:s:w:")) != EOF) { switch (dopt) { - case 'h': usage(); return 0; - case 'P': P = atoi(optarg); break; - case 'Q': Q = atoi(optarg); break; - case 'm': m = atoi(optarg); break; - case 'w': bw = atof(optarg); break; - case 's': As = atof(optarg); break; + case 'h': usage(); return 0; + case 'P': interp = atoi(optarg); break; + case 'Q': decim = atoi(optarg); break; + case 'm': m = atoi(optarg); break; + case 'w': bw = atof(optarg); break; + case 's': As = atof(optarg); break; default: exit(1); } } // validate input - if (P == 0 || P > 1000) { - fprintf(stderr,"error: %s, input rate P must be in [1,1000]\n", argv[0]); + if (interp == 0 || interp > 1000) { + fprintf(stderr,"error: %s, interpolation rate must be in [1,1000]\n", argv[0]); exit(1); - } else if (Q == 0 || Q > 1000) { - fprintf(stderr,"error: %s, output rate Q must be in [1,1000]\n", argv[0]); + } else if (decim == 0 || decim > 1000) { + fprintf(stderr,"error: %s, decimation rate must be in [1,1000]\n", argv[0]); exit(1); } // create resampler object - rresamp_crcf q = rresamp_crcf_create_kaiser(P,Q,m,bw,As); + rresamp_crcf q = rresamp_crcf_create_kaiser(interp,decim,m,bw,As); rresamp_crcf_print(q); float rate = rresamp_crcf_get_rate(q); // number of sample blocks (limit by large interp/decim rates) - unsigned int n = 120e3 / (P > Q ? P : Q); + unsigned int n = 120e3 / (interp > decim ? interp : decim); // input/output buffers - float complex buf_x[Q]; // input - float complex buf_y[P]; // output + float complex buf_x[decim]; // input + float complex buf_y[interp]; // output // create signal generator (wide-band noise) msourcecf gen = msourcecf_create_default(); @@ -84,15 +79,15 @@ int main(int argc, char*argv[]) // generate input signal (filtered noise) unsigned int i; for (i=0; i Date: Thu, 7 Mar 2024 09:48:38 -0500 Subject: [PATCH 230/334] rresamp: allowing for a default bandwidth of -1 * this sets the critical bandwidth depending upon interpolation or decimation * for interpolation the critical bandwidth is 0.5 * for decimation the critical bandwidth is 0.5*interp/decim --- examples/rresamp_crcf_example.c | 17 ++++++++++------- include/liquid.h | 6 ++++-- src/filter/src/rresamp.proto.c | 8 +++++++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/examples/rresamp_crcf_example.c b/examples/rresamp_crcf_example.c index 430b3e42b..c27944b38 100644 --- a/examples/rresamp_crcf_example.c +++ b/examples/rresamp_crcf_example.c @@ -19,7 +19,7 @@ void usage() printf(" -P : interpolation rate, default: 5\n"); printf(" -Q : decimation rate, default: 3\n"); printf(" -m : filter semi-length (delay), default: 12\n"); - printf(" -w : filter bandwidth, default: 0.5f\n"); + printf(" -w : filter bandwidth, default: -1\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); } @@ -28,8 +28,8 @@ int main(int argc, char*argv[]) // options unsigned int interp = 3; // output rate (interpolation factor) unsigned int decim = 5; // input rate (decimation factor) - unsigned int m = 12; // resampling filter semi-length (filter delay) - float bw = 0.5f; // resampling filter bandwidth + unsigned int m = 20; // resampling filter semi-length (filter delay) + float bw = -1.0f; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; @@ -57,6 +57,7 @@ int main(int argc, char*argv[]) // create resampler object rresamp_crcf q = rresamp_crcf_create_kaiser(interp,decim,m,bw,As); + if (q == NULL) return -1; rresamp_crcf_print(q); float rate = rresamp_crcf_get_rate(q); @@ -64,12 +65,14 @@ int main(int argc, char*argv[]) unsigned int n = 120e3 / (interp > decim ? interp : decim); // input/output buffers - float complex buf_x[decim]; // input + float complex buf_x[decim ]; // input float complex buf_y[interp]; // output - // create signal generator (wide-band noise) + // create signal generator (wide-band noise and tone) + float noise_bw = 0.7f * (rate > 1.0 ? 1.0 : rate); msourcecf gen = msourcecf_create_default(); - msourcecf_add_noise(gen, 0.0f, 0.7f * (rate > 1.0 ? 1.0 : rate), 0); + msourcecf_add_noise(gen, 0.0f, noise_bw, 0); + msourcecf_add_tone (gen, rate > 1.0 ? 0.4 : noise_bw, 0.00f, 20); // create spectral periodogram objects unsigned int nfft = 2400; @@ -123,7 +126,7 @@ int main(int argc, char*argv[]) fprintf(fid,"figure('Color','white','position',[500 500 800 600]);\n"); fprintf(fid,"plot(fx,X,'-','LineWidth',2,'Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," fy,Y,'-','LineWidth',2,'Color',[0.5 0 0], 'MarkerSize',1);\n"); - fprintf(fid,"legend('original','resampled','location','northeast');"); + fprintf(fid,"legend('original','resampled','location','northwest');"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('Power Spectral Density [dB]');\n"); fprintf(fid,"fmin = min(fx( 1),fy( 1));\n"); diff --git a/include/liquid.h b/include/liquid.h index f69e79f53..a5142244d 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -4367,7 +4367,9 @@ RRESAMP() RRESAMP(_create)(unsigned int _interp, \ /* the resampler is configured as an interpolator a value of */ \ /* 0.5 (critically filtered) or less is recommended. */ \ /* When the resampler is configured as a decimator, the */ \ -/* critical sampling rate is 0.5*_interp/_decim, */ \ +/* critical bandwidth is 0.5*_interp/_decim. */ \ +/* When _bw < 0, the object will use the appropriate */ \ +/* critical bandwidth (interpolation or decimation), */ \ /* 0 < _bw <= 0.5 */ \ /* _as : filter stop-band attenuation [dB], 0 < _as */ \ RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, \ diff --git a/src/filter/src/rresamp.proto.c b/src/filter/src/rresamp.proto.c index 15035a7c3..c55c4710e 100644 --- a/src/filter/src/rresamp.proto.c +++ b/src/filter/src/rresamp.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -96,6 +96,12 @@ RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, _interp /= gcd; _decim /= gcd; + // check for critical bandwidth + if (_bw < 0) + _bw = _interp > _decim ? 0.5f : 0.5f * (float)_interp / (float)_decim; + else if (_bw > 0.5f) + return liquid_error_config("rresamp_%s_create_kaiser(), invalid bandwidth (%g), must be less than 0.5", EXTENSION_FULL, _bw); + // design filter unsigned int h_len = 2*_interp*_m + 1; float * hf = (float*) malloc(h_len*sizeof(float)); From beeec3028deaece64ed4510155e03c3862d9830f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 11:02:42 -0500 Subject: [PATCH 231/334] rresamp/autotest: logging unique output files --- src/filter/tests/rresamp_crcf_autotest.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/filter/tests/rresamp_crcf_autotest.c b/src/filter/tests/rresamp_crcf_autotest.c index 34434aebb..2b1db4430 100644 --- a/src/filter/tests/rresamp_crcf_autotest.c +++ b/src/filter/tests/rresamp_crcf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,8 +28,8 @@ #define max(a,b) ((a)>(b)?(a):(b)) // test rational-rate resampler -void test_harness_rresamp_crcf(unsigned int _P, - unsigned int _Q, +void test_harness_rresamp_crcf(unsigned int _interp, + unsigned int _decim, unsigned int _m, float _bw, float _as) @@ -41,7 +41,7 @@ void test_harness_rresamp_crcf(unsigned int _P, float tol = 0.5f; // create resampler with rate P/Q - rresamp_crcf resamp = rresamp_crcf_create_kaiser(_P, _Q, _m, _bw, _as); + rresamp_crcf resamp = rresamp_crcf_create_kaiser(_interp, _decim, _m, _bw, _as); float r = rresamp_crcf_get_rate(resamp); // create and configure objects @@ -50,17 +50,17 @@ void test_harness_rresamp_crcf(unsigned int _P, symstreamrcf_set_gain(gen, sqrtf(bw*r)); // generate samples and push through spgram object - float complex buf_0[_Q]; // input buffer - float complex buf_1[_P]; // output buffer + float complex buf_0[_decim]; // input buffer + float complex buf_1[_interp]; // output buffer while (spgramcf_get_num_samples_total(q) < n) { // generate block of samples - symstreamrcf_write_samples(gen, buf_0, _Q); + symstreamrcf_write_samples(gen, buf_0, _decim); // resample rresamp_crcf_execute(resamp, buf_0, buf_1); // run samples through the spgram object - spgramcf_write(q, buf_1, _P); + spgramcf_write(q, buf_1, _interp); } // verify result @@ -71,8 +71,10 @@ void test_harness_rresamp_crcf(unsigned int _P, {.fmin=-0.4f*bw, .fmax=+0.4f*bw, .pmin=0-tol, .pmax= 0 +tol, .test_lo=1, .test_hi=1}, {.fmin=+0.6f*bw, .fmax=+0.5f, .pmin=0, .pmax=-_as+tol, .test_lo=0, .test_hi=1}, }; + char filename[256]; + sprintf(filename,"autotest/logs/rresamp_crcf_P%u_Q%u.m", _interp, _decim); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, - liquid_autotest_verbose ? "autotest/logs/rresamp_crcf.m" : NULL); + liquid_autotest_verbose ? filename : NULL); // destroy objects rresamp_crcf_destroy(resamp); From 8a1e939275c1bf54174ae2d38d974ffe3937b6fb Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 11:45:01 -0500 Subject: [PATCH 232/334] rresamp/autotest: running more extensive tests with create options --- include/liquid.h | 5 ++ src/filter/src/rresamp.proto.c | 6 +- src/filter/tests/rresamp_crcf_autotest.c | 73 ++++++++++++++++-------- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index a5142244d..1c68d29af 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4383,6 +4383,11 @@ RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, \ /* Note that because the filter coefficients are computed internally */ \ /* here, the greatest common divisor (gcd) from _interp and _decim is */ \ /* internally removed to improve speed. */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ +/* _interp : interpolation factor, _interp > 0 */ \ +/* _decim : decimation factor, _decim > 0 */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ RRESAMP() RRESAMP(_create_prototype)(int _type, \ unsigned int _interp, \ unsigned int _decim, \ diff --git a/src/filter/src/rresamp.proto.c b/src/filter/src/rresamp.proto.c index c55c4710e..2fc6177b3 100644 --- a/src/filter/src/rresamp.proto.c +++ b/src/filter/src/rresamp.proto.c @@ -153,9 +153,9 @@ RRESAMP() RRESAMP(_create_prototype)(int _type, RRESAMP() q = RRESAMP(_create)(_interp, _decim, _m, h); q->block_len = gcd; - // adjust gain for decimator - if (decim) - RRESAMP(_set_scale)(q, (float)(q->P)/(float)(q->Q)); + // adjust gain according to resampling rate + float rate = RRESAMP(_get_rate)(q); + RRESAMP(_set_scale)(q, decim ? sqrtf(rate) : 1.0f / sqrtf(rate)); // free allocated memory and return object free(hf); diff --git a/src/filter/tests/rresamp_crcf_autotest.c b/src/filter/tests/rresamp_crcf_autotest.c index 2b1db4430..6d6b2fdbf 100644 --- a/src/filter/tests/rresamp_crcf_autotest.c +++ b/src/filter/tests/rresamp_crcf_autotest.c @@ -20,28 +20,41 @@ * THE SOFTWARE. */ +#include #include "autotest/autotest.h" #include "liquid.h" -// convenience methods -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) - // test rational-rate resampler -void test_harness_rresamp_crcf(unsigned int _interp, - unsigned int _decim, - unsigned int _m, - float _bw, - float _as) +void test_rresamp_crcf(const char * _method, + unsigned int _interp, + unsigned int _decim, + unsigned int _m, + float _bw, + float _as) { // options - unsigned int n=800000; // number of output samples to analyze - float bw = 0.2f; // target output bandwidth - unsigned int nfft = 800; - float tol = 0.5f; + unsigned int n = 800000; // number of output samples to analyze + float bw = 0.2f; // target output bandwidth + unsigned int nfft = 800; // number of bins in transform + float tol = 0.5f; // error tolerance [dB] + + // create resampler with rate _interp/_decim + rresamp_crcf resamp = NULL; + if (strcmp(_method,"baseline")==0) { + resamp = rresamp_crcf_create_kaiser(_interp, _decim, _m, _bw, _as); + } else if (strcmp(_method,"default")==0) { + resamp = rresamp_crcf_create_default(_interp, _decim); + } else { + printf("creating resampler using %s\n", _method); + int ftype = liquid_getopt_str2firfilt(_method); + float beta = _bw; // rename to avoid confusion + resamp = rresamp_crcf_create_prototype(ftype, _interp, _decim, _m, beta); + } - // create resampler with rate P/Q - rresamp_crcf resamp = rresamp_crcf_create_kaiser(_interp, _decim, _m, _bw, _as); + if (resamp == NULL) { + liquid_autotest_failed(); + return; + } float r = rresamp_crcf_get_rate(resamp); // create and configure objects @@ -72,7 +85,7 @@ void test_harness_rresamp_crcf(unsigned int _interp, {.fmin=+0.6f*bw, .fmax=+0.5f, .pmin=0, .pmax=-_as+tol, .test_lo=0, .test_hi=1}, }; char filename[256]; - sprintf(filename,"autotest/logs/rresamp_crcf_P%u_Q%u.m", _interp, _decim); + sprintf(filename,"autotest/logs/rresamp_crcf_%s_P%u_Q%u.m", _method, _interp, _decim); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, liquid_autotest_verbose ? filename : NULL); @@ -82,13 +95,27 @@ void test_harness_rresamp_crcf(unsigned int _interp, symstreamrcf_destroy(gen); } -// actual tests -void autotest_rresamp_crcf_P1_Q5() { test_harness_rresamp_crcf( 1, 5, 15, 0.4f, 60.0f); } -void autotest_rresamp_crcf_P2_Q5() { test_harness_rresamp_crcf( 2, 5, 15, 0.4f, 60.0f); } -void autotest_rresamp_crcf_P3_Q5() { test_harness_rresamp_crcf( 3, 5, 15, 0.4f, 60.0f); } -void autotest_rresamp_crcf_P6_Q5() { test_harness_rresamp_crcf( 6, 5, 15, 0.4f, 60.0f); } -void autotest_rresamp_crcf_P8_Q5() { test_harness_rresamp_crcf( 8, 5, 15, 0.4f, 60.0f); } -void autotest_rresamp_crcf_P9_Q5() { test_harness_rresamp_crcf( 9, 5, 15, 0.4f, 60.0f); } +// baseline tests using create_kaiser() method +void autotest_rresamp_crcf_baseline_P1_Q5() { test_rresamp_crcf("baseline", 1, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_baseline_P2_Q5() { test_rresamp_crcf("baseline", 2, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_baseline_P3_Q5() { test_rresamp_crcf("baseline", 3, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_baseline_P6_Q5() { test_rresamp_crcf("baseline", 6, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_baseline_P8_Q5() { test_rresamp_crcf("baseline", 8, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_baseline_P9_Q5() { test_rresamp_crcf("baseline", 9, 5, 15, -1, 60.0f); } + +// tests using create_default() method +void autotest_rresamp_crcf_default_P1_Q5() { test_rresamp_crcf("default", 1, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_default_P2_Q5() { test_rresamp_crcf("default", 2, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_default_P3_Q5() { test_rresamp_crcf("default", 3, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_default_P6_Q5() { test_rresamp_crcf("default", 6, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_default_P8_Q5() { test_rresamp_crcf("default", 8, 5, 15, -1, 60.0f); } +void autotest_rresamp_crcf_default_P9_Q5() { test_rresamp_crcf("default", 9, 5, 15, -1, 60.0f); } + +// tests using create_prototype() method +void autotest_rresamp_crcf_arkaiser_P3_Q5() { test_rresamp_crcf("arkaiser", 3, 5, 40, 0.2, 50.0f); } +void autotest_rresamp_crcf_arkaiser_P5_Q3() { test_rresamp_crcf("arkaiser", 5, 3, 40, 0.2, 50.0f); } +void autotest_rresamp_crcf_rrcos_P3_Q5() { test_rresamp_crcf("rrcos", 3, 5, 40, 0.2, 50.0f); } +void autotest_rresamp_crcf_rrcos_P5_Q3() { test_rresamp_crcf("rrcos", 5, 3, 40, 0.2, 50.0f); } // test copy method void autotest_rresamp_copy() From 4bbea205c280b747a00f7cc9715887b40985c1d2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 11:59:54 -0500 Subject: [PATCH 233/334] rresamp/autotest: testing configurations --- src/filter/tests/rresamp_crcf_autotest.c | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/filter/tests/rresamp_crcf_autotest.c b/src/filter/tests/rresamp_crcf_autotest.c index 6d6b2fdbf..cdf996451 100644 --- a/src/filter/tests/rresamp_crcf_autotest.c +++ b/src/filter/tests/rresamp_crcf_autotest.c @@ -162,3 +162,35 @@ void autotest_rresamp_copy() symstreamrcf_destroy(gen); } +// test errors and invalid configuration +void autotest_rresamp_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping rresamp config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + CONTEND_ISNULL( rresamp_crcf_copy(NULL) ); + // test creating invalid objects + + // create valid object + rresamp_crcf resamp = rresamp_crcf_create_kaiser(30, 50, 20, 0.3f, 60.0f); + CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_print(resamp) ); + CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_set_scale(resamp, 7.22f) ); + float scale; + CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_get_scale(resamp, &scale) ); + CONTEND_EQUALITY( scale, 7.22f ); + + // get properties + CONTEND_EQUALITY( 20, rresamp_crcf_get_delay (resamp) ); + CONTEND_EQUALITY( 10, rresamp_crcf_get_block_len(resamp) ); + CONTEND_EQUALITY( 0.6f, rresamp_crcf_get_rate (resamp) ); + CONTEND_EQUALITY( 30, rresamp_crcf_get_P (resamp) ); + CONTEND_EQUALITY( 3, rresamp_crcf_get_interp (resamp) ); + CONTEND_EQUALITY( 50, rresamp_crcf_get_Q (resamp) ); + CONTEND_EQUALITY( 5, rresamp_crcf_get_decim (resamp) ); + rresamp_crcf_destroy(resamp); +} + From b63b40ebb4e0272e445ef37eba8b1e1b7ef5c746 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 13:42:01 -0500 Subject: [PATCH 234/334] rresamp/autotest: checking for invalid configurations --- src/filter/tests/rresamp_crcf_autotest.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/filter/tests/rresamp_crcf_autotest.c b/src/filter/tests/rresamp_crcf_autotest.c index cdf996451..9e7299060 100644 --- a/src/filter/tests/rresamp_crcf_autotest.c +++ b/src/filter/tests/rresamp_crcf_autotest.c @@ -172,8 +172,12 @@ void autotest_rresamp_config() #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif + // test copying/creating invalid objects CONTEND_ISNULL( rresamp_crcf_copy(NULL) ); - // test creating invalid objects + CONTEND_ISNULL( rresamp_crcf_create(0, 5, 20, NULL) ); // interp is 0 + CONTEND_ISNULL( rresamp_crcf_create(3, 0, 20, NULL) ); // decim is 0 + CONTEND_ISNULL( rresamp_crcf_create(3, 5, 0, NULL) ); // filter length is 0 + CONTEND_ISNULL( rresamp_crcf_create_kaiser(3,5,20,99.0f,60) ); // bandwidth > 0.5 // create valid object rresamp_crcf resamp = rresamp_crcf_create_kaiser(30, 50, 20, 0.3f, 60.0f); From f6e99c22caadaf6c484d546bffcfb565caa356c8 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 14:12:52 -0500 Subject: [PATCH 235/334] iirfilt: adding method for setting/getting scale --- include/liquid.h | 10 +++++++++ src/filter/src/iirfilt.proto.c | 38 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 1c68d29af..f5f2ab0ae 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -3437,6 +3437,16 @@ int IIRFILT(_print)(IIRFILT() _q); \ /* Reset iirfilt object internals */ \ int IIRFILT(_reset)(IIRFILT() _q); \ \ +/* Set output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +int IIRFILT(_set_scale)(IIRFILT() _q, TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor applied to each output sample */ \ +int IIRFILT(_get_scale)(IIRFILT() _q, TC * _scale); \ + \ /* Compute filter output given a single input sample */ \ /* _q : iirfilt object */ \ /* _x : input sample */ \ diff --git a/src/filter/src/iirfilt.proto.c b/src/filter/src/iirfilt.proto.c index 34d4ca44c..8e858286b 100644 --- a/src/filter/src/iirfilt.proto.c +++ b/src/filter/src/iirfilt.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,6 +69,8 @@ struct IIRFILT(_s) { // second-order sections IIRFILTSOS() * qsos; // second-order sections filters unsigned int nsos; // number of second-order sections + + TC scale; // output scaling factor }; // initialize internal objects/arrays @@ -143,7 +145,8 @@ IIRFILT() IIRFILT(_create)(TC * _b, // reset internal state IIRFILT(_reset)(q); - // return iirfilt object + // set scale and return + IIRFILT(_set_scale)(q, 1); return q; } @@ -191,6 +194,9 @@ IIRFILT() IIRFILT(_create_sos)(TC * _B, q->qsos[i] = IIRFILTSOS(_create)(bt,at); //q->qsos[i] = IIRFILT(_create)(q->b+3*i,3,q->a+3*i,3); } + + // set scale and return + IIRFILT(_set_scale)(q, 1); return q; } @@ -257,9 +263,7 @@ IIRFILT() IIRFILT(_create_prototype)(liquid_iirdes_filtertype _ftype, // create simplified low-pass Butterworth IIR filter // _n : filter order // _fc : low-pass prototype cut-off frequency -IIRFILT() IIRFILT(_create_lowpass)( - unsigned int _order, - float _fc) +IIRFILT() IIRFILT(_create_lowpass)(unsigned int _order, float _fc) { return IIRFILT(_create_prototype)(LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_LOWPASS, @@ -542,6 +546,20 @@ int IIRFILT(_reset)(IIRFILT() _q) return LIQUID_OK; } +// set scale value to be applied to each output sample +int IIRFILT(_set_scale)(IIRFILT() _q, TC _scale) +{ + _q->scale = _scale; + return LIQUID_OK; +} + +// get output scaling for filter +int IIRFILT(_get_scale)(IIRFILT() _q, TC * _scale) +{ + *_scale = _q->scale; + return LIQUID_OK; +} + // execute normal iir filter using traditional numerator/denominator // form (not second-order sections form) // _q : iirfilt object @@ -581,6 +599,8 @@ int IIRFILT(_execute_norm)(IIRFILT() _q, // set return value *_y = y0; #endif + // apply scaling + *_y *= _q->scale; return LIQUID_OK; } @@ -602,7 +622,7 @@ int IIRFILT(_execute_sos)(IIRFILT() _q, // output for filter n becomes input to filter n+1 t0 = t1; } - *_y = t1; + *_y = t1 * _q->scale; return LIQUID_OK; } @@ -653,8 +673,8 @@ unsigned int IIRFILT(_get_length)(IIRFILT() _q) // _fc : frequency // _H : output frequency response int IIRFILT(_freqresponse)(IIRFILT() _q, - float _fc, - float complex * _H) + float _fc, + float complex * _H) { unsigned int i; float complex H = 0.0f; @@ -692,7 +712,7 @@ int IIRFILT(_freqresponse)(IIRFILT() _q, } // set return value - *_H = H; + *_H = H * _q->scale; return LIQUID_OK; } From acd8fe5ae4d20a073f008a1acb201562ca6bd4f6 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 14:25:50 -0500 Subject: [PATCH 236/334] iirinterp: using cheby2 default filter, scaling output --- src/filter/src/iirinterp.proto.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/filter/src/iirinterp.proto.c b/src/filter/src/iirinterp.proto.c index 54345057a..d60b56552 100644 --- a/src/filter/src/iirinterp.proto.c +++ b/src/filter/src/iirinterp.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -70,7 +70,7 @@ IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, unsigned int _order) { return IIRINTERP(_create_prototype)(_M, - LIQUID_IIRDES_BUTTER, + LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, _order, @@ -101,7 +101,11 @@ IIRINTERP() IIRINTERP(_create_prototype)(unsigned int _M, q->M = _M; // create filter - q->iirfilt = IIRFILT(_create_prototype)(_ftype, _btype, _format, _order, _fc, _f0, _ap, _as); + q->iirfilt = IIRFILT(_create_prototype)(_ftype, _btype, _format, + _order, _fc, _f0, _ap, _as); + + // set appropriate scale + IIRFILT(_set_scale)(q->iirfilt, q->M); // return interpolator object return q; From a51fc116fc5d29a5e3e55ffe6a4017300c8c4b5d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 14:26:07 -0500 Subject: [PATCH 237/334] iirinterp/autotest: adding appropriate tests --- examples/iirinterp_crcf_example.c | 11 +--- src/filter/tests/iirinterp_autotest.c | 77 +++++++++++++++++++++------ 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/examples/iirinterp_crcf_example.c b/examples/iirinterp_crcf_example.c index ac6248f67..231dc5f4c 100644 --- a/examples/iirinterp_crcf_example.c +++ b/examples/iirinterp_crcf_example.c @@ -1,10 +1,5 @@ -// -// iirinterp_crcf_example.c -// // This example demonstrates the iirinterp object (IIR interpolator) // interface. -// - #include #include #include @@ -23,7 +18,6 @@ void usage() printf(" n : number of input samples, default: 64\n"); } - int main(int argc, char*argv[]) { // options unsigned int k = 4; // interpolation factor @@ -75,10 +69,7 @@ int main(int argc, char*argv[]) { // destroy interpolator object iirinterp_crcf_destroy(q); - - // // export output file - // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); @@ -93,7 +84,7 @@ int main(int argc, char*argv[]) { fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); for (i=0; i Date: Thu, 7 Mar 2024 14:36:49 -0500 Subject: [PATCH 238/334] iirfilt/autotest: adding configuration testing --- src/filter/tests/iirfilt_copy_autotest.c | 33 +++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/filter/tests/iirfilt_copy_autotest.c b/src/filter/tests/iirfilt_copy_autotest.c index 16098526e..c195c601c 100644 --- a/src/filter/tests/iirfilt_copy_autotest.c +++ b/src/filter/tests/iirfilt_copy_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,3 +59,34 @@ void testbench_iirfilt_copy(liquid_iirdes_format _format) void autotest_iirfilt_copy_tf () { testbench_iirfilt_copy(LIQUID_IIRDES_TF ); } void autotest_iirfilt_copy_sos() { testbench_iirfilt_copy(LIQUID_IIRDES_SOS); } +// test errors and invalid configuration +void autotest_iirfilt_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping iirfilt config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + CONTEND_ISNULL( iirfilt_crcf_copy(NULL) ); + CONTEND_ISNULL( iirfilt_crcf_create(NULL, 0, NULL, 5) ); // nb is 0 + CONTEND_ISNULL( iirfilt_crcf_create(NULL, 5, NULL, 0) ); // nb is 0 + CONTEND_ISNULL( iirfilt_crcf_create_sos(NULL, NULL, 0) ); // nsos is 0 + + // create valid object + iirfilt_crcf filter = iirfilt_crcf_create_lowpass(7, 0.1f); + CONTEND_EQUALITY( LIQUID_OK, iirfilt_crcf_print(filter) ); + + // check properties + CONTEND_EQUALITY( LIQUID_OK, iirfilt_crcf_set_scale(filter, 7.22f) ); + float scale; + CONTEND_EQUALITY( LIQUID_OK, iirfilt_crcf_get_scale(filter, &scale) ); + CONTEND_EQUALITY( scale, 7.22f ); + CONTEND_EQUALITY( 7+1, iirfilt_crcf_get_length(filter) ); + + // destroy object + iirfilt_crcf_destroy(filter); +} + From 1b85695a5f4542cc290c8e98f58a5770db4b9b39 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 15:33:08 -0500 Subject: [PATCH 239/334] iirfilt: scaling dc-blocking filter, adding autotest --- src/filter/src/iirfilt.proto.c | 6 +++- src/filter/tests/iirfilt_copy_autotest.c | 45 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/filter/src/iirfilt.proto.c b/src/filter/src/iirfilt.proto.c index 8e858286b..6143e6edb 100644 --- a/src/filter/src/iirfilt.proto.c +++ b/src/filter/src/iirfilt.proto.c @@ -391,7 +391,11 @@ IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha) // convert to type-specific array TC b[2] = {(TC)bf[0], (TC)bf[1]}; TC a[2] = {(TC)af[0], (TC)af[1]}; - return IIRFILT(_create)(b,2,a,2); + IIRFILT() q = IIRFILT(_create)(b,2,a,2); + + // adjust scale so maintain consistent gain across the band + IIRFILT(_set_scale)(q, sqrt(1-_alpha)); + return q; } // create phase-locked loop iirfilt object diff --git a/src/filter/tests/iirfilt_copy_autotest.c b/src/filter/tests/iirfilt_copy_autotest.c index c195c601c..65b36ed9c 100644 --- a/src/filter/tests/iirfilt_copy_autotest.c +++ b/src/filter/tests/iirfilt_copy_autotest.c @@ -23,6 +23,51 @@ #include "autotest/autotest.h" #include "liquid.internal.h" +// +void autotest_iirfilt_dcblock() +{ + // options + unsigned int n = 400000; // number of output samples to analyze + float alpha= 0.2f; // forgetting factor + unsigned int nfft = 1200; // number of bins in transform + float tol = 0.7f; // error tolerance [dB] + + // create base object + iirfilt_crcf filter = iirfilt_crcf_create_dc_blocker(alpha); + + // create and configure objects + spgramcf q = spgramcf_create(nfft, LIQUID_WINDOW_HANN, nfft/2, nfft/4); + + // start running input through filter + float complex x, y; + unsigned int i; + for (i=0; i Date: Thu, 7 Mar 2024 17:06:59 -0500 Subject: [PATCH 240/334] iirfilt: adding integrator example --- examples/iirfilt_rrrf_integrator_example.c | 72 ++++++++++++++++++++++ makefile.in | 1 + 2 files changed, 73 insertions(+) create mode 100644 examples/iirfilt_rrrf_integrator_example.c diff --git a/examples/iirfilt_rrrf_integrator_example.c b/examples/iirfilt_rrrf_integrator_example.c new file mode 100644 index 000000000..97077400f --- /dev/null +++ b/examples/iirfilt_rrrf_integrator_example.c @@ -0,0 +1,72 @@ +// This example demonstrates how to create an integrating recursive +// (infinite impulse response) filter. +#include +#include + +#include "liquid.h" + +#define OUTPUT_FILENAME "iirfilt_rrrf_integrator_example.m" + +int main() { + // options + unsigned int num_samples = 1200; // number of samples + + // allocate memory for data arrays + float buf_0[num_samples]; // filter input + float buf_1[num_samples]; // filter output + + // generate input signal + unsigned int i; + for (i=0; i 0.1*num_samples && i < 0.6*num_samples ? 1 : 0) + 0.1*randnf(); + + // design filter from prototype + iirfilt_rrrf q = iirfilt_rrrf_create_integrator(); + iirfilt_rrrf_print(q); + + // run filter + iirfilt_rrrf_execute_block(q, buf_0, num_samples, buf_1); + + // destroy filter object + iirfilt_rrrf_destroy(q); + + // plot results to output file + FILE * fid = fopen(OUTPUT_FILENAME,"w"); + fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all;\n"); + fprintf(fid,"close all;\n"); + fprintf(fid,"\n"); + fprintf(fid,"num_samples=%u;\n",num_samples); + fprintf(fid,"x=zeros(1,num_samples);\n"); + fprintf(fid,"y=zeros(1,num_samples);\n"); + + // save input, output arrays + for (i=0; i Date: Thu, 7 Mar 2024 17:30:41 -0500 Subject: [PATCH 241/334] iirdes/zpk2sosf: handling case where gain is negative (e.g. integrator) --- examples/iirfilt_rrrf_integrator_example.c | 4 +-- src/filter/src/iirdes.c | 32 +++++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/examples/iirfilt_rrrf_integrator_example.c b/examples/iirfilt_rrrf_integrator_example.c index 97077400f..be3b3a220 100644 --- a/examples/iirfilt_rrrf_integrator_example.c +++ b/examples/iirfilt_rrrf_integrator_example.c @@ -18,7 +18,7 @@ int main() { // generate input signal unsigned int i; for (i=0; i 0.1*num_samples && i < 0.6*num_samples ? 1 : 0) + 0.1*randnf(); + buf_0[i] = (i > 200 && i < 800 ? 1 : 0) + 0.1*randnf(); // design filter from prototype iirfilt_rrrf q = iirfilt_rrrf_create_integrator(); @@ -59,7 +59,7 @@ int main() { fprintf(fid," plot(t,y,'-','Color',[0 0.5 0.2],'LineWidth',2);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('input with DC offset');\n"); - fprintf(fid," axis([0 num_samples -3 3]);\n"); + fprintf(fid," axis([0 num_samples -3 650]);\n"); fprintf(fid," grid on;\n"); // close output file diff --git a/src/filter/src/iirdes.c b/src/filter/src/iirdes.c index dc17310ad..021334a83 100644 --- a/src/filter/src/iirdes.c +++ b/src/filter/src/iirdes.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -470,6 +470,10 @@ int iirdes_dzpk2sosf(float complex * _zd, z0 = -zp[2*i+0]; z1 = -zp[2*i+1]; +#if LIQUID_IIRDES_DEBUG_PRINT + printf("[%3u] z0 = %12.8f + j%12.8f, z1 = %12.8f + j%12.8f\n", + i, crealf(z0), cimagf(z0), crealf(z1), cimagf(z1)); +#endif // expand complex pole pairs _a[3*i+0] = 1.0; @@ -497,16 +501,30 @@ int iirdes_dzpk2sosf(float complex * _zd, _b[3*i+2] = 0.0; } - // distribute gain equally amongst all feed-forward - // coefficients - float k = powf( crealf(_kd), 1.0f/(float)(L+r) ); + // distribute gain equally amongst all feed-forward coefficients + float k = crealf(_kd); + float sgn = k < 0 ? -1 : 1; + float g = powf( k*sgn, 1.0f/(float)(L+r) ); // adjust gain of first element for (i=0; i Date: Thu, 7 Mar 2024 17:51:45 -0500 Subject: [PATCH 242/334] iirfilt: adjusting integrator gain, adding test --- src/filter/src/iirfilt.proto.c | 4 ++-- src/filter/tests/iirfilt_copy_autotest.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/filter/src/iirfilt.proto.c b/src/filter/src/iirfilt.proto.c index 6143e6edb..a74e3056c 100644 --- a/src/filter/src/iirfilt.proto.c +++ b/src/filter/src/iirfilt.proto.c @@ -301,8 +301,8 @@ IIRFILT() IIRFILT(_create_integrator)() 0.1641457f * cexpf(_Complex_I * M_PI / 180.0f * -21.89539f), 0.1641457f * cexpf(_Complex_I * M_PI / 180.0f * 21.89539f), 1.0f,}; - // gain, digital, integrator - float complex kdi = -1.89213380759321e-05f; + // gain, digital, integrator (slight adjustment added for proper gain) + float complex kdi = -1.89213380759321e-05f / 0.9695401191711425781f; // second-order sections // allocate 12 values for 4 second-order sections each with diff --git a/src/filter/tests/iirfilt_copy_autotest.c b/src/filter/tests/iirfilt_copy_autotest.c index 65b36ed9c..c46e6a1a2 100644 --- a/src/filter/tests/iirfilt_copy_autotest.c +++ b/src/filter/tests/iirfilt_copy_autotest.c @@ -68,6 +68,30 @@ void autotest_iirfilt_dcblock() iirfilt_crcf_destroy(filter); } +void autotest_iirfilt_integrator() +{ + // options + unsigned int num_ones = 10; + unsigned int num_samples = 200; + + // allocate memory for data arrays + float buf_0[num_samples]; // filter input + float buf_1[num_samples]; // filter output + + // generate input signal + unsigned int i; + for (i=0; i Date: Thu, 7 Mar 2024 18:10:48 -0500 Subject: [PATCH 243/334] iirfilt/autotest: reducing number of samples in integrator test --- src/filter/tests/iirfilt_copy_autotest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filter/tests/iirfilt_copy_autotest.c b/src/filter/tests/iirfilt_copy_autotest.c index c46e6a1a2..a4e3d85d3 100644 --- a/src/filter/tests/iirfilt_copy_autotest.c +++ b/src/filter/tests/iirfilt_copy_autotest.c @@ -72,7 +72,7 @@ void autotest_iirfilt_integrator() { // options unsigned int num_ones = 10; - unsigned int num_samples = 200; + unsigned int num_samples = 40; // allocate memory for data arrays float buf_0[num_samples]; // filter input From 9b96a0e83a121ea1c74f84a0c9a2eb1003a57d32 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 18:18:21 -0500 Subject: [PATCH 244/334] iirfilt/autotest: adding test for differentiator --- makefile.in | 2 +- src/filter/src/iirfilt.proto.c | 4 +- ...ilt_copy_autotest.c => iirfilt_autotest.c} | 78 +++++++++++++------ 3 files changed, 56 insertions(+), 28 deletions(-) rename src/filter/tests/{iirfilt_copy_autotest.c => iirfilt_autotest.c} (86%) diff --git a/makefile.in b/makefile.in index cd8b6108a..f5526b8e4 100644 --- a/makefile.in +++ b/makefile.in @@ -523,8 +523,8 @@ filter_autotests := \ src/filter/tests/iirdecim_autotest.c \ src/filter/tests/iirdes_autotest.c \ src/filter/tests/iirdes_support_autotest.c \ + src/filter/tests/iirfilt_autotest.c \ src/filter/tests/iirfilt_xxxf_autotest.c \ - src/filter/tests/iirfilt_copy_autotest.c \ src/filter/tests/iirfiltsos_autotest.c \ src/filter/tests/iirhilb_autotest.c \ src/filter/tests/iirinterp_autotest.c \ diff --git a/src/filter/src/iirfilt.proto.c b/src/filter/src/iirfilt.proto.c index a74e3056c..c89cbfa82 100644 --- a/src/filter/src/iirfilt.proto.c +++ b/src/filter/src/iirfilt.proto.c @@ -350,8 +350,8 @@ IIRFILT() IIRFILT(_create_differentiator)() 0.1958670f * cexpf(_Complex_I * M_PI / 180.0f * -40.51510f), 0.1958670f * cexpf(_Complex_I * M_PI / 180.0f * 40.51510f), 0.1886088f,}; - // gain, digital, differentiator - float complex kdd = 2.09049284907492e-05f; + // gain, digital, differentiator (slight adjustment added for proper gain) + float complex kdd = 2.09049284907492e-05f / 1.033477783203125000f; // second-order sections // allocate 12 values for 4 second-order sections each with diff --git a/src/filter/tests/iirfilt_copy_autotest.c b/src/filter/tests/iirfilt_autotest.c similarity index 86% rename from src/filter/tests/iirfilt_copy_autotest.c rename to src/filter/tests/iirfilt_autotest.c index a4e3d85d3..20719fdab 100644 --- a/src/filter/tests/iirfilt_copy_autotest.c +++ b/src/filter/tests/iirfilt_autotest.c @@ -23,7 +23,59 @@ #include "autotest/autotest.h" #include "liquid.internal.h" -// +void autotest_iirfilt_integrator() +{ + // options + unsigned int num_ones = 10; + unsigned int num_samples = 40; + + // allocate memory for data arrays + float buf_0[num_samples]; // filter input + float buf_1[num_samples]; // filter output + + // generate input signal + unsigned int i; + for (i=0; i Date: Thu, 7 Mar 2024 20:40:37 -0500 Subject: [PATCH 245/334] autotest/psd: adding method to validate iirfilt object response --- autotest/autotest.c | 15 ++++ autotest/autotest.h | 4 + src/filter/tests/iirdes_autotest.c | 114 +++++++---------------------- 3 files changed, 44 insertions(+), 89 deletions(-) diff --git a/autotest/autotest.c b/autotest/autotest.c index 6d7a4ba35..78a62a529 100644 --- a/autotest/autotest.c +++ b/autotest/autotest.c @@ -347,3 +347,18 @@ int liquid_autotest_validate_psd_firfilt_cccf(firfilt_cccf _q, unsigned int _nff return liquid_autotest_validate_spectrum(psd,_nfft,_regions,num_regions,debug_filename); } +// validate spectral content of an iir filter (real coefficients, input) +int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nfft, + autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename) +{ + float psd[_nfft]; + unsigned int i; + for (i=0; i<_nfft; i++) { + float f = (float)(i)/(float)(_nfft) - 0.5f; + float complex H; + iirfilt_rrrf_freqresponse(_q, f, &H); + psd[i] = 20*log10f(cabsf(H)); + } + return liquid_autotest_validate_spectrum(psd,_nfft,_regions,num_regions,debug_filename); +} + diff --git a/autotest/autotest.h b/autotest/autotest.h index d6b7520ed..148a50311 100644 --- a/autotest/autotest.h +++ b/autotest/autotest.h @@ -312,5 +312,9 @@ int liquid_autotest_validate_psd_firfilt_crcf(firfilt_crcf _q, unsigned int _nff int liquid_autotest_validate_psd_firfilt_cccf(firfilt_cccf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); +// validate spectral content of an iir filter (real coefficients, input) +int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nfft, + autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); + #endif // __LIQUID_AUTOTEST_H__ diff --git a/src/filter/tests/iirdes_autotest.c b/src/filter/tests/iirdes_autotest.c index 4be64c56b..9dc4ff464 100644 --- a/src/filter/tests/iirdes_autotest.c +++ b/src/filter/tests/iirdes_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -85,31 +85,23 @@ void testbench_iirdes_ellip_lowpass(unsigned int _n, // filter order unsigned int nfft = 800; // number of points to evaluate // design filter from prototype - iirfilt_crcf q = iirfilt_crcf_create_prototype( + iirfilt_rrrf q = iirfilt_rrrf_create_prototype( LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, _n,_fc,0.0f,_ap,_as); - if (liquid_autotest_verbose) - iirfilt_crcf_print(q); // compute regions for testing float H0 = 0.0f, H1 = -_ap, H2 = -_as; - // compute response and compare to expected or mask - unsigned int i; - float H[nfft]; // filter response - for (i=0; i Date: Thu, 7 Mar 2024 20:50:02 -0500 Subject: [PATCH 246/334] iirfiltsos: extending tests for both forms --- src/filter/tests/iirfiltsos_autotest.c | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/filter/tests/iirfiltsos_autotest.c b/src/filter/tests/iirfiltsos_autotest.c index 6fe3efb38..e982cbd4e 100644 --- a/src/filter/tests/iirfiltsos_autotest.c +++ b/src/filter/tests/iirfiltsos_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,9 @@ void autotest_iirfiltsos_impulse_n2() 0.1952621458756350, 0.0976310729378175}; - iirfiltsos_rrrf f = iirfiltsos_rrrf_create(b,a); + // create identical objects + iirfiltsos_rrrf q0 = iirfiltsos_rrrf_create(b,a); + iirfiltsos_rrrf q1 = iirfiltsos_rrrf_create(b,a); // initialize oracle; expected output (generated with octave) float test[15] = { @@ -62,14 +64,20 @@ void autotest_iirfiltsos_impulse_n2() // hit filter with impulse, compare output for (i=0; i<15; i++) { + // generate input v = (i==0) ? 1.0f : 0.0f; - iirfiltsos_rrrf_execute(f, v, &y); + // run direct-form I + iirfiltsos_rrrf_execute_df1(q0, v, &y); + CONTEND_DELTA(test[i], y, tol); + // run direct-form II + iirfiltsos_rrrf_execute_df2(q1, v, &y); CONTEND_DELTA(test[i], y, tol); } - iirfiltsos_rrrf_destroy(f); + iirfiltsos_rrrf_destroy(q0); + iirfiltsos_rrrf_destroy(q1); } @@ -86,7 +94,9 @@ void autotest_iirfiltsos_step_n2() 0.1952621458756350, 0.0976310729378175}; - iirfiltsos_rrrf f = iirfiltsos_rrrf_create(b,a); + // create identical objects + iirfiltsos_rrrf q0 = iirfiltsos_rrrf_create(b,a); + iirfiltsos_rrrf q1 = iirfiltsos_rrrf_create(b,a); float test[15] = { 0.0976310729378175, @@ -111,12 +121,17 @@ void autotest_iirfiltsos_step_n2() // hit filter with step, compare output for (i=0; i<15; i++) { - iirfiltsos_rrrf_execute(f, 1.0f, &y); + // run direct-form I + iirfiltsos_rrrf_execute_df1(q0, 1, &y); + CONTEND_DELTA(test[i], y, tol); - CONTEND_DELTA(test[i], y, tol ); + // run direct-form II + iirfiltsos_rrrf_execute_df2(q1, 1, &y); + CONTEND_DELTA(test[i], y, tol); } - iirfiltsos_rrrf_destroy(f); + iirfiltsos_rrrf_destroy(q0); + iirfiltsos_rrrf_destroy(q1); } void autotest_iirfiltsos_copy() From ebfac5d8a108c16072bea9465a0db79fa43c3b2f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 20:53:00 -0500 Subject: [PATCH 247/334] iirfiltsos/autotest: adding configuration test --- src/filter/tests/iirfiltsos_autotest.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/filter/tests/iirfiltsos_autotest.c b/src/filter/tests/iirfiltsos_autotest.c index e982cbd4e..860bb75a1 100644 --- a/src/filter/tests/iirfiltsos_autotest.c +++ b/src/filter/tests/iirfiltsos_autotest.c @@ -169,3 +169,21 @@ void autotest_iirfiltsos_copy() iirfiltsos_crcf_destroy(q1); } +// test errors and invalid configuration +void autotest_iirfiltsos_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping iirfilt config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + CONTEND_ISNULL( iirfiltsos_crcf_copy(NULL) ); + + // create valid object and test configuration + //iirfiltsos_crcf filter = iirfiltsos_crcf_create(...); + //iirfiltsos_crcf_destroy(filter); +} + From 4fcf396576fc1417d185be35439f32c27c0e575e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 20:57:13 -0500 Subject: [PATCH 248/334] firdes/autotest: adding rkaiser configuration tests --- src/filter/tests/firdes_autotest.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index 5ddbf46d6..aec31dd82 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -236,6 +236,11 @@ void autotest_liquid_firdes_config() CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.0f, 0, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.6f, 0, h), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_rkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_kaiser(h_len, 0.2f, 60.0f, 0.0f, h), LIQUID_OK ); CONTEND_EQUALITY(liquid_firdes_kaiser( 0, 0.2f, 60.0f, 0.0f, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_kaiser(h_len,-0.1f, 60.0f, 0.0f, h), LIQUID_EICONFIG); From de1d738a4d34c5af72eb821b323733b1f21fabbf Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 20:57:50 -0500 Subject: [PATCH 249/334] firdes/autotest: adding arkaiser configuration tests --- src/filter/tests/firdes_autotest.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index aec31dd82..4fb7a9474 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -241,6 +241,11 @@ void autotest_liquid_firdes_config() CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_arkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_kaiser(h_len, 0.2f, 60.0f, 0.0f, h), LIQUID_OK ); CONTEND_EQUALITY(liquid_firdes_kaiser( 0, 0.2f, 60.0f, 0.0f, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_kaiser(h_len,-0.1f, 60.0f, 0.0f, h), LIQUID_EICONFIG); From e77b1a86fc011b6609ced6f4348ac51a4bbb39a2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Thu, 7 Mar 2024 21:03:58 -0500 Subject: [PATCH 250/334] symsync/autotest: adding basic config --- src/filter/tests/symsync_copy_autotest.c | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/filter/tests/symsync_copy_autotest.c b/src/filter/tests/symsync_copy_autotest.c index 849ff6e6f..5541d770a 100644 --- a/src/filter/tests/symsync_copy_autotest.c +++ b/src/filter/tests/symsync_copy_autotest.c @@ -67,3 +67,33 @@ void autotest_symsync_copy() symsync_crcf_destroy(q1); } +// test errors and invalid configuration +void autotest_symsync_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping symsync config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + CONTEND_ISNULL( symsync_crcf_copy(NULL) ); + + CONTEND_ISNULL( symsync_crcf_create(0, 12, NULL, 48) ); // k is too small + CONTEND_ISNULL( symsync_crcf_create(2, 0, NULL, 48) ); // M is too small + CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 0) ); // h_len is too small + CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 47) ); // h_len is not divisible by M + + //CONTEND_ISNULL( symsync_crcf_create_nyquist(2, 12, NULL, 47) ); // h_len is not divisible by M + + // // create valid object + // symsync_crcf q = symsync_crcf_create ... + // CONTEND_EQUALITY( LIQUID_OK, symsync_crcf_print(filter) ); + + // // check properties ... + + // // destroy object + // symsync_crcf_destroy(filter); +} + From b11470af5b162b6bfef7888417cd1e9734cc2592 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 8 Mar 2024 07:00:09 -0500 Subject: [PATCH 251/334] symsync: adding method to check lock state, tests --- include/liquid.h | 4 ++++ src/filter/src/symsync.proto.c | 8 ++++++- src/filter/tests/symsync_copy_autotest.c | 27 ++++++++++++++++++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index f5f2ab0ae..bbb18914f 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4962,6 +4962,10 @@ int SYMSYNC(_lock)(SYMSYNC() _q); \ /* Unlock the symbol synchronizer's loop control */ \ int SYMSYNC(_unlock)(SYMSYNC() _q); \ \ +/* Check the lock state of the symbol synchronizer's loop control, */ \ +/* returning 1 if the object is locked, 0 if unlocked. */ \ +int SYMSYNC(_is_locked)(SYMSYNC() _q); \ + \ /* Set synchronizer output rate (samples/symbol) */ \ /* _q : synchronizer object */ \ /* _k_out : output samples/symbol, _k_out > 0 */ \ diff --git a/src/filter/src/symsync.proto.c b/src/filter/src/symsync.proto.c index 0702772f5..4a7a43bb6 100644 --- a/src/filter/src/symsync.proto.c +++ b/src/filter/src/symsync.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -377,6 +377,12 @@ int SYMSYNC(_unlock)(SYMSYNC() _q) return LIQUID_OK; } +// check lock state +int SYMSYNC(_is_locked)(SYMSYNC() _q) +{ + return _q->is_locked; +} + // set synchronizer output rate (samples/symbol) // _q : synchronizer object // _k_out : output samples/symbol diff --git a/src/filter/tests/symsync_copy_autotest.c b/src/filter/tests/symsync_copy_autotest.c index 5541d770a..4c304b733 100644 --- a/src/filter/tests/symsync_copy_autotest.c +++ b/src/filter/tests/symsync_copy_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -85,15 +85,28 @@ void autotest_symsync_config() CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 0) ); // h_len is too small CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 47) ); // h_len is not divisible by M + CONTEND_ISNULL( symsync_crcf_create_kaiser(0, 12, 0.2, 48) ); // k is too small + CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 0, 0.2, 48) ); // m is too small + CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 12, 7.2, 48) ); // beta is too large + CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 12, 0.2, 0) ); // M is too small + //CONTEND_ISNULL( symsync_crcf_create_nyquist(2, 12, NULL, 47) ); // h_len is not divisible by M - // // create valid object - // symsync_crcf q = symsync_crcf_create ... - // CONTEND_EQUALITY( LIQUID_OK, symsync_crcf_print(filter) ); + // create valid object + symsync_crcf q = symsync_crcf_create_kaiser(2, 12, 0.2, 48); + CONTEND_EQUALITY( LIQUID_OK, symsync_crcf_print(q) ); + + // check lock state + CONTEND_EQUALITY( symsync_crcf_lock(q), LIQUID_OK ); + CONTEND_TRUE ( symsync_crcf_is_locked(q) ); + CONTEND_EQUALITY( symsync_crcf_unlock(q), LIQUID_OK ); + CONTEND_FALSE ( symsync_crcf_is_locked(q) ); - // // check properties ... + // check invalid properties + CONTEND_EQUALITY( LIQUID_EICONFIG, symsync_crcf_set_output_rate(q, 0) ); + CONTEND_EQUALITY( LIQUID_EICONFIG, symsync_crcf_set_lf_bw(q, -1) ); - // // destroy object - // symsync_crcf_destroy(filter); + // destroy object + symsync_crcf_destroy(q); } From 1b686e839bcde70931d7cff22ee777438b8b337c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 8 Mar 2024 07:29:58 -0500 Subject: [PATCH 252/334] symsync/autotest: adding option for seprate method --- src/filter/tests/symsync_crcf_autotest.c | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/filter/tests/symsync_crcf_autotest.c b/src/filter/tests/symsync_crcf_autotest.c index 30383e53e..881877bff 100644 --- a/src/filter/tests/symsync_crcf_autotest.c +++ b/src/filter/tests/symsync_crcf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,15 +20,15 @@ * THE SOFTWARE. */ -// -// symsync_crcf_autotest.c : test symbol timing synchronizer -// +// symbol timing synchronizer tests +#include #include "autotest/autotest.h" #include "liquid.h" // -void symsync_crcf_test(unsigned int _k, +void symsync_crcf_test(const char * _method, + unsigned int _k, unsigned int _m, float _beta, float _tau, @@ -44,9 +44,9 @@ void symsync_crcf_test(unsigned int _k, unsigned int num_symbols_init=200; // number of initial symbols unsigned int num_symbols_test=100; // number of testing symbols - // transmit/receive filter types - liquid_firfilt_type ftype_tx = LIQUID_FIRFILT_ARKAISER; - liquid_firfilt_type ftype_rx = LIQUID_FIRFILT_ARKAISER; + // transmit filter type + liquid_firfilt_type ftype_tx = strcmp(_method,"rnyquist")==0 ? + LIQUID_FIRFILT_ARKAISER : LIQUID_FIRFILT_KAISER; float bt = 0.02f; // loop filter bandwidth float tau = _tau; // fractional symbol offset @@ -123,7 +123,7 @@ void symsync_crcf_test(unsigned int _k, // // create symbol synchronizer - symsync_crcf sync = symsync_crcf_create_rnyquist(ftype_rx, k, m, beta, num_filters); + symsync_crcf sync = symsync_crcf_create_rnyquist(ftype_tx, k, m, beta, num_filters); // set loop filter bandwidth symsync_crcf_set_lf_bw(sync,bt); @@ -170,8 +170,8 @@ void symsync_crcf_test(unsigned int _k, } // autotest scenarios -void autotest_symsync_crcf_scenario_0() { symsync_crcf_test(2, 7, 0.35, 0.00, 1.0f ); } -void autotest_symsync_crcf_scenario_1() { symsync_crcf_test(2, 7, 0.35, -0.25, 1.0f ); } -void autotest_symsync_crcf_scenario_2() { symsync_crcf_test(2, 7, 0.35, -0.25, 1.0001f ); } -void autotest_symsync_crcf_scenario_3() { symsync_crcf_test(2, 7, 0.35, -0.25, 0.9999f ); } +void autotest_symsync_crcf_scenario_0() { symsync_crcf_test("rnyquist", 2, 7, 0.35, 0.00, 1.0f ); } +void autotest_symsync_crcf_scenario_1() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0f ); } +void autotest_symsync_crcf_scenario_2() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0001f ); } +void autotest_symsync_crcf_scenario_3() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 0.9999f ); } From 2f4b4cf042f11a555befa8de96c398bfbbb3d04c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 8 Mar 2024 07:33:27 -0500 Subject: [PATCH 253/334] symsync/autotest: testing nyquist filter operation --- src/filter/tests/symsync_crcf_autotest.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/filter/tests/symsync_crcf_autotest.c b/src/filter/tests/symsync_crcf_autotest.c index 881877bff..91ed7a23d 100644 --- a/src/filter/tests/symsync_crcf_autotest.c +++ b/src/filter/tests/symsync_crcf_autotest.c @@ -123,7 +123,11 @@ void symsync_crcf_test(const char * _method, // // create symbol synchronizer - symsync_crcf sync = symsync_crcf_create_rnyquist(ftype_tx, k, m, beta, num_filters); + symsync_crcf sync = NULL; + if (strcmp(_method,"rnyquist")==0) + sync = symsync_crcf_create_rnyquist(ftype_tx, k, m, beta, num_filters); + else + sync = symsync_crcf_create_kaiser(k, m, beta, num_filters); // set loop filter bandwidth symsync_crcf_set_lf_bw(sync,bt); @@ -169,9 +173,15 @@ void symsync_crcf_test(const char * _method, } -// autotest scenarios +// autotest scenarios (root-Nyquist) void autotest_symsync_crcf_scenario_0() { symsync_crcf_test("rnyquist", 2, 7, 0.35, 0.00, 1.0f ); } void autotest_symsync_crcf_scenario_1() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0f ); } void autotest_symsync_crcf_scenario_2() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0001f ); } void autotest_symsync_crcf_scenario_3() { symsync_crcf_test("rnyquist", 2, 7, 0.35, -0.25, 0.9999f ); } +// autotest scenarios (Nyquist) +void autotest_symsync_crcf_scenario_4() { symsync_crcf_test("nyquist", 2, 7, 0.35, 0.00, 1.0f ); } +void autotest_symsync_crcf_scenario_5() { symsync_crcf_test("nyquist", 2, 7, 0.35, -0.25, 1.0f ); } +void autotest_symsync_crcf_scenario_6() { symsync_crcf_test("nyquist", 2, 7, 0.35, -0.25, 1.0001f ); } +void autotest_symsync_crcf_scenario_7() { symsync_crcf_test("nyquist", 2, 7, 0.35, -0.25, 0.9999f ); } + From ff5b1b675860714ef1f35782a3b75ee06dbcc65e Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 8 Mar 2024 07:40:21 -0500 Subject: [PATCH 254/334] symsync/autotest: aligning symsync_rrrf with symsync_crcf tests --- src/filter/tests/symsync_rrrf_autotest.c | 44 +++++++++++++++--------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/filter/tests/symsync_rrrf_autotest.c b/src/filter/tests/symsync_rrrf_autotest.c index 5b776de64..a36893d56 100644 --- a/src/filter/tests/symsync_rrrf_autotest.c +++ b/src/filter/tests/symsync_rrrf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,35 +20,35 @@ * THE SOFTWARE. */ -// -// symsync_rrrf_autotest.c : test symbol timing synchronizer -// +// symbol timing synchronizer tests +#include #include "autotest/autotest.h" #include "liquid.h" // -void symsync_rrrf_test(unsigned int _k, +void symsync_rrrf_test(const char * _method, + unsigned int _k, unsigned int _m, float _beta, float _tau, float _rate) { // options - float tol = 0.2f; // error tolerance + float tol = 0.20f; // error tolerance unsigned int k = _k; // samples/symbol (input) unsigned int m = _m; // filter delay (symbols) float beta = _beta; // filter excess bandwidth factor unsigned int num_filters= 32; // number of filters in the bank - unsigned int num_symbols_init=200; // number of initial symbols + unsigned int num_symbols_init=400; // number of initial symbols unsigned int num_symbols_test=100; // number of testing symbols - // transmit/receive filter types - liquid_firfilt_type ftype_tx = LIQUID_FIRFILT_ARKAISER; - liquid_firfilt_type ftype_rx = LIQUID_FIRFILT_ARKAISER; + // transmit filter type + liquid_firfilt_type ftype_tx = strcmp(_method,"rnyquist")==0 ? + LIQUID_FIRFILT_ARKAISER : LIQUID_FIRFILT_KAISER; - float bt = 0.02f; // loop filter bandwidth + float bt = 0.01f; // loop filter bandwidth float tau = _tau; // fractional symbol offset float rate = _rate; // resampled rate @@ -119,7 +119,11 @@ void symsync_rrrf_test(unsigned int _k, // // create symbol synchronizer - symsync_rrrf sync = symsync_rrrf_create_rnyquist(ftype_rx, k, m, beta, num_filters); + symsync_rrrf sync = NULL; + if (strcmp(_method,"rnyquist")==0) + sync = symsync_rrrf_create_rnyquist(ftype_tx, k, m, beta, num_filters); + else + sync = symsync_rrrf_create_kaiser(k, m, beta, num_filters); // set loop filter bandwidth symsync_rrrf_set_lf_bw(sync,bt); @@ -165,9 +169,15 @@ void symsync_rrrf_test(unsigned int _k, } -// autotest scenarios -void autotest_symsync_rrrf_scenario_0() { symsync_rrrf_test(2, 7, 0.35, 0.00, 1.0f ); } -void autotest_symsync_rrrf_scenario_1() { symsync_rrrf_test(2, 7, 0.35, -0.25, 1.0f ); } -void autotest_symsync_rrrf_scenario_2() { symsync_rrrf_test(2, 7, 0.35, -0.25, 1.0001f ); } -void autotest_symsync_rrrf_scenario_3() { symsync_rrrf_test(2, 7, 0.35, -0.25, 0.9999f ); } +// autotest scenarios (root-Nyquist) +void autotest_symsync_rrrf_scenario_0() { symsync_rrrf_test("rnyquist", 2, 7, 0.35, 0.00, 1.0f ); } +void autotest_symsync_rrrf_scenario_1() { symsync_rrrf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0f ); } +void autotest_symsync_rrrf_scenario_2() { symsync_rrrf_test("rnyquist", 2, 7, 0.35, -0.25, 1.0001f ); } +void autotest_symsync_rrrf_scenario_3() { symsync_rrrf_test("rnyquist", 2, 7, 0.35, -0.25, 0.9999f ); } + +// autotest scenarios (Nyquist) +void autotest_symsync_rrrf_scenario_4() { symsync_rrrf_test("nyquist", 2, 7, 0.35, 0.00, 1.0f ); } +void autotest_symsync_rrrf_scenario_5() { symsync_rrrf_test("nyquist", 2, 7, 0.35, -0.25, 1.0f ); } +void autotest_symsync_rrrf_scenario_6() { symsync_rrrf_test("nyquist", 2, 7, 0.35, -0.25, 1.0001f ); } +void autotest_symsync_rrrf_scenario_7() { symsync_rrrf_test("nyquist", 2, 7, 0.35, -0.25, 0.9999f ); } From 3496f59b0c7034264ae524d0bddc9dea0b828fa1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 8 Mar 2024 18:57:30 -0500 Subject: [PATCH 255/334] symsync: cleaning object of old debugging macros --- src/filter/src/symsync.proto.c | 213 --------------------------------- 1 file changed, 213 deletions(-) diff --git a/src/filter/src/symsync.proto.c b/src/filter/src/symsync.proto.c index 4a7a43bb6..7a825ed9c 100644 --- a/src/filter/src/symsync.proto.c +++ b/src/filter/src/symsync.proto.c @@ -39,11 +39,6 @@ #include #include -#define DEBUG_SYMSYNC 0 -#define DEBUG_SYMSYNC_PRINT 0 -#define DEBUG_SYMSYNC_FILENAME "symsync_internal_debug.m" -#define DEBUG_BUFFER_LEN (1024) - // // forward declaration of internal methods // @@ -66,12 +61,6 @@ int SYMSYNC(_advance_internal_loop)(SYMSYNC() _q, TO _mf, TO _dmf); -// print results to output debugging file -// _q : synchronizer object -// _filename : output filename -int SYMSYNC(_output_debug_file)(SYMSYNC() _q, - const char * _filename); - // internal structure struct SYMSYNC(_s) { unsigned int h_len; // matched filter length @@ -101,15 +90,6 @@ struct SYMSYNC(_s) { unsigned int npfb; // number of filters in the bank FIRPFB() mf; // matched filter FIRPFB() dmf; // derivative matched filter - -#if DEBUG_SYMSYNC - windowf debug_rate; - windowf debug_del; - windowf debug_tau; - windowf debug_bsoft; - windowf debug_b; - windowf debug_q_hat; -#endif }; // create synchronizer object from external coefficients @@ -181,15 +161,6 @@ SYMSYNC() SYMSYNC(_create)(unsigned int _k, // unlock loop control SYMSYNC(_unlock)(q); -#if DEBUG_SYMSYNC - q->debug_rate = windowf_create(DEBUG_BUFFER_LEN); - q->debug_del = windowf_create(DEBUG_BUFFER_LEN); - q->debug_tau = windowf_create(DEBUG_BUFFER_LEN); - q->debug_bsoft = windowf_create(DEBUG_BUFFER_LEN); - q->debug_b = windowf_create(DEBUG_BUFFER_LEN); - q->debug_q_hat = windowf_create(DEBUG_BUFFER_LEN); -#endif - // return main object return q; } @@ -294,15 +265,6 @@ SYMSYNC() SYMSYNC(_copy)(SYMSYNC() q_orig) q_copy->mf = FIRPFB(_copy)(q_orig->mf); q_copy->dmf = FIRPFB(_copy)(q_orig->dmf); -#if DEBUG_SYMSYNC - // copy debugging windows - q_copy->debug_rate = windowf_copy(q_orig->debug_rate); - q_copy->debug_del = windowf_copy(q_orig->debug_del); - q_copy->debug_tau = windowf_copy(q_orig->debug_tau); - q_copy->debug_bsoft = windowf_copy(q_orig->debug_bsoft); - q_copy->debug_b = windowf_copy(q_orig->debug_b); - q_copy->debug_q_hat = windowf_copy(q_orig->debug_q_hat); -#endif // return object return q_copy; } @@ -310,19 +272,6 @@ SYMSYNC() SYMSYNC(_copy)(SYMSYNC() q_orig) // destroy symsync object, freeing all internal memory int SYMSYNC(_destroy)(SYMSYNC() _q) { -#if DEBUG_SYMSYNC - // output debugging file - SYMSYNC(_output_debug_file)(_q, DEBUG_SYMSYNC_FILENAME); - - // destroy internal window objects - windowf_destroy(_q->debug_rate); - windowf_destroy(_q->debug_del); - windowf_destroy(_q->debug_tau); - windowf_destroy(_q->debug_bsoft); - windowf_destroy(_q->debug_b); - windowf_destroy(_q->debug_q_hat); -#endif - // destroy filterbank objects FIRPFB(_destroy)(_q->mf); FIRPFB(_destroy)(_q->dmf); @@ -488,10 +437,6 @@ int SYMSYNC(_step)(SYMSYNC() _q, // continue loop until filterbank index rolls over while (_q->b < _q->npfb) { -#if DEBUG_SYMSYNC_PRINT - printf(" [%2u] : tau : %12.8f, b : %4u (%12.8f)\n", n, _q->tau, _q->b, _q->bf); -#endif - // compute filterbank output FIRPFB(_execute)(_q->mf, _q->b, &mf); @@ -503,16 +448,6 @@ int SYMSYNC(_step)(SYMSYNC() _q, // reset counter _q->decim_counter = 0; -#if DEBUG_SYMSYNC - // save debugging variables - windowf_push(_q->debug_rate, _q->rate); - windowf_push(_q->debug_del, _q->del); - windowf_push(_q->debug_tau, _q->tau); - windowf_push(_q->debug_bsoft, _q->bf); - windowf_push(_q->debug_b, _q->b); - windowf_push(_q->debug_q_hat, _q->q_hat); -#endif - // if synchronizer is locked, don't update internal timing offset if (_q->is_locked) continue; @@ -572,154 +507,6 @@ int SYMSYNC(_advance_internal_loop)(SYMSYNC() _q, _q->rate += _q->rate_adjustment * _q->q_hat; _q->del = _q->rate + _q->q_hat; -#if DEBUG_SYMSYNC_PRINT - printf("q : %12.8f, rate : %12.8f, del : %12.8f, q_hat : %12.8f\n", _q->q, _q->rate, _q->del, _q->q_hat); -#endif - return LIQUID_OK; -} - -// print results to output debugging file -// _q : synchronizer object -// _filename : output filename -int SYMSYNC(_output_debug_file)(SYMSYNC() _q, - const char * _filename) -{ - FILE * fid = fopen(_filename, "w"); - if (!fid) - return liquid_error(LIQUID_EICONFIG,"symsync_%s_output_debug_file(), could not open '%s' for writing", EXTENSION_FULL, _filename); - fprintf(fid,"%% %s, auto-generated file\n\n", DEBUG_SYMSYNC_FILENAME); - fprintf(fid,"\n"); - fprintf(fid,"clear all;\n"); - fprintf(fid,"close all;\n"); - - fprintf(fid,"npfb = %u;\n",_q->npfb); - fprintf(fid,"k = %u;\n",_q->k); - fprintf(fid,"\n\n"); - -#if DEBUG_SYMSYNC - fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); - float * r; - unsigned int i; - - // save filter responses - FIRPFB(_reset)(_q->mf); - FIRPFB(_reset)(_q->dmf); - fprintf(fid,"h = [];\n"); - fprintf(fid,"dh = [];\n"); - fprintf(fid,"h_len = %u;\n", _q->h_len); - for (i=0; i<_q->h_len; i++) { - // push impulse - if (i==0) { - FIRPFB(_push)(_q->mf, 1.0f); - FIRPFB(_push)(_q->dmf, 1.0f); - } else { - FIRPFB(_push)(_q->mf, 0.0f); - FIRPFB(_push)(_q->dmf, 0.0f); - } - - // compute output for all filters - TO mf; // matched filter output - TO dmf; // derivative matched filter output - - unsigned int n; - for (n=0; n<_q->npfb; n++) { - FIRPFB(_execute)(_q->mf, n, &mf); - FIRPFB(_execute)(_q->dmf, n, &dmf); - - fprintf(fid,"h(%4u) = %12.8f; dh(%4u) = %12.8f;\n", i*_q->npfb+n+1, crealf(mf), i*_q->npfb+n+1, crealf(dmf)); - } - } - // plot response - fprintf(fid,"\n"); - fprintf(fid,"figure;\n"); - fprintf(fid,"th = [0:(h_len*npfb-1)]/(k*npfb) - h_len/(2*k);\n"); - fprintf(fid,"m = abs(round(th(1)));\n"); - //fprintf(fid,"plot(t,h,t,dh);\n"); - fprintf(fid,"subplot(3,1,1),\n"); - fprintf(fid," plot(th, h, 'LineWidth', 2, 'Color', [0 0.5 0.2]);\n"); - fprintf(fid," ylabel('MF');\n"); - fprintf(fid," axis([-m m -0.25 1.25]);\n"); - fprintf(fid," grid on;\n"); - fprintf(fid,"subplot(3,1,2),\n"); - fprintf(fid," plot(th, dh, 'LineWidth', 2, 'Color', [0 0.2 0.5]);\n"); - fprintf(fid," ylabel('dMF');\n"); - fprintf(fid," axis([-m m -0.10 0.10]);\n"); - fprintf(fid," grid on;\n"); - fprintf(fid,"subplot(3,1,3),\n"); - fprintf(fid," plot(th,-h.*dh, 'LineWidth', 2, 'Color', [0.5 0 0]);\n"); - fprintf(fid," xlabel('Symbol Index');\n"); - fprintf(fid," ylabel('-MF*dMF');\n"); - fprintf(fid," axis([-m m -0.08 0.08]);\n"); - fprintf(fid," grid on;\n"); - - // print rate buffer - fprintf(fid,"rate = zeros(1,n);\n"); - windowf_read(_q->debug_rate, &r); - for (i=0; idebug_del, &r); - for (i=0; idebug_tau, &r); - for (i=0; idebug_bsoft, &r); - for (i=0; idebug_b, &r); - for (i=0; idebug_q_hat, &r); - for (i=0; i Date: Fri, 8 Mar 2024 19:02:47 -0500 Subject: [PATCH 256/334] symsync/autotest: testing configuration for create_rnyquist() --- src/filter/tests/symsync_copy_autotest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/filter/tests/symsync_copy_autotest.c b/src/filter/tests/symsync_copy_autotest.c index 4c304b733..2514fccf2 100644 --- a/src/filter/tests/symsync_copy_autotest.c +++ b/src/filter/tests/symsync_copy_autotest.c @@ -85,13 +85,16 @@ void autotest_symsync_config() CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 0) ); // h_len is too small CONTEND_ISNULL( symsync_crcf_create(2, 12, NULL, 47) ); // h_len is not divisible by M + CONTEND_ISNULL( symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, 0, 12, 0.2, 48) ); // k is too small + CONTEND_ISNULL( symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, 2, 0, 0.2, 48) ); // m is too small + CONTEND_ISNULL( symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, 2, 12, 7.2, 48) ); // beta is too large + CONTEND_ISNULL( symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, 2, 12, 0.2, 0) ); // M is too small + CONTEND_ISNULL( symsync_crcf_create_kaiser(0, 12, 0.2, 48) ); // k is too small CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 0, 0.2, 48) ); // m is too small CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 12, 7.2, 48) ); // beta is too large CONTEND_ISNULL( symsync_crcf_create_kaiser(2, 12, 0.2, 0) ); // M is too small - //CONTEND_ISNULL( symsync_crcf_create_nyquist(2, 12, NULL, 47) ); // h_len is not divisible by M - // create valid object symsync_crcf q = symsync_crcf_create_kaiser(2, 12, 0.2, 48); CONTEND_EQUALITY( LIQUID_OK, symsync_crcf_print(q) ); From 4e84cb04350853a6cc83e353fa3f3cd48d62d313 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 10 Mar 2024 11:18:25 -0400 Subject: [PATCH 257/334] build: removing unnecessary explicit framing targets --- makefile.in | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/makefile.in b/makefile.in index f5526b8e4..3fc8e9091 100644 --- a/makefile.in +++ b/makefile.in @@ -676,20 +676,6 @@ src/framing/src/framing_rrrf.o : %.o : %.c $(include_headers) ${framing_pro src/framing/src/framing_crcf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} src/framing/src/framing_cccf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} -src/framing/src/bpacketgen.o : %.o : %.c $(include_headers) -src/framing/src/bpacketsync.o : %.o : %.c $(include_headers) -src/framing/src/detector_cccf.o : %.o : %.c $(include_headers) -src/framing/src/dsssframegen.o : %.o : %.c $(include_headers) -src/framing/src/dsssframesync.o : %.o : %.c $(include_headers) -src/framing/src/framedatastats.o : %.o : %.c $(include_headers) -src/framing/src/framesyncstats.o : %.o : %.c $(include_headers) -src/framing/src/framegen64.o : %.o : %.c $(include_headers) -src/framing/src/framesync64.o : %.o : %.c $(include_headers) -src/framing/src/flexframegen.o : %.o : %.c $(include_headers) -src/framing/src/flexframesync.o : %.o : %.c $(include_headers) -src/framing/src/ofdmflexframegen.o : %.o : %.c $(include_headers) -src/framing/src/ofdmflexframesync.o : %.o : %.c $(include_headers) - framing_autotests := \ src/framing/tests/bpacketsync_autotest.c \ src/framing/tests/bsync_autotest.c \ @@ -1194,7 +1180,8 @@ objects := \ $(sequence_objects) \ $(utility_objects) \ $(vector_objects) \ - + +$(objects) : %.o : %.c $(include_headers) autotest_sources := \ autotest/null_autotest.c \ From 5001de3c7c549cc4efe90216d52df57d99dddfe9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 10 Mar 2024 16:54:45 -0400 Subject: [PATCH 258/334] modem/autotest: moving configuration test filename --- makefile.in | 2 +- .../tests/{modem_copy_autotest.c => modem_config_autotest.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/modem/tests/{modem_copy_autotest.c => modem_config_autotest.c} (100%) diff --git a/makefile.in b/makefile.in index 3fc8e9091..c2dd443e3 100644 --- a/makefile.in +++ b/makefile.in @@ -895,7 +895,7 @@ modem_autotests := \ src/modem/tests/fskmodem_autotest.c \ src/modem/tests/gmskmodem_autotest.c \ src/modem/tests/modem_autotest.c \ - src/modem/tests/modem_copy_autotest.c \ + src/modem/tests/modem_config_autotest.c \ src/modem/tests/modem_demodsoft_autotest.c \ src/modem/tests/modem_demodstats_autotest.c \ src/modem/tests/modem_utilities_autotest.c \ diff --git a/src/modem/tests/modem_copy_autotest.c b/src/modem/tests/modem_config_autotest.c similarity index 100% rename from src/modem/tests/modem_copy_autotest.c rename to src/modem/tests/modem_config_autotest.c From 2f94f8233a0d5f06390254b4e9b978a979f029a6 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 10 Mar 2024 18:43:02 -0400 Subject: [PATCH 259/334] modem/autotest: adding configuration tests --- src/modem/tests/modem_config_autotest.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/modem/tests/modem_config_autotest.c b/src/modem/tests/modem_config_autotest.c index 619e8e330..ebc8f03fa 100644 --- a/src/modem/tests/modem_config_autotest.c +++ b/src/modem/tests/modem_config_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -132,3 +132,23 @@ void autotest_modem_copy_arb256opt() { modemcf_test_copy(LIQUID_MODEM_ARB256OPT) void autotest_modem_copy_arb64vt() { modemcf_test_copy(LIQUID_MODEM_ARB64VT); } void autotest_modem_copy_pi4dqpsk() { modemcf_test_copy(LIQUID_MODEM_PI4DQPSK); } +// test errors and invalid configuration +void autotest_modem_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping modem config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + CONTEND_ISNULL( modemcf_copy(NULL) ); + CONTEND_ISNULL( modemcf_create(LIQUID_MODEM_ARB) ); + + // create object and check configuration + modemcf q = modemcf_create(LIQUID_MODEM_QAM64); + CONTEND_EQUALITY( LIQUID_OK, modemcf_print(q) ); + modemcf_destroy(q); +} + From 22fa2accb572a58a9ab0568132dec25dc7174093 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 10 Mar 2024 18:53:28 -0400 Subject: [PATCH 260/334] cpfskmodem: adding configuration tests --- include/liquid.h | 1 + src/modem/src/cpfskdem.c | 6 +++--- src/modem/src/cpfskmod.c | 6 +++--- src/modem/tests/cpfskmodem_autotest.c | 28 +++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index bbb18914f..1a3ea760b 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8222,6 +8222,7 @@ int gmskdem_demodulate(gmskdem _q, // CP-FSK filter prototypes typedef enum { + //LIQUID_CPFSK_UNKNOWN=0 LIQUID_CPFSK_SQUARE=0, // square pulse LIQUID_CPFSK_RCOS_FULL, // raised-cosine (full response) LIQUID_CPFSK_RCOS_PARTIAL, // raised-cosine (partial response) diff --git a/src/modem/src/cpfskdem.c b/src/modem/src/cpfskdem.c index 425400620..7b04ab130 100644 --- a/src/modem/src/cpfskdem.c +++ b/src/modem/src/cpfskdem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -138,14 +138,14 @@ cpfskdem cpfskdem_create(unsigned int _bps, // validate input if (_bps == 0) return liquid_error_config("cpfskdem_create(), bits/symbol must be greater than 0"); + if (_h <= 0.0f) + return liquid_error_config("cpfskdem_create(), modulation index must be greater than 0"); if (_k < 2 || (_k%2)) return liquid_error_config("cpfskmod_create(), samples/symbol must be greater than 2 and even"); if (_m == 0) return liquid_error_config("cpfskdem_create(), filter delay must be greater than 0"); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("cpfskdem_create(), filter roll-off must be in (0,1]"); - if (_h <= 0.0f) - return liquid_error_config("cpfskdem_create(), modulation index must be greater than 0"); // create main object memory cpfskdem q = (cpfskdem) malloc(sizeof(struct cpfskdem_s)); diff --git a/src/modem/src/cpfskmod.c b/src/modem/src/cpfskmod.c index 843022c75..c8c5b415b 100644 --- a/src/modem/src/cpfskmod.c +++ b/src/modem/src/cpfskmod.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -79,14 +79,14 @@ cpfskmod cpfskmod_create(unsigned int _bps, // validate input if (_bps == 0) return liquid_error_config("cpfskmod_create(), bits/symbol must be greater than 0"); + if (_h <= 0.0f) + return liquid_error_config("cpfskmod_create(), modulation index must be greater than 0"); if (_k < 2 || (_k%2)) return liquid_error_config("cpfskmod_create(), samples/symbol must be greater than 2 and even"); if (_m == 0) return liquid_error_config("cpfskmod_create(), filter delay must be greater than 0"); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("cpfskmod_create(), filter roll-off must be in (0,1]"); - if (_h <= 0.0f) - return liquid_error_config("cpfskmod_create(), modulation index must be greater than 0"); // create main object memory cpfskmod q = (cpfskmod) malloc(sizeof(struct cpfskmod_s)); diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index 27f57c073..e4d3932ed 100644 --- a/src/modem/tests/cpfskmodem_autotest.c +++ b/src/modem/tests/cpfskmodem_autotest.c @@ -171,3 +171,31 @@ void autotest_cpfskmodem_spectrum() liquid_autotest_verbose ? filename : NULL); } + +// test errors and invalid configuration +void autotest_cpfskmodem_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping modem config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + //CONTEND_ISNULL( modemcf_copy(NULL) ); + CONTEND_ISNULL( cpfskmod_create(0, 0.5f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _bps is less than 1 + CONTEND_ISNULL( cpfskmod_create(1, 0.0f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _h (mod index) is out of range + CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 5, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _k is not even + CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 4, 0, 0.25f, LIQUID_CPFSK_SQUARE) ); // _m is too small + CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 4, 12, 0.00f, LIQUID_CPFSK_SQUARE) ); // _beta is too small + + CONTEND_ISNULL( cpfskdem_create(0, 0.5f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _bps is less than 1 + CONTEND_ISNULL( cpfskdem_create(1, 0.0f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _h (mod index) is out of range + CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 5, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _k is not even + CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 4, 0, 0.25f, LIQUID_CPFSK_SQUARE) ); // _m is too small + CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 4, 12, 0.00f, LIQUID_CPFSK_SQUARE) ); // _beta is too small + + // TODO: create object and check configuration +} + From 8c0ea76eaab215b09790b01622e7c487aaf5d9cf Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 11 Mar 2024 17:36:51 -0400 Subject: [PATCH 261/334] cpfskmodem/autotest: adding more configuration tests --- src/modem/tests/cpfskmodem_autotest.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index e4d3932ed..68f15f999 100644 --- a/src/modem/tests/cpfskmodem_autotest.c +++ b/src/modem/tests/cpfskmodem_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2018 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -171,7 +171,6 @@ void autotest_cpfskmodem_spectrum() liquid_autotest_verbose ? filename : NULL); } - // test errors and invalid configuration void autotest_cpfskmodem_config() { @@ -189,13 +188,23 @@ void autotest_cpfskmodem_config() CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 5, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _k is not even CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 4, 0, 0.25f, LIQUID_CPFSK_SQUARE) ); // _m is too small CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 4, 12, 0.00f, LIQUID_CPFSK_SQUARE) ); // _beta is too small + CONTEND_ISNULL( cpfskmod_create(1, 0.5f, 4, 12, 0.00f, -1) ); // invalid filter type CONTEND_ISNULL( cpfskdem_create(0, 0.5f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _bps is less than 1 CONTEND_ISNULL( cpfskdem_create(1, 0.0f, 4, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _h (mod index) is out of range CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 5, 12, 0.25f, LIQUID_CPFSK_SQUARE) ); // _k is not even CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 4, 0, 0.25f, LIQUID_CPFSK_SQUARE) ); // _m is too small CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 4, 12, 0.00f, LIQUID_CPFSK_SQUARE) ); // _beta is too small + CONTEND_ISNULL( cpfskdem_create(1, 0.5f, 4, 12, 0.00f, -1) ); // invalid filter type + + // create modulator object and check configuration + cpfskmod mod = cpfskmod_create(1, 0.5f, 4, 12, 0.5f, LIQUID_CPFSK_SQUARE); + CONTEND_EQUALITY( LIQUID_OK, cpfskmod_print(mod) ); + cpfskmod_destroy(mod); - // TODO: create object and check configuration + // create demodulator object and check configuration + cpfskdem dem = cpfskdem_create(1, 0.5f, 4, 12, 0.5f, LIQUID_CPFSK_SQUARE); + CONTEND_EQUALITY( LIQUID_OK, cpfskdem_print(dem) ); + cpfskdem_destroy(dem); } From 9e1c40d8cf1a8a23069c9e6c1da4b70575b1683b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 11:20:50 -0400 Subject: [PATCH 262/334] qdsync: adding method to get state, performance example --- examples/qdsync_cccf_performance_example.c | 99 ++++++++++++++++++++++ include/liquid.h | 3 + makefile.in | 1 + src/framing/src/qdsync.proto.c | 9 +- 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 examples/qdsync_cccf_performance_example.c diff --git a/examples/qdsync_cccf_performance_example.c b/examples/qdsync_cccf_performance_example.c new file mode 100644 index 000000000..6df24399f --- /dev/null +++ b/examples/qdsync_cccf_performance_example.c @@ -0,0 +1,99 @@ +// This example tests the performance for detecting and decoding frames +// with the qdsync_cccf object. +#include +#include +#include +#include "liquid.h" +#define OUTPUT_FILENAME "qdsync_cccf_performance_example.m" + +int main(int argc, char*argv[]) +{ + // options + unsigned int seq_len = 1024; // number of sync symbols + unsigned int k = 2; // samples/symbol + unsigned int m = 7; // filter delay [symbols] + float beta = 0.3f; // excess bandwidth factor + int ftype = LIQUID_FIRFILT_ARKAISER; + float threshold = 0.10f;// + unsigned int min_trials = 10; // + unsigned int max_trials = 100; // + unsigned int min_missed = 4; // + float SNRdB = -25.0f; + + // generate synchronization sequence (QPSK symbols) + float complex seq[seq_len]; + unsigned int i; + for (i=0; i= min_missed) + break; + if (num_trials >= max_trials) + break; + } + float pmd = (float)num_missed / (float)num_trials; + printf("SNR: %8.3f dB, missed %3u / %3u (%5.1f%%)\n", SNRdB, num_missed, num_trials, pmd*100); + if (num_missed < min_missed) + break; + SNRdB += 1.0f; + } + + qdsync_cccf_destroy(q); + +#if 0 + // open file for storing results + FILE * fid = fopen(OUTPUT_FILENAME,"w"); + fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); + fprintf(fid,"clear all; close all;\n"); + + // export results + fprintf(fid,"seq_len = %u;\n", seq_len); + fprintf(fid,"figure('color','white','position',[100 100 800 800]);\n"); + fprintf(fid,"hold on;\n"); + fprintf(fid,"hold off;\n"); + fprintf(fid,"legend('Preamble','Payload');\n"); + fprintf(fid,"grid on; xlabel('real'); ylabel('imag');\n"); + fclose(fid); + printf("results written to '%s'\n", OUTPUT_FILENAME); +#endif + return 0; +} + diff --git a/include/liquid.h b/include/liquid.h index 1a3ea760b..bde0af9c7 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6434,6 +6434,9 @@ int QDSYNC(_reset)(QDSYNC() _q); \ /* Print synchronizer object information to stdout */ \ int QDSYNC(_print)(QDSYNC() _q); \ \ +/* Get detection state */ \ +int QDSYNC(_is_detected)(QDSYNC() _q); \ + \ /* Get detection threshold */ \ float QDSYNC(_get_threshold)(QDSYNC() _q); \ \ diff --git a/makefile.in b/makefile.in index c2dd443e3..20480b5a0 100644 --- a/makefile.in +++ b/makefile.in @@ -1627,6 +1627,7 @@ example_programs := \ examples/poly_findroots_example \ examples/qdetector_cccf_example \ examples/qdsync_cccf_example \ + examples/qdsync_cccf_performance_example \ examples/qpacketmodem_performance_example \ examples/qpacketmodem_example \ examples/qpilotsync_example \ diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index 06f8fc0a0..afb917844 100644 --- a/src/framing/src/qdsync.proto.c +++ b/src/framing/src/qdsync.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -118,6 +118,7 @@ QDSYNC() QDSYNC(_create_linear)(TI * _seq, QDSYNC(_set_context )(q, _context ); // reset and return object + QDSYNC(_set_threshold)(q, 0.05f); // TODO: set threshold appropriate to sequence length QDSYNC(_reset)(q); return q; } @@ -180,6 +181,12 @@ int QDSYNC(_print)(QDSYNC() _q) return LIQUID_OK; } +// get detection state +int QDSYNC(_is_detected)(QDSYNC() _q) +{ + return _q->state == QDSYNC_STATE_SYNC; +} + // get detection threshold float QDSYNC(_get_threshold)(QDSYNC() _q) { From f3274d5d18d61f4aede82aeece1b0a77b9f44c76 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 11:41:47 -0400 Subject: [PATCH 263/334] dsssframe64: fixing msequence generator polynomial for preamble --- src/framing/src/dsssframe64gen.c | 4 ++-- src/framing/src/dsssframe64sync.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index f3ac1bbf8..bd6ec9348 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,7 +58,7 @@ dsssframe64gen dsssframe64gen_create() unsigned int i; // generate p/n sequence - q->ms = msequence_create(11, 0x0805, 1); + q->ms = msequence_create(11, 0x0500, 1); for (i=0; i<1024; i++) { q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index e5091a970..55b46a315 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -94,7 +94,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, unsigned int i; // generate p/n sequence - q->ms = msequence_create(11, 0x0805, 1); + q->ms = msequence_create(11, 0x0500, 1); for (i=0; i<1024; i++) { q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; From 88442ad3eba49fc43af5f2d459252437eb3f8f1b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 11:50:47 -0400 Subject: [PATCH 264/334] dsssframe64: adjusting threshold, displaying stats in example --- examples/dsssframe64sync_performance_example.c | 9 ++++++--- src/framing/src/dsssframe64sync.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/dsssframe64sync_performance_example.c b/examples/dsssframe64sync_performance_example.c index 3d73139d4..841027b2d 100644 --- a/examples/dsssframe64sync_performance_example.c +++ b/examples/dsssframe64sync_performance_example.c @@ -35,7 +35,7 @@ int main(int argc, char*argv[]) fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); - printf("# %8s %6s %6s %6s\n", "SNR", "detect", "valid", "trials"); + printf("# %8s %6s (%7s) %6s (%7s) %6s\n", "SNR", "missed", "percent", "errors", "percent", "trials"); fclose(fid); while (SNRdB < -5.0f) { dsssframe64sync_reset_framedatastats(fs); @@ -64,8 +64,11 @@ int main(int argc, char*argv[]) } // print results framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); - printf(" %8.3f %6u %6u %6u\n", - SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials); + unsigned int num_misses = num_trials - stats.num_frames_detected; + float pmd = (float) num_misses / (float) num_trials; + float per = (float) num_errors / (float) num_trials; + printf(" %8.3f %6u (%6.2f%%) %6u (%6.2f%%) %6u\n", + SNRdB,num_misses,pmd*100,num_errors,per*100,num_trials); fid = fopen(OUTPUT_FILENAME,"a"); fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%12g; pvalid(end+1)=%12g;\n", SNRdB, diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 55b46a315..774ea087c 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -104,7 +104,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, unsigned int k = 2; // samples/symbol q->detector = qdsync_cccf_create_linear(q->preamble_pn, 1024, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta, dsssframe64sync_callback_internal, (void*)q); - qdsync_cccf_set_threshold(q->detector, 0.100f); // detection threshold + qdsync_cccf_set_threshold(q->detector, 0.097f); // detection threshold qdsync_cccf_set_range (q->detector, 0.006f); // frequency offset search range [radians/sample] // create payload demodulator/decoder object From 9699a1c1aee87889a9e14ac8f6d0daa870211b1c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 13:12:29 -0400 Subject: [PATCH 265/334] dsssframe64: making spreading factor (fixed) internal value --- src/framing/src/dsssframe64gen.c | 17 ++++++++++------- src/framing/src/dsssframe64sync.c | 19 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index bd6ec9348..81042099b 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -20,8 +20,7 @@ * THE SOFTWARE. */ -// DS/SS frame generator with fixed fields: 8-byte header, 64-byte payload, -// 128-symbol spreading factor +// DS/SS frame generator with fixed fields: 8-byte header and 64-byte payload #include #include @@ -36,16 +35,19 @@ int dsssframe64gen_write(dsssframe64gen _q, float complex * _buf); struct dsssframe64gen_s { + unsigned int m; // filter delay (symbols) + float beta; // filter excess bandwidth factor + unsigned int sf; // spreading factor (fixed) + // objects qpacketmodem enc; // packet encoder/modulator qpilotgen pilotgen; // pilot symbol generator msequence ms; // spreading sequence generator + firinterp_crcf interp; // pulse-shaping filter/interpolator + // buffers float complex preamble_pn[1024]; // 1024-symbol p/n sequence unsigned char payload_dec[ 150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol float complex payload_sym[ 600]; // modulated payload symbols float complex payload_tx [ 650]; // modulated payload symbols with pilots - unsigned int m; // filter delay (symbols) - float beta; // filter excess bandwidth factor - firinterp_crcf interp; // pulse-shaping filter/interpolator }; // create dsssframe64gen object @@ -54,6 +56,7 @@ dsssframe64gen dsssframe64gen_create() dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); q->m = 15; q->beta = 0.20f; + q->sf = 128; // spreading factor unsigned int i; @@ -120,7 +123,7 @@ int dsssframe64gen_print(dsssframe64gen _q) // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) { - return 2*(1024 + 650*128 + 2*_q->m); + return 2*(1024 + 650*_q->sf + 2*_q->m); } // generate a frame @@ -172,7 +175,7 @@ int dsssframe64gen_write(dsssframe64gen _q, // frame payload for (i=0; i<650; i++) { float complex sym = _q->payload_tx[i]; // strip out raw payload symbol - for (j=0; j<128; j++) { + for (j=0; j<_q->sf; j++) { // generate pseudo-random symbol unsigned int p = msequence_generate_symbol(_q->ms, 2); float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 774ea087c..90c7b8da1 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -22,6 +22,8 @@ // basic direct sequence/spread spectrum frame synchronizer with 8 bytes header // and 64 bytes payload +// * reliable frame detection (1% missed) down to -14 dB SNR +// * reliable frame decoding (1% errors) down to -13 dB SNR #include #include @@ -53,6 +55,7 @@ struct dsssframe64sync_s { void * context; // user-defined data structure unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor + unsigned int sf; // spreading factor (fixed) framesyncstats_s framesyncstats;// frame statistic object (synchronizer) framedatastats_s framedatastats;// frame statistic object (packet statistics) @@ -90,6 +93,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, q->context = _context; q->m = 15; // filter delay (symbols) q->beta = 0.20f;// excess bandwidth factor + q->sf = 128; // spreading factor unsigned int i; @@ -268,29 +272,30 @@ int dsssframe64sync_step(dsssframe64sync _q, float complex * _buf, unsigned int _buf_len) { - // TODO: do this more efficiently? unsigned int i; for (i=0; i<_buf_len; i++) { - // receive preamble + // receive preamble (not currently used) if (_q->preamble_counter < 1024) { _q->preamble_rx[_q->preamble_counter++] = _buf[i]; continue; } - // generate pseudo-random symbol + // generate pseudo-random spreading symbol and de-spread chip unsigned int p = msequence_generate_symbol(_q->ms, 2); float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); _q->sym_despread += _buf[i] * conjf(s); _q->chip_counter++; - if (_q->chip_counter == 128) { - _q->payload_rx[_q->payload_counter] = _q->sym_despread / 128.0f; + // accumulate + if (_q->chip_counter == _q->sf) { + _q->payload_rx[_q->payload_counter] = _q->sym_despread / (float)(_q->sf); _q->payload_counter++; _q->chip_counter = 0; _q->sym_despread = 0; if (_q->payload_counter == 650) { dsssframe64sync_decode(_q); - return 1; // reset + msequence_reset(_q->ms); + return 1; // reset qdsync } } } @@ -328,7 +333,7 @@ int dsssframe64sync_decode(dsssframe64sync _q) if (_q->callback != NULL) { // offset estimates float dphi_hat = qdsync_cccf_get_dphi(_q->detector) + - qpilotsync_get_dphi(_q->pilotsync) / 128.0f; + qpilotsync_get_dphi(_q->pilotsync) / (float)(_q->sf); // set framesyncstats internals _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); From d5db0628046c0478669c8f28d227b5ea125c9c6c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 17:41:07 +0000 Subject: [PATCH 266/334] dsssframe64: allocating memory on heap --- examples/dsssframe64sync_example.c | 8 +++++--- examples/dsssframe64sync_performance_example.c | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index 161403462..8af35d0d6 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -44,8 +44,8 @@ int main(int argc, char *argv[]) // generate the frame in blocks unsigned int buf_len = dsssframe64gen_get_frame_len(fg); - float complex buf_tx[buf_len]; // transmit buffer - float complex buf_rx[buf_len]; // receive buffer (channel output) + float complex * buf_tx = (float complex *)malloc(buf_len*sizeof(float complex)); + float complex * buf_rx = (float complex *)malloc(buf_len*sizeof(float complex)); // export results to file FILE * fid = fopen(filename,"w"); @@ -88,8 +88,10 @@ int main(int argc, char *argv[]) fclose(fid); printf("results written to %s\n", filename); - // destroy allocated objects + // destroy allocated objects and free memory dsssframe64gen_destroy(fg); + free(buf_tx); + free(buf_rx); return 0; } diff --git a/examples/dsssframe64sync_performance_example.c b/examples/dsssframe64sync_performance_example.c index 841027b2d..c1aff359e 100644 --- a/examples/dsssframe64sync_performance_example.c +++ b/examples/dsssframe64sync_performance_example.c @@ -29,7 +29,7 @@ int main(int argc, char*argv[]) // create buffer for the frame samples unsigned int frame_len = dsssframe64gen_get_frame_len(fg); - float complex frame[frame_len]; + float complex * frame = (float complex *)malloc(frame_len*sizeof(float complex)); float SNRdB = -25.0f; FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); @@ -93,8 +93,9 @@ int main(int argc, char*argv[]) fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); - // clean up allocated objects + // clean up allocated objects and memory blocks dsssframe64gen_destroy(fg); dsssframe64sync_destroy(fs); + free(frame); return 0; } From 3b7828705568bbc5e72babf14a16a9b4e30456a5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 14:13:04 -0400 Subject: [PATCH 267/334] dsssframe64: reducing spreading factor from 128 to 80 * zero-padding transmit buffer to ensure entire frame gets through synchronizer * performance is limited by detection of 1024-chip preamble * could increase the preamble, but at the cost of increased computational complexity --- examples/dsssframe64sync_example.c | 2 +- src/framing/src/dsssframe64gen.c | 10 +++++++--- src/framing/src/dsssframe64sync.c | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/dsssframe64sync_example.c b/examples/dsssframe64sync_example.c index 8af35d0d6..62d844634 100644 --- a/examples/dsssframe64sync_example.c +++ b/examples/dsssframe64sync_example.c @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) { // options unsigned int nfft = 2400; - float SNRdB = -15.0f; + float SNRdB = -10.0f; const char * filename = "dsssframe64sync_example.m"; // create dsssframe64gen object diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 81042099b..52b4bc7d8 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -56,7 +56,7 @@ dsssframe64gen dsssframe64gen_create() dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); q->m = 15; q->beta = 0.20f; - q->sf = 128; // spreading factor + q->sf = 80; // spreading factor unsigned int i; @@ -123,7 +123,8 @@ int dsssframe64gen_print(dsssframe64gen _q) // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) { - return 2*(1024 + 650*_q->sf + 2*_q->m); + // add a small amount of zero-padding to ensure entire frame gets pushed through synchronizer + return 2*(1024 + 650*_q->sf + 2*_q->m) + 64; } // generate a frame @@ -190,7 +191,10 @@ int dsssframe64gen_write(dsssframe64gen _q, n+=2; } - assert(n==dsssframe64gen_get_frame_len(_q)); + // zero-pad end to ensure synchronizer can receive full payload + while (n < dsssframe64gen_get_frame_len(_q)) + _buf[n++] = 0; + return LIQUID_OK; } diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 90c7b8da1..30b87f435 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -23,7 +23,7 @@ // basic direct sequence/spread spectrum frame synchronizer with 8 bytes header // and 64 bytes payload // * reliable frame detection (1% missed) down to -14 dB SNR -// * reliable frame decoding (1% errors) down to -13 dB SNR +// * reliable frame decoding (1% errors) down to -11 dB SNR #include #include @@ -93,7 +93,7 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, q->context = _context; q->m = 15; // filter delay (symbols) q->beta = 0.20f;// excess bandwidth factor - q->sf = 128; // spreading factor + q->sf = 80; // spreading factor unsigned int i; From cdf0cdfab1b1560be20021c6b1b42cef59fcef32 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 14:47:22 -0400 Subject: [PATCH 268/334] dsssframe64: simplifying autotest --- src/framing/tests/dsssframe64sync_autotest.c | 36 ++++---------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/src/framing/tests/dsssframe64sync_autotest.c b/src/framing/tests/dsssframe64sync_autotest.c index b4b010700..4cacce731 100644 --- a/src/framing/tests/dsssframe64sync_autotest.c +++ b/src/framing/tests/dsssframe64sync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,49 +27,26 @@ #include "autotest/autotest.h" #include "liquid.h" -static int callback_dsssframe64sync_autotest( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _userdata) -{ - //printf("callback invoked, payload valid: %s\n", _payload_valid ? "yes" : "no"); - int * frames_recovered = (int*) _userdata; - - *frames_recovered += _header_valid && _payload_valid ? 1 : 0; - return 0; -} - // AUTOTEST : test simple recovery of frame in noise void autotest_dsssframe64sync() { - unsigned int i; - int frames_recovered = 0; - // create objects - dsssframe64gen fg = dsssframe64gen_create(); - dsssframe64sync fs = dsssframe64sync_create(callback_dsssframe64sync_autotest, - (void*)&frames_recovered); - dsssframe64sync_set_threshold(fs, 0.5f); + dsssframe64gen fg = dsssframe64gen_create(); + dsssframe64sync fs = dsssframe64sync_create(NULL, NULL); // generate the frame unsigned int frame_len = dsssframe64gen_get_frame_len(fg); - float complex frame[frame_len]; + float complex * frame = (float complex *)malloc(frame_len*sizeof(float complex)); dsssframe64gen_execute(fg, NULL, NULL, frame); // add some noise + unsigned int i; for (i=0; i Date: Sun, 17 Mar 2024 14:55:08 -0400 Subject: [PATCH 269/334] qdsync: removing low default threshold; causing tests to fail --- src/framing/src/qdsync.proto.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index afb917844..aee476f08 100644 --- a/src/framing/src/qdsync.proto.c +++ b/src/framing/src/qdsync.proto.c @@ -118,7 +118,6 @@ QDSYNC() QDSYNC(_create_linear)(TI * _seq, QDSYNC(_set_context )(q, _context ); // reset and return object - QDSYNC(_set_threshold)(q, 0.05f); // TODO: set threshold appropriate to sequence length QDSYNC(_reset)(q); return q; } From b4c9076f72aca737dec8be01201dcf7630ac6ebc Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 14:55:49 -0400 Subject: [PATCH 270/334] dsssframe64: renaming autotest --- makefile.in | 2 +- .../{dsssframe64sync_autotest.c => dsssframe64_autotest.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/framing/tests/{dsssframe64sync_autotest.c => dsssframe64_autotest.c} (100%) diff --git a/makefile.in b/makefile.in index 3b88e2892..0d5e2205f 100644 --- a/makefile.in +++ b/makefile.in @@ -682,7 +682,7 @@ framing_autotests := \ src/framing/tests/bpacketsync_autotest.c \ src/framing/tests/bsync_autotest.c \ src/framing/tests/detector_autotest.c \ - src/framing/tests/dsssframe64sync_autotest.c \ + src/framing/tests/dsssframe64_autotest.c \ src/framing/tests/dsssframesync_autotest.c \ src/framing/tests/flexframesync_autotest.c \ src/framing/tests/framesync64_autotest.c \ diff --git a/src/framing/tests/dsssframe64sync_autotest.c b/src/framing/tests/dsssframe64_autotest.c similarity index 100% rename from src/framing/tests/dsssframe64sync_autotest.c rename to src/framing/tests/dsssframe64_autotest.c From c4595edd1595e9d06e017037cbe56f7f1a255054 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 15:05:19 -0400 Subject: [PATCH 271/334] dsssframe64: adding interface for copy() methods, basic config testing --- include/liquid.h | 7 +++++++ src/framing/src/dsssframe64gen.c | 1 + src/framing/src/dsssframe64sync.c | 4 +++- src/framing/tests/dsssframe64_autotest.c | 24 ++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index d80ca92c8..71cc25592 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6003,6 +6003,9 @@ typedef struct dsssframe64gen_s * dsssframe64gen; // create dsssframe64gen object dsssframe64gen dsssframe64gen_create(); +// copy object +dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig); + // destroy dsssframe64gen object int dsssframe64gen_destroy(dsssframe64gen _q); @@ -6029,6 +6032,10 @@ unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); typedef struct dsssframe64sync_s * dsssframe64sync; dsssframe64sync dsssframe64sync_create(framesync_callback _callback, void * _userdata); + +// copy object +dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig); + int dsssframe64sync_destroy (dsssframe64sync _q); int dsssframe64sync_print (dsssframe64sync _q); int dsssframe64sync_reset (dsssframe64sync _q); diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 52b4bc7d8..9cf3a137a 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -96,6 +96,7 @@ dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig) return liquid_error_config("dsssframe64gen_copy(), object cannot be NULL"); // not yet implemented + liquid_error(LIQUID_ENOIMP, "dsssframe64gen_copy(), method not yet implemented"); return NULL; } diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 30b87f435..56bb6c92d 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -158,7 +158,9 @@ dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) return q_copy; #else - return liquid_error_config("dsssframe64sync_copy(), method not yet implemented"); + // not yet implemented + liquid_error(LIQUID_ENOIMP, "dsssframe64sync_copy(), method not yet implemented"); + return NULL; #endif } diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index 4cacce731..c6ed61518 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -60,3 +60,27 @@ void autotest_dsssframe64sync() free(frame); } +// test errors and invalid configuration +void autotest_dsssframe64_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping dsssframe64 config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // test copying/creating invalid objects + CONTEND_ISNULL( dsssframe64gen_copy(NULL) ); + CONTEND_ISNULL( dsssframe64sync_copy(NULL) ); + + // create valid objects + dsssframe64gen fg = dsssframe64gen_create(); + dsssframe64sync fs = dsssframe64sync_create(NULL, NULL); + CONTEND_EQUALITY( LIQUID_OK, dsssframe64gen_print(fg) ); + CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_print(fs) ); + + dsssframe64gen_destroy(fg); + dsssframe64sync_destroy(fs); +} + From 0172300a191b2b509e33e846b7800daf8be85561 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 16:23:58 -0400 Subject: [PATCH 272/334] qdsync,qdetector: adding methods to get frequency offset range --- include/liquid.h | 10 ++++++++-- src/framing/src/qdetector.proto.c | 8 +++++++- src/framing/src/qdsync.proto.c | 6 ++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index bde0af9c7..55c22467a 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6344,11 +6344,14 @@ void * QDETECTOR(_execute)(QDETECTOR() _q, TI _x); \ /* get detection threshold */ \ float QDETECTOR(_get_threshold)(QDETECTOR() _q); \ \ -/* set detection threshold (should be between 0 and 1, good starting */ \ +/* Set detection threshold (should be between 0 and 1, good starting */ \ /* point is 0.5) */ \ int QDETECTOR(_set_threshold)(QDETECTOR() _q, \ float _threshold); \ \ +/* Get carrier offset search range */ \ +float QDETECTOR(_get_range)(QDETECTOR() _q); \ + \ /* Set carrier offset search range */ \ int QDETECTOR(_set_range)(QDETECTOR() _q, \ float _dphi_max); \ @@ -6444,7 +6447,10 @@ float QDSYNC(_get_threshold)(QDSYNC() _q); \ int QDSYNC(_set_threshold)(QDSYNC() _q, \ float _threshold); \ \ -/* set carrier offset search range */ \ +/* Get carrier offset search range */ \ +float QDSYNC(_get_range)(QDSYNC() _q); \ + \ +/* Set carrier offset search range */ \ int QDSYNC(_set_range)(QDSYNC() _q, \ float _dphi_max); \ \ diff --git a/src/framing/src/qdetector.proto.c b/src/framing/src/qdetector.proto.c index 5c13f45eb..4511ea018 100644 --- a/src/framing/src/qdetector.proto.c +++ b/src/framing/src/qdetector.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -380,6 +380,12 @@ int QDETECTOR(_set_threshold)(QDETECTOR() _q, return LIQUID_OK; } +// get carrier offset search range +float QDETECTOR(_get_range)(QDETECTOR() _q) +{ + return _q->range; +} + // set carrier offset search range int QDETECTOR(_set_range)(QDETECTOR() _q, float _dphi_max) diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index aee476f08..0ec0877f6 100644 --- a/src/framing/src/qdsync.proto.c +++ b/src/framing/src/qdsync.proto.c @@ -198,6 +198,12 @@ int QDSYNC(_set_threshold)(QDSYNC() _q, float _threshold) return QDETECTOR(_set_threshold)(_q->detector, _threshold); } +// get carrier offset search range +float QDSYNC(_get_range)(QDSYNC() _q) +{ + return QDETECTOR(_get_range)(_q->detector); +} + // set carrier offset search range int QDSYNC(_set_range)(QDSYNC() _q, float _dphi_max) { From f8a3418bb054cf1a7a6c70f746fd65c261d31bc1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 16:29:02 -0400 Subject: [PATCH 273/334] dsssframe64: adding methods to get/set threshold/range, tests --- include/liquid.h | 3 +++ src/framing/src/dsssframe64sync.c | 18 ++++++++++++------ src/framing/tests/dsssframe64_autotest.c | 11 +++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 6310ea9ee..0bd70aeba 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -6057,6 +6057,9 @@ float dsssframe64sync_get_threshold(dsssframe64sync _q); int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold); +// get carrier offset search range [radians/sample] +float dsssframe64sync_get_range(dsssframe64sync _q); + // set carrier offset search range int dsssframe64sync_set_range(dsssframe64sync _q, float _dphi_max); diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 56bb6c92d..9d0164b6d 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -237,12 +237,6 @@ int dsssframe64sync_execute(dsssframe64sync _q, return qdsync_cccf_execute(_q->detector, _buf, _buf_len); } -// get detection threshold -float dsssframe64sync_get_threshold(dsssframe64sync _q) -{ - return qdsync_cccf_get_threshold(_q->detector); -} - // set detection threshold int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold) @@ -250,6 +244,12 @@ int dsssframe64sync_set_threshold(dsssframe64sync _q, return qdsync_cccf_set_threshold(_q->detector, _threshold); } +// get detection threshold +float dsssframe64sync_get_threshold(dsssframe64sync _q) +{ + return qdsync_cccf_get_threshold(_q->detector); +} + // set carrier offset search range int dsssframe64sync_set_range(dsssframe64sync _q, float _dphi_max) @@ -257,6 +257,12 @@ int dsssframe64sync_set_range(dsssframe64sync _q, return qdsync_cccf_set_range(_q->detector, _dphi_max); } +// get detection threshold +float dsssframe64sync_get_range(dsssframe64sync _q) +{ + return qdsync_cccf_get_range(_q->detector); +} + // reset frame data statistics int dsssframe64sync_reset_framedatastats(dsssframe64sync _q) { diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index c6ed61518..03707fcc3 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -80,6 +80,17 @@ void autotest_dsssframe64_config() CONTEND_EQUALITY( LIQUID_OK, dsssframe64gen_print(fg) ); CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_print(fs) ); + // synchronizer parameters + CONTEND_EQUALITY( 0, dsssframe64sync_is_frame_open(fs) ); + CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_set_callback(fs, NULL) ); + CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_set_context (fs, NULL) ); + float threshold = 0.123f; + CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_set_threshold(fs, threshold) ); + CONTEND_EQUALITY( threshold, dsssframe64sync_get_threshold(fs) ); + float range = 0.00722f; + CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_set_range(fs, range) ); + //CONTEND_EQUALITY( range, dsssframe64sync_get_range(fs) ); + dsssframe64gen_destroy(fg); dsssframe64sync_destroy(fs); } From 466b6fb4192471fe76c0df6f9d58e032e8392739 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 20:55:39 -0400 Subject: [PATCH 274/334] msequence: adding copy() method --- include/liquid.h | 3 +++ src/sequence/src/msequence.c | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/liquid.h b/include/liquid.h index 0bd70aeba..3e9fc288c 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -9789,6 +9789,9 @@ msequence msequence_create(unsigned int _m, unsigned int _g, unsigned int _a); +// Copy maximal-length sequence (m-sequence) object +msequence msequence_copy(msequence q_orig); + // create a maximal-length sequence (m-sequence) object from a generator polynomial msequence msequence_create_genpoly(unsigned int _g); diff --git a/src/sequence/src/msequence.c b/src/sequence/src/msequence.c index ecad555ff..fe0ae1a9b 100644 --- a/src/sequence/src/msequence.c +++ b/src/sequence/src/msequence.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -71,6 +71,18 @@ msequence msequence_create(unsigned int _m, return ms; } +// Copy maximal-length sequence (m-sequence) object +msequence msequence_copy(msequence q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("msequence_copy(), object cannot be NULL"); + + // create filter object and copy base parameters + msequence q_copy = (msequence) malloc(sizeof(struct msequence_s)); + memmove(q_copy, q_orig, sizeof(struct msequence_s)); + return q_copy; +} // create a maximal-length sequence (m-sequence) object from a generator polynomial msequence msequence_create_genpoly(unsigned int _g) From d84f50dde482374da3efe03a00ed6c792e2534d9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 21:01:50 -0400 Subject: [PATCH 275/334] dsssframe64: adding copy() method, test --- src/framing/src/dsssframe64gen.c | 13 +++++++--- src/framing/tests/dsssframe64_autotest.c | 31 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/framing/src/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c index 9cf3a137a..4fd6f3e9c 100644 --- a/src/framing/src/dsssframe64gen.c +++ b/src/framing/src/dsssframe64gen.c @@ -95,9 +95,16 @@ dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig) if (q_orig == NULL) return liquid_error_config("dsssframe64gen_copy(), object cannot be NULL"); - // not yet implemented - liquid_error(LIQUID_ENOIMP, "dsssframe64gen_copy(), method not yet implemented"); - return NULL; + // create filter object and copy base parameters + dsssframe64gen q_copy = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); + memmove(q_copy, q_orig, sizeof(struct dsssframe64gen_s)); + + // copy objects + q_copy->enc = qpacketmodem_copy (q_orig->enc ); + q_copy->pilotgen = qpilotgen_copy (q_orig->pilotgen); + q_copy->ms = msequence_copy (q_orig->ms ); + q_copy->interp = firinterp_crcf_copy(q_orig->interp ); + return q_copy; } // destroy dsssframe64gen object diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index 03707fcc3..747eb8720 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -95,3 +95,34 @@ void autotest_dsssframe64_config() dsssframe64sync_destroy(fs); } +// test that the complete internal state of one generator can be copied to a new +// object +void autotest_dsssframe64gen_copy() +{ + // create object and copy + dsssframe64gen q0 = dsssframe64gen_create(); + dsssframe64gen q1 = dsssframe64gen_copy(q0); + + // allocate buffers for frames + unsigned int frame_len = dsssframe64gen_get_frame_len(q0); + float complex * buf_0 = (float complex *)malloc(frame_len*sizeof(float complex)); + float complex * buf_1 = (float complex *)malloc(frame_len*sizeof(float complex)); + unsigned char header [ 8] = {0,0,0,0,0,0,0,0,}; + unsigned char payload[64] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}; + + // encode + dsssframe64gen_execute(q0, header, payload, buf_0); + dsssframe64gen_execute(q1, header, payload, buf_1); + + // ensure identical outputs + CONTEND_SAME_DATA(buf_0, buf_1, frame_len*sizeof(float complex)); + + // destroy objects and free memory + dsssframe64gen_destroy(q0); + dsssframe64gen_destroy(q1); + free(buf_0); + free(buf_1); +} + From afa0d80b95cc3992bfafc881e1a94200965614b9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 17 Mar 2024 21:46:29 -0400 Subject: [PATCH 276/334] dsssframe64sync: addinf copy() method, tests --- src/framing/src/dsssframe64sync.c | 25 ++++++------ src/framing/tests/dsssframe64_autotest.c | 49 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/framing/src/dsssframe64sync.c b/src/framing/src/dsssframe64sync.c index 9d0164b6d..27a84e620 100644 --- a/src/framing/src/dsssframe64sync.c +++ b/src/framing/src/dsssframe64sync.c @@ -136,7 +136,6 @@ dsssframe64sync dsssframe64sync_create(framesync_callback _callback, // copy object dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) { -#if 0 // validate input if (q_orig == NULL) return liquid_error_config("dsssframe64sync_copy(), object cannot be NULL"); @@ -147,21 +146,16 @@ dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) // copy entire memory space over and overwrite values as needed memmove(q_copy, q_orig, sizeof(struct dsssframe64sync_s)); - // set callback and context fields - q_copy->callback = q_orig->callback; - q_copy->context = q_orig->context; + // copy internal objects + q_copy->detector = qdsync_cccf_copy (q_orig->detector); + q_copy->ms = msequence_copy (q_orig->ms); + q_copy->dec = qpacketmodem_copy(q_orig->dec); + q_copy->pilotsync = qpilotsync_copy (q_orig->pilotsync); - // copy objects - q_copy->detector = qdsync_cccf_copy(q_orig->detector); - q_copy->dec = qpacketmodem_copy (q_orig->dec); - q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); + // update detector callback's context to use q_copy + qdsync_cccf_set_context(q_copy->detector, (void*)q_copy); return q_copy; -#else - // not yet implemented - liquid_error(LIQUID_ENOIMP, "dsssframe64sync_copy(), method not yet implemented"); - return NULL; -#endif } // destroy frame synchronizer object, freeing all internal memory @@ -181,7 +175,10 @@ int dsssframe64sync_destroy(dsssframe64sync _q) // print frame synchronizer object internals int dsssframe64sync_print(dsssframe64sync _q) { - printf("\n"); + printf("\n", + _q->preamble_counter, + _q->chip_counter, + _q->payload_counter); return LIQUID_OK; } diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index 747eb8720..cfe7ae752 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -126,3 +126,52 @@ void autotest_dsssframe64gen_copy() free(buf_1); } +// test that the complete internal state of one synchronizer can be copied to a new +// object and it can maintain state +void autotest_dsssframe64sync_copy() +{ + // create object and generte frame + dsssframe64gen fg = dsssframe64gen_create(); + unsigned int frame_len = dsssframe64gen_get_frame_len(fg); + float complex * frame= (float complex *)malloc(frame_len*sizeof(float complex)); + dsssframe64gen_execute(fg, NULL, NULL, frame); + + // creamte original frame synchronizer + dsssframe64sync q0 = dsssframe64sync_create(NULL, NULL); + + // run half of frame through synchronizer + unsigned int n = 12000; + dsssframe64sync_execute(q0, frame, n); + + // ensure frame was not yet decoded + framedatastats_s s0, s1; + s0 = dsssframe64sync_get_framedatastats(q0); + CONTEND_EQUALITY(s0.num_frames_detected, 0); + + // copy object + dsssframe64sync q1 = dsssframe64sync_copy(q0); + + // run remaining half of frame through synchronizers + dsssframe64sync_execute(q0, frame+n, frame_len-n); + dsssframe64sync_execute(q1, frame+n, frame_len-n); + + // ensure frame was decoded by both synchronizers + s0 = dsssframe64sync_get_framedatastats(q0); + CONTEND_EQUALITY(s0.num_frames_detected, 1); + CONTEND_EQUALITY(s0.num_headers_valid, 1); + CONTEND_EQUALITY(s0.num_payloads_valid, 1); + CONTEND_EQUALITY(s0.num_bytes_received, 64); + + s1 = dsssframe64sync_get_framedatastats(q1); + CONTEND_EQUALITY(s1.num_frames_detected, 1); + CONTEND_EQUALITY(s1.num_headers_valid, 1); + CONTEND_EQUALITY(s1.num_payloads_valid, 1); + CONTEND_EQUALITY(s1.num_bytes_received, 64); + + // destroy objects and free memory + dsssframe64gen_destroy(fg); + dsssframe64sync_destroy(q0); + dsssframe64sync_destroy(q1); + free(frame); +} + From 8d75f5082ab9ce4967764095004522e53177d6de Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 18 Mar 2024 08:11:54 -0400 Subject: [PATCH 277/334] dsssframe64: ensuring callback was invoked in synchronizer --- src/framing/tests/dsssframe64_autotest.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index cfe7ae752..31acf9877 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -27,12 +27,28 @@ #include "autotest/autotest.h" #include "liquid.h" -// AUTOTEST : test simple recovery of frame in noise +// static callback function +static int framing_autotest_callback( + unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _context) +{ + printf("*** callback invoked (%s) ***\n", _payload_valid ? "pass" : "FAIL"); + unsigned int * secret = (unsigned int*) _context; + *secret = 0x01234567; + return 0; +} + void autotest_dsssframe64sync() { // create objects + unsigned int context = 0; dsssframe64gen fg = dsssframe64gen_create(); - dsssframe64sync fs = dsssframe64sync_create(NULL, NULL); + dsssframe64sync fs = dsssframe64sync_create(framing_autotest_callback, (void*)&context); // generate the frame unsigned int frame_len = dsssframe64gen_get_frame_len(fg); @@ -47,6 +63,9 @@ void autotest_dsssframe64sync() // try to receive the frame dsssframe64sync_execute(fs, frame, frame_len); + // ensure callback was invoked + CONTEND_EQUALITY(context, 0x01234567); + // parse statistics framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); CONTEND_EQUALITY(stats.num_frames_detected, 1); From a39faff107a11e592b5146b25561e878b10f98e4 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 18 Mar 2024 17:24:13 -0400 Subject: [PATCH 278/334] qdetector: storing internal frequency offset range --- src/framing/src/qdetector.proto.c | 13 ++++++++----- src/framing/tests/dsssframe64_autotest.c | 2 +- src/framing/tests/qdsync_cccf_autotest.c | 6 +++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/framing/src/qdetector.proto.c b/src/framing/src/qdetector.proto.c index 4511ea018..5128adb0e 100644 --- a/src/framing/src/qdetector.proto.c +++ b/src/framing/src/qdetector.proto.c @@ -57,6 +57,7 @@ struct QDETECTOR(_s) { unsigned int counter; // sample counter for determining when to compute FFTs float threshold; // detection threshold + float dphi_max; // carrier offset search range (radians/sample) int range; // carrier offset search range (subcarriers) unsigned int num_transforms; // number of transforms taken (debugging) @@ -287,6 +288,7 @@ QDETECTOR() QDETECTOR(_copy)(QDETECTOR() q_orig) // copy internal state q_copy->counter = q_orig->counter; q_copy->threshold = q_orig->threshold; + q_copy->dphi_max = q_orig->dphi_max; q_copy->range = q_orig->range; q_copy->num_transforms = q_orig->num_transforms; // buffer power magnitude @@ -324,7 +326,7 @@ int QDETECTOR(_print)(QDETECTOR() _q) printf("qdetector_%s:\n", EXTENSION_FULL); printf(" template length (time): %-u\n", _q->s_len); printf(" FFT size : %-u\n", _q->nfft); - printf(" search range (bins) : %-d\n", _q->range); + printf(" search range : %g [radians/sample], %-d [bins]\n",_q->dphi_max, _q->range); printf(" detection threshold : %6.4f\n", _q->threshold); printf(" sum{ s^2 } : %.2f\n", _q->s2_sum); return LIQUID_OK; @@ -383,19 +385,20 @@ int QDETECTOR(_set_threshold)(QDETECTOR() _q, // get carrier offset search range float QDETECTOR(_get_range)(QDETECTOR() _q) { - return _q->range; + return _q->dphi_max; } // set carrier offset search range int QDETECTOR(_set_range)(QDETECTOR() _q, - float _dphi_max) + float _dphi_max) { if (_dphi_max < 0.0f || _dphi_max > 0.5f) return liquid_error(LIQUID_EICONFIG,"carrier offset search range (%12.4e) out of range; ignoring", _dphi_max); // set internal search range - _q->range = (int)(_dphi_max * _q->nfft / (2*M_PI)); - _q->range = _q->range < 0 ? 0 : _q->range; + _q->dphi_max = _dphi_max; + _q->range = (int)(_q->dphi_max * _q->nfft / (2*M_PI)); + _q->range = _q->range < 0 ? 0 : _q->range; //printf("range: %d / %u\n", _q->range, _q->nfft); return LIQUID_OK; } diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index 31acf9877..030e7abf1 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -108,7 +108,7 @@ void autotest_dsssframe64_config() CONTEND_EQUALITY( threshold, dsssframe64sync_get_threshold(fs) ); float range = 0.00722f; CONTEND_EQUALITY( LIQUID_OK, dsssframe64sync_set_range(fs, range) ); - //CONTEND_EQUALITY( range, dsssframe64sync_get_range(fs) ); + CONTEND_EQUALITY( range, dsssframe64sync_get_range(fs) ); dsssframe64gen_destroy(fg); dsssframe64sync_destroy(fs); diff --git a/src/framing/tests/qdsync_cccf_autotest.c b/src/framing/tests/qdsync_cccf_autotest.c index 1e1c59eaf..443642399 100644 --- a/src/framing/tests/qdsync_cccf_autotest.c +++ b/src/framing/tests/qdsync_cccf_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -325,6 +325,10 @@ void autotest_qdsync_cccf_config() CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_set_threshold(q,0.654321f)) CONTEND_EQUALITY(0.654321f, qdsync_cccf_get_threshold(q)) + // set/get range + CONTEND_EQUALITY(LIQUID_OK, qdsync_cccf_set_range(q,0.007220f)) + CONTEND_EQUALITY(0.007220f, qdsync_cccf_get_range(q)) + // set invalid buffer length CONTEND_INEQUALITY(LIQUID_OK, qdsync_cccf_set_buf_len(q,0)) From 966c26be89c69ae52ab18257ad06e3207006f386 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Mon, 18 Mar 2024 17:58:41 -0400 Subject: [PATCH 279/334] framing/autotest: using consistent internal callback --- autotest/autotest.c | 18 ++++++++- autotest/autotest.h | 13 ++++++- src/framing/tests/dsssframe64_autotest.c | 18 +-------- src/framing/tests/dsssframesync_autotest.c | 27 ++------------ src/framing/tests/flexframesync_autotest.c | 8 +++- src/framing/tests/framesync64_autotest.c | 43 +++++++--------------- src/framing/tests/fskframesync_autotest.c | 25 +++---------- src/framing/tests/gmskframe_autotest.c | 29 ++------------- src/framing/tests/ofdmflexframe_autotest.c | 9 ++++- 9 files changed, 69 insertions(+), 121 deletions(-) diff --git a/autotest/autotest.c b/autotest/autotest.c index 78a62a529..ccd3cb785 100644 --- a/autotest/autotest.c +++ b/autotest/autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -362,3 +362,19 @@ int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nff return liquid_autotest_validate_spectrum(psd,_nfft,_regions,num_regions,debug_filename); } +// callback function to simplify testing for framing objects +int framing_autotest_callback( + unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _context) +{ + printf("*** callback invoked (%s) ***\n", _payload_valid ? "pass" : "FAIL"); + unsigned int * secret = (unsigned int*) _context; + *secret = FRAMING_AUTOTEST_SECRET; + return 0; +} + diff --git a/autotest/autotest.h b/autotest/autotest.h index 148a50311..5945ab5e2 100644 --- a/autotest/autotest.h +++ b/autotest/autotest.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -316,5 +316,16 @@ int liquid_autotest_validate_psd_firfilt_cccf(firfilt_cccf _q, unsigned int _nff int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); +// callback function to simplify testing for framing objects +#define FRAMING_AUTOTEST_SECRET 0x01234567 +int framing_autotest_callback( + unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _context); + #endif // __LIQUID_AUTOTEST_H__ diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c index 030e7abf1..f8b14490a 100644 --- a/src/framing/tests/dsssframe64_autotest.c +++ b/src/framing/tests/dsssframe64_autotest.c @@ -27,22 +27,6 @@ #include "autotest/autotest.h" #include "liquid.h" -// static callback function -static int framing_autotest_callback( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _context) -{ - printf("*** callback invoked (%s) ***\n", _payload_valid ? "pass" : "FAIL"); - unsigned int * secret = (unsigned int*) _context; - *secret = 0x01234567; - return 0; -} - void autotest_dsssframe64sync() { // create objects @@ -64,7 +48,7 @@ void autotest_dsssframe64sync() dsssframe64sync_execute(fs, frame, frame_len); // ensure callback was invoked - CONTEND_EQUALITY(context, 0x01234567); + CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); // parse statistics framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); diff --git a/src/framing/tests/dsssframesync_autotest.c b/src/framing/tests/dsssframesync_autotest.c index bb8234c8c..1ef54d4d1 100644 --- a/src/framing/tests/dsssframesync_autotest.c +++ b/src/framing/tests/dsssframesync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,25 +26,6 @@ #include "autotest/autotest.h" #include "liquid.h" -static int callback_dsssframe( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _userdata) -{ - printf("*** dsssframe callback invoked ***\n"); - framesyncstats_print(&_stats); - if (_payload_valid) - *((int*)_userdata) = 1; // success - return 0; -} - -// -// AUTOTEST : test simple recovery of frame in noise -// void autotest_dsssframesync() { unsigned int _payload_len = 400; @@ -60,8 +41,8 @@ void autotest_dsssframesync() dsssframegen_assemble(fg, NULL, NULL, _payload_len); // create dsssframesync object - int success = 0; - dsssframesync fs = dsssframesync_create(callback_dsssframe,(void*)&success); + unsigned int context = 0; + dsssframesync fs = dsssframesync_create(framing_autotest_callback, (void*)&context); // generate the frame int frame_complete = 0; @@ -87,7 +68,7 @@ void autotest_dsssframesync() CONTEND_EQUALITY( stats.num_payloads_valid, 1 ); CONTEND_EQUALITY( stats.num_bytes_received, _payload_len ); #endif - CONTEND_EQUALITY( success, 1 ); + CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); // destroy objects dsssframegen_destroy(fg); diff --git a/src/framing/tests/flexframesync_autotest.c b/src/framing/tests/flexframesync_autotest.c index f5e984ed4..a7546fed6 100644 --- a/src/framing/tests/flexframesync_autotest.c +++ b/src/framing/tests/flexframesync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,8 @@ void autotest_flexframesync() flexframegen fg = flexframegen_create(&fgprops); // create flexframesync object - flexframesync fs = flexframesync_create(NULL,NULL); + unsigned int context = 0; + flexframesync fs = flexframesync_create(framing_autotest_callback, (void*)&context); // initialize header and payload unsigned char header[14] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; @@ -78,6 +79,9 @@ void autotest_flexframesync() if (liquid_autotest_verbose) flexframesync_print(fs); + // ensure callback was invoked + CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); + // check to see that frame was recovered CONTEND_EQUALITY( stats.num_frames_detected, 1 ); CONTEND_EQUALITY( stats.num_headers_valid, 1 ); diff --git a/src/framing/tests/framesync64_autotest.c b/src/framing/tests/framesync64_autotest.c index 7a1b78cc7..6393fe2c7 100644 --- a/src/framing/tests/framesync64_autotest.c +++ b/src/framing/tests/framesync64_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,30 +27,15 @@ #include "autotest/autotest.h" #include "liquid.h" -static int callback_framesync64_autotest( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _userdata) -{ - //printf("callback invoked, payload valid: %s\n", _payload_valid ? "yes" : "no"); - *((int*)(_userdata)) += _header_valid && _payload_valid ? 1 : 0; - return 0; -} - // AUTOTEST : test simple recovery of frame in noise void autotest_framesync64() { unsigned int i; - int frames_recovered = 0; // create objects + unsigned int context = 0; framegen64 fg = framegen64_create(); - framesync64 fs = framesync64_create(callback_framesync64_autotest, - (void*)&frames_recovered); + framesync64 fs = framesync64_create(framing_autotest_callback, (void*)&context); // generate the frame float complex frame[LIQUID_FRAME64_LEN]; @@ -63,8 +48,8 @@ void autotest_framesync64() // try to receive the frame framesync64_execute(fs, frame, LIQUID_FRAME64_LEN); - // check to see that exactly one frame was recovered - CONTEND_EQUALITY( frames_recovered, 1 ); + // ensure callback was actually invoked + CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); // parse statistics framedatastats_s stats = framesync64_get_framedatastats(fs); @@ -97,13 +82,12 @@ void autotest_framegen64_copy() void autotest_framesync64_copy() { unsigned int i; - int frames_recovered_0 = 0; - int frames_recovered_1 = 0; + int context_0 = 0; + int context_1 = 0; // create objects framegen64 fg = framegen64_create(); - framesync64 fs0 = framesync64_create(callback_framesync64_autotest, - (void*)&frames_recovered_0); + framesync64 fs0 = framesync64_create(framing_autotest_callback, (void*)&context_0); // feed random samples into synchronizer float complex buf[LIQUID_FRAME64_LEN]; @@ -120,7 +104,7 @@ void autotest_framesync64_copy() // copy object, but set different context framesync64 fs1 = framesync64_copy(fs0); - framesync64_set_userdata(fs1, (void*)&frames_recovered_1); + framesync64_set_userdata(fs1, (void*)&context_1); framesync64_print(fs0); framesync64_print(fs1); @@ -131,12 +115,12 @@ void autotest_framesync64_copy() framesync64_execute(fs1, buf+i, 1); // ensure that the frames are recovered at exactly the same time - CONTEND_EQUALITY( frames_recovered_0, frames_recovered_1 ); + CONTEND_EQUALITY( context_0, context_1 ); } // check that frame was actually recovered by each object - CONTEND_EQUALITY( frames_recovered_0, 1 ); - CONTEND_EQUALITY( frames_recovered_1, 1 ); + CONTEND_EQUALITY( context_0, 0x01234567 ); + CONTEND_EQUALITY( context_1, 0x01234567 ); // parse statistics framedatastats_s stats_0 = framesync64_get_framedatastats(fs0); @@ -174,13 +158,12 @@ void autotest_framesync64_config() framesync64 q = framesync64_create(NULL, NULL); CONTEND_EQUALITY(LIQUID_OK, framesync64_print(q)) - CONTEND_EQUALITY(LIQUID_OK, framesync64_set_callback(q,callback_framesync64_autotest)) + CONTEND_EQUALITY(LIQUID_OK, framesync64_set_callback(q,NULL)) CONTEND_EQUALITY(LIQUID_OK, framesync64_set_userdata(q,NULL)) CONTEND_EQUALITY(LIQUID_OK, framesync64_set_threshold(q,0.654321f)) CONTEND_EQUALITY(0.654321f, framesync64_get_threshold(q)) - framesync64_destroy(q); } diff --git a/src/framing/tests/fskframesync_autotest.c b/src/framing/tests/fskframesync_autotest.c index 9ffbef087..941e4d698 100644 --- a/src/framing/tests/fskframesync_autotest.c +++ b/src/framing/tests/fskframesync_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,20 +27,6 @@ #include "autotest/autotest.h" #include "liquid.h" -static int callback_fskframesync_autotest( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _userdata) -{ - //printf("callback invoked, payload valid: %s\n", _payload_valid ? "yes" : "no"); - *((int*)(_userdata)) += _header_valid && _payload_valid ? 1 : 0; - return 0; -} - // AUTOTEST : test simple recovery of frame in noise void autotest_fskframesync() { @@ -60,12 +46,11 @@ void autotest_fskframesync() float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain unsigned int i; - int frames_recovered = 0; + unsigned int context = 0; // create objects fskframegen fg = fskframegen_create(); - fskframesync fs = fskframesync_create(callback_fskframesync_autotest, - (void*)&frames_recovered); + fskframesync fs = fskframesync_create(framing_autotest_callback, (void*)&context); // assemble the frame unsigned char header [ 8]; @@ -94,8 +79,8 @@ void autotest_fskframesync() fskframesync_execute_block(fs, buf_rx, buf_len); } - // check to see that exactly one frame was recovered - CONTEND_EQUALITY( frames_recovered, 1 ); + // check to see that callback was invoked + CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); #if 0 // parse statistics diff --git a/src/framing/tests/gmskframe_autotest.c b/src/framing/tests/gmskframe_autotest.c index aacc80182..41d9db5c4 100644 --- a/src/framing/tests/gmskframe_autotest.c +++ b/src/framing/tests/gmskframe_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,26 +26,6 @@ #include "autotest/autotest.h" #include "liquid.h" -static int gmskframesync_autotest_callback( - unsigned char * _header, - int _header_valid, - unsigned char * _payload, - unsigned int _payload_len, - int _payload_valid, - framesyncstats_s _stats, - void * _userdata) -{ - // check data - unsigned int * secret = (unsigned int*) _userdata; - unsigned int i, num_errors = 0; - for (i=0; i<8; i++) - num_errors += _header[i] != i; - for (i=0; i<_payload_len; i++) - num_errors += _payload[i] != (i & 0xff); - *secret = num_errors == 0 ? 0x01234567 : 0; - return 0; -} - // test simple recovery of GMSK frame void autotest_gmskframesync_process() { @@ -54,14 +34,13 @@ void autotest_gmskframesync_process() crc_scheme crc = LIQUID_CRC_32; fec_scheme fec0 = LIQUID_FEC_NONE; fec_scheme fec1 = LIQUID_FEC_NONE; - unsigned int secret = 0; // placeholder for secret return value + unsigned int context = 0; // create objects gmskframegen fg = gmskframegen_create(); // create frame synchronizer - gmskframesync fs = gmskframesync_create( - gmskframesync_autotest_callback,(void*)&secret); + gmskframesync fs = gmskframesync_create(framing_autotest_callback, (void*)&context); if (liquid_autotest_verbose) { gmskframegen_print(fg); @@ -91,7 +70,7 @@ void autotest_gmskframesync_process() CONTEND_EQUALITY( gmskframesync_is_frame_open(fs), 0 ); // check to see that frame was recovered - CONTEND_EQUALITY( secret, 0x01234567 ); + CONTEND_EQUALITY( context, FRAMING_AUTOTEST_SECRET ); // parse statistics framedatastats_s stats = gmskframesync_get_framedatastats(fs); diff --git a/src/framing/tests/ofdmflexframe_autotest.c b/src/framing/tests/ofdmflexframe_autotest.c index 814ab0b29..ca243e437 100644 --- a/src/framing/tests/ofdmflexframe_autotest.c +++ b/src/framing/tests/ofdmflexframe_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ void testbench_ofdmflexframe(unsigned int _M, modulation_scheme _ms) { // create frame generator/synchronizer + unsigned int context = 0; ofdmflexframegenprops_s fgprops; ofdmflexframegenprops_init_default(&fgprops); fgprops.check = LIQUID_CRC_32; @@ -41,7 +42,8 @@ void testbench_ofdmflexframe(unsigned int _M, fgprops.fec1 = LIQUID_FEC_NONE; fgprops.mod_scheme = _ms; ofdmflexframegen fg = ofdmflexframegen_create( _M, _cp_len, _taper_len, NULL, &fgprops); - ofdmflexframesync fs = ofdmflexframesync_create(_M, _cp_len, _taper_len, NULL, NULL, NULL); + ofdmflexframesync fs = ofdmflexframesync_create(_M, _cp_len, _taper_len, NULL, + framing_autotest_callback, (void*)&context); // initialize header and payload unsigned char header[8] = {0, 1, 2, 3, 4, 5, 6, 7}; @@ -66,6 +68,9 @@ void testbench_ofdmflexframe(unsigned int _M, if (liquid_autotest_verbose) ofdmflexframesync_print(fs); + // verify callback was invoked + CONTEND_EQUALITY( context, FRAMING_AUTOTEST_SECRET ); + // verify frame data statistics framedatastats_s stats = ofdmflexframesync_get_framedatastats(fs); CONTEND_EQUALITY( stats.num_frames_detected, 1 ); From 52d5216a9c391b367d34eb0f3160d9639827c297 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 09:45:41 -0400 Subject: [PATCH 280/334] build: adding example to simulate linear modem BER --- examples/modem_ber_example.c | 109 +++++++++++++++++++++++++++++++++++ makefile.in | 1 + 2 files changed, 110 insertions(+) create mode 100644 examples/modem_ber_example.c diff --git a/examples/modem_ber_example.c b/examples/modem_ber_example.c new file mode 100644 index 000000000..0ecd22cca --- /dev/null +++ b/examples/modem_ber_example.c @@ -0,0 +1,109 @@ +// This example runs a bit error rate simulation for a specified modulation +// scheme and saves the resulting data points to a file for plotting. +#include +#include +#include +#include +#include +#include "liquid.h" + +// print usage/help message +void usage() +{ + printf("modem_example [options]\n"); + printf(" -h : print help\n"); + printf(" -m : modulation scheme\n"); + liquid_print_modulation_schemes(); +} + +int main(int argc, char*argv[]) +{ + // simulation parameters + modulation_scheme ms = LIQUID_MODEM_QPSK; // modulation scheme + float SNRdB_min = -5.0f; // starting SNR value + float SNRdB_max = 40.0f; // maximum SNR value + float SNRdB_step = 1.0f; // step size + unsigned int num_trials = 1e6; // number of symbols + char filename[] = "modem_ber_example.m"; + + int dopt; + while ((dopt = getopt(argc,argv,"hm:")) != EOF) { + switch (dopt) { + case 'h': usage(); return 0; + case 'm': + ms = liquid_getopt_str2mod(optarg); + if (ms == LIQUID_MODEM_UNKNOWN) { + fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", + argv[0], optarg); + return 1; + } + break; + default: + exit(1); + } + } + + // create modem objects + modem mod = modem_create(ms); // modulator + modem dem = modem_create(ms); // demodulator + + // compute derived values and initialize counters + unsigned int m = modem_get_bps(mod); // modulation bits/symbol + unsigned int M = 1 << m; // constellation size: 2^m + unsigned int i, sym_in, sym_out; + float complex sample; + + // iterate through SNR values + printf("# modulation scheme : %s\n", modulation_types[ms].name); + printf("# %8s %8s %8s %12s\n", "SNR [dB]", "errors", "trials", "BER"); + float SNRdB = SNRdB_min; // set SNR value + FILE * fid = fopen(filename,"w"); + fprintf(fid,"%% %s : auto-generated file\n", filename); + fprintf(fid,"clear all; close all; SNRdB=[]; BER=[]; ms='%s';\n", modulation_types[ms].name); + while (1) { + // compute noise standard deviation + float nstd = powf(10.0f, -SNRdB/20.0f); + + // reset modem objects (only necessary for differential schemes) + modem_reset(mod); + modem_reset(dem); + + // run trials + unsigned int num_bit_errors = 0; + for (i=0; i 0) + fprintf(fid,"SNRdB(end+1)=%12.3f; BER(end+1)=%12.4e;\n", SNRdB, ber); + + // stop iterating if SNR exceed maximum or no errors were detected + SNRdB += SNRdB_step; + if (SNRdB > SNRdB_max || num_bit_errors == 0) + break; + + } + fprintf(fid,"figure; semilogy(SNRdB,BER,'-x'); grid on; axis([SNRdB(1) SNRdB(end) 1e-6 1]);\n"); + fprintf(fid,"xlabel('SNR [dB]'); ylabel('BER'); title(ms)\n"); + fclose(fid); + printf("results written to %s\n", filename); + + // destroy modem objects and return + modem_destroy(mod); + modem_destroy(dem); + return 0; +} diff --git a/makefile.in b/makefile.in index 0d5e2205f..179869c1d 100644 --- a/makefile.in +++ b/makefile.in @@ -1602,6 +1602,7 @@ example_programs := \ examples/math_lngamma_example \ examples/math_primitive_root_example \ examples/modem_arb_example \ + examples/modem_ber_example \ examples/modem_example \ examples/modem_pi4dqpsk_example \ examples/modem_soft_example \ From 5441f01815dab92772104b76fd88d8f5fad4ab4d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 10:16:41 -0400 Subject: [PATCH 281/334] build: adding script to simulate GMSK modem performance --- examples/gmskmodem_ber_example.c | 114 +++++++++++++++++++++++++++++++ makefile.in | 1 + 2 files changed, 115 insertions(+) create mode 100644 examples/gmskmodem_ber_example.c diff --git a/examples/gmskmodem_ber_example.c b/examples/gmskmodem_ber_example.c new file mode 100644 index 000000000..f781fcd3e --- /dev/null +++ b/examples/gmskmodem_ber_example.c @@ -0,0 +1,114 @@ +// This example runs a bit error rate simulation for GMSK modulation. +#include +#include +#include +#include +#include +#include "liquid.h" + +// print usage/help message +void usage() +{ + printf("modem_example [options]\n"); + printf(" -h : print help\n"); +} + +int main(int argc, char*argv[]) +{ + // simulation parameters + unsigned int k = 4; // filter samples/symbol + unsigned int m = 3; // filter delay (symbols) + float BT = 0.3f; // bandwidth-time product + float SNRdB_min = -5.0f; // starting SNR value + float SNRdB_max = 15.0f; // maximum SNR value + float SNRdB_step = 1.0f; // step size + unsigned int num_trials = 1e6; // number of symbols + char filename[] = "gmskmodem_ber_example.m"; + + int dopt; + while ((dopt = getopt(argc,argv,"h")) != EOF) { + switch (dopt) { + case 'h': usage(); return 0; + default: + exit(1); + } + } + + // create modem objects + gmskmod mod = gmskmod_create(k, m, BT); // modulator + gmskdem dem = gmskdem_create(k, m, BT); // demodulator + + // derived values and buffers + unsigned int delay = 2*m; + unsigned int symbol_buffer[delay]; // delay between tx/rx + unsigned int symbol_index = 0; + float complex buf[k]; // sample buffer + unsigned int i, j, sym_in, sym_out, sym_buf; + + // iterate through SNR values + printf("# GMSK, k=%u, m=%u, BT=%.3f\n", k, m, BT); + printf("# %8s %8s %8s %12s %12s\n", "SNR [dB]", "errors", "trials", "BER", "theory"); + float SNRdB = SNRdB_min; // set SNR value + FILE * fid = fopen(filename,"w"); + fprintf(fid,"%% %s : auto-generated file\n", filename); + fprintf(fid,"clear all; close all; SNRdB=[]; BER=[]; theory=[];\n"); + while (1) + { + // compute noise standard deviation, compensating for over-sampling + float nstd = powf(10.0f, -SNRdB/20.0f) * sqrtf((float)k); + + // reset modem objects (only necessary for differential schemes) + gmskmod_reset(mod); + gmskdem_reset(dem); + + // run trials + unsigned int num_bit_errors = 0; + for (i=0; i delay) + num_bit_errors += count_bit_errors(sym_buf, sym_out); + } + + // compute results and print formatted results to screen + unsigned int num_bit_trials = m * num_trials; + float ber = (float)num_bit_errors / (float)(num_bit_trials); + float gamma = powf(10.0f, SNRdB/10.0f); + float theory = liquid_Qf(sqrtf(2*gamma)); + printf(" %8.2f %8u %8u %12.4e %12.4e\n", SNRdB, num_bit_errors, num_bit_trials, ber, theory); + + if (num_bit_errors > 0) { + fprintf(fid,"SNRdB(end+1)=%12.3f; BER(end+1)=%12.4e; theory(end+1)=%12.4e;\n", + SNRdB, ber, theory); + } + + // stop iterating if SNR exceed maximum or no errors were detected + SNRdB += SNRdB_step; + if (SNRdB > SNRdB_max) + break; + } + fprintf(fid,"figure; semilogy(SNRdB,BER,'-x',SNRdB,theory,'-x');grid on;\n"); + fprintf(fid,"axis([-5 15 1e-6 1]);xlabel('SNR [dB]'); ylabel('BER'); legend('sim','theory');\n"); + fclose(fid); + printf("results written to %s\n", filename); + + // destroy modem objects and return + gmskmod_destroy(mod); + gmskdem_destroy(dem); + return 0; +} diff --git a/makefile.in b/makefile.in index 179869c1d..0d9cf1a3c 100644 --- a/makefile.in +++ b/makefile.in @@ -1576,6 +1576,7 @@ example_programs := \ examples/gasearch_knapsack_example \ examples/gmskframesync_example \ examples/gmskmodem_example \ + examples/gmskmodem_ber_example \ examples/gmsk_eqlms_example \ examples/gmsk_tracking_example \ examples/gradsearch_datafit_example \ From e69f26540ef4dee7eb83488d34492af7a06fa551 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 14:08:20 -0400 Subject: [PATCH 282/334] cpfskmodem: adjusting debugging and print statements --- examples/cpfskmodem_example.c | 1 + src/modem/src/cpfskdem.c | 33 +++++++++++++++++++++------------ src/modem/src/cpfskmod.c | 29 ++++++++--------------------- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/examples/cpfskmodem_example.c b/examples/cpfskmodem_example.c index b5fdcb1bf..23670993f 100644 --- a/examples/cpfskmodem_example.c +++ b/examples/cpfskmodem_example.c @@ -92,6 +92,7 @@ int main(int argc, char*argv[]) // print modulator cpfskmod_print(mod); + cpfskdem_print(mod); // get full symbol delay unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem); diff --git a/src/modem/src/cpfskdem.c b/src/modem/src/cpfskdem.c index 7b04ab130..ed23c9a3a 100644 --- a/src/modem/src/cpfskdem.c +++ b/src/modem/src/cpfskdem.c @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // continuous phase frequency-shift keying demodulator -// #include #include @@ -32,10 +30,6 @@ #define DEBUG_CPFSKDEM 0 -// -// internal methods -// - // initialize coherent demodulator int cpfskdem_init_coherent(cpfskdem _q); @@ -171,7 +165,9 @@ cpfskdem cpfskdem_create(unsigned int _bps, // reset modem object cpfskdem_reset(q); - +#if DEBUG_CPFSKDEM + printf("clear all; close all; y=[]; z=[];\n"); +#endif return q; } @@ -259,6 +255,11 @@ int cpfskdem_init_noncoherent(cpfskdem _q) // destroy modem object int cpfskdem_destroy(cpfskdem _q) { +#if DEBUG_CPFSKDEM + printf("figure('position',[100 100 400 400]);\n"); + printf("n=length(z); i=1:%u:n; plot(z,'-',z(i),'o');\n", _q->k); + printf("axis square; axis([-1 1 -1 1]*1.5); grid on;\n"); +#endif switch(_q->demod_type) { case CPFSKDEM_COHERENT: firfilt_crcf_destroy(_q->data.coherent.mf); @@ -275,8 +276,16 @@ int cpfskdem_destroy(cpfskdem _q) // print modulation internals int cpfskdem_print(cpfskdem _q) { - printf("cpfskdem:\n"); - printf(" k : %u\n", _q->k); + printf("bps, _q->h, _q->k, _q->m, _q->beta); + switch(_q->type) { + case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; + case LIQUID_CPFSK_RCOS_FULL: printf(", type=\"rcos-full\""); break; + case LIQUID_CPFSK_RCOS_PARTIAL: printf(", type=\"rcos-partial\""); break; + case LIQUID_CPFSK_GMSK: printf(", type=\"gmsk\""); break; + default:; + } + printf(">\n"); return LIQUID_OK; } @@ -424,8 +433,8 @@ unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, // compute output sample float complex zp; firfilt_crcf_execute(_q->data.coherent.mf, &zp); - printf("y(end+1) = %12.8f + 1i*%12.8f;\n", crealf(_y), cimagf(_y)); - printf("z(end+1) = %12.8f + 1i*%12.8f;\n", crealf(zp), cimagf(zp)); + printf("y(end+1) = %12.8f + %12.8fj;\n", crealf(_y[i]), cimagf(_y[i])); + printf("z(end+1) = %12.8f + %12.8fj;\n", crealf( zp), cimagf( zp)); #endif // decimate output @@ -447,7 +456,7 @@ unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, #if DEBUG_CPFSKDEM // print result to screen - printf(" %3u : %12.8f + j%12.8f, (%1u)\n", + printf("%% %3u : %12.8f + j%12.8f, (%1u)\n", _q->index++, crealf(z), cimagf(z), phi_hat, v, sym_out); #endif } diff --git a/src/modem/src/cpfskmod.c b/src/modem/src/cpfskmod.c index c8c5b415b..84220c902 100644 --- a/src/modem/src/cpfskmod.c +++ b/src/modem/src/cpfskmod.c @@ -28,10 +28,6 @@ #include "liquid.internal.h" -// -// internal methods -// - // design transmit filter int cpfskmod_firdes(unsigned int _k, unsigned int _m, @@ -166,25 +162,16 @@ int cpfskmod_destroy(cpfskmod _q) // print cpfskmod object internals int cpfskmod_print(cpfskmod _q) { - printf("cpfskmod : continuous-phase frequency-shift keying modem\n"); - printf(" bits/symbol : %u\n", _q->bps); - printf(" modulation index: %-6.3f\n", _q->h); - printf(" samples/symbol : %u\n", _q->k); - printf(" filter delay : %u symbols\n", _q->m); - printf(" filter roll-off : %-6.3f\n", _q->beta); - printf(" filter type : "); + printf("bps, _q->h, _q->k, _q->m, _q->beta); switch(_q->type) { - case LIQUID_CPFSK_SQUARE: printf("square\n"); break; - case LIQUID_CPFSK_RCOS_FULL: printf("rcos (full)\n"); break; - case LIQUID_CPFSK_RCOS_PARTIAL: printf("rcos (partial)\n"); break; - case LIQUID_CPFSK_GMSK: printf("gmsk\n"); break; - default: printf("unknown\n"); break; + case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; + case LIQUID_CPFSK_RCOS_FULL: printf(", type=\"rcos-full\""); break; + case LIQUID_CPFSK_RCOS_PARTIAL: printf(", type=\"rcos-partial\""); break; + case LIQUID_CPFSK_GMSK: printf(", type=\"gmsk\""); break; + default:; } - printf(" filter :\n"); - // print filter coefficients - unsigned int i; - for (i=0; i<_q->ht_len; i++) - printf(" h(%3u) = %12.8f;\n", i+1, _q->ht[i]); + printf(">\n"); return LIQUID_OK; } From 2bf4197dae1c0faf9e62180511d786bf80642147 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 15:12:56 -0400 Subject: [PATCH 283/334] cpfskmod: moving definition to macro --- include/liquid.h | 84 ++++++++++--------- makefile.in | 2 +- .../src/{cpfskmod.c => cpfskmod.proto.c} | 56 ++++++------- src/modem/src/modemcf.c | 6 +- 4 files changed, 80 insertions(+), 68 deletions(-) rename src/modem/src/{cpfskmod.c => cpfskmod.proto.c} (87%) diff --git a/include/liquid.h b/include/liquid.h index 3e9fc288c..118129e83 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8315,45 +8315,53 @@ typedef enum { LIQUID_CPFSK_GMSK, // Gauss minimum-shift keying pulse } liquid_cpfsk_filter; -// CP-FSK modulator -typedef struct cpfskmod_s * cpfskmod; - -// create cpfskmod object (frequency modulator) -// _bps : bits per symbol, _bps > 0 -// _h : modulation index, _h > 0 -// _k : samples/symbol, _k > 1, _k even -// _m : filter delay (symbols), _m > 0 -// _beta : filter bandwidth parameter, _beta > 0 -// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -cpfskmod cpfskmod_create(unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type); -//cpfskmod cpfskmod_create_msk(unsigned int _k); -//cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); - -// destroy cpfskmod object -int cpfskmod_destroy(cpfskmod _q); - -// print cpfskmod object internals -int cpfskmod_print(cpfskmod _q); - -// reset state -int cpfskmod_reset(cpfskmod _q); - -// get transmit delay [symbols] -unsigned int cpfskmod_get_delay(cpfskmod _q); - -// modulate sample -// _q : frequency modulator object -// _s : input symbol -// _y : output sample array, [size: _k x 1] -int cpfskmod_modulate(cpfskmod _q, - unsigned int _s, - liquid_float_complex * _y); +// TODO: rename to cpfskmodcf for consistency +#define LIQUID_CPFSKMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(cpfskmod,name) + +#define LIQUID_CPFSKMOD_DEFINE_API(CPFSKMOD,T,TC) \ + \ +/* Continuous-Phase Frequency-Shift Keying Modulator */ \ +typedef struct CPFSKMOD(_s) * CPFSKMOD(); \ + \ +/* create cpfskmod object (frequency modulator) */ \ +/* _bps : bits per symbol, _bps > 0 */ \ +/* _h : modulation index, _h > 0 */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter bandwidth parameter, _beta > 0 */ \ +/* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ +CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, \ + float _h, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _type); \ + \ +/* cpfskmod cpfskmod_create_msk(unsigned int _k); */ \ +/* cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); */ \ + \ +/* destroy cpfskmod object */ \ +int CPFSKMOD(_destroy)(CPFSKMOD() _q); \ + \ +/* print cpfskmod object internals */ \ +int CPFSKMOD(_print)(CPFSKMOD() _q); \ + \ +/* reset state */ \ +int CPFSKMOD(_reset)(CPFSKMOD() _q); \ + \ +/* get transmit delay [symbols] */ \ +unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q); \ + \ +/* modulate sample */ \ +/* _q : frequency modulator object */ \ +/* _s : input symbol */ \ +/* _y : output sample array, [size: _k x 1] */ \ +int CPFSKMOD(_modulate)(CPFSKMOD() _q, \ + unsigned int _s, \ + TC * _y); \ +// define cpfskmod APIs +LIQUID_CPFSKMOD_DEFINE_API(LIQUID_CPFSKMOD_MANGLE_FLOAT,float,liquid_float_complex) // CP-FSK demodulator diff --git a/makefile.in b/makefile.in index 0d9cf1a3c..54b4fa7c0 100644 --- a/makefile.in +++ b/makefile.in @@ -849,7 +849,6 @@ matrix_benchmarks := \ modem_objects := \ src/modem/src/ampmodem.o \ src/modem/src/cpfskdem.o \ - src/modem/src/cpfskmod.o \ src/modem/src/fskdem.o \ src/modem/src/fskmod.o \ src/modem/src/gmskdem.o \ @@ -862,6 +861,7 @@ modem_objects := \ # explicit targets and dependencies modem_prototypes := \ + src/modem/src/cpfskmod.proto.c \ src/modem/src/freqdem.proto.c \ src/modem/src/freqmod.proto.c \ src/modem/src/modem_common.proto.c \ diff --git a/src/modem/src/cpfskmod.c b/src/modem/src/cpfskmod.proto.c similarity index 87% rename from src/modem/src/cpfskmod.c rename to src/modem/src/cpfskmod.proto.c index 84220c902..56dede005 100644 --- a/src/modem/src/cpfskmod.c +++ b/src/modem/src/cpfskmod.proto.c @@ -29,15 +29,15 @@ #include "liquid.internal.h" // design transmit filter -int cpfskmod_firdes(unsigned int _k, - unsigned int _m, - float _beta, - int _type, - float * _h, - unsigned int _h_len); +int CPFSKMOD(_firdes)(unsigned int _k, + unsigned int _m, + float _beta, + int _type, + float * _h, + unsigned int _h_len); // cpfskmod -struct cpfskmod_s { +struct CPFSKMOD(_s) { // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol @@ -58,19 +58,19 @@ struct cpfskmod_s { float b0, b1, a1, v0, v1; // integrator }; -// create cpfskmod object (frequency modulator) +// create CPFSKMOD() object (frequency modulator) // _bps : bits per symbol, _bps > 0 // _h : modulation index, _h > 0 // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -cpfskmod cpfskmod_create(unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type) +CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type) { // validate input if (_bps == 0) @@ -85,7 +85,7 @@ cpfskmod cpfskmod_create(unsigned int _bps, return liquid_error_config("cpfskmod_create(), filter roll-off must be in (0,1]"); // create main object memory - cpfskmod q = (cpfskmod) malloc(sizeof(struct cpfskmod_s)); + CPFSKMOD() q = (CPFSKMOD()) malloc(sizeof(struct CPFSKMOD(_s))); // set basic internal properties q->bps = _bps; // bits per symbol @@ -146,8 +146,8 @@ cpfskmod cpfskmod_create(unsigned int _bps, return q; } -// destroy cpfskmod object -int cpfskmod_destroy(cpfskmod _q) +// destroy CPFSKMOD() object +int CPFSKMOD(_destroy)(CPFSKMOD() _q) { // destroy pulse-shaping filter/interpolator free(_q->ht); @@ -159,8 +159,8 @@ int cpfskmod_destroy(cpfskmod _q) return LIQUID_OK; } -// print cpfskmod object internals -int cpfskmod_print(cpfskmod _q) +// print CPFSKMOD() object internals +int CPFSKMOD(_print)(CPFSKMOD() _q) { printf("bps, _q->h, _q->k, _q->m, _q->beta); @@ -176,7 +176,7 @@ int cpfskmod_print(cpfskmod _q) } // reset state -int cpfskmod_reset(cpfskmod _q) +int CPFSKMOD(_reset)(CPFSKMOD() _q) { // reset interpolator firinterp_rrrf_reset(_q->interp); @@ -188,7 +188,7 @@ int cpfskmod_reset(cpfskmod _q) } // get transmit delay [symbols] -unsigned int cpfskmod_get_delay(cpfskmod _q) +unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q) { return _q->symbol_delay; } @@ -197,7 +197,7 @@ unsigned int cpfskmod_get_delay(cpfskmod _q) // _q : frequency modulator object // _s : input symbol // _y : output sample array [size: _k x 1] -int cpfskmod_modulate(cpfskmod _q, +int CPFSKMOD(_modulate)(CPFSKMOD() _q, unsigned int _s, float complex * _y) { @@ -231,12 +231,12 @@ int cpfskmod_modulate(cpfskmod _q, // // design transmit filter -int cpfskmod_firdes(unsigned int _k, - unsigned int _m, - float _beta, - int _type, - float * _ht, - unsigned int _ht_len) +int CPFSKMOD(_firdes)(unsigned int _k, + unsigned int _m, + float _beta, + int _type, + float * _ht, + unsigned int _ht_len) { unsigned int i; // create filter based on specified type diff --git a/src/modem/src/modemcf.c b/src/modem/src/modemcf.c index f8b94686c..2d001f4c4 100644 --- a/src/modem/src/modemcf.c +++ b/src/modem/src/modemcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ #include "liquid.internal.h" // Macro definitions +#define CPFSKMOD(name) LIQUID_CONCAT(cpfskmod,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define FREQMOD(name) LIQUID_CONCAT(freqmod,name) #define FREQDEM(name) LIQUID_CONCAT(freqdem,name) @@ -61,6 +62,9 @@ // arbitrary modems #include "modem_arb.proto.c" +// non-linear modems +#include "cpfskmod.proto.c" + // analog modems #include "freqmod.proto.c" #include "freqdem.proto.c" From b36c7ad9ca778ca498230c2cd8389dbfa1a37d45 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 15:39:06 -0400 Subject: [PATCH 284/334] cpfskdem: moving definition to macro --- include/liquid.h | 94 +++++++------- makefile.in | 2 +- .../src/{cpfskdem.c => cpfskdem.proto.c} | 118 ++++++++---------- src/modem/src/modemcf.c | 2 + 4 files changed, 97 insertions(+), 119 deletions(-) rename src/modem/src/{cpfskdem.c => cpfskdem.proto.c} (80%) diff --git a/include/liquid.h b/include/liquid.h index 118129e83..45eb232eb 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8364,58 +8364,54 @@ int CPFSKMOD(_modulate)(CPFSKMOD() _q, \ LIQUID_CPFSKMOD_DEFINE_API(LIQUID_CPFSKMOD_MANGLE_FLOAT,float,liquid_float_complex) -// CP-FSK demodulator -typedef struct cpfskdem_s * cpfskdem; - -// create cpfskdem object (frequency modulator) -// _bps : bits per symbol, _bps > 0 -// _h : modulation index, _h > 0 -// _k : samples/symbol, _k > 1, _k even -// _m : filter delay (symbols), _m > 0 -// _beta : filter bandwidth parameter, _beta > 0 -// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -cpfskdem cpfskdem_create(unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type); -//cpfskdem cpfskdem_create_msk(unsigned int _k); -//cpfskdem cpfskdem_create_gmsk(unsigned int _k, float _BT); - -// destroy cpfskdem object -int cpfskdem_destroy(cpfskdem _q); - -// print cpfskdem object internals -int cpfskdem_print(cpfskdem _q); -// reset state -int cpfskdem_reset(cpfskdem _q); - -// get receive delay [symbols] -unsigned int cpfskdem_get_delay(cpfskdem _q); - -#if 0 -// demodulate array of samples -// _q : continuous-phase frequency demodulator object -// _y : input sample array, [size: _n x 1] -// _n : input sample array length -// _s : output symbol array -// _nw : number of output symbols written -int cpfskdem_demodulate(cpfskdem _q, - liquid_float_complex * _y, - unsigned int _n, - unsigned int * _s, - unsigned int * _nw); -#else -// demodulate array of samples, assuming perfect timing -// _q : continuous-phase frequency demodulator object -// _y : input sample array, [size: _k x 1] -unsigned int cpfskdem_demodulate(cpfskdem _q, - liquid_float_complex * _y); -#endif +// TODO: rename to cpfskdemcf for consistency +#define LIQUID_CPFSKDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(cpfskdem,name) +#define LIQUID_CPFSKDEM_DEFINE_API(CPFSKDEM,T,TC) \ + \ +/* Continuous-Phase Frequency-Shift Keying Demodulator */ \ +typedef struct CPFSKDEM(_s) * CPFSKDEM(); \ + \ +/* create demodulator object */ \ +/* _bps : bits per symbol, _bps > 0 */ \ +/* _h : modulation index, _h > 0 */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter bandwidth parameter, _beta > 0 */ \ +/* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ +CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, \ + float _h, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _type); \ + \ +/* CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k); */ \ +/* CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, float _BT); */ \ + \ +/* Destroy demodulator object, freeing all internal memory */ \ +int CPFSKDEM(_destroy)(CPFSKDEM() _q); \ + \ +/* Print demodulator object internals */ \ +int CPFSKDEM(_print)(CPFSKDEM() _q); \ + \ +/* Reset state */ \ +int CPFSKDEM(_reset)(CPFSKDEM() _q); \ + \ +/* get receive delay [symbols] */ \ +unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q); \ + \ +/* demodulate array of samples, assuming perfect timing */ \ +/* _q : continuous-phase frequency demodulator object */ \ +/* _y : input sample array, [size: _k x 1] */ \ +unsigned int CPFSKDEM(_demodulate)(CPFSKDEM() _q, \ + TC * _y); \ + \ +/* demodulate_block */ \ +// define cpfskmod APIs +LIQUID_CPFSKDEM_DEFINE_API(LIQUID_CPFSKDEM_MANGLE_FLOAT,float,liquid_float_complex) // // M-ary frequency-shift keying (MFSK) modems diff --git a/makefile.in b/makefile.in index 54b4fa7c0..ee7e2f7c1 100644 --- a/makefile.in +++ b/makefile.in @@ -848,7 +848,6 @@ matrix_benchmarks := \ modem_objects := \ src/modem/src/ampmodem.o \ - src/modem/src/cpfskdem.o \ src/modem/src/fskdem.o \ src/modem/src/fskmod.o \ src/modem/src/gmskdem.o \ @@ -861,6 +860,7 @@ modem_objects := \ # explicit targets and dependencies modem_prototypes := \ + src/modem/src/cpfskdem.proto.c \ src/modem/src/cpfskmod.proto.c \ src/modem/src/freqdem.proto.c \ src/modem/src/freqmod.proto.c \ diff --git a/src/modem/src/cpfskdem.c b/src/modem/src/cpfskdem.proto.c similarity index 80% rename from src/modem/src/cpfskdem.c rename to src/modem/src/cpfskdem.proto.c index ed23c9a3a..d641272e3 100644 --- a/src/modem/src/cpfskdem.c +++ b/src/modem/src/cpfskdem.proto.c @@ -28,38 +28,22 @@ #include "liquid.internal.h" -#define DEBUG_CPFSKDEM 0 +#define DEBUG_CPFSKDEM() 0 // initialize coherent demodulator -int cpfskdem_init_coherent(cpfskdem _q); +int CPFSKDEM(_init_coherent)(CPFSKDEM() _q); // initialize non-coherent demodulator -int cpfskdem_init_noncoherent(cpfskdem _q); +int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q); -#if 0 -// demodulate array of samples (coherent) -int cpfskdem_demodulate_coherent(cpfskdem _q, - float complex _y, - unsigned int * _s, - unsigned int * _nw); - -// demodulate array of samples (non-coherent) -int cpfskdem_demodulate_noncoherent(cpfskdem _q, - float complex _y, - unsigned int * _s, - unsigned int * _nw); -#else // demodulate array of samples (coherent) -unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, - float complex * _y); +unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, TC * _y); // demodulate array of samples (non-coherent) -unsigned int cpfskdem_demodulate_noncoherent(cpfskdem _q, - float complex * _y); -#endif +unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, TC * _y); // cpfskdem -struct cpfskdem_s { +struct CPFSKDEM(_s) { // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol @@ -78,13 +62,12 @@ struct cpfskdem_s { // demodulation function pointer #if 0 - void (*demodulate)(cpfskdem _q, - float complex _y, - unsigned int * _s, - unsigned int * _nw); + void (*demodulate)(CPFSKDEM() _q, + TC _y, + unsigned int * _s, + unsigned int * _nw); #else - unsigned int (*demodulate)(cpfskdem _q, - float complex * _y); + unsigned int (*demodulate)(CPFSKDEM() _q, TC * _y); #endif // common data structure shared between coherent and non-coherent @@ -92,12 +75,9 @@ struct cpfskdem_s { union { // coherent demodulator struct { - /* - nco_crcf nco; // oscillator/phase-locked loop - firpfb_crcf mf; // matched filter - firpfb_crcf dmf; // matched filter (derivative) - */ - + //nco_crcf nco; // oscillator/phase-locked loop + //firpfb_crcf mf; // matched filter + //firpfb_crcf dmf; // matched filter (derivative) firfilt_crcf mf; // matched filter } coherent; @@ -115,19 +95,19 @@ struct cpfskdem_s { float complex z_prime; // (coherent only) }; -// create cpfskdem object (frequency demodulator) +// create CPFSKDEM() object (frequency demodulator) // _bps : bits per symbol, _bps > 0 // _h : modulation index, _h > 0 // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) -cpfskdem cpfskdem_create(unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _type) +CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type) { // validate input if (_bps == 0) @@ -135,14 +115,14 @@ cpfskdem cpfskdem_create(unsigned int _bps, if (_h <= 0.0f) return liquid_error_config("cpfskdem_create(), modulation index must be greater than 0"); if (_k < 2 || (_k%2)) - return liquid_error_config("cpfskmod_create(), samples/symbol must be greater than 2 and even"); + return liquid_error_config("cpfskdem_create(), samples/symbol must be greater than 2 and even"); if (_m == 0) return liquid_error_config("cpfskdem_create(), filter delay must be greater than 0"); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("cpfskdem_create(), filter roll-off must be in (0,1]"); // create main object memory - cpfskdem q = (cpfskdem) malloc(sizeof(struct cpfskdem_s)); + CPFSKDEM() q = (cpfskdem) malloc(sizeof(struct CPFSKDEM(_s))); // set basic internal properties q->bps = _bps; // bits per symbol @@ -161,10 +141,10 @@ cpfskdem cpfskdem_create(unsigned int _bps, //cpfskdem_init_noncoherent(q); fprintf(stderr,"warning: cpfskdem_create(), coherent demodulation with h > 2/3 not recommended\n"); } - cpfskdem_init_coherent(q); + CPFSKDEM(_init_coherent)(q); // reset modem object - cpfskdem_reset(q); + CPFSKDEM(_reset)(q); #if DEBUG_CPFSKDEM printf("clear all; close all; y=[]; z=[];\n"); #endif @@ -172,7 +152,7 @@ cpfskdem cpfskdem_create(unsigned int _bps, } // initialize coherent demodulator -int cpfskdem_init_coherent(cpfskdem _q) +int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) { // specify coherent receiver _q->demod_type = CPFSKDEM_COHERENT; @@ -229,12 +209,12 @@ int cpfskdem_init_coherent(cpfskdem _q) } // initialize non-coherent demodulator -int cpfskdem_init_noncoherent(cpfskdem _q) +int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q) { #if 0 // specify non-coherent receiver _q->demod_type = CPFSKDEM_NONCOHERENT; - + // set demodulate function pointer _q->demodulate = cpfskdem_demodulate_noncoherent; @@ -253,7 +233,7 @@ int cpfskdem_init_noncoherent(cpfskdem _q) } // destroy modem object -int cpfskdem_destroy(cpfskdem _q) +int CPFSKDEM(_destroy)(CPFSKDEM() _q) { #if DEBUG_CPFSKDEM printf("figure('position',[100 100 400 400]);\n"); @@ -274,7 +254,7 @@ int cpfskdem_destroy(cpfskdem _q) } // print modulation internals -int cpfskdem_print(cpfskdem _q) +int CPFSKDEM(_print)(CPFSKDEM() _q) { printf("bps, _q->h, _q->k, _q->m, _q->beta); @@ -290,7 +270,7 @@ int cpfskdem_print(cpfskdem _q) } // reset modem object -int cpfskdem_reset(cpfskdem _q) +int CPFSKDEM(_reset)(CPFSKDEM() _q) { switch(_q->demod_type) { case CPFSKDEM_COHERENT: @@ -309,7 +289,7 @@ int cpfskdem_reset(cpfskdem _q) } // get transmit delay [symbols] -unsigned int cpfskdem_get_delay(cpfskdem _q) +unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q) { return _q->symbol_delay; } @@ -321,11 +301,11 @@ unsigned int cpfskdem_get_delay(cpfskdem _q) // _n : input sample array length // _s : output symbol array // _nw : number of output symbols written -int cpfskdem_demodulate(cpfskdem _q, - float complex * _y, - unsigned int _n, - unsigned int * _s, - unsigned int * _nw) +int CPFSKDEM(_demodulate)(CPFSKDEM() _q, + TC * _y, + unsigned int _n, + unsigned int * _s, + unsigned int * _nw) { // iterate through each sample calling type-specific demodulation function unsigned int i; @@ -344,10 +324,10 @@ int cpfskdem_demodulate(cpfskdem _q, } // demodulate array of samples (coherent) -int cpfskdem_demodulate_coherent(cpfskdem _q, - float complex _y, - unsigned int * _s, - unsigned int * _nw) +int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, + TC _y, + unsigned int * _s, + unsigned int * _nw) { // clear output counter *_nw = 0; @@ -368,7 +348,7 @@ int cpfskdem_demodulate_coherent(cpfskdem _q, if ( (_q->counter % _q->k)==0 ) { // reset sample counter _q->counter = 0; - + // compute output sample float complex z; firfilt_crcf_execute(_q->data.coherent.mf, &z); @@ -398,7 +378,7 @@ int cpfskdem_demodulate_coherent(cpfskdem _q, } // demodulate array of samples (non-coherent) -int cpfskdem_demodulate_noncoherent(cpfskdem _q, +int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, float complex _y, unsigned int * _s, unsigned int * _nw) @@ -412,15 +392,15 @@ int cpfskdem_demodulate_noncoherent(cpfskdem _q, // demodulate array of samples // _q : continuous-phase frequency demodulator object // _y : input sample array [size: _k x 1] -unsigned int cpfskdem_demodulate(cpfskdem _q, - float complex * _y) +unsigned int CPFSKDEM(_demodulate)(CPFSKDEM() _q, + TC * _y) { return _q->demodulate(_q, _y); } // demodulate array of samples (coherent) -unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, - float complex * _y) +unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, + TC * _y) { unsigned int i; unsigned int sym_out = 0; @@ -465,8 +445,8 @@ unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, } // demodulate array of samples (non-coherent) -unsigned int cpfskdem_demodulate_noncoherent(cpfskdem _q, - float complex * _y) +unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, + TC * _y) { return 0; } diff --git a/src/modem/src/modemcf.c b/src/modem/src/modemcf.c index 2d001f4c4..e83b0aef0 100644 --- a/src/modem/src/modemcf.c +++ b/src/modem/src/modemcf.c @@ -27,6 +27,7 @@ #include "liquid.internal.h" // Macro definitions +#define CPFSKDEM(name) LIQUID_CONCAT(cpfskdem,name) #define CPFSKMOD(name) LIQUID_CONCAT(cpfskmod,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define FREQMOD(name) LIQUID_CONCAT(freqmod,name) @@ -63,6 +64,7 @@ #include "modem_arb.proto.c" // non-linear modems +#include "cpfskdem.proto.c" #include "cpfskmod.proto.c" // analog modems From 893eb9bff87b60c35ebd38b716f0ab4114963f20 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 15:51:43 -0400 Subject: [PATCH 285/334] cpfskdem: flipping coherent and noncoherent methods * techincally the current (default) behoavior is not coherent * the demodulator applies an I/Q bandpass "matched" filter, and then observes the phase difference between adjacent symbols * a truly coherent demodulator would take the absolte phase into consideration, giving e.g. a 3 dB performance improvement for GMSK * need a way to allow the user to specify this upon object creation * probably also want time tracking, carrier tracking, at some point as well --- src/modem/src/cpfskdem.proto.c | 105 ++++++++++++++------------------- 1 file changed, 44 insertions(+), 61 deletions(-) diff --git a/src/modem/src/cpfskdem.proto.c b/src/modem/src/cpfskdem.proto.c index d641272e3..c269efaf2 100644 --- a/src/modem/src/cpfskdem.proto.c +++ b/src/modem/src/cpfskdem.proto.c @@ -78,16 +78,14 @@ struct CPFSKDEM(_s) { //nco_crcf nco; // oscillator/phase-locked loop //firpfb_crcf mf; // matched filter //firpfb_crcf dmf; // matched filter (derivative) - firfilt_crcf mf; // matched filter + //eqlms_rrrf equalizer; } coherent; // non-coherent demodulator struct { - firpfb_rrrf mf; // matched filter - firpfb_rrrf dmf; // matched filter (derivative) - eqlms_rrrf equalizer; + firfilt_crcf mf; // matched filter } noncoherent; - } data; + } demod; // state variables unsigned int index; // debug @@ -141,7 +139,7 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, //cpfskdem_init_noncoherent(q); fprintf(stderr,"warning: cpfskdem_create(), coherent demodulation with h > 2/3 not recommended\n"); } - CPFSKDEM(_init_coherent)(q); + CPFSKDEM(_init_noncoherent)(q); // reset modem object CPFSKDEM(_reset)(q); @@ -151,14 +149,20 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, return q; } -// initialize coherent demodulator +// initialize non-coherent demodulator int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) +{ + return liquid_error(LIQUID_EUMODE,"cpfskdem_init_coherent(), unsupported mode"); +} + +// initialize noncoherent demodulator +int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q) { // specify coherent receiver - _q->demod_type = CPFSKDEM_COHERENT; + _q->demod_type = CPFSKDEM_NONCOHERENT; // set demodulate function pointer - _q->demodulate = cpfskdem_demodulate_coherent; + _q->demodulate = cpfskdem_demodulate_noncoherent; // create object depending upon input type float bw = 0.0f; @@ -169,28 +173,28 @@ int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) //bw = 0.9f / (float)k; bw = 0.4f; _q->symbol_delay = _q->m; - _q->data.coherent.mf = firfilt_crcf_create_kaiser(2*_q->k*_q->m+1, bw, 60.0f, 0.0f); - firfilt_crcf_set_scale(_q->data.coherent.mf, 2.0f * bw); + _q->demod.noncoherent.mf = firfilt_crcf_create_kaiser(2*_q->k*_q->m+1, bw, 60.0f, 0.0f); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.0f * bw); break; case LIQUID_CPFSK_RCOS_FULL: if (_q->M==2) { - _q->data.coherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.5f,0); - firfilt_crcf_set_scale(_q->data.coherent.mf, 1.33f / (float)_q->k); + _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.5f,0); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 1.33f / (float)_q->k); _q->symbol_delay = _q->m; } else { - _q->data.coherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.9f,0); - firfilt_crcf_set_scale(_q->data.coherent.mf, 3.25f / (float)_q->k); + _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.9f,0); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 3.25f / (float)_q->k); _q->symbol_delay = 0; // TODO: fix this value } break; case LIQUID_CPFSK_RCOS_PARTIAL: if (_q->M==2) { - _q->data.coherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.3f,0); - firfilt_crcf_set_scale(_q->data.coherent.mf, 1.10f / (float)_q->k); + _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.3f,0); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 1.10f / (float)_q->k); _q->symbol_delay = _q->m; } else { - _q->data.coherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.27f,0); - firfilt_crcf_set_scale(_q->data.coherent.mf, 2.90f / (float)_q->k); + _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.27f,0); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.90f / (float)_q->k); _q->symbol_delay = 0; // TODO: fix this value } break; @@ -198,40 +202,16 @@ int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) bw = 0.5f / (float)_q->k; // TODO: figure out beta value here beta = (_q->M == 2) ? 0.8*gmsk_bt : 1.0*gmsk_bt; - _q->data.coherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,beta,0); - firfilt_crcf_set_scale(_q->data.coherent.mf, 2.0f * bw); + _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,beta,0); + firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.0f * bw); _q->symbol_delay = _q->m; break; default: - return liquid_error(LIQUID_EICONFIG,"cpfskdem_init_coherent(), invalid tx filter type"); + return liquid_error(LIQUID_EICONFIG,"cpfskdem_init_noncoherent(), invalid tx filter type"); } return LIQUID_OK; } -// initialize non-coherent demodulator -int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q) -{ -#if 0 - // specify non-coherent receiver - _q->demod_type = CPFSKDEM_NONCOHERENT; - - // set demodulate function pointer - _q->demodulate = cpfskdem_demodulate_noncoherent; - - // create object depending upon input type - switch(_q->type) { - case LIQUID_CPFSK_SQUARE: - case LIQUID_CPFSK_RCOS_FULL: - case LIQUID_CPFSK_RCOS_PARTIAL: - case LIQUID_CPFSK_GMSK: - break; - } - return LIQUID_OK; -#else - return liquid_error(LIQUID_EUMODE,"cpfskdem_init_noncoherent(), unsupported mode"); -#endif -} - // destroy modem object int CPFSKDEM(_destroy)(CPFSKDEM() _q) { @@ -242,9 +222,10 @@ int CPFSKDEM(_destroy)(CPFSKDEM() _q) #endif switch(_q->demod_type) { case CPFSKDEM_COHERENT: - firfilt_crcf_destroy(_q->data.coherent.mf); + return liquid_error(LIQUID_EINT,"cpfskdem_destroy(), coherent mode not supported"); break; case CPFSKDEM_NONCOHERENT: + firfilt_crcf_destroy(_q->demod.noncoherent.mf); break; } @@ -274,7 +255,7 @@ int CPFSKDEM(_reset)(CPFSKDEM() _q) { switch(_q->demod_type) { case CPFSKDEM_COHERENT: - firfilt_crcf_reset(_q->data.coherent.mf); + firfilt_crcf_reset(_q->demod.noncoherent.mf); break; case CPFSKDEM_NONCOHERENT: break; @@ -301,7 +282,7 @@ unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q) // _n : input sample array length // _s : output symbol array // _nw : number of output symbols written -int CPFSKDEM(_demodulate)(CPFSKDEM() _q, +int CPFSKDEM(_demodulate)(CPFSKDEM() _q, TC * _y, unsigned int _n, unsigned int * _s, @@ -333,12 +314,12 @@ int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, *_nw = 0; // push input sample through filter - firfilt_crcf_push(_q->data.coherent.mf, _y); + firfilt_crcf_push(_q->demod.noncoherent.mf, _y); #if DEBUG_CPFSKDEM // compute output sample float complex zp; - firfilt_crcf_execute(_q->data.coherent.mf, &zp); + firfilt_crcf_execute(_q->demod.noncoherent.mf, &zp); printf("y(end+1) = %12.8f + 1i*%12.8f;\n", crealf(_y), cimagf(_y)); printf("z(end+1) = %12.8f + 1i*%12.8f;\n", crealf(zp), cimagf(zp)); #endif @@ -351,7 +332,7 @@ int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, // compute output sample float complex z; - firfilt_crcf_execute(_q->data.coherent.mf, &z); + firfilt_crcf_execute(_q->demod.noncoherent.mf, &z); // compute instantaneous frequency scaled by modulation index // TODO: pre-compute scaling factor @@ -401,18 +382,26 @@ unsigned int CPFSKDEM(_demodulate)(CPFSKDEM() _q, // demodulate array of samples (coherent) unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, TC * _y) +{ + liquid_error(LIQUID_EINT,"cpfskdem_demodulate_coherent(), coherent mode not supported"); + return 0; +} + +// demodulate array of samples (non-coherent) +unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, + TC * _y) { unsigned int i; unsigned int sym_out = 0; for (i=0; i<_q->k; i++) { // push input sample through filter - firfilt_crcf_push(_q->data.coherent.mf, _y[i]); + firfilt_crcf_push(_q->demod.noncoherent.mf, _y[i]); #if DEBUG_CPFSKDEM // compute output sample float complex zp; - firfilt_crcf_execute(_q->data.coherent.mf, &zp); + firfilt_crcf_execute(_q->demod.noncoherent.mf, &zp); printf("y(end+1) = %12.8f + %12.8fj;\n", crealf(_y[i]), cimagf(_y[i])); printf("z(end+1) = %12.8f + %12.8fj;\n", crealf( zp), cimagf( zp)); #endif @@ -421,7 +410,7 @@ unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, if ( i == 0 ) { // compute output sample float complex z; - firfilt_crcf_execute(_q->data.coherent.mf, &z); + firfilt_crcf_execute(_q->demod.noncoherent.mf, &z); // compute instantaneous frequency scaled by modulation index // TODO: pre-compute scaling factor @@ -444,11 +433,5 @@ unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, return sym_out; } -// demodulate array of samples (non-coherent) -unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, - TC * _y) -{ - return 0; -} #endif From 2e8ecac345c5b87951ca9af44e6efe56c36aaffa Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 16:09:24 -0400 Subject: [PATCH 286/334] cpfskmod: adding copy() method, untested --- include/liquid.h | 9 ++++--- src/modem/src/cpfskmod.proto.c | 48 ++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 45eb232eb..08ad81610 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8340,13 +8340,16 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, \ /* cpfskmod cpfskmod_create_msk(unsigned int _k); */ \ /* cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); */ \ \ -/* destroy cpfskmod object */ \ +/* Copy object including all internal objects and state */ \ +CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() _q); \ + \ +/* Destroy modulator object, freeing all allocate memory */ \ int CPFSKMOD(_destroy)(CPFSKMOD() _q); \ \ -/* print cpfskmod object internals */ \ +/* Print modulator status to stdout */ \ int CPFSKMOD(_print)(CPFSKMOD() _q); \ \ -/* reset state */ \ +/* Reset internal state of modulator object */ \ int CPFSKMOD(_reset)(CPFSKMOD() _q); \ \ /* get transmit delay [symbols] */ \ diff --git a/src/modem/src/cpfskmod.proto.c b/src/modem/src/cpfskmod.proto.c index 56dede005..5b56d260f 100644 --- a/src/modem/src/cpfskmod.proto.c +++ b/src/modem/src/cpfskmod.proto.c @@ -36,8 +36,8 @@ int CPFSKMOD(_firdes)(unsigned int _k, float * _h, unsigned int _h_len); -// cpfskmod -struct CPFSKMOD(_s) { +struct CPFSKMOD(_s) +{ // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol @@ -49,13 +49,13 @@ struct CPFSKMOD(_s) { unsigned int symbol_delay; // transmit filter delay [symbols] // pulse-shaping filter - float * ht; // filter coefficients + T * ht; // filter coefficients unsigned int ht_len; // filter length - firinterp_rrrf interp; // interpolator + firinterp_rrrf interp; // phase interpolator // phase integrator - float * phase_interp; // phase interpolation buffer - float b0, b1, a1, v0, v1; // integrator + T * phase_interp; // phase interpolation buffer + T b0, b1, a1, v0, v1; // integrator }; // create CPFSKMOD() object (frequency modulator) @@ -131,14 +131,14 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, } // create pulse-shaping filter and scale by modulation index - q->ht = (float*) malloc(q->ht_len *sizeof(float)); - cpfskmod_firdes(q->k, q->m, q->beta, q->type, q->ht, q->ht_len); + q->ht = (T*) malloc(q->ht_len *sizeof(T)); + CPFSKMOD(_firdes)(q->k, q->m, q->beta, q->type, q->ht, q->ht_len); for (i=0; iht_len; i++) q->ht[i] *= M_PI * q->h; q->interp = firinterp_rrrf_create(q->k, q->ht, q->ht_len); // allocate buffer for phase interpolation - q->phase_interp = (float*) malloc(q->k*sizeof(float)); + q->phase_interp = (T*) malloc(q->k*sizeof(T)); // reset modem object cpfskmod_reset(q); @@ -146,7 +146,27 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, return q; } -// destroy CPFSKMOD() object +// Copy object including all internal objects and state +CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("cpfskmod_copy(), object cannot be NULL"); + + // create filter object and copy base parameters + CPFSKMOD() q_copy = (CPFSKMOD()) malloc(sizeof(struct CPFSKMOD(_s))); + memmove(q_copy, q_orig, sizeof(struct CPFSKMOD(_s))); + + // copy objects, arrays + q_copy->interp = firinterp_rrrf_copy(q_orig->interp); + q_copy->ht = (T*) liquid_malloc_copy(q_orig->ht, q_orig->ht_len, sizeof(T)); + q_copy->phase_interp = (T*) liquid_malloc_copy(q_orig->phase_interp, q_orig->k, sizeof(T)); + + // return new object + return q_copy; +} + +// destroy modulator object int CPFSKMOD(_destroy)(CPFSKMOD() _q) { // destroy pulse-shaping filter/interpolator @@ -159,7 +179,7 @@ int CPFSKMOD(_destroy)(CPFSKMOD() _q) return LIQUID_OK; } -// print CPFSKMOD() object internals +// print modulator object internals int CPFSKMOD(_print)(CPFSKMOD() _q) { printf("M) + 1.0f; From d6bdff1b39c5b8b104b36ed1299e03e7f5734451 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 13 Apr 2024 16:16:40 -0400 Subject: [PATCH 287/334] cpfskdem: adding copy() method, untested --- include/liquid.h | 3 +++ src/modem/src/cpfskdem.proto.c | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/liquid.h b/include/liquid.h index 08ad81610..59fc0fd52 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8393,6 +8393,9 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, \ /* CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k); */ \ /* CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, float _BT); */ \ \ +/* Copy object including all internal objects and state */ \ +CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() _q); \ + \ /* Destroy demodulator object, freeing all internal memory */ \ int CPFSKDEM(_destroy)(CPFSKDEM() _q); \ \ diff --git a/src/modem/src/cpfskdem.proto.c b/src/modem/src/cpfskdem.proto.c index c269efaf2..bbca1dd68 100644 --- a/src/modem/src/cpfskdem.proto.c +++ b/src/modem/src/cpfskdem.proto.c @@ -149,6 +149,31 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, return q; } +// Copy object including all internal objects and state +CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() q_orig) +{ + // validate input + if (q_orig == NULL) + return liquid_error_config("cpfskdem_copy(), object cannot be NULL"); + + // create filter object and copy base parameters + CPFSKDEM() q_copy = (CPFSKDEM()) malloc(sizeof(struct CPFSKDEM(_s))); + memmove(q_copy, q_orig, sizeof(struct CPFSKDEM(_s))); + + // copy objects + if (q_orig->demod_type == CPFSKDEM_COHERENT) { + //return liquid_error_config("cpfskdem_copy(), coherent mode not supported"); + liquid_error(LIQUID_EINT,"cpfskdem_copy(), coherent mode not supported"); + return NULL; + } else { + q_copy->demod.noncoherent.mf = firfilt_crcf_copy(q_orig->demod.noncoherent.mf); + } + + // return new object + return q_copy; +} + + // initialize non-coherent demodulator int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) { From 9cc889f39082fc695df95ecef26acd720c8d6686 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 07:41:22 -0400 Subject: [PATCH 288/334] cpfskmodem: adding convenience create() methods for MSK, GMSK --- include/liquid.h | 38 +++++++++++++++++++++++++--------- src/modem/src/cpfskdem.proto.c | 18 ++++++++++++++++ src/modem/src/cpfskmod.proto.c | 18 ++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index 59fc0fd52..f0969f0fb 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8324,12 +8324,12 @@ typedef enum { typedef struct CPFSKMOD(_s) * CPFSKMOD(); \ \ /* create cpfskmod object (frequency modulator) */ \ -/* _bps : bits per symbol, _bps > 0 */ \ -/* _h : modulation index, _h > 0 */ \ -/* _k : samples/symbol, _k > 1, _k even */ \ -/* _m : filter delay (symbols), _m > 0 */ \ -/* _beta : filter bandwidth parameter, _beta > 0 */ \ -/* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ +/* _bps : bits per symbol, _bps > 0 */ \ +/* _h : modulation index, _h > 0 */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter bandwidth parameter, _beta > 0 */ \ +/* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, \ float _h, \ unsigned int _k, \ @@ -8337,8 +8337,17 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, \ float _beta, \ int _type); \ \ -/* cpfskmod cpfskmod_create_msk(unsigned int _k); */ \ -/* cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); */ \ +/* create modulator object for minimum-shift keying */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +CPFSKMOD() CPFSKMOD(_create_msk)(unsigned int _k); \ + \ +/* create modulator object for Gauss minimum-shift keying */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _BT : bandwidth-time factor, 0 < _BT < 1 */ \ +CPFSKMOD() CPFSKMOD(_create_gmsk)(unsigned int _k, \ + unsigned int _m, \ + float _BT); \ \ /* Copy object including all internal objects and state */ \ CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() _q); \ @@ -8390,8 +8399,17 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, \ float _beta, \ int _type); \ \ -/* CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k); */ \ -/* CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, float _BT); */ \ +/* create demodulator object for minimum-shift keying */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k); \ + \ +/* create demodulator object for Gauss minimum-shift keying */ \ +/* _k : samples/symbol, _k > 1, _k even */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _BT : bandwidth-time factor, 0 < _BT < 1 */ \ +CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, \ + unsigned int _m, \ + float _BT); \ \ /* Copy object including all internal objects and state */ \ CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() _q); \ diff --git a/src/modem/src/cpfskdem.proto.c b/src/modem/src/cpfskdem.proto.c index bbca1dd68..3ffc7105a 100644 --- a/src/modem/src/cpfskdem.proto.c +++ b/src/modem/src/cpfskdem.proto.c @@ -173,6 +173,24 @@ CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() q_orig) return q_copy; } +// create demodulator object for minimum-shift keying +// _k : samples/symbol, _k > 1, _k even +CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k) +{ + return CPFSKDEM(_create)(1, 0.5f, _k, 1, 1.0f, LIQUID_CPFSK_SQUARE); +} + +// create demodulator object for Gauss minimum-shift keying +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _BT : bandwidth-time factor, 0 < _BT < 1 +CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, + unsigned int _m, + float _BT) +{ + return CPFSKDEM(_create)(1, 0.5f, _k, _m, _BT, LIQUID_CPFSK_GMSK); +} + // initialize non-coherent demodulator int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) diff --git a/src/modem/src/cpfskmod.proto.c b/src/modem/src/cpfskmod.proto.c index 5b56d260f..c96241fc7 100644 --- a/src/modem/src/cpfskmod.proto.c +++ b/src/modem/src/cpfskmod.proto.c @@ -146,6 +146,24 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, return q; } +// create modulator object for minimum-shift keying +// _k : samples/symbol, _k > 1, _k even +CPFSKMOD() CPFSKMOD(_create_msk)(unsigned int _k) +{ + return CPFSKMOD(_create)(1, 0.5f, _k, 1, 1.0f, LIQUID_CPFSK_SQUARE); +} + +// create modulator object for minimum-shift keying +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _BT : bandwidth-time factor, 0 < _BT < 1 +CPFSKMOD() CPFSKMOD(_create_gmsk)(unsigned int _k, + unsigned int _m, + float _BT) +{ + return CPFSKMOD(_create)(1, 0.5f, _k, _m, _BT, LIQUID_CPFSK_GMSK); +} + // Copy object including all internal objects and state CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() q_orig) { From 5c3fdf1dced7463713a9fdaf8c58550bc4c9534c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 07:56:28 -0400 Subject: [PATCH 289/334] cpfskmodem/autotest: adding tests for various samples/symbol, cleanup --- src/modem/tests/cpfskmodem_autotest.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index 68f15f999..b298615df 100644 --- a/src/modem/tests/cpfskmodem_autotest.c +++ b/src/modem/tests/cpfskmodem_autotest.c @@ -37,17 +37,14 @@ void cpfskmodem_test_mod_demod(unsigned int _bps, // derived values unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem); - //unsigned int M = 1 << _m; // constellation size - - unsigned int num_symbols = 80 + delay; // number of symbols to test - - msequence ms = msequence_create_default(7); + unsigned int num_symbols = 180 + delay; // number of symbols to test float complex buf[_k]; // sample buffer unsigned int sym_in [num_symbols]; // symbol buffer unsigned int sym_out[num_symbols]; // symbol buffer // modulate, demodulate, count errors + msequence ms = msequence_create_default(7); unsigned int i; for (i=0; i Date: Sun, 14 Apr 2024 09:01:05 -0400 Subject: [PATCH 290/334] github: testing uploading with github action --- .github/workflows/coverage.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 14258ec71..46447fb45 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -45,5 +45,8 @@ jobs: - name: make coverage run: make -j 2 coverage - - name: upload report - run: bash <(curl -s https://codecov.io/bash) + - name: upload report to codecov with github action + uses: codecov/codecov-action@v4.2.0 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + From e20809b31fcdad308a7b48282dcc5e892a844472 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:02:24 -0400 Subject: [PATCH 291/334] github: enabling coverage workflow on coverage-dev branch --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 46447fb45..e6df2e358 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,6 +6,7 @@ on: push: branches: - master + - coverage-dev jobs: standard: From 1e7fccf6e1ff2a14995bce430310708bf8d4a66d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:19:52 -0400 Subject: [PATCH 292/334] github: adding verbose flag to coverage upload testing --- .github/workflows/coverage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e6df2e358..ffb00040c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -48,6 +48,8 @@ jobs: - name: upload report to codecov with github action uses: codecov/codecov-action@v4.2.0 + with: + verbose: true env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From bb2826d53ba38d63047748b5a756447b6549a2b0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:30:28 -0400 Subject: [PATCH 293/334] github: moving token to 'with' instead of 'env' --- .github/workflows/coverage.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ffb00040c..9e6d90f85 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -49,7 +49,5 @@ jobs: - name: upload report to codecov with github action uses: codecov/codecov-action@v4.2.0 with: - verbose: true - env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 9994d32ac8f3b32b540419ae920c70aaf78ec656 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:33:28 -0400 Subject: [PATCH 294/334] github: fixing syntax for specifying secret token, adding fail on error --- .github/workflows/coverage.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9e6d90f85..9e94d2105 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -49,5 +49,7 @@ jobs: - name: upload report to codecov with github action uses: codecov/codecov-action@v4.2.0 with: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + From 25db8f315e355349297dc912a3047ebbfdedf391 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:37:31 -0400 Subject: [PATCH 295/334] github: downgrading codecov action to v4 --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9e94d2105..6809dcd0b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -47,7 +47,7 @@ jobs: run: make -j 2 coverage - name: upload report to codecov with github action - uses: codecov/codecov-action@v4.2.0 + uses: codecov/codecov-action@v4 with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} From 486eb8e5b5f8fee6f4394c16aaa4ecfb93e2ab18 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 09:53:03 -0400 Subject: [PATCH 296/334] github: testing token key in workflow --- .github/workflows/coverage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 6809dcd0b..6265a2294 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -50,6 +50,7 @@ jobs: uses: codecov/codecov-action@v4 with: fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + token: "my-secret-token" #${{ secrets.CODECOV_TOKEN }} From c4a568557de953758d36858e8384db2b341f4649 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 10:08:19 -0400 Subject: [PATCH 297/334] github: trying to use proper token; not sure why this is not working --- .github/workflows/coverage.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 6265a2294..a5ea16160 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -51,6 +51,4 @@ jobs: with: fail_ci_if_error: true verbose: true - token: "my-secret-token" #${{ secrets.CODECOV_TOKEN }} - - + token: ${{ secrets.CODECOV_TOKEN }} From d1f161e0cb3d3994656d9a06954acb325fb3ec32 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 15:35:29 -0400 Subject: [PATCH 298/334] modem: including additional configuration tests --- include/liquid.internal.h | 13 ------------- src/modem/src/modem_common.proto.c | 6 +++--- src/modem/tests/modem_config_autotest.c | 14 +++++++++++++- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 1f9e027cd..15f08c1e5 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1381,19 +1381,6 @@ int MODEM(_demodulate_soft_table)(MODEM() _q, \ unsigned int * _sym_out, \ unsigned char * _soft_bits); \ \ -/* Demodulate a linear symbol constellation using dynamic */ \ -/* threshold calculation */ \ -/* _v : input value */ \ -/* _m : bits per symbol */ \ -/* _alpha : scaling factor */ \ -/* _s : demodulated symbol */ \ -/* _res : residual */ \ -int MODEM(_demodulate_linear_array)(T _v, \ - unsigned int _m, \ - T _alpha, \ - unsigned int * _s, \ - T * _res); \ - \ /* Demodulate a linear symbol constellation using */ \ /* referenced lookup table */ \ /* _v : input value */ \ diff --git a/src/modem/src/modem_common.proto.c b/src/modem/src/modem_common.proto.c index d560d6068..52bc452f5 100644 --- a/src/modem/src/modem_common.proto.c +++ b/src/modem/src/modem_common.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -212,8 +212,6 @@ MODEM() MODEM(_create)(modulation_scheme _scheme) return liquid_error_config("modem%s_create(), unknown/unsupported modulation scheme : %u",EXTENSION,_scheme); } - // should never get to this point, but adding return statement - // to keep compiler happy return NULL; } @@ -578,6 +576,7 @@ T MODEM(_get_demodulator_evm)(MODEM() _q) return cabsf(_q->x_hat - _q->r); } +#if 0 // Demodulate a linear symbol constellation using dynamic threshold calculation // _v : input value // _m : bits per symbol @@ -604,6 +603,7 @@ int MODEM(_demodulate_linear_array)(T _v, *_res = _v; return LIQUID_OK; } +#endif // Demodulate a linear symbol constellation using referenced lookup table // _v : input value diff --git a/src/modem/tests/modem_config_autotest.c b/src/modem/tests/modem_config_autotest.c index ebc8f03fa..52ecb2ec4 100644 --- a/src/modem/tests/modem_config_autotest.c +++ b/src/modem/tests/modem_config_autotest.c @@ -22,7 +22,7 @@ #include #include "autotest/autotest.h" -#include "liquid.h" +#include "liquid.internal.h" // Helper function to keep code base small void modemcf_test_copy(modulation_scheme _ms) @@ -145,10 +145,22 @@ void autotest_modem_config() // test copying/creating invalid objects CONTEND_ISNULL( modemcf_copy(NULL) ); CONTEND_ISNULL( modemcf_create(LIQUID_MODEM_ARB) ); + CONTEND_ISNULL( modemcf_create(-1) ); // create object and check configuration modemcf q = modemcf_create(LIQUID_MODEM_QAM64); CONTEND_EQUALITY( LIQUID_OK, modemcf_print(q) ); + + // internal: try to initialize using invalid configuration + CONTEND_INEQUALITY( LIQUID_OK, modemcf_init(q,0) ); + CONTEND_INEQUALITY( LIQUID_OK, modemcf_init(q,77) ); + + // internal: try to modulate using invalid inputs + float complex sym; + CONTEND_INEQUALITY( LIQUID_OK, modemcf_modulate (q,8193,&sym) ); + CONTEND_INEQUALITY( LIQUID_OK, modemcf_modulate_map(q,8193,&sym) ); + CONTEND_INEQUALITY( LIQUID_OK, modemcf_demodsoft_gentab(q,227) ); + modemcf_destroy(q); } From 9de2878e0e2a7f2554f5760491a5b999abc36f58 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 16:08:09 -0400 Subject: [PATCH 299/334] cpfskmodem: adding access methods, additional testing --- include/liquid.h | 34 +++++++++- src/modem/src/cpfskdem.proto.c | 43 +++++++++++- src/modem/src/cpfskmod.proto.c | 35 +++++++++- src/modem/tests/cpfskmodem_autotest.c | 95 ++++++++++++++++----------- 4 files changed, 163 insertions(+), 44 deletions(-) diff --git a/include/liquid.h b/include/liquid.h index f0969f0fb..3d3406e07 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -8361,9 +8361,24 @@ int CPFSKMOD(_print)(CPFSKMOD() _q); \ /* Reset internal state of modulator object */ \ int CPFSKMOD(_reset)(CPFSKMOD() _q); \ \ -/* get transmit delay [symbols] */ \ +/* Get modulator's number of bits per symbol */ \ +unsigned int CPFSKMOD(_get_bits_per_symbol)(CPFSKMOD() _q); \ + \ +/* Get modulator's modulation index */ \ +float CPFSKMOD(_get_modulation_index)(CPFSKMOD() _q); \ + \ +/* Get modulator's number of samples per symbol */ \ +unsigned int CPFSKMOD(_get_samples_per_symbol)(CPFSKMOD() _q); \ + \ +/* Get modulator's filter delay [symbols] */ \ unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q); \ \ +/* Get modulator's bandwidth parameter */ \ +float CPFSKMOD(_get_beta)(CPFSKMOD() _q); \ + \ +/* Get modulator's filter type */ \ +int CPFSKMOD(_get_type)(CPFSKMOD() _q); \ + \ /* modulate sample */ \ /* _q : frequency modulator object */ \ /* _s : input symbol */ \ @@ -8423,9 +8438,24 @@ int CPFSKDEM(_print)(CPFSKDEM() _q); \ /* Reset state */ \ int CPFSKDEM(_reset)(CPFSKDEM() _q); \ \ -/* get receive delay [symbols] */ \ +/* Get demodulator's number of bits per symbol */ \ +unsigned int CPFSKDEM(_get_bits_per_symbol)(CPFSKDEM() _q); \ + \ +/* Get demodulator's modulation index */ \ +float CPFSKDEM(_get_modulation_index)(CPFSKDEM() _q); \ + \ +/* Get demodulator's number of samples per symbol */ \ +unsigned int CPFSKDEM(_get_samples_per_symbol)(CPFSKDEM() _q); \ + \ +/* Get demodulator's transmit delay [symbols] */ \ unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q); \ \ +/* Get demodulator's bandwidth parameter */ \ +float CPFSKDEM(_get_beta)(CPFSKDEM() _q); \ + \ +/* Get demodulator's filter type */ \ +int CPFSKDEM(_get_type)(CPFSKDEM() _q); \ + \ /* demodulate array of samples, assuming perfect timing */ \ /* _q : continuous-phase frequency demodulator object */ \ /* _y : input sample array, [size: _k x 1] */ \ diff --git a/src/modem/src/cpfskdem.proto.c b/src/modem/src/cpfskdem.proto.c index 3ffc7105a..a4f781335 100644 --- a/src/modem/src/cpfskdem.proto.c +++ b/src/modem/src/cpfskdem.proto.c @@ -130,6 +130,16 @@ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, q->beta = _beta; // filter roll-off factor (only for certain filters) q->type = _type; // filter type + switch(q->type) { + case LIQUID_CPFSK_SQUARE: + case LIQUID_CPFSK_RCOS_FULL: + case LIQUID_CPFSK_RCOS_PARTIAL: + case LIQUID_CPFSK_GMSK: + break; + default: + return liquid_error_config("cpfskdem_create(), invalid filter type '%d'", q->type); + } + // derived values q->M = 1 << q->bps; // constellation size @@ -312,12 +322,43 @@ int CPFSKDEM(_reset)(CPFSKDEM() _q) return LIQUID_OK; } -// get transmit delay [symbols] +// Get demodulator's number of bits per symbol +unsigned int CPFSKDEM(_get_bits_per_symbol)(CPFSKDEM() _q) +{ + return _q->bps; +} + +// Get demodulator's modulation index +float CPFSKDEM(_get_modulation_index)(CPFSKDEM() _q) +{ + return _q->h; +} + +// Get demodulator's number of samples per symbol +unsigned int CPFSKDEM(_get_samples_per_symbol)(CPFSKDEM() _q) +{ + return _q->k; +} + +// Get demodulator's filter delay [symbols] unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q) { return _q->symbol_delay; } +// Get demodulator's bandwidth parameter +float CPFSKDEM(_get_beta)(CPFSKDEM() _q) +{ + return _q->beta; +} + +// Get demodulator's filter type +int CPFSKDEM(_get_type)(CPFSKDEM() _q) +{ + return _q->type; +} + + #if 0 // demodulate array of samples // _q : continuous-phase frequency demodulator object diff --git a/src/modem/src/cpfskmod.proto.c b/src/modem/src/cpfskmod.proto.c index c96241fc7..dd3343316 100644 --- a/src/modem/src/cpfskmod.proto.c +++ b/src/modem/src/cpfskmod.proto.c @@ -127,7 +127,7 @@ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, q->ht_len = 2*(q->k)*(q->m) + (q->k) + 1; break; default: - return liquid_error_config("cpfskmodem_create(), invalid filter type '%d'", q->type); + return liquid_error_config("cpfskmod_create(), invalid filter type '%d'", q->type); } // create pulse-shaping filter and scale by modulation index @@ -225,12 +225,43 @@ int CPFSKMOD(_reset)(CPFSKMOD() _q) return LIQUID_OK; } -// get transmit delay [symbols] +// Get modulator's number of bits per symbol +unsigned int CPFSKMOD(_get_bits_per_symbol)(CPFSKMOD() _q) +{ + return _q->bps; +} + +// Get modulator's modulation index +float CPFSKMOD(_get_modulation_index)(CPFSKMOD() _q) +{ + return _q->h; +} + +// Get modulator's number of samples per symbol +unsigned int CPFSKMOD(_get_samples_per_symbol)(CPFSKMOD() _q) +{ + return _q->k; +} + +// Get modulator's filter delay [symbols] unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q) { return _q->symbol_delay; } +// Get modulator's bandwidth parameter +float CPFSKMOD(_get_beta)(CPFSKMOD() _q) +{ + return _q->beta; +} + +// Get modulator's filter type +int CPFSKMOD(_get_type)(CPFSKMOD() _q) +{ + return _q->type; +} + + // modulate sample // _q : frequency modulator object // _s : input symbol diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index b298615df..003cd16f1 100644 --- a/src/modem/tests/cpfskmodem_autotest.c +++ b/src/modem/tests/cpfskmodem_autotest.c @@ -24,22 +24,15 @@ #include "liquid.h" // Help function to keep code base small -void cpfskmodem_test_mod_demod(unsigned int _bps, - float _h, - unsigned int _k, - unsigned int _m, - float _beta, - int _filter_type) +void cpfskmodem_test_mod_demod(cpfskmod mod, cpfskdem dem) { - // create modulator/demodulator pair - cpfskmod mod = cpfskmod_create(_bps, _h, _k, _m, _beta, _filter_type); - cpfskdem dem = cpfskdem_create(_bps, _h, _k, _m, _beta, _filter_type); - // derived values unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem); - unsigned int num_symbols = 180 + delay; // number of symbols to test + unsigned int k = cpfskmod_get_samples_per_symbol(mod); + unsigned int bps = cpfskmod_get_bits_per_symbol(mod); - float complex buf[_k]; // sample buffer + unsigned int num_symbols = 180 + delay; // number of symbols to test + float complex buf[k]; // sample buffer unsigned int sym_in [num_symbols]; // symbol buffer unsigned int sym_out[num_symbols]; // symbol buffer @@ -48,7 +41,7 @@ void cpfskmodem_test_mod_demod(unsigned int _bps, unsigned int i; for (i=0; i Date: Sun, 14 Apr 2024 19:31:42 -0400 Subject: [PATCH 300/334] gitlab: updating ci/cd script to upload to codecov.io --- .gitlab-ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a2fecff94..e3def3ab7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,7 +79,10 @@ coverage: - ./bootstrap.sh - ./configure --enable-coverage - make -j4 coverage - - bash <(curl -s https://codecov.io/bash) + - curl -Os https://cli.codecov.io/latest/linux/codecov + - chmod +x codecov + - ./codecov upload-process -t $CODECOV_TOKEN + coverage: '/lines: \d+\.\d+%/' artifacts: paths: [coverage.out] From 9e018d923fd1bee34de266323b785e213f3b6b8c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 14 Apr 2024 19:45:26 -0400 Subject: [PATCH 301/334] gitlab: adding options for integrating with codecov.io --- .gitlab-ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e3def3ab7..39271ee0c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,9 +79,10 @@ coverage: - ./bootstrap.sh - ./configure --enable-coverage - make -j4 coverage - - curl -Os https://cli.codecov.io/latest/linux/codecov + - curl -Os http://cli.codecov.io/latest/linux/codecov - chmod +x codecov - - ./codecov upload-process -t $CODECOV_TOKEN + - ./codecov --version + - ./codecov upload-process -t $CODECOV_TOKEN --git-service gitlab --slug jgaeddert/liquid-dsp coverage: '/lines: \d+\.\d+%/' artifacts: From 4ae1006a54096420893e7806d21267edccb54617 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 16 Apr 2024 08:32:38 -0400 Subject: [PATCH 302/334] firpfbchr: adding initial test harness --- makefile.in | 3 +- src/multichannel/src/firpfbchr.proto.c | 10 ++-- .../tests/firpfbchr_crcf_autotest.c | 56 +++++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/multichannel/tests/firpfbchr_crcf_autotest.c diff --git a/makefile.in b/makefile.in index ee7e2f7c1..1daf4d5d7 100644 --- a/makefile.in +++ b/makefile.in @@ -938,10 +938,11 @@ src/multichannel/src/firpfbch_cccf.o : %.o : %.c $(include_headers) $(multichann # autotests multichannel_autotests := \ - src/multichannel/tests/firpfbch2_crcf_autotest.c \ src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c \ src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c \ src/multichannel/tests/firpfbch_crcf_autotest.c \ + src/multichannel/tests/firpfbch2_crcf_autotest.c \ + src/multichannel/tests/firpfbchr_crcf_autotest.c \ src/multichannel/tests/ofdmframe_autotest.c \ # benchmarks diff --git a/src/multichannel/src/firpfbchr.proto.c b/src/multichannel/src/firpfbchr.proto.c index 9507a586a..403cde46a 100644 --- a/src/multichannel/src/firpfbchr.proto.c +++ b/src/multichannel/src/firpfbchr.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,12 +20,8 @@ * THE SOFTWARE. */ -// -// firpfbchr.c -// // finite impulse response polyphase filterbank channelizer with output // rate Fs / P -// #include #include @@ -71,8 +67,12 @@ FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _chans, // validate input if (_chans < 2) return liquid_error_config("firpfbchr_%s_create(), number of channels must be at least 2", EXTENSION_FULL); + if (_decim < 1) + return liquid_error_config("firpfbchr_%s_create(), decimation rate must be at least 1", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbchr_%s_create(), filter semi-length must be at least 1", EXTENSION_FULL); + if (_h == NULL) + return liquid_error_config("firpfbchr_%s_create(), filter coefficients cannot be null", EXTENSION_FULL); // create object FIRPFBCHR() q = (FIRPFBCHR()) malloc(sizeof(struct FIRPFBCHR(_s))); diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c new file mode 100644 index 000000000..719f38b8d --- /dev/null +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007 - 2024 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "autotest/autotest.h" +#include "liquid.h" + +void autotest_firpfbchr_crcf_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping firpfbchr_crcf config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + // design prototype filter + unsigned int h_len = 2*64*12+1; + float h[2*64*12+1]; + liquid_firdes_kaiser(h_len, 0.1f, 60.0f, 0.0f, h); + + // check invalid function calls + CONTEND_ISNULL(firpfbchr_crcf_create( 0, 76, 12, h)) // too few channels + CONTEND_ISNULL(firpfbchr_crcf_create(64, 0, 12, h)) // decimation rate too small + CONTEND_ISNULL(firpfbchr_crcf_create(64, 76, 0, h)) // filter delay too small + CONTEND_ISNULL(firpfbchr_crcf_create(64, 76, 12, NULL)) // coefficients pointer set to NULL + + //CONTEND_ISNULL(firpfbchr_crcf_copy(NULL)) + + // create proper object and test configurations + firpfbchr_crcf q = firpfbchr_crcf_create_kaiser(64, 76, 12, 60.0f); + + CONTEND_EQUALITY(LIQUID_OK, firpfbchr_crcf_print(q)) + + firpfbchr_crcf_destroy(q); +} + From 345203aa5c17a8d30aef49adb17a432450d41022 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 16 Apr 2024 17:22:04 -0400 Subject: [PATCH 303/334] firpfbchr: adding test methods for create_kaiser() --- src/multichannel/src/firpfbchr.proto.c | 4 ++++ src/multichannel/tests/firpfbchr_crcf_autotest.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/multichannel/src/firpfbchr.proto.c b/src/multichannel/src/firpfbchr.proto.c index 403cde46a..bcb3d5e30 100644 --- a/src/multichannel/src/firpfbchr.proto.c +++ b/src/multichannel/src/firpfbchr.proto.c @@ -130,8 +130,12 @@ FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _chans, // validate input if (_chans < 2) return liquid_error_config("firpfbchr_%s_create_kaiser(), number of channels must be at least 2", EXTENSION_FULL); + if (_decim < 1) + return liquid_error_config("firpfbchr_%s_create_kaiser(), decimation rate must be at least 1", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbchr_%s_create_kaiser(), filter semi-length must be at least 1", EXTENSION_FULL); + if (_as <= 0.0f) + return liquid_error_config("firpfbchr_%s_create_kaiser(), stop-band suppression out of range", EXTENSION_FULL); // design prototype filter unsigned int h_len = 2*_chans*_m+1; diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c index 719f38b8d..a2e390910 100644 --- a/src/multichannel/tests/firpfbchr_crcf_autotest.c +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -44,6 +44,12 @@ void autotest_firpfbchr_crcf_config() CONTEND_ISNULL(firpfbchr_crcf_create(64, 76, 0, h)) // filter delay too small CONTEND_ISNULL(firpfbchr_crcf_create(64, 76, 12, NULL)) // coefficients pointer set to NULL + // kaiser + CONTEND_ISNULL(firpfbchr_crcf_create_kaiser( 0, 76, 12, 60.0f)) // too few channels + CONTEND_ISNULL(firpfbchr_crcf_create_kaiser(64, 0, 12, 60.0f)) // decimation rate too small + CONTEND_ISNULL(firpfbchr_crcf_create_kaiser(64, 76, 0, 60.0f)) // filter delay too small + CONTEND_ISNULL(firpfbchr_crcf_create_kaiser(64, 76, 12, -1.0f)) // stop-band suppression out of range + //CONTEND_ISNULL(firpfbchr_crcf_copy(NULL)) // create proper object and test configurations From 2ff55309ef6cba6c7bc666905d458c58f994a50c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 16 Apr 2024 17:24:08 -0400 Subject: [PATCH 304/334] firpfbchr: adding tests for access parameters --- src/multichannel/tests/firpfbchr_crcf_autotest.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c index a2e390910..917e9c79e 100644 --- a/src/multichannel/tests/firpfbchr_crcf_autotest.c +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -56,6 +56,9 @@ void autotest_firpfbchr_crcf_config() firpfbchr_crcf q = firpfbchr_crcf_create_kaiser(64, 76, 12, 60.0f); CONTEND_EQUALITY(LIQUID_OK, firpfbchr_crcf_print(q)) + CONTEND_EQUALITY(64, firpfbchr_crcf_get_num_channels(q)) + CONTEND_EQUALITY(76, firpfbchr_crcf_get_decim_rate(q)) + CONTEND_EQUALITY(12, firpfbchr_crcf_get_m(q)) firpfbchr_crcf_destroy(q); } From baa8ac3c7ef7b2510fdd0478b6a868543620c2a1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 16 Apr 2024 17:38:50 -0400 Subject: [PATCH 305/334] firpfbchr: adding test for output spectrum --- .../tests/firpfbchr_crcf_autotest.c | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c index 917e9c79e..b2f2a52a8 100644 --- a/src/multichannel/tests/firpfbchr_crcf_autotest.c +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -24,6 +24,85 @@ #include "autotest/autotest.h" #include "liquid.h" +void autotest_firpfbchr_crcf() +{ + // options + unsigned int M = 16; // number of channels + unsigned int P = 6; // output decimation rate + unsigned int m = 5; // filter semi-length (symbols) + unsigned int num_blocks=1<<16; // number of symbols + float As = 60.0f; // filter stop-band attenuation + + unsigned int i; + unsigned int channel_id = 3; + + // create filterbank objects from prototype + firpfbchr_crcf qa = firpfbchr_crcf_create_kaiser(M, P, m, As); + firpfbchr_crcf_print(qa); + + // create multi-signal source generator + msourcecf gen = msourcecf_create_default(); + + // add signals (gen, fc, bw, gain, {options}) + msourcecf_add_noise(gen, 0.00f, 1.0f, -60); // wide-band noise + msourcecf_add_noise(gen, -0.30f, 0.1f, -20); // narrow-band noise + msourcecf_add_tone (gen, 0.08f, 0.0f, 0); // tone + // modulated data + msourcecf_add_modem(gen, + (float)channel_id/(float)M, // center frequency + 0.080f, // bandwidth (symbol rate) + -20, // gain + LIQUID_MODEM_QPSK, // modulation scheme + 12, // filter semi-length + 0.3f); // modem parameters + + // create spectral periodogoram + unsigned int nfft = 2400; + spgramcf p0 = spgramcf_create_default(nfft); + spgramcf p1 = spgramcf_create_default(nfft); + + // run channelizer + float complex buf_0[P]; + float complex buf_1[M]; + for (i=0; i Date: Tue, 16 Apr 2024 17:45:48 -0400 Subject: [PATCH 306/334] autotest/psd: adding method to valid psd based on spgramcf object --- autotest/autotest.c | 10 ++++++++++ autotest/autotest.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/autotest/autotest.c b/autotest/autotest.c index ccd3cb785..811ea550d 100644 --- a/autotest/autotest.c +++ b/autotest/autotest.c @@ -362,6 +362,16 @@ int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nff return liquid_autotest_validate_spectrum(psd,_nfft,_regions,num_regions,debug_filename); } +// validate spectral content of a spectral periodogram object +int liquid_autotest_validate_psd_spgramcf(spgramcf _q, + autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename) +{ + unsigned int nfft = spgramcf_get_nfft(_q); + float psd[nfft]; + spgramcf_get_psd(_q, psd); + return liquid_autotest_validate_spectrum(psd,nfft,_regions,num_regions,debug_filename); +} + // callback function to simplify testing for framing objects int framing_autotest_callback( unsigned char * _header, diff --git a/autotest/autotest.h b/autotest/autotest.h index 5945ab5e2..c961fa66d 100644 --- a/autotest/autotest.h +++ b/autotest/autotest.h @@ -316,6 +316,10 @@ int liquid_autotest_validate_psd_firfilt_cccf(firfilt_cccf _q, unsigned int _nff int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); +// validate spectral content of a spectral periodogram object +int liquid_autotest_validate_psd_spgramcf(spgramcf _q, + autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); + // callback function to simplify testing for framing objects #define FRAMING_AUTOTEST_SECRET 0x01234567 int framing_autotest_callback( From e98f1b8eec61d61dc96c49a846877c6fb10257a9 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Tue, 16 Apr 2024 18:53:24 -0400 Subject: [PATCH 307/334] firpfbchr: extending test to include multiple output spectra --- .../tests/firpfbchr_crcf_autotest.c | 82 +++++++++++-------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c index b2f2a52a8..e12acb018 100644 --- a/src/multichannel/tests/firpfbchr_crcf_autotest.c +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -29,13 +29,10 @@ void autotest_firpfbchr_crcf() // options unsigned int M = 16; // number of channels unsigned int P = 6; // output decimation rate - unsigned int m = 5; // filter semi-length (symbols) + unsigned int m = 12; // filter semi-length (symbols) unsigned int num_blocks=1<<16; // number of symbols float As = 60.0f; // filter stop-band attenuation - unsigned int i; - unsigned int channel_id = 3; - // create filterbank objects from prototype firpfbchr_crcf qa = firpfbchr_crcf_create_kaiser(M, P, m, As); firpfbchr_crcf_print(qa); @@ -43,27 +40,29 @@ void autotest_firpfbchr_crcf() // create multi-signal source generator msourcecf gen = msourcecf_create_default(); - // add signals (gen, fc, bw, gain, {options}) - msourcecf_add_noise(gen, 0.00f, 1.0f, -60); // wide-band noise - msourcecf_add_noise(gen, -0.30f, 0.1f, -20); // narrow-band noise - msourcecf_add_tone (gen, 0.08f, 0.0f, 0); // tone + // add signals (gen, fc, bw, gain, {options}) + msourcecf_add_noise(gen, 0.00f, 1.00f, -60); // wide-band noise + msourcecf_add_noise(gen, -0.30f, 0.10f, -20); // narrow-band noise + msourcecf_add_noise(gen, 0.08f, 0.01f, -30); // very narrow-band noise // modulated data msourcecf_add_modem(gen, - (float)channel_id/(float)M, // center frequency - 0.080f, // bandwidth (symbol rate) - -20, // gain - LIQUID_MODEM_QPSK, // modulation scheme - 12, // filter semi-length - 0.3f); // modem parameters + 0.1875f, // center frequency + 0.065f, // bandwidth (symbol rate) + -20, // gain + LIQUID_MODEM_QPSK, // modulation scheme + 12, // filter semi-length + 0.3f); // modem parameters // create spectral periodogoram unsigned int nfft = 2400; spgramcf p0 = spgramcf_create_default(nfft); - spgramcf p1 = spgramcf_create_default(nfft); + spgramcf c1 = spgramcf_create_default(nfft); + spgramcf c3 = spgramcf_create_default(nfft); // run channelizer float complex buf_0[P]; float complex buf_1[M]; + unsigned int i; for (i=0; i Date: Wed, 17 Apr 2024 08:14:04 -0400 Subject: [PATCH 308/334] firdes/autotest: checking edge cases in create() for arkaiser, rkaiser --- src/filter/tests/firdes_autotest.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index 4fb7a9474..c2d4e6976 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -236,15 +236,19 @@ void autotest_liquid_firdes_config() CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.0f, 0, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.6f, 0, h), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_rkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); - - CONTEND_EQUALITY(liquid_firdes_arkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); + CONTEND_EQUALITY(liquid_firdes_rkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large + + CONTEND_EQUALITY(liquid_firdes_arkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large CONTEND_EQUALITY(liquid_firdes_kaiser(h_len, 0.2f, 60.0f, 0.0f, h), LIQUID_OK ); CONTEND_EQUALITY(liquid_firdes_kaiser( 0, 0.2f, 60.0f, 0.0f, h), LIQUID_EICONFIG); From 34977c8d4017150315e2a61e0cc85c0b740b4258 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 17 Apr 2024 17:31:01 -0400 Subject: [PATCH 309/334] firdes/autotest: checking rkaiser for spectral response --- src/filter/tests/firdes_autotest.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index c2d4e6976..ae0f5d77d 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -93,15 +93,17 @@ void autotest_liquid_firdes_rrcos() { void autotest_liquid_firdes_rkaiser() { // Initialize variables - unsigned int k=2, m=3; + unsigned int k=2, m=10; float beta=0.3f; float offset=0.0f; - float isi_test = -30.0f; + float isi_test = -60.0f; // Create filter unsigned int h_len = 2*k*m+1; float h[h_len]; liquid_firdes_rkaiser(k,m,beta,offset,h); + // scale by samples per symbol + liquid_vectorf_mulscalar(h, h_len, 1.0f/(float)k, h); // compute filter ISI float isi_max; @@ -115,6 +117,15 @@ void autotest_liquid_firdes_rkaiser() // ensure ISI is sufficiently small CONTEND_LESS_THAN(isi_max, isi_test); CONTEND_LESS_THAN(isi_rms, isi_test); + + // verify spectrum + autotest_psd_s regions[] = { + {.fmin=-0.50, .fmax=-0.35f, .pmin= 0, .pmax=-70, .test_lo=0, .test_hi=1}, + {.fmin=-0.20, .fmax= 0.20f, .pmin=-1, .pmax= +1, .test_lo=1, .test_hi=1}, + {.fmin= 0.35, .fmax= 0.50f, .pmin= 0, .pmax=-70, .test_lo=0, .test_hi=1}, + }; + liquid_autotest_validate_psd_signalf(h, h_len, regions, 3, + liquid_autotest_verbose ? "autotest/logs/firdes_rkaiser.m" : NULL); } void autotest_liquid_firdes_dcblock() @@ -319,7 +330,7 @@ void testbench_firdes_prototype(const char * _type, // scale by samples per symbol liquid_vectorf_mulscalar(h, h_len, 1.0f/(float)_k, h); - // verify interpolated spectrum + // verify spectrum float bw = 1.0f / (float)_k; float f0 = 0.45*bw*(1-_beta); float f1 = 0.55*bw*(1+_beta); From 78dd6dcb982b98ef943347cad61cebb5f90dfe6d Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 17 Apr 2024 17:42:11 -0400 Subject: [PATCH 310/334] firdes/autotest: testing frequency response for rnyquist filters --- src/filter/tests/firdes_autotest.c | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index ae0f5d77d..6de829079 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -89,45 +89,51 @@ void autotest_liquid_firdes_rrcos() { CONTEND_DELTA( h[i], h0[i], 0.00001f ); } - -void autotest_liquid_firdes_rkaiser() +void test_harness_matched_filter(int _type, + unsigned int _k, + unsigned int _m, + float _beta, + float _tol_isi, + float _tol_as) { - // Initialize variables - unsigned int k=2, m=10; - float beta=0.3f; - float offset=0.0f; - float isi_test = -60.0f; - // Create filter - unsigned int h_len = 2*k*m+1; + unsigned int h_len = 2*_k*_m+1; float h[h_len]; - liquid_firdes_rkaiser(k,m,beta,offset,h); + liquid_firdes_prototype(_type,_k,_m,_beta,0.0f,h); + // scale by samples per symbol - liquid_vectorf_mulscalar(h, h_len, 1.0f/(float)k, h); + liquid_vectorf_mulscalar(h, h_len, 1.0f/(float)_k, h); // compute filter ISI float isi_max; float isi_rms; - liquid_filter_isi(h,k,m,&isi_rms,&isi_max); + liquid_filter_isi(h,_k,_m,&isi_rms,&isi_max); // convert to log scale isi_max = 20*log10f(isi_max); isi_rms = 20*log10f(isi_rms); // ensure ISI is sufficiently small - CONTEND_LESS_THAN(isi_max, isi_test); - CONTEND_LESS_THAN(isi_rms, isi_test); + CONTEND_LESS_THAN(isi_max, _tol_isi); + CONTEND_LESS_THAN(isi_rms, _tol_isi); // verify spectrum autotest_psd_s regions[] = { - {.fmin=-0.50, .fmax=-0.35f, .pmin= 0, .pmax=-70, .test_lo=0, .test_hi=1}, - {.fmin=-0.20, .fmax= 0.20f, .pmin=-1, .pmax= +1, .test_lo=1, .test_hi=1}, - {.fmin= 0.35, .fmax= 0.50f, .pmin= 0, .pmax=-70, .test_lo=0, .test_hi=1}, + {.fmin=-0.50, .fmax=-0.35f, .pmin= 0, .pmax=_tol_as, .test_lo=0, .test_hi=1}, + {.fmin=-0.20, .fmax= 0.20f, .pmin=-1, .pmax= +1, .test_lo=1, .test_hi=1}, + {.fmin= 0.35, .fmax= 0.50f, .pmin= 0, .pmax=_tol_as, .test_lo=0, .test_hi=1}, }; + char filename[256]; + sprintf(filename,"autotest/logs/firdes_%s.m", liquid_firfilt_type_str[_type][0]); liquid_autotest_validate_psd_signalf(h, h_len, regions, 3, - liquid_autotest_verbose ? "autotest/logs/firdes_rkaiser.m" : NULL); + liquid_autotest_verbose ? filename : NULL); } +// test matched filter responses for square-root nyquist filter prototypes +void autotest_firdes_rrcos () { test_harness_matched_filter(LIQUID_FIRFILT_RRC, 2, 10, 0.3f, -60.0f, -40.0f); } +void autotest_firdes_rkaiser () { test_harness_matched_filter(LIQUID_FIRFILT_RKAISER, 2, 10, 0.3f, -60.0f, -70.0f); } +void autotest_firdes_arkaiser() { test_harness_matched_filter(LIQUID_FIRFILT_ARKAISER,2, 10, 0.3f, -60.0f, -70.0f); } + void autotest_liquid_firdes_dcblock() { // options From 831ebb447de8f39d1e5e377edcc471f5fd041806 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 20 Apr 2024 17:02:52 -0400 Subject: [PATCH 311/334] rkaiser: moving tests to separate package --- include/liquid.internal.h | 16 ---------- makefile.in | 1 + src/filter/src/rkaiser.c | 29 ++++------------- src/filter/tests/firdes_autotest.c | 26 +++------------ src/filter/tests/rkaiser_autotest.c | 49 +++++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 61 deletions(-) create mode 100644 src/filter/tests/rkaiser_autotest.c diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 15f08c1e5..b35d2a643 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -794,22 +794,6 @@ float estimate_req_filter_len_Herrmann(float _df, float rkaiser_approximate_rho(unsigned int _m, float _beta); -// Design frequency-shifted root-Nyquist filter based on -// the Kaiser-windowed sinc using the bisection method -// -// _k : filter over-sampling rate (samples/symbol) -// _m : filter delay (symbols) -// _beta : filter excess bandwidth factor (0,1) -// _dt : filter fractional sample delay -// _h : resulting filter, [size: 2*_k*_m+1] -// _rho : transition bandwidth adjustment, 0 < _rho < 1 -int liquid_firdes_rkaiser_bisection(unsigned int _k, - unsigned int _m, - float _beta, - float _dt, - float * _h, - float * _rho); - // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc using the quadratic method. // diff --git a/makefile.in b/makefile.in index 1daf4d5d7..e8b69fa61 100644 --- a/makefile.in +++ b/makefile.in @@ -536,6 +536,7 @@ filter_autotests := \ src/filter/tests/rresamp_crcf_partition_autotest.c \ src/filter/tests/resamp_crcf_autotest.c \ src/filter/tests/resamp2_crcf_autotest.c \ + src/filter/tests/rkaiser_autotest.c \ src/filter/tests/symsync_copy_autotest.c \ src/filter/tests/symsync_crcf_autotest.c \ src/filter/tests/symsync_rrrf_autotest.c \ diff --git a/src/filter/src/rkaiser.c b/src/filter/src/rkaiser.c index 845439765..538783703 100644 --- a/src/filter/src/rkaiser.c +++ b/src/filter/src/rkaiser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -62,7 +62,6 @@ int liquid_firdes_rkaiser(unsigned int _k, // simply call internal method and ignore output rho value float rho; - //liquid_firdes_rkaiser_bisection(_k,_m,_beta,_dt,_h,&rho); return liquid_firdes_rkaiser_quadratic(_k,_m,_beta,_dt,_h,&rho); } @@ -90,29 +89,18 @@ int liquid_firdes_arkaiser(unsigned int _k, if (_dt < -1.0f || _dt > 1.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_arkaiser(), dt must be in [-1,1]"); -#if 0 - // compute bandwidth adjustment estimate - float rho_hat = rkaiser_approximate_rho(_m,_beta); // bandwidth correction factor -#else - // rho ~ c0 + c1*log(_beta) + c2*log^2(_beta) - - // c0 ~ 0.762886 + 0.067663*log(m) - // c1 ~ 0.065515 - // c2 ~ log( 1 - 0.088*m^-1.6 ) - + // compute bandwidth correction factor, rho ~ c0 + c1*log(_beta) + c2*log^2(_beta) float c0 = 0.762886 + 0.067663*logf(_m); float c1 = 0.065515; float c2 = logf( 1 - 0.088*powf(_m,-1.6 ) ); - float log_beta = logf(_beta); - float rho_hat = c0 + c1*log_beta + c2*log_beta*log_beta; - // ensure range is valid + // ensure range is valid and override if approximation is out of range if (rho_hat <= 0.0f || rho_hat >= 1.0f) rho_hat = rkaiser_approximate_rho(_m,_beta); -#endif + // compute filter design parameters unsigned int n=2*_k*_m+1; // filter length float kf = (float)_k; // samples/symbol (float) float del = _beta*rho_hat / kf; // transition bandwidth @@ -199,6 +187,7 @@ float rkaiser_approximate_rho(unsigned int _m, return rho_hat; } +#if 0 // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc. // @@ -317,6 +306,7 @@ int liquid_firdes_rkaiser_bisection(unsigned int _k, *_rho = x_hat; return LIQUID_OK; } +#endif // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc using the quadratic search method. @@ -334,13 +324,6 @@ int liquid_firdes_rkaiser_quadratic(unsigned int _k, float * _h, float * _rho) { - if ( _k < 1 ) - return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_quadratic(): k must be greater than 0"); - if ( _m < 1 ) - return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_quadratic(): m must be greater than 0"); - if ( (_beta < 0.0f) || (_beta > 1.0f) ) - return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_quadratic(): beta must be in [0,1]"); - // algorithm: // 1. choose initial bounding points [x0,x2] where x0 < x2 // 2. choose x1 as bisection of [x0,x2]: x1 = 0.5*(x0+x2) diff --git a/src/filter/tests/firdes_autotest.c b/src/filter/tests/firdes_autotest.c index 6de829079..527bd0dfa 100644 --- a/src/filter/tests/firdes_autotest.c +++ b/src/filter/tests/firdes_autotest.c @@ -109,15 +109,11 @@ void test_harness_matched_filter(int _type, float isi_rms; liquid_filter_isi(h,_k,_m,&isi_rms,&isi_max); - // convert to log scale - isi_max = 20*log10f(isi_max); - isi_rms = 20*log10f(isi_rms); + // ensure ISI is sufficiently small (log scale) + CONTEND_LESS_THAN(20*log10f(isi_max), _tol_isi); + CONTEND_LESS_THAN(20*log10f(isi_rms), _tol_isi); - // ensure ISI is sufficiently small - CONTEND_LESS_THAN(isi_max, _tol_isi); - CONTEND_LESS_THAN(isi_rms, _tol_isi); - - // verify spectrum + // verify spectrum response autotest_psd_s regions[] = { {.fmin=-0.50, .fmax=-0.35f, .pmin= 0, .pmax=_tol_as, .test_lo=0, .test_hi=1}, {.fmin=-0.20, .fmax= 0.20f, .pmin=-1, .pmax= +1, .test_lo=1, .test_hi=1}, @@ -253,20 +249,6 @@ void autotest_liquid_firdes_config() CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.0f, 0, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_windowf(wtype, h_len, 0.6f, 0, h), LIQUID_EICONFIG); - CONTEND_EQUALITY(liquid_firdes_rkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small - CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large - - CONTEND_EQUALITY(liquid_firdes_arkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small - CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large - CONTEND_EQUALITY(liquid_firdes_kaiser(h_len, 0.2f, 60.0f, 0.0f, h), LIQUID_OK ); CONTEND_EQUALITY(liquid_firdes_kaiser( 0, 0.2f, 60.0f, 0.0f, h), LIQUID_EICONFIG); CONTEND_EQUALITY(liquid_firdes_kaiser(h_len,-0.1f, 60.0f, 0.0f, h), LIQUID_EICONFIG); diff --git a/src/filter/tests/rkaiser_autotest.c b/src/filter/tests/rkaiser_autotest.c new file mode 100644 index 000000000..ce14167c7 --- /dev/null +++ b/src/filter/tests/rkaiser_autotest.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007 - 2024 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "autotest/autotest.h" +#include "liquid.internal.h" + +void autotest_liquid_rkaiser_config() +{ +#if LIQUID_STRICT_EXIT + AUTOTEST_WARN("skipping config test with strict exit enabled\n"); + return; +#endif +#if !LIQUID_SUPPRESS_ERROR_OUTPUT + fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); +#endif + CONTEND_EQUALITY(liquid_firdes_rkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small + CONTEND_EQUALITY(liquid_firdes_rkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large + + CONTEND_EQUALITY(liquid_firdes_arkaiser(0, 12, 0.2f, 0, NULL), LIQUID_EICONFIG); // k too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 0, 0.2f, 0, NULL), LIQUID_EICONFIG); // m too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12,-0.7f, 0, NULL), LIQUID_EICONFIG); // beta too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 2.7f, 0, NULL), LIQUID_EICONFIG); // beta too large + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f,-2, NULL), LIQUID_EICONFIG); // dt too small + CONTEND_EQUALITY(liquid_firdes_arkaiser(2, 12, 0.2f, 3, NULL), LIQUID_EICONFIG); // dt too large +} + From 7d685087f92c2667067a4dbe91cc60ded8c9cef2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 20 Apr 2024 17:52:47 -0400 Subject: [PATCH 312/334] cleaning up print statements, reducing verbosity --- src/audio/src/cvsd.c | 9 ++++---- src/buffer/src/cbuffer.proto.c | 11 ++-------- src/buffer/src/wdelay.proto.c | 11 ++-------- src/buffer/tests/window_autotest.c | 11 +--------- src/equalization/src/eqlms.proto.c | 5 ----- src/fft/src/spwaterfall.proto.c | 4 ++-- src/filter/src/dds.proto.c | 27 ++++++++++------------- src/filter/src/firdespm.c | 31 +++++++++++++-------------- src/filter/src/firfilt.proto.c | 21 ++++-------------- src/multichannel/src/firpfbch.proto.c | 11 ++++------ 10 files changed, 45 insertions(+), 96 deletions(-) diff --git a/src/audio/src/cvsd.c b/src/audio/src/cvsd.c index 11f3218dd..1c62fda02 100644 --- a/src/audio/src/cvsd.c +++ b/src/audio/src/cvsd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -112,12 +112,11 @@ int cvsd_destroy(cvsd _q) // print cvsd object parameters int cvsd_print(cvsd _q) { - printf("cvsd codec:\n"); - printf(" num bits: %u\n", _q->num_bits); - printf(" zeta : %8.4f\n", _q->zeta); + printf("num_bits, _q->zeta); #if CVSD_ENABLE_SIGNAL_CONDITIONING - printf(" alpha : %8.4f\n", _q->alpha); + printf(", alpha=%g", _q->alpha); #endif + printf(">\n"); return LIQUID_OK; } diff --git a/src/buffer/src/cbuffer.proto.c b/src/buffer/src/cbuffer.proto.c index f7d8e5928..5e13ceb9b 100644 --- a/src/buffer/src/cbuffer.proto.c +++ b/src/buffer/src/cbuffer.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -123,18 +123,11 @@ int CBUFFER(_destroy)(CBUFFER() _q) // print cbuffer object properties int CBUFFER(_print)(CBUFFER() _q) { - printf("cbuffer%s [max size: %u, max read: %u, elements: %u]\n", + printf("\n", EXTENSION, _q->max_size, _q->max_read, _q->num_elements); - - unsigned int i; - for (i=0; i<_q->num_elements; i++) { - printf("%u", i); - BUFFER_PRINT_LINE(_q,(_q->read_index+i)%(_q->max_size)) - printf("\n"); - } return LIQUID_OK; } diff --git a/src/buffer/src/wdelay.proto.c b/src/buffer/src/wdelay.proto.c index 71f694058..243cba317 100644 --- a/src/buffer/src/wdelay.proto.c +++ b/src/buffer/src/wdelay.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -116,14 +116,7 @@ int WDELAY(_destroy)(WDELAY() _q) // print delay buffer object's state to stdout int WDELAY(_print)(WDELAY() _q) { - printf("wdelay [%u elements] :\n", _q->delay+1); - unsigned int i, j; - for (i=0; i<_q->delay+1; i++) { - j = (i + _q->read_index) % (_q->delay+1); - printf("%4u", i); - BUFFER_PRINT_VALUE(_q->v[j]); - printf("\n"); - } + printf("\n", _q->delay); return LIQUID_OK; } diff --git a/src/buffer/tests/window_autotest.c b/src/buffer/tests/window_autotest.c index 3ad6fd7d9..96a8be087 100644 --- a/src/buffer/tests/window_autotest.c +++ b/src/buffer/tests/window_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2021 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -138,15 +138,6 @@ void autotest_windowf() windowf_read(w, &r); CONTEND_SAME_DATA(r,test8,10*sizeof(float)); - if (liquid_autotest_verbose) { - // manual print - printf("manual output:\n"); - for (i=0; i<10; i++) - printf("%6u : %f\n", i, r[i]); - - windowf_debug_print(w); - } - windowf_destroy(w); } diff --git a/src/equalization/src/eqlms.proto.c b/src/equalization/src/eqlms.proto.c index 9737adb44..780b3b0fa 100644 --- a/src/equalization/src/eqlms.proto.c +++ b/src/equalization/src/eqlms.proto.c @@ -236,11 +236,6 @@ int EQLMS(_reset)(EQLMS() _q) int EQLMS(_print)(EQLMS() _q) { printf("\n", EXTENSION_FULL, _q->h_len, _q->mu); - unsigned int i, j; - for (i=0; i<_q->h_len; i++) { - j = _q->h_len - i - 1; - printf(" w[%3u] = %12.4e + j*%12.4e;\n", i, creal(_q->w0[j]), cimag(_q->w0[j])); - } return LIQUID_OK; } diff --git a/src/fft/src/spwaterfall.proto.c b/src/fft/src/spwaterfall.proto.c index 38f1fda52..e47783acd 100644 --- a/src/fft/src/spwaterfall.proto.c +++ b/src/fft/src/spwaterfall.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -196,7 +196,7 @@ int SPWATERFALL(_reset)(SPWATERFALL() _q) // prints the spwaterfall object's parameters int SPWATERFALL(_print)(SPWATERFALL() _q) { - printf("spwaterfall%s: nfft=%u, time=%u\n", EXTENSION, _q->nfft, _q->time); + printf("\n", EXTENSION, _q->nfft, _q->time); return LIQUID_OK; } diff --git a/src/filter/src/dds.proto.c b/src/filter/src/dds.proto.c index cbd88826d..2fce7cbd9 100644 --- a/src/filter/src/dds.proto.c +++ b/src/filter/src/dds.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -205,22 +205,17 @@ int DDS(_destroy)(DDS() _q) // print dds object internals int DDS(_print)(DDS() _q) { - printf("direct digital synthesizer (dds), rate : %u\n", _q->rate); - printf(" fc : %8.5f\n", _q->fc0); - printf(" bw : %8.5f\n", _q->bw0); - printf(" nco/f : %8.4f\n", nco_crcf_get_frequency(_q->ncox) / (2.0f*M_PI)); - printf(" as : %8.2f [dB]\n", _q->as0); - printf(" halfband stages (low rate -> high rate) :\n"); + printf("rate, + _q->fc0, + _q->bw0, + nco_crcf_get_frequency(_q->ncox) / (2.0f*M_PI), + _q->as0, + _q->num_stages); unsigned int i; - for (i=0; i<_q->num_stages; i++) { - printf(" [%3u] : fc = %8.5f, ft = %8.5f, m = %3u\n", - i, - _q->fc[i], - _q->ft[i], - _q->m[i]); - //RESAMP2(_print)(_q->halfband_resamp[i]); - } - printf(" complexity : %12.4f\n",0.0f); + for (i=0; i<_q->num_stages; i++) + printf("{fc=%.5f, ft=%.5f, m=%u},",_q->fc[i],_q->ft[i],_q->m[i]); + printf("]>\n"); return LIQUID_OK; } diff --git a/src/filter/src/firdespm.c b/src/filter/src/firdespm.c index 00b19439b..c7e942a26 100644 --- a/src/filter/src/firdespm.c +++ b/src/filter/src/firdespm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -466,26 +466,25 @@ int firdespm_destroy(firdespm _q) int firdespm_print(firdespm _q) { unsigned int i; + printf("num_bands; i++) printf(" band %-5u", i); - printf("\n"); + printf(", lo=["); + for (i=0; i<_q->num_bands; i++) printf("%g,", _q->bands[2*i+0]); + printf("]"); - printf(" lower band edge "); - for (i=0; i<_q->num_bands; i++) printf("%16.8f", _q->bands[2*i+0]); - printf("\n"); + printf(", hi=["); + for (i=0; i<_q->num_bands; i++) printf("%g,", _q->bands[2*i+1]); + printf("]"); - printf(" upper band edge "); - for (i=0; i<_q->num_bands; i++) printf("%16.8f", _q->bands[2*i+1]); - printf("\n"); + printf(", des=["); + for (i=0; i<_q->num_bands; i++) printf("%g,", _q->des[i]); + printf("]"); - printf(" desired value "); - for (i=0; i<_q->num_bands; i++) printf("%16.8f", _q->des[i]); - printf("\n"); + printf(", w=["); + for (i=0; i<_q->num_bands; i++) printf("%g,", _q->weights[i]); + printf("]"); - printf(" weighting "); - for (i=0; i<_q->num_bands; i++) printf("%16.8f", _q->weights[i]); - printf("\n"); + printf(">\n"); return LIQUID_OK; } diff --git a/src/filter/src/firfilt.proto.c b/src/filter/src/firfilt.proto.c index aaea94b29..c7b09e4d4 100644 --- a/src/filter/src/firfilt.proto.c +++ b/src/filter/src/firfilt.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -348,23 +348,10 @@ int FIRFILT(_reset)(FIRFILT() _q) // print filter object internals (taps, buffer) int FIRFILT(_print)(FIRFILT() _q) { - printf("firfilt_%s:\n", EXTENSION_FULL); - unsigned int i; - unsigned int n = _q->h_len; - for (i=0; ih_len); + printf(", scale="); PRINTVAL_TC(_q->scale,%12.8f); - printf("\n"); - -#if LIQUID_FIRFILT_USE_WINDOW - WINDOW(_print)(_q->w); -#endif + printf(">\n"); return LIQUID_OK; } diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 0683c3a1a..9e80f450a 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -263,12 +263,9 @@ int FIRPFBCH(_reset)(FIRPFBCH() _q) // print firpfbch object int FIRPFBCH(_print)(FIRPFBCH() _q) { - unsigned int i; - printf("firpfbch (%s) [%u channels]:\n", - _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", - _q->num_channels); - for (i=0; i<_q->h_len; i++) - printf(" h[%3u] = %12.8f + %12.8f*j\n", i, crealf(_q->h[i]), cimagf(_q->h[i])); + printf("\n", + _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", + _q->num_channels); return LIQUID_OK; } From be241bcc84b390649f73167467221809d8fb12be Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 08:30:41 -0400 Subject: [PATCH 313/334] ofdmflexframe: reducing print() verbosity --- src/framing/src/ofdmflexframegen.c | 43 ++++++----------------------- src/framing/src/ofdmflexframesync.c | 23 +++++++-------- 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/src/framing/src/ofdmflexframegen.c b/src/framing/src/ofdmflexframegen.c index 90191a814..6fa6b8ab0 100644 --- a/src/framing/src/ofdmflexframegen.c +++ b/src/framing/src/ofdmflexframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// ofdmflexframegen.c -// // OFDM flexible frame generator -// #include #include @@ -273,35 +269,14 @@ int ofdmflexframegen_is_assembled(ofdmflexframegen _q) int ofdmflexframegen_print(ofdmflexframegen _q) { - printf("ofdmflexframegen:\n"); - printf(" num subcarriers : %-u\n", _q->M); - printf(" * NULL : %-u\n", _q->M_null); - printf(" * pilot : %-u\n", _q->M_pilot); - printf(" * data : %-u\n", _q->M_data); - printf(" cyclic prefix len : %-u\n", _q->cp_len); - printf(" taper len : %-u\n", _q->taper_len); - printf(" properties:\n"); - printf(" * mod scheme : %s\n", modulation_types[_q->props.mod_scheme].fullname); - printf(" * fec (inner) : %s\n", fec_scheme_str[_q->props.fec0][1]); - printf(" * fec (outer) : %s\n", fec_scheme_str[_q->props.fec1][1]); - printf(" * CRC scheme : %s\n", crc_scheme_str[_q->props.check][1]); - printf(" frame assembled : %s\n", _q->frame_assembled ? "yes" : "no"); - if (_q->frame_assembled) { - printf(" payload:\n"); - printf(" * decoded bytes : %-u\n", _q->payload_dec_len); - printf(" * encoded bytes : %-u\n", _q->payload_enc_len); - printf(" * modulated syms : %-u\n", _q->payload_mod_len); - printf(" total OFDM symbols : %-u\n", ofdmflexframegen_getframelen(_q)); - printf(" * S0 symbols : %-u @ %u\n", 2, _q->M+_q->cp_len); - printf(" * S1 symbols : %-u @ %u\n", 1, _q->M+_q->cp_len); - printf(" * header symbols : %-u @ %u\n", _q->num_symbols_header, _q->M+_q->cp_len); - printf(" * payload symbols : %-u @ %u\n", _q->num_symbols_payload, _q->M+_q->cp_len); - - // compute asymptotic spectral efficiency - unsigned int num_bits = 8*_q->payload_dec_len; - unsigned int num_samples = (_q->M+_q->cp_len)*(3 + _q->num_symbols_header + _q->num_symbols_payload); - printf(" spectral efficiency : %-6.4f b/s/Hz\n", (float)num_bits / (float)num_samples); - } + printf("M); + printf(", null=%u", _q->M_null); + printf(", pilot=%u", _q->M_pilot); + printf(", data=%u", _q->M_data); + printf(", cp=%u", _q->cp_len); + printf(", taper=%u", _q->taper_len); + printf(">\n"); return LIQUID_OK; } diff --git a/src/framing/src/ofdmflexframesync.c b/src/framing/src/ofdmflexframesync.c index 44f9fcedc..92b6c1fab 100644 --- a/src/framing/src/ofdmflexframesync.c +++ b/src/framing/src/ofdmflexframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// ofdmflexframesync.c -// // OFDM frame synchronizer -// #include #include @@ -243,14 +239,15 @@ int ofdmflexframesync_destroy(ofdmflexframesync _q) int ofdmflexframesync_print(ofdmflexframesync _q) { - printf("ofdmflexframesync:\n"); - printf(" num subcarriers : %-u\n", _q->M); - printf(" * NULL : %-u\n", _q->M_null); - printf(" * pilot : %-u\n", _q->M_pilot); - printf(" * data : %-u\n", _q->M_data); - printf(" cyclic prefix len : %-u\n", _q->cp_len); - printf(" taper len : %-u\n", _q->taper_len); - return framedatastats_print(&_q->framedatastats); + printf("M); + printf(", null=%u", _q->M_null); + printf(", pilot=%u", _q->M_pilot); + printf(", data=%u", _q->M_data); + printf(", cp=%u", _q->cp_len); + printf(", taper=%u", _q->taper_len); + printf(">\n"); + return LIQUID_OK; } int ofdmflexframesync_set_header_len(ofdmflexframesync _q, From a11dd45fdfd99eb0e780776252e6bf19e542d1d0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 08:47:36 -0400 Subject: [PATCH 314/334] qdsync: cleaning print() method --- src/framing/src/qdsync.proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framing/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index 0ec0877f6..a2c0b5dea 100644 --- a/src/framing/src/qdsync.proto.c +++ b/src/framing/src/qdsync.proto.c @@ -176,7 +176,7 @@ int QDSYNC(_reset)(QDSYNC() _q) int QDSYNC(_print)(QDSYNC() _q) { - printf("\n"); + printf("\n", _q->seq_len); return LIQUID_OK; } From 587a3619e4c9e52170a197c132b1e0dea0abbff1 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 08:49:53 -0400 Subject: [PATCH 315/334] qpilotgen/sync: reducing print() verbosity --- src/framing/src/qpilotgen.c | 9 +++------ src/framing/src/qpilotsync.c | 10 +++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/framing/src/qpilotgen.c b/src/framing/src/qpilotgen.c index 99dc23c61..e77adbf3a 100644 --- a/src/framing/src/qpilotgen.c +++ b/src/framing/src/qpilotgen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -144,11 +144,8 @@ int qpilotgen_reset(qpilotgen _q) int qpilotgen_print(qpilotgen _q) { - printf("qpilotgen:\n"); - printf(" payload len : %u\n", _q->payload_len); - printf(" pilot spacing : %u\n", _q->pilot_spacing); - printf(" num pilots : %u\n", _q->num_pilots); - printf(" frame len : %u\n", _q->frame_len); + printf("\n", + _q->payload_len, _q->frame_len, _q->num_pilots); return LIQUID_OK; } diff --git a/src/framing/src/qpilotsync.c b/src/framing/src/qpilotsync.c index b1e6cd814..92b1941a8 100644 --- a/src/framing/src/qpilotsync.c +++ b/src/framing/src/qpilotsync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -161,12 +161,8 @@ int qpilotsync_reset(qpilotsync _q) int qpilotsync_print(qpilotsync _q) { - printf("qpilotsync:\n"); - printf(" payload len : %u\n", _q->payload_len); - printf(" pilot spacing : %u\n", _q->pilot_spacing); - printf(" num pilots : %u\n", _q->num_pilots); - printf(" frame len : %u\n", _q->frame_len); - printf(" nfft : %u\n", _q->nfft); + printf("\n", + _q->payload_len, _q->frame_len, _q->num_pilots, _q->nfft); return LIQUID_OK; } From 2f9dbe8dd0a8f0d5d10b3f8b4c6ce612d1756841 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 08:58:13 -0400 Subject: [PATCH 316/334] firpfb: reducing verbosity in print() method --- examples/firpfb_rrrf_example.c | 1 + src/filter/src/firpfb.proto.c | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/firpfb_rrrf_example.c b/examples/firpfb_rrrf_example.c index 43a8e7c85..6d2df1f4a 100644 --- a/examples/firpfb_rrrf_example.c +++ b/examples/firpfb_rrrf_example.c @@ -12,6 +12,7 @@ int main(int argc, char*argv[]) { // create object firpfb_rrrf pfb = firpfb_rrrf_create_default(M, m); + firpfb_rrrf_print(pfb); // generate and interpolate signal (windowed sinc pulse) float buf_0[ num_samples]; diff --git a/src/filter/src/firpfb.proto.c b/src/filter/src/firpfb.proto.c index 9bdd223cc..20d8cb813 100644 --- a/src/filter/src/firpfb.proto.c +++ b/src/filter/src/firpfb.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -297,12 +297,11 @@ int FIRPFB(_destroy)(FIRPFB() _q) // print firpfb object's parameters int FIRPFB(_print)(FIRPFB() _q) { - printf("fir polyphase filterbank [%u] :\n", _q->num_filters); - unsigned int i; - for (i=0; i<_q->num_filters; i++) { - printf(" bank %3u: ",i); - DOTPROD(_print)(_q->dp[i]); - } + printf("num_filters, _q->h_sub_len); + printf(", scale="); + PRINTVAL_TC(_q->scale,%g); + printf(">\n"); return LIQUID_OK; } From 343e6dbf0fec37bc841e2cc7bbb29ac718b17e2f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:01:45 -0400 Subject: [PATCH 317/334] firpfbch{,2,r}: cleaning print() methods --- src/multichannel/src/firpfbch.proto.c | 4 ++-- src/multichannel/src/firpfbch2.proto.c | 15 ++++----------- src/multichannel/src/firpfbchr.proto.c | 7 ++----- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 9e80f450a..25a7e420d 100644 --- a/src/multichannel/src/firpfbch.proto.c +++ b/src/multichannel/src/firpfbch.proto.c @@ -263,9 +263,9 @@ int FIRPFBCH(_reset)(FIRPFBCH() _q) // print firpfbch object int FIRPFBCH(_print)(FIRPFBCH() _q) { - printf("\n", + printf("\n", _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", - _q->num_channels); + _q->num_channels, _q->p); return LIQUID_OK; } diff --git a/src/multichannel/src/firpfbch2.proto.c b/src/multichannel/src/firpfbch2.proto.c index 5221b4bab..4575fe842 100644 --- a/src/multichannel/src/firpfbch2.proto.c +++ b/src/multichannel/src/firpfbch2.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -255,16 +255,9 @@ int FIRPFBCH2(_reset)(FIRPFBCH2() _q) // print firpfbch2 object internals int FIRPFBCH2(_print)(FIRPFBCH2() _q) { - printf("firpfbch2_%s:\n", EXTENSION_FULL); - printf(" type : %s\n", _q->type==LIQUID_ANALYZER ? "analysis" : "synthesis"); - printf(" channels : %u\n", _q->M); - printf(" h_len : %u\n", _q->h_len); - printf(" semi-length : %u\n", _q->m); - - // TODO: print filter coefficients... - unsigned int i; - for (i=0; i<_q->M; i++) - DOTPROD(_print)(_q->dp[i]); + printf("\n", + _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", + _q->M, _q->m); return LIQUID_OK; } diff --git a/src/multichannel/src/firpfbchr.proto.c b/src/multichannel/src/firpfbchr.proto.c index bcb3d5e30..f31ca9cfc 100644 --- a/src/multichannel/src/firpfbchr.proto.c +++ b/src/multichannel/src/firpfbchr.proto.c @@ -211,11 +211,8 @@ int FIRPFBCHR(_reset)(FIRPFBCHR() _q) // print firpfbchr object internals int FIRPFBCHR(_print)(FIRPFBCHR() _q) { - printf("firpfbchr_%s:\n", EXTENSION_FULL); - printf(" channels : %u\n", _q->M); - printf(" decim (P) : %u\n", _q->P); - printf(" h_len : %u\n", _q->h_len); - printf(" semi-length : %u\n", _q->m); + printf("\n", + _q->M, _q->P, _q->m); return LIQUID_OK; } From a86cca804c02b8a5797daef148cb9685734babe5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:06:33 -0400 Subject: [PATCH 318/334] ofdmframe{gen,sync}: cleaning print() methods --- examples/ofdmframesync_example.c | 4 ++-- src/framing/src/ofdmflexframegen.c | 2 +- src/framing/src/ofdmflexframesync.c | 2 +- src/multichannel/src/ofdmframegen.c | 20 ++++++++++---------- src/multichannel/src/ofdmframesync.c | 16 +++++++++++----- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/ofdmframesync_example.c b/examples/ofdmframesync_example.c index 5464d617f..5c2d6eee0 100644 --- a/examples/ofdmframesync_example.c +++ b/examples/ofdmframesync_example.c @@ -102,11 +102,11 @@ int main(int argc, char*argv[]) // create frame generator ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, p); - //ofdmframegen_print(fg); + ofdmframegen_print(fg); // create frame synchronizer ofdmframesync fs = ofdmframesync_create(M, cp_len, taper_len, p, callback, (void*)&data); - //ofdmframesync_print(fs); + ofdmframesync_print(fs); unsigned int n=0; diff --git a/src/framing/src/ofdmflexframegen.c b/src/framing/src/ofdmflexframegen.c index 6fa6b8ab0..38f71b9f9 100644 --- a/src/framing/src/ofdmflexframegen.c +++ b/src/framing/src/ofdmflexframegen.c @@ -269,7 +269,7 @@ int ofdmflexframegen_is_assembled(ofdmflexframegen _q) int ofdmflexframegen_print(ofdmflexframegen _q) { - printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); diff --git a/src/framing/src/ofdmflexframesync.c b/src/framing/src/ofdmflexframesync.c index 92b6c1fab..29057b923 100644 --- a/src/framing/src/ofdmflexframesync.c +++ b/src/framing/src/ofdmflexframesync.c @@ -239,7 +239,7 @@ int ofdmflexframesync_destroy(ofdmflexframesync _q) int ofdmflexframesync_print(ofdmflexframesync _q) { - printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); diff --git a/src/multichannel/src/ofdmframegen.c b/src/multichannel/src/ofdmframegen.c index 150cb8532..55af8072f 100644 --- a/src/multichannel/src/ofdmframegen.c +++ b/src/multichannel/src/ofdmframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -187,15 +187,15 @@ int ofdmframegen_destroy(ofdmframegen _q) int ofdmframegen_print(ofdmframegen _q) { - printf("ofdmframegen:\n"); - printf(" num subcarriers : %-u\n", _q->M); - printf(" - NULL : %-u\n", _q->M_null); - printf(" - pilot : %-u\n", _q->M_pilot); - printf(" - data : %-u\n", _q->M_data); - printf(" cyclic prefix len : %-u\n", _q->cp_len); - printf(" taper len : %-u\n", _q->taper_len); - printf(" "); - return ofdmframe_print_sctype(_q->p, _q->M); + printf("M); + printf(", null=%u", _q->M_null); + printf(", pilot=%u", _q->M_pilot); + printf(", data=%u", _q->M_data); + printf(", cp=%u", _q->cp_len); + printf(", taper=%u", _q->taper_len); + printf(">\n"); + return LIQUID_OK; } int ofdmframegen_reset(ofdmframegen _q) diff --git a/src/multichannel/src/ofdmframesync.c b/src/multichannel/src/ofdmframesync.c index 515c5c7df..7426baf52 100644 --- a/src/multichannel/src/ofdmframesync.c +++ b/src/multichannel/src/ofdmframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -84,6 +84,7 @@ struct ofdmframesync_s { unsigned int M2; // number of subcarriers (divided by 2) unsigned int cp_len; // cyclic prefix length unsigned char * p; // subcarrier allocation (null, pilot, data) + unsigned int taper_len; // number of samples in tapering window/overlap // constants unsigned int M_null; // number of null subcarriers @@ -197,6 +198,7 @@ ofdmframesync ofdmframesync_create(unsigned int _M, q->M = _M; q->cp_len = _cp_len; + q->taper_len = _taper_len; // derived values q->M2 = _M/2; @@ -346,10 +348,14 @@ int ofdmframesync_destroy(ofdmframesync _q) int ofdmframesync_print(ofdmframesync _q) { - printf("ofdmframesync:\n"); - printf(" num subcarriers : %-u\n", _q->M); - printf(" cyclic prefix len : %-u\n", _q->cp_len); - //printf(" taper len : %-u\n", _q->taper_len); + printf("M); + printf(", null=%u", _q->M_null); + printf(", pilot=%u", _q->M_pilot); + printf(", data=%u", _q->M_data); + printf(", cp=%u", _q->cp_len); + printf(", taper=%u", _q->taper_len); + printf(">\n"); return LIQUID_OK; } From ad70aa1c1e5bb1de794fdb767a4219b57937d2b2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:10:50 -0400 Subject: [PATCH 319/334] optim/gasearch: cleaning print() methods for gasearch, chromosome --- src/optim/src/chromosome.c | 14 ++++++-------- src/optim/src/gasearch.c | 21 ++++++++------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/optim/src/chromosome.c b/src/optim/src/chromosome.c index ea1147a52..32719ec3b 100644 --- a/src/optim/src/chromosome.c +++ b/src/optim/src/chromosome.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// chromosome.c -// +// chromosome object for genetic algorithm search #include #include @@ -138,7 +136,7 @@ unsigned int chromosome_get_num_traits(chromosome _q) int chromosome_print(chromosome _q) { unsigned int i,j; - printf("chromosome: "); + printf("num_traits; i++) { for (j=0; j<_q->bits_per_trait[i]; j++) { @@ -149,17 +147,17 @@ int chromosome_print(chromosome _q) if (i != _q->num_traits-1) printf("."); } - printf("\n"); + printf(">\n"); return LIQUID_OK; } int chromosome_printf(chromosome _q) { unsigned int i; - printf("chromosome: "); + printf("num_traits; i++) printf("%6.3f", chromosome_valuef(_q,i)); - printf("\n"); + printf(">\n"); return LIQUID_OK; } diff --git a/src/optim/src/gasearch.c b/src/optim/src/gasearch.c index a846aabdf..e84376faa 100644 --- a/src/optim/src/gasearch.c +++ b/src/optim/src/gasearch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -141,18 +141,13 @@ int gasearch_destroy(gasearch _g) // print search parameter internals int gasearch_print(gasearch _g) { - printf("ga search :\n"); - printf(" num traits : %u\n", _g->num_parameters); - printf(" bits/chromosome : %u\n", _g->bits_per_chromosome); - printf(" population size : %u\n", _g->population_size); - printf(" selection size : %u\n", _g->selection_size); - printf(" mutation rate : %12.8f\n", _g->mutation_rate); - printf("population:\n"); - unsigned int i; - for (i=0; i<_g->population_size; i++) { - printf("%4u: [%8.4f] ", i, _g->utility[i]); - chromosome_printf( _g->population[i] ); - } + printf("num_parameters); + printf(", bits=%u", _g->bits_per_chromosome); + printf(", population=%u", _g->population_size); + printf(", selection=%u", _g->selection_size); + printf(", mutation=%g", _g->mutation_rate); + printf(">\n"); return LIQUID_OK; } From 6391d4cb5c3bc92b2f4dfaa9ad792342d67f3d06 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:25:05 -0400 Subject: [PATCH 320/334] modem: cleaning print() method for consistency --- src/modem/src/modem_common.proto.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modem/src/modem_common.proto.c b/src/modem/src/modem_common.proto.c index 52bc452f5..6af604b63 100644 --- a/src/modem/src/modem_common.proto.c +++ b/src/modem/src/modem_common.proto.c @@ -300,9 +300,8 @@ int MODEM(_destroy)(MODEM() _q) // print a modem object int MODEM(_print)(MODEM() _q) { - printf("linear modem:\n"); - printf(" scheme: %s\n", modulation_types[_q->scheme].name); - printf(" bits/symbol: %u\n", _q->m); + printf("\n", + EXTENSION, modulation_types[_q->scheme].name, 1 << (_q->m)); return LIQUID_OK; } From 9370f9ea1e24b3ca2b44a5c11a09ac955f6f6b21 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:39:22 -0400 Subject: [PATCH 321/334] iirfiltsos: cleaning print() method for consistency --- src/filter/src/iirfiltsos.proto.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/filter/src/iirfiltsos.proto.c b/src/filter/src/iirfiltsos.proto.c index fce6a47c5..a5b89e186 100644 --- a/src/filter/src/iirfiltsos.proto.c +++ b/src/filter/src/iirfiltsos.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -134,17 +134,19 @@ int IIRFILTSOS(_destroy)(IIRFILTSOS() _q) // print iirfiltsos object properties to stdout int IIRFILTSOS(_print)(IIRFILTSOS() _q) { - printf("iir filter | sos:\n"); + printf("b[0],%12.8f); printf(","); - PRINTVAL_TC(_q->b[1],%12.8f); printf(","); - PRINTVAL_TC(_q->b[2],%12.8f); printf("\n"); + printf(", b=["); + PRINTVAL_TC(_q->b[0],%g); printf(","); + PRINTVAL_TC(_q->b[1],%g); printf(","); + PRINTVAL_TC(_q->b[2],%g); printf("]"); - printf(" a : "); - PRINTVAL_TC(_q->a[0],%12.8f); printf(","); - PRINTVAL_TC(_q->a[1],%12.8f); printf(","); - PRINTVAL_TC(_q->a[2],%12.8f); printf("\n"); + printf(", a=["); + PRINTVAL_TC(_q->a[0],%g); printf(","); + PRINTVAL_TC(_q->a[1],%g); printf(","); + PRINTVAL_TC(_q->a[2],%g); printf("]"); + + printf(">\n"); return LIQUID_OK; } From 34532777341249267329152f8f5eb64f1002f5c2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:44:22 -0400 Subject: [PATCH 322/334] iirfilt: cleaning print() method for consistency --- src/filter/src/iirfilt.proto.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/filter/src/iirfilt.proto.c b/src/filter/src/iirfilt.proto.c index c89cbfa82..3411a1f94 100644 --- a/src/filter/src/iirfilt.proto.c +++ b/src/filter/src/iirfilt.proto.c @@ -504,9 +504,13 @@ int IIRFILT(_destroy)(IIRFILT() _q) // print iirfilt object internals int IIRFILT(_print)(IIRFILT() _q) { - printf("iir filter [%s]:\n", _q->type == IIRFILT_TYPE_NORM ? "normal" : "sos"); - unsigned int i; + printf("type == IIRFILT_TYPE_NORM ? "normal" : "sos"); + printf(", order=%u", _q->n-1); + printf(">\n"); +#if 0 + unsigned int i; if (_q->type == IIRFILT_TYPE_SOS) { for (i=0; i<_q->nsos; i++) IIRFILTSOS(_print)(_q->qsos[i]); @@ -521,14 +525,8 @@ int IIRFILT(_print)(IIRFILT() _q) for (i=0; i<_q->na; i++) PRINTVAL_TC(_q->a[i],%12.8f); printf("\n"); - -#if 0 - printf(" v :"); - for (i=0; i<_q->n; i++) - PRINTVAL(_q->v[i]); - printf("\n"); -#endif } +#endif return LIQUID_OK; } From eb4d54678de0c05d1e241bbcfbb4ee35631d2a17 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:47:19 -0400 Subject: [PATCH 323/334] fftfilt: cleaning print() method for consistency --- src/filter/src/fftfilt.proto.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/filter/src/fftfilt.proto.c b/src/filter/src/fftfilt.proto.c index bbf000943..eb52ba612 100644 --- a/src/filter/src/fftfilt.proto.c +++ b/src/filter/src/fftfilt.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // finite impulse response (FIR) filter using fast Fourier transforms (FFTs) -// #include #include @@ -162,19 +160,12 @@ int FFTFILT(_reset)(FFTFILT() _q) // print filter object internals (taps, buffer) int FFTFILT(_print)(FFTFILT() _q) { - printf("fftfilt_%s: [h_len=%u, n=%u]\n", EXTENSION_FULL, _q->h_len, _q->n); - unsigned int i; - unsigned int n = _q->h_len; - for (i=0; ih_len, _q->n); - // print scaling - printf(" scale = "); - PRINTVAL_TC(_q->scale,%12.8f); - printf("\n"); + printf(", scale="); + PRINTVAL_TC(_q->scale,%g); + printf(">\n"); return LIQUID_OK; } From 89310391d7febfdee72c6152a8fe7d14d93008d2 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:49:57 -0400 Subject: [PATCH 324/334] cbuffer: removing antiquated debug print method --- examples/cbufferf_example.c | 4 --- include/liquid.h | 3 -- src/buffer/src/cbuffer.proto.c | 43 +---------------------------- src/buffer/tests/cbuffer_autotest.c | 5 ++-- 4 files changed, 3 insertions(+), 52 deletions(-) diff --git a/examples/cbufferf_example.c b/examples/cbufferf_example.c index b660f1958..d4d850d6d 100644 --- a/examples/cbufferf_example.c +++ b/examples/cbufferf_example.c @@ -1,6 +1,3 @@ -// -// cbufferf_example.c -// // This example demonstrates the circular buffer object on // floating-point data. // @@ -35,7 +32,6 @@ int main() { cbufferf_write(cb, v, 8); // print - cbufferf_debug_print(cb); cbufferf_print(cb); // destroy object diff --git a/include/liquid.h b/include/liquid.h index 3d3406e07..3be8080e8 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -420,9 +420,6 @@ int CBUFFER(_destroy)(CBUFFER() _q); \ /* Print cbuffer object properties to stdout */ \ int CBUFFER(_print)(CBUFFER() _q); \ \ -/* Print cbuffer object properties and internal state */ \ -int CBUFFER(_debug_print)(CBUFFER() _q); \ - \ /* Clear internal buffer */ \ int CBUFFER(_reset)(CBUFFER() _q); \ \ diff --git a/src/buffer/src/cbuffer.proto.c b/src/buffer/src/cbuffer.proto.c index 5e13ceb9b..d13364be4 100644 --- a/src/buffer/src/cbuffer.proto.c +++ b/src/buffer/src/cbuffer.proto.c @@ -124,48 +124,7 @@ int CBUFFER(_destroy)(CBUFFER() _q) int CBUFFER(_print)(CBUFFER() _q) { printf("\n", - EXTENSION, - _q->max_size, - _q->max_read, - _q->num_elements); - return LIQUID_OK; -} - -// print cbuffer object properties and internal state -int CBUFFER(_debug_print)(CBUFFER() _q) -{ - printf("cbuffer%s [max size: %u, max read: %u, elements: %u]\n", - EXTENSION, - _q->max_size, - _q->max_read, - _q->num_elements); - - unsigned int i; - for (i=0; i<_q->max_size; i++) { - // print read index pointer - if (i==_q->read_index) - printf(""); - else - printf(" "); - - // print write index pointer - if (i==_q->write_index) - printf(""); - else - printf(" "); - - // print buffer value - BUFFER_PRINT_LINE(_q,i) - printf("\n"); - } - printf("----------------------------------\n"); - - // print excess buffer memory - for (i=_q->max_size; i<_q->num_allocated; i++) { - printf(" "); - BUFFER_PRINT_LINE(_q,i) - printf("\n"); - } + EXTENSION, _q->max_size, _q->max_read, _q->num_elements); return LIQUID_OK; } diff --git a/src/buffer/tests/cbuffer_autotest.c b/src/buffer/tests/cbuffer_autotest.c index edcac8ccd..16986100a 100644 --- a/src/buffer/tests/cbuffer_autotest.c +++ b/src/buffer/tests/cbuffer_autotest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -315,8 +315,7 @@ void autotest_cbufferf_config() CONTEND_EQUALITY(cbufferf_push(q,0), LIQUID_OK); // ensure no errors with printing - CONTEND_EQUALITY(cbufferf_print(q), LIQUID_OK); - CONTEND_EQUALITY(cbufferf_debug_print(q), LIQUID_OK); + CONTEND_EQUALITY(cbufferf_print(q), LIQUID_OK); // buffer full; cannot write more CONTEND_INEQUALITY(cbufferf_push(q,0), LIQUID_OK); From cfc869d80501da3a11f7802ad0ddcec6f3648ada Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sun, 21 Apr 2024 09:54:26 -0400 Subject: [PATCH 325/334] agc: cleaning print() statement for consistency --- src/agc/src/agc.proto.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/agc/src/agc.proto.c b/src/agc/src/agc.proto.c index 02eb6ef7f..a654c7910 100644 --- a/src/agc/src/agc.proto.c +++ b/src/agc/src/agc.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -113,12 +113,12 @@ int AGC(_destroy)(AGC() _q) // print agc object internals int AGC(_print)(AGC() _q) { - printf("agc [rssi: %12.4f dB, output gain: %.3f dB, bw: %12.4e, locked: %s, squelch: %s]:\n", - AGC(_get_rssi)(_q), - _q->scale > 0 ? 10.*log10f(_q->scale) : -100.0f, - _q->bandwidth, - _q->is_locked ? "yes" : "no", - _q->squelch_mode == LIQUID_AGC_SQUELCH_DISABLED ? "disabled" : "enabled"); + printf("\n", + AGC(_get_rssi)(_q), + _q->scale > 0 ? 10.*log10f(_q->scale) : -100.0f, + _q->bandwidth, + _q->is_locked ? "true" : "false", + _q->squelch_mode == LIQUID_AGC_SQUELCH_DISABLED ? "disabled" : "enabled"); return LIQUID_OK; } From 155bf9a4d767888175e7d63142fcbb83ea9513ed Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 24 Apr 2024 07:57:37 -0400 Subject: [PATCH 326/334] cleaning up print statements for consistency in agc, audio, eq, filter --- src/audio/src/cvsd.c | 2 +- src/buffer/src/wdelay.proto.c | 2 +- src/equalization/src/eqlms.proto.c | 2 +- src/equalization/src/eqrls.proto.c | 41 ++---------------------------- src/filter/src/autocorr.proto.c | 2 +- src/filter/src/dds.proto.c | 2 +- src/filter/src/fdelay.proto.c | 2 +- src/filter/src/firdecim.proto.c | 10 +++----- src/filter/src/firdespm.c | 2 +- src/filter/src/firfarrow.proto.c | 6 +++-- src/filter/src/firfilt.proto.c | 2 +- src/filter/src/firhilb.proto.c | 14 +--------- src/filter/src/firinterp.proto.c | 7 ++--- src/filter/src/firpfb.proto.c | 2 +- src/filter/src/iirdecim.proto.c | 2 +- src/filter/src/iirhilb.proto.c | 2 +- src/filter/src/iirinterp.proto.c | 2 +- src/filter/src/msresamp.proto.c | 7 +++++ src/filter/src/msresamp2.proto.c | 7 +++++ src/filter/src/ordfilt.proto.c | 2 +- src/filter/src/resamp.proto.c | 3 ++- src/filter/src/resamp2.proto.c | 2 +- src/filter/src/rresamp.proto.c | 2 +- src/filter/src/symsync.proto.c | 3 ++- 24 files changed, 48 insertions(+), 80 deletions(-) diff --git a/src/audio/src/cvsd.c b/src/audio/src/cvsd.c index 1c62fda02..370976cb0 100644 --- a/src/audio/src/cvsd.c +++ b/src/audio/src/cvsd.c @@ -112,7 +112,7 @@ int cvsd_destroy(cvsd _q) // print cvsd object parameters int cvsd_print(cvsd _q) { - printf("num_bits, _q->zeta); + printf("num_bits, _q->zeta); #if CVSD_ENABLE_SIGNAL_CONDITIONING printf(", alpha=%g", _q->alpha); #endif diff --git a/src/buffer/src/wdelay.proto.c b/src/buffer/src/wdelay.proto.c index 243cba317..d4a9735c9 100644 --- a/src/buffer/src/wdelay.proto.c +++ b/src/buffer/src/wdelay.proto.c @@ -116,7 +116,7 @@ int WDELAY(_destroy)(WDELAY() _q) // print delay buffer object's state to stdout int WDELAY(_print)(WDELAY() _q) { - printf("\n", _q->delay); + printf("\n", _q->delay); return LIQUID_OK; } diff --git a/src/equalization/src/eqlms.proto.c b/src/equalization/src/eqlms.proto.c index 780b3b0fa..7d1162cb5 100644 --- a/src/equalization/src/eqlms.proto.c +++ b/src/equalization/src/eqlms.proto.c @@ -235,7 +235,7 @@ int EQLMS(_reset)(EQLMS() _q) // print eqlms object internals int EQLMS(_print)(EQLMS() _q) { - printf("\n", EXTENSION_FULL, _q->h_len, _q->mu); + printf("\n", EXTENSION_FULL, _q->h_len, _q->mu); return LIQUID_OK; } diff --git a/src/equalization/src/eqrls.proto.c b/src/equalization/src/eqrls.proto.c index b0488e191..c7c189623 100644 --- a/src/equalization/src/eqrls.proto.c +++ b/src/equalization/src/eqrls.proto.c @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // Recursive least-squares (RLS) equalizer -// #include #include @@ -181,43 +179,8 @@ int EQRLS(_destroy)(EQRLS() _q) // print eqrls object internals int EQRLS(_print)(EQRLS() _q) { - printf("equalizer (RLS):\n"); - printf(" order: %u\n", _q->p); - unsigned int i; - for (i=0; i<_q->p; i++) { -#if T_COMPLEX - printf(" %3u: w = %12.8f + j%12.8f\n", i, crealf(_q->w1[_q->p-i-1]), cimagf(_q->w1[_q->p-i-1])); -#else - printf(" %3u: w = %12.8f\n", i, _q->w1[_q->p-i-1]); -#endif - } - -#ifdef DEBUG - unsigned int r,c,p=_q->p; - printf("P0:\n"); - for (r=0; rP0,p,p,r,c)); - } - printf("\n"); - } - - printf("P1:\n"); - for (r=0; rP1,p,p,r,c)); - } - printf("\n"); - } - - printf("gxl:\n"); - for (r=0; rgxl,p,p,r,c)); - } - printf("\n"); - } -#endif + printf("\n", + EXTENSION_FULL, _q->p, _q->lambda, _q->delta); return LIQUID_OK; } diff --git a/src/filter/src/autocorr.proto.c b/src/filter/src/autocorr.proto.c index 22796462b..c2cbf2ebb 100644 --- a/src/filter/src/autocorr.proto.c +++ b/src/filter/src/autocorr.proto.c @@ -111,7 +111,7 @@ int AUTOCORR(_reset)(AUTOCORR() _q) // print auto-correlator parameters to stdout int AUTOCORR(_print)(AUTOCORR() _q) { - printf("autocorr [%u window, %u delay]\n", _q->window_size, _q->delay); + printf("\n", _q->window_size, _q->delay); return LIQUID_OK; } diff --git a/src/filter/src/dds.proto.c b/src/filter/src/dds.proto.c index 2fce7cbd9..b85b2b531 100644 --- a/src/filter/src/dds.proto.c +++ b/src/filter/src/dds.proto.c @@ -205,7 +205,7 @@ int DDS(_destroy)(DDS() _q) // print dds object internals int DDS(_print)(DDS() _q) { - printf("rate, _q->fc0, _q->bw0, diff --git a/src/filter/src/fdelay.proto.c b/src/filter/src/fdelay.proto.c index 3a5af351a..ac21cc535 100644 --- a/src/filter/src/fdelay.proto.c +++ b/src/filter/src/fdelay.proto.c @@ -105,7 +105,7 @@ int FDELAY(_reset)(FDELAY() _q) // Print delay object internals int FDELAY(_print)(FDELAY() _q) { - printf("\n", + printf("\n", _q->nmax, _q->m, _q->npfb, _q->delay); return LIQUID_OK; } diff --git a/src/filter/src/firdecim.proto.c b/src/filter/src/firdecim.proto.c index ab7ae2f09..c52006d2f 100644 --- a/src/filter/src/firdecim.proto.c +++ b/src/filter/src/firdecim.proto.c @@ -182,13 +182,11 @@ int FIRDECIM(_destroy)(FIRDECIM() _q) // print decimator object internals int FIRDECIM(_print)(FIRDECIM() _q) { - printf("FIRDECIM() [%u] :\n", _q->M); - printf(" window:\n"); - WINDOW(_print)(_q->w); + printf("M); // print scaling - printf(" scale = "); - PRINTVAL_TC(_q->scale,%12.8f); - printf("\n"); + printf(", scale="); + PRINTVAL_TC(_q->scale,%g); + printf(">\n"); return LIQUID_OK; } diff --git a/src/filter/src/firdespm.c b/src/filter/src/firdespm.c index c7e942a26..3c0fdcee1 100644 --- a/src/filter/src/firdespm.c +++ b/src/filter/src/firdespm.c @@ -466,7 +466,7 @@ int firdespm_destroy(firdespm _q) int firdespm_print(firdespm _q) { unsigned int i; - printf("num_bands; i++) printf("%g,", _q->bands[2*i+0]); diff --git a/src/filter/src/firfarrow.proto.c b/src/filter/src/firfarrow.proto.c index 3cca5a33a..38c0da14f 100644 --- a/src/filter/src/firfarrow.proto.c +++ b/src/filter/src/firfarrow.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -136,7 +136,8 @@ int FIRFARROW(_destroy)(FIRFARROW() _q) // print firfarrow object's internal properties int FIRFARROW(_print)(FIRFARROW() _q) { - printf("firfarrow [len : %u, poly-order : %u]\n", _q->h_len, _q->Q); + printf("\n", _q->h_len, _q->Q); +#if 0 printf("polynomial coefficients:\n"); // print coefficients @@ -155,6 +156,7 @@ int FIRFARROW(_print)(FIRFARROW() _q) PRINTVAL_TC(_q->h[n-i-1],%12.8f); printf(";\n"); } +#endif return LIQUID_OK; } diff --git a/src/filter/src/firfilt.proto.c b/src/filter/src/firfilt.proto.c index c7b09e4d4..c70e235f1 100644 --- a/src/filter/src/firfilt.proto.c +++ b/src/filter/src/firfilt.proto.c @@ -348,7 +348,7 @@ int FIRFILT(_reset)(FIRFILT() _q) // print filter object internals (taps, buffer) int FIRFILT(_print)(FIRFILT() _q) { - printf("h_len); + printf("h_len); printf(", scale="); PRINTVAL_TC(_q->scale,%12.8f); printf(">\n"); diff --git a/src/filter/src/firhilb.proto.c b/src/filter/src/firhilb.proto.c index cb083d476..f5da32f39 100644 --- a/src/filter/src/firhilb.proto.c +++ b/src/filter/src/firhilb.proto.c @@ -157,19 +157,7 @@ int FIRHILB(_destroy)(FIRHILB() _q) // print firhilb object internals int FIRHILB(_print)(FIRHILB() _q) { - printf("fir hilbert transform: [%u]\n", _q->h_len); - unsigned int i; - for (i=0; i<_q->h_len; i++) { - printf(" hc(%4u) = %8.4f + j*%8.4f;\n", i+1, crealf(_q->hc[i]), cimagf(_q->hc[i])); - } - printf("---\n"); - for (i=0; i<_q->h_len; i++) { - printf(" h(%4u) = %8.4f;\n", i+1, _q->h[i]); - } - printf("---\n"); - for (i=0; i<_q->hq_len; i++) { - printf(" hq(%4u) = %8.4f;\n", i+1, _q->hq[i]); - } + printf("\n", EXTENSION_SHORT, _q->h_len); return LIQUID_OK; } diff --git a/src/filter/src/firinterp.proto.c b/src/filter/src/firinterp.proto.c index 98f605bc5..655326aa0 100644 --- a/src/filter/src/firinterp.proto.c +++ b/src/filter/src/firinterp.proto.c @@ -212,9 +212,10 @@ int FIRINTERP(_destroy)(FIRINTERP() _q) // print interpolator state int FIRINTERP(_print)(FIRINTERP() _q) { - printf("interp():\n"); - printf(" interp : %u\n", _q->M); - printf(" h_len : %u\n", _q->h_len); + printf("M); + printf(", h_len=%u", _q->h_len); + printf(">\n"); return FIRPFB(_print)(_q->filterbank); } diff --git a/src/filter/src/firpfb.proto.c b/src/filter/src/firpfb.proto.c index 20d8cb813..a13b3815c 100644 --- a/src/filter/src/firpfb.proto.c +++ b/src/filter/src/firpfb.proto.c @@ -297,7 +297,7 @@ int FIRPFB(_destroy)(FIRPFB() _q) // print firpfb object's parameters int FIRPFB(_print)(FIRPFB() _q) { - printf("num_filters, _q->h_sub_len); printf(", scale="); PRINTVAL_TC(_q->scale,%g); diff --git a/src/filter/src/iirdecim.proto.c b/src/filter/src/iirdecim.proto.c index 08e29e57d..7303148d5 100644 --- a/src/filter/src/iirdecim.proto.c +++ b/src/filter/src/iirdecim.proto.c @@ -136,7 +136,7 @@ int IIRDECIM(_destroy)(IIRDECIM() _q) // print interpolator state int IIRDECIM(_print)(IIRDECIM() _q) { - printf("\n", EXTENSION_FULL, _q->M); + printf("\n", EXTENSION_FULL, _q->M); return LIQUID_OK; } diff --git a/src/filter/src/iirhilb.proto.c b/src/filter/src/iirhilb.proto.c index 51fcf6e22..d55756eb8 100644 --- a/src/filter/src/iirhilb.proto.c +++ b/src/filter/src/iirhilb.proto.c @@ -113,7 +113,7 @@ int IIRHILB(_destroy)(IIRHILB() _q) // print iirhilb object internals int IIRHILB(_print)(IIRHILB() _q) { - printf("\n"); + printf("\n"); return LIQUID_OK; } diff --git a/src/filter/src/iirinterp.proto.c b/src/filter/src/iirinterp.proto.c index d60b56552..e54f35b57 100644 --- a/src/filter/src/iirinterp.proto.c +++ b/src/filter/src/iirinterp.proto.c @@ -138,7 +138,7 @@ int IIRINTERP(_destroy)(IIRINTERP() _q) // print interpolator state int IIRINTERP(_print)(IIRINTERP() _q) { - printf("\n", EXTENSION_FULL, _q->M); + printf("\n", EXTENSION_FULL, _q->M); return LIQUID_OK; } diff --git a/src/filter/src/msresamp.proto.c b/src/filter/src/msresamp.proto.c index 940fd5cd7..36475764b 100644 --- a/src/filter/src/msresamp.proto.c +++ b/src/filter/src/msresamp.proto.c @@ -187,6 +187,12 @@ int MSRESAMP(_destroy)(MSRESAMP() _q) // print msresamp object internals int MSRESAMP(_print)(MSRESAMP() _q) { + printf("\n", + EXTENSION_FULL, + _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim", + _q->num_halfband_stages, + _q->rate); +#if 0 printf("multi-stage resampler\n"); printf(" composite rate : %12.10f\n", _q->rate); printf(" type : %s\n", _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim"); @@ -227,6 +233,7 @@ int MSRESAMP(_print)(MSRESAMP() _q) printf(" [%2u, r=%11.7f] : arbitrary, r=%12.8f\n", stage, r, rate); stage++; } +#endif return LIQUID_OK; } diff --git a/src/filter/src/msresamp2.proto.c b/src/filter/src/msresamp2.proto.c index bb46a2625..f2884297a 100644 --- a/src/filter/src/msresamp2.proto.c +++ b/src/filter/src/msresamp2.proto.c @@ -228,6 +228,12 @@ int MSRESAMP2(_destroy)(MSRESAMP2() _q) // print msresamp2 object internals int MSRESAMP2(_print)(MSRESAMP2() _q) { + printf("\n", + EXTENSION_FULL, + _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim", + _q->num_stages, + MSRESAMP2(_get_rate)(_q)); +#if 0 printf("multi-stage half-band resampler:\n"); printf(" type : %s\n", _q->type == LIQUID_RESAMP_DECIM ? "decimator" : "interpolator"); printf(" number of stages : %u stage%s\n", _q->num_stages, _q->num_stages == 1 ? "" : "s"); @@ -246,6 +252,7 @@ int MSRESAMP2(_print)(MSRESAMP2() _q) printf(" stage[%2u] {m=%3u, as=%6.2f dB, fc=%6.3f, f0=%6.3f}\n", i, _q->m_stage[g], _q->as_stage[g], _q->fc_stage[g], _q->f0_stage[g]); } +#endif return LIQUID_OK; } diff --git a/src/filter/src/ordfilt.proto.c b/src/filter/src/ordfilt.proto.c index da81c8a26..43a794dfc 100644 --- a/src/filter/src/ordfilt.proto.c +++ b/src/filter/src/ordfilt.proto.c @@ -145,7 +145,7 @@ int ORDFILT(_reset)(ORDFILT() _q) // print filter object internals (taps, buffer) int ORDFILT(_print)(ORDFILT() _q) { - printf("ordfilt_%s:\n", EXTENSION_FULL); + printf("\n", EXTENSION_FULL, _q->n, _q->k); return LIQUID_OK; } diff --git a/src/filter/src/resamp.proto.c b/src/filter/src/resamp.proto.c index 3a7866968..1b22faedb 100644 --- a/src/filter/src/resamp.proto.c +++ b/src/filter/src/resamp.proto.c @@ -185,7 +185,8 @@ int RESAMP(_destroy)(RESAMP() _q) // print resampler object int RESAMP(_print)(RESAMP() _q) { - printf("resampler [rate: %f]\n", _q->rate); + printf("\n", + EXTENSION_FULL, _q->r, _q->m, _q->as, _q->fc, _q->npfb); return FIRPFB(_print)(_q->f); } diff --git a/src/filter/src/resamp2.proto.c b/src/filter/src/resamp2.proto.c index 0122ff4e5..98256ffdc 100644 --- a/src/filter/src/resamp2.proto.c +++ b/src/filter/src/resamp2.proto.c @@ -211,7 +211,7 @@ int RESAMP2(_destroy)(RESAMP2() _q) // print a resamp2 object's internals int RESAMP2(_print)(RESAMP2() _q) { - printf("\n", + printf("\n", EXTENSION_FULL, _q->h_len,_q->f0); return LIQUID_OK; } diff --git a/src/filter/src/rresamp.proto.c b/src/filter/src/rresamp.proto.c index 2fc6177b3..bb3484e56 100644 --- a/src/filter/src/rresamp.proto.c +++ b/src/filter/src/rresamp.proto.c @@ -209,7 +209,7 @@ int RRESAMP(_destroy)(RRESAMP() _q) // print resampler object int RRESAMP(_print)(RRESAMP() _q) { - printf("\n", EXTENSION_FULL, + printf("\n", EXTENSION_FULL, _q->P, _q->Q, (float)(_q->P) / (float)(_q->Q), _q->block_len, _q->m); return LIQUID_OK; } diff --git a/src/filter/src/symsync.proto.c b/src/filter/src/symsync.proto.c index 7a825ed9c..7f2723755 100644 --- a/src/filter/src/symsync.proto.c +++ b/src/filter/src/symsync.proto.c @@ -287,7 +287,8 @@ int SYMSYNC(_destroy)(SYMSYNC() _q) // print symsync object's parameters int SYMSYNC(_print)(SYMSYNC() _q) { - printf("symsync_%s [rate: %f]\n", EXTENSION_FULL, _q->rate); + printf("\n", + EXTENSION_FULL, _q->rate, _q->k, _q->k_out); return FIRPFB(_print)(_q->mf); } From d35019f8c191b220705ec580d71818fbcc198f8f Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 24 Apr 2024 08:14:56 -0400 Subject: [PATCH 327/334] bpacket{gen,sync}: fixing print statements to be consistent --- examples/bpacketsync_example.c | 1 + src/framing/src/bpacketgen.c | 21 +++++++++++---------- src/framing/src/bpacketsync.c | 21 +++++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/examples/bpacketsync_example.c b/examples/bpacketsync_example.c index cd7850757..4a2a07c23 100644 --- a/examples/bpacketsync_example.c +++ b/examples/bpacketsync_example.c @@ -118,6 +118,7 @@ int main(int argc, char*argv[]) { // create packet synchronizer bpacketsync ps = bpacketsync_create(0, callback, (void*)msg_dec); + bpacketsync_print(ps); // initialize original data message for (i=0; ig); - printf(" p/n len : %u bytes\n", _q->pnsequence_len); - printf(" header len : %u bytes\n", _q->header_len); - printf(" payload len : %u bytes\n", _q->dec_msg_len); - printf(" crc : %s\n", crc_scheme_str[_q->crc][1]); - printf(" fec (inner) : %s\n", fec_scheme_str[_q->fec0][1]); - printf(" fec (outer) : %s\n", fec_scheme_str[_q->fec1][1]); - printf(" packet len : %u bytes\n", _q->packet_len); - printf(" efficiency : %8.2f %%\n", 100.0f*(float)_q->dec_msg_len/(float)_q->packet_len); + printf("g); + printf(", pn_len%u", _q->pnsequence_len); + printf(", header=%u", _q->header_len); + printf(", payload=%u", _q->dec_msg_len); + printf(", crc=\"%s\"", crc_scheme_str[_q->crc][0]); + printf(", fec_0=\"%s\"", fec_scheme_str[_q->fec0][0]); + printf(", fec_1=\"%s\"", fec_scheme_str[_q->fec1][0]); + printf(", packet=%u", _q->packet_len); + printf(", efficiency=%g", (float)_q->dec_msg_len/(float)_q->packet_len); + printf(">\n"); } // return length of full packet diff --git a/src/framing/src/bpacketsync.c b/src/framing/src/bpacketsync.c index df403b7d0..e22e3330c 100644 --- a/src/framing/src/bpacketsync.c +++ b/src/framing/src/bpacketsync.c @@ -179,16 +179,17 @@ int bpacketsync_destroy(bpacketsync _q) int bpacketsync_print(bpacketsync _q) { - printf("bpacketsync:\n"); - printf(" p/n poly : 0x%.4x\n", _q->g); - printf(" p/n len : %u bytes\n", _q->pnsequence_len); - printf(" header len : %u bytes\n", _q->header_len); - printf(" payload len : %u bytes\n", _q->dec_msg_len); - printf(" crc : %s\n", crc_scheme_str[_q->crc][1]); - printf(" fec (inner) : %s\n", fec_scheme_str[_q->fec0][1]); - printf(" fec (outer) : %s\n", fec_scheme_str[_q->fec1][1]); - printf(" packet len : %u bytes\n", _q->packet_len); - printf(" efficiency : %8.2f %%\n", 100.0f*(float)_q->dec_msg_len/(float)_q->packet_len); + printf("g); + printf(", pn_len%u", _q->pnsequence_len); + printf(", header=%u", _q->header_len); + printf(", payload=%u", _q->dec_msg_len); + printf(", crc=\"%s\"", crc_scheme_str[_q->crc][0]); + printf(", fec_0=\"%s\"", fec_scheme_str[_q->fec0][0]); + printf(", fec_1=\"%s\"", fec_scheme_str[_q->fec1][0]); + printf(", packet=%u", _q->packet_len); + printf(", efficiency=%g", (float)_q->dec_msg_len/(float)_q->packet_len); + printf(">\n"); return LIQUID_OK; } From b999c4703d169751ac17cfbd0b2c1904ce1f574c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Wed, 24 Apr 2024 18:58:03 -0400 Subject: [PATCH 328/334] framing: cleaning print() methods for consistency --- examples/symstreamcf_example.c | 1 + src/framing/src/bpresync.proto.c | 2 +- src/framing/src/bsync.proto.c | 2 +- src/framing/src/detector_cccf.c | 11 ++++++----- src/framing/src/dsssframegen.c | 2 +- src/framing/src/dsssframesync.c | 4 ++-- src/framing/src/flexframegen.c | 9 ++++----- src/framing/src/flexframesync.c | 6 +++--- src/framing/src/framegen64.c | 4 ++++ src/framing/src/framesync64.c | 4 ++-- src/framing/src/fskframegen.c | 4 ++++ src/framing/src/fskframesync.c | 4 ++++ src/framing/src/gmskframegen.c | 5 ++++- src/framing/src/gmskframesync.c | 4 ++-- src/framing/src/msource.proto.c | 4 +++- src/framing/src/presync.proto.c | 2 +- src/framing/src/qdetector.proto.c | 13 +++++++------ src/framing/src/qpacketmodem.proto.c | 19 ++++++++++--------- src/framing/src/qsource.proto.c | 20 ++++++++++---------- src/framing/src/symstream.proto.c | 12 ++++++++---- src/framing/src/symstreamr.proto.c | 16 ++++++++-------- src/framing/src/symtrack.proto.c | 6 ++++++ 22 files changed, 92 insertions(+), 62 deletions(-) diff --git a/examples/symstreamcf_example.c b/examples/symstreamcf_example.c index c3a4b743f..6bbf60ac7 100644 --- a/examples/symstreamcf_example.c +++ b/examples/symstreamcf_example.c @@ -33,6 +33,7 @@ int main() // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); + symstreamcf_print(gen); unsigned int total_samples = 0; while (total_samples < num_samples) { diff --git a/src/framing/src/bpresync.proto.c b/src/framing/src/bpresync.proto.c index 5bbb6f2fd..c182ffd4a 100644 --- a/src/framing/src/bpresync.proto.c +++ b/src/framing/src/bpresync.proto.c @@ -146,7 +146,7 @@ int BPRESYNC(_destroy)(BPRESYNC() _q) int BPRESYNC(_print)(BPRESYNC() _q) { - printf("bpresync_%s: %u samples\n", EXTENSION_FULL, _q->n); + printf("\n", EXTENSION_FULL, _q->n); return LIQUID_OK; } diff --git a/src/framing/src/bsync.proto.c b/src/framing/src/bsync.proto.c index ad271d163..f007befbb 100644 --- a/src/framing/src/bsync.proto.c +++ b/src/framing/src/bsync.proto.c @@ -145,7 +145,7 @@ int BSYNC(_destroy)(BSYNC() _fs) int BSYNC(_print)(BSYNC() _fs) { - printf("\n", EXTENSION_FULL, _fs->n); + printf("\n", EXTENSION_FULL, _fs->n); return LIQUID_OK; } diff --git a/src/framing/src/detector_cccf.c b/src/framing/src/detector_cccf.c index 9465821cb..39e890341 100644 --- a/src/framing/src/detector_cccf.c +++ b/src/framing/src/detector_cccf.c @@ -209,11 +209,12 @@ void detector_cccf_destroy(detector_cccf _q) void detector_cccf_print(detector_cccf _q) { - printf("detector_cccf:\n"); - printf(" sequence length : %-u\n", _q->n); - printf(" threshold : %8.4f\n", _q->threshold); - printf(" maximum carrier : %8.4f rad/sample\n", _q->dphi_max); - printf(" num. correlators : %u\n", _q->m); + printf("n); + printf(", thresh=%g", _q->threshold); + printf(", dphi_max=%8.4f", _q->dphi_max); + printf(", ncorrs=%u", _q->m); + printf(">\n"); } void detector_cccf_reset(detector_cccf _q) diff --git a/src/framing/src/dsssframegen.c b/src/framing/src/dsssframegen.c index fa4ba37b3..f7f8da18c 100644 --- a/src/framing/src/dsssframegen.c +++ b/src/framing/src/dsssframegen.c @@ -21,7 +21,7 @@ */ // -// dsssdsssframegen.c +// dsssframegen.c // // dsss flexible frame generator // diff --git a/src/framing/src/dsssframesync.c b/src/framing/src/dsssframesync.c index 62a0ee079..71fe5eff7 100644 --- a/src/framing/src/dsssframesync.c +++ b/src/framing/src/dsssframesync.c @@ -190,8 +190,8 @@ int dsssframesync_destroy(dsssframesync _q) int dsssframesync_print(dsssframesync _q) { - printf("dsssframesync:\n"); - return framedatastats_print(&_q->framedatastats); + printf("\n"); + return LIQUID_OK; } int dsssframesync_reset(dsssframesync _q) diff --git a/src/framing/src/flexframegen.c b/src/framing/src/flexframegen.c index 045b84ccc..4b91e17da 100644 --- a/src/framing/src/flexframegen.c +++ b/src/framing/src/flexframegen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,7 @@ * THE SOFTWARE. */ -// -// flexframegen.c -// // flexible frame generator -// #include #include @@ -178,6 +174,8 @@ int flexframegen_destroy(flexframegen _q) // print flexframegen object internals int flexframegen_print(flexframegen _q) { + printf("\n"); +#if 0 unsigned int num_frame_symbols = 64 + // preamble p/n sequence length _q->header_sym_len + // header symbols @@ -198,6 +196,7 @@ int flexframegen_print(flexframegen _q) printf(" tail : %u symbols\n", _q->m); printf(" total : %u symbols\n", num_frame_symbols); printf(" efficiency : %.2f bits/second/Hz\n", eta); +#endif return LIQUID_OK; } diff --git a/src/framing/src/flexframesync.c b/src/framing/src/flexframesync.c index 4b0e513a1..8d3ffed5a 100644 --- a/src/framing/src/flexframesync.c +++ b/src/framing/src/flexframesync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2023 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -281,8 +281,8 @@ int flexframesync_destroy(flexframesync _q) // print frame synchronizer object internals int flexframesync_print(flexframesync _q) { - printf("flexframesync:\n"); - return framedatastats_print(&_q->framedatastats); + printf("\n"); + return LIQUID_OK; } // reset frame synchronizer object diff --git a/src/framing/src/framegen64.c b/src/framing/src/framegen64.c index d3ce6c93e..3bba4921c 100644 --- a/src/framing/src/framegen64.c +++ b/src/framing/src/framegen64.c @@ -112,6 +112,7 @@ int framegen64_destroy(framegen64 _q) // print framegen64 object internals int framegen64_print(framegen64 _q) { +#if 0 float eta = (float) (8*(64 + 8)) / (float) (LIQUID_FRAME64_LEN/2); printf("framegen64 [m=%u, beta=%4.2f]:\n", _q->m, _q->beta); printf(" preamble/etc.\n"); @@ -133,6 +134,9 @@ int framegen64_print(framegen64 _q) printf(" summary\n"); printf(" * total symbols : %3u\n", LIQUID_FRAME64_LEN/2); printf(" * spectral efficiency : %6.4f b/s/Hz\n", eta); +#else + printf("\n", _q->m, _q->beta); +#endif return LIQUID_OK; } diff --git a/src/framing/src/framesync64.c b/src/framing/src/framesync64.c index 6eca7a759..4c002433a 100644 --- a/src/framing/src/framesync64.c +++ b/src/framing/src/framesync64.c @@ -181,8 +181,8 @@ int framesync64_destroy(framesync64 _q) // print frame synchronizer object internals int framesync64_print(framesync64 _q) { - printf("framesync64:\n"); - return framedatastats_print(&_q->framedatastats); + printf("\n"); + return LIQUID_OK; } // reset frame synchronizer object diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c index 1c5df8e52..32306e25f 100644 --- a/src/framing/src/fskframegen.c +++ b/src/framing/src/fskframegen.c @@ -253,6 +253,7 @@ int fskframegen_reset(fskframegen _q) // print fskframegen object internals int fskframegen_print(fskframegen _q) { +#if 0 printf("fskframegen:\n"); printf(" physical properties\n"); printf(" bits/symbol : %u\n", _q->m); @@ -267,6 +268,9 @@ int fskframegen_print(fskframegen _q) printf(" fec (inner) : %s\n", fec_scheme_str[_q->payload_fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->payload_fec1][1]); printf(" total samples : %-4u samples\n", fskframegen_getframelen(_q)); +#else + printf("\n"); +#endif return LIQUID_OK; } diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c index 8d30274e6..7113f1c94 100644 --- a/src/framing/src/fskframesync.c +++ b/src/framing/src/fskframesync.c @@ -309,6 +309,7 @@ int fskframesync_destroy(fskframesync _q) // print frame synchronizer object internals int fskframesync_print(fskframesync _q) { +#if 0 printf("fskframesync:\n"); printf(" physical properties\n"); printf(" bits/symbol : %u\n", _q->m); @@ -323,6 +324,9 @@ int fskframesync_print(fskframesync _q) printf(" fec (inner) : %s\n", fec_scheme_str[_q->payload_fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->payload_fec1][1]); printf(" total samples : %-4u samples\n", 0); +#else + printf("\n"); +#endif return LIQUID_OK; } diff --git a/src/framing/src/gmskframegen.c b/src/framing/src/gmskframegen.c index aee09a8a9..ce33baafc 100644 --- a/src/framing/src/gmskframegen.c +++ b/src/framing/src/gmskframegen.c @@ -205,7 +205,7 @@ int gmskframegen_is_assembled(gmskframegen _q) // print gmskframegen object internals int gmskframegen_print(gmskframegen _q) { - // plot +#if 0 printf("gmskframegen:\n"); printf(" physical properties\n"); printf(" samples/symbol : %u\n", _q->k); @@ -221,6 +221,9 @@ int gmskframegen_print(gmskframegen _q) printf(" fec (inner) : %s\n", fec_scheme_str[_q->fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->fec1][1]); printf(" total samples : %-4u samples\n", gmskframegen_getframelen(_q)); +#else + printf("\n"); +#endif return LIQUID_OK; } diff --git a/src/framing/src/gmskframesync.c b/src/framing/src/gmskframesync.c index 34c521f9d..23d12d4e6 100644 --- a/src/framing/src/gmskframesync.c +++ b/src/framing/src/gmskframesync.c @@ -282,8 +282,8 @@ int gmskframesync_destroy(gmskframesync _q) // print frame synchronizer object internals int gmskframesync_print(gmskframesync _q) { - printf("gmskframesync:\n"); - return framedatastats_print(&_q->framedatastats); + printf("\n"); + return LIQUID_OK; } int gmskframesync_set_header_len(gmskframesync _q, diff --git a/src/framing/src/msource.proto.c b/src/framing/src/msource.proto.c index 7697b25b7..9d5d44eff 100644 --- a/src/framing/src/msource.proto.c +++ b/src/framing/src/msource.proto.c @@ -175,11 +175,13 @@ int MSOURCE(_reset)(MSOURCE() _q) // print int MSOURCE(_print)(MSOURCE() _q) { - printf("msource%s, M=%u, m=%u, as=%.1f dB, %llu samples:\n", + printf("\n", EXTENSION, _q->M, _q->m, _q->as, _q->num_samples); +#if 0 unsigned int i; for (i=0; i<_q->num_sources; i++) QSOURCE(_print)(_q->sources[i]); +#endif return LIQUID_OK; } diff --git a/src/framing/src/presync.proto.c b/src/framing/src/presync.proto.c index facc0ec6a..ada1e0e16 100644 --- a/src/framing/src/presync.proto.c +++ b/src/framing/src/presync.proto.c @@ -148,7 +148,7 @@ int PRESYNC(_destroy)(PRESYNC() _q) int PRESYNC(_print)(PRESYNC() _q) { - printf("bpresync_%s: %u samples\n", EXTENSION_FULL, _q->n); + printf("\n", EXTENSION_FULL, _q->n); return LIQUID_OK; } diff --git a/src/framing/src/qdetector.proto.c b/src/framing/src/qdetector.proto.c index 5128adb0e..b42f1b20b 100644 --- a/src/framing/src/qdetector.proto.c +++ b/src/framing/src/qdetector.proto.c @@ -323,12 +323,13 @@ int QDETECTOR(_destroy)(QDETECTOR() _q) int QDETECTOR(_print)(QDETECTOR() _q) { - printf("qdetector_%s:\n", EXTENSION_FULL); - printf(" template length (time): %-u\n", _q->s_len); - printf(" FFT size : %-u\n", _q->nfft); - printf(" search range : %g [radians/sample], %-d [bins]\n",_q->dphi_max, _q->range); - printf(" detection threshold : %6.4f\n", _q->threshold); - printf(" sum{ s^2 } : %.2f\n", _q->s2_sum); + printf("s_len); + printf(", nfft=%u", _q->nfft); + printf(", dphi_max=%g",_q->dphi_max); + printf(", thresh=%g", _q->threshold); + printf(", energy=%g\n", _q->s2_sum); + printf(">\n"); return LIQUID_OK; } diff --git a/src/framing/src/qpacketmodem.proto.c b/src/framing/src/qpacketmodem.proto.c index 6f4a1ef9e..6e3ec3d4f 100644 --- a/src/framing/src/qpacketmodem.proto.c +++ b/src/framing/src/qpacketmodem.proto.c @@ -133,15 +133,16 @@ int QPACKETMODEM(_reset)(QPACKETMODEM() _q) // print object internals int QPACKETMODEM(_print)(QPACKETMODEM() _q) { - printf("qpacketmodem:\n"); - printf(" check : %s\n", crc_scheme_str[packetizer_get_crc(_q->p)][1]); - printf(" fec (inner) : %s\n", fec_scheme_str[packetizer_get_fec0(_q->p)][1]); - printf(" fec (outer) : %s\n", fec_scheme_str[packetizer_get_fec1(_q->p)][1]); - printf(" modulation scheme : %s\n", modulation_types[MODEM(_get_scheme)(_q->mod_payload)].name); - printf(" payload dec len : %u\n", _q->payload_dec_len); - printf(" payload enc len : %u\n", _q->payload_enc_len); - printf(" payload bit len : %u\n", _q->payload_bit_len); - printf(" payload mod len : %u\n", _q->payload_mod_len); + printf("p)][0]); + printf(", fec_0=\"%s\"", fec_scheme_str[packetizer_get_fec0(_q->p)][0]); + printf(", fec_1=\"%s\"", fec_scheme_str[packetizer_get_fec1(_q->p)][0]); + printf(", ms=\"%s\"", modulation_types[MODEM(_get_scheme)(_q->mod_payload)].name); + printf(", dec=%u", _q->payload_dec_len); + printf(", enc=%u", _q->payload_enc_len); + printf(", bit=%u", _q->payload_bit_len); + printf(", mod=%u", _q->payload_mod_len); + printf(">\n"); return LIQUID_OK; } diff --git a/src/framing/src/qsource.proto.c b/src/framing/src/qsource.proto.c index ca72fb8fc..26000fe61 100644 --- a/src/framing/src/qsource.proto.c +++ b/src/framing/src/qsource.proto.c @@ -317,22 +317,22 @@ int QSOURCE(_init_gmsk)(QSOURCE() _q, int QSOURCE(_print)(QSOURCE() _q) { // TODO: print generic parameters - printf(" qsource%s[%3d] : ", EXTENSION, _q->id); + printf("id); // print type-specific parameters float bw = _q->bw; switch (_q->type) { - case QSOURCE_USER: printf("user "); break; - case QSOURCE_TONE: printf("tone "); break; - case QSOURCE_CHIRP: printf("chirp"); break; - case QSOURCE_NOISE: printf("noise"); break; - case QSOURCE_MODEM: printf("modem"); bw *= 0.5f; break; - case QSOURCE_FSK: printf("fsk "); bw *= 0.5f; break; - case QSOURCE_GMSK: printf("gmsk "); bw *= 0.5f; break; + case QSOURCE_USER: printf(", type=\"user\""); break; + case QSOURCE_TONE: printf(", type=\"tone\""); break; + case QSOURCE_CHIRP: printf(", type=\"chirp\""); break; + case QSOURCE_NOISE: printf(", type=\"noise\""); break; + case QSOURCE_MODEM: printf(", type=\"modem\""); bw *= 0.5f; break; + case QSOURCE_FSK: printf(", type=\"fsk\""); bw *= 0.5f; break; + case QSOURCE_GMSK: printf(", type=\"gmsk\""); bw *= 0.5f; break; default: return liquid_error(LIQUID_EINT,"qsource%s_print(), invalid internal state",EXTENSION); } - printf(" : fc=%6.3f, bw=%5.3f, P=%4u, m=%2u, as=%5.1f dB, gain=%5.1f dB %c\n", - _q->fc, bw, _q->P, _q->m, _q->as, QSOURCE(_get_gain)(_q), _q->enabled ? '*' : ' '); + printf(", fc=%g, bw=%g, P=%u, m=%u, as=%g, gain=%g, enabled=%u>\n", + _q->fc, bw, _q->P, _q->m, _q->as, QSOURCE(_get_gain)(_q), _q->enabled); return LIQUID_OK; } diff --git a/src/framing/src/symstream.proto.c b/src/framing/src/symstream.proto.c index 08c06db6d..317d34eeb 100644 --- a/src/framing/src/symstream.proto.c +++ b/src/framing/src/symstream.proto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2022 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// // Symbol streaming generator -// #include #include @@ -138,7 +136,13 @@ int SYMSTREAM(_destroy)(SYMSTREAM() _q) // print symstream object's parameters int SYMSTREAM(_print)(SYMSTREAM() _q) { - printf("symstream_%s:\n", EXTENSION); + printf("k); + printf(", m=%u", _q->m); + printf(", beta=%.3f", _q->beta); + printf(", ms=\"%s\"", modulation_types[_q->mod_scheme].name); + printf(", gain=%g", _q->gain); + printf(">\n"); return LIQUID_OK; } diff --git a/src/framing/src/symstreamr.proto.c b/src/framing/src/symstreamr.proto.c index c9046d10c..cbf7e2b27 100644 --- a/src/framing/src/symstreamr.proto.c +++ b/src/framing/src/symstreamr.proto.c @@ -126,14 +126,14 @@ int SYMSTREAMR(_destroy)(SYMSTREAMR() _q) // print symstream object's parameters int SYMSTREAMR(_print)(SYMSTREAMR() _q) { - printf("\n", - EXTENSION, - liquid_firfilt_type_str[SYMSTREAMR(_get_ftype)(_q)][0], - SYMSTREAMR(_get_bw) (_q), - SYMSTREAMR(_get_m) (_q), - SYMSTREAMR(_get_beta)(_q), - modulation_types[SYMSTREAMR(_get_scheme)(_q)].name, - SYMSTREAMR(_get_gain)(_q)); + printf("\n", + EXTENSION, + liquid_firfilt_type_str[SYMSTREAMR(_get_ftype)(_q)][0], + SYMSTREAMR(_get_bw) (_q), + SYMSTREAMR(_get_m) (_q), + SYMSTREAMR(_get_beta)(_q), + modulation_types[SYMSTREAMR(_get_scheme)(_q)].name, + SYMSTREAMR(_get_gain)(_q)); return LIQUID_OK; } diff --git a/src/framing/src/symtrack.proto.c b/src/framing/src/symtrack.proto.c index d8154383a..872d930a9 100644 --- a/src/framing/src/symtrack.proto.c +++ b/src/framing/src/symtrack.proto.c @@ -169,6 +169,7 @@ int SYMTRACK(_destroy)(SYMTRACK() _q) // print symtrack object's parameters int SYMTRACK(_print)(SYMTRACK() _q) { +#if 0 printf("symtrack_%s:\n", EXTENSION_FULL); printf(" k:%u, m:%u, beta:%.3f, ms:%s\n", _q->k, _q->m, _q->beta, modulation_types[_q->mod_scheme].name); @@ -181,6 +182,11 @@ int SYMTRACK(_print)(SYMTRACK() _q) printf("?\n"); return liquid_error(LIQUID_EINT,"symtrack_%s_print(), invalid equalization strategy"); } +#else + printf("\n", + _q->k, _q->m, _q->beta, modulation_types[_q->mod_scheme].name); +#endif return LIQUID_OK; } From 965216f5954147116e121b56b03b1651a5bbb02c Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 26 Apr 2024 08:32:34 -0400 Subject: [PATCH 329/334] modem: cleaning print() methods for consistency --- src/modem/src/ampmodem.c | 16 ++++++++-------- src/modem/src/cpfskdem.proto.c | 2 +- src/modem/src/cpfskmod.proto.c | 2 +- src/modem/src/freqdem.proto.c | 3 +-- src/modem/src/freqmod.proto.c | 7 ++++--- src/modem/src/fskdem.c | 9 +++++---- src/modem/src/fskmod.c | 9 +++++---- src/modem/src/gmskdem.c | 11 ++++++----- src/modem/src/gmskmod.c | 4 +++- 9 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/modem/src/ampmodem.c b/src/modem/src/ampmodem.c index 43683691d..2828f272d 100644 --- a/src/modem/src/ampmodem.c +++ b/src/modem/src/ampmodem.c @@ -136,16 +136,16 @@ int ampmodem_destroy(ampmodem _q) int ampmodem_print(ampmodem _q) { - printf("ampmodem:\n"); - printf(" type : "); + printf("type) { - case LIQUID_AMPMODEM_DSB: printf("double side-band\n"); break; - case LIQUID_AMPMODEM_USB: printf("single side-band (upper)\n"); break; - case LIQUID_AMPMODEM_LSB: printf("single side-band (lower)\n"); break; - default: printf("unknown\n"); + case LIQUID_AMPMODEM_DSB: printf(", type=\"DSB\""); break; + case LIQUID_AMPMODEM_USB: printf(", type=\"USB\""); break; + case LIQUID_AMPMODEM_LSB: printf(", type=\"LSB\""); break; + default: printf(", type=\"?\""); } - printf(" supp. carrier : %s\n", _q->suppressed_carrier ? "yes" : "no"); - printf(" mod. index : %-8.4f\n", _q->mod_index); + printf(", carrier_suppressed=%s", _q->suppressed_carrier ? "true" : "false"); + printf(", mod_index=%g", _q->mod_index); + printf(">\n"); return LIQUID_OK; } diff --git a/src/modem/src/cpfskdem.proto.c b/src/modem/src/cpfskdem.proto.c index a4f781335..daa97067d 100644 --- a/src/modem/src/cpfskdem.proto.c +++ b/src/modem/src/cpfskdem.proto.c @@ -290,7 +290,7 @@ int CPFSKDEM(_destroy)(CPFSKDEM() _q) // print modulation internals int CPFSKDEM(_print)(CPFSKDEM() _q) { - printf("bps, _q->h, _q->k, _q->m, _q->beta); switch(_q->type) { case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; diff --git a/src/modem/src/cpfskmod.proto.c b/src/modem/src/cpfskmod.proto.c index dd3343316..676026244 100644 --- a/src/modem/src/cpfskmod.proto.c +++ b/src/modem/src/cpfskmod.proto.c @@ -200,7 +200,7 @@ int CPFSKMOD(_destroy)(CPFSKMOD() _q) // print modulator object internals int CPFSKMOD(_print)(CPFSKMOD() _q) { - printf("bps, _q->h, _q->k, _q->m, _q->beta); switch(_q->type) { case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; diff --git a/src/modem/src/freqdem.proto.c b/src/modem/src/freqdem.proto.c index a5b3b8e9c..8c8c8685d 100644 --- a/src/modem/src/freqdem.proto.c +++ b/src/modem/src/freqdem.proto.c @@ -74,8 +74,7 @@ int FREQDEM(_destroy)(FREQDEM() _q) // print modulation internals int FREQDEM(_print)(FREQDEM() _q) { - printf("freqdem:\n"); - printf(" mod. factor : %8.4f\n", _q->kf); + printf("\n", _q->kf); return LIQUID_OK; } diff --git a/src/modem/src/freqmod.proto.c b/src/modem/src/freqmod.proto.c index 66de42a39..2bcdd3d77 100644 --- a/src/modem/src/freqmod.proto.c +++ b/src/modem/src/freqmod.proto.c @@ -86,9 +86,10 @@ int FREQMOD(_destroy)(FREQMOD() _q) // print modulation internals int FREQMOD(_print)(FREQMOD() _q) { - printf("freqmod:\n"); - printf(" mod. factor : %8.4f\n", _q->kf); - printf(" sincos table len : %u\n", _q->sincos_table_len); + printf("kf); + printf(", tablen=%u", _q->sincos_table_len); + printf(">\n"); return LIQUID_OK; } diff --git a/src/modem/src/fskdem.c b/src/modem/src/fskdem.c index eb95aea0a..5d5129f6a 100644 --- a/src/modem/src/fskdem.c +++ b/src/modem/src/fskdem.c @@ -186,10 +186,11 @@ int fskdem_destroy(fskdem _q) // print fskdem object internals int fskdem_print(fskdem _q) { - printf("fskdem : frequency-shift keying demodulator\n"); - printf(" bits/symbol : %u\n", _q->m); - printf(" samples/symbol : %u\n", _q->k); - printf(" bandwidth : %8.5f\n", _q->bandwidth); + printf("m); + printf(", samples/symbol=%u", _q->k); + printf(", bandwidth=%g", _q->bandwidth); + printf(">\n"); return LIQUID_OK; } diff --git a/src/modem/src/fskmod.c b/src/modem/src/fskmod.c index fae96bd6a..35d306fa6 100644 --- a/src/modem/src/fskmod.c +++ b/src/modem/src/fskmod.c @@ -110,10 +110,11 @@ int fskmod_destroy(fskmod _q) // print fskmod object internals int fskmod_print(fskmod _q) { - printf("fskmod : frequency-shift keying modulator\n"); - printf(" bits/symbol : %u\n", _q->m); - printf(" samples/symbol : %u\n", _q->k); - printf(" bandwidth : %8.5f\n", _q->bandwidth); + printf("m); + printf(", samples/symbol=%u", _q->k); + printf(", bandwidth=%g", _q->bandwidth); + printf(">\n"); return LIQUID_OK; } diff --git a/src/modem/src/gmskdem.c b/src/modem/src/gmskdem.c index f837d29be..6dd07790a 100644 --- a/src/modem/src/gmskdem.c +++ b/src/modem/src/gmskdem.c @@ -173,13 +173,14 @@ int gmskdem_destroy(gmskdem _q) int gmskdem_print(gmskdem _q) { - printf("gmskdem [k=%u, m=%u, BT=%8.3f]\n", _q->k, _q->m, _q->BT); + printf("k, _q->m, _q->BT); #if GMSKDEM_USE_EQUALIZER - printf(" equalizer bandwidth : %12.8f\n", eqlms_rrrf_get_bw(_q->eq)); + printf(", eq_bw=%g", eqlms_rrrf_get_bw(_q->eq)); #endif - unsigned int i; - for (i=0; i<_q->h_len; i++) - printf(" hr(%4u) = %12.8f;\n", i+1, _q->h[i]); + //unsigned int i; + //for (i=0; i<_q->h_len; i++) + // printf(" hr(%4u) = %12.8f;\n", i+1, _q->h[i]); + printf(">\n"); return LIQUID_OK; } diff --git a/src/modem/src/gmskmod.c b/src/modem/src/gmskmod.c index 2602812d4..b85e57c11 100644 --- a/src/modem/src/gmskmod.c +++ b/src/modem/src/gmskmod.c @@ -122,10 +122,12 @@ int gmskmod_destroy(gmskmod _q) int gmskmod_print(gmskmod _q) { - printf("gmskmod [k=%u, m=%u, BT=%8.3f]\n", _q->k, _q->m, _q->BT); + printf("\n", _q->k, _q->m, _q->BT); +#if 0 unsigned int i; for (i=0; i<_q->h_len; i++) printf(" ht(%4u) = %12.8f;\n", i+1, _q->h[i]); +#endif return LIQUID_OK; } From d7152173ae6744e618e32c7307df4964ff3754d8 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 27 Apr 2024 11:29:14 -0400 Subject: [PATCH 330/334] bsequence: cleaning print() methods for consistency --- src/sequence/src/bsequence.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sequence/src/bsequence.c b/src/sequence/src/bsequence.c index 41014b6e9..065c41622 100644 --- a/src/sequence/src/bsequence.c +++ b/src/sequence/src/bsequence.c @@ -116,6 +116,7 @@ int bsequence_init(bsequence _bs, // Print sequence to the screen int bsequence_print(bsequence _bs) { +#if 0 unsigned int i, j; unsigned int chunk; unsigned int p = 8*sizeof(unsigned int); @@ -136,6 +137,9 @@ int bsequence_print(bsequence _bs) } } printf("\n"); +#else + printf("", _bs->num_bits); +#endif return LIQUID_OK; } From b4460c42ffdafad92e586e8e745cca0b44a24542 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Fri, 26 Apr 2024 16:56:14 -0400 Subject: [PATCH 331/334] nco: cleaning print() methods for consistency --- src/nco/src/nco.proto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nco/src/nco.proto.c b/src/nco/src/nco.proto.c index c85bbf3da..036b71860 100644 --- a/src/nco/src/nco.proto.c +++ b/src/nco/src/nco.proto.c @@ -111,8 +111,8 @@ int NCO(_destroy)(NCO() _q) // Print nco object internals to stdout int NCO(_print)(NCO() _q) { - printf("nco [phase: 0x%.8x rad, freq: 0x%.8x rad/sample]\n", - _q->theta, _q->d_theta); + printf("\n", + EXTENSION, _q->theta, _q->d_theta); #if LIQUID_DEBUG_NCO // print entire table unsigned int i; From 96317f58e836eed63e7aeb9507e9032ded074db5 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 27 Apr 2024 13:36:08 -0400 Subject: [PATCH 332/334] optim: cleaning print() methods for consistency --- src/optim/src/gradsearch.c | 13 +++++++++++-- src/optim/src/qnsearch.c | 10 ++++++++++ src/optim/src/qs1dsearch.c | 2 +- src/optim/src/utilities.c | 6 ++---- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/optim/src/gradsearch.c b/src/optim/src/gradsearch.c index d079f4b9c..269d7f775 100644 --- a/src/optim/src/gradsearch.c +++ b/src/optim/src/gradsearch.c @@ -92,13 +92,12 @@ void gradsearch_destroy(gradsearch _q) // print status void gradsearch_print(gradsearch _q) { +#if 0 //printf("gradient search:\n"); printf("u=%12.4e ", _q->u); // utility -#if 0 // enable more verbose output printf("|p|=%7.1e ", _q->pnorm); // norm(p) printf("del=%7.1e ", _q->delta); // delta -#endif printf("step=%7.1e ", _q->alpha); // alpha (step size) unsigned int i; @@ -106,6 +105,16 @@ void gradsearch_print(gradsearch _q) for (i=0; i<_q->num_parameters; i++) printf("%8.4f", _q->v[i]); printf("}\n"); +#else + printf("num_parameters); + printf(", dir=\"%s\"", _q->direction == LIQUID_OPTIM_MAXIMIZE ? "max" : "min"); + printf(", pnorm=%g", _q->pnorm); // norm(p) + printf(", delta=%g", _q->delta); // delta + printf(", u=%g", _q->u); + printf(">\n"); +#endif + // return LIQUID_OK; } float gradsearch_step(gradsearch _q) diff --git a/src/optim/src/qnsearch.c b/src/optim/src/qnsearch.c index 61bef0556..9786f6467 100644 --- a/src/optim/src/qnsearch.c +++ b/src/optim/src/qnsearch.c @@ -120,11 +120,21 @@ int qnsearch_destroy(qnsearch _q) int qnsearch_print(qnsearch _q) { +#if 0 printf("[%.3f] ", _q->utility); unsigned int i; for (i=0; i<_q->num_parameters; i++) printf("%.3f ", _q->v[i]); printf("\n"); +#else + printf("num_parameters); + printf(", dir=\"%s\"", _q->minimize ? "min" : "max"); + printf(", gamma=%g", _q->gamma); + printf(", delta=%g", _q->delta); // delta + printf(", u=%g", _q->utility); + printf(">\n"); +#endif return LIQUID_OK; } diff --git a/src/optim/src/qs1dsearch.c b/src/optim/src/qs1dsearch.c index 16600b829..abf8a1f71 100644 --- a/src/optim/src/qs1dsearch.c +++ b/src/optim/src/qs1dsearch.c @@ -71,7 +71,7 @@ int qs1dsearch_destroy(qs1dsearch _q) int qs1dsearch_print(qs1dsearch _q) { - printf("\n", + printf("\n", _q->vn, _q->v0, _q->vp, _q->un, _q->u0, _q->up); return LIQUID_OK; } diff --git a/src/optim/src/utilities.c b/src/optim/src/utilities.c index a8d1be351..61c5d835d 100644 --- a/src/optim/src/utilities.c +++ b/src/optim/src/utilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2020 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// utilities.c : n-dimensional utility functions -// +// n-dimensional utility functions #include #include From 8b31f3e2805f57623017d196279f9a0379bc957b Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 27 Apr 2024 13:39:37 -0400 Subject: [PATCH 333/334] random/scramble: fixing incorrect description in comment --- src/random/src/scramble.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/random/src/scramble.c b/src/random/src/scramble.c index a675dcb7b..1483f3748 100644 --- a/src/random/src/scramble.c +++ b/src/random/src/scramble.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 - 2015 Joseph Gaeddert + * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,9 +20,7 @@ * THE SOFTWARE. */ -// -// Finite impulse response filter design -// +// data scrambler #include #include From 231df906ea87a26c2c78740a4a73fc7ad0248df0 Mon Sep 17 00:00:00 2001 From: "Joseph D. Gaeddert" Date: Sat, 27 Apr 2024 13:45:46 -0400 Subject: [PATCH 334/334] rresamp/autotest: reducing verbosity --- src/filter/tests/rresamp_crcf_autotest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filter/tests/rresamp_crcf_autotest.c b/src/filter/tests/rresamp_crcf_autotest.c index 9e7299060..2c376bc35 100644 --- a/src/filter/tests/rresamp_crcf_autotest.c +++ b/src/filter/tests/rresamp_crcf_autotest.c @@ -45,7 +45,7 @@ void test_rresamp_crcf(const char * _method, } else if (strcmp(_method,"default")==0) { resamp = rresamp_crcf_create_default(_interp, _decim); } else { - printf("creating resampler using %s\n", _method); + //printf("creating resampler using %s\n", _method); int ftype = liquid_getopt_str2firfilt(_method); float beta = _bw; // rename to avoid confusion resamp = rresamp_crcf_create_prototype(ftype, _interp, _decim, _m, beta);