diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index ccbbddebb..6eade040d 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -16,7 +16,13 @@ jobs: runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + + - name: setup + if: runner.os == 'macos' + run: | + brew update + brew install autoconf automake #- name: Setup libfec # run: git clone https://github.com/jgaeddert/libfec.git && cd libfec && ./configure && make && sudo make install diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 14258ec71..a5ea16160 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,6 +6,7 @@ on: push: branches: - master + - coverage-dev jobs: standard: @@ -45,5 +46,9 @@ 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 + with: + fail_ci_if_error: true + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 03b6d590a..96b30b061 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,7 +83,11 @@ coverage: - ./bootstrap.sh - ./configure --enable-coverage - make -j4 coverage - - bash <(curl -s https://codecov.io/bash) + - curl -Os http://cli.codecov.io/latest/linux/codecov + - chmod +x codecov + - ./codecov --version + - ./codecov upload-process -t $CODECOV_TOKEN --git-service gitlab --slug jgaeddert/liquid-dsp + coverage: '/lines: \d+\.\d+%/' artifacts: paths: [coverage.out] diff --git a/autotest/autotest.c b/autotest/autotest.c index 78a62a529..811ea550d 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,29 @@ 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, + 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..c961fa66d 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,20 @@ 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( + 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/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; i +#include +#include +#include +#include +#include +#include + +#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 * _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; + float SNRdB = -10.0f; + const char * filename = "dsssframe64sync_example.m"; + + // 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 = (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"); + 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_execute(fg, NULL, NULL, buf_tx); + + // apply channel (AWGN) + float nstd = powf(10.0f,-SNRdB/20.0f); + unsigned int i; + for (i=0; i +#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); + 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() ) * M_SQRT1_2; +} + +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 = 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); + 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); + fprintf(fid,"clear all; close all;\n"); + fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); + printf("# %8s %6s (%7s) %6s (%7s) %6s\n", "SNR", "missed", "percent", "errors", "percent", "trials"); + fclose(fid); + while (SNRdB < -5.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); + 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, + (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"); + 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([-30 10 1e-3 1]);\n"); + fprintf(fid,"grid on;\n"); + fclose(fid); + printf("results written to %s\n", OUTPUT_FILENAME); + + // clean up allocated objects and memory blocks + dsssframe64gen_destroy(fg); + dsssframe64sync_destroy(fs); + free(frame); + return 0; +} 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/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/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/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/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/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/include/liquid.h b/include/liquid.h index b2fb13b90..bbf321164 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); \ \ @@ -5993,6 +5990,83 @@ int dsssframesync_debug_disable (dsssframesync _q); int dsssframesync_debug_print (dsssframesync _q, const char * _filename); framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q); +// +// Direct sequence/spread spectrum framing with fixed 64-byte payload +// + +// frame generator object type +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); + +// print dsssframe64gen object internals +int dsssframe64gen_print(dsssframe64gen _q); + +// get length of assembled frame (samples) +unsigned int dsssframe64gen_get_frame_len(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; + +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); +int dsssframe64sync_is_frame_open (dsssframe64sync _q); +int dsssframe64sync_set_callback(dsssframe64sync _q, + framesync_callback _callback); +int dsssframe64sync_set_context(dsssframe64sync _q, + void * _context); +// execute frame synchronizer +// _q : frame synchronizer object +// _buf : input sample array, shape: (_buf_len,) +// _buf_len : number of input samples +int dsssframe64sync_execute(dsssframe64sync _q, liquid_float_complex * _buf, unsigned int _buf_len); + +// get detection threshold +float dsssframe64sync_get_threshold(dsssframe64sync _q); + +// set detection threshold +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); + +// reset frame data statistics +int dsssframe64sync_reset_framedatastats(dsssframe64sync _q); + +// retrieve frame data statistics +framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q); + // // OFDM flexframe generator // @@ -6344,11 +6418,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); \ @@ -6434,6 +6511,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); \ \ @@ -6441,7 +6521,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); \ \ @@ -8228,105 +8311,164 @@ 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) 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) -// 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); +#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); \ + \ +/* 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); \ + \ +/* Destroy modulator object, freeing all allocate memory */ \ +int CPFSKMOD(_destroy)(CPFSKMOD() _q); \ + \ +/* Print modulator status to stdout */ \ +int CPFSKMOD(_print)(CPFSKMOD() _q); \ + \ +/* Reset internal state of modulator object */ \ +int CPFSKMOD(_reset)(CPFSKMOD() _q); \ + \ +/* 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 */ \ +/* _y : output sample array, [size: _k x 1] */ \ +int CPFSKMOD(_modulate)(CPFSKMOD() _q, \ + unsigned int _s, \ + TC * _y); \ -// print cpfskdem object internals -int cpfskdem_print(cpfskdem _q); +// define cpfskmod APIs +LIQUID_CPFSKMOD_DEFINE_API(LIQUID_CPFSKMOD_MANGLE_FLOAT,float,liquid_float_complex) -// 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); \ + \ +/* 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); \ + \ +/* 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 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] */ \ +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 @@ -9708,6 +9850,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/include/liquid.internal.h b/include/liquid.internal.h index 1f9e027cd..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. // @@ -1381,19 +1365,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/makefile.in b/makefile.in index 8722c6265..d17cb6f9e 100644 --- a/makefile.in +++ b/makefile.in @@ -537,6 +537,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 \ @@ -633,6 +634,8 @@ framing_objects := \ src/framing/src/bpacketgen.o \ src/framing/src/bpacketsync.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 \ @@ -677,24 +680,11 @@ 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 \ src/framing/tests/detector_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 \ @@ -860,8 +850,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 \ @@ -874,6 +862,8 @@ 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 \ src/modem/src/modem_common.proto.c \ @@ -910,7 +900,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 \ @@ -950,10 +940,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 @@ -1195,7 +1186,8 @@ objects := \ $(sequence_objects) \ $(utility_objects) \ $(vector_objects) \ - + +$(objects) : %.o : %.c $(include_headers) autotest_sources := \ autotest/null_autotest.c \ @@ -1630,6 +1622,8 @@ 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 \ examples/dotprod_cccf_example \ @@ -1687,6 +1681,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 \ @@ -1713,6 +1708,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 \ @@ -1743,6 +1739,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/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; } diff --git a/src/audio/src/cvsd.c b/src/audio/src/cvsd.c index 11f3218dd..370976cb0 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..d13364be4 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,56 +123,8 @@ 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", - 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; -} - -// 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"); - } + printf("\n", + EXTENSION, _q->max_size, _q->max_read, _q->num_elements); return LIQUID_OK; } diff --git a/src/buffer/src/wdelay.proto.c b/src/buffer/src/wdelay.proto.c index 71f694058..d4a9735c9 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/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); 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..7d1162cb5 100644 --- a/src/equalization/src/eqlms.proto.c +++ b/src/equalization/src/eqlms.proto.c @@ -235,12 +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); - 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])); - } + 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/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/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 cbd88826d..b85b2b531 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/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/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; } 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 00b19439b..3c0fdcee1 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/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 aaea94b29..c70e235f1 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/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 9bdd223cc..a13b3815c 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; } 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/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; } 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; } 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/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/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 4a7a43bb6..7f2723755 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); @@ -338,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); } @@ -488,10 +438,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 +449,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 +508,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; 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; } 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/dsssframe64gen.c b/src/framing/src/dsssframe64gen.c new file mode 100644 index 000000000..4fd6f3e9c --- /dev/null +++ b/src/framing/src/dsssframe64gen.c @@ -0,0 +1,208 @@ +/* + * 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. + */ + +// DS/SS frame generator with fixed fields: 8-byte header and 64-byte payload + +#include +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +// write samples to buffer +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 +}; + +// create dsssframe64gen object +dsssframe64gen dsssframe64gen_create() +{ + dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); + q->m = 15; + q->beta = 0.20f; + q->sf = 80; // spreading factor + + unsigned int i; + + // generate p/n sequence + 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; + } + + // 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, 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); + + // 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"); + + // 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 +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; +} + +// get full frame length [samples] +unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) +{ + // 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 +// _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, + float complex * _buf) +{ + 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); + + // write frame to buffer + return dsssframe64gen_write(_q, _buf); +} + +// write samples to buffer +// _q : frame generator object +// _buf : output frame samples (full frame) +int dsssframe64gen_write(dsssframe64gen _q, + float complex * _buf) +{ + unsigned int i, j, n=0; + + // p/n sequence + for (i=0; i<1024; i++) { + firinterp_crcf_execute(_q->interp, _q->preamble_pn[i], &_buf[n]); + n+=2; + } + + // frame payload + for (i=0; i<650; i++) { + float complex sym = _q->payload_tx[i]; // strip out raw payload symbol + 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); + 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; + } + + // 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 new file mode 100644 index 000000000..27a84e620 --- /dev/null +++ b/src/framing/src/dsssframe64sync.c @@ -0,0 +1,369 @@ +/* + * 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. + */ + +// 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 -11 dB SNR + +#include +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +// internal update +int dsssframe64sync_step(dsssframe64sync _q, + float complex * _buf, + unsigned int _buf_len); + +// internal decode received frame, update statistics, invoke callback +int dsssframe64sync_decode(dsssframe64sync _q); + +// 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 * 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) + + // preamble + 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 [650]; // 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 + + // status variables + 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 +// _context : user-defined data object passed to callback +dsssframe64sync dsssframe64sync_create(framesync_callback _callback, + void * _context) +{ + dsssframe64sync q = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); + q->callback = _callback; + q->context = _context; + q->m = 15; // filter delay (symbols) + q->beta = 0.20f;// excess bandwidth factor + q->sf = 80; // spreading factor + + unsigned int i; + + // generate p/n sequence + 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; + } + + // create frame detector + 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.097f); // 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; + 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, 13); + assert( qpilotsync_get_frame_len(q->pilotsync)==650); + + // 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)); + + // 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); + + // update detector callback's context to use q_copy + qdsync_cccf_set_context(q_copy->detector, (void*)q_copy); + + return q_copy; +} + +// destroy frame synchronizer object, freeing all internal memory +int dsssframe64sync_destroy(dsssframe64sync _q) +{ + // destroy synchronization objects + 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 + + // free main object memory + free(_q); + return LIQUID_OK; +} + +// print frame synchronizer object internals +int dsssframe64sync_print(dsssframe64sync _q) +{ + printf("\n", + _q->preamble_counter, + _q->chip_counter, + _q->payload_counter); + return LIQUID_OK; +} + +// reset frame synchronizer object +int dsssframe64sync_reset(dsssframe64sync _q) +{ + // reset detector/synchronizer + qdsync_cccf_reset(_q->detector); + msequence_reset(_q->ms); + + // reset state + _q->preamble_counter= 0; + _q->chip_counter = 0; + _q->payload_counter = 0; + _q->sym_despread = 0; + + // reset frame statistics + _q->framesyncstats.evm = 0.0f; + + 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) +{ + _q->callback = _callback; + return LIQUID_OK; +} + +// set the user-defined data field (context) +int dsssframe64sync_set_context(dsssframe64sync _q, + void * _context) +{ + _q->context= _context; + return LIQUID_OK; +} + +// execute frame synchronizer +// _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) +{ + // run detector/synchronizer, invoking internal callback as needed + return qdsync_cccf_execute(_q->detector, _buf, _buf_len); +} + +// set detection threshold +int dsssframe64sync_set_threshold(dsssframe64sync _q, + float _threshold) +{ + 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) +{ + 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) +{ + return framedatastats_reset(&_q->framedatastats); +} + +// retrieve frame data statistics +framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q) +{ + return _q->framedatastats; +} + +// internal update +int dsssframe64sync_step(dsssframe64sync _q, + float complex * _buf, + unsigned int _buf_len) +{ + unsigned int i; + for (i=0; i<_buf_len; i++) { + // receive preamble (not currently used) + if (_q->preamble_counter < 1024) { + _q->preamble_rx[_q->preamble_counter++] = _buf[i]; + continue; + } + + // 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++; + + // 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); + msequence_reset(_q->ms); + return 1; // reset qdsync + } + } + } + + return 0; // need more data +} + +// internal decode received frame, update statistics, invoke callback +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 + // debug: export symbols to file + unsigned int i; + FILE * fid = fopen("dsssframe64sync_debug.m","w"); + 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])); + fclose(fid); +#endif + // 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) { + // offset estimates + float dphi_hat = qdsync_cccf_get_dphi(_q->detector) + + qpilotsync_get_dphi(_q->pilotsync) / (float)(_q->sf); + + // set framesyncstats internals + _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); + _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; + _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; +} + 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/ofdmflexframegen.c b/src/framing/src/ofdmflexframegen.c index 90191a814..38f71b9f9 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..29057b923 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, 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 5c13f45eb..b42f1b20b 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 @@ -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 @@ -321,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 (bins) : %-d\n", _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; } @@ -380,16 +383,23 @@ int QDETECTOR(_set_threshold)(QDETECTOR() _q, return LIQUID_OK; } +// get carrier offset search range +float QDETECTOR(_get_range)(QDETECTOR() _q) +{ + 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/src/qdsync.proto.c b/src/framing/src/qdsync.proto.c index 06f8fc0a0..a2c0b5dea 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 @@ -176,10 +176,16 @@ int QDSYNC(_reset)(QDSYNC() _q) int QDSYNC(_print)(QDSYNC() _q) { - printf("\n"); + printf("\n", _q->seq_len); 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) { @@ -192,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) { 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/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; } 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 248928f61..65cbb9afd 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; } diff --git a/src/framing/tests/dsssframe64_autotest.c b/src/framing/tests/dsssframe64_autotest.c new file mode 100644 index 000000000..f8b14490a --- /dev/null +++ b/src/framing/tests/dsssframe64_autotest.c @@ -0,0 +1,180 @@ +/* + * 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 +#include +#include +#include "autotest/autotest.h" +#include "liquid.h" + +void autotest_dsssframe64sync() +{ + // create objects + unsigned int context = 0; + dsssframe64gen fg = dsssframe64gen_create(); + dsssframe64sync fs = dsssframe64sync_create(framing_autotest_callback, (void*)&context); + + // generate the frame + 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); + + // add some noise + unsigned int i; + for (i=0; itype) { - 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.c b/src/modem/src/cpfskdem.proto.c similarity index 55% rename from src/modem/src/cpfskdem.c rename to src/modem/src/cpfskdem.proto.c index 425400620..daa97067d 100644 --- a/src/modem/src/cpfskdem.c +++ b/src/modem/src/cpfskdem.proto.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. */ -// // continuous phase frequency-shift keying demodulator -// #include #include @@ -30,42 +28,22 @@ #include "liquid.internal.h" -#define DEBUG_CPFSKDEM 0 - -// -// internal methods -// +#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); - -#if 0 -// demodulate array of samples (coherent) -int cpfskdem_demodulate_coherent(cpfskdem _q, - float complex _y, - unsigned int * _s, - unsigned int * _nw); +int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q); -// 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 @@ -84,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 @@ -98,22 +75,17 @@ 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) - */ - - firfilt_crcf mf; // matched filter + //nco_crcf nco; // oscillator/phase-locked loop + //firpfb_crcf mf; // matched filter + //firpfb_crcf dmf; // matched filter (derivative) + //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 @@ -121,34 +93,34 @@ 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) 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"); + 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]"); - 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)); + CPFSKDEM() q = (cpfskdem) malloc(sizeof(struct CPFSKDEM(_s))); // set basic internal properties q->bps = _bps; // bits per symbol @@ -158,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 @@ -167,22 +149,73 @@ 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); - + CPFSKDEM(_reset)(q); +#if DEBUG_CPFSKDEM + printf("clear all; close all; y=[]; z=[];\n"); +#endif return q; } -// initialize coherent demodulator -int cpfskdem_init_coherent(cpfskdem _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; +} + +// 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) +{ + 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; @@ -193,28 +226,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; @@ -222,48 +255,30 @@ 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_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_error(LIQUID_EICONFIG,"cpfskdem_init_noncoherent(), invalid tx filter type"); } return LIQUID_OK; -#else - return liquid_error(LIQUID_EUMODE,"cpfskdem_init_noncoherent(), unsupported mode"); -#endif } // destroy modem object -int cpfskdem_destroy(cpfskdem _q) +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); + return liquid_error(LIQUID_EINT,"cpfskdem_destroy(), coherent mode not supported"); break; case CPFSKDEM_NONCOHERENT: + firfilt_crcf_destroy(_q->demod.noncoherent.mf); break; } @@ -273,19 +288,27 @@ int cpfskdem_destroy(cpfskdem _q) } // print modulation internals -int cpfskdem_print(cpfskdem _q) +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; } // reset modem object -int cpfskdem_reset(cpfskdem _q) +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; @@ -299,12 +322,43 @@ int cpfskdem_reset(cpfskdem _q) return LIQUID_OK; } -// get transmit delay [symbols] -unsigned int cpfskdem_get_delay(cpfskdem _q) +// 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 @@ -312,11 +366,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; @@ -335,21 +389,21 @@ 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; // 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 @@ -359,10 +413,10 @@ 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); + firfilt_crcf_execute(_q->demod.noncoherent.mf, &z); // compute instantaneous frequency scaled by modulation index // TODO: pre-compute scaling factor @@ -389,7 +443,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) @@ -403,36 +457,44 @@ 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) +{ + 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); - 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)); + 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 // decimate output 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 @@ -447,7 +509,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 } @@ -455,11 +517,5 @@ unsigned int cpfskdem_demodulate_coherent(cpfskdem _q, return sym_out; } -// demodulate array of samples (non-coherent) -unsigned int cpfskdem_demodulate_noncoherent(cpfskdem _q, - float complex * _y) -{ - return 0; -} #endif diff --git a/src/modem/src/cpfskmod.c b/src/modem/src/cpfskmod.proto.c similarity index 63% rename from src/modem/src/cpfskmod.c rename to src/modem/src/cpfskmod.proto.c index 843022c75..676026244 100644 --- a/src/modem/src/cpfskmod.c +++ b/src/modem/src/cpfskmod.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 @@ -28,20 +28,16 @@ #include "liquid.internal.h" -// -// internal methods -// - // design transmit filter -int cpfskmod_firdes(unsigned int _k, - unsigned int _m, - float _beta, - int _type, - float * _h, - unsigned int _h_len); - -// cpfskmod -struct cpfskmod_s { +int CPFSKMOD(_firdes)(unsigned int _k, + unsigned int _m, + float _beta, + int _type, + float * _h, + unsigned int _h_len); + +struct CPFSKMOD(_s) +{ // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol @@ -53,43 +49,43 @@ 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) +// 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) 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)); + CPFSKMOD() q = (CPFSKMOD()) malloc(sizeof(struct CPFSKMOD(_s))); // set basic internal properties q->bps = _bps; // bits per symbol @@ -131,18 +127,18 @@ 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 - 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); @@ -150,8 +146,46 @@ cpfskmod cpfskmod_create(unsigned int _bps, return q; } -// destroy cpfskmod object -int cpfskmod_destroy(cpfskmod _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) +{ + // 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 free(_q->ht); @@ -163,33 +197,24 @@ int cpfskmod_destroy(cpfskmod _q) return LIQUID_OK; } -// print cpfskmod object internals -int cpfskmod_print(cpfskmod _q) +// print modulator 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; } // reset state -int cpfskmod_reset(cpfskmod _q) +int CPFSKMOD(_reset)(CPFSKMOD() _q) { // reset interpolator firinterp_rrrf_reset(_q->interp); @@ -200,19 +225,50 @@ int cpfskmod_reset(cpfskmod _q) return LIQUID_OK; } -// get transmit delay [symbols] -unsigned int cpfskmod_get_delay(cpfskmod _q) +// 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 // _y : output sample array [size: _k x 1] -int cpfskmod_modulate(cpfskmod _q, - unsigned int _s, - float complex * _y) +int CPFSKMOD(_modulate)(CPFSKMOD() _q, + unsigned int _s, + TC * _y) { // run interpolator float v = 2.0f*_s - (float)(_q->M) + 1.0f; @@ -244,12 +300,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/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; } diff --git a/src/modem/src/modem_common.proto.c b/src/modem/src/modem_common.proto.c index 885235f0e..7e14b4c2f 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; } @@ -302,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; } @@ -587,6 +584,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 @@ -613,6 +611,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/src/modemcf.c b/src/modem/src/modemcf.c index f8b94686c..e83b0aef0 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,8 @@ #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) #define FREQDEM(name) LIQUID_CONCAT(freqdem,name) @@ -61,6 +63,10 @@ // arbitrary modems #include "modem_arb.proto.c" +// non-linear modems +#include "cpfskdem.proto.c" +#include "cpfskmod.proto.c" + // analog modems #include "freqmod.proto.c" #include "freqdem.proto.c" diff --git a/src/modem/tests/cpfskmodem_autotest.c b/src/modem/tests/cpfskmodem_autotest.c index 27f57c073..003cd16f1 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 @@ -24,34 +24,24 @@ #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 M = 1 << _m; // constellation size - - unsigned int num_symbols = 80 + delay; // number of symbols to test + unsigned int k = cpfskmod_get_samples_per_symbol(mod); + unsigned int bps = cpfskmod_get_bits_per_symbol(mod); - msequence ms = msequence_create_default(7); - - 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 // modulate, demodulate, count errors + msequence ms = msequence_create_default(7); unsigned int i; for (i=0; i #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) @@ -132,3 +132,35 @@ 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) ); + 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); +} + diff --git a/src/multichannel/src/firpfbch.proto.c b/src/multichannel/src/firpfbch.proto.c index 0683c3a1a..25a7e420d 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, _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 9507a586a..f31ca9cfc 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))); @@ -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; @@ -207,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; } 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; } diff --git a/src/multichannel/tests/firpfbchr_crcf_autotest.c b/src/multichannel/tests/firpfbchr_crcf_autotest.c new file mode 100644 index 000000000..e12acb018 --- /dev/null +++ b/src/multichannel/tests/firpfbchr_crcf_autotest.c @@ -0,0 +1,156 @@ +/* + * 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() +{ + // options + unsigned int M = 16; // number of channels + unsigned int P = 6; // output decimation rate + 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 + + // 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.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, + 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 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; itheta, _q->d_theta); + printf("\n", + EXTENSION, _q->theta, _q->d_theta); #if LIQUID_DEBUG_NCO // print entire table unsigned int i; 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; } 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 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 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; } 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)