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/preamble.h
|
||||
src/preamble.c
|
||||
src/transmission.h
|
||||
src/transmission.c
|
||||
)
|
||||
|
||||
include_directories(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
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