diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt index eb98d50..4d8bab0 100644 --- a/impl/CMakeLists.txt +++ b/impl/CMakeLists.txt @@ -17,6 +17,8 @@ set(sources src/config.h src/preamble.h src/preamble.c + src/transmission.h + src/transmission.c ) include_directories( diff --git a/impl/src/config.h b/impl/src/config.h index 747bcaf..67d4a8e 100644 --- a/impl/src/config.h +++ b/impl/src/config.h @@ -13,4 +13,11 @@ #define PREAMBLE_MSEQ_POLY LIQUID_MSEQUENCE_GENPOLY_M6 #define PREAMBLE_MSEQ_INIT 0x00000001 +#define RRC_SPS 4 // samples per symbol +#define RRC_DELAY 7 // delay in symbols +#define RRC_BETA 0.2f + +#define TRANSMISSION_RAMP_UP_LEN 32 // symbols +#define TRANSMISSION_RAMP_DOWN_LEN 32 // symbols + #endif // CONFIG_H diff --git a/impl/src/main.c b/impl/src/main.c index b168f4a..0209524 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -7,6 +7,7 @@ #include "packet_mod.h" #include "config.h" #include "preamble.h" +#include "transmission.h" int main(void) { @@ -38,8 +39,38 @@ int main(void) float complex msg_mod[nsyms]; packet_mod_get_result_cf(&pmod, msg_mod, &nsyms); // get the data - dump_array_cf(msg_mod, nsyms, 1.0f, "/tmp/tx.cpx"); + size_t burst_len = 0; + float complex whole_burst[65536]; + size_t len; + + transmission_ctx_t transm; + transmission_init(&transm); + + len = 65536-burst_len; + if(transmission_ramp_up(&transm, whole_burst+burst_len, &len) != OK) { + printf("Ramp-up requires %zd symbols at offset %zd.\n", len, burst_len); + return 1; + } + burst_len += len; + + len = 65536-burst_len; + if(transmission_filter_packet(&transm, msg_mod, nsyms, whole_burst+burst_len, &len) != OK) { + printf("Packet requires %zd symbols at offset %zd.\n", len, burst_len); + return 1; + } + burst_len += len; + + len = 65536-burst_len; + if(transmission_ramp_down(&transm, whole_burst+burst_len, &len) != OK) { + printf("Ramp-down requires %zd symbols at offset %zd.\n", len, burst_len); + return 1; + } + burst_len += len; + + dump_array_cf(whole_burst, burst_len, 1.0f, "/tmp/tx.cpx"); + +#if 0 // channel float complex msg_received[nsyms]; @@ -86,6 +117,7 @@ int main(void) unsigned int bit_errors = count_bit_errors_array(msg_org, msg_dec, sizeof(msg_org)); printf("%u bit errors detected.\n", bit_errors); +#endif fec_destroy(q); diff --git a/impl/src/transmission.c b/impl/src/transmission.c new file mode 100644 index 0000000..a1ac60b --- /dev/null +++ b/impl/src/transmission.c @@ -0,0 +1,98 @@ +#include + +#include "transmission.h" + +#include "config.h" + +result_t transmission_init(transmission_ctx_t *ctx) +{ + ctx->rrc_interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_RRC, RRC_SPS, RRC_DELAY, RRC_BETA, 0); + return OK; +} + + +result_t transmission_free(transmission_ctx_t *ctx) +{ + firinterp_crcf_destroy(ctx->rrc_interp); + + return OK; +} + + +result_t transmission_ramp_up(transmission_ctx_t *ctx, float complex *output, size_t *output_size) +{ + if(*output_size < RRC_SPS*TRANSMISSION_RAMP_UP_LEN) { + *output_size = RRC_SPS*TRANSMISSION_RAMP_UP_LEN; + return ERR_SIZE; + } + + // ramp up alternating ±1 symbols following a sin(t)^2 curve + for(size_t i = 0; i < TRANSMISSION_RAMP_UP_LEN; i++) { + float s = sinf((float)M_PI / 2.0f * i / TRANSMISSION_RAMP_UP_LEN); + float symbol = s*s; + + if((i % 2) != 0) { + symbol = -symbol; + } + + firinterp_crcf_execute(ctx->rrc_interp, symbol, output + (RRC_SPS*i)); + } + + *output_size = RRC_SPS*TRANSMISSION_RAMP_UP_LEN; + + return OK; +} + + +result_t transmission_ramp_down(transmission_ctx_t *ctx, float complex *output, size_t *output_size) +{ + const size_t total_symbols = TRANSMISSION_RAMP_DOWN_LEN + 2*RRC_DELAY; + if(*output_size < RRC_SPS*total_symbols) { + *output_size = RRC_SPS*total_symbols; + return ERR_SIZE; + } + + // ramp down alternating ±1 symbols following a cos(t)^2 curve + for(size_t i = 0; i < TRANSMISSION_RAMP_DOWN_LEN; i++) { + float s = cosf((float)M_PI / 2.0f * i / TRANSMISSION_RAMP_DOWN_LEN); + float symbol = s*s; + + if((i % 2) != 0) { + symbol = -symbol; + } + + firinterp_crcf_execute(ctx->rrc_interp, symbol, output + (RRC_SPS*i)); + } + + // add 2*RRC_DELAY zeros to flush the filter history + for(size_t i = 0; i < 2*RRC_DELAY; i++) { + firinterp_crcf_execute(ctx->rrc_interp, 0.0f, output + (RRC_SPS*(TRANSMISSION_RAMP_DOWN_LEN+i))); + } + + *output_size = RRC_SPS*total_symbols; + + return OK; +} + + +result_t transmission_filter_packet( + transmission_ctx_t *ctx, + const float complex *packet, + size_t packet_size, + float complex *output, + size_t *output_size) +{ + if(*output_size < RRC_SPS*packet_size) { + *output_size = RRC_SPS*packet_size; + return ERR_SIZE; + } + + // ramp down alternating ±1 symbols following a cos(t)^2 curve + for(size_t i = 0; i < packet_size; i++) { + firinterp_crcf_execute(ctx->rrc_interp, packet[i], output + (RRC_SPS*i)); + } + + *output_size = RRC_SPS*TRANSMISSION_RAMP_DOWN_LEN; + + return OK; +} diff --git a/impl/src/transmission.h b/impl/src/transmission.h new file mode 100644 index 0000000..5002b32 --- /dev/null +++ b/impl/src/transmission.h @@ -0,0 +1,79 @@ +#ifndef TRANSMISSION_H +#define TRANSMISSION_H + +#include +#include + +#include + +#include "results.h" + +typedef struct +{ + firinterp_crcf rrc_interp; +} transmission_ctx_t; + + +/*!\brief Initialize the transmission object. + * + * \param ctx Pointer to the context to initialize. + * \returns The result code of the initialization. + */ +result_t transmission_init(transmission_ctx_t *ctx); + + +/*!\brief Free all memory associated with the given context. + * + * \param ctx Pointer to the context to free. + * \returns The result code of the operation. + */ +result_t transmission_free(transmission_ctx_t *ctx); + + +/*!\brief Generate a signal ramp-up and write it to the output array. + * + * \param ctx Pointer to the transmission context. + * \param output Pointer to the output array. + * \param output_size Pointer to the output size. Must be set to the number + * of samples that can be stored in \ref output when + * calling the function. It will be changed to the number + * of samples actually produced. + * \returns The result code of the operation. + */ +result_t transmission_ramp_up(transmission_ctx_t *ctx, float complex *output, size_t *output_size); + + +/*!\brief Generate a signal ramp-down and write it to the output array. + * + * \param ctx Pointer to the transmission context. + * \param output Pointer to the output array. + * \param output_size Pointer to the output size. Must be set to the number + * of samples that can be stored in \ref output when + * calling the function. It will be changed to the number + * of samples actually produced. + * \returns The result code of the operation. + */ +result_t transmission_ramp_down(transmission_ctx_t *ctx, float complex *output, size_t *output_size); + + +/*!\brief Filter the given symbols. + * + * \param ctx Pointer to the transmission context. + * \param packet Pointer to the symbols to filter. + * \param packet_size Number of samples in \ref packet. + * \param output Pointer to the output array. + * \param output_size Pointer to the output size. Must be set to the number + * of samples that can be stored in \ref output when + * calling the function. It will be changed to the number + * of samples actually produced. + * \returns The result code of the operation. + */ +result_t transmission_filter_packet( + transmission_ctx_t *ctx, + const float complex *packet, + size_t packet_size, + float complex *output, + size_t *output_size); + + +#endif // TRANSMISSION_H