1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
// This example demonstrates the interfaces to the fskframegen and
// fskframesync objects used to completely encapsulate data for
// over-the-air transmission.
//
// SEE ALSO: flexframesync_example.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <getopt.h>
#include <time.h>
#include "liquid.h"
#define OUTPUT_FILENAME "fskframesync_example.m"
void usage()
{
printf("fskframesync_example [options]\n");
printf(" h : print usage\n");
printf(" d : enable debugging\n");
printf(" S : signal-to-noise ratio [dB], default: 20\n");
printf(" F : carrier frequency offset, default: 0\n");
printf(" P : carrier phase offset, default: 0\n");
printf(" T : fractional sample timing offset, default: 0.01\n");
}
// static callback function
static int callback(unsigned char * _header,
int _header_valid,
unsigned char * _payload,
unsigned int _payload_len,
int _payload_valid,
framesyncstats_s _stats,
void * _userdata);
// global arrays
unsigned char header[8];
unsigned char payload[200];
int main(int argc, char*argv[])
{
srand( time(NULL) );
// options
float SNRdB = 20.0f; // signal-to-noise ratio
float noise_floor = -20.0f; // noise floor
float dphi = 0.01f; // carrier frequency offset
float theta = 0.0f; // carrier phase offset
float dt = -0.2f; // fractional sample timing offset
crc_scheme check = LIQUID_CRC_32; // data validity check
fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner)
fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer)
unsigned int payload_len = 200; // payload length
int debug_enabled = 0;
// get options
int dopt;
while((dopt = getopt(argc,argv,"hdS:F:P:T:")) != EOF){
switch (dopt) {
case 'h': usage(); return 0;
case 'd': debug_enabled = 1; break;
case 'S': SNRdB = atof(optarg); break;
case 'F': dphi = atof(optarg); break;
case 'P': theta = atof(optarg); break;
case 'T': dt = atof(optarg); break;
default:
exit(-1);
}
}
printf("channel offsets: dt=%.3f, dphi=%.3f, theta=%.3f\n", dt, dphi, theta);
// derived values
float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev.
float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain
// create frame generator
fskframegen fg = fskframegen_create();
fskframegen_print(fg);
// create frame synchronizer using default properties
fskframesync fs = fskframesync_create(callback,NULL);
fskframesync_print(fs);
if (debug_enabled)
fskframesync_debug_enable(fs);
// data payload
unsigned int i;
// initialize header and payload data
for (i=0; i<8; i++)
header[i] = i;
for (i=0; i<200; i++)
payload[i] = rand() & 0xff;
// allocate memory for the frame samples
unsigned int buf_len = 64;
float complex buf_tx[buf_len]; // receive buffer
float complex buf_rx[buf_len]; // transmit buffer
// assemble the frame
fskframegen_assemble(fg, header, payload, payload_len, check, fec0, fec1);
// spectral periodogram
unsigned int nfft = 4200;
spgramcf periodogram = spgramcf_create_default(nfft);
// write frame in blocks
int frame_complete = 0;
while (!frame_complete)
{
frame_complete = fskframegen_write_samples(fg, buf_tx, buf_len);
// add noise, channel gain
for (i=0; i<buf_len; i++)
buf_rx[i] = buf_tx[i]*gamma + nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2;
// synchronize/receive the frame
fskframesync_execute_block(fs, buf_rx, buf_len);
// estimate power spectral density
spgramcf_write(periodogram, buf_rx, buf_len);
}
// compute power spectral density of received signal
float psd[nfft];
spgramcf_get_psd(periodogram, psd);
// clean up allocated objects
spgramcf_destroy(periodogram);
fskframegen_destroy(fg);
fskframesync_destroy(fs);
//
// export results
//
FILE * fid = fopen(OUTPUT_FILENAME,"w");
fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
fprintf(fid,"clear all\n");
fprintf(fid,"close all\n");
fprintf(fid,"nfft = %u;\n", nfft);
// save power spectral density
fprintf(fid,"psd = zeros(1,nfft);\n");
for (i=0; i<nfft; i++)
fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);
// plot PSD
fprintf(fid,"figure('Color','white');\n");
fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n");
fprintf(fid,"axis([-0.5 0.5 -30 30]);\n");
fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
fprintf(fid,"ylabel('PSD [dB]');\n");
fprintf(fid,"grid on;\n");
fclose(fid);
printf("results written to '%s'\n", OUTPUT_FILENAME);
printf("done.\n");
return 0;
}
// static callback function
static int callback(unsigned char * _header,
int _header_valid,
unsigned char * _payload,
unsigned int _payload_len,
int _payload_valid,
framesyncstats_s _stats,
void * _userdata)
{
printf("*** callback invoked ***\n");
printf(" error vector mag. : %12.8f dB\n", _stats.evm);
printf(" rssi : %12.8f dB\n", _stats.rssi);
printf(" carrier offset : %12.8f\n", _stats.cfo);
printf(" mod. scheme : %s\n", modulation_types[_stats.mod_scheme].fullname);
printf(" mod. depth : %u\n", _stats.mod_bps);
printf(" payload CRC : %s\n", crc_scheme_str[_stats.check][1]);
printf(" payload fec (inner) : %s\n", fec_scheme_str[_stats.fec0][1]);
printf(" payload fec (outer) : %s\n", fec_scheme_str[_stats.fec1][1]);
printf(" header crc : %s\n", _header_valid ? "pass" : "FAIL");
printf(" header data : %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
_header[0], _header[1], _header[2], _header[3],
_header[4], _header[5], _header[6], _header[7]);
printf(" num header errors : %u / %u\n",
count_bit_errors_array(_header, header, 8),
8*8);
printf(" payload crc : %s\n", _payload_valid ? "pass" : "FAIL");
printf(" num payload errors : %u / %u\n",
count_bit_errors_array(_payload, payload, 64),
64*8);
return 0;
}
|