Initial import
This commit is contained in:
292
demodulator.c
Normal file
292
demodulator.c
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
/* Title: demodulatore */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <dsp.h>
|
||||||
|
#include <libq.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../phy/phy.h" // a chi cazzo serve?
|
||||||
|
|
||||||
|
#include "../peripheral/adc.h"
|
||||||
|
#include "../peripheral/gpio.h"
|
||||||
|
|
||||||
|
// serve? direi di si
|
||||||
|
#include "modem_types.h"
|
||||||
|
|
||||||
|
#include "demodulator.h"
|
||||||
|
|
||||||
|
// buffer dei simboli ricevuti
|
||||||
|
uint8_t rx_symbol_buffer[MAX_SYMBOL_BUFFER_SIZE];
|
||||||
|
uint8_t rx_symbol_buffer_index, rx_symbol_buffer_lenght;
|
||||||
|
|
||||||
|
uint8_t rx_sample_buffers_buffer[MAX_BUFFERS_PER_SYMBOL], rx_sample_buffer_index;
|
||||||
|
|
||||||
|
uint8_t volatile process_input_sample_buffer;
|
||||||
|
|
||||||
|
detector_symbol detector_constellation[MAX_MODULATION_ALPHABET_SIZE], symbol_error, min_symbol_distance;
|
||||||
|
|
||||||
|
// zona del simbolo da esaminare:
|
||||||
|
uint8_t rx_symbol_detected_part_offset, rx_symbol_detected_part_length;
|
||||||
|
|
||||||
|
// NCO
|
||||||
|
fractional tanlock_nco_rotor_inc;
|
||||||
|
|
||||||
|
// #####################################################
|
||||||
|
|
||||||
|
void demodulator_setup(void) {
|
||||||
|
// RX
|
||||||
|
set_rx_GPIOs();
|
||||||
|
|
||||||
|
// setup rotore NCO demodulatore, posizionalo al centro della costellazione
|
||||||
|
tanlock_nco_rotor_inc = get_angular_frequency(find_constellation_center_values(mod.constellation).frequency);
|
||||||
|
|
||||||
|
demodulator_prepare_constellation_symbols(mod.constellation, detector_constellation);
|
||||||
|
min_symbol_distance = demodulator_find_min_symbol_distance(detector_constellation);
|
||||||
|
|
||||||
|
// zona del simbolo da esaminare:
|
||||||
|
// due quarti centrali del simbolo, da verificare
|
||||||
|
// si lavora solo su mezzo simbolo, ma si regge una sfasatura di +-1/4 di simbolo
|
||||||
|
rx_symbol_detected_part_offset = mod.buffers_per_symbol / 4;
|
||||||
|
rx_symbol_detected_part_length = mod.buffers_per_symbol / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trova valori medii dei parametri di modulazione
|
||||||
|
|
||||||
|
symbol find_constellation_center_values(symbol *constellation) {
|
||||||
|
uint8_t i;
|
||||||
|
symbol max, min, center;
|
||||||
|
max.amplitude = max.frequency = max.phase = 0;
|
||||||
|
min.frequency = min.phase = min.amplitude = 0xFFFF;
|
||||||
|
|
||||||
|
for (i = 0; i < mod.alphabet_size; i++) {
|
||||||
|
if (constellation[i].frequency < min.frequency) min.frequency = constellation[i].frequency;
|
||||||
|
if (constellation[i].frequency > max.frequency) max.frequency = constellation[i].frequency;
|
||||||
|
|
||||||
|
if (constellation[i].phase < min.phase) min.phase = constellation[i].phase;
|
||||||
|
if (constellation[i].phase > max.phase) max.phase = constellation[i].phase;
|
||||||
|
|
||||||
|
if (constellation[i].amplitude < min.amplitude) min.amplitude = constellation[i].amplitude;
|
||||||
|
if (constellation[i].amplitude > max.amplitude) max.amplitude = constellation[i].amplitude;
|
||||||
|
|
||||||
|
}
|
||||||
|
center.frequency = min.frequency + ((max.frequency - min.frequency) / 2);
|
||||||
|
center.phase = min.phase + ((max.phase - min.phase) / 2);
|
||||||
|
center.amplitude = min.amplitude + ((max.amplitude - min.amplitude) / 2);
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t get_angular_frequency(uint16_t frequency) {
|
||||||
|
int32_t tmpfreq = (int32_t) frequency << 16;
|
||||||
|
return __builtin_divsd(tmpfreq, SAMPLING_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FIR_init(void) {
|
||||||
|
#ifdef __DSP_LIB__
|
||||||
|
// inizializza filtri passa basso
|
||||||
|
FIRDelayInit(&ph_det_lpFilterQ);
|
||||||
|
FIRDelayInit(&ph_det_lpFilterI);
|
||||||
|
FIRDelayInit(&ph_det_lpFilterFreq);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void demodulator_sample_buffer_demodulate(fractional *buffer, detector_symbol* outsymbol) {
|
||||||
|
uint8_t i;
|
||||||
|
fractional demodulator_frequency_diff = 0, demodulator_phase_diff = 0;
|
||||||
|
static fractional freq_lp[1];
|
||||||
|
_Q15_16 frequency_accu = 0, phase_accu = 0, amplitude_accu = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < SAMPLES_PER_BUFFER; i++) {
|
||||||
|
// ampiezza
|
||||||
|
amplitude_accu += _Q15abs(buffer[i]);
|
||||||
|
|
||||||
|
// fase
|
||||||
|
demodulator_phase_diff = demodulator_phase_detector(buffer[i]);
|
||||||
|
phase_accu += demodulator_phase_diff;
|
||||||
|
|
||||||
|
// frequenza
|
||||||
|
demodulator_frequency_diff = demodulator_frequency_detector(demodulator_phase_diff);
|
||||||
|
|
||||||
|
#ifdef __DSP_LIB__
|
||||||
|
FIR(1, &freq_lp[0], &demodulator_frequency_diff, &ph_det_lpFilterFreq);
|
||||||
|
#endif
|
||||||
|
frequency_accu = frequency_accu + freq_lp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// media
|
||||||
|
outsymbol->amplitude = __builtin_divsd(amplitude_accu, SAMPLES_PER_BUFFER);
|
||||||
|
outsymbol->phase = __builtin_divsd(phase_accu, SAMPLES_PER_BUFFER);
|
||||||
|
outsymbol->frequency = __builtin_divsd(frequency_accu, SAMPLES_PER_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
fractional demodulator_phase_detector(fractional sig_in) {
|
||||||
|
static fractional tanlock_nco_rotor_pos;
|
||||||
|
static fractional Q_mix_lp[1], I_mix_lp[1];
|
||||||
|
// MIX
|
||||||
|
fractional I_mix, Q_mix, phasediff;
|
||||||
|
// moltiplica per segnale iniettato 171 cicli
|
||||||
|
|
||||||
|
// perche' 15? perche i campioni sono da 12 bit
|
||||||
|
I_mix = _Q16shr((__builtin_mulss(sig_in, _Q15sinPI(tanlock_nco_rotor_pos))), 16);
|
||||||
|
Q_mix = _Q16shr((__builtin_mulss(sig_in, _Q15cosPI(tanlock_nco_rotor_pos))), 16);
|
||||||
|
|
||||||
|
#ifdef __DSP_LIB__
|
||||||
|
// filtra l'i/q 270 cicli
|
||||||
|
FIR(1, &I_mix_lp[0], &I_mix, &ph_det_lpFilterI);
|
||||||
|
FIR(1, &Q_mix_lp[0], &Q_mix, &ph_det_lpFilterQ);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// incrementa il rotore dell'oscillatore locale
|
||||||
|
tanlock_nco_rotor_pos += tanlock_nco_rotor_inc; // non deve saturare!
|
||||||
|
|
||||||
|
// calcola arcotangente, circa 420 cicli
|
||||||
|
phasediff = _Q15atan2circle(I_mix_lp[0], Q_mix_lp[0]);
|
||||||
|
// phasediff = _Q15atan2circle(I_mix, Q_mix);
|
||||||
|
|
||||||
|
return phasediff;
|
||||||
|
}
|
||||||
|
|
||||||
|
fractional demodulator_frequency_detector(fractional phase) {
|
||||||
|
static fractional demodulator_last_phase, demodulator_last_delta;
|
||||||
|
fractional demodulator_phase_delta = 0, demodulator_phase_delta_tmp = 0;
|
||||||
|
|
||||||
|
demodulator_phase_delta_tmp = _Q15sub(phase, demodulator_last_phase);
|
||||||
|
|
||||||
|
// antiskew
|
||||||
|
if (_Q15abs(demodulator_phase_delta_tmp) < MAX_PHASE_SKEW) demodulator_phase_delta = demodulator_phase_delta_tmp;
|
||||||
|
else {
|
||||||
|
demodulator_phase_delta = demodulator_last_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// storici
|
||||||
|
demodulator_last_phase = phase;
|
||||||
|
demodulator_last_delta = demodulator_phase_delta;
|
||||||
|
|
||||||
|
return demodulator_phase_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ####### symbolame ##########
|
||||||
|
|
||||||
|
void demodulator_prepare_constellation_symbols(symbol *constellation, detector_symbol *demod_constellation) {
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < mod.alphabet_size; i++) {
|
||||||
|
demod_constellation[i].frequency = _Q15sub(get_angular_frequency(constellation[i].frequency), tanlock_nco_rotor_inc);
|
||||||
|
demod_constellation[i].phase = constellation[i].phase;
|
||||||
|
demod_constellation[i].amplitude = constellation[i].amplitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detector_symbol demodulator_find_min_symbol_distance(detector_symbol *demod_constellation) {
|
||||||
|
// find minimum distance between symbols
|
||||||
|
uint8_t i, k;
|
||||||
|
detector_symbol tmp_distance, min_distance;
|
||||||
|
min_distance.frequency = min_distance.phase = min_distance.amplitude = 0x7FFF;
|
||||||
|
for (i = 0; i < mod.alphabet_size; i++) {
|
||||||
|
for (k = 0; k < mod.alphabet_size; k++) {
|
||||||
|
if (k != i) {
|
||||||
|
tmp_distance.frequency = _Q15abs(_Q15sub(demod_constellation[i].frequency, demod_constellation[k].frequency));
|
||||||
|
if (tmp_distance.frequency < min_distance.frequency) min_distance.frequency = tmp_distance.frequency;
|
||||||
|
|
||||||
|
tmp_distance.phase = _Q15sub(demod_constellation[i].phase, demod_constellation[k].phase);
|
||||||
|
tmp_distance.amplitude = _Q15sub(demod_constellation[i].amplitude, demod_constellation[k].amplitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trova il simbolo piu vicino nella costellazione
|
||||||
|
|
||||||
|
uint8_t demodulator_find_nearest_symbol(detector_symbol *in_symbol, detector_symbol *target_constellation, detector_symbol *moderror) {
|
||||||
|
detector_symbol distance, min_distance = {0x7FFF, 0x7FFF, 0x7FFF};
|
||||||
|
uint8_t i, nearest_symbol = 0;
|
||||||
|
for (i = 0; i < mod.alphabet_size; i++) {
|
||||||
|
if (mod.frequency_keying) {
|
||||||
|
distance.frequency = _Q15abs(_Q15sub(target_constellation[i].frequency, in_symbol->frequency));
|
||||||
|
if (distance.frequency < min_distance.frequency) {
|
||||||
|
min_distance.frequency = distance.frequency;
|
||||||
|
nearest_symbol = i;
|
||||||
|
moderror->frequency = distance.frequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearest_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trova deviazione dal simbolo
|
||||||
|
|
||||||
|
uint8_t find_symbol_deviation(uint8_t *serie, uint8_t mean, uint8_t len) {
|
||||||
|
int16_t sum_deviation = 0;
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
sum_deviation += (serie[i] - mean)*(serie[i] - mean);
|
||||||
|
return sqrt(sum_deviation / len);
|
||||||
|
}
|
||||||
|
// valore ricorrente
|
||||||
|
|
||||||
|
uint8_t demodulator_most_frequent_value(uint8_t *serie, uint8_t range, uint8_t len) {
|
||||||
|
uint8_t i, prezzemolo = 0, prezzemolo_occurrences = 0;
|
||||||
|
uint8_t occurrencez[MAX_MODULATION_ALPHABET_SIZE] = {0};
|
||||||
|
// conta ricorrenze per ogni simbolo
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
occurrencez[serie[i]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trova il simbolo con la ricorrenza maggiore
|
||||||
|
for (i = 0; i < range; i++) {
|
||||||
|
if (occurrencez[i] > prezzemolo_occurrences) {
|
||||||
|
prezzemolo = i;
|
||||||
|
prezzemolo_occurrences = occurrencez[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prezzemolo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fractional _Q15atan2circle(fractional Y, fractional X) {
|
||||||
|
// ARCTAN a cerchio pieno
|
||||||
|
fractional atang = 0, offset = 0, temp = 0;
|
||||||
|
fractional X_sign = X;
|
||||||
|
|
||||||
|
if (Y <= 0) {
|
||||||
|
temp = Y;
|
||||||
|
Y = X;
|
||||||
|
X = _Q15neg(temp);
|
||||||
|
offset = _Q15add(offset, 16384);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_Q15abs(Y) <= _Q15abs(X)) {
|
||||||
|
if (X_sign < 0) {
|
||||||
|
temp = _Q15add(X, Y);
|
||||||
|
Y = _Q15sub(Y, X);
|
||||||
|
} else {
|
||||||
|
temp = _Q15sub(X, Y);
|
||||||
|
Y = _Q15add(Y, X);
|
||||||
|
}
|
||||||
|
|
||||||
|
X = temp;
|
||||||
|
offset = _Q15add(offset, 8192);
|
||||||
|
}
|
||||||
|
// circa 300 cy
|
||||||
|
#ifdef _libq_h_
|
||||||
|
atang = _Q15atanYByXByPI(Y, X); // vuole il large code model ? no! 2.2.2 del man
|
||||||
|
#endif
|
||||||
|
if (atang < 0) {
|
||||||
|
atang = _Q15sub(atang, offset);
|
||||||
|
} else {
|
||||||
|
atang = _Q15add(atang, offset);
|
||||||
|
}
|
||||||
|
return atang;
|
||||||
|
}
|
||||||
|
|
||||||
|
// devel
|
||||||
|
/*
|
||||||
|
fractional delay_phase_detector(fractional sig_in) {
|
||||||
|
fractional phased_sig_in, phasediff;
|
||||||
|
phased_sig_in = delay(sig_in, 2, delay_buffer);
|
||||||
|
phasediff = _Q15atan2circle(phased_sig_in, sig_in);
|
||||||
|
return phasediff;
|
||||||
|
}
|
||||||
|
*/
|
||||||
80
demodulator.h
Normal file
80
demodulator.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* File: demodulator.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEMODULATOR_H
|
||||||
|
#define DEMODULATOR_H
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <dsp.h>
|
||||||
|
#else
|
||||||
|
typedef int16_t _Q0_15;
|
||||||
|
typedef int32_t _Q15_16;
|
||||||
|
|
||||||
|
typedef _Q0_15 _Q15;
|
||||||
|
typedef _Q15_16 _Q16;
|
||||||
|
|
||||||
|
typedef int16_t fractional;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "modem_types.h"
|
||||||
|
|
||||||
|
#define MAX_PHASE_SKEW 10000L
|
||||||
|
#define ADC_MAX_AMPLITUDE 10000L
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fractional frequency;
|
||||||
|
fractional phase;
|
||||||
|
fractional amplitude;
|
||||||
|
} detector_symbol;
|
||||||
|
|
||||||
|
extern detector_symbol detector_constellation[MAX_MODULATION_ALPHABET_SIZE], symbol_error, min_symbol_distance;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t buffer[MAX_SYMBOL_BUFFER_SIZE];
|
||||||
|
uint8_t index;
|
||||||
|
uint8_t length;
|
||||||
|
} symbol_buffer;
|
||||||
|
|
||||||
|
// extern symbol_buffer rx_symbol_buffer;
|
||||||
|
|
||||||
|
// buffer dei simboli
|
||||||
|
extern uint8_t rx_symbol_buffer[MAX_SYMBOL_BUFFER_SIZE];
|
||||||
|
extern uint8_t rx_symbol_buffer_index, rx_symbol_buffer_lenght;
|
||||||
|
|
||||||
|
extern uint8_t rx_sample_buffers_buffer[MAX_BUFFERS_PER_SYMBOL], rx_sample_buffer_index;
|
||||||
|
|
||||||
|
extern uint8_t volatile process_input_sample_buffer;
|
||||||
|
|
||||||
|
// zona del simbolo da esaminare:
|
||||||
|
extern uint8_t rx_symbol_detected_part_offset, rx_symbol_detected_part_length;
|
||||||
|
|
||||||
|
// NCO
|
||||||
|
extern fractional tanlock_nco_rotor_inc;
|
||||||
|
|
||||||
|
#ifdef __DSP_LIB__
|
||||||
|
extern FIRStruct ph_det_lpFilterI, ph_det_lpFilterQ, ph_det_lpFilterFreq;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void demodulator_setup(void);
|
||||||
|
void demodulator_sample_buffer_demodulate(fractional *buffer, detector_symbol* outsymbol);
|
||||||
|
|
||||||
|
symbol find_constellation_center_values(symbol *constellation);
|
||||||
|
int16_t get_angular_frequency(uint16_t frequency);
|
||||||
|
void demodulator_prepare_constellation_symbols(symbol *constellation, detector_symbol *demod_constellation);
|
||||||
|
detector_symbol demodulator_find_min_symbol_distance(detector_symbol *demod_constellation);
|
||||||
|
uint8_t demodulator_most_frequent_value(uint8_t *serie, uint8_t range, uint8_t len);
|
||||||
|
uint8_t demodulator_find_nearest_symbol(detector_symbol *in_symbol, detector_symbol *target_constellation, detector_symbol *moderror);
|
||||||
|
|
||||||
|
fractional demodulator_phase_detector(fractional sig_in);
|
||||||
|
fractional demodulator_frequency_detector(fractional phase);
|
||||||
|
|
||||||
|
fractional _Q15atan2circle(fractional Y, fractional X);
|
||||||
|
void FIR_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* DEMODULATOR_H */
|
||||||
|
|
||||||
162
modem.c
Normal file
162
modem.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/* armando modem - iz4kll */
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <libq.h>
|
||||||
|
#include <dsp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "modem.h"
|
||||||
|
|
||||||
|
#include "../peripheral/gpio.h"
|
||||||
|
#include "../peripheral/adc.h"
|
||||||
|
#include "../peripheral/dac.h"
|
||||||
|
|
||||||
|
#if defined(__DEBUG) && ! defined(__MPLAB_DEBUGGER_PK3)
|
||||||
|
extern fractional debug_value1, debug_value2, debug_value3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// parametri della modulazione
|
||||||
|
modulation mod;
|
||||||
|
|
||||||
|
uint8_t modem_tx_state, modem_rx_state;
|
||||||
|
|
||||||
|
|
||||||
|
// predelay
|
||||||
|
uint16_t modem_predelay_mstime, modem_predelay_buffer_size, modem_predelay_buffer_index;
|
||||||
|
|
||||||
|
// non trasmettere quando stai ricevendo payload phy
|
||||||
|
uint8_t modem_avoid_overlap;
|
||||||
|
|
||||||
|
// payload
|
||||||
|
uint16_t modem_payload_max_symbols, modem_payload_symbols_index;
|
||||||
|
|
||||||
|
// solo al boot
|
||||||
|
|
||||||
|
void modem_init(void) {
|
||||||
|
FIR_init();
|
||||||
|
/// Initialize the A/D converter
|
||||||
|
adc_init();
|
||||||
|
adc_init_dma();
|
||||||
|
/// Initialize the Timer to generate sampling event for ADC
|
||||||
|
adc_init_tmr();
|
||||||
|
|
||||||
|
modem_preamble_waiting = 0;
|
||||||
|
#ifndef __DEBUG
|
||||||
|
// PENDING
|
||||||
|
InitDACDMA(); // prima di initdac!!
|
||||||
|
initDac(); // Initialize the D/A converter
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ad ogni cambio modulazione
|
||||||
|
|
||||||
|
void modem_set_up(void) {
|
||||||
|
/// imposta dimensione alfabeto
|
||||||
|
mod.alphabet_size = (1 << mod.bits_per_symbol);
|
||||||
|
/// calcola numero di buffer per simbolo
|
||||||
|
mod.buffers_per_symbol = BUFFER_RATE / mod.symbol_rate;
|
||||||
|
|
||||||
|
/// setup modulatore
|
||||||
|
modulator_setup();
|
||||||
|
|
||||||
|
/// setup demodulatore
|
||||||
|
demodulator_setup();
|
||||||
|
|
||||||
|
modem_set_up_predelay();
|
||||||
|
|
||||||
|
// va a valle del popolamento della costellazione di detect
|
||||||
|
modem_set_up_preamble();
|
||||||
|
}
|
||||||
|
|
||||||
|
// loopback per test
|
||||||
|
|
||||||
|
void DAC_ADC_loopback(void){
|
||||||
|
#ifdef __DSP_LIB__
|
||||||
|
/// Travaso DAC-> ADC per test
|
||||||
|
VectorCopy(SAMPLES_PER_BUFFER, ADCBuffer[dac_buffer_toggle], Q_DACBuffer[dac_buffer_toggle]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_process_sample_buffer(fractional *buffer) {
|
||||||
|
static detector_symbol detector_modulation_averages;
|
||||||
|
|
||||||
|
// demodula un buffer di campioni e torna le medie di freq, ph e amp
|
||||||
|
demodulator_sample_buffer_demodulate(buffer, &detector_modulation_averages);
|
||||||
|
|
||||||
|
// spia OverLoad
|
||||||
|
#ifdef USE_GPIO
|
||||||
|
if ((gpio_mode == GPIO_INFO) && (detector_modulation_averages.amplitude > ADC_MAX_AMPLITUDE)) GPIO_ADC_OL = 1;
|
||||||
|
else {
|
||||||
|
GPIO_ADC_OL = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ! defined(__DEBUG)
|
||||||
|
// viene riasserito dall'interrupt DMA2, meglio azzerare presto per non perdere eventi
|
||||||
|
process_input_sample_buffer = 0; // TEST quando in debug ci pensa chi ?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__DEBUG) && ! defined(__MPLAB_DEBUGGER_PK3)
|
||||||
|
// stampa frequenza vista dal demodulatore
|
||||||
|
debug_value2 = detector_modulation_averages.frequency;
|
||||||
|
#endif
|
||||||
|
// aspetta un preambolo
|
||||||
|
if (modem_preamble_waiting) {
|
||||||
|
if (modem_detect_preamble(detector_modulation_averages.frequency)) {
|
||||||
|
// preambolo trovato
|
||||||
|
modem_preamble_waiting = 0;
|
||||||
|
modem_post_preamble_timer = modem_post_preamble_delay;
|
||||||
|
#ifdef USE_GPIO
|
||||||
|
if (gpio_mode == GPIO_INFO) GPIO_PHY_PAYLOAD = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else if (modem_post_preamble_timer > 0) {
|
||||||
|
modem_post_preamble_timer--; // aspetta
|
||||||
|
} else {
|
||||||
|
// comincia a ricevere i dati
|
||||||
|
// aspetta header o dati
|
||||||
|
if (rx_sample_buffer_index < mod.buffers_per_symbol) {
|
||||||
|
// confronta le medie con la costellazione e torna il simbolo piu vicino
|
||||||
|
rx_sample_buffers_buffer[rx_sample_buffer_index] = demodulator_find_nearest_symbol(&detector_modulation_averages, detector_constellation, &symbol_error);
|
||||||
|
|
||||||
|
#ifdef USE_GPIO
|
||||||
|
// qualita' TODO
|
||||||
|
GPIO_SYM_OK = 0;
|
||||||
|
if (symbol_error.frequency < (min_symbol_distance.frequency / 4)) GPIO_SYM_OK = 1;
|
||||||
|
else {
|
||||||
|
GPIO_SYM_OK = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// sarebbe preferibile avere uno storico dei valori, invece che dei simboli, ma sarebbe MAX_BUFFERS_PER_SYMBOL * detector_symbol
|
||||||
|
// anche accumulare una media sembra critico
|
||||||
|
}
|
||||||
|
rx_sample_buffer_index++;
|
||||||
|
|
||||||
|
#if defined(__DEBUG) && ! defined(__MPLAB_DEBUGGER_PK3)
|
||||||
|
// value3 = rx_sample_buffer_index;
|
||||||
|
debug_value3 = symbol_error.frequency;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// numero di buffer per simbolo raggiunto
|
||||||
|
if (rx_sample_buffer_index >= mod.buffers_per_symbol) {
|
||||||
|
// valore piu ricorrente
|
||||||
|
rx_symbol_buffer[rx_symbol_buffer_index] = demodulator_most_frequent_value(&rx_sample_buffers_buffer[rx_symbol_detected_part_offset], mod.alphabet_size, rx_symbol_detected_part_length);
|
||||||
|
|
||||||
|
// deviazione TODO
|
||||||
|
// find_symbol_deviation(&rx_sample_buffers_buffer[rx_symbol_detected_part_offset], rx_symbol_buffer[rx_symbol_buffer_index], rx_symbol_detected_part_length);
|
||||||
|
|
||||||
|
// simbolo fatto, avanza al successivo
|
||||||
|
rx_symbol_buffer_index++;
|
||||||
|
rx_sample_buffer_index = 0;
|
||||||
|
// stava qua
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_set_up_predelay(void) {
|
||||||
|
silence = (rotor_symbol){0, 0, 0};
|
||||||
|
modem_predelay_buffer_size = (modem_predelay_mstime * BUFFER_RATE) / 1000;
|
||||||
|
}
|
||||||
43
modem.h
Normal file
43
modem.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/** @file
|
||||||
|
* @brief armando, strato modem
|
||||||
|
*
|
||||||
|
* Lo strato modem e' diviso nella sezione modulator (tx) e demodulator (rx) e scambia dati:
|
||||||
|
* - in basso con adc/dac/gpio
|
||||||
|
* in rx con ADCBuffer
|
||||||
|
* in tx con DACBuffer
|
||||||
|
* - in alto con lo strato phy:
|
||||||
|
* in rx con rx_symbol_buffer e rx_symbol_buffer_index
|
||||||
|
* in tx con tx_symbol_buffer e tx_symbol_buffer_index
|
||||||
|
*
|
||||||
|
* La configurazione dello strato e' definita dalla struttura modulation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MODEM_H
|
||||||
|
#define MODEM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <dsp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "modem_types.h"
|
||||||
|
|
||||||
|
#include "modulator.h"
|
||||||
|
#include "demodulator.h"
|
||||||
|
#include "preamble.h"
|
||||||
|
|
||||||
|
// protoz
|
||||||
|
void modem_set_up(void);
|
||||||
|
void modem_init(void);
|
||||||
|
|
||||||
|
void DAC_ADC_loopback(void);
|
||||||
|
|
||||||
|
// todo
|
||||||
|
int pll_frequency_servo(fractional frequency_error);
|
||||||
|
|
||||||
|
void modem_process_sample_buffer(fractional *buffer);
|
||||||
|
|
||||||
|
void modem_set_up_predelay(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
73
modem_types.h
Normal file
73
modem_types.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* File: modem_types.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file */
|
||||||
|
|
||||||
|
#ifndef MODEM_TYPES_H
|
||||||
|
#define MODEM_TYPES_H
|
||||||
|
|
||||||
|
// Sampling Control
|
||||||
|
// il buffer rate deve essere > fmod_min/2
|
||||||
|
// il buffer rate deve > symbol rate
|
||||||
|
|
||||||
|
#define SAMPLING_RATE 16000UL ///< frequenza di campionamento
|
||||||
|
#define SAMPLES_PER_BUFFER 32U ///< dimensione del buffer dei campioni
|
||||||
|
#define BUFFER_RATE (SAMPLING_RATE / SAMPLES_PER_BUFFER) ///< frequenza di buffer: deve essere > di MAX_SYMBOL_RATE * 3
|
||||||
|
|
||||||
|
#define MAX_SYMBOL_RATE 500U
|
||||||
|
#define MIN_SYMBOL_RATE 20U //umm, se troppo piccolo da problemi nelle dimensioni dei buffer
|
||||||
|
|
||||||
|
#define MIN_BUFFERS_PER_SYMBOL (BUFFER_RATE / MAX_SYMBOL_RATE)
|
||||||
|
#define MAX_BUFFERS_PER_SYMBOL (BUFFER_RATE / MIN_SYMBOL_RATE)
|
||||||
|
|
||||||
|
#define MAX_MODULATION_ALPHABET_SIZE 16U ///< massimo numero di simboli nella costellazione
|
||||||
|
|
||||||
|
#define MAX_SYMBOL_BUFFER_SIZE 512U ///< MAX_FEC_OUTPUT_SIZE * MAX_FEC_PER_BLOCK
|
||||||
|
|
||||||
|
#define MODEM_STATE_PREDELAY_WAIT 0
|
||||||
|
#define MODEM_STATE_PREDELAY_PROCESS 1
|
||||||
|
#define MODEM_STATE_PREDELAY_DONE 2
|
||||||
|
#define MODEM_STATE_PREAMBLE_WAIT 3
|
||||||
|
#define MODEM_STATE_PREAMBLE_PROCESS 4
|
||||||
|
#define MODEM_STATE_PREAMBLE_DONE 5
|
||||||
|
#define MODEM_STATE_POST_PREAMBLE_WAIT 6
|
||||||
|
#define MODEM_STATE_POST_PREAMBLE_PROCESS 7
|
||||||
|
#define MODEM_STATE_POST_PREAMBLE_DONE 8
|
||||||
|
#define MODEM_STATE_PAYLOAD_WAIT 9
|
||||||
|
#define MODEM_STATE_PAYLOAD_PROCESS 10
|
||||||
|
#define MODEM_STATE_PAYLOAD_DONE 11
|
||||||
|
#define MODEM_STATE_IDLE 12
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t frequency; ///< frequenza del simbolo
|
||||||
|
uint16_t phase; ///< fase del simbolo
|
||||||
|
uint16_t amplitude; ///< ampiezza del simbolo
|
||||||
|
} symbol;
|
||||||
|
|
||||||
|
// parametri della modulazione
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t symbol_rate; ///< numero di simboli per secondo
|
||||||
|
uint8_t buffers_per_symbol; ///< numero di buffer di campioni in un simbolo
|
||||||
|
uint8_t bits_per_symbol; ///< bit di informazione espressi da un simbolo
|
||||||
|
uint8_t alphabet_size; ///< numero di possibili simboli che compongono la modulazione
|
||||||
|
uint8_t amplitude_keying; ///< manipolazione di ampiezza
|
||||||
|
uint8_t frequency_keying; ///< manipolazione di frequenza
|
||||||
|
uint8_t phase_keying; ///< manipolazione di fase
|
||||||
|
symbol constellation[MAX_MODULATION_ALPHABET_SIZE]; ///< descrizione della costellazione
|
||||||
|
} modulation;
|
||||||
|
|
||||||
|
extern modulation mod;
|
||||||
|
|
||||||
|
extern uint8_t modem_tx_state, modem_rx_state;
|
||||||
|
|
||||||
|
extern uint16_t modem_predelay_mstime, modem_predelay_buffer_size, modem_predelay_buffer_index;
|
||||||
|
|
||||||
|
extern uint8_t modem_avoid_overlap;
|
||||||
|
|
||||||
|
// payload
|
||||||
|
extern uint16_t modem_payload_max_symbols, modem_payload_symbols_index;
|
||||||
|
|
||||||
|
#endif /* MODEM_TYPES_H */
|
||||||
|
|
||||||
70
modulator.c
Normal file
70
modulator.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* armando modem - 2014 */
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <xc.h>
|
||||||
|
#include <dsp.h>
|
||||||
|
#include <libq.h>
|
||||||
|
#elif __unix
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "modem.h"
|
||||||
|
#include "modulator.h"
|
||||||
|
|
||||||
|
#include "../peripheral/dac.h"
|
||||||
|
#include "../peripheral/gpio.h"
|
||||||
|
|
||||||
|
rotor_symbol rotor_constellation[MAX_MODULATION_ALPHABET_SIZE];
|
||||||
|
rotor_symbol silence;
|
||||||
|
|
||||||
|
// buffer dei simboli
|
||||||
|
uint8_t tx_symbol_buffer[MAX_SYMBOL_BUFFER_SIZE];
|
||||||
|
uint8_t tx_symbol_buffer_index, tx_symbol_buffer_lenght;
|
||||||
|
|
||||||
|
void modulator_setup(void) {
|
||||||
|
// TX
|
||||||
|
#ifdef USE_GPIO
|
||||||
|
set_tx_GPIOs();
|
||||||
|
#endif
|
||||||
|
modulator_prepare_constellation_symbols(mod.constellation, rotor_constellation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #####################################################
|
||||||
|
|
||||||
|
// genera un buffer di campioni
|
||||||
|
|
||||||
|
void modulator_generate_sample_buffer(fractional *Q_buffer, fractional *I_buffer, uint8_t size, rotor_symbol symbol) {
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
static fractional modulator_rotor, modulator_rotor_position;
|
||||||
|
i = 0;
|
||||||
|
while (i < size) {
|
||||||
|
modulator_rotor_position = modulator_rotor + symbol.offset;
|
||||||
|
Q_buffer[i] = __builtin_mulss(_Q15sinPI(modulator_rotor_position), // non deve saturare
|
||||||
|
symbol.gain) >> 15;
|
||||||
|
|
||||||
|
I_buffer[i] = __builtin_mulss(_Q15cosPI(modulator_rotor_position), // non deve saturare
|
||||||
|
symbol.gain) >> 15;
|
||||||
|
|
||||||
|
modulator_rotor += symbol.increment; // la _Q15 satura!
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ! defined(__DEBUG)
|
||||||
|
// viene riasserito dal DMA del dac, dove mettere?
|
||||||
|
populate_tx_sample_buffer = 0; // fatto
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// traduce da modulazione astratta a parametri per il modulatore
|
||||||
|
|
||||||
|
void modulator_prepare_constellation_symbols(symbol *constellation, rotor_symbol *mod_constellation) {
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < mod.alphabet_size; i++) {
|
||||||
|
mod_constellation[i].increment = get_angular_frequency(constellation[i].frequency);
|
||||||
|
mod_constellation[i].offset = constellation[i].phase;
|
||||||
|
mod_constellation[i].gain = constellation[i].amplitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
modulator.h
Normal file
38
modulator.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* File: modulator.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MODULATOR_H
|
||||||
|
#define MODULATOR_H
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <dsp.h>
|
||||||
|
#else
|
||||||
|
typedef int16_t fractional;
|
||||||
|
#define _Q15 _Q15sinPI(_Q15);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "modem.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fractional increment;
|
||||||
|
fractional offset;
|
||||||
|
fractional gain;
|
||||||
|
} rotor_symbol;
|
||||||
|
|
||||||
|
extern rotor_symbol rotor_constellation[MAX_MODULATION_ALPHABET_SIZE];
|
||||||
|
extern rotor_symbol silence;
|
||||||
|
|
||||||
|
// buffer dei simboli
|
||||||
|
extern uint8_t tx_symbol_buffer[MAX_SYMBOL_BUFFER_SIZE];
|
||||||
|
extern uint8_t tx_symbol_buffer_index, tx_symbol_buffer_lenght;
|
||||||
|
|
||||||
|
// protoz
|
||||||
|
void modulator_setup(void);
|
||||||
|
void modulator_generate_sample_buffer(fractional *Q_buffer, fractional *I_buffer, uint8_t size, rotor_symbol symbol);
|
||||||
|
void modulator_prepare_constellation_symbols(symbol *constellation, rotor_symbol *mod_constellation);
|
||||||
|
void set_GPIO_bit(uint8_t symbol);
|
||||||
|
|
||||||
|
#endif /* MODULATOR_H */
|
||||||
|
|
||||||
64
ph_det_lp.s
Normal file
64
ph_det_lp.s
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
.equ ph_det_lpNumTaps, 63
|
||||||
|
|
||||||
|
|
||||||
|
.section .xdata
|
||||||
|
.align 128
|
||||||
|
|
||||||
|
ph_det_lpTaps:
|
||||||
|
.hword 0xFFB5, 0xFFD2, 0xFFF3, 0x0014, 0x0039, 0x0060, 0x0089, 0x00B3, 0x00DF
|
||||||
|
.hword 0x010C, 0x013A, 0x0169, 0x0198, 0x01C7, 0x01F6, 0x0224, 0x0251, 0x027D
|
||||||
|
.hword 0x02A7, 0x02D0, 0x02F7, 0x031B, 0x033C, 0x035B, 0x0377, 0x038F, 0x03A4
|
||||||
|
.hword 0x03B6, 0x03C3, 0x03CD, 0x03D3, 0x03D5, 0x03D3, 0x03CD, 0x03C3, 0x03B6
|
||||||
|
.hword 0x03A4, 0x038F, 0x0377, 0x035B, 0x033C, 0x031B, 0x02F7, 0x02D0, 0x02A7
|
||||||
|
.hword 0x027D, 0x0251, 0x0224, 0x01F6, 0x01C7, 0x0198, 0x0169, 0x013A, 0x010C
|
||||||
|
.hword 0x00DF, 0x00B3, 0x0089, 0x0060, 0x0039, 0x0014, 0xFFF3, 0xFFD2, 0xFFB5
|
||||||
|
|
||||||
|
.section .ybss, "b"
|
||||||
|
.align 128
|
||||||
|
|
||||||
|
ph_det_lpDelayI:
|
||||||
|
.space ph_det_lpNumTaps*2
|
||||||
|
|
||||||
|
ph_det_lpDelayQ:
|
||||||
|
.space ph_det_lpNumTaps*2
|
||||||
|
|
||||||
|
ph_det_lpDelayFreq:
|
||||||
|
.space ph_det_lpNumTaps*2
|
||||||
|
|
||||||
|
.section .data
|
||||||
|
.global _ph_det_lpFilterI
|
||||||
|
|
||||||
|
_ph_det_lpFilterI:
|
||||||
|
.hword ph_det_lpNumTaps
|
||||||
|
.hword ph_det_lpTaps
|
||||||
|
.hword ph_det_lpTaps+ph_det_lpNumTaps*2-1
|
||||||
|
.hword 0xff00
|
||||||
|
.hword ph_det_lpDelayI
|
||||||
|
.hword ph_det_lpDelayI+ph_det_lpNumTaps*2-1
|
||||||
|
.hword ph_det_lpDelayI
|
||||||
|
|
||||||
|
|
||||||
|
.section .data
|
||||||
|
.global _ph_det_lpFilterQ
|
||||||
|
|
||||||
|
_ph_det_lpFilterQ:
|
||||||
|
.hword ph_det_lpNumTaps
|
||||||
|
.hword ph_det_lpTaps
|
||||||
|
.hword ph_det_lpTaps+ph_det_lpNumTaps*2-1
|
||||||
|
.hword 0xff00
|
||||||
|
.hword ph_det_lpDelayQ
|
||||||
|
.hword ph_det_lpDelayQ+ph_det_lpNumTaps*2-1
|
||||||
|
.hword ph_det_lpDelayQ
|
||||||
|
|
||||||
|
.section .data
|
||||||
|
.global _ph_det_lpFilterFreq
|
||||||
|
|
||||||
|
_ph_det_lpFilterFreq:
|
||||||
|
.hword ph_det_lpNumTaps
|
||||||
|
.hword ph_det_lpTaps
|
||||||
|
.hword ph_det_lpTaps+ph_det_lpNumTaps*2-1
|
||||||
|
.hword 0xff00
|
||||||
|
.hword ph_det_lpDelayFreq
|
||||||
|
.hword ph_det_lpDelayFreq+ph_det_lpNumTaps*2-1
|
||||||
|
.hword ph_det_lpDelayFreq
|
||||||
|
|
||||||
20
pll.c
Normal file
20
pll.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <libq.h>
|
||||||
|
#include <dsp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "demodulator.h"
|
||||||
|
|
||||||
|
int pll_frequency_servo(fractional frequency_error) {
|
||||||
|
fractional frequency_servo_feedback;
|
||||||
|
|
||||||
|
if (_Q15abs(frequency_error) < 1) frequency_servo_feedback = frequency_error;
|
||||||
|
else {
|
||||||
|
frequency_servo_feedback = _Q15shr(frequency_error, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
return frequency_servo_feedback;
|
||||||
|
}
|
||||||
|
|
||||||
135
preamble.c
Normal file
135
preamble.c
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// debug
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <xc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <libq.h>
|
||||||
|
#include <dsp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../ringbuf.h"
|
||||||
|
#include "modem_types.h"
|
||||||
|
|
||||||
|
#include "preamble.h"
|
||||||
|
|
||||||
|
#include "../peripheral/gpio.h" //debug
|
||||||
|
#include "../mini-printf.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__DEBUG) && ! defined(__MPLAB_DEBUGGER_PK3)
|
||||||
|
#include "../peripheral/uarts.h"
|
||||||
|
extern fractional debug_value3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// preambolo
|
||||||
|
uint8_t modem_preamble_waiting, modem_post_preamble_delay, modem_post_preamble_timer;
|
||||||
|
// uint8_t modem_preamble_pending, modem_preamble_done;
|
||||||
|
uint16_t BuffersPerPreamble;
|
||||||
|
|
||||||
|
fractional sync_values_sequence[(MODEM_PREAMBLE_LENGTH * MAX_BUFFERS_PER_SYMBOL)];
|
||||||
|
_Q15_16 preamble_squelch_distance;
|
||||||
|
|
||||||
|
void modem_set_up_preamble(void) {
|
||||||
|
uint8_t sync_symbols[MODEM_PREAMBLE_LENGTH];
|
||||||
|
modem_generate_preamble(sync_symbols);
|
||||||
|
modem_generate_preamble_fingerprint(sync_symbols, sync_values_sequence, mod.buffers_per_symbol);
|
||||||
|
BuffersPerPreamble = MODEM_PREAMBLE_LENGTH * mod.buffers_per_symbol;
|
||||||
|
|
||||||
|
preamble_squelch_distance = _Q16mpy(modem_get_preamble_max_correlation_index(sync_symbols), _Q16ftoi(MODEM_PREAMBLE_SQUELCH));
|
||||||
|
|
||||||
|
modem_post_preamble_delay = BUFFER_RATE / mod.symbol_rate; // un simbolo
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t modem_generate_preamble(uint8_t *ModulationSymbolsBuffer) {
|
||||||
|
uint8_t i;
|
||||||
|
// barker code con N=13
|
||||||
|
uint8_t sync_sequence[13] = {1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1};
|
||||||
|
|
||||||
|
for (i = 0; i < MODEM_PREAMBLE_LENGTH; i++) {
|
||||||
|
if (sync_sequence[i]) {
|
||||||
|
ModulationSymbolsBuffer[i] = (mod.alphabet_size - 1);
|
||||||
|
} else {
|
||||||
|
ModulationSymbolsBuffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MODEM_PREAMBLE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trasforma la sequenza di simboli nella sua rappresentazione in sottosimboli
|
||||||
|
|
||||||
|
void modem_generate_preamble_fingerprint(uint8_t *ModulationSymbolsBuffer, fractional *symbols_values_sequence, uint8_t values_per_symbol) {
|
||||||
|
uint8_t i, l, m = 0;
|
||||||
|
for (i = 0; i < MODEM_PREAMBLE_LENGTH; i++) {
|
||||||
|
for (l = 0; l < values_per_symbol; l++) {
|
||||||
|
symbols_values_sequence[m] = detector_constellation[ModulationSymbolsBuffer[i]].frequency;
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trova indice di correlazione massimo per la data modulationz
|
||||||
|
|
||||||
|
_Q15_16 modem_get_preamble_max_correlation_index(uint8_t *ModulationSymbolsBuffer) {
|
||||||
|
uint8_t i;
|
||||||
|
_Q15_16 symbol_mass = 0;
|
||||||
|
_Q15_16 mass = 0;
|
||||||
|
for (i = 0; i < MODEM_PREAMBLE_LENGTH; i++) {
|
||||||
|
symbol_mass = __builtin_mulss(
|
||||||
|
detector_constellation[ModulationSymbolsBuffer[i]].frequency,
|
||||||
|
detector_constellation[ModulationSymbolsBuffer[i]].frequency);
|
||||||
|
mass += symbol_mass;
|
||||||
|
}
|
||||||
|
return mass * mod.buffers_per_symbol;
|
||||||
|
}
|
||||||
|
/// riconosce preambolo
|
||||||
|
|
||||||
|
uint8_t modem_detect_preamble(fractional insymbol) {
|
||||||
|
static _Q15_16 somigl_hist;
|
||||||
|
static fractional in_sym_ringbuf[MODEM_PREAMBLE_SEARCH_BUFF_SIZE];
|
||||||
|
static uint16_t in_sym_ringbuf_index;
|
||||||
|
|
||||||
|
uint8_t found = 0;
|
||||||
|
uint16_t i;
|
||||||
|
_Q15_16 distance_accu = 0;
|
||||||
|
|
||||||
|
// mette nel ringbuffer
|
||||||
|
in_sym_ringbuf[in_sym_ringbuf_index] = insymbol;
|
||||||
|
|
||||||
|
// correla
|
||||||
|
for (i = 0; i < BuffersPerPreamble; i++) {
|
||||||
|
// product
|
||||||
|
|
||||||
|
distance_accu += __builtin_mulss(
|
||||||
|
in_sym_ringbuf[ringbuf_idx_from_end(&in_sym_ringbuf_index, MODEM_PREAMBLE_SEARCH_BUFF_SIZE_MASK, (BuffersPerPreamble - i))],
|
||||||
|
sync_values_sequence[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__DEBUG) && ! defined(__MPLAB_DEBUGGER_PK3)
|
||||||
|
debug_value3 = _Q16shr(distance_accu, 16);
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
if (distance_accu > preamble_squelch_distance) LATBbits.LATB3 = 1;
|
||||||
|
else {
|
||||||
|
LATBbits.LATB3 = 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if ((distance_accu > preamble_squelch_distance) && (somigl_hist > distance_accu)) {
|
||||||
|
// trovato !
|
||||||
|
|
||||||
|
//resetta il riconoscimento di preambolo
|
||||||
|
somigl_hist = 0;
|
||||||
|
memset(in_sym_ringbuf, 0, MODEM_PREAMBLE_SEARCH_BUFF_SIZE * sizeof (in_sym_ringbuf));
|
||||||
|
in_sym_ringbuf_index = 0;
|
||||||
|
|
||||||
|
found = 1;
|
||||||
|
} else {
|
||||||
|
somigl_hist = distance_accu;
|
||||||
|
ringbuf_increment(&in_sym_ringbuf_index, MODEM_PREAMBLE_SEARCH_BUFF_SIZE_MASK);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
53
preamble.h
Normal file
53
preamble.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* File: preamble.h
|
||||||
|
* Author: nzasch
|
||||||
|
*
|
||||||
|
* Created on 12 gennaio 2017, 15.05
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PREAMBLE_H
|
||||||
|
#define PREAMBLE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __XC16
|
||||||
|
#include <libq.h>
|
||||||
|
#include <dsp.h>
|
||||||
|
#else
|
||||||
|
typedef int16_t _Q0_15;
|
||||||
|
typedef int32_t _Q15_16;
|
||||||
|
|
||||||
|
typedef _Q0_15 _Q15;
|
||||||
|
typedef _Q15_16 _Q16;
|
||||||
|
|
||||||
|
typedef int16_t fractional;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "modem_types.h"
|
||||||
|
#include "demodulator.h"
|
||||||
|
|
||||||
|
#define MODEM_PREAMBLE_LENGTH 13U
|
||||||
|
#define MODEM_PREAMBLE_SQUELCH 0.7f // da 0 a 1
|
||||||
|
|
||||||
|
// ((16000 ? 32) ? 20) ? 13 = 325
|
||||||
|
#define MODEM_PREAMBLE_SEARCH_BUFF_SIZE 512U // circa (MODEM_PREAMBLE_LENGTH * MAX_BUFFERS_PER_SYMBOL) ma deve esere ^ di 2
|
||||||
|
#define MODEM_PREAMBLE_SEARCH_BUFF_SIZE_MASK (MODEM_PREAMBLE_SEARCH_BUFF_SIZE - 1)
|
||||||
|
|
||||||
|
extern fractional sync_values_sequence[MODEM_PREAMBLE_LENGTH * MAX_BUFFERS_PER_SYMBOL]; ///< buffer che contiene il modello di sequenza
|
||||||
|
extern _Q15_16 preamble_squelch_distance; ///< squelch pesato sulla lunghezza del preambolo
|
||||||
|
|
||||||
|
// extern uint8_t modem_preamble_pending, modem_preamble_done;
|
||||||
|
extern uint8_t modem_preamble_waiting, modem_post_preamble_delay, modem_post_preamble_timer;
|
||||||
|
extern uint16_t BuffersPerPreamble;
|
||||||
|
|
||||||
|
// protoz
|
||||||
|
void modem_set_up_preamble(void);
|
||||||
|
|
||||||
|
uint8_t modem_generate_preamble(uint8_t *ModulationSymbolsBuffer);
|
||||||
|
void modem_generate_preamble_fingerprint(uint8_t *ModulationSymbolsBuffer, fractional *symbols_values_sequence, uint8_t values_per_symbol);
|
||||||
|
|
||||||
|
_Q15_16 modem_get_preamble_max_correlation_index(uint8_t *ModulationSymbolsBuffer);
|
||||||
|
uint8_t modem_detect_preamble(fractional insymbol);
|
||||||
|
|
||||||
|
#endif /* PREAMBLE_H */
|
||||||
|
|
||||||
Reference in New Issue
Block a user