Implemented pulse shaping
The pulse shaper currently uses an RRC filter with beta=0.2.
This commit is contained in:
parent
a6fed80149
commit
d522a1d6bd
|
@ -17,6 +17,8 @@ set(sources
|
||||||
src/config.h
|
src/config.h
|
||||||
src/preamble.h
|
src/preamble.h
|
||||||
src/preamble.c
|
src/preamble.c
|
||||||
|
src/transmission.h
|
||||||
|
src/transmission.c
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|
|
@ -13,4 +13,11 @@
|
||||||
#define PREAMBLE_MSEQ_POLY LIQUID_MSEQUENCE_GENPOLY_M6
|
#define PREAMBLE_MSEQ_POLY LIQUID_MSEQUENCE_GENPOLY_M6
|
||||||
#define PREAMBLE_MSEQ_INIT 0x00000001
|
#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
|
#endif // CONFIG_H
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "packet_mod.h"
|
#include "packet_mod.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "preamble.h"
|
#include "preamble.h"
|
||||||
|
#include "transmission.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
@ -38,8 +39,38 @@ int main(void)
|
||||||
|
|
||||||
float complex msg_mod[nsyms];
|
float complex msg_mod[nsyms];
|
||||||
packet_mod_get_result_cf(&pmod, msg_mod, &nsyms); // get the data
|
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
|
// channel
|
||||||
float complex msg_received[nsyms];
|
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));
|
unsigned int bit_errors = count_bit_errors_array(msg_org, msg_dec, sizeof(msg_org));
|
||||||
printf("%u bit errors detected.\n", bit_errors);
|
printf("%u bit errors detected.\n", bit_errors);
|
||||||
|
#endif
|
||||||
|
|
||||||
fec_destroy(q);
|
fec_destroy(q);
|
||||||
|
|
||||||
|
|
98
impl/src/transmission.c
Normal file
98
impl/src/transmission.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
79
impl/src/transmission.h
Normal file
79
impl/src/transmission.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef TRANSMISSION_H
|
||||||
|
#define TRANSMISSION_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
|
#include <liquid/liquid.h>
|
||||||
|
|
||||||
|
#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
|
Loading…
Reference in a new issue