first commit
This commit is contained in:
+595
@@ -0,0 +1,595 @@
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#include <assert.h>
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "audio_agc.h"
|
||||
#include "audio_driver.h" // ADC_CLIP_WARN_THRESHOLD
|
||||
#include "uhsdr_math.h"
|
||||
|
||||
#define AGC_WDSP_RB_SIZE ((AUDIO_SAMPLE_RATE/1000)*4) // max buffer size based on max sample rate to be supported
|
||||
// this translates to 192 at 48k SPS. We have FM using the AGC at full sampling speed
|
||||
|
||||
|
||||
agc_wdsp_params_t agc_wdsp_conf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// AGC
|
||||
//#define MAX_SAMPLE_RATE (24000.0)
|
||||
//#define MAX_N_TAU (8)
|
||||
//#define MAX_TAU_ATTACK (0.01)
|
||||
//#define RB_SIZE (int) (MAX_SAMPLE_RATE * MAX_N_TAU * MAX_TAU_ATTACK + 1)
|
||||
//int8_t AGC_mode = 2;
|
||||
int pmode;// = 1; // if 0, calculate magnitude by max(|I|, |Q|), if 1, calculate sqrtf(I*I+Q*Q)
|
||||
float32_t out_sample[2];
|
||||
float32_t abs_out_sample;
|
||||
float32_t tau_attack;
|
||||
float32_t tau_decay;
|
||||
int n_tau;
|
||||
float32_t max_gain;
|
||||
float32_t var_gain;
|
||||
float32_t fixed_gain; // = 1.0;
|
||||
float32_t max_input;
|
||||
float32_t out_targ;
|
||||
float32_t tau_fast_backaverage;
|
||||
float32_t tau_fast_decay;
|
||||
float32_t pop_ratio;
|
||||
//uint8_t hang_enable;
|
||||
float32_t tau_hang_backmult;
|
||||
float32_t hangtime;
|
||||
float32_t hang_thresh;
|
||||
float32_t tau_hang_decay;
|
||||
float32_t ring[2 * AGC_WDSP_RB_SIZE]; //192]; //96];
|
||||
float32_t abs_ring[AGC_WDSP_RB_SIZE];// 192 //96]; // abs_ring is half the size of ring
|
||||
//assign constants
|
||||
int ring_buffsize; // = 96;
|
||||
//do one-time initialization
|
||||
int out_index; // = -1;
|
||||
float32_t ring_max; // = 0.0;
|
||||
float32_t volts; // = 0.0;
|
||||
float32_t save_volts; // = 0.0;
|
||||
float32_t fast_backaverage; // = 0.0;
|
||||
float32_t hang_backaverage; // = 0.0;
|
||||
int hang_counter; // = 0;
|
||||
uint8_t decay_type; // = 0;
|
||||
uint8_t state; // = 0;
|
||||
int attack_buffsize;
|
||||
uint32_t in_index;
|
||||
float32_t attack_mult;
|
||||
float32_t decay_mult;
|
||||
float32_t fast_decay_mult;
|
||||
float32_t fast_backmult;
|
||||
float32_t onemfast_backmult;
|
||||
float32_t out_target;
|
||||
float32_t min_volts;
|
||||
float32_t inv_out_target;
|
||||
float32_t tmp;
|
||||
float32_t slope_constant;
|
||||
float32_t inv_max_input;
|
||||
float32_t hang_level;
|
||||
float32_t hang_backmult;
|
||||
float32_t onemhang_backmult;
|
||||
float32_t hang_decay_mult;
|
||||
bool remove_dc;
|
||||
float32_t sample_rate;
|
||||
bool initialised;
|
||||
} agc_variables_t;
|
||||
|
||||
agc_variables_t agc_wdsp;
|
||||
|
||||
/**
|
||||
* Sets the basic initial values for the WDSP AGC
|
||||
* Call only once at startup!
|
||||
*/
|
||||
void AudioAgc_AgcWdsp_Init()
|
||||
{
|
||||
// the values below are all loaded from
|
||||
// EEPROM, which happens BEFORE we get here
|
||||
// so there is no point in setting these.
|
||||
// agc_wdsp_conf.mode = 2;
|
||||
// agc_wdsp_conf.slope = 70;
|
||||
// agc_wdsp_conf.hang_enable = 0;
|
||||
// agc_wdsp_conf.tau_decay[0] = 4000;
|
||||
// agc_wdsp_conf.tau_decay[1] = 2000;
|
||||
// agc_wdsp_conf.tau_decay[2] = 500;
|
||||
// agc_wdsp_conf.tau_decay[3] = 250;
|
||||
// agc_wdsp_conf.tau_decay[4] = 50;
|
||||
// agc_wdsp_conf.thresh = 20;
|
||||
// agc_wdsp_conf.tau_hang_decay = 500;
|
||||
|
||||
// these are not stored in volatile memory
|
||||
// so let us initialize them here.
|
||||
agc_wdsp_conf.hang_time = 500;
|
||||
agc_wdsp_conf.hang_thresh = 45;
|
||||
agc_wdsp_conf.action = 0;
|
||||
agc_wdsp_conf.switch_mode = 1;
|
||||
agc_wdsp_conf.hang_action = 0;
|
||||
agc_wdsp_conf.tau_decay[5] = 1; // this is the OFF-Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the AGC data structures, has to be called when switching modes, filter changes
|
||||
*
|
||||
* @param sample_rate audio sample rate
|
||||
* @param remove_dc Should be set for AM demodulation (AM,SAM,DSB) If set to true, remove DC in output
|
||||
*/
|
||||
void AudioAgc_SetupAgcWdsp(float32_t sample_rate, bool remove_dc)
|
||||
{
|
||||
// this is a quick and dirty hack
|
||||
// it initialises the AGC variables once again,
|
||||
// if the decimation rate is changed
|
||||
// this should prevent confusion between the distance of in_index and out_index variables
|
||||
// because these are freshly initialised
|
||||
// in_index and out_index have a distance of 48 (sample rate 12000) or 96 (sample rate 24000)
|
||||
// so that has to be defined very well when filter from 4k8 to 5k0 (changing decimation rate from 4 to 2)
|
||||
|
||||
agc_wdsp.remove_dc = remove_dc;
|
||||
|
||||
if(agc_wdsp.sample_rate != sample_rate)
|
||||
{
|
||||
agc_wdsp.initialised = false; // force initialisation
|
||||
agc_wdsp.sample_rate = sample_rate; // remember decimation rate for next time
|
||||
}
|
||||
// Start variables taken from wdsp
|
||||
// RXA.c !!!!
|
||||
/*
|
||||
0.001, // tau_attack
|
||||
0.250, // tau_decay
|
||||
4, // n_tau
|
||||
10000.0, // max_gain
|
||||
1.5, // var_gain
|
||||
1000.0, // fixed_gain
|
||||
1.0, // max_input
|
||||
1.0, // out_target
|
||||
0.250, // tau_fast_backaverage
|
||||
0.005, // tau_fast_decay
|
||||
5.0, // pop_ratio
|
||||
1, // hang_enable
|
||||
0.500, // tau_hang_backmult
|
||||
0.250, // hangtime
|
||||
0.250, // hang_thresh
|
||||
0.100); // tau_hang_decay
|
||||
*/
|
||||
// one time initialization
|
||||
if(!agc_wdsp.initialised)
|
||||
{
|
||||
|
||||
/*
|
||||
*
|
||||
* //assign constants
|
||||
a->ring_buffsize = RB_SIZE;
|
||||
//do one-time initialization
|
||||
a->out_index = -1;
|
||||
a->ring_max = 0.0;
|
||||
a->volts = 0.0;
|
||||
a->save_volts = 0.0;
|
||||
a->fast_backaverage = 0.0;
|
||||
a->hang_backaverage = 0.0;
|
||||
a->hang_counter = 0;
|
||||
a->decay_type = 0;
|
||||
a->state = 0;
|
||||
a->ring = (double *)malloc0(RB_SIZE * sizeof(complex));
|
||||
a->abs_ring = (double *)malloc0(RB_SIZE * sizeof(double));
|
||||
loadWcpAGC(a);
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
agc_wdsp.ring_buffsize = AGC_WDSP_RB_SIZE; //192; //96;
|
||||
//do one-time initialization
|
||||
agc_wdsp.out_index = -1; //agc_wdsp.ring_buffsize; // or -1 ??
|
||||
agc_wdsp.fixed_gain = 1.0;
|
||||
agc_wdsp.ring_max = 0.0;
|
||||
agc_wdsp.volts = 0.0;
|
||||
agc_wdsp.save_volts = 0.0;
|
||||
agc_wdsp.fast_backaverage = 0.0;
|
||||
agc_wdsp.hang_backaverage = 0.0;
|
||||
agc_wdsp.hang_counter = 0;
|
||||
agc_wdsp.decay_type = 0;
|
||||
agc_wdsp.state = 0;
|
||||
for(int idx = 0; idx < AGC_WDSP_RB_SIZE; idx++)
|
||||
{
|
||||
agc_wdsp.ring[idx * 2 + 0] = 0.0;
|
||||
agc_wdsp.ring[idx * 2 + 1] = 0.0;
|
||||
agc_wdsp.abs_ring[idx] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
agc_wdsp.tau_attack = 0.001; // tau_attack
|
||||
// tau_decay = agc_wdsp_conf.tau_decay / 1000.0; // 0.250; // tau_decay
|
||||
agc_wdsp.n_tau = 4; // n_tau
|
||||
|
||||
// max_gain = 1000.0; // 1000.0; determines the AGC threshold = knee level
|
||||
// max_gain is powf (10.0, (float32_t)agc_wdsp_conf.thresh / 20.0);
|
||||
// fixed_gain = ads.agc_rf_gain; //0.7; // if AGC == OFF, this gain is used
|
||||
agc_wdsp.max_input = (float32_t)ADC_CLIP_WARN_THRESHOLD; // which is 4096 at the moment
|
||||
//32767.0; // maximum value of 16-bit audio // 1.0; //
|
||||
agc_wdsp.out_targ = (float32_t)ADC_CLIP_WARN_THRESHOLD; // 4096, tweaked, so that volume when switching between the two AGCs remains equal
|
||||
//12000.0; // target value of audio after AGC
|
||||
agc_wdsp.tau_fast_backaverage = 0.250; // tau_fast_backaverage
|
||||
agc_wdsp.tau_fast_decay = 0.005; // tau_fast_decay
|
||||
agc_wdsp.pop_ratio = 5.0; // pop_ratio
|
||||
// hang_enable = 0; // hang_enable
|
||||
agc_wdsp.tau_hang_backmult = 0.500; // tau_hang_backmult
|
||||
|
||||
agc_wdsp.initialised = true;
|
||||
}
|
||||
// var_gain = 32.0; // slope of the AGC --> this is 10 * 10^(slope / 20) --> for 10dB slope, this is 30.0
|
||||
agc_wdsp.var_gain = pow10f((float32_t)agc_wdsp_conf.slope / 20.0 / 10.0); // 10^(slope / 200)
|
||||
|
||||
// hangtime = 0.250; // hangtime
|
||||
agc_wdsp.hangtime = (float32_t)agc_wdsp_conf.hang_time / 1000.0;
|
||||
|
||||
// hang_thresh = 0.250; // hang_thresh
|
||||
// tau_hang_decay = 0.100; // tau_hang_decay
|
||||
|
||||
//calculate internal parameters
|
||||
if(agc_wdsp_conf.switch_mode)
|
||||
{
|
||||
switch (agc_wdsp_conf.mode)
|
||||
{
|
||||
case 5: //agcOFF
|
||||
break;
|
||||
case 1: //agcLONG
|
||||
agc_wdsp.hangtime = 2.000;
|
||||
// agc_wdsp_conf.tau_decay = 2000;
|
||||
// hang_thresh = 1.0;
|
||||
// agc_wdsp_conf.hang_enable = 1;
|
||||
break;
|
||||
case 2: //agcSLOW
|
||||
agc_wdsp.hangtime = 1.000;
|
||||
// hang_thresh = 1.0;
|
||||
// agc_wdsp_conf.tau_decay = 500;
|
||||
// agc_wdsp_conf.hang_enable = 1;
|
||||
break;
|
||||
case 3: //agcMED
|
||||
// hang_thresh = 1.0;
|
||||
agc_wdsp.hangtime = 0.250;
|
||||
// agc_wdsp_conf.tau_decay = 250;
|
||||
break;
|
||||
case 4: //agcFAST
|
||||
// hang_thresh = 1.0;
|
||||
agc_wdsp.hangtime = 0.100;
|
||||
// agc_wdsp_conf.tau_decay = 50;
|
||||
break;
|
||||
case 0: //agcFrank --> very long
|
||||
// agc_wdsp_conf.hang_enable = 0;
|
||||
// hang_thresh = 0.300; // from which level on should hang be enabled
|
||||
agc_wdsp.hangtime = 3.000; // hang time, if enabled
|
||||
agc_wdsp.tau_hang_backmult = 0.500; // time constant exponential averager
|
||||
// agc_wdsp_conf.tau_decay = 4000; // time constant decay long
|
||||
agc_wdsp.tau_fast_decay = 0.05; // tau_fast_decay
|
||||
agc_wdsp.tau_fast_backaverage = 0.250; // time constant exponential averager
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
agc_wdsp_conf.switch_mode = 0;
|
||||
}
|
||||
// float32_t noise_offset = 10.0 * log10f(fhigh - rxa[channel].nbp0.p->flow)
|
||||
// * size / rate);
|
||||
// max_gain = out_target / var_gain * powf (10.0, (thresh + noise_offset) / 20.0));
|
||||
agc_wdsp.tau_hang_decay = (float32_t)agc_wdsp_conf.tau_hang_decay / 1000.0;
|
||||
agc_wdsp.tau_decay = (float32_t)agc_wdsp_conf.tau_decay[agc_wdsp_conf.mode] / 1000.0;
|
||||
agc_wdsp.max_gain = pow10f ((float32_t)agc_wdsp_conf.thresh / 20.0);
|
||||
agc_wdsp.fixed_gain = agc_wdsp.max_gain / 10.0;
|
||||
// attack_buff_size is 48 for sample rate == 12000 and
|
||||
// 96 for sample rate == 24000
|
||||
// 192 for sample rate == 48000
|
||||
agc_wdsp.attack_buffsize = ceilf(sample_rate * agc_wdsp.n_tau * agc_wdsp.tau_attack);
|
||||
|
||||
agc_wdsp.in_index = agc_wdsp.attack_buffsize + agc_wdsp.out_index; // attack_buffsize + out_index can be more than 2x ring_bufsize !!!
|
||||
agc_wdsp.in_index %= agc_wdsp.ring_buffsize; // need to keep this within the index boundaries
|
||||
|
||||
agc_wdsp.attack_mult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_attack));
|
||||
agc_wdsp.decay_mult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_decay));
|
||||
agc_wdsp.fast_decay_mult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_fast_decay));
|
||||
agc_wdsp.fast_backmult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_fast_backaverage));
|
||||
agc_wdsp.onemfast_backmult = 1.0 - agc_wdsp.fast_backmult;
|
||||
|
||||
agc_wdsp.out_target = agc_wdsp.out_targ * (1.0 - expf(-(float32_t)agc_wdsp.n_tau)) * 0.9999;
|
||||
// out_target = out_target * (1.0 - expf(-(float32_t)n_tau)) * 0.9999;
|
||||
agc_wdsp.min_volts = agc_wdsp.out_target / (agc_wdsp.var_gain * agc_wdsp.max_gain);
|
||||
agc_wdsp.inv_out_target = 1.0 / agc_wdsp.out_target;
|
||||
|
||||
float32_t tmpA = log10f(agc_wdsp.out_target / (agc_wdsp.max_input * agc_wdsp.var_gain * agc_wdsp.max_gain));
|
||||
if (tmpA == 0.0)
|
||||
{
|
||||
tmpA = 1e-16;
|
||||
}
|
||||
agc_wdsp.slope_constant = (agc_wdsp.out_target * (1.0 - 1.0 / agc_wdsp.var_gain)) / tmpA;
|
||||
|
||||
agc_wdsp.inv_max_input = 1.0 / agc_wdsp.max_input;
|
||||
|
||||
if (agc_wdsp.max_input > agc_wdsp.min_volts)
|
||||
{
|
||||
float32_t convert
|
||||
= pow10f ((float32_t)agc_wdsp_conf.hang_thresh / 20.0);
|
||||
float32_t tmpB = (convert - agc_wdsp.min_volts) / (agc_wdsp.max_input - agc_wdsp.min_volts);
|
||||
if(tmpB < 1e-8)
|
||||
{
|
||||
tmpB = 1e-8;
|
||||
}
|
||||
agc_wdsp.hang_thresh = 1.0 + 0.125 * log10f (tmpB);
|
||||
}
|
||||
else
|
||||
{
|
||||
agc_wdsp.hang_thresh = 1.0;
|
||||
}
|
||||
|
||||
float32_t tmpC = pow10f ((agc_wdsp.hang_thresh - 1.0) / 0.125);
|
||||
agc_wdsp.hang_level = (agc_wdsp.max_input * tmpC + (agc_wdsp.out_target /
|
||||
(agc_wdsp.var_gain * agc_wdsp.max_gain)) * (1.0 - tmpC)) * 0.637;
|
||||
|
||||
agc_wdsp.hang_backmult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_hang_backmult));
|
||||
agc_wdsp.onemhang_backmult = 1.0 - agc_wdsp.hang_backmult;
|
||||
|
||||
agc_wdsp.hang_decay_mult = 1.0 - expf(-1.0 / (sample_rate * agc_wdsp.tau_hang_decay));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param blockSize
|
||||
* @param agcbuffer a pointer to the list of buffers of size blockSize containing the audio data
|
||||
* @param num_channels
|
||||
*/
|
||||
void AudioAgc_RunAgcWdsp(int16_t blockSize, float32_t (*agcbuffer)[AUDIO_BLOCK_SIZE], const bool use_stereo )
|
||||
{
|
||||
// Be careful: the original source code has no comments,
|
||||
// all comments added by DD4WH, February 2017: comments could be wrong, misinterpreting or highly misleading!
|
||||
//
|
||||
if (agc_wdsp_conf.mode == 5) // AGC OFF
|
||||
{
|
||||
for (uint16_t i = 0; i < blockSize; i++)
|
||||
{
|
||||
agcbuffer[0][i] = agcbuffer[0][i] * agc_wdsp.fixed_gain;
|
||||
if (use_stereo)
|
||||
{
|
||||
agcbuffer[1][i] = agcbuffer[1][i] * agc_wdsp.fixed_gain;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < blockSize; i++)
|
||||
{
|
||||
if (++agc_wdsp.out_index >= agc_wdsp.ring_buffsize)
|
||||
{
|
||||
agc_wdsp.out_index -= agc_wdsp.ring_buffsize;
|
||||
}
|
||||
if (++agc_wdsp.in_index >= agc_wdsp.ring_buffsize)
|
||||
{
|
||||
agc_wdsp.in_index -= agc_wdsp.ring_buffsize;
|
||||
}
|
||||
|
||||
agc_wdsp.out_sample[0] = agc_wdsp.ring[2 * agc_wdsp.out_index];
|
||||
if(use_stereo)
|
||||
{
|
||||
agc_wdsp.out_sample[1] = agc_wdsp.ring[2 * agc_wdsp.out_index + 1];
|
||||
}
|
||||
agc_wdsp.abs_out_sample = agc_wdsp.abs_ring[agc_wdsp.out_index];
|
||||
agc_wdsp.ring[2 * agc_wdsp.in_index] = agcbuffer[0][i];
|
||||
if(use_stereo)
|
||||
{
|
||||
agc_wdsp.ring[2 * agc_wdsp.in_index + 1] = agcbuffer[1][i];
|
||||
}
|
||||
agc_wdsp.abs_ring[agc_wdsp.in_index] = fabsf(agcbuffer[0][i]);
|
||||
if(use_stereo)
|
||||
{
|
||||
if(agc_wdsp.abs_ring[agc_wdsp.in_index] < fabsf(agcbuffer[1][i]))
|
||||
{
|
||||
agc_wdsp.abs_ring[agc_wdsp.in_index] = fabsf(agcbuffer[1][i]);
|
||||
}
|
||||
}
|
||||
|
||||
agc_wdsp.fast_backaverage = agc_wdsp.fast_backmult * agc_wdsp.abs_out_sample + agc_wdsp.onemfast_backmult * agc_wdsp.fast_backaverage;
|
||||
agc_wdsp.hang_backaverage = agc_wdsp.hang_backmult * agc_wdsp.abs_out_sample + agc_wdsp.onemhang_backmult * agc_wdsp.hang_backaverage;
|
||||
if(agc_wdsp.hang_backaverage > agc_wdsp.hang_level)
|
||||
{
|
||||
agc_wdsp_conf.hang_action = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
agc_wdsp_conf.hang_action = 0;
|
||||
}
|
||||
|
||||
if ((agc_wdsp.abs_out_sample >= agc_wdsp.ring_max) && (agc_wdsp.abs_out_sample > 0.0))
|
||||
{
|
||||
agc_wdsp.ring_max = 0.0;
|
||||
int k = agc_wdsp.out_index;
|
||||
|
||||
for (uint16_t j = 0; j < agc_wdsp.attack_buffsize; j++)
|
||||
{
|
||||
if (++k == agc_wdsp.ring_buffsize)
|
||||
{
|
||||
k = 0;
|
||||
}
|
||||
if (agc_wdsp.abs_ring[k] > agc_wdsp.ring_max)
|
||||
{
|
||||
agc_wdsp.ring_max = agc_wdsp.abs_ring[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (agc_wdsp.abs_ring[agc_wdsp.in_index] > agc_wdsp.ring_max)
|
||||
{
|
||||
agc_wdsp.ring_max = agc_wdsp.abs_ring[agc_wdsp.in_index];
|
||||
}
|
||||
|
||||
if (agc_wdsp.hang_counter > 0)
|
||||
{
|
||||
--agc_wdsp.hang_counter;
|
||||
}
|
||||
|
||||
switch (agc_wdsp.state)
|
||||
{
|
||||
case 0: // starting point after ATTACK
|
||||
{
|
||||
if (agc_wdsp.ring_max >= agc_wdsp.volts)
|
||||
{ // ATTACK
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.attack_mult;
|
||||
}
|
||||
else
|
||||
{ // DECAY
|
||||
if (agc_wdsp.volts > agc_wdsp.pop_ratio * agc_wdsp.fast_backaverage)
|
||||
{ // short time constant detector
|
||||
agc_wdsp.state = 1;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.fast_decay_mult;
|
||||
}
|
||||
else
|
||||
{ // hang AGC enabled and being activated
|
||||
if (agc_wdsp_conf.hang_enable && (agc_wdsp.hang_backaverage > agc_wdsp.hang_level))
|
||||
{
|
||||
agc_wdsp.state = 2;
|
||||
agc_wdsp.hang_counter = (int)(agc_wdsp.hangtime * agc_wdsp.sample_rate);
|
||||
agc_wdsp.decay_type = 1;
|
||||
}
|
||||
else
|
||||
{// long time constant detector
|
||||
agc_wdsp.state = 3;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.decay_mult;
|
||||
agc_wdsp.decay_type = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // short time constant decay
|
||||
{
|
||||
if (agc_wdsp.ring_max >= agc_wdsp.volts)
|
||||
{ // ATTACK
|
||||
agc_wdsp.state = 0;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.attack_mult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (agc_wdsp.volts > agc_wdsp.save_volts)
|
||||
{// short time constant detector
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.fast_decay_mult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (agc_wdsp.hang_counter > 0)
|
||||
{
|
||||
agc_wdsp.state = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (agc_wdsp.decay_type == 0)
|
||||
{// long time constant detector
|
||||
agc_wdsp.state = 3;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.decay_mult;
|
||||
}
|
||||
else
|
||||
{ // hang time constant
|
||||
agc_wdsp.state = 4;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.hang_decay_mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // Hang is enabled and active, hang counter still counting
|
||||
{ // ATTACK
|
||||
if (agc_wdsp.ring_max >= agc_wdsp.volts)
|
||||
{
|
||||
agc_wdsp.state = 0;
|
||||
agc_wdsp.save_volts = agc_wdsp.volts;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.attack_mult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (agc_wdsp.hang_counter == 0)
|
||||
{ // hang time constant
|
||||
agc_wdsp.state = 4;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.hang_decay_mult;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: // long time constant decay in progress
|
||||
{
|
||||
if (agc_wdsp.ring_max >= agc_wdsp.volts)
|
||||
{ // ATTACK
|
||||
agc_wdsp.state = 0;
|
||||
agc_wdsp.save_volts = agc_wdsp.volts;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.attack_mult;
|
||||
}
|
||||
else
|
||||
{ // DECAY
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.decay_mult;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: // hang was enabled and counter has counted to zero --> hang decay
|
||||
{
|
||||
if (agc_wdsp.ring_max >= agc_wdsp.volts)
|
||||
{ // ATTACK
|
||||
agc_wdsp.state = 0;
|
||||
agc_wdsp.save_volts = agc_wdsp.volts;
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.attack_mult;
|
||||
}
|
||||
else
|
||||
{ // HANG DECAY
|
||||
agc_wdsp.volts += (agc_wdsp.ring_max - agc_wdsp.volts) * agc_wdsp.hang_decay_mult;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (agc_wdsp.volts < agc_wdsp.min_volts)
|
||||
{
|
||||
agc_wdsp.volts = agc_wdsp.min_volts; // no AGC action is taking place
|
||||
agc_wdsp_conf.action = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// LED indicator for AGC action
|
||||
agc_wdsp_conf.action = 1;
|
||||
}
|
||||
|
||||
float32_t vo = Math_log10f_fast(agc_wdsp.inv_max_input * agc_wdsp.volts);
|
||||
if(vo > 0.0)
|
||||
{
|
||||
vo = 0.0;
|
||||
}
|
||||
|
||||
float32_t mult = (agc_wdsp.out_target - agc_wdsp.slope_constant * vo) / agc_wdsp.volts;
|
||||
agcbuffer[0][i] = agc_wdsp.out_sample[0] * mult;
|
||||
if(use_stereo)
|
||||
{
|
||||
agcbuffer[1][i] = agc_wdsp.out_sample[1] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
if(agc_wdsp.remove_dc)
|
||||
{
|
||||
static float32_t wold[2] = { 0.0, 0.0 };
|
||||
|
||||
// eliminate DC in the audio after the AGC
|
||||
for(uint16_t i = 0; i < blockSize; i++)
|
||||
{
|
||||
float32_t w = agcbuffer[0][i] + wold[0] * 0.9999; // yes, I want a superb bass response ;-)
|
||||
agcbuffer[0][i] = w - wold[0];
|
||||
wold[0] = w;
|
||||
if(use_stereo)
|
||||
{
|
||||
float32_t w = agcbuffer[1][i] + wold[1] * 0.9999; // yes, I want a superb bass response ;-)
|
||||
agcbuffer[1][i] = w - wold[1];
|
||||
wold[1] = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**--------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Description: Code for automatic gain control based on the WDSP Lib **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __AUDIO_AGC_H
|
||||
#define __AUDIO_AGC_H
|
||||
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
// these are the control parameter
|
||||
// for external runtime configuration
|
||||
// of the AGC
|
||||
typedef struct
|
||||
{
|
||||
uint8_t mode;
|
||||
uint8_t slope;
|
||||
uint8_t hang_enable;
|
||||
int thresh;
|
||||
int hang_thresh;
|
||||
int hang_time;
|
||||
uint8_t action;
|
||||
uint8_t switch_mode;
|
||||
uint8_t hang_action;
|
||||
int tau_decay[6];
|
||||
int tau_hang_decay;
|
||||
} agc_wdsp_params_t;
|
||||
|
||||
|
||||
extern agc_wdsp_params_t agc_wdsp_conf;
|
||||
|
||||
void AudioAgc_RunAgcWdsp(int16_t blockSize, float32_t (*agcbuffer)[AUDIO_BLOCK_SIZE], const bool use_stereo );
|
||||
void AudioAgc_SetupAgcWdsp(float32_t sample_rate, bool remove_dc);
|
||||
void AudioAgc_AgcWdsp_Init(void);
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**--------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Description: Code for fast convolution filtering **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __AUDIO_CONVOLUTION_H
|
||||
#define __AUDIO_CONVOLUTION_H
|
||||
|
||||
#include "arm_math.h"
|
||||
//#include "softdds.h"
|
||||
#include "uhsdr_hw_i2s.h"
|
||||
#include "uhsdr_board.h"
|
||||
#include "codec.h"
|
||||
#include "audio_driver.h"
|
||||
#include "radio_management.h"
|
||||
#include "usbd_audio_if.h"
|
||||
|
||||
|
||||
#define SAMPLE_BUFFER_SIZE 256
|
||||
#define SAMPLE_BUFFER_NUM 4
|
||||
#define SAMPLE_BUFFER_FIFO_SIZE (SAMPLE_BUFFER_NUM + 1)
|
||||
|
||||
extern arm_fir_decimate_instance_f32 DECIMATE_RX_I;
|
||||
extern arm_fir_decimate_instance_f32 DECIMATE_RX_Q;
|
||||
//extern AudioDriverBuffer adb;
|
||||
|
||||
#ifdef USE_CONVOLUTION
|
||||
#define FFT_CONVOLUTION_SIZE 256
|
||||
#define CONVOLUTION_MAX_NO_OF_BLOCKS 8
|
||||
#define CONVOLUTION_MAX_NO_OF_COEFFS 2048
|
||||
#endif
|
||||
|
||||
#ifdef USE_CONVOLUTION
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// for convolution filtering
|
||||
float32_t i_buffer_convolution[FFT_CONVOLUTION_SIZE / 2];
|
||||
float32_t q_buffer_convolution[FFT_CONVOLUTION_SIZE / 2];
|
||||
|
||||
float32_t fmask[CONVOLUTION_MAX_NO_OF_BLOCKS][FFT_CONVOLUTION_SIZE * 2];
|
||||
float32_t fftin[FFT_CONVOLUTION_SIZE * 2];
|
||||
float32_t fftout[CONVOLUTION_MAX_NO_OF_BLOCKS][FFT_CONVOLUTION_SIZE * 2];
|
||||
float32_t ifftout[FFT_CONVOLUTION_SIZE * 2];
|
||||
float32_t accum[FFT_CONVOLUTION_SIZE * 2];
|
||||
float32_t a_buffer[2][FFT_CONVOLUTION_SIZE / 2]; // for convolution, we need an output buffer of 128 samples
|
||||
} ConvolutionBuffers;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// for convolution filtering
|
||||
int nc; // no. of coefficients
|
||||
int size; // no. of input samples
|
||||
int nfor; // no. of blocks in the convolution
|
||||
int buffidx; // buffer pointer
|
||||
int DF; // decimation factor
|
||||
float32_t impulse[CONVOLUTION_MAX_NO_OF_COEFFS * 2]; // impulse response has real and imaginary components
|
||||
float32_t maskgen[FFT_CONVOLUTION_SIZE * 2];
|
||||
} ConvolutionBuffersShared;
|
||||
|
||||
extern ConvolutionBuffersShared cbs;
|
||||
|
||||
void AudioDriver_CalcConvolutionFilterCoeffs (int N, float32_t f_low, float32_t f_high, float32_t samplerate, int wintype, int rtype, float32_t scale);
|
||||
void AudioDriver_RxProcessorConvolution(AudioSample_t * const src, AudioSample_t * const dst, const uint16_t blockSize);
|
||||
void convolution_handle(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+3130
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,682 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __AUDIO_DRIVER_H
|
||||
#define __AUDIO_DRIVER_H
|
||||
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "uhsdr_types.h"
|
||||
#include "arm_math.h"
|
||||
#include "softdds.h"
|
||||
#include "audio_filter.h"
|
||||
|
||||
#define IQ_SAMPLE_RATE_F ((float32_t)IQ_SAMPLE_RATE)
|
||||
|
||||
#define AUDIO_SAMPLE_RATE_F ((float32_t)AUDIO_SAMPLE_RATE)
|
||||
|
||||
|
||||
|
||||
#if defined(USE_32_IQ_BITS)
|
||||
typedef int32_t iq_data_t;
|
||||
#else
|
||||
typedef int16_t iq_data_t;
|
||||
#endif
|
||||
|
||||
#if defined(USE_32_AUDIO_BITS)
|
||||
typedef int32_t audio_data_t;
|
||||
#else
|
||||
typedef int16_t audio_data_t;
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
__packed audio_data_t l;
|
||||
__packed audio_data_t r;
|
||||
} AudioSample_t;
|
||||
|
||||
typedef struct {
|
||||
__packed iq_data_t l;
|
||||
__packed iq_data_t r;
|
||||
} IqSample_t;
|
||||
|
||||
#ifdef USE_CONVOLUTION
|
||||
typedef struct {
|
||||
COMP samples[SAMPLE_BUFFER_SIZE];
|
||||
} Sample_Buffer;
|
||||
#endif
|
||||
|
||||
// -----------------------------
|
||||
// FFT buffer, this is double the size of the length of the FFT used for spectrum display and waterfall spectrum
|
||||
#ifdef USE_FFT_1024
|
||||
#define FFT_IQ_BUFF_LEN 1024
|
||||
#else
|
||||
#define FFT_IQ_BUFF_LEN 512
|
||||
#endif
|
||||
#define SPEC_BUFF_LEN (FFT_IQ_BUFF_LEN/2)
|
||||
|
||||
// twice the number of samples in the each iq block buffer
|
||||
// (which is half of the total dma buffer, since in each interrupt we get half of the total dma buffer)
|
||||
#define IQ_BUFSZ (2*IQ_BLOCK_SIZE)
|
||||
#define AUDIO_BUFSZ (2*AUDIO_BLOCK_SIZE)
|
||||
|
||||
// Audio filter
|
||||
#define FIR_RXAUDIO_BLOCK_SIZE IQ_BLOCK_SIZE
|
||||
#define FIR_RXAUDIO_NUM_TAPS 16 // maximum number of taps in the decimation and interpolation FIR filters
|
||||
#define IIR_RXAUDIO_BLOCK_SIZE IQ_BLOCK_SIZE
|
||||
#define IIR_RXAUDIO_NUM_STAGES_MAX 12 // we use a maximum stage number of 10 at the moment, so this is 12 just to be safe
|
||||
//
|
||||
#define CODEC_DEFAULT_GAIN 0x1F // Gain of line input to start with
|
||||
#define ADC_CLIP_WARN_THRESHOLD 4096 // This is at least 12dB below the clipping threshold of the A/D converter itself
|
||||
//
|
||||
//
|
||||
//
|
||||
#define SCALING_FACTOR_IQ_PHASE_ADJUST 2000.0
|
||||
#define SCALING_FACTOR_IQ_AMPLITUDE_ADJUST 2731.0
|
||||
|
||||
#define SAM_PLL_HILBERT_STAGES 7
|
||||
|
||||
|
||||
#ifdef USE_TWO_CHANNEL_AUDIO
|
||||
#define NUM_AUDIO_CHANNELS 2
|
||||
#else
|
||||
#define NUM_AUDIO_CHANNELS 1
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
// for SAM demodulation
|
||||
// DX adjustments: zeta = 0.15, omegaN = 100.0
|
||||
// very stable, but does not lock very fast
|
||||
// standard settings: zeta = 1.0, omegaN = 250.0
|
||||
// maybe user can choose between slow (DX), medium, fast SAM PLL
|
||||
// zeta / omegaN
|
||||
// DX = 0.2, 70
|
||||
// medium 0.6, 200
|
||||
// fast 1.2, 500
|
||||
|
||||
|
||||
//pll
|
||||
float32_t omega_min; // (2.0 * 3.141592653589793f * pll_fmin * DF / IQ_SAMPLE_RATE_F);
|
||||
float32_t omega_max; //(2.0 * 3.141592653589793f * pll_fmax * DF / IQ_SAMPLE_RATE_F);
|
||||
float32_t g1; //(1.0 - exp(-2.0 * omegaN * zeta * DF / IQ_SAMPLE_RATE_F));
|
||||
float32_t g2; //(- g1 + 2.0 * (1 - exp(- omegaN * zeta * DF / IQ_SAMPLE_RATE_F)
|
||||
// * cosf(omegaN * DF / IQ_SAMPLE_RATE_F * sqrtf(1.0 - zeta * zeta))));
|
||||
|
||||
//fade leveler
|
||||
float32_t mtauR; //(exp(- DF / (IQ_SAMPLE_RATE_F * tauR))); //0.99948;
|
||||
float32_t onem_mtauR;
|
||||
float32_t mtauI; //(exp(- DF / (IQ_SAMPLE_RATE_F * tauI))); //0.99999255955;
|
||||
float32_t onem_mtauI;
|
||||
} demod_sam_param_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t teta1;
|
||||
float32_t teta2;
|
||||
float32_t teta3;
|
||||
float32_t teta1_old;
|
||||
float32_t teta2_old;
|
||||
float32_t teta3_old;
|
||||
float32_t M_c1;
|
||||
float32_t M_c2;
|
||||
} iq_correction_data_t;
|
||||
|
||||
typedef float32_t audio_block_t[AUDIO_BLOCK_SIZE];
|
||||
typedef float32_t iq_block_t[IQ_BLOCK_SIZE];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
iq_block_t i_buffer;
|
||||
iq_block_t q_buffer;
|
||||
} iq_buffer_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Stereo buffers
|
||||
iq_buffer_t iq_buf;
|
||||
float32_t agc_valbuf[IQ_BLOCK_SIZE]; // holder for "running" AGC value
|
||||
|
||||
audio_block_t a_buffer[2];
|
||||
|
||||
demod_sam_param_t sam;
|
||||
iq_correction_data_t iq_corr;
|
||||
} AudioDriverBuffer;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float sql_avg; // averaged squelch level (for FM)
|
||||
bool squelched; // TRUE if FM receiver audio is to be squelched
|
||||
|
||||
float subaudible_tone_gen_freq; // frequency, in Hz, of currently-selected subaudible tone for generation
|
||||
soft_dds_t subaudible_tone_dds;
|
||||
|
||||
soft_dds_t tone_burst_dds;
|
||||
bool tone_burst_active; // this is TRUE if the tone burst is actively being generated
|
||||
//
|
||||
float subaudible_tone_det_freq; // frequency, in Hz, of currently-selected subaudible tone for detection
|
||||
bool subaudible_tone_detected; // TRUE if subaudible tone has been detected
|
||||
|
||||
Goertzel goertzel[3];
|
||||
#define FM_HIGH 0
|
||||
#define FM_LOW 1
|
||||
#define FM_CTR 2
|
||||
|
||||
} fm_conf_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SAM_SIDEBAND_BOTH = 0,
|
||||
SAM_SIDEBAND_LSB,
|
||||
SAM_SIDEBAND_USB,
|
||||
#ifdef USE_TWO_CHANNEL_AUDIO
|
||||
SAM_SIDEBAND_STEREO,
|
||||
#endif
|
||||
SAM_SIDEBAND_MAX
|
||||
} sam_sideband_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#define DSP_NR_ENABLE 0x01 // DSP NR mode is on (| 1)
|
||||
#define DSP_NR_POSTAGC_ENABLE 0x02 // DSP NR is to occur post AGC (| 2)
|
||||
#define DSP_NOTCH_ENABLE 0x04 // DSP Notch mode is on (| 4)
|
||||
#define DSP_NB_ENABLE 0x08 // DSP is to be displayed on screen instead of NB (| 8)
|
||||
#define DSP_MNOTCH_ENABLE 0x10 // Manual Notch enabled
|
||||
#define DSP_MPEAK_ENABLE 0x20 // Manual Peak enabled
|
||||
#define DSP_ANR_ENABLE 0x40 // DSP ANR (Leak LMS) mode is on
|
||||
|
||||
uint8_t active; // Used to hold various aspects of DSP mode selection
|
||||
uint8_t mode; // holds the mode chosen in the DSP
|
||||
uint16_t mode_mask; // holds the DSP mode mask (to be chosen by virtual dsp keyboard)
|
||||
uint8_t active_toggle; // holder used on the press-hold of button G2 to "remember" the previous setting
|
||||
uint8_t nr_strength; // "Strength" of DSP Noise reduction - to be converted to "Mu" factor
|
||||
#if defined (USE_LMS_AUTONOTCH)
|
||||
uint8_t notch_numtaps;
|
||||
uint8_t notch_mu;
|
||||
// mu adjust of notch DSP LMS
|
||||
uint8_t notch_delaybuf_len; // size of DSP notch delay buffer
|
||||
#endif
|
||||
uint8_t inhibit; // if != 0, DSP (NR, Notch) functions are inhibited. Used during power-up and switching
|
||||
uint8_t nb_setting;
|
||||
ulong notch_frequency; // frequency of the manual notch filter
|
||||
ulong peak_frequency; // frequency of the manual peak filter
|
||||
|
||||
int bass_gain; // gain of the low shelf EQ filter
|
||||
int treble_gain; // gain of the high shelf EQ filter
|
||||
// int tx_bass_gain; // gain of the TX low shelf EQ filter
|
||||
// int tx_treble_gain; // gain of the TX high shelf EQ filter
|
||||
int tx_eq_gain[5]; // gain of the TX 5-bands EQ filter
|
||||
|
||||
} dsp_params_t;
|
||||
|
||||
// Audio driver publics
|
||||
typedef struct AudioDriverState
|
||||
{
|
||||
//
|
||||
// Lock audio filter flag
|
||||
//
|
||||
volatile bool af_disabled; // if TRUE, audio filtering is disabled (used during filter bandwidth changing, etc.)
|
||||
volatile bool tx_filter_adjusting; // used to disable TX I/Q filter during phase adjustment
|
||||
|
||||
float codec_gain_calc; // spectrum gain value
|
||||
|
||||
bool adc_clip; // used to display warning in s meter
|
||||
bool adc_half_clip; // used to control input gain and spectrum gain
|
||||
bool adc_quarter_clip; // used to control input gain and spectrum gain
|
||||
float peak_audio; // used for audio metering to detect the peak audio level
|
||||
|
||||
float alc_val; // "live" transmitter ALC value
|
||||
float alc_decay; // decay rate (speed) of ALC
|
||||
|
||||
uchar decimation_rate; // current decimation/interpolation rate
|
||||
uint32_t decimated_freq; // resulting decimated sample frequency (used in iq and audio processing)
|
||||
|
||||
fm_conf_t fm_conf; // configuration parameters for the fm demodulator
|
||||
|
||||
soft_dds_t beep; // this is the actively-used DDS tone word for the radio's beep generator
|
||||
float beep_loudness_factor; // this is used to set the beep loudness
|
||||
|
||||
/* SAM */
|
||||
// sam related output variables
|
||||
int carrier_freq_offset;
|
||||
|
||||
// sam related configuration parameters, stored in config memory
|
||||
int pll_fmax_int;
|
||||
int zeta_int; // zeta * 100
|
||||
int omegaN_int;
|
||||
uint8_t fade_leveler; // boolean
|
||||
// sam related operation parameters, not stored in config memory
|
||||
sam_sideband_t sam_sideband; // 0 = both, 1 = LSB, 2 = USB
|
||||
|
||||
/* IQ Balance */
|
||||
float32_t iq_phase_balance_rx;
|
||||
float32_t iq_phase_balance_tx[IQ_TRANS_NUM];
|
||||
|
||||
ulong snap_carrier_freq; // used for passing the estimated carrier freq in SNAP mode to the print routine in UI_Driver
|
||||
bool CW_signal; // if CW decoder is enabled and carrier snap is wanted, this indicates whenever a pulse is received
|
||||
// only in that case, the carrier frequency is estimated and the display refreshed
|
||||
} AudioDriverState;
|
||||
|
||||
void AudioManagement_CalcIQPhaseAdjust(uint32_t freq);
|
||||
|
||||
// S meter public
|
||||
typedef struct SMeter
|
||||
{
|
||||
// configurable ALPHA = 1 - e^(-T/Tau)
|
||||
// we use alpha config value scaling of 100, i.e. 100 => alpha = 1.00
|
||||
// this construct permits us to use a single configuration store for both
|
||||
// it looks rather complex but this is necessary to ensure type safety checks are working
|
||||
union {
|
||||
uint16_t alphaCombined;
|
||||
struct
|
||||
{
|
||||
uint8_t DecayAlpha;
|
||||
uint8_t AttackAlpha;
|
||||
} alphaSplit;
|
||||
} config;
|
||||
|
||||
// first/upper 8 bits is AttackAlpha
|
||||
// second/lower 8 bits is DecayAlpha
|
||||
#define SMETER_ALPHA_ATTACK_DEFAULT 50
|
||||
#define SMETER_ALPHA_DECAY_DEFAULT 5
|
||||
#define SMETER_ALPHA_MIN 1 // used for both alphas
|
||||
#define SMETER_ALPHA_MAX 100 // used for both alphas
|
||||
|
||||
// averaged values, used for display
|
||||
float32_t dbm;
|
||||
float32_t dbmhz;
|
||||
|
||||
// current measurements, used for averaging
|
||||
float32_t dbm_cur;
|
||||
float32_t dbmhz_cur;
|
||||
|
||||
// internal variables for dbm low pass calculation
|
||||
float32_t AttackAvedbm;
|
||||
float32_t DecayAvedbm;
|
||||
float32_t AttackAvedbmhz;
|
||||
float32_t DecayAvedbmhz;
|
||||
|
||||
uint32_t s_count; // number of S steps, used for display and CAT level
|
||||
} SMeter;
|
||||
|
||||
|
||||
#define MAX_BASS 20
|
||||
#define MIN_BASS -20
|
||||
#define MAX_TREBLE 20
|
||||
#define MIN_TREBLE -20
|
||||
//#define MAX_TX_BASS 5
|
||||
//#define MIN_TX_BASS -20
|
||||
//#define MAX_TX_TREBLE 5
|
||||
//#define MIN_TX_TREBLE -20
|
||||
#define MAX_TX_EQ 20
|
||||
#define MIN_TX_EQ -20
|
||||
|
||||
#define MIN_PEAK_NOTCH_FREQ 200
|
||||
//
|
||||
// AGC Time constants
|
||||
// C. Turner, KA7OEI
|
||||
//
|
||||
#define AGC_KNEE 1000//4000 // ADC "knee" threshold for AGC action
|
||||
//
|
||||
#define AGC_KNEE_REF 1000
|
||||
#define AGC_VAL_MAX_REF 131072//4096
|
||||
#define POST_AGC_GAIN_SCALING_REF 1.333
|
||||
|
||||
#define AGC_ATTACK 0.033 // Attack time multiplier for AGC
|
||||
//
|
||||
#define AGC_FAST_DECAY 0.0002 // Decay rate multiplier for "Fast" AGC
|
||||
#define AGC_MED_DECAY 0.00006 // Decay rate multiplier for "Medium" AGC
|
||||
#define AGC_SLOW_DECAY 0.00001 // Decay rate for multiplier "Slow" AGC
|
||||
//
|
||||
#define AGC_ATTACK_FM 0.0033 // Attack time for FM (S-meter reading only)
|
||||
#define AGC_DECAY_FM 0.0333 // Decay time for FM (S-meter reading only)
|
||||
//
|
||||
|
||||
#define AGC_VAL_MIN 0.02 // Minimum AGC gain multiplier (e.g. gain reduction of 34dB)
|
||||
//#define AGC_VAL_MAX 4096//1024 // Maximum AGC gain multiplier (e.g. gain multiplication of 60dB)
|
||||
|
||||
#define AGC_PREFILTER_MAXGAIN 5 // Scaling factor for RF gain adjustment (e.g. factor by which RFG will be multiplied to yield actual RFG multiplier
|
||||
#define AGC_PREFILTER_MINGAIN 0.5 // Minimum "RFG" gain multiplier (e.g. gain reduction of 6 dB)
|
||||
//
|
||||
#define AGC_PREFILTER_HISIG_THRESHOLD 0.1 // Threshold at which adjustment of RFGAIN (pre-filter) gain adjustment will occur
|
||||
#define AGC_PREFILTER_LOWSIG_THRESHOLD 1.0 // Threshold at which adjustment of RFGAIN (pre-filter) gain adjustment will occur
|
||||
#define AGC_PREFILTER_ATTACK_RATE 0.0002 // Attack rate for RFG reduction
|
||||
#define AGC_PREFILTER_DECAY_RATE 0.000002 // Decay rate for RFG gain recovery
|
||||
//
|
||||
#define AGC_PREFILTER_MAX_SIGNAL 1 // maximum level of pre-filtered signal
|
||||
//
|
||||
#define POST_AGC_GAIN_SCALING 1.333//0.333 // Used to rescale the post-filter audio level to a value suitable for the codec. This sets the line level output
|
||||
// to approx. 1000mV peak-peak.
|
||||
//
|
||||
#define POST_AGC_GAIN_SCALING_DECIMATE_4 3.46 // Used to scale audio from the decimation/interpolation-by-4 process (based square root of decimation factor)
|
||||
//
|
||||
#define POST_AGC_GAIN_SCALING_DECIMATE_2 (POST_AGC_GAIN_SCALING_DECIMATE_4 * 0.6) // Scales audio from decimation/interpolation-by-2 process
|
||||
//
|
||||
#define AM_SCALING 1.0 // was 2.0 // Amount of gain multiplication to apply to audio and AGC to make recovery equal to that of SSB
|
||||
#define AM_AUDIO_SCALING 1.4 // was 1.4 // Additional correction factor applied to audio demodulation to make amplitude equal to that of SSB demodulation
|
||||
//
|
||||
//#define AGC_GAIN_CAL 155000.0//22440 // multiplier value (linear, not DB) to calibrate the S-Meter reading to the AGC value
|
||||
//
|
||||
#define AUTO_RFG_DECREASE_LOCKOUT 1
|
||||
#define AUTO_RFG_INCREASE_TIMER 5//10
|
||||
//
|
||||
//#define AGC_SLOW 0 // Mode setting for slow AGC
|
||||
//#define AGC_MED 1 // Mode setting for medium AGC
|
||||
//#define AGC_FAST 2 // Mode setting for fast AGC
|
||||
//#define AGC_CUSTOM 3 // Mode setting for custom AGC
|
||||
//#define AGC_OFF 4 // Mode setting for AGC off
|
||||
//#define AGC_MAX_MODE 4 // Maximum for mode setting for AGC
|
||||
//#define AGC_DEFAULT AGC_MED // Default!
|
||||
//
|
||||
//#define AGC_CUSTOM_MAX 30 // Maximum (slowest) setting for custom AGC
|
||||
//#define AGC_CUSTOM_DEFAULT 12 // Default custom AGC setting (approx. equal to "medium")
|
||||
//#define AGC_CUSTOM_FAST_WARNING 2 // Value at or below which setting the custom AGC is likely to degrade audio
|
||||
//
|
||||
#define MAX_RF_GAIN_MAX 30 // Maximum setting for "Max RF gain"
|
||||
#define MAX_RF_GAIN_DEFAULT 10
|
||||
|
||||
// Noise blanker constants
|
||||
#define MAX_NB_SETTING 15
|
||||
#define NB_WARNING1_SETTING 7 // setting at or above which NB warning1 (yellow) is given
|
||||
#define NB_WARNING2_SETTING 12 // setting at or above which NB warning2 (orange) is given
|
||||
#define NB_WARNING3_SETTING 15 // setting at or above which NB warning3 (red) is given
|
||||
|
||||
// Values used for "custom" AGC settings
|
||||
#define LINE_OUT_SCALING_FACTOR 10 // multiplication of audio for fixed LINE out level (nominally 1vpp)
|
||||
//
|
||||
#define LINE_IN_GAIN_RESCALE 20 // multiplier for line input gain
|
||||
#define MIC_GAIN_RESCALE 2 // divisor for microphone gain setting
|
||||
|
||||
|
||||
// ALC (Auto Level Control) for transmitter, constants
|
||||
#define ALC_VAL_MAX 1 // Maximum ALC Value is 1 (e.g. it can NEVER amplify)
|
||||
#define ALC_VAL_MIN 0.001 // Minimum ALC Value - it can provide up to 60dB of attenuation
|
||||
#define ALC_ATTACK 0.1//0.033 // Attack time for the ALC's gain control
|
||||
#define ALC_KNEE 30000 // The audio value threshold for the ALC operation
|
||||
|
||||
// Decay (release time) for ALC/Audio compressor
|
||||
#define ALC_DECAY_MAX 20 // Maximum (slowest) setting for ALC decay
|
||||
#define ALC_DECAY_DEFAULT 10 // Default custom ALC setting (approx. equal to AGC "medium")
|
||||
|
||||
// Audio post-filter (pre-alc) gain adjust. This effectively sets the min/max compression level.
|
||||
#define ALC_POSTFILT_GAIN_MIN 1
|
||||
#define ALC_POSTFILT_GAIN_MAX 25
|
||||
#define ALC_POSTFILT_GAIN_DEFAULT 1
|
||||
//
|
||||
#define SSB_ALC_GAIN_CORRECTION 1.00 // This scales the output of the ALC for 100% modulation for SSB transmission
|
||||
//
|
||||
#define SSB_GAIN_COMP 1.133 // This compensates for slight differences in gain processing in the SSB algorithm (empirically derived)
|
||||
//
|
||||
#define AM_GAIN_COMP 1.133 // This compensates for slight differences in gain processing in the AM algorithm (empirically derived)
|
||||
//
|
||||
#define FREEDV_GAIN_COMP (20*SSB_GAIN_COMP)
|
||||
|
||||
// The following are calibration constants for AM (transmitter) modulation, carefully adjusted for proper D/A scaling to set
|
||||
// maximum possible 95-100% AM modulation depth.
|
||||
//
|
||||
#define AM_ALC_GAIN_CORRECTION 0.23 // This scales the output of the ALC for 100% modulation with respect to the carrier level
|
||||
#define AM_CARRIER_LEVEL 5100 // This sets the AM carrier level in DAC units, scaled for proper ALC operation and 100% modulation
|
||||
//
|
||||
// DO NOT change the above unless you know *EXACTLY* what you are doing! If you screw with these numbers, you WILL wreck the
|
||||
// AM modulation!!! (No, I'm not kidding!)
|
||||
|
||||
// FM TX/RX
|
||||
#define NUM_SUBAUDIBLE_TONES 56
|
||||
#define FM_SUBAUDIBLE_TONE_OFF 0
|
||||
|
||||
// FM TX
|
||||
|
||||
#define FM_TONE_BURST_MAX 2
|
||||
extern uint32_t fm_tone_burst_freq[FM_TONE_BURST_MAX+1];
|
||||
|
||||
#define FM_TONE_BURST_OFF 0
|
||||
|
||||
#define FM_TONE_BURST_DURATION 100 // duration, in 100ths of a second, of the tone burst
|
||||
|
||||
// FM RX
|
||||
#define FM_SQUELCH_MAX 20 // maximum setting for FM squelch
|
||||
#define FM_SQUELCH_DEFAULT 12 // default setting for FM squelch
|
||||
#define FM_SUBAUDIBLE_GOERTZEL_WINDOW 400 // this sets the overall number of samples involved in the Goertzel decode windows (this value * "size/2")
|
||||
|
||||
|
||||
#define MIN_BEEP_FREQUENCY 200 // minimum beep frequency in Hz
|
||||
#define MAX_BEEP_FREQUENCY 3000 // maximum beep frequency in Hz
|
||||
#define DEFAULT_BEEP_FREQUENCY 1000 // default beep frequency in Hz
|
||||
|
||||
#define BEEP_DURATION 2 // duration of beep in 100ths of a second
|
||||
|
||||
#define MAX_BEEP_LOUDNESS 21 // maximum setting for beep loudness
|
||||
#define DEFAULT_BEEP_LOUDNESS 10 // default loudness for the keyboard beep
|
||||
|
||||
// Factors used in audio compressor adjustment limits
|
||||
//
|
||||
#define TX_AUDIO_COMPRESSION_MIN -1 // -1 = OFF
|
||||
#define TX_AUDIO_COMPRESSION_MAX 13 // 0 = least compression, 12 = most, 13 = EEPROM values ("CUS" = CUSTOM) - custom selected by user
|
||||
#define TX_AUDIO_COMPRESSION_SV 13
|
||||
#define TX_AUDIO_COMPRESSION_DEFAULT 2
|
||||
//
|
||||
//
|
||||
#define RX_DECIMATION_RATE_8KHZ 6 // Decimation/Interpolation rate in receive function for 8 kHz sample rate
|
||||
#define RX_DECIMATION_RATE_12KHZ 4 // Decimation/Interpolation rate in receive function for 12 kHz sample rate
|
||||
#define RX_DECIMATION_RATE_24KHZ 2 // Decimation/Interpolation rate in receive function for 24 kHz sample rate
|
||||
#define RX_DECIMATION_RATE_48KHZ 1 // Deimcation/Interpolation rate in receive function for 48 kHz sample rate (e.g. no decimation!)
|
||||
|
||||
#define DSP_NR_STRENGTH_MIN 1
|
||||
#define DSP_NR_STRENGTH_MAX 200 // Maximum menu setting for DSP "Strength"
|
||||
#define DSP_NR_STRENGTH_STEP 5
|
||||
#define DSP_NR_STRENGTH_DEFAULT 160 // Default setting
|
||||
|
||||
#ifdef USE_LMS_AUTONOTCH
|
||||
//
|
||||
// Automatic Notch Filter
|
||||
//
|
||||
#define LMS_NOTCH_DELAYBUF_SIZE_MAX 512
|
||||
//
|
||||
#define DSP_NOTCH_NUMTAPS_MAX 64//128
|
||||
#define DSP_NOTCH_NUMTAPS_MIN 64
|
||||
#define DSP_NOTCH_NUMTAPS_DEFAULT 64//96
|
||||
//
|
||||
#define DSP_NOTCH_BUFLEN_MIN 128//64//48 // minimum length of decorrelation buffer for the notch filter FIR
|
||||
#define DSP_NOTCH_BUFLEN_MAX 128//192 // maximum decorrelation buffer length for the notch filter FIR
|
||||
#define DSP_NOTCH_DELAYBUF_DEFAULT 128//104 // default decorrelation buffer length for the notch filter FIR
|
||||
//
|
||||
#define DSP_NOTCH_MU_MAX 40//40 // maximum "strength" (convergence) setting for the notch
|
||||
#define DSP_NOTCH_MU_DEFAULT 10//25 // default convergence setting for the notch
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DSP_SWITCH_OFF = 0,
|
||||
DSP_SWITCH_NR,
|
||||
DSP_SWITCH_ANR,
|
||||
DSP_SWITCH_NOTCH,
|
||||
DSP_SWITCH_NR_AND_NOTCH,
|
||||
DSP_SWITCH_NOTCH_MANUAL,
|
||||
DSP_SWITCH_PEAK_FILTER,
|
||||
DSP_SWITCH_MAX, // bass & treble not used here
|
||||
DSP_SWITCH_BASS = 98,
|
||||
DSP_SWITCH_TREBLE = 99,
|
||||
} dsp_mode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ModeVK_SSB = 0,
|
||||
ModeVK_CW,
|
||||
ModeVK_AM,
|
||||
ModeVK_SAM,
|
||||
ModeVK_FM,
|
||||
ModeVK_RTTY,
|
||||
ModeVK_BPSK,
|
||||
ModeVK_FDV,
|
||||
ModeVK_SWITCH_MAX,
|
||||
} ModeVK_t;
|
||||
|
||||
#define DSP_SWITCH_MODEMASK_ENABLE_MASK ((1<<DSP_SWITCH_MAX)-1)
|
||||
#define DSP_SWITCH_MODEMASK_ENABLE_DEFAULT ((1<<DSP_SWITCH_MAX)-1)
|
||||
#define DSP_SWITCH_MODEMASK_ENABLE_DSPOFF (1<<DSP_SWITCH_OFF)
|
||||
|
||||
//
|
||||
#define AUDIO_DELAY_BUFSIZE (IQ_BUFSZ)*5 // Size of AGC delaying audio buffer - Must be a multiple of IQ_BUFSZ.
|
||||
// This is divided by the decimation rate so that the time delay is constant.
|
||||
|
||||
|
||||
#define FREQ_IQ_CONV_MODE_OFF 0 // No frequency conversion
|
||||
#define FREQ_IQ_CONV_P6KHZ 1 // LO is 6KHz above receive frequency in RX mode
|
||||
#define FREQ_IQ_CONV_M6KHZ 2 // LO is 6KHz below receive frequency in RX mode
|
||||
#define FREQ_IQ_CONV_P12KHZ 3 // LO is 12KHz above receive frequency in RX mode
|
||||
#define FREQ_IQ_CONV_M12KHZ 4 // LO is 12KHz below receive frequency in RX mode
|
||||
#define FREQ_IQ_CONV_SLIDE 5 // LO slide frequency in RX mode
|
||||
//
|
||||
#define FREQ_IQ_CONV_MODE_DEFAULT FREQ_IQ_CONV_M12KHZ //FREQ_IQ_CONV_MODE_OFF
|
||||
#define FREQ_IQ_CONV_MODE_MAX 5
|
||||
|
||||
// Public Audio
|
||||
extern AudioDriverState ads;
|
||||
extern SMeter sm;
|
||||
|
||||
extern AudioDriverBuffer adb;
|
||||
|
||||
typedef struct SnapCarrier
|
||||
{
|
||||
bool snap;
|
||||
} SnapCarrier;
|
||||
|
||||
extern SnapCarrier sc;
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_LEAKY_LMS
|
||||
#define LEAKYLMSDLINE_SIZE 256 //512 // was 256 //2048 // dline_size
|
||||
// 1024 funktioniert nicht
|
||||
typedef struct
|
||||
{// Automatic noise reduction
|
||||
// Variable-leak LMS algorithm
|
||||
// taken from (c) Warren Pratts wdsp library 2016
|
||||
// GPLv3 licensed
|
||||
// #define DLINE_SIZE 256 //512 //2048 // dline_size
|
||||
int16_t n_taps; // = 64; //64; // taps
|
||||
int16_t delay; // = 16; //16; // delay
|
||||
int dline_size; // = LEAKYLMSDLINE_SIZE;
|
||||
//int ANR_buff_size = FFT_length / 2.0;
|
||||
int position;// = 0;
|
||||
float32_t two_mu;// = 0.0001; typical: 0.001 to 0.000001 = 1000 to 1 -> div by 1000000 // two_mu --> "gain"
|
||||
uint32_t two_mu_int;
|
||||
float32_t gamma;// = 0.1; typical: 1.000 to 0.001 = 1000 to 1 -> div by 1000 // gamma --> "leakage"
|
||||
uint32_t gamma_int;
|
||||
float32_t lidx;// = 120.0; // lidx
|
||||
float32_t lidx_min;// = 0.0; // lidx_min
|
||||
float32_t lidx_max;// = 200.0; // lidx_max
|
||||
float32_t ngamma;// = 0.001; // ngamma
|
||||
float32_t den_mult;// = 6.25e-10; // den_mult
|
||||
float32_t lincr;// = 1.0; // lincr
|
||||
float32_t ldecr;// = 3.0; // ldecr
|
||||
//int ANR_mask = ANR_dline_size - 1;
|
||||
int mask;// = DLINE_SIZE - 1;
|
||||
int in_idx;// = 0;
|
||||
float32_t d [LEAKYLMSDLINE_SIZE];
|
||||
float32_t w [LEAKYLMSDLINE_SIZE];
|
||||
uint8_t on;// = 0;
|
||||
uint8_t notch;// = 0;
|
||||
} lLMS;
|
||||
|
||||
extern lLMS leakyLMS;
|
||||
#endif
|
||||
|
||||
// TODO: Discuss to drop 16 bit I2S support. Would simplify the incoming/outgoing data handling. We could
|
||||
// align all scalings accordingly and would not have most of the ugly stuff below
|
||||
// FIXME: This is ugly: The STM32F4 returns 32bit reads from 16 bit peripherals such as the SPI/I2S
|
||||
// with the two half words in "mixed endian" instead of the wanted "little endian". This is documented in
|
||||
// the data sheet, so the only thing we can do is to swap the halfwords. This is in fact a single ror16 operation
|
||||
// if the compiler is smart enough to detect what we want.
|
||||
|
||||
|
||||
// these constants are used to adjust the 32 bit integer samples to represent the same levels as if we sample 16 bit integers,
|
||||
// effectively "shifting" them down or up.
|
||||
// FIXME: switch to 16 bit extended mode for 16 bit samples will eliminate the need for this at the expense of
|
||||
// using the same DMA memory (two times the memory true 16 bit values take, in our case this is 2*(2*(IQ_BLOCK_SIZE*2samples*2bytes) = 512 bytes)
|
||||
#ifdef USE_32_IQ_BITS
|
||||
#define IQ_BIT_SHIFT 16
|
||||
#define IQ_BIT_SCALE_DOWN (0.0000152587890625)
|
||||
#else
|
||||
#define IQ_BIT_SHIFT 0
|
||||
#define IQ_BIT_SCALE_DOWN (1.0)
|
||||
#endif
|
||||
#define IQ_BIT_SCALE_UP (1<<IQ_BIT_SHIFT)
|
||||
#define IQ_BIT_SCALE_DOWN24 (0.0039)
|
||||
|
||||
#ifdef USE_32_AUDIO_BITS
|
||||
#define AUDIO_BIT_SHIFT 16
|
||||
#define AUDIO_BIT_SCALE_DOWN (0.0000152587890625)
|
||||
#else
|
||||
#define AUDIO_BIT_SHIFT 0
|
||||
#define AUDIO_BIT_SCALE_DOWN (1.0)
|
||||
#endif
|
||||
#define AUDIO_BIT_SCALE_UP (1<<AUDIO_BIT_SHIFT)
|
||||
|
||||
// we have to swap them only if we are having 32bit values from/to I2S and an STM32F4
|
||||
#if defined(STM32F4) && defined(USE_32_IQ_BITS)
|
||||
static inline int32_t I2S_correctHalfWord(const int32_t word)
|
||||
{
|
||||
uint32_t uWord = (uint32_t)word;
|
||||
return uWord >> 16 | uWord << 16;
|
||||
}
|
||||
|
||||
static inline int16_t I2S_IqSample_2_Int16(const iq_data_t sample) { return (I2S_correctHalfWord(sample)) >> IQ_BIT_SHIFT; }
|
||||
static inline int16_t I2S_AudioSample_2_Int16(const iq_data_t sample) { return (I2S_correctHalfWord(sample)) >> IQ_BIT_SHIFT; }
|
||||
static inline iq_data_t I2S_Int16_2_IqSample(const int16_t sample) { return (I2S_correctHalfWord(sample << IQ_BIT_SHIFT)); }
|
||||
static inline iq_data_t I2S_Int16_2_AudioSample(const int16_t sample) { return (I2S_correctHalfWord(sample << IQ_BIT_SHIFT)); }
|
||||
|
||||
#else
|
||||
#define I2S_correctHalfWord(a) (a)
|
||||
|
||||
#if defined(USE_32_IQ_BITS)
|
||||
static inline int16_t I2S_IqSample_2_Int16(const iq_data_t sample) { return sample >> 16; }
|
||||
static inline iq_data_t I2S_Int16_2_IqSample(const int16_t sample) { return sample << 16; }
|
||||
#else
|
||||
static inline int16_t I2S_IqSample_2_Int16(const iq_data_t sample) { return sample; }
|
||||
static inline iq_data_t I2S_Int16_2_IqSample(const int16_t sample) { return sample; }
|
||||
#endif
|
||||
#if defined(USE_32_AUDIO_BITS)
|
||||
static inline int16_t I2S_AudioSample_2_Int16(const iq_data_t sample) { return sample >> 16; }
|
||||
static inline iq_data_t I2S_Int16_2_AudioSample(const int16_t sample) { return sample << 16; }
|
||||
#else
|
||||
static inline int16_t I2S_AudioSample_2_Int16(const iq_data_t sample) { return sample; }
|
||||
static inline iq_data_t I2S_Int16_2_AudioSample(const int16_t sample) { return sample; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// Exports
|
||||
void AudioDriver_Init(void);
|
||||
void AudioDriver_SetProcessingChain(uint8_t dmod_mode, bool reset_dsp_nr);
|
||||
int32_t AudioDriver_GetTranslateFreq(void);
|
||||
void AudioDriver_SetSamPllParameters (void);
|
||||
|
||||
void AudioDriver_I2SCallback(AudioSample_t *audio, IqSample_t *iq, AudioSample_t *audioDst, int16_t size);
|
||||
void AudioDriver_CalcPeakEQ(float32_t coeffs[5], float32_t f0, float32_t q, float32_t gain, float32_t FS);
|
||||
|
||||
void AudioDriver_CalcLowShelf(float32_t coeffs[5], float32_t f0, float32_t S, float32_t gain, float32_t FS);
|
||||
void AudioDriver_CalcHighShelf(float32_t coeffs[5], float32_t f0, float32_t S, float32_t gain, float32_t FS);
|
||||
void AudioDriver_CalcBandpass(float32_t coeffs[5], float32_t f0, float32_t FS);
|
||||
void AudioDriver_SetBiquadCoeffs(float32_t* coeffsTo,const float32_t* coeffsFrom);
|
||||
|
||||
void AudioDriver_IQPhaseAdjust(uint16_t txrx_mode, float32_t* i_buffer, float32_t* q_buffer, const uint16_t blockSize);
|
||||
void AudioDriver_AgcWdsp_Set(void);
|
||||
|
||||
#endif
|
||||
+1440
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,182 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef DRIVERS_AUDIO_AUDIO_FILTER_H_
|
||||
#define DRIVERS_AUDIO_AUDIO_FILTER_H_
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
#include "arm_math.h"
|
||||
|
||||
// TODO: Decide if we switch to use this struct
|
||||
typedef struct
|
||||
{
|
||||
arm_fir_instance_f32 I;
|
||||
arm_fir_instance_f32 Q;
|
||||
} FIR_IQ_t;
|
||||
|
||||
extern arm_fir_instance_f32 Fir_Tx_Hilbert_Q;
|
||||
extern arm_fir_instance_f32 Fir_Tx_Hilbert_I;
|
||||
extern arm_fir_instance_f32 Fir_Rx_Hilbert_Q;
|
||||
extern arm_fir_instance_f32 Fir_Rx_Hilbert_I;
|
||||
extern arm_fir_instance_f32 Fir_TxFreeDV_Interpolate_Q;
|
||||
extern arm_fir_instance_f32 Fir_TxFreeDV_Interpolate_I;
|
||||
extern arm_fir_decimate_instance_f32 DECIMATE_RX_I;
|
||||
extern arm_fir_decimate_instance_f32 DECIMATE_RX_Q;
|
||||
|
||||
|
||||
void AudioFilter_SetRxHilbertAndDecimationFIR(uint8_t dmod_mode);
|
||||
void AudioFilter_SetTxHilbertFIR(void);
|
||||
|
||||
enum
|
||||
{
|
||||
AUDIO_100HZ = 0,
|
||||
AUDIO_200HZ,
|
||||
// AUDIO_300HZ = 0,
|
||||
AUDIO_300HZ,
|
||||
AUDIO_500HZ,
|
||||
AUDIO_1P4KHZ,
|
||||
AUDIO_1P6KHZ,
|
||||
AUDIO_1P8KHZ,
|
||||
AUDIO_2P1KHZ,
|
||||
AUDIO_2P3KHZ,
|
||||
AUDIO_2P5KHZ,
|
||||
AUDIO_2P7KHZ,
|
||||
AUDIO_2P9KHZ,
|
||||
AUDIO_3P2KHZ,
|
||||
AUDIO_3P4KHZ,
|
||||
AUDIO_3P6KHZ,
|
||||
AUDIO_3P8KHZ,
|
||||
AUDIO_4P0KHZ,
|
||||
AUDIO_4P2KHZ,
|
||||
AUDIO_4P4KHZ,
|
||||
AUDIO_4P6KHZ,
|
||||
AUDIO_4P8KHZ,
|
||||
AUDIO_5P0KHZ,
|
||||
AUDIO_5P5KHZ,
|
||||
AUDIO_6P0KHZ,
|
||||
AUDIO_6P5KHZ,
|
||||
AUDIO_7P0KHZ,
|
||||
AUDIO_7P5KHZ,
|
||||
AUDIO_8P0KHZ,
|
||||
AUDIO_8P5KHZ,
|
||||
AUDIO_9P0KHZ,
|
||||
AUDIO_9P5KHZ,
|
||||
AUDIO_10P0KHZ,
|
||||
AUDIO_OFF,
|
||||
AUDIO_FILTER_NUM
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FILTER_MODE_CW = 0,
|
||||
FILTER_MODE_SSB,
|
||||
FILTER_MODE_AM,
|
||||
FILTER_MODE_FM,
|
||||
FILTER_MODE_SAM,
|
||||
FILTER_MODE_MAX
|
||||
};
|
||||
|
||||
#define AUDIO_DEFAULT_FILTER AUDIO_2P3KHZ
|
||||
//
|
||||
// use below to define the lowest-used filter number
|
||||
//
|
||||
#define AUDIO_MIN_FILTER 0
|
||||
//
|
||||
// use below to define the highest-used filter number-1
|
||||
//
|
||||
#define AUDIO_MAX_FILTER (AUDIO_FILTER_NUM-1)
|
||||
|
||||
|
||||
typedef struct FilterDescriptor_s
|
||||
{
|
||||
const uint8_t id;
|
||||
const char* const name;
|
||||
const uint16_t width;
|
||||
} FilterDescriptor;
|
||||
|
||||
extern const FilterDescriptor FilterInfo[AUDIO_FILTER_NUM];
|
||||
extern uint16_t filterpath_mode_map[FILTER_MODE_MAX];
|
||||
|
||||
typedef struct FilterPathDescriptor_s
|
||||
{
|
||||
const uint8_t id;
|
||||
const char* name;
|
||||
const uint16_t mode;
|
||||
const uint8_t filter_select_id;
|
||||
|
||||
|
||||
// arm_fir_instance_f32*
|
||||
const uint16_t FIR_numTaps;
|
||||
const float *FIR_I_coeff_file;
|
||||
// arm_fir_instance_f32*
|
||||
const float *FIR_Q_coeff_file;
|
||||
|
||||
// arm_fir_decimate_instance_f32*
|
||||
const arm_fir_decimate_instance_f32* dec;
|
||||
|
||||
const uint8_t sample_rate_dec;
|
||||
|
||||
const arm_iir_lattice_instance_f32* pre_instance;
|
||||
const arm_fir_interpolate_instance_f32* interpolate;
|
||||
const arm_iir_lattice_instance_f32* iir_instance;
|
||||
// const arm_biquad_casd_df1_inst_f32* notch_instance;
|
||||
|
||||
const uint16_t offset; // how much offset in Hz has the center frequency of the filter from base frequency.
|
||||
// remark: this IS in fact IDENTICAL to the CENTRE FREQUENCY of the filter
|
||||
// For most non-CW filters 0 is okay,
|
||||
// in this case bandwidth/2 is being used here.
|
||||
} FilterPathDescriptor;
|
||||
|
||||
|
||||
//#define AUDIO_FILTER_PATH_NUM 87
|
||||
#define AUDIO_FILTER_PATH_NUM 107
|
||||
|
||||
extern const FilterPathDescriptor FilterPathInfo[AUDIO_FILTER_PATH_NUM];
|
||||
|
||||
enum
|
||||
{
|
||||
PATH_ALL_APPLICABLE = 0,
|
||||
PATH_NEXT_BANDWIDTH = 1,
|
||||
PATH_SAME_BANDWITH =2,
|
||||
PATH_UP = 4,
|
||||
PATH_DOWN = 8,
|
||||
PATH_USE_RULES = 16,
|
||||
PATH_LAST_USED_IN_MODE = 32,
|
||||
PATH_DONT_STORE = 64,
|
||||
};
|
||||
|
||||
uint8_t AudioFilter_NextApplicableFilterPath(const uint16_t query, const uint16_t filter_mode, const uint8_t current_path);
|
||||
bool AudioFilter_IsApplicableFilterPath(const uint16_t query, const uint16_t filter_mode, const uint8_t filter_path);
|
||||
void AudioFilter_GetNamesOfFilterPath(uint16_t filter_path,const char** filter_names);
|
||||
uint16_t AudioFilter_GetFilterModeFromDemodMode(uint8_t dmod_mode);
|
||||
uint8_t AudioFilter_NextApplicableFilter(void);
|
||||
void AudioFilter_SetDefaultMemories(void);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int a;
|
||||
float32_t b;
|
||||
float32_t sin;
|
||||
float32_t cos;
|
||||
float32_t r;
|
||||
float32_t buf[3];
|
||||
} Goertzel;
|
||||
|
||||
|
||||
void AudioFilter_CalcGoertzel(Goertzel* g, float32_t freq, const uint32_t size, const float goertzel_coeff, float32_t samplerate);
|
||||
void AudioFilter_GoertzelInput(Goertzel* goertzel, float32_t in);
|
||||
float32_t AudioFilter_GoertzelEnergy(Goertzel* goertzel);
|
||||
|
||||
#endif /* DRIVERS_AUDIO_AUDIO_FILTER_H_ */
|
||||
@@ -0,0 +1,480 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
|
||||
#include "uhsdr_board.h"
|
||||
|
||||
#include "audio_management.h"
|
||||
#include "math.h"
|
||||
#include "audio_driver.h"
|
||||
#include "softdds.h"
|
||||
#include "fm_subaudible_tone_table.h"
|
||||
#include "radio_management.h"
|
||||
|
||||
/**
|
||||
* Calculate the ALC Decay for the Tx Voice Compressor
|
||||
*/
|
||||
void AudioManagement_CalcALCDecay()
|
||||
{
|
||||
// calculate ALC decay (release) time constant - this needs to be moved to its own function (and the one in "ui_menu.c")
|
||||
ads.alc_decay = pow10f(-((((float32_t)ts.alc_decay_var)+35.0)/10.0));
|
||||
}
|
||||
|
||||
// make sure the frequencies below match the order of iq_freq_enum_t !
|
||||
|
||||
#define AUDIO_M_IQ_ADJUST_INIT(freqVal) { .freq = freqVal , .adj = { .rx = { IQ_BALANCE_OFF, IQ_BALANCE_OFF }, .tx = { { IQ_BALANCE_OFF, IQ_BALANCE_OFF }, { IQ_BALANCE_OFF,IQ_BALANCE_OFF } } } },
|
||||
|
||||
freq_adjust_point_t iq_adjust[IQ_FREQ_NUM+1] =
|
||||
{
|
||||
AUDIO_M_IQ_ADJUST_INIT( 3600000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(14100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(21100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(28100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(29650000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(52000000)
|
||||
AUDIO_M_IQ_ADJUST_INIT( 1900000)
|
||||
AUDIO_M_IQ_ADJUST_INIT( 7100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(10100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(18100000)
|
||||
AUDIO_M_IQ_ADJUST_INIT(24900000)
|
||||
// this must be last
|
||||
AUDIO_M_IQ_ADJUST_INIT(0)
|
||||
};
|
||||
|
||||
|
||||
static int32_t AudioManagement_GetBalanceValFromStruct(freq_adjust_point_t* point, iq_adjust_params_t what)
|
||||
{
|
||||
int32_t retval = IQ_BALANCE_OFF;
|
||||
switch(what)
|
||||
{
|
||||
case IQ_RX_GAIN:
|
||||
retval = point->adj.rx.gain;
|
||||
break;
|
||||
case IQ_RX_PHASE:
|
||||
retval = point->adj.rx.phase;
|
||||
break;
|
||||
case IQ_TX_TRANS_ON_GAIN:
|
||||
retval = point->adj.tx[IQ_TRANS_ON].gain;
|
||||
break;
|
||||
case IQ_TX_TRANS_OFF_GAIN:
|
||||
retval = point->adj.tx[IQ_TRANS_OFF].gain;
|
||||
break;
|
||||
case IQ_TX_TRANS_ON_PHASE:
|
||||
retval = point->adj.tx[IQ_TRANS_ON].phase;
|
||||
break;
|
||||
case IQ_TX_TRANS_OFF_PHASE:
|
||||
retval = point->adj.tx[IQ_TRANS_OFF].phase;
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param freq for which the two closest points shall be found
|
||||
* @return idx of lower frequency point, please note that the higher frequency point may be the stop value
|
||||
*/
|
||||
|
||||
static uint32_t AudioManagement_GetNextValid(freq_adjust_point_t* points, uint32_t idx, iq_adjust_params_t what)
|
||||
{
|
||||
if(!(ts.expflags2 & EXPFLAGS2_IMPROV_IQ_ADJ)) // regular I/Q adj.
|
||||
{
|
||||
// while (points[idx].freq != 0)
|
||||
while (idx <= 5)
|
||||
{
|
||||
int32_t val = AudioManagement_GetBalanceValFromStruct(&points[idx], what);
|
||||
if (val != IQ_BALANCE_OFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
else // advance I/Q adj.
|
||||
{
|
||||
uint8_t iq_adv_adj_order[] = {6, 0, 7, 8, 1, 9, 2, 10, 3, 4, 5};
|
||||
uint8_t i = 0;
|
||||
while (i <= 10)
|
||||
{
|
||||
if(idx == iq_adv_adj_order[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
int32_t val;
|
||||
while (i <= 10)
|
||||
{
|
||||
val = AudioManagement_GetBalanceValFromStruct(&points[(iq_adv_adj_order[i])], what);
|
||||
if (val != IQ_BALANCE_OFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
idx = iq_adv_adj_order[i];
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void AudioManagement_FindFreqRange(freq_adjust_point_t* points, uint32_t freq, iq_adjust_params_t what, float32_t* adj_low_ptr, float32_t* adj_high_ptr, float32_t* freq_low_ptr, float32_t* freq_high_ptr )
|
||||
{
|
||||
// AudioManagement_GetBalanceValFromStruct(&points[idx], what);
|
||||
uint32_t idx = AudioManagement_GetNextValid(points, 0, what);
|
||||
uint32_t previous_idx = idx;
|
||||
uint32_t before_previous_idx = idx;
|
||||
uint32_t valid_points = 0;
|
||||
bool found_match = false;
|
||||
|
||||
if(!(ts.expflags2 & EXPFLAGS2_IMPROV_IQ_ADJ))
|
||||
{
|
||||
// searching for the frist valid calibration point just higher than this frequency
|
||||
// while (points[idx].freq != 0)
|
||||
while (idx <= 5)
|
||||
{
|
||||
valid_points++;
|
||||
if (freq < points[idx].freq)
|
||||
{
|
||||
// we found one valid calibration point which is higher.
|
||||
// now we need to see if there is a second point if possible.
|
||||
// if the idx is not equal previous_idx, there was a valid lower frequency calibration point
|
||||
// which is nice otherwise we try to find one more higher point
|
||||
if (previous_idx == idx)
|
||||
{
|
||||
// we are lower than the lowest entry, now check if there is one more valid calibration point
|
||||
idx = AudioManagement_GetNextValid(points, idx+1, what);
|
||||
// if (points[idx].freq == 0) // stop entry
|
||||
if (idx == 5) // stop entry
|
||||
{
|
||||
// no more valid points, too bad
|
||||
idx = previous_idx; // we keep both points identical then
|
||||
}
|
||||
}
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
before_previous_idx = previous_idx;
|
||||
previous_idx = idx;
|
||||
idx = AudioManagement_GetNextValid(points, idx+1, what);
|
||||
}
|
||||
}
|
||||
else // Advanced I/Q just. We assume that advanced alignment is only needed by advanced users. We work on all alignment points.
|
||||
{
|
||||
uint8_t iq_adv_adj_order[] = {6, 0, 7, 8, 1, 9, 2, 10, 3, 4, 5};
|
||||
uint8_t i;
|
||||
uint8_t previous_i = 0;
|
||||
|
||||
if(freq <= points[(iq_adv_adj_order[0])].freq)
|
||||
{
|
||||
i = previous_i = 0;
|
||||
}
|
||||
else if(freq >= points[(iq_adv_adj_order[10])].freq)
|
||||
{
|
||||
i = previous_i = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 1;
|
||||
while (i <= 9)
|
||||
{
|
||||
if(freq == points[(iq_adv_adj_order[i])].freq)
|
||||
{
|
||||
previous_i = i;
|
||||
break;
|
||||
}
|
||||
else if(freq < points[(iq_adv_adj_order[i])].freq)
|
||||
{
|
||||
previous_i = (i - 1);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
previous_idx = iq_adv_adj_order[previous_i];
|
||||
idx = iq_adv_adj_order[i];
|
||||
}
|
||||
|
||||
if(!(ts.expflags2 & EXPFLAGS2_IMPROV_IQ_ADJ))
|
||||
{
|
||||
if (found_match == false)
|
||||
{
|
||||
if (valid_points > 1)
|
||||
{
|
||||
// we had two or more valid points, but all are below or equal the frequency
|
||||
// just use the last two valid points, idx is not a valid point but the stop entry
|
||||
idx = previous_idx;
|
||||
previous_idx = before_previous_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we had not a single valid calibration point, too bad
|
||||
// idx is same as previous_idx and both point to the last "stop" entry
|
||||
// nothing to be done now, but we handle it like the next case, makes no difference
|
||||
|
||||
// we had only one valid point, and that must be in previous_idx
|
||||
// no problem, we use it for all frequencies
|
||||
idx = previous_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*adj_high_ptr = AudioManagement_GetBalanceValFromStruct(&points[idx], what);
|
||||
*adj_low_ptr = AudioManagement_GetBalanceValFromStruct(&points[previous_idx], what);
|
||||
*freq_high_ptr = points[idx].freq;
|
||||
*freq_low_ptr = points[previous_idx].freq;
|
||||
|
||||
}
|
||||
|
||||
static float AudioManagement_CalcAdjustInFreqRangeHelperNew(freq_adjust_point_t* points, iq_adjust_params_t what, float32_t freq, float32_t scaling)
|
||||
{
|
||||
float32_t adj_low, adj_high;
|
||||
float32_t freq_low, freq_high;
|
||||
|
||||
AudioManagement_FindFreqRange(points, freq, what, &adj_low, &adj_high, &freq_low, &freq_high);
|
||||
|
||||
if (adj_high == IQ_BALANCE_OFF)
|
||||
{
|
||||
if (adj_low == IQ_BALANCE_OFF)
|
||||
{
|
||||
// no data available, set both to zero
|
||||
adj_high = adj_low = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we use the low value for both
|
||||
adj_high = adj_low;
|
||||
}
|
||||
} else if (adj_low == IQ_BALANCE_OFF)
|
||||
{
|
||||
// we use the high value for both
|
||||
adj_low = adj_high;
|
||||
}
|
||||
float32_t adj_delta = (freq_high != freq_low)? (adj_high - adj_low) / (freq_high - freq_low) * (freq - freq_low) : 0;
|
||||
|
||||
|
||||
return (adj_delta + adj_low)/scaling;
|
||||
// get current gain adjustment setting USB and other modes
|
||||
}
|
||||
|
||||
static void AudioManagement_CalcIqGainAdjustVarHelper(volatile iq_float_t* var, float32_t adj)
|
||||
{
|
||||
var->i = 1 + adj;
|
||||
var->q = 1 - adj;
|
||||
}
|
||||
|
||||
void AudioManagement_CalcIqPhaseGainAdjust(float freq)
|
||||
{
|
||||
//
|
||||
// the phase adjustment is done by mixing a little bit of I into Q or vice versa
|
||||
// this is justified because the phase shift between two signals of equal frequency can
|
||||
// be regulated by adjusting the amplitudes of the two signals!
|
||||
|
||||
ads.iq_phase_balance_rx = AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_RX_PHASE,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_PHASE_ADJUST);
|
||||
|
||||
|
||||
// please note that the RX adjustments for gain are negative
|
||||
// and the adjustments for TX (in the function AudioManagement_CalcTxIqGainAdj) are positive
|
||||
float32_t adj_i_rx = -AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_RX_GAIN,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_AMPLITUDE_ADJUST);
|
||||
|
||||
AudioManagement_CalcIqGainAdjustVarHelper(&ts.rx_adj_gain_var,adj_i_rx);
|
||||
|
||||
|
||||
ads.iq_phase_balance_tx[IQ_TRANS_ON] = AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_TX_TRANS_ON_PHASE,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_PHASE_ADJUST);
|
||||
ads.iq_phase_balance_tx[IQ_TRANS_OFF] = AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_TX_TRANS_OFF_PHASE,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_PHASE_ADJUST);
|
||||
|
||||
AudioManagement_CalcIqGainAdjustVarHelper(&ts.tx_adj_gain_var[IQ_TRANS_ON],AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_TX_TRANS_ON_GAIN,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_AMPLITUDE_ADJUST));
|
||||
|
||||
AudioManagement_CalcIqGainAdjustVarHelper(
|
||||
&ts.tx_adj_gain_var[IQ_TRANS_OFF],
|
||||
AudioManagement_CalcAdjustInFreqRangeHelperNew(
|
||||
iq_adjust,
|
||||
IQ_TX_TRANS_OFF_GAIN,
|
||||
freq,
|
||||
SCALING_FACTOR_IQ_AMPLITUDE_ADJUST));
|
||||
|
||||
|
||||
}
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
typedef struct AlcParams_s
|
||||
{
|
||||
uint32_t tx_postfilt_gain;
|
||||
uint32_t alc_decay;
|
||||
} AlcParams;
|
||||
|
||||
static const AlcParams alc_params[] =
|
||||
{
|
||||
{ 1, 15},
|
||||
{ 2, 12},
|
||||
{ 4, 10},
|
||||
{ 6, 9},
|
||||
{ 7, 8},
|
||||
{ 8, 7},
|
||||
{ 10, 6},
|
||||
{ 12, 5},
|
||||
{ 15, 4},
|
||||
{ 17, 3},
|
||||
{ 20, 2},
|
||||
{ 25, 1},
|
||||
{ 25, 0},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set TX audio compression settings (gain and ALC decay rate) based on user setting
|
||||
*/
|
||||
void AudioManagement_CalcTxCompLevel()
|
||||
{
|
||||
int16_t tx_comp_level = ts.tx_comp_level;
|
||||
|
||||
if (TX_AUDIO_COMPRESSION_MIN < tx_comp_level && tx_comp_level < TX_AUDIO_COMPRESSION_SV)
|
||||
{
|
||||
ts.alc_tx_postfilt_gain_var = alc_params[ts.tx_comp_level].tx_postfilt_gain; // restore "pristine" EEPROM values
|
||||
ts.alc_decay_var = alc_params[ts.tx_comp_level].alc_decay;
|
||||
|
||||
}
|
||||
else if (tx_comp_level == TX_AUDIO_COMPRESSION_SV) // get the speech compressor setting
|
||||
{
|
||||
// read saved values from EEPROM
|
||||
ts.alc_tx_postfilt_gain_var = ts.alc_tx_postfilt_gain; // restore "pristine" EEPROM values
|
||||
ts.alc_decay_var = ts.alc_decay;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.alc_tx_postfilt_gain_var = 4;
|
||||
ts.alc_decay_var = 10;
|
||||
}
|
||||
AudioManagement_CalcALCDecay();
|
||||
}
|
||||
|
||||
#include "fm_subaudible_tone_table.h"
|
||||
//
|
||||
//*----------------------------------------------------------------------------
|
||||
//* Function Name : UiCalcSubaudibleGenFreq
|
||||
//* Object : Calculate frequency word for subaudible tone generation [KA7OEI October, 2015]
|
||||
//* Input Parameters :
|
||||
//* Output Parameters :
|
||||
//* Functions called :
|
||||
//*----------------------------------------------------------------------------
|
||||
void AudioManagement_CalcSubaudibleGenFreq(float32_t freq)
|
||||
{
|
||||
ads.fm_conf.subaudible_tone_gen_freq = freq; // look up tone frequency (in Hz)
|
||||
softdds_setFreqDDS(&ads.fm_conf.subaudible_tone_dds, ads.fm_conf.subaudible_tone_gen_freq,ts.samp_rate,false);
|
||||
}
|
||||
|
||||
|
||||
#define FM_GOERTZEL_HIGH 1.04 // ratio of "high" detect frequency with respect to center
|
||||
#define FM_GOERTZEL_LOW 0.95 // ratio of "low" detect frequency with respect to center
|
||||
/**
|
||||
* @brief Calculate frequency word for subaudible tone, call after change of detection frequency [KA7OEI October, 2015]
|
||||
*/
|
||||
void AudioManagement_CalcSubaudibleDetFreq(float32_t freq)
|
||||
{
|
||||
const uint32_t size = AUDIO_BLOCK_SIZE;
|
||||
|
||||
ads.fm_conf.subaudible_tone_det_freq = freq; // look up tone frequency (in Hz)
|
||||
|
||||
if (freq > 0)
|
||||
{
|
||||
// Calculate Goertzel terms for tone detector(s)
|
||||
AudioFilter_CalcGoertzel(&ads.fm_conf.goertzel[FM_HIGH], ads.fm_conf.subaudible_tone_det_freq, FM_SUBAUDIBLE_GOERTZEL_WINDOW*size,FM_GOERTZEL_HIGH, IQ_SAMPLE_RATE);
|
||||
AudioFilter_CalcGoertzel(&ads.fm_conf.goertzel[FM_LOW], ads.fm_conf.subaudible_tone_det_freq, FM_SUBAUDIBLE_GOERTZEL_WINDOW*size,FM_GOERTZEL_LOW, IQ_SAMPLE_RATE);
|
||||
AudioFilter_CalcGoertzel(&ads.fm_conf.goertzel[FM_CTR], ads.fm_conf.subaudible_tone_det_freq, FM_SUBAUDIBLE_GOERTZEL_WINDOW*size,1.0, IQ_SAMPLE_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fm_tone_burst_freq[FM_TONE_BURST_MAX+1] = { 0, 1750, 2135 };
|
||||
|
||||
//
|
||||
//
|
||||
//*----------------------------------------------------------------------------
|
||||
//* Function Name : UiLoadToneBurstMode
|
||||
//* Object : Load tone burst mode [KA7OEI October, 2015]
|
||||
//* Input Parameters :
|
||||
//* Output Parameters :
|
||||
//* Functions called :
|
||||
//*----------------------------------------------------------------------------
|
||||
void AudioManagement_LoadToneBurstMode()
|
||||
{
|
||||
uint16_t frequency = 0;
|
||||
|
||||
if (ts.fm_tone_burst_mode <= FM_TONE_BURST_MAX)
|
||||
{
|
||||
frequency = fm_tone_burst_freq[ts.fm_tone_burst_mode];
|
||||
}
|
||||
|
||||
softdds_setFreqDDS(&ads.fm_conf.tone_burst_dds, frequency, ts.samp_rate, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates the sound for a given beep frequency, call after change of beep freq or before beep [KA7OEI October, 2015]
|
||||
*/
|
||||
void AudioManagement_KeyBeepPrepare()
|
||||
{
|
||||
softdds_setFreqDDS(&ads.beep, ts.beep_frequency,ts.samp_rate,false);
|
||||
|
||||
float32_t calc = (float)(ts.beep_loudness-1); // range 0-20
|
||||
calc /= 2; // range 0-10
|
||||
calc *= calc; // range 0-100
|
||||
calc += 3; // range 3-103
|
||||
ads.beep_loudness_factor = calc / 400; // range from 0.0075 to 0.2575 - multiplied by DDS output
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tell audio driver to make beeping sound [KA7OEI October, 2015]
|
||||
*/
|
||||
void AudioManagement_KeyBeep()
|
||||
{
|
||||
if((ts.flags2 & FLAGS2_KEY_BEEP_ENABLE) && (ads.beep.step > 0)) // is beep enabled and frequency non-zero?
|
||||
{
|
||||
ads.beep.acc = 0; // force reset of accumulator to start at zero to minimize "click" caused by an abrupt voltage transition at startup
|
||||
ts.beep_timing = BEEP_DURATION * (IQ_INTERRUPT_FREQ / 100); // set duration of beep and activate it
|
||||
}
|
||||
}
|
||||
|
||||
void AudioManagement_SetSidetoneForDemodMode(uint8_t dmod_mode, bool tune_mode)
|
||||
{
|
||||
float tonefreq[2] = {0.0, 0.0};
|
||||
switch(dmod_mode)
|
||||
{
|
||||
case DEMOD_CW:
|
||||
tonefreq[0] = tune_mode?CW_SIDETONE_FREQ_DEFAULT:ts.cw_sidetone_freq;
|
||||
break;
|
||||
case DEMOD_DIGI:
|
||||
if (ts.digital_mode == DigitalMode_RTTY || ts.digital_mode == DigitalMode_BPSK)
|
||||
{
|
||||
tonefreq[0] = tune_mode?CW_SIDETONE_FREQ_DEFAULT:ts.cw_sidetone_freq;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tonefreq[0] = tune_mode?SSB_TUNE_FREQ:0.0;
|
||||
|
||||
if (tune_mode && ts.tune_tone_mode == TUNE_TONE_TWO)
|
||||
{ // ARRL Standard is 700Hz and 1900Hz
|
||||
// so I temporarily changed this to SSB_TUNE_FREQ + 1200, DD4WH 2016_07_14
|
||||
// --> TWO_TONE = 750Hz and 1950Hz
|
||||
// tonefreq[1] = tune_mode?(SSB_TUNE_FREQ+600):0.0;
|
||||
tonefreq[1] = SSB_TUNE_FREQ+1200;
|
||||
}
|
||||
}
|
||||
|
||||
softdds_configRunIQ(tonefreq,ts.samp_rate,0);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef DRIVERS_AUDIO_AUDIO_MANAGEMENT_H_
|
||||
#define DRIVERS_AUDIO_AUDIO_MANAGEMENT_H_
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
void AudioManagement_CalcIqPhaseGainAdjust(float32_t freq);
|
||||
|
||||
void AudioManagement_CalcTxCompLevel(void);
|
||||
void AudioManagement_CalcNB_AGC(void);
|
||||
void AudioManagement_CalcAGCVals(void);
|
||||
void AudioManagement_CalcRFGain(void);
|
||||
void AudioManagement_CalcALCDecay(void);
|
||||
void AudioManagement_CalcAGCDecay(void);
|
||||
void AudioManagement_SetSidetoneForDemodMode(uint8_t dmod_mode, bool tune_mode);
|
||||
|
||||
void AudioManagement_LoadToneBurstMode(void);
|
||||
void AudioManagement_CalcSubaudibleGenFreq(float32_t freq); // load/set current FM subaudible tone settings for generation
|
||||
void AudioManagement_CalcSubaudibleDetFreq(float32_t freq);
|
||||
|
||||
void AudioManagement_KeyBeep(void);
|
||||
void AudioManagement_KeyBeepPrepare(void);
|
||||
|
||||
#define IQ_BALANCE_OFF -128 // Minimum setting for IQ balance
|
||||
#define IQ_BALANCE_MAX 127 // Maximum setting for IQ balance
|
||||
|
||||
#define MIN_IQ_GAIN_BALANCE IQ_BALANCE_OFF // Minimum setting for IQ gain balance
|
||||
#define MAX_IQ_GAIN_BALANCE IQ_BALANCE_MAX // Maximum setting for IQ gain balance
|
||||
|
||||
#define MIN_IQ_PHASE_BALANCE IQ_BALANCE_OFF // Minimum setting for IQ phase balance
|
||||
#define MAX_IQ_PHASE_BALANCE IQ_BALANCE_MAX // Maximum setting for IQ phase balance
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t phase;
|
||||
int32_t gain;
|
||||
} iq_adjust_balance_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IQ_RX_GAIN,
|
||||
IQ_RX_PHASE,
|
||||
IQ_TX_TRANS_ON_GAIN,
|
||||
IQ_TX_TRANS_OFF_GAIN,
|
||||
IQ_TX_TRANS_ON_PHASE,
|
||||
IQ_TX_TRANS_OFF_PHASE,
|
||||
|
||||
} iq_adjust_params_t;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
iq_adjust_balance_t rx;
|
||||
iq_adjust_balance_t tx[2];
|
||||
} iq_adjust_vals_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t freq;
|
||||
iq_adjust_vals_t adj;
|
||||
} freq_adjust_point_t;
|
||||
|
||||
|
||||
// this data structure(s) must have at least 2 elements (including the stop element)
|
||||
// corresponding frequencies are stored in const array iq_adjust_freq
|
||||
typedef enum {
|
||||
IQ_80M = 0,
|
||||
IQ_20M,
|
||||
IQ_15M,
|
||||
IQ_10M,
|
||||
IQ_10M_UP,
|
||||
IQ_6M,
|
||||
IQ_160M,
|
||||
IQ_40M,
|
||||
IQ_30M,
|
||||
IQ_17M,
|
||||
IQ_12M,
|
||||
IQ_FREQ_NUM
|
||||
} iq_freq_enum_t;
|
||||
|
||||
// the order here must match the order in the structure below!
|
||||
|
||||
extern freq_adjust_point_t iq_adjust[];
|
||||
|
||||
// For advance I/Q jusify
|
||||
//const uint8_t iq_adv_adj_order[] = {6, 0, 7, 8, 1, 9, 2, 10, 3, 4, 5};
|
||||
|
||||
#endif /* DRIVERS_AUDIO_AUDIO_MANAGEMENT_H_ */
|
||||
+2537
File diff suppressed because it is too large
Load Diff
+139
@@ -0,0 +1,139 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __AUDIO_NR_H
|
||||
#define __AUDIO_NR_H
|
||||
|
||||
#include "uhsdr_board_config.h"
|
||||
|
||||
#ifdef USE_ALTERNATE_NR
|
||||
// this contains our shared buffer structure, since FreeDV and NR are mutually exclusive
|
||||
// they can use the same set of buffers for exchanging data between audio interrupt and
|
||||
// user code
|
||||
#include "freedv_uhsdr.h"
|
||||
|
||||
#define NR_FFT_SIZE 128
|
||||
|
||||
// for the mcHF, we would uncomment all those four // !
|
||||
//#if defined(STM32F7) || defined(STM32H7)
|
||||
#define NR_FFT_L_2 (NR_FFT_SIZE * 2) // for NR FFT size 256
|
||||
//#else
|
||||
//#define NR_FFT_L_2 (NR_FFT_SIZE) // for NR FFT size 128
|
||||
//#endif
|
||||
|
||||
|
||||
|
||||
// we need another struct, because of the need for strict allocation of memory for users of the
|
||||
// mcHF hardware with small RAM (192 kb)
|
||||
typedef struct NoiseReduction2 // declaration
|
||||
{
|
||||
float32_t Hk[NR_FFT_L_2 / 2]; // gain factors
|
||||
float32_t X[NR_FFT_L_2 / 2][2]; // magnitudes of the current and the last FFT bins
|
||||
//float32_t X[NR_FFT_L/2]; // magnitudes of the current and the last FFT bins
|
||||
// float32_t long_tone_gain[NR_FFT_L_2 / 2];
|
||||
// float32_t long_tone[NR_FFT_L_2 / 2][2];
|
||||
// int VAD_delay;
|
||||
// int VAD_duration; //takes the duration of the last vowel
|
||||
// uint32_t VAD_crash_detector; // this is counted upwards during speech detection, if noise is detected, it is reset to zero
|
||||
// if it exceeds a certain limit, noise estimate is done irrespective of the VAD value
|
||||
// this helps to get the noise estimate out of a very low position --> "VAD crash"
|
||||
// uint8_t VAD_type; // 0 = Sohn et al. VAD, 1 = Esch & Vary 2009 VAD
|
||||
bool notch_change; // indicates that notch filter has to be changed
|
||||
// uint32_t long_tone_counter[NR_FFT_L_2 / 2]; // holds the notch index for every bin, the higher, the more notchworthy is a bin
|
||||
uint8_t notch1_bin; // frequency bin where notch filter 1 has to work
|
||||
uint8_t max_bin; // holds the bin number of the strongest persistent tone during tone detection
|
||||
float32_t long_tone_max; // power value of the strongest persistent tone, used for max search
|
||||
bool notch1_active; // is notch1 active?
|
||||
bool notch2_active; // is notch21 active?
|
||||
bool notch3_active; // is notch3 active?
|
||||
bool notch4_active; // is notch4 active?
|
||||
//float32_t tax; // for NR devel2: noise output smoothing time constant = -tinc/ln(0.8)
|
||||
//int16_t tax_int;
|
||||
//float32_t tap; // for NR devel2: speech prob smoothing time constant = -tinc/ln(0.9) tinc = frame time (5.33ms)
|
||||
//int16_t tap_int;
|
||||
int16_t asnr; // for NR devel2: active SNR in dB
|
||||
float32_t ax;
|
||||
float32_t ap;
|
||||
float32_t xih1;
|
||||
float32_t xih1r;
|
||||
float32_t pfac;
|
||||
int16_t snr_prio_min_int;
|
||||
float32_t snr_prio_min;
|
||||
int16_t NN;// for musical noise reduction
|
||||
int16_t width;// for musical noise reduction
|
||||
float32_t pre_power;// for musical noise reduction
|
||||
float32_t post_power;// for musical noise reduction
|
||||
float32_t power_ratio; // for musical noise reduction
|
||||
float32_t power_threshold;
|
||||
int16_t power_threshold_int;
|
||||
} NoiseReduction2;
|
||||
|
||||
extern NoiseReduction2 NR2; // declaration, definition is in audio_nr.c
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool enable; // enable spectral noise reduction
|
||||
uint8_t first_time; // set to 1 for initialization of the NR variables
|
||||
|
||||
float32_t alpha; // alpha smoothing constant for spectral noise reduction
|
||||
float32_t beta; // beta smoothing constant for spectral noise reduction
|
||||
|
||||
// bool gain_smooth_enable; // enable gain smoothing
|
||||
// float32_t gain_smooth_alpha; // smoothing constant for gain smoothing in the spectral noise reduction
|
||||
// bool long_tone_enable; // enable elimination of long tones in the spectral NR algorithm
|
||||
// float32_t long_tone_alpha; // time constant for long tone detection
|
||||
// int16_t long_tone_thresh; // threshold for long tone detection
|
||||
// bool long_tone_reset; // used to reset gains of the long tone detection to 1.0
|
||||
// int16_t vad_delay; // how many frames to delay the noise estimate after VAD has detected NOISE
|
||||
// int16_t mode;
|
||||
// float32_t vad_thresh; // threshold for voice activity detector in spectral noise reduction
|
||||
|
||||
bool fft_256_enable; // debugging: enable FFT256 instead of FFT128 for spectral NR
|
||||
|
||||
uint16_t NR_FFT_L; // resulting FFT length: 128 or 256
|
||||
uint8_t NR_FFT_LOOP_NO;
|
||||
bool NR_decimation_enable; // set to true, if we want to use another decimation step for the spectral NR leading to 6ksps sample rate
|
||||
bool NR_decimation_active; // set to true if the current buffer content is "double decimated" down to 6khz, set by the buffer producer
|
||||
|
||||
} audio_nr_params_t;
|
||||
|
||||
extern audio_nr_params_t nr_params;
|
||||
|
||||
|
||||
void NR_Init(void);
|
||||
|
||||
void AudioNr_Prepare(void);
|
||||
void AudioNr_HandleNoiseReduction(void);
|
||||
void AudioNr_ActivateAutoNotch(uint8_t notch1_bin, bool notch1_active);
|
||||
|
||||
|
||||
int NR_in_buffer_peek(NR_Buffer** c_ptr);
|
||||
int NR_in_buffer_remove(NR_Buffer** c_ptr);
|
||||
/* no room left in the buffer returns 0 */
|
||||
int NR_in_buffer_add(NR_Buffer* c);
|
||||
void NR_in_buffer_reset(void);
|
||||
int8_t NR_in_has_data(void);
|
||||
int32_t NR_in_has_room(void);
|
||||
|
||||
|
||||
int NR_out_buffer_peek(NR_Buffer** c_ptr);
|
||||
int NR_out_buffer_remove(NR_Buffer** c_ptr);
|
||||
/* no room left in the buffer returns 0 */
|
||||
int NR_out_buffer_add(NR_Buffer* c);
|
||||
void NR_out_buffer_reset(void);
|
||||
int8_t NR_out_has_data(void);
|
||||
int32_t NR_out_has_room(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,159 @@
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR Firmware **
|
||||
** O Belousov - R1CBU 2021 **
|
||||
** **
|
||||
**--------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "uhsdr_board.h"
|
||||
#include "audio_reverb.h"
|
||||
|
||||
//#define CF0 2595
|
||||
//#define CF1 2241
|
||||
//#define CF2 2911
|
||||
//#define CF3 3234
|
||||
#define DECIM 5
|
||||
|
||||
//#define AP0 480
|
||||
//#define AP1 161
|
||||
//#define AP2 46
|
||||
#define CF0 (3460 / DECIM)
|
||||
#define CF1 (2988 / DECIM)
|
||||
#define CF2 (3882 / DECIM)
|
||||
#define CF3 (4312 / DECIM)
|
||||
|
||||
#define AP0 (480 / DECIM)
|
||||
#define AP1 (161 / DECIM)
|
||||
#define AP2 (46 / DECIM)
|
||||
|
||||
static float32_t cfbuf0[CF0];
|
||||
static float32_t cfbuf1[CF1];
|
||||
static float32_t cfbuf2[CF2];
|
||||
static float32_t cfbuf3[CF3];
|
||||
|
||||
static float32_t apbuf0[AP0];
|
||||
static float32_t apbuf1[AP1];
|
||||
static float32_t apbuf2[AP2];
|
||||
|
||||
typedef struct {
|
||||
float32_t *buf;
|
||||
uint16_t index;
|
||||
uint16_t delay;
|
||||
float32_t gain;
|
||||
} item_t;
|
||||
|
||||
static float32_t wet0 = 1.0f;
|
||||
static float32_t wet1 = 0.0f;
|
||||
static float32_t result = 0.0f;
|
||||
static uint8_t decim_count = 0;
|
||||
|
||||
static item_t cf0, cf1, cf2, cf3;
|
||||
static item_t ap0, ap1, ap2;
|
||||
|
||||
static float32_t CalcComb(float32_t in, item_t *comb) {
|
||||
float32_t readback = comb->buf[comb->index];
|
||||
float32_t new = readback * comb->gain + in;
|
||||
|
||||
comb->buf[comb->index] = new;
|
||||
comb->index++;
|
||||
|
||||
if (comb->index > comb->delay)
|
||||
comb->index = 0;
|
||||
|
||||
return readback;
|
||||
}
|
||||
|
||||
static float32_t CalcAllPass(float32_t in, item_t *allpass) {
|
||||
float32_t reedback = allpass->buf[allpass->index] - allpass->gain*in;
|
||||
float32_t new = reedback*allpass->gain + in;
|
||||
|
||||
allpass->buf[allpass->index] = new;
|
||||
allpass->index++;
|
||||
|
||||
if (allpass->index > allpass->delay)
|
||||
allpass->index = 0;
|
||||
|
||||
return reedback;
|
||||
}
|
||||
|
||||
void AudioReverb_Init(void) {
|
||||
cf0.buf = (float32_t*) &cfbuf0; cf0.gain = 0.805f;
|
||||
cf1.buf = (float32_t*) &cfbuf1; cf1.gain = 0.827f;
|
||||
cf2.buf = (float32_t*) &cfbuf2; cf2.gain = 0.783f;
|
||||
cf3.buf = (float32_t*) &cfbuf3; cf3.gain = 0.764f;
|
||||
|
||||
ap0.buf = (float32_t*) &apbuf0; ap0.gain = 0.7f;
|
||||
ap1.buf = (float32_t*) &apbuf1; ap1.gain = 0.7f;
|
||||
ap2.buf = (float32_t*) &apbuf2; ap2.gain = 0.7f;
|
||||
|
||||
wet0 = 1.0f;
|
||||
wet1 = 0.0f;
|
||||
result = 0.0f;
|
||||
decim_count = 0;
|
||||
|
||||
// AudioReverb_SetDelay(1.0f);
|
||||
// AudioReverb_SetWet(0.5f);
|
||||
AudioReverb_SetDelay();
|
||||
AudioReverb_SetWet();
|
||||
}
|
||||
|
||||
//void AudioReverb_SetDelay(float32_t x) {
|
||||
// cf0.delay = (uint16_t) (x * CF0);
|
||||
// cf1.delay = (uint16_t) (x * CF1);
|
||||
// cf2.delay = (uint16_t) (x * CF2);
|
||||
// cf3.delay = (uint16_t) (x * CF3);
|
||||
//
|
||||
// ap0.delay = (uint16_t) (x * AP0);
|
||||
// ap1.delay = (uint16_t) (x * AP1);
|
||||
// ap2.delay = (uint16_t) (x * AP2);
|
||||
//}
|
||||
|
||||
void AudioReverb_SetDelay()
|
||||
{
|
||||
float32_t x = ts.reverb_delay / 100.f;
|
||||
cf0.index = 0; cf0.delay = (uint16_t) (x * CF0);
|
||||
cf1.index = 0; cf1.delay = (uint16_t) (x * CF1);
|
||||
cf2.index = 0; cf2.delay = (uint16_t) (x * CF2);
|
||||
cf3.index = 0; cf3.delay = (uint16_t) (x * CF3);
|
||||
|
||||
ap0.index = 0; ap0.delay = (uint16_t) (x * AP0);
|
||||
ap1.index = 0; ap1.delay = (uint16_t) (x * AP1);
|
||||
ap2.index = 0; ap2.delay = (uint16_t) (x * AP2);
|
||||
}
|
||||
|
||||
//void AudioReverb_SetWet(float32_t x) {
|
||||
void AudioReverb_SetWet()
|
||||
{
|
||||
float32_t x = ts.reverb_gain / 100.0f;
|
||||
wet0 = x;
|
||||
wet1 = 1.0f - x;
|
||||
}
|
||||
|
||||
float32_t AudioReverb_Calc(float32_t in)
|
||||
{
|
||||
// float32_t new = (CalcComb(in, &cf0) + CalcComb(in, &cf1) + CalcComb(in, &cf2) + CalcComb(in, &cf3)) / 4.0f;
|
||||
decim_count++;
|
||||
|
||||
if (decim_count >= DECIM)
|
||||
{
|
||||
result = (CalcComb(in, &cf0) + CalcComb(in, &cf1) + CalcComb(in, &cf2) + CalcComb(in, &cf3)) / 4.0f;
|
||||
|
||||
result = CalcAllPass(result, &ap0);
|
||||
result = CalcAllPass(result, &ap1);
|
||||
result = CalcAllPass(result, &ap2);
|
||||
|
||||
// new = CalcAllPass(new, &ap0);
|
||||
// new = CalcAllPass(new, &ap1);
|
||||
// new = CalcAllPass(new, &ap2);
|
||||
decim_count = 0;
|
||||
}
|
||||
|
||||
// return wet0 * new + wet1 * in;
|
||||
return wet0 * result + wet1 * in;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*************************************************************************************
|
||||
** **
|
||||
** UHSDR Firmware **
|
||||
** O Belousov - R1CBU 2021 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef AUDIO_AUDIO_REVERB_H_
|
||||
#define AUDIO_AUDIO_REVERB_H_
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
extern void AudioReverb_Init(void);
|
||||
//extern void AudioReverb_SetDelay(float32_t x);
|
||||
//extern void AudioReverb_SetWet(float32_t x);
|
||||
extern void AudioReverb_SetDelay();
|
||||
extern void AudioReverb_SetWet();
|
||||
float32_t AudioReverb_Calc(float32_t in);
|
||||
|
||||
#endif /* AUDIO_AUDIO_REVERB_H_ */
|
||||
+702
@@ -0,0 +1,702 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include "uhsdr_board.h"
|
||||
#include "audio_driver.h"
|
||||
#include "radio_management.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "uhsdr_hw_i2c.h"
|
||||
#include "codec.h"
|
||||
#include "uhsdr_mcu.h"
|
||||
|
||||
// I2C addresses
|
||||
#define W8731_ADDR_0 0x1A // CS = 0, MODE to GND
|
||||
#define W8731_ADDR_1 0x1B // CS = 1, MODE to GND
|
||||
|
||||
// The 7 bits Codec address (sent through I2C interface)
|
||||
#define CODEC_ADDRESS (W8731_ADDR_0<<1)
|
||||
|
||||
// Registers
|
||||
#define W8731_LEFT_LINE_IN 0x00 // 0000000
|
||||
#define W8731_RIGHT_LINE_IN 0x01 // 0000001
|
||||
#define W8731_LEFT_HEADPH_OUT 0x02 // 0000010
|
||||
#define W8731_RIGHT_HEADPH_OUT 0x03 // 0000011
|
||||
#define W8731_ANLG_AU_PATH_CNTR 0x04 // 0000100
|
||||
#define W8731_DIGI_AU_PATH_CNTR 0x05 // 0000101
|
||||
#define W8731_POWER_DOWN_CNTR 0x06 // 0000110
|
||||
#define W8731_DIGI_AU_INTF_FORMAT 0x07 // 0000111
|
||||
#define W8731_SAMPLING_CNTR 0x08 // 0001000
|
||||
#define W8731_ACTIVE_CNTR 0x09 // 0001001
|
||||
#define W8731_RESET 0x0F // 0001111
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
//#define W8731_DEEMPH_CNTR 0x06 // WM8731 codec De-emphasis enabled
|
||||
#define W8731_DEEMPH_CNTR 0x00 // WM8731 codec De-emphasis disabled
|
||||
|
||||
|
||||
#define W8731_HEADPH_OUT_ZCEN 0x0080 // bit 7 W8731_LEFT_HEADPH_OUT / W8731_RIGHT_HEADPH_OUT
|
||||
#define W8731_HEADPH_OUT_HPBOTH 0x0100 // bit 8 W8731_LEFT_HEADPH_OUT / W8731_RIGHT_HEADPH_OUT
|
||||
#define W8731_LINE_IN_LRBOTH 0x0100 // bit 8 W8731_LEFT_LINE_IN_OUT / W8731_RIGHT_LINE_IN
|
||||
|
||||
#define W8731_ANLG_AU_PATH_CNTR_DACSEL (0x10)
|
||||
#define W8731_ANLG_AU_PATH_CNTR_INSEL_MIC (0x04)
|
||||
#define W8731_ANLG_AU_PATH_CNTR_INSEL_LINE (0x00)
|
||||
#define W8731_ANLG_AU_PATH_CNTR_MUTEMIC (0x02)
|
||||
#define W8731_ANLG_AU_PATH_CNTR_MICBBOOST (0x01)
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_PHILIPS 0x02
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_PCM 0x00
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_16B (0x0 << 2)
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_20B (0x1 << 2)
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_24B (0x2 << 2)
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_32B (0x3 << 2)
|
||||
|
||||
#define W8731_DIGI_AU_INTF_FORMAT_I2S_PROTO W8731_DIGI_AU_INTF_FORMAT_PHILIPS
|
||||
|
||||
#define W8731_POWER_DOWN_CNTR_POWEROFF (0x80)
|
||||
#define W8731_POWER_DOWN_CNTR_CLKOUTPD (0x40)
|
||||
#define W8731_POWER_DOWN_CNTR_OSCPD (0x20)
|
||||
#define W8731_POWER_DOWN_CNTR_OUTPD (0x10)
|
||||
#define W8731_POWER_DOWN_CNTR_DACPD (0x08)
|
||||
#define W8731_POWER_DOWN_CNTR_ADCPD (0x04)
|
||||
#define W8731_POWER_DOWN_CNTR_MICPD (0x02)
|
||||
#define W8731_POWER_DOWN_CNTR_LINEPD (0x01)
|
||||
|
||||
#define W8731_SAMPLING_CNTR_BOSR (0x0002)
|
||||
|
||||
#define W8731_SAMPLING_CNTR_96K (0x0007 << 2)
|
||||
#define W8731_SAMPLING_CNTR_48K (0x0000 << 2)
|
||||
#define W8731_SAMPLING_CNTR_32K (0x0006 << 2)
|
||||
#define W8731_SAMPLING_CNTR_8K (0x0003 << 2)
|
||||
|
||||
|
||||
#define W8731_VOL_MAX 0x50
|
||||
|
||||
#define W8731_POWER_DOWN_CNTR_MCHF_ALL_ON (W8731_POWER_DOWN_CNTR_CLKOUTPD|W8731_POWER_DOWN_CNTR_OSCPD)
|
||||
// all on but osc and out, since we don't need it, clock comes from STM
|
||||
|
||||
#define W8731_POWER_DOWN_CNTR_MCHF_MIC_OFF (W8731_POWER_DOWN_CNTR_CLKOUTPD|W8731_POWER_DOWN_CNTR_OSCPD|W8731_POWER_DOWN_CNTR_MICPD)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool present;
|
||||
} mchf_codec_t;
|
||||
|
||||
|
||||
__IO mchf_codec_t mchf_codecs[CODEC_NUM];
|
||||
|
||||
// FIXME: for now we use 32bits transfer size, does not change the ADC/DAC resolution
|
||||
// which is 24 bits in any case. We should reduce finally to 24bits (which requires also the I2S/SAI peripheral to
|
||||
// use 24bits)
|
||||
|
||||
#if defined(USE_32_IQ_BITS)
|
||||
#define IQ_WORD_SIZE WORD_SIZE_32
|
||||
#else
|
||||
#define IQ_WORD_SIZE WORD_SIZE_16
|
||||
#endif
|
||||
|
||||
#if defined(USE_32_AUDIO_BITS)
|
||||
#define AUDIO_WORD_SIZE WORD_SIZE_32
|
||||
#else
|
||||
#define AUDIO_WORD_SIZE WORD_SIZE_16
|
||||
#endif
|
||||
|
||||
#ifdef UI_BRD_OVI40
|
||||
#include "dac.h"
|
||||
/**
|
||||
* @brief controls volume on "external" PA via DAC
|
||||
* @param vol volume in range of 0 to CODEC_SPEAKER_MAX_VOLUME
|
||||
*/
|
||||
static void AudioPA_Volume(uint8_t vol)
|
||||
{
|
||||
uint32_t lv = vol>CODEC_SPEAKER_MAX_VOLUME?CODEC_SPEAKER_MAX_VOLUME:vol;
|
||||
HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R, (lv * 4095)/CODEC_SPEAKER_MAX_VOLUME);
|
||||
}
|
||||
/**
|
||||
* @brief controls sound delivery on "external" PA via DAC
|
||||
* @param enable true == amplification, false == powerdown
|
||||
*/
|
||||
static void AudioPA_Enable(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
GPIO_SetBits(AUDIO_PA_EN_PIO,AUDIO_PA_EN);
|
||||
}
|
||||
else
|
||||
{
|
||||
GPIO_ResetBits(AUDIO_PA_EN_PIO,AUDIO_PA_EN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @brief writes 16 bit data word to codec register
|
||||
* @returns I2C error code
|
||||
*/
|
||||
static uint32_t Codec_WriteRegister(I2C_HandleTypeDef* hi2c, uint8_t RegisterAddr, uint16_t RegisterValue)
|
||||
{
|
||||
// Assemble 2-byte data in WM8731 format
|
||||
uint8_t Byte1 = ((RegisterAddr<<1)&0xFE) | ((RegisterValue>>8)&0x01);
|
||||
uint8_t Byte2 = RegisterValue&0xFF;
|
||||
return UhsdrHw_I2C_WriteRegister(hi2c, CODEC_ADDRESS, Byte1, 1, Byte2);
|
||||
}
|
||||
|
||||
static uint32_t Codec_ResetCodec(I2C_HandleTypeDef* hi2c, uint32_t AudioFreq, CodecSampleWidth_t word_size)
|
||||
{
|
||||
uint32_t retval = HAL_OK;
|
||||
|
||||
retval = Codec_WriteRegister(hi2c, W8731_RESET, 0);
|
||||
// Reset register
|
||||
if( retval == HAL_OK)
|
||||
{
|
||||
// Reg 00: Left Line In (0dB, mute off)
|
||||
Codec_WriteRegister(hi2c, W8731_LEFT_LINE_IN,0x001F);
|
||||
|
||||
// Reg 01: Right Line In (0dB, mute off)
|
||||
Codec_WriteRegister(hi2c, W8731_RIGHT_LINE_IN,0x001F);
|
||||
|
||||
// Reg 02: Left Headphone out (0dB)
|
||||
//Codec_WriteRegister(0x02,0x0079);
|
||||
// Reg 03: Right Headphone out (0dB)
|
||||
//Codec_WriteRegister(0x03,0x0079);
|
||||
|
||||
|
||||
// Reg 04: Analog Audio Path Control (DAC sel, ADC line, Mute Mic)
|
||||
Codec_WriteRegister(hi2c, W8731_ANLG_AU_PATH_CNTR,
|
||||
W8731_ANLG_AU_PATH_CNTR_DACSEL |
|
||||
W8731_ANLG_AU_PATH_CNTR_INSEL_LINE |
|
||||
W8731_ANLG_AU_PATH_CNTR_MUTEMIC);
|
||||
|
||||
// Reg 05: Digital Audio Path Control(all filters disabled)
|
||||
// De-emphasis control, bx11x - 48kHz
|
||||
// bx00x - off
|
||||
// DAC soft mute b1xxx - mute on
|
||||
// b0xxx - mute off
|
||||
//
|
||||
Codec_WriteRegister(hi2c, W8731_DIGI_AU_PATH_CNTR,W8731_DEEMPH_CNTR);
|
||||
|
||||
// Reg 06: Power Down Control (Clk off, Osc off, Mic off))
|
||||
Codec_WriteRegister(hi2c, W8731_POWER_DOWN_CNTR,W8731_POWER_DOWN_CNTR_MCHF_MIC_OFF);
|
||||
|
||||
|
||||
// Reg 07: Digital Audio Interface Format (i2s, 16/32 bit, slave)
|
||||
uint16_t size_reg_val;
|
||||
|
||||
switch(word_size)
|
||||
{
|
||||
case WORD_SIZE_32:
|
||||
size_reg_val = W8731_DIGI_AU_INTF_FORMAT_32B;
|
||||
break;
|
||||
case WORD_SIZE_24:
|
||||
size_reg_val = W8731_DIGI_AU_INTF_FORMAT_24B;
|
||||
break;
|
||||
case WORD_SIZE_16:
|
||||
default:
|
||||
size_reg_val = W8731_DIGI_AU_INTF_FORMAT_16B;
|
||||
break;
|
||||
}
|
||||
|
||||
Codec_WriteRegister(hi2c, W8731_DIGI_AU_INTF_FORMAT,W8731_DIGI_AU_INTF_FORMAT_I2S_PROTO|size_reg_val);
|
||||
|
||||
|
||||
// Reg 08: Sampling Control (Normal, 256x, 48k ADC/DAC)
|
||||
// master clock: 12.288 Mhz
|
||||
uint16_t samp_reg_val;
|
||||
|
||||
switch (AudioFreq)
|
||||
{
|
||||
case 32000:
|
||||
samp_reg_val = W8731_SAMPLING_CNTR_32K;
|
||||
break;
|
||||
case 8000:
|
||||
samp_reg_val = W8731_SAMPLING_CNTR_8K;
|
||||
break;
|
||||
case 96000:
|
||||
samp_reg_val = W8731_SAMPLING_CNTR_96K;
|
||||
break;
|
||||
case 48000:
|
||||
default:
|
||||
samp_reg_val = W8731_SAMPLING_CNTR_48K;
|
||||
break;
|
||||
}
|
||||
|
||||
Codec_WriteRegister(hi2c, W8731_SAMPLING_CNTR,samp_reg_val);
|
||||
|
||||
// Reg 09: Active Control
|
||||
// and now we start the Codec Digital Interface
|
||||
Codec_WriteRegister(hi2c, W8731_ACTIVE_CNTR,0x0001);
|
||||
}
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
#ifdef SDR_AMBER
|
||||
#ifndef UI_BRD_MCHF
|
||||
uint32_t Codec_Reset_CS4270_Codec()
|
||||
{
|
||||
uint32_t retval = HAL_OK;
|
||||
// uint32_t AudioFreq = ts.samp_rate;
|
||||
// CodecSampleWidth_t word_size = IQ_WORD_SIZE;
|
||||
|
||||
GPIO_ResetBits(BAND3_PIO, BAND3); // this port is using for CS4270 codec RESET in TRX Amber
|
||||
non_os_delay(); // we can't use HAL_Delay here
|
||||
GPIO_SetBits(BAND3_PIO, BAND3);
|
||||
|
||||
retval = Board_AmberCS4270_Write(0x02, 0x01); // total codec powerdown
|
||||
if(retval != HAL_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
non_os_delay();
|
||||
retval = Board_AmberCS4270_Write(0x02, 0x00); // total codec powerup
|
||||
|
||||
if(retval == HAL_OK)
|
||||
{
|
||||
// Board_AmberCS4270_Write(0x02, 0x02); // DAC powerdown, we need RESET just on RX
|
||||
Board_AmberCS4270_Write(0x03, 0x00); // slave, divide 1
|
||||
Board_AmberCS4270_Write(0x04, 0x09); // I2S for DAC & ADC
|
||||
Board_AmberCS4270_Write(0x05, 0x80); // DACs single volume
|
||||
Board_AmberCS4270_Write(0x06, 0x00); // Automute off
|
||||
Board_AmberCS4270_Write(0x07, 0x00); // DACs max volume
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief initializes codec
|
||||
* @param AudioFreq sample rate in Hertz
|
||||
* @param word_size should be set to WORD_SIZE_16, since we have not yet implemented any other word_size
|
||||
*/
|
||||
uint32_t Codec_Reset(uint32_t AudioFreq)
|
||||
{
|
||||
|
||||
uint32_t retval;
|
||||
#ifdef UI_BRD_MCHF
|
||||
retval = Codec_ResetCodec(CODEC_I2C, AudioFreq, IQ_WORD_SIZE);
|
||||
#else
|
||||
ts.codecWM8731_Audio_present = false;
|
||||
retval = Codec_ResetCodec(CODEC_ANA_I2C, AudioFreq, AUDIO_WORD_SIZE);
|
||||
if (retval == 0)
|
||||
{
|
||||
ts.codecWM8731_Audio_present = true;
|
||||
mchf_codecs[1].present = true;
|
||||
retval = Codec_ResetCodec(CODEC_IQ_I2C, AudioFreq, IQ_WORD_SIZE);
|
||||
}
|
||||
#endif
|
||||
if (retval == 0)
|
||||
{
|
||||
mchf_codecs[0].present = true;
|
||||
|
||||
#ifdef UI_BRD_OVI40
|
||||
AudioPA_Enable(true);
|
||||
#endif
|
||||
|
||||
Codec_VolumeSpkr(0); // mute speaker
|
||||
Codec_VolumeLineOut(ts.txrx_mode); // configure lineout according to mode
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if defined(SDR_AMBER) && defined(UI_BRD_OVI40)
|
||||
else
|
||||
{
|
||||
ts.codecCS4270_present = Codec_Reset_CS4270_Codec() == HAL_OK;
|
||||
if(ts.codecCS4270_present)
|
||||
{
|
||||
AudioPA_Enable(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call this if the twin peaks happen, this restarts the I2S audio stream and it may fix the issue
|
||||
*/
|
||||
void Codec_RestartI2S(void)
|
||||
{
|
||||
#if !defined(UI_BRD_MCHF) && defined(SDR_AMBER)
|
||||
if(ts.codecCS4270_present)
|
||||
{
|
||||
Codec_Reset_CS4270_Codec();
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
// Reg 09: Active Control
|
||||
Codec_WriteRegister(CODEC_IQ_I2C, W8731_ACTIVE_CNTR,0x0000);
|
||||
non_os_delay(); // we can't use HAL_Delay here, since our audio interrupt has higher priority which stops the ticks.
|
||||
// Reg 09: Active Control
|
||||
Codec_WriteRegister(CODEC_IQ_I2C, W8731_ACTIVE_CNTR,0x0001);
|
||||
#if !defined(UI_BRD_MCHF) && defined(SDR_AMBER)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This enables the microphone if in TX and sets gain, does nothing in RX or if audio_source is not microphone
|
||||
* @param txrx_mode the mode for which it should be configured
|
||||
*/
|
||||
void Codec_SwitchMicTxRxMode(uint8_t txrx_mode)
|
||||
{
|
||||
// only adjust the hardware if in TX txrx_mode with mic selected (it will kill RX otherwise!)
|
||||
if(txrx_mode == TRX_MODE_TX && ts.tx_audio_source == TX_AUDIO_MIC)
|
||||
{
|
||||
// Set up microphone gain and adjust mic boost accordingly
|
||||
// Reg 04: Analog Audio Path Control (DAC sel, ADC Mic, Mic on)
|
||||
|
||||
// non_os_delay();
|
||||
|
||||
if(ts.tx_gain[TX_AUDIO_MIC] > 50) // actively adjust microphone gain and microphone boost
|
||||
{
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_ANLG_AU_PATH_CNTR,
|
||||
W8731_ANLG_AU_PATH_CNTR_DACSEL |
|
||||
W8731_ANLG_AU_PATH_CNTR_INSEL_MIC|
|
||||
W8731_ANLG_AU_PATH_CNTR_MICBBOOST); // mic boost on
|
||||
|
||||
ts.tx_mic_gain_mult = (ts.tx_gain[TX_AUDIO_MIC] - 35)/3; // above 50, rescale software amplification
|
||||
}
|
||||
else
|
||||
{
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_ANLG_AU_PATH_CNTR,
|
||||
W8731_ANLG_AU_PATH_CNTR_DACSEL |
|
||||
W8731_ANLG_AU_PATH_CNTR_INSEL_MIC); // mic boost off
|
||||
|
||||
ts.tx_mic_gain_mult = ts.tx_gain[TX_AUDIO_MIC];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_microphone_active(void)
|
||||
{
|
||||
return ts.tx_audio_source == TX_AUDIO_MIC && (ts.dmod_mode != DEMOD_CW && is_demod_rtty() == false && is_demod_psk() == false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief sets certain settings in preparation for smooth TX switching, call before actual switch function is called
|
||||
* @param current_txrx_mode the current mode, not the future mode (this is assumed to be TRX_MODE_TX)
|
||||
*/
|
||||
void Codec_PrepareTx(uint8_t current_txrx_mode)
|
||||
{
|
||||
Codec_LineInGainAdj(0); // yes - momentarily mute LINE IN audio if in LINE IN mode until we have switched to TX
|
||||
|
||||
bool uses_mic_input = is_microphone_active();
|
||||
|
||||
if (uses_mic_input) // we are in MIC IN mode
|
||||
{
|
||||
ts.tx_mic_gain_mult = 0; // momentarily set the mic gain to zero while we go to TX
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_ANLG_AU_PATH_CNTR,
|
||||
W8731_ANLG_AU_PATH_CNTR_DACSEL
|
||||
| W8731_ANLG_AU_PATH_CNTR_INSEL_LINE
|
||||
| W8731_ANLG_AU_PATH_CNTR_MUTEMIC);
|
||||
// Mute the microphone with the CODEC (this does so without a CLICK) and remain/switch line in on
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_POWER_DOWN_CNTR,
|
||||
W8731_POWER_DOWN_CNTR_MCHF_ALL_ON);
|
||||
// now we power on all amps including the mic preamp and bias
|
||||
}
|
||||
|
||||
// Is translate mode active and we have NOT already muted the audio output?
|
||||
if ((ts.iq_freq_mode) && (current_txrx_mode == TRX_MODE_RX))
|
||||
{
|
||||
Codec_VolumeSpkr(0);
|
||||
Codec_VolumeLineOut(TRX_MODE_TX); // yes - mute the audio codec to suppress an approx. 6 kHz chirp when going in to TX mode
|
||||
}
|
||||
|
||||
|
||||
if (uses_mic_input)
|
||||
{
|
||||
HAL_Delay(10);
|
||||
// pause an instant because the codec chip has its own delay before tasks complete when we use the microphone input!
|
||||
// otherwise audible noise will be transmitted
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief setups up the codec according to tx/rx mode and selected sources
|
||||
* @param txrx_mode the mode for which it should be configured
|
||||
*
|
||||
*/
|
||||
void Codec_SwitchTxRxMode(uint8_t txrx_mode)
|
||||
{
|
||||
// First step - mute sound
|
||||
Codec_VolumeSpkr(0);
|
||||
Codec_VolumeLineOut(txrx_mode);
|
||||
|
||||
if(txrx_mode == TRX_MODE_RX)
|
||||
{
|
||||
// Mute line input
|
||||
Codec_LineInGainAdj(0);
|
||||
|
||||
// Reg 04: Analog Audio Path Control (DAC sel, ADC line, Mute Mic)
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_ANLG_AU_PATH_CNTR,
|
||||
W8731_ANLG_AU_PATH_CNTR_DACSEL|
|
||||
W8731_ANLG_AU_PATH_CNTR_INSEL_LINE|
|
||||
W8731_ANLG_AU_PATH_CNTR_MUTEMIC);
|
||||
|
||||
// Reg 06: Power Down Control (Clk off, Osc off, Mic Off)
|
||||
// COMMENT: It would be tempting to set bit 1 "MICPD" of "W8731_POWER_DOWN_CTR" to zero to disable mic power down
|
||||
// and maintain microphone bias during receive, but this seems to cause problems on receive (e.g. deafness) even
|
||||
// if the microphone is muted and "mic boost" is disabled. (KA7OEI 20151030)
|
||||
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_POWER_DOWN_CNTR,W8731_POWER_DOWN_CNTR_MCHF_MIC_OFF); // turn off mic bias
|
||||
}
|
||||
else // It is transmit
|
||||
{
|
||||
if(RadioManagement_UsesTxSidetone())
|
||||
{
|
||||
Codec_TxSidetoneSetgain(txrx_mode); // set sidetone level
|
||||
}
|
||||
else // Not CW or TUNE mode
|
||||
{
|
||||
|
||||
// Select source or leave it as it is
|
||||
// PHONE out is muted, normal exit routed to TX modulator
|
||||
// input audio is routed via 4066 switch
|
||||
|
||||
if(ts.tx_audio_source == TX_AUDIO_MIC)
|
||||
{
|
||||
// now enabled the analog path according to gain settings
|
||||
// with or without boost
|
||||
Codec_SwitchMicTxRxMode(txrx_mode);
|
||||
}
|
||||
else if (ts.tx_audio_source != TX_AUDIO_DIG || ts.tx_audio_source != TX_AUDIO_DIGIQ)
|
||||
{
|
||||
// we change gain only if it is not a digital tx input source
|
||||
Codec_LineInGainAdj(ts.tx_gain[ts.tx_audio_source]);
|
||||
// set LINE input gain if in LINE in mode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calculates and sets sidetone gain based on tx power factor
|
||||
*
|
||||
* This calculates the relative level of the sidetone and sets the headphone gain appropriately
|
||||
* to keep the sidetone level more or less the same.
|
||||
* This seems to be slightly "off", particularly at the extremes of high and low
|
||||
* transmit power levels - this needs to be looked into...
|
||||
*
|
||||
*/
|
||||
|
||||
void Codec_TxSidetoneSetgain(uint8_t txrx_mode)
|
||||
{
|
||||
// Note that this function is called from places OTHER than Codec_RX_TX(), above!
|
||||
|
||||
if(txrx_mode == TRX_MODE_TX) // bail out if not in transmit mode
|
||||
{
|
||||
float32_t vcalc = 0;
|
||||
|
||||
if(ts.cw_sidetone_gain) // calculate if the sidetone gain is non-zero
|
||||
{
|
||||
float32_t pf = ts.tx_power_factor; // get TX scaling power factor
|
||||
if ( pf == 0 )
|
||||
{
|
||||
pf = 0.001; // Almost zero but prevent from NoNe (1/0) in the next equation.
|
||||
}
|
||||
|
||||
float32_t signal_level_db = 10* log10f(1/(pf*pf));
|
||||
// we invert the square of power_factor (aka the signal energy)
|
||||
// since we are calculating attenuation of the original signal (assuming normalization to 1.0)
|
||||
// get the log
|
||||
// and multiple with 10 to convert to deciBels
|
||||
|
||||
float32_t sidetone_level_db = 6.0 *((float32_t)ts.cw_sidetone_gain-5);
|
||||
// get the sidetone gain (level) setting
|
||||
// offset by # of dB the desired sidetone gain
|
||||
|
||||
vcalc = signal_level_db + sidetone_level_db; // add the calculated gain to the desired sidetone gain
|
||||
|
||||
if(vcalc > 127) // enforce limits of calculation to range of attenuator
|
||||
{
|
||||
vcalc = 127;
|
||||
}
|
||||
else if (vcalc < 0)
|
||||
{
|
||||
vcalc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Codec_VolumeSpkr(vcalc/5); // divide by 5 to convert decibel to volume control steps
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief audio volume control in TX and RX modes for speaker [left headphone]
|
||||
* @param vol speaker / headphone volume in range [0 - CODEC_SPEAKER_MAX_VOLUME], unit is dB, 0 represents muting, one increment represents 5db
|
||||
*/
|
||||
|
||||
void Codec_VolumeSpkr(uint8_t vol)
|
||||
{
|
||||
#ifdef UI_BRD_MCHF
|
||||
uint32_t lv = vol*5>W8731_VOL_MAX?W8731_VOL_MAX:vol*5;
|
||||
// limit max value to 80
|
||||
|
||||
lv += 0x2F; // volume offset, all lower values including 0x2F represent muting
|
||||
// Reg 02: Speaker - variable volume, change at zero crossing in order to prevent audible clicks
|
||||
// Codec_WriteRegister(W8731_LEFT_HEADPH_OUT,lv); // (lv | W8731_HEADPH_OUT_ZCEN));
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_LEFT_HEADPH_OUT,(lv | W8731_HEADPH_OUT_ZCEN));
|
||||
#else
|
||||
// external PA Control
|
||||
AudioPA_Volume(vol);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief audio volume control in TX and RX modes for lineout [right headphone]
|
||||
*
|
||||
* At RX Lineout is always on with constant level (control via ts.lineout_gain)
|
||||
* At TX only if no frequency translation is active AND TX lineout mute is not set OR in CW
|
||||
* (because we send always without frequency translation in CW)
|
||||
*
|
||||
* @param txrx_mode txrx for which volume is to be set
|
||||
*/
|
||||
void Codec_VolumeLineOut(uint8_t txrx_mode)
|
||||
{
|
||||
|
||||
uint16_t lov = ts.lineout_gain + 0x2F;
|
||||
// Selectively mute "Right Headphone" output (LINE OUT) depending on transceiver configuration
|
||||
|
||||
#ifdef UI_BRD_MCHF
|
||||
// only needed if we have MCHF_UI which shares IQ and Audio on same codec
|
||||
// we can only "listen to the transmit output if we are send
|
||||
if (
|
||||
(txrx_mode == TRX_MODE_TX)
|
||||
&&
|
||||
((ts.flags1 & FLAGS1_MUTE_LINEOUT_TX) || (ts.iq_freq_mode && ts.dmod_mode != DEMOD_CW))
|
||||
)
|
||||
{
|
||||
// at CW we transmit without translation, no matter what the iq_freq_mode for RX is
|
||||
// is translate mode active OR translate mode OFF but LINE OUT to be muted during transmit
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_RIGHT_HEADPH_OUT,0); // yes - mute LINE OUT during transmit
|
||||
}
|
||||
else // receive mode - LINE OUT always enabled
|
||||
{
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_RIGHT_HEADPH_OUT,lov); // value selected for 0.5VRMS at AGC setting
|
||||
}
|
||||
#elif defined(UI_BRD_OVI40)
|
||||
UNUSED(txrx_mode);
|
||||
// we have a special shared lineout/headphone on the OVI40.
|
||||
// And since we have a dedidacted IQ codec, there is no need to switch of the lineout or headphones here
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_RIGHT_HEADPH_OUT, lov | W8731_HEADPH_OUT_ZCEN | W8731_HEADPH_OUT_HPBOTH ); // value selected for 0.5VRMS at AGC setting
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief mute the Codecs Digital to Analog Converter Output
|
||||
* @param state true -> mute, false -> unmute
|
||||
*/
|
||||
void Codec_MuteDAC(bool state)
|
||||
{
|
||||
if(state)
|
||||
{
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_DIGI_AU_PATH_CNTR,(W8731_DEEMPH_CNTR|0x08)); // mute
|
||||
}
|
||||
else
|
||||
{
|
||||
Codec_WriteRegister(CODEC_ANA_I2C, W8731_DIGI_AU_PATH_CNTR,(W8731_DEEMPH_CNTR)); // mute off
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Codec WM8371 line input gain for both channels
|
||||
* @param gain in range of [0-255]
|
||||
*/
|
||||
static void Codec_InGainAdj(I2C_HandleTypeDef* hi2c, uint16_t gain)
|
||||
{
|
||||
// Use Reg 00: Left Line In, set flag to adjust gain of both channels simultaneously
|
||||
Codec_WriteRegister(hi2c, W8731_LEFT_LINE_IN, gain | W8731_LINE_IN_LRBOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Codec WM8371 line input gain for both audio in channels
|
||||
* @param gain in range of [0-255]
|
||||
*/
|
||||
void Codec_LineInGainAdj(uint8_t gain)
|
||||
{
|
||||
Codec_InGainAdj(CODEC_ANA_I2C, gain);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Codec WM8371 line input gain for IQ in (both channels)
|
||||
* @param gain in range of [0-255]
|
||||
*/
|
||||
void Codec_IQInGainAdj(uint8_t gain)
|
||||
{
|
||||
#ifdef SDR_AMBER
|
||||
if(ts.codecCS4270_present) // simulation of level control at the ADC input, which is absent in the CS4270 codec
|
||||
{
|
||||
float32_t gain_t;
|
||||
switch(gain)
|
||||
{
|
||||
case 0: gain_t = 0.0188; break; // -34.5 dB
|
||||
case 1: gain_t = 0.0224; break; // -33.0 dB
|
||||
case 2: gain_t = 0.0266; break; // -31.5 dB
|
||||
case 3: gain_t = 0.0316; break; // -30.0 dB
|
||||
case 4: gain_t = 0.0376; break; // -28.5 dB
|
||||
case 5: gain_t = 0.0447; break; // -27.0 dB
|
||||
case 6: gain_t = 0.0531; break; // -25.5 dB
|
||||
case 7: gain_t = 0.0631; break; // -24.0 dB
|
||||
case 8: gain_t = 0.0750; break; // -22.5 dB
|
||||
case 9: gain_t = 0.0891; break; // -21.0 dB
|
||||
case 10: gain_t = 0.1060; break; // -19.5 dB
|
||||
case 11: gain_t = 0.1260; break; // -18.0 dB
|
||||
case 12: gain_t = 0.1500; break; // -16.5 dB
|
||||
case 13: gain_t = 0.1780; break; // -15.0 dB
|
||||
case 14: gain_t = 0.2110; break; // -13.5 dB
|
||||
case 15: gain_t = 0.2510; break; // -12.0 dB
|
||||
case 16: gain_t = 0.2990; break; // -10.5 dB
|
||||
case 17: gain_t = 0.3550; break; // -9.0 dB
|
||||
case 18: gain_t = 0.4220; break; // -7.5 dB
|
||||
case 19: gain_t = 0.5010; break; // -6.0 dB
|
||||
case 20: gain_t = 0.5960; break; // -4.5 dB
|
||||
case 21: gain_t = 0.7080; break; // -3.0 dB
|
||||
case 22: gain_t = 0.8410; break; // -1.5 dB
|
||||
case 23: gain_t = 1.0000; break; // 0 dB
|
||||
case 24: gain_t = 1.1900; break; // 1.5 dB
|
||||
case 25: gain_t = 1.4100; break; // 3.0 dB
|
||||
case 26: gain_t = 1.6800; break; // 4.5 dB
|
||||
case 27: gain_t = 2.0000; break; // 6.0 dB
|
||||
case 28: gain_t = 2.3700; break; // 7.5 dB
|
||||
case 29: gain_t = 2.8200; break; // 9.0 dB
|
||||
case 30: gain_t = 3.3500; break; // 10.5 dB
|
||||
case 31: gain_t = 4.0000; break; // 12.0 dB
|
||||
}
|
||||
ts.rf_gain_codecCS4270 = gain_t;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
Codec_InGainAdj(CODEC_IQ_I2C, gain);
|
||||
#ifdef SDR_AMBER
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if all codec resources are available for switching
|
||||
* It basically checks if the I2C is currently in use
|
||||
* This function must be called before changing the oscillator in interrupts
|
||||
* otherwise deadlocks may happen
|
||||
* @return true if it is safe to call codec functions in an interrupt
|
||||
*/
|
||||
bool Codec_ReadyForIrqCall(void)
|
||||
{
|
||||
return (CODEC_ANA_I2C->Lock == HAL_UNLOCKED) && (CODEC_IQ_I2C->Lock == HAL_UNLOCKED);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __CODEC_H
|
||||
#define __CODEC_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WORD_SIZE_16 = 0,
|
||||
WORD_SIZE_24 = 2,
|
||||
WORD_SIZE_32 = 3,
|
||||
} CodecSampleWidth_t;
|
||||
|
||||
#include "ui_configuration.h"
|
||||
#ifdef UI_BRD_MCHF
|
||||
#define CODEC_SPEAKER_MAX_VOLUME 16
|
||||
#else
|
||||
#define CODEC_SPEAKER_MAX_VOLUME AUDIO_GAIN_MAX
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief setups up the codec according to tx/rx mode and selected sources
|
||||
* @param txrx_mode the mode for which it should be configured
|
||||
*
|
||||
*/
|
||||
void Codec_SwitchTxRxMode(uint8_t txrx_mode);
|
||||
void Codec_MCUInterfaceInit(uint32_t AudioFreq);
|
||||
void Codec_VolumeLineOut(uint8_t txrx_mode);
|
||||
void Codec_VolumeSpkr(uint8_t vol);
|
||||
void Codec_LineInGainAdj(uint8_t gain);
|
||||
void Codec_IQInGainAdj(uint8_t gain);
|
||||
void Codec_MuteDAC(bool state);
|
||||
|
||||
uint32_t Codec_Reset(uint32_t AudioFreq);
|
||||
void Codec_RestartI2S(void);
|
||||
void Codec_TxSidetoneSetgain(uint8_t mode);
|
||||
void Codec_SwitchMicTxRxMode(uint8_t mode);
|
||||
void Codec_PrepareTx(uint8_t current_txrx_mode);
|
||||
|
||||
bool Codec_ReadyForIrqCall(void);
|
||||
#endif
|
||||
|
||||
#ifdef SDR_AMBER
|
||||
uint32_t Codec_Reset_CS4270_Codec(void);
|
||||
#endif
|
||||
@@ -0,0 +1,250 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "uhsdr_board.h"
|
||||
#include "profiling.h"
|
||||
#include "uhsdr_hw_i2s.h"
|
||||
|
||||
#include "audio_driver.h"
|
||||
|
||||
#ifdef UI_BRD_MCHF
|
||||
#include "i2s.h"
|
||||
#endif
|
||||
|
||||
#ifdef UI_BRD_OVI40
|
||||
#include "sai.h"
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IqSample_t out[2*IQ_BLOCK_SIZE];
|
||||
IqSample_t in[2*IQ_BLOCK_SIZE];
|
||||
} dma_iq_buffer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AudioSample_t out[2*AUDIO_BLOCK_SIZE];
|
||||
AudioSample_t in[2*AUDIO_BLOCK_SIZE];
|
||||
} dma_audio_buffer_t;
|
||||
|
||||
|
||||
// we do something tricky here:
|
||||
// if we have a single codec both buffers are in fact the same, so we use a union
|
||||
// if we have two codecs we use a struct hence two separate buffers
|
||||
|
||||
typedef
|
||||
#if CODEC_NUM == 1
|
||||
union
|
||||
#else
|
||||
struct
|
||||
#endif
|
||||
{
|
||||
dma_iq_buffer_t iq_buf;
|
||||
dma_audio_buffer_t audio_buf;
|
||||
} I2S_DmaBuffers_t;
|
||||
|
||||
static __UHSDR_DMAMEM I2S_DmaBuffers_t dma;
|
||||
|
||||
|
||||
void UhsdrHwI2s_Codec_ClearTxDmaBuffer()
|
||||
{
|
||||
memset((void*)&dma.iq_buf.out, 0, sizeof(dma.iq_buf.out));
|
||||
}
|
||||
|
||||
// #define PROFILE_APP
|
||||
static void MchfHw_Codec_HandleBlock(uint16_t which)
|
||||
{
|
||||
#ifdef PROFILE_EVENTS
|
||||
// we stop during interrupt
|
||||
// at the end we start again
|
||||
#ifdef PROFILE_APP
|
||||
profileCycleCount_stop();
|
||||
#else
|
||||
profileTimedEventStart(ProfileAudioInterrupt);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EXEC_PROFILING
|
||||
// Profiling pin (high level)
|
||||
GPIOE->BSRRL = GPIO_Pin_10;
|
||||
#endif
|
||||
|
||||
ts.audio_int_counter++; // generating a time base for encoder handling
|
||||
|
||||
// Transfer complete interrupt
|
||||
// Point to 2nd half of buffers
|
||||
const size_t sz = IQ_BLOCK_SIZE;
|
||||
const uint16_t offset = which == 0?sz:0;
|
||||
|
||||
AudioSample_t *audio;
|
||||
IqSample_t *iq;
|
||||
|
||||
if (ts.txrx_mode != TRX_MODE_TX)
|
||||
{
|
||||
iq = &dma.iq_buf.in[offset];
|
||||
audio = &dma.audio_buf.out[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
audio = &dma.audio_buf.in[offset];
|
||||
iq = &dma.iq_buf.out[offset];
|
||||
}
|
||||
|
||||
AudioSample_t *audioDst = &dma.audio_buf.out[offset];
|
||||
|
||||
// Handle
|
||||
AudioDriver_I2SCallback(audio, iq, audioDst, sz);
|
||||
|
||||
#ifdef EXEC_PROFILING
|
||||
// Profiling pin (low level)
|
||||
GPIOE->BSRRH = GPIO_Pin_10;
|
||||
#endif
|
||||
#ifdef PROFILE_EVENTS
|
||||
// we stopped during interrupt
|
||||
// now we start again
|
||||
#ifdef PROFILE_APP
|
||||
profileCycleCount_start();
|
||||
#else
|
||||
profileTimedEventStop(ProfileAudioInterrupt);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UI_BRD_MCHF
|
||||
/**
|
||||
* @brief HAL Handler for Codec DMA Interrupt
|
||||
*/
|
||||
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
|
||||
{
|
||||
MchfHw_Codec_HandleBlock(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAL Handler for Codec DMA Interrupt
|
||||
*/
|
||||
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
|
||||
{
|
||||
MchfHw_Codec_HandleBlock(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UI_BRD_OVI40
|
||||
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hi2s)
|
||||
{
|
||||
if (hi2s == &hsai_BlockA2)
|
||||
{
|
||||
MchfHw_Codec_HandleBlock(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hi2s)
|
||||
{
|
||||
if (hi2s == &hsai_BlockA2)
|
||||
{
|
||||
MchfHw_Codec_HandleBlock(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(UI_BRD_OVI40) && defined(USE_32_IQ_BITS) && defined(USE_32_AUDIO_BITS)
|
||||
static void UhsdrHWI2s_Sai32Bits(SAI_HandleTypeDef* hsai)
|
||||
{
|
||||
hsai->hdmarx->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||
hsai->hdmarx->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||
HAL_DMA_Init(hsai->hdmarx);
|
||||
|
||||
HAL_SAI_InitProtocol(hsai, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_32BIT, 2);
|
||||
}
|
||||
|
||||
static void UhsdrHWI2s_Sai24Bits(SAI_HandleTypeDef* hsai)
|
||||
{
|
||||
hsai->hdmarx->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||
hsai->hdmarx->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||
HAL_DMA_Init(hsai->hdmarx);
|
||||
|
||||
HAL_SAI_InitProtocol(hsai, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_24BIT, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void UhsdrHwI2s_SetBitWidth(void)
|
||||
{
|
||||
#if defined(USE_32_IQ_BITS)
|
||||
#if defined(UI_BRD_MCHF)
|
||||
hi2s3.Init.DataFormat = I2S_DATAFORMAT_32B;
|
||||
HAL_I2S_Init(&hi2s3);
|
||||
#endif
|
||||
#if defined(UI_BRD_OVI40)
|
||||
if(ts.codecCS4270_present)
|
||||
{
|
||||
UhsdrHWI2s_Sai24Bits(&hsai_BlockA2);
|
||||
UhsdrHWI2s_Sai24Bits(&hsai_BlockB2);
|
||||
}
|
||||
else
|
||||
{
|
||||
UhsdrHWI2s_Sai32Bits(&hsai_BlockA2);
|
||||
UhsdrHWI2s_Sai32Bits(&hsai_BlockB2);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_32_AUDIO_BITS)
|
||||
#if defined(UI_BRD_OVI40)
|
||||
UhsdrHWI2s_Sai32Bits(&hsai_BlockA1);
|
||||
UhsdrHWI2s_Sai32Bits(&hsai_BlockB1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UhsdrHwI2s_Codec_StartDMA()
|
||||
{
|
||||
UhsdrHwI2s_SetBitWidth();
|
||||
|
||||
#ifdef UI_BRD_MCHF
|
||||
HAL_I2SEx_TransmitReceive_DMA(&hi2s3,(uint16_t*)dma.iq_buf.out,(uint16_t*)dma.iq_buf.in,sizeof(dma.iq_buf.in)/sizeof(dma.iq_buf.in[0].l));
|
||||
#endif
|
||||
#ifdef UI_BRD_OVI40
|
||||
// we clean the buffers since we don't know if we are in a "cleaned" memory segement
|
||||
memset((void*)&dma.audio_buf,0,sizeof(dma.audio_buf));
|
||||
memset((void*)&dma.iq_buf,0,sizeof(dma.iq_buf));
|
||||
|
||||
HAL_SAI_Receive_DMA(&hsai_BlockA1,(uint8_t*)dma.audio_buf.in,sizeof(dma.audio_buf.in)/sizeof(dma.audio_buf.in[0].l));
|
||||
HAL_SAI_Transmit_DMA(&hsai_BlockB1,(uint8_t*)dma.audio_buf.out,sizeof(dma.audio_buf.out)/sizeof(dma.audio_buf.out[0].l));
|
||||
|
||||
HAL_SAI_Receive_DMA(&hsai_BlockA2,(uint8_t*)dma.iq_buf.in,sizeof(dma.iq_buf.in)/sizeof(dma.iq_buf.in[0].l));
|
||||
HAL_SAI_Transmit_DMA(&hsai_BlockB2,(uint8_t*)dma.iq_buf.out,sizeof(dma.iq_buf.out)/sizeof(dma.iq_buf.out[0].l));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void UhsdrHwI2s_Codec_StopDMA(void)
|
||||
{
|
||||
#ifdef UI_BRD_MCHF
|
||||
HAL_I2S_DMAStop(&hi2s3);
|
||||
#endif
|
||||
#ifdef UI_BRD_OVI40
|
||||
HAL_SAI_DMAStop(&hsai_BlockA1);
|
||||
HAL_SAI_DMAStop(&hsai_BlockB1);
|
||||
HAL_SAI_DMAStop(&hsai_BlockA2);
|
||||
HAL_SAI_DMAStop(&hsai_BlockB2);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __MCHF_HW_I2S_H
|
||||
#define __MCHF_HW_I2S_H
|
||||
|
||||
#include "uhsdr_board_config.h"
|
||||
|
||||
void UhsdrHwI2s_Codec_StartDMA(void);
|
||||
void UhsdrHwI2s_Codec_StopDMA(void);
|
||||
|
||||
void UhsdrHwI2s_Codec_ClearTxDmaBuffer(void);
|
||||
|
||||
#endif
|
||||
|
||||
+1108
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* cw_decoder.h
|
||||
*
|
||||
* Created on: 07.09.2017
|
||||
* Author: danilo
|
||||
*/
|
||||
|
||||
#ifndef AUDIO_CW_CW_DECODER_H_
|
||||
#define AUDIO_CW_CW_DECODER_H_
|
||||
|
||||
#define CW_DECODER_BLOCKSIZE_MIN 8
|
||||
#define CW_DECODER_BLOCKSIZE_MAX 128
|
||||
#define CW_DECODER_BLOCKSIZE_DEFAULT 88
|
||||
|
||||
#define CW_DECODER_THRESH_MIN 1000
|
||||
#define CW_DECODER_THRESH_MAX 50000
|
||||
#define CW_DECODER_THRESH_DEFAULT 32000
|
||||
|
||||
#define CW_DECODER_FLAGS_DEFAULT (0b110001) // NOISECANCEL_ENABLE, SNAP_ENABLE, SHOW_CW_LED
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t sampling_freq;
|
||||
float32_t target_freq;
|
||||
// float32_t speed;
|
||||
uint8_t speed;
|
||||
// uint8_t average;
|
||||
uint32_t thresh;
|
||||
uint8_t blocksize;
|
||||
|
||||
// uint8_t AGC_enable;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t noisecancel_enable:1;
|
||||
uint16_t spikecancel:2;
|
||||
#define CW_SPIKECANCEL_MODE_OFF 0
|
||||
#define CW_SPIKECANCEL_MODE_SPIKE 1
|
||||
#define CW_SPIKECANCEL_MODE_SHORT 2
|
||||
uint16_t use_3_goertzels:1;
|
||||
uint16_t snap_enable:1;
|
||||
uint16_t show_CW_LED:1; // menu choice whether the user wants the CW LED indicator to be working or not
|
||||
};
|
||||
uint16_t flags;
|
||||
};
|
||||
} cw_config_t;
|
||||
|
||||
extern cw_config_t cw_decoder_config;
|
||||
|
||||
|
||||
void CwDecode_RxProcessor(float32_t * const src, int16_t blockSize);
|
||||
void CwDecode_Filter_Set(void);
|
||||
//void CW_Decoder_WPM_display_erase(void);
|
||||
void CwDecoder_WpmDisplayUpdate(bool force_update);
|
||||
void CwDecoder_WpmDisplayClearOrPrepare(bool prepare);
|
||||
|
||||
#endif /* AUDIO_CW_CW_DECODER_H_ */
|
||||
+1100
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#ifndef __CW_GEN_H
|
||||
#define __CW_GEN_H
|
||||
|
||||
#include "arm_math.h"
|
||||
|
||||
void CwGen_Init(void);
|
||||
|
||||
void CwGen_PrepareTx(void);
|
||||
void CwGen_SetSpeed(void);
|
||||
|
||||
bool CwGen_Process( float32_t *i_buffer, float32_t *q_buffer, uint32_t size );
|
||||
|
||||
// As showed tests calling them (CwGen_DahIRQ & CwGen_DitIRQ) is matter only for Ultimatic mode.
|
||||
// After change code to work in this mode w/o them, these extra dependencies with low-level layers could be removed.
|
||||
void CwGen_DahIRQ(void);
|
||||
void CwGen_DitIRQ(void);
|
||||
|
||||
uint8_t CwGen_CharacterIdFunc( uint32_t );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**--------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Description: Please provide one **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#include <assert.h>
|
||||
#include "ui_driver.h" // for pushing into UI buffer
|
||||
#include "uhsdr_digi_buffer.h"
|
||||
|
||||
#define DIGIMODES_TX_BUFFER_SIZE 128
|
||||
|
||||
static __IO uint8_t digimodes_tx_buffer[DIGIMODES_TX_BUFFER_SIZE];
|
||||
static __IO int32_t digimodes_tx_buffer_head = 0;
|
||||
static __IO int32_t digimodes_tx_tail = 0;
|
||||
static __IO uint32_t active_consumer = 0;
|
||||
|
||||
// keeps prev consumer to restore it by calling DigiModes_Restore_BufferConsumer();
|
||||
static __IO uint32_t prev_consumer = CW;
|
||||
|
||||
void DigiModes_Restore_BufferConsumer()
|
||||
{
|
||||
active_consumer = prev_consumer;
|
||||
}
|
||||
|
||||
/*
|
||||
* The UI consumer has higher priority to protect it by changing modes.
|
||||
* UI should release buffer by calling DigiModes_Restore_BufferConsumer()
|
||||
*/
|
||||
digi_buff_consumer_t DigiModes_Set_BufferConsumer( digi_buff_consumer_t consumer )
|
||||
{
|
||||
assert((consumer & RTTY) || (consumer & BPSK) || (consumer & CW) || (consumer & UI));
|
||||
if ( active_consumer == UI ) // <- UI has higher priority
|
||||
{
|
||||
prev_consumer = consumer; // in case we change mode
|
||||
return prev_consumer;
|
||||
}
|
||||
prev_consumer = active_consumer;
|
||||
active_consumer = consumer;
|
||||
return prev_consumer;
|
||||
}
|
||||
|
||||
uint8_t DigiModes_TxBufferHasData()
|
||||
{
|
||||
int32_t len = digimodes_tx_buffer_head - digimodes_tx_tail;
|
||||
return len < 0 ? ( len + DIGIMODES_TX_BUFFER_SIZE ) : len;
|
||||
}
|
||||
|
||||
bool DigiModes_TxBufferRemove( uint8_t* c_ptr, digi_buff_consumer_t consumer )
|
||||
{
|
||||
assert( c_ptr );
|
||||
assert((consumer & RTTY) || (consumer & BPSK) || (consumer & CW) || (consumer & UI));
|
||||
|
||||
bool retval = false;
|
||||
|
||||
if ( consumer == active_consumer && digimodes_tx_buffer_head != digimodes_tx_tail)
|
||||
{
|
||||
*c_ptr = digimodes_tx_buffer[digimodes_tx_tail];
|
||||
digimodes_tx_tail = (digimodes_tx_tail + 1) % DIGIMODES_TX_BUFFER_SIZE;
|
||||
|
||||
// push removed char to UI buffer to display it on the screen.
|
||||
// characters for UI and CW prints when they add to digi_buffer
|
||||
if ( active_consumer == RTTY || active_consumer == BPSK )
|
||||
{
|
||||
UiDriver_TextMsgPutChar( *c_ptr );
|
||||
}
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* no room left in the buffer returns 0 */
|
||||
int32_t DigiModes_TxBufferPutChar( uint8_t c, digi_buff_consumer_t source )
|
||||
{
|
||||
assert((source & CW) || (source & KeyBoard) || (source & UI));
|
||||
|
||||
int32_t ret = 0;
|
||||
/*
|
||||
* In case when source and consumer are equal we just
|
||||
* print on the screen without putting into digi_buffer
|
||||
* to prevent from infinite loop
|
||||
* ( CW working as a source and receiver at the same time )
|
||||
*/
|
||||
if ( active_consumer == source )
|
||||
{
|
||||
if(!(ts.dmod_mode == DEMOD_CW && !ts.cw_decoder_enable))
|
||||
{
|
||||
UiDriver_TextMsgPutChar( c );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t next_head = (digimodes_tx_buffer_head + 1) % DIGIMODES_TX_BUFFER_SIZE;
|
||||
if (next_head != digimodes_tx_tail)
|
||||
{
|
||||
/* there is room */
|
||||
digimodes_tx_buffer[digimodes_tx_buffer_head] = c;
|
||||
digimodes_tx_buffer_head = next_head;
|
||||
/*
|
||||
* If the consumer is UI we print on the screen
|
||||
* right the way on the inputing text into buffer
|
||||
*/
|
||||
if ( active_consumer == UI )
|
||||
{
|
||||
if(!(ts.dmod_mode == DEMOD_CW && !ts.cw_decoder_enable))
|
||||
{
|
||||
UiDriver_TextMsgPutChar( c );
|
||||
}
|
||||
}
|
||||
ret ++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DigiModes_TxBufferPutSign( const char* s, digi_buff_consumer_t source )
|
||||
{
|
||||
assert( s );
|
||||
assert((source & CW) || (source & KeyBoard));
|
||||
|
||||
DigiModes_TxBufferPutChar( '<', source );
|
||||
DigiModes_TxBufferPutChar( s[0], source );
|
||||
DigiModes_TxBufferPutChar( s[1], source );
|
||||
DigiModes_TxBufferPutChar( '>', source );
|
||||
}
|
||||
|
||||
void DigiModes_TxBufferReset()
|
||||
{
|
||||
digimodes_tx_tail = digimodes_tx_buffer_head;
|
||||
}
|
||||
|
||||
#if defined(_UNIT_TEST_)
|
||||
uint32_t DigiModes_TxBufferGetCurrentConsumer( void )
|
||||
{
|
||||
return active_consumer;
|
||||
}
|
||||
uint32_t DigiModes_TxBufferGetPrevConsumer( void )
|
||||
{
|
||||
return prev_consumer;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**--------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Description: Please provide one **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __UHSDR_DIGI_BUFFER_H
|
||||
#define __UHSDR_DIGI_BUFFER_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTTY = 1,
|
||||
BPSK = 2,
|
||||
CW = 4,
|
||||
UI = 8,
|
||||
KeyBoard = 16, // <- keyboard should be used as a source only
|
||||
} digi_buff_consumer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint8_t DigiModes_TxBufferHasData(void);
|
||||
|
||||
/*
|
||||
* The Digi buffer has multi consumers, some of them trying to get an entry
|
||||
* from the buffer at the same time.
|
||||
* to organize it, the allowed consumer for buffer should be set before using it.
|
||||
*
|
||||
* @return - previous consumer
|
||||
*/
|
||||
digi_buff_consumer_t DigiModes_Set_BufferConsumer( digi_buff_consumer_t consumer );
|
||||
void DigiModes_Restore_BufferConsumer(void);
|
||||
|
||||
/*
|
||||
* @return - true if element was removed from buffer and available in c_ptr
|
||||
* false if there is no elements in buffer or this consumer not
|
||||
* allowed to remove elements from buffer.
|
||||
*/
|
||||
bool DigiModes_TxBufferRemove( uint8_t* c_ptr, digi_buff_consumer_t consumer );
|
||||
|
||||
int32_t DigiModes_TxBufferPutChar( uint8_t c, digi_buff_consumer_t source );
|
||||
void DigiModes_TxBufferPutSign( const char* s, digi_buff_consumer_t source );
|
||||
|
||||
void DigiModes_TxBufferReset( );
|
||||
|
||||
#if defined(_UNIT_TEST_)
|
||||
uint32_t DigiModes_TxBufferGetCurrentConsumer( void );
|
||||
uint32_t DigiModes_TxBufferGetPrevConsumer( void );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // __UHSDR_DIGI_BUFFER_H
|
||||
@@ -0,0 +1,174 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
#ifndef _filters_h_
|
||||
#define _filters_h_
|
||||
|
||||
#include "uhsdr_board.h"
|
||||
#include "arm_math.h"
|
||||
|
||||
#define IQ_RX_BLOCK_SIZE IQ_BLOCK_SIZE
|
||||
#define IQ_RX_NUM_TAPS 89
|
||||
|
||||
#define IQ_RX_NUM_TAPS_HI 199
|
||||
#define IQ_RX_NUM_TAPS_LO 31
|
||||
|
||||
//#define IQ_RX_NUM_TAPS_HI 121
|
||||
//#define IQ_RX_NUM_TAPS_MAX 121
|
||||
#define IQ_RX_NUM_TAPS_MAX 199
|
||||
//#define IQ_RX_NUM_TAPS_HI 499
|
||||
//#define IQ_RX_NUM_TAPS_MAX 499
|
||||
|
||||
#define FIR_TX_FREEDV_INTERPOLATE_NUM_TAPS 30
|
||||
|
||||
typedef struct {
|
||||
const float32_t* i;
|
||||
const float32_t* q;
|
||||
const int num_taps;
|
||||
} IQ_FilterDescriptor;
|
||||
|
||||
extern const arm_fir_decimate_instance_f32 FirRxDecimate;
|
||||
extern const arm_fir_decimate_instance_f32 FirRxDecimate_sideband_supp;
|
||||
extern const arm_fir_decimate_instance_f32 FirZoomFFTDecimate[6];
|
||||
extern const arm_fir_decimate_instance_f32 FirRxDecimateMinLPF;
|
||||
extern const arm_fir_interpolate_instance_f32 FirRxInterpolate;
|
||||
extern const arm_fir_interpolate_instance_f32 FirRxInterpolate_4_5k;
|
||||
extern const arm_fir_interpolate_instance_f32 FirRxInterpolate_4_10k;
|
||||
extern const arm_fir_interpolate_instance_f32 FirRxInterpolate10KHZ;
|
||||
extern const arm_fir_instance_f32 Fir_TxFreeDV_Interpolate;
|
||||
extern const float Fir_Rx_FreeDV_Interpolate_Coeffs[24];
|
||||
|
||||
extern const float iq_rx_am_10k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_2k3_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_3k6_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_5k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_4k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_6k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float iq_rx_am_7k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
|
||||
extern const float i_rx_10k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_3k6_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_4k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_5k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_6k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_7k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
//extern const float i_rx_coeffs[IQ_NUM_TAPS];
|
||||
extern const float i_rx_wow_coeffs[IQ_RX_NUM_TAPS_HI];
|
||||
extern const float i_rx_new_coeffs[IQ_RX_NUM_TAPS_HI];
|
||||
extern const float i_rx_FREEDV_700D_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_FREEDV_700D_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float i_rx_FREEDV_700D_F4_coeffs[IQ_RX_NUM_TAPS_LO];
|
||||
extern const float q_rx_FREEDV_700D_F4_coeffs[IQ_RX_NUM_TAPS_LO];
|
||||
|
||||
extern const float q_rx_new_coeffs[IQ_RX_NUM_TAPS_HI];
|
||||
extern const float q_rx_wow_coeffs[IQ_RX_NUM_TAPS_HI];
|
||||
//extern const float q_rx_coeffs[IQ_NUM_TAPS];
|
||||
extern const float q_rx_10k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_3k6_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_4k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_5k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_6k_coeffs[IQ_RX_NUM_TAPS];
|
||||
extern const float q_rx_7k5_coeffs[IQ_RX_NUM_TAPS];
|
||||
|
||||
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k4_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k4_BPF;
|
||||
//extern const arm_iir_lattice_instance_f32 IIR_1k4_SSTV;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k6_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k6_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_1k425;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_1k275;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_1k125;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_1k575;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_1k725;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_1k8_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_10k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_10k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_15k_hpf;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_15k_hpf;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k1_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k1_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k3_1k412;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k3_1k275;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k3_1k562;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k3_1k712;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k3_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k5_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k7_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k7_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k9_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_2k9_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_2k7;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_WIDE_BASS;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_WIDE_TREBLE;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_SOPRANO;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_eSSB_4k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_eSSB_5k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_eSSB_6k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_TX_2k7_FM;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k2_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k2_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k4_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k4_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k6_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k6_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k8_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k8_BPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_500;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_550;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_600;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_650;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_700;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_750;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_800;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_850;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_900;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_100hz_950;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_500;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_550;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_600;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_650;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_700;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_750;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_800;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_850;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_900;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_200hz_950;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_750;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_800;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_850;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_900;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_950;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_700;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_650;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_600;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_550;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_300hz_500;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_3k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_4k2_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_4k4_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_4k6_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_4k8_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_4k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_5k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_500hz_750;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_500hz_850;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_500hz_950;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_500hz_650;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_500hz_550;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_5k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_6k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_6k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_7k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_7k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_8k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_8k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_8k5_hpf;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_9k5_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_9k_LPF;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_5k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_10k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_8k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_8k5;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_9k;
|
||||
extern const arm_iir_lattice_instance_f32 IIR_aa_9k5;
|
||||
#endif
|
||||
@@ -0,0 +1,184 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** License: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
/**************************************************************
|
||||
|
||||
KA7OEI, November, 2014
|
||||
|
||||
IMPORTANT NOTE:
|
||||
|
||||
This is a MINIMAL FIR Lowpass filter that is applied to the RX input
|
||||
decimation. It is NOT designed to provide any significant filtering!
|
||||
|
||||
The majority of anti-aliasing for this decimation operation is provided BY the
|
||||
Phase-Added Hilbert Transformer that PRECEDES this!
|
||||
|
||||
This is an absolutely minimized operation to reduce processor overhead!
|
||||
|
||||
Response:
|
||||
|
||||
DC-2370 Hz: >=-0.25dB
|
||||
-1dB @ 3492 Hz
|
||||
-3dB @ 5320 Hz
|
||||
-6dB @ 6958 Hz
|
||||
-10dB @ 8396 Hz
|
||||
Notch @ 10767 Hz with -20dB points at 10000 and 11598 Hz.
|
||||
Min. -7.6dB @ 16.4 kHz
|
||||
-20dB > 22.9 kHz
|
||||
|
||||
|
||||
|
||||
***************************************************************/
|
||||
|
||||
//const arm_fir_decimate_instance_f32 FirRxDecimate =
|
||||
//{
|
||||
// .numTaps = 4,
|
||||
// .pCoeffs = (float*) (const float[])
|
||||
// {
|
||||
// -0.3105711170561,
|
||||
// -0.2100034101786,
|
||||
// -0.2099936469089,
|
||||
// -0.3105557871709
|
||||
// }
|
||||
//};
|
||||
|
||||
|
||||
|
||||
// this is the decimation filter used for decimating the I and the Q path
|
||||
// when in CW/SSB mode and filter BW <= 3k6
|
||||
// 48ksps, 43 taps
|
||||
// Fc=3.6kHz 0.1500
|
||||
// Kaiser Beta 2.20, Raised Cosine 0.750
|
||||
const arm_fir_decimate_instance_f32 FirRxDecimate =
|
||||
{
|
||||
.numTaps = 43,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-596.2286796599541960E-6,-927.3655504344595780E-6,-940.6330523057968090E-6,-298.4871913266846950E-6, 0.001186311749146407, 0.003340717388857422, 0.005503534826465819, 0.006586352026602872, 0.005378691189561175, 0.001056745384724361,-0.006253091035763602,-0.015078013363837874,-0.022588392594615103,-0.025094197603292432,-0.018999101368626720,-0.001976514919694041, 0.025998282705991884, 0.062138450304126999, 0.101110564031515582, 0.136092352983227610, 0.160375863194488072, 0.169067382812500000, 0.160375863194488072, 0.136092352983227610, 0.101110564031515582, 0.062138450304126999, 0.025998282705991884,-0.001976514919694041,-0.018999101368626720,-0.025094197603292432,-0.022588392594615103,-0.015078013363837874,-0.006253091035763602, 0.001056745384724361, 0.005378691189561175, 0.006586352026602872, 0.005503534826465819, 0.003340717388857422, 0.001186311749146407,-298.4871913266846950E-6,-940.6330523057968090E-6,-927.3655504344595780E-6,-596.2286796599541960E-6
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
|
||||
// this is an antialias lowpass filter for the first filter instance before the decimation
|
||||
// 48ksps, 83 taps
|
||||
// Fc=3.6kHz 0.1500
|
||||
// Kaiser Beta 2.20, Raised Cosine 0.780
|
||||
// --> stopband suppression > 70dB [> 5.5kHz]
|
||||
const arm_fir_decimate_instance_f32 FirRxDecimate_sideband_supp =
|
||||
{
|
||||
.numTaps = 83,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-69.04572960222937180E-6,-137.6834398584523170E-6,-186.3970280457814400E-6,-181.9425732680219880E-6,-104.7375909552678900E-6, 37.22776946454347070E-6, 204.5969072113929600E-6, 337.6430886700526340E-6, 380.2712946166168420E-6, 308.0147076442374330E-6, 146.5458495799618390E-6,-31.48113457454075360E-6,-135.5241548808152460E-6,-104.1622729286465440E-6, 49.66097981004921280E-6, 219.8972970987902040E-6, 234.0369712091759310E-6,-72.92696579416441690E-6,-758.2621215486242360E-6,-0.001685885336453723,-0.002502896255855177,-0.002712504642547770,-0.001844951124000482, 314.9034535895095810E-6, 0.003522159070787864, 0.006982502500958138, 0.009453648049644431, 0.009558702320444503, 0.006257513701590612,-650.2918349336806610E-6,-0.010158967215772004,-0.019985981030678633,-0.026889297155700119,-0.027354668266382533,-0.018512617437158409, 950.1502355180025460E-6, 0.030152564469343023, 0.065873978372928979, 0.103000681197519150, 0.135500724389660737, 0.157707975855713750, 0.165595703121596383, 0.157707975855713750, 0.135500724389660737, 0.103000681197519150, 0.065873978372928979, 0.030152564469343023, 950.1502355180025460E-6,-0.018512617437158409,-0.027354668266382533,-0.026889297155700119,-0.019985981030678633,-0.010158967215772004,-650.2918349336806610E-6, 0.006257513701590612, 0.009558702320444503, 0.009453648049644431, 0.006982502500958138, 0.003522159070787864, 314.9034535895095810E-6,-0.001844951124000482,-0.002712504642547770,-0.002502896255855177,-0.001685885336453723,-758.2621215486242360E-6,-72.92696579416441690E-6, 234.0369712091759310E-6, 219.8972970987902040E-6, 49.66097981004921280E-6,-104.1622729286465440E-6,-135.5241548808152460E-6,-31.48113457454075360E-6, 146.5458495799618390E-6, 308.0147076442374330E-6, 380.2712946166168420E-6, 337.6430886700526340E-6, 204.5969072113929600E-6, 37.22776946454347070E-6,-104.7375909552678900E-6,-181.9425732680219880E-6,-186.3970280457814400E-6,-137.6834398584523170E-6,-69.04572960222937180E-6
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
|
||||
// this is the decimation filter used for decimating the I and the Q path
|
||||
// when in CW/SSB mode and filter BW <= 3k6
|
||||
// 48ksps, 43 taps
|
||||
// Fc=3.6kHz 0.1500
|
||||
// Kaiser Beta 2.20, Raised Cosine 0.750
|
||||
|
||||
//const arm_fir_decimate_instance_f32 FirRxDecimate_sideband_supp =
|
||||
//{
|
||||
// .numTaps = 43,
|
||||
// .pCoeffs = (float*) (const float[])
|
||||
// {
|
||||
// -596.2286796599541960E-6,-927.3655504344595780E-6,-940.6330523057968090E-6,-298.4871913266846950E-6, 0.001186311749146407, 0.003340717388857422, 0.005503534826465819, 0.006586352026602872, 0.005378691189561175, 0.001056745384724361,-0.006253091035763602,-0.015078013363837874,-0.022588392594615103,-0.025094197603292432,-0.018999101368626720,-0.001976514919694041, 0.025998282705991884, 0.062138450304126999, 0.101110564031515582, 0.136092352983227610, 0.160375863194488072, 0.169067382812500000, 0.160375863194488072, 0.136092352983227610, 0.101110564031515582, 0.062138450304126999, 0.025998282705991884,-0.001976514919694041,-0.018999101368626720,-0.025094197603292432,-0.022588392594615103,-0.015078013363837874,-0.006253091035763602, 0.001056745384724361, 0.005378691189561175, 0.006586352026602872, 0.005503534826465819, 0.003340717388857422, 0.001186311749146407,-298.4871913266846950E-6,-940.6330523057968090E-6,-927.3655504344595780E-6,-596.2286796599541960E-6
|
||||
// }
|
||||
//};
|
||||
|
||||
|
||||
const arm_fir_decimate_instance_f32 FirZoomFFTDecimate[] =
|
||||
{
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.3105711170561,
|
||||
-0.2100034101786,
|
||||
-0.2099936469089,
|
||||
-0.3105557871709
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
},
|
||||
// 48ksps, 12kHz lowpass
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
475.1179397144384210E-6,
|
||||
0.503905202786044337,
|
||||
0.503905202786044337,
|
||||
475.1179397144384210E-6
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
},
|
||||
// 48ksps, 6kHz lowpass
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.198273254218889416,
|
||||
0.298085149879260325,
|
||||
0.298085149879260325,
|
||||
0.198273254218889416
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
},
|
||||
// 48ksps, 3kHz lowpass
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.199820836596682871,
|
||||
0.272777397353925699,
|
||||
0.272777397353925699,
|
||||
0.199820836596682871
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
},
|
||||
// 48ksps, 1.5kHz lowpass
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.199820836596682871,
|
||||
0.272777397353925699,
|
||||
0.272777397353925699,
|
||||
0.199820836596682871
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
},
|
||||
// 48ksps, 750Hz lowpass
|
||||
{
|
||||
.numTaps = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.199820836596682871,
|
||||
0.272777397353925699,
|
||||
0.272777397353925699,
|
||||
0.199820836596682871
|
||||
},
|
||||
.pState = NULL // we don't use this directly
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
/**************************************************************
|
||||
|
||||
KA7OEI, November, 2014
|
||||
|
||||
IMPORTANT NOTE:
|
||||
|
||||
This is a MINIMAL FIR Lowpass filter that is applied to the RX input
|
||||
decimation. It is NOT designed to provide any significant filtering!
|
||||
|
||||
The majority anti-aliasing for this decimation operation is provided ONLY by the
|
||||
Phase-Added Hilbert Transformer that precedes this!
|
||||
|
||||
This is an absolutely minimized operation to reduce processor overhead!
|
||||
|
||||
3rd order, Least Pth-Norm, 48 ksps, Fpass=10000, Fstop=15000, Wpass=10, Wstop=1
|
||||
|
||||
Response:
|
||||
|
||||
DC-10330 Hz: >=-0.5dB
|
||||
-1dB @ 10900 Hz Hz
|
||||
-3dB @ 13089 Hz
|
||||
-6dB @ 14900 Hz
|
||||
-10dB @ 16700 Hz
|
||||
Notch @ 19590 Hz with -20dB points at 18510 and 20880 Hz.
|
||||
Min. -13.8dB @ 23.6 kHz
|
||||
|
||||
***************************************************************/
|
||||
|
||||
const arm_fir_decimate_instance_f32 FirRxDecimateMinLPF =
|
||||
{
|
||||
.numTaps = 4,
|
||||
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.1848172721704,
|
||||
0.135814345129,
|
||||
0.5586516940301,
|
||||
0.4419794765896
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
/**************************************************************
|
||||
|
||||
KA7OEI, November, 2014
|
||||
|
||||
IMPORTANT NOTE:
|
||||
|
||||
This low-pass filter is designed to remove aliasing artifacts from the interpolated output.
|
||||
|
||||
Response (15th order FIR, Least Pth-norm: Fpass = 4000 Hz, Fstop = 8600 Hz Fsamp = 12000 Hz):
|
||||
|
||||
-6dB: 5075 Hz
|
||||
-10dB: 5841 Hz
|
||||
-20dB: 7034 Hz
|
||||
-40dB: 8270 Hz
|
||||
-50dB: >8550 Hz
|
||||
|
||||
Because the Nyquist Frequency is 6 kHz with the 12 kHz input sample rate, with filtered
|
||||
audio limited to <3 kHz by the normal SSB audio filters, there will be NO aliased
|
||||
content <9 kHz so the response of this low-pass filter may be relaxed to provide
|
||||
a higher degree of filtering (e.g. >50dB) >8550 Hz.
|
||||
|
||||
In the case of the 3.6 kHz filter, the aliasing extends down no farther than 8200 Hz where the
|
||||
attenuation is still at least 40dB where this, plus the effects of psychoacoustic masking
|
||||
should make these artifacts inaudible.
|
||||
|
||||
***************************************************************/
|
||||
|
||||
const arm_fir_interpolate_instance_f32 FirRxInterpolate=
|
||||
{
|
||||
.phaseLength = 16,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0064096284297950057,
|
||||
0.017769515865099398,
|
||||
0.032257990537557804,
|
||||
0.040774242726362854,
|
||||
0.031402652968355385,
|
||||
-0.0044545611189248744,
|
||||
-0.065457689067971975,
|
||||
-0.13802671944933273,
|
||||
-0.20064935251937976,
|
||||
-0.23328570256042488,
|
||||
-0.22670802442881149,
|
||||
-0.18633542013951426,
|
||||
-0.1286861967088595,
|
||||
-0.072726968058963559,
|
||||
-0.031602889405696735,
|
||||
-0.009023372039440496
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
/*#####################################################
|
||||
*
|
||||
* Interpolation filter with 4 taps
|
||||
* 4 taps minimum for the ARM function to work
|
||||
* two versions:
|
||||
* 1.) for filter bandwidths between 3k4 and 4k8
|
||||
* --> 5kHz stop frequency
|
||||
* 2.) for filter bandwidths between 8k0 and 10k
|
||||
* --> 10kHz stop frequency
|
||||
*
|
||||
* these "filters" do not filter much with 4 taps . . .
|
||||
* FIR 4 taps, Fstop 5kHz / 10kHz, Rectangular
|
||||
* designed with Iowa Hills FIR Filter Designer
|
||||
* DD4WH 2016_03_11
|
||||
*
|
||||
* ####################################################
|
||||
*/
|
||||
|
||||
const arm_fir_interpolate_instance_f32 FirRxInterpolate_4_5k=
|
||||
{
|
||||
.phaseLength = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.210149639888675743,
|
||||
0.292367020487055873,
|
||||
0.292367020487055873,
|
||||
0.210149639888675743
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
const arm_fir_interpolate_instance_f32 FirRxInterpolate_4_10k=
|
||||
{
|
||||
.phaseLength = 4,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.139302961114601442,
|
||||
0.460435107346899464,
|
||||
0.460435107346899464,
|
||||
0.139302961114601442
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
// FIXME: Is this the right file for a FreeDV TX filter?
|
||||
// this is meant to be an interpolation filter for FreeDV
|
||||
// cutoff 2.4kHz (30 Taps)
|
||||
|
||||
const arm_fir_instance_f32 Fir_TxFreeDV_Interpolate =
|
||||
{
|
||||
.numTaps = FIR_TX_FREEDV_INTERPOLATE_NUM_TAPS,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.001351058376639693,
|
||||
-0.003185783059285283,
|
||||
-0.005575655191465650,
|
||||
-0.007911042143847070,
|
||||
-0.009195803961917746,
|
||||
-0.008176776032790899,
|
||||
-0.003590261795373249,
|
||||
0.005518212389136743,
|
||||
0.019475233722896626,
|
||||
0.037749136460739165,
|
||||
0.058883910956281677,
|
||||
0.080638648048914893,
|
||||
0.100323507980679211,
|
||||
0.115270746696726323,
|
||||
0.123339678809895686,
|
||||
0.123339678809895686,
|
||||
0.115270746696726323,
|
||||
0.100323507980679211,
|
||||
0.080638648048914893,
|
||||
0.058883910956281677,
|
||||
0.037749136460739165,
|
||||
0.019475233722896626,
|
||||
0.005518212389136743,
|
||||
-0.003590261795373249,
|
||||
-0.008176776032790899,
|
||||
-0.009195803961917746,
|
||||
-0.007911042143847070,
|
||||
-0.005575655191465650,
|
||||
-0.003185783059285283,
|
||||
-0.001351058376639693
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
/*
|
||||
|
||||
// And here for you to try the same filter with 60 taps
|
||||
// this is meant to be an interpolation filter for FreeDV
|
||||
// cutoff 2.4kHz
|
||||
|
||||
const arm_fir_instance_f32 FirFreeDVInterpolate=
|
||||
{
|
||||
.numTaps = 30,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
-325.7026576032276350E-6,
|
||||
-371.9001810615538940E-6,
|
||||
-297.4863280206030250E-6,
|
||||
-42.52080605332919560E-6,
|
||||
430.2851136718793440E-6,
|
||||
0.001114933511882014,
|
||||
0.001945133332895070,
|
||||
0.002786351459208297,
|
||||
0.003441665727387134,
|
||||
0.003674210056274392,
|
||||
0.003245972098811801,
|
||||
0.001969072608194520,
|
||||
-237.8878302134766050E-6,
|
||||
-0.003298503514874146,
|
||||
-0.006943439896700603,
|
||||
-0.010701717349100807,
|
||||
-0.013925451717764645,
|
||||
-0.015850079401508791,
|
||||
-0.015685944805004001,
|
||||
-0.012730898974573298,
|
||||
-0.006488430580536590,
|
||||
0.003227089128632603,
|
||||
0.016216448931132731,
|
||||
0.031868083873548676,
|
||||
0.049186001642367742,
|
||||
0.066873952747489043,
|
||||
0.083467736074663401,
|
||||
0.097499421337832640,
|
||||
0.107671414315587272,
|
||||
0.113015797883873961,
|
||||
0.113015797883873961,
|
||||
0.107671414315587272,
|
||||
0.097499421337832640,
|
||||
0.083467736074663401,
|
||||
0.066873952747489043,
|
||||
0.049186001642367742,
|
||||
0.031868083873548676,
|
||||
0.016216448931132731,
|
||||
0.003227089128632603,
|
||||
-0.006488430580536590,
|
||||
-0.012730898974573298,
|
||||
-0.015685944805004001,
|
||||
-0.015850079401508791,
|
||||
-0.013925451717764645,
|
||||
-0.010701717349100807,
|
||||
-0.006943439896700603,
|
||||
-0.003298503514874146,
|
||||
-237.8878302134766050E-6
|
||||
0.001969072608194520,
|
||||
0.003245972098811801,
|
||||
0.003674210056274392,
|
||||
0.003441665727387134,
|
||||
0.002786351459208297,
|
||||
0.001945133332895070,
|
||||
0.001114933511882014,
|
||||
430.2851136718793440E-6,
|
||||
-42.52080605332919560E-6,
|
||||
-297.4863280206030250E-6,
|
||||
-371.9001810615538940E-6,
|
||||
-325.7026576032276350E-6
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
const float32_t Fir_Rx_FreeDV_Interpolate_Coeffs[24] =
|
||||
{
|
||||
-0.017405444562935534,
|
||||
-0.017108768884742161,
|
||||
-0.013120768604810904,
|
||||
-0.004804294719432716,
|
||||
0.007973629566960488,
|
||||
0.024740722876424703,
|
||||
0.044407570327122774,
|
||||
0.065355761534977047,
|
||||
0.085619214114458830,
|
||||
0.103134409504618857,
|
||||
0.116021478863062078,
|
||||
0.122850816384744946,
|
||||
0.122850816384744946,
|
||||
0.116021478863062078,
|
||||
0.103134409504618857,
|
||||
0.085619214114458830,
|
||||
0.065355761534977047,
|
||||
0.044407570327122774,
|
||||
0.024740722876424703,
|
||||
0.007973629566960488,
|
||||
-0.004804294719432716,
|
||||
-0.013120768604810904,
|
||||
-0.017108768884742161,
|
||||
-0.017405444562935534
|
||||
};
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
/**************************************************************
|
||||
|
||||
KA7OEI, November, 2014
|
||||
|
||||
IMPORTANT NOTE:
|
||||
|
||||
This low-pass filter is designed to remove aliasing artifacts from the interpolated output.
|
||||
|
||||
Response (15th order FIR, Least Pth-norm: Fpass = 10000 Hz, Fstop = 1200 Hz Fsamp = 24000 Hz):
|
||||
|
||||
Ripple: +/- 0.5dB
|
||||
-6dB: 10640 Hz
|
||||
-10dB: 10873 Hz
|
||||
-20dB: 11240 Hz
|
||||
-30dB: 11449 Hz
|
||||
Notch at 11608 Hz
|
||||
-34dB peak > 12000 (Ripple response at this level)
|
||||
|
||||
This low-pass filter is a special case for the 10 kHz passband. Due to the limited order, the ultimate response at Nyquist is
|
||||
only on the order of -34dB, but this is suitable to avoid audible aliasing artifacts because of phsycoacoustic masking effects.
|
||||
|
||||
***************************************************************/
|
||||
|
||||
const arm_fir_interpolate_instance_f32 FirRxInterpolate10KHZ=
|
||||
{
|
||||
.phaseLength = 16,
|
||||
.pCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.05811583205356,
|
||||
-0.0367094411696,
|
||||
0.01940709235172,
|
||||
-0.02834514773976,
|
||||
-0.01544119658805,
|
||||
0.00554906655524,
|
||||
-0.08598762701749,
|
||||
0.04147536848705,
|
||||
-0.165163226107,
|
||||
0.01287481670083,
|
||||
-0.1999399439611,
|
||||
-0.1925399994825,
|
||||
-0.1329419101037,
|
||||
-0.7311312926885,
|
||||
0.05542105288489,
|
||||
0.4430274622578
|
||||
},
|
||||
.pState = NULL
|
||||
};
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __I_TX_FILTER_H
|
||||
#define __I_TX_FILTER_H
|
||||
|
||||
#define IQ_TX_BLOCK_SIZE 1
|
||||
#define IQ_TX_NUM_TAPS 89
|
||||
|
||||
/*
|
||||
* Hilbert 0 Degree, "Phase-added" bandpass filter
|
||||
* Kaiser Window FIR Filter, Beta = 3.25, Raised Cosine = 9.30
|
||||
* Fc = 5.23 kHz
|
||||
* BW = 9.50 kHz
|
||||
* 89 Taps
|
||||
*
|
||||
* 20140926 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*/
|
||||
|
||||
const float i_tx_coeffs[I_NUM_TAPS] =
|
||||
{
|
||||
0.000101250517153683,
|
||||
-0.000515927338247317,
|
||||
-0.00176919806883,
|
||||
-0.001893116080949,
|
||||
-0.000577659000336806,
|
||||
3.550079658197940E-6,
|
||||
-0.00172963585657513,
|
||||
-0.0038100999663584,
|
||||
-0.0031472032338157,
|
||||
-0.000586333586637393,
|
||||
-0.000494536851592284,
|
||||
-0.00415653740435641,
|
||||
-0.00680718523656846,
|
||||
-0.00429325456879721,
|
||||
-0.000273434114376999,
|
||||
-0.00181389209595478,
|
||||
-0.0082208278123836,
|
||||
-0.0105062537188667,
|
||||
-0.00469751224581168,
|
||||
0.000452038013830452,
|
||||
-0.00454071945888382,
|
||||
-0.0142111518079221,
|
||||
-0.0142255278253247,
|
||||
-0.00344416232313822,
|
||||
0.001565954170156727,
|
||||
-0.00947713768589062,
|
||||
-0.0222735621260352,
|
||||
-0.0167608122370822,
|
||||
0.000803648164899460,
|
||||
0.002905223684809450,
|
||||
-0.0179852797068097,
|
||||
-0.0327457542271941,
|
||||
-0.0160524441181231,
|
||||
0.010701868004134297,
|
||||
0.004196449024939201,
|
||||
-0.0338893802111143,
|
||||
-0.0479948819717114,
|
||||
-0.00683680444677724,
|
||||
0.036441721082929118,
|
||||
0.005133250668784600,
|
||||
-0.0804182627087614,
|
||||
-0.0919356431907568,
|
||||
0.060333107936900596,
|
||||
0.291908298625711771,
|
||||
0.404029117624692125,
|
||||
0.291908298625728535,
|
||||
0.060333107936918977,
|
||||
-0.0919356431907509,
|
||||
-0.0804182627087674,
|
||||
0.005133250668778217,
|
||||
0.036441721082930000,
|
||||
-0.00683680444677221,
|
||||
-0.0479948819717094,
|
||||
-0.033889380211117,
|
||||
0.004196449024936275,
|
||||
0.010701868004134651,
|
||||
-0.016052444118121,
|
||||
-0.0327457542271935,
|
||||
-0.0179852797068109,
|
||||
0.002905223684808852,
|
||||
0.000803648164900392,
|
||||
-0.0167608122370813,
|
||||
-0.0222735621260356,
|
||||
-0.00947713768589167,
|
||||
0.001565954170156743,
|
||||
-0.00344416232313721,
|
||||
-0.0142255278253243,
|
||||
-0.0142111518079231,
|
||||
-0.00454071945888512,
|
||||
0.000452038013830350,
|
||||
-0.00469751224581064,
|
||||
-0.0105062537188658,
|
||||
-0.00822082781238365,
|
||||
-0.0018138920959553,
|
||||
-0.000273434114377146,
|
||||
-0.00429325456879692,
|
||||
-0.0068071852365683,
|
||||
-0.00415653740435665,
|
||||
-0.000494536851592651,
|
||||
-0.000586333586637503,
|
||||
-0.00314720323381554,
|
||||
-0.00381009996635821,
|
||||
-0.00172963585657509,
|
||||
3.550079658144650E-6,
|
||||
-0.000577659000336875,
|
||||
-0.00189311608094905,
|
||||
-0.00176919806883003,
|
||||
-0.000515927338247313,
|
||||
0.000101250517153702
|
||||
};
|
||||
|
||||
//static float32_t FirState_I_TX[128];
|
||||
//arm_fir_instance_f32 FIR_I_TX;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,379 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 2020.04.27 by Y.Korenev UB8JDC using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR, structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - 12 KSPS Sample Rate
|
||||
// - Bandwidth 100 Hz (CW)
|
||||
// - 10th order Butterworth bandpass filter
|
||||
// - Single-precision floating-point
|
||||
// - Coefficients importing in reverse order!
|
||||
//
|
||||
#define IIR_100hz_numStages 10
|
||||
|
||||
//
|
||||
// 500 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_500 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117045402527,
|
||||
-0.961479723453522,
|
||||
0.995523214340210,
|
||||
-0.968451142311096,
|
||||
0.998828113079071,
|
||||
-0.966746151447296,
|
||||
0.999394357204437,
|
||||
-0.966019272804260,
|
||||
0.999540567398071,
|
||||
-0.968152463436127
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.074513349408335e-07,
|
||||
-4.139578777540010e-07,
|
||||
-7.580364353998448e-07,
|
||||
-5.984049948892789e-07,
|
||||
-4.667455399953724e-08,
|
||||
1.742693171991050e-07,
|
||||
1.272666239060527e-08,
|
||||
-1.451467124269357e-08,
|
||||
-4.154731003680467e-10,
|
||||
3.492807154614752e-10
|
||||
}
|
||||
};
|
||||
//
|
||||
// 550 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_550 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117164611816,
|
||||
-0.954406321048737,
|
||||
0.995446324348450,
|
||||
-0.961397528648377,
|
||||
0.998838007450104,
|
||||
-0.959627330303192,
|
||||
0.999398231506348,
|
||||
-0.958896815776825,
|
||||
0.999529540538788,
|
||||
-0.961052417755127
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.066608419364457e-07,
|
||||
-4.062592893205874e-07,
|
||||
-7.287537755473750e-07,
|
||||
-5.394011282078282e-07,
|
||||
7.951572733588819e-09,
|
||||
1.959667628170791e-07,
|
||||
7.976567850676020e-09,
|
||||
-1.985828923523059e-08,
|
||||
-3.296478645609113e-10,
|
||||
5.870664510077006e-10
|
||||
}
|
||||
};
|
||||
//
|
||||
// 600 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_600 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117105007172,
|
||||
-0.946678876876831,
|
||||
0.995385706424713,
|
||||
-0.953669130802155,
|
||||
0.998845875263214,
|
||||
-0.951852679252625,
|
||||
0.999400973320007,
|
||||
-0.951121032238007,
|
||||
0.999521076679230,
|
||||
-0.953288018703461
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.057972482954028e-07,
|
||||
-3.979138227805379e-07,
|
||||
-6.973535846555023e-07,
|
||||
-4.773115165335184e-07,
|
||||
6.319763912188137e-08,
|
||||
2.142628687806791e-07,
|
||||
5.286769910739508e-10,
|
||||
-2.597028903039700e-08,
|
||||
-5.918551759798163e-11,
|
||||
9.229992881110149e-10
|
||||
}
|
||||
};
|
||||
//
|
||||
// 650 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_650 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117105007172,
|
||||
-0.938302576541901,
|
||||
0.995337128639221,
|
||||
-0.945275247097015,
|
||||
0.998852193355560,
|
||||
-0.943426966667175,
|
||||
0.999403059482575,
|
||||
-0.942695379257202,
|
||||
0.999514400959015,
|
||||
-0.944866895675659
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203308801787e-08,
|
||||
-1.048611366627483e-07,
|
||||
-3.889442155013967e-07,
|
||||
-6.640120773226954e-07,
|
||||
-4.127688271182706e-07,
|
||||
1.180438644610149e-07,
|
||||
2.281452537999940e-07,
|
||||
-9.835012804160215e-09,
|
||||
-3.262511327761786e-08,
|
||||
4.808165532388387e-10,
|
||||
1.369539703865996e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 700 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_700 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117105007172,
|
||||
-0.929283201694489,
|
||||
0.995297670364380,
|
||||
-0.936224520206451,
|
||||
0.998857378959656,
|
||||
-0.934354960918427,
|
||||
0.999404788017273,
|
||||
-0.933626711368561,
|
||||
0.999508917331696,
|
||||
-0.935794889926910
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.038531749486538e-07,
|
||||
-3.793751943703683e-07,
|
||||
-6.289155862759799e-07,
|
||||
-3.464265319053084e-07,
|
||||
1.714726352020080e-07,
|
||||
2.366920881513579e-07,
|
||||
-2.321627867729603e-08,
|
||||
-3.949672944258964e-08,
|
||||
1.384046655061866e-09,
|
||||
1.929782778020694e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 750 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_750 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117105007172,
|
||||
-0.919626951217651,
|
||||
0.995265305042267,
|
||||
-0.926525056362152,
|
||||
0.998861670494080,
|
||||
-0.924643456935883,
|
||||
0.999406158924103,
|
||||
-0.923918902873993,
|
||||
0.999504446983337,
|
||||
-0.926079809665680
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.027740239578634e-07,
|
||||
-3.692328789384192e-07,
|
||||
-5.922586296946974e-07,
|
||||
-2.789512905110314e-07,
|
||||
2.224872162059910e-07,
|
||||
2.391011832969525e-07,
|
||||
-3.958798444614331e-08,
|
||||
-4.616278204139235e-08,
|
||||
2.746912253215328e-09,
|
||||
2.592701386916474e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 800 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_800 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117164611816,
|
||||
-0.909340500831604,
|
||||
0.995238363742828,
|
||||
-0.916185200214386,
|
||||
0.998865187168121,
|
||||
-0.914298593997955,
|
||||
0.999407291412354,
|
||||
-0.913579702377319,
|
||||
0.999500691890717,
|
||||
-0.915728092193604
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.016244510765318e-07,
|
||||
-3.585451509025006e-07,
|
||||
-5.542443659578566e-07,
|
||||
-2.110181753778306e-07,
|
||||
2.701280834571662e-07,
|
||||
2.347170919847486e-07,
|
||||
-5.878169773154696e-08,
|
||||
-5.211252940284794e-08,
|
||||
4.661536934236210e-09,
|
||||
3.328791242651619e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 850 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_850 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117224216461,
|
||||
-0.898430705070496,
|
||||
0.995215833187103,
|
||||
-0.905213057994843,
|
||||
0.998868167400360,
|
||||
-0.903327405452728,
|
||||
0.999408245086670,
|
||||
-0.902615189552307,
|
||||
0.999497592449188,
|
||||
-0.904747426509857
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-1.004052165853864e-07,
|
||||
-3.473411993581976e-07,
|
||||
-5.150816946297709e-07,
|
||||
-1.433014062968141e-07,
|
||||
3.134916255476128e-07,
|
||||
2.230537887726314e-07,
|
||||
-8.048506572322367e-08,
|
||||
-5.676345793403925e-08,
|
||||
7.207070940040694e-09,
|
||||
4.085846327939180e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 900 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_900 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117045402527,
|
||||
-0.886905252933502,
|
||||
0.995196700096130,
|
||||
-0.893617093563080,
|
||||
0.998870730400085,
|
||||
-0.891737699508667,
|
||||
0.999409019947052,
|
||||
-0.891032636165619,
|
||||
0.999494969844818,
|
||||
-0.893145799636841
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-9.911717313570989e-08,
|
||||
-3.356518618602422e-07,
|
||||
-4.749855975205719e-07,
|
||||
-7.647016531109330e-08,
|
||||
3.517440632094804e-07,
|
||||
2.038139115256854e-07,
|
||||
-1.042412947072080e-07,
|
||||
-5.948210812789512e-08,
|
||||
1.044057107435492e-08,
|
||||
4.785924101469163e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 950 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_100hz_950 =
|
||||
{
|
||||
.numStages = IIR_100hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.844117164611816,
|
||||
-0.874771952629089,
|
||||
0.995180428028107,
|
||||
-0.881405830383301,
|
||||
0.998872876167297,
|
||||
-0.879536986351013,
|
||||
0.999409675598145,
|
||||
-0.878840029239655,
|
||||
0.999492764472961,
|
||||
-0.880931198596954
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.131203397619629e-08,
|
||||
-9.776120180049475e-08,
|
||||
-3.235090559883247e-07,
|
||||
-4.341745807323605e-07,
|
||||
-1.117885339851910e-08,
|
||||
3.841382465452625e-07,
|
||||
1.769026027886866e-07,
|
||||
-1.294563389819814e-07,
|
||||
-5.961092597317474e-08,
|
||||
1.438790597774187e-08,
|
||||
5.323763208053833e-09
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20140915 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 8th order Elliptic lowpass filter
|
||||
//
|
||||
//
|
||||
// -6dB point: 10.0 kHz
|
||||
// -20dB point: 10.18 kHz
|
||||
// -40dB point: 10.46 kHz
|
||||
// -60dB point: >10.88 kHz
|
||||
//
|
||||
//#define NCoef 8
|
||||
#define IIR_10k_numStages 8
|
||||
const arm_iir_lattice_instance_f32 IIR_10k =
|
||||
{
|
||||
.numStages = IIR_10k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3059837075323,
|
||||
-0.5896555175446,
|
||||
0.7331597393194,
|
||||
-0.713542623059,
|
||||
0.8999944361723,
|
||||
-0.4831480007607,
|
||||
0.9938574536212,
|
||||
-0.2965660617857
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.01294033742346,
|
||||
0.06059508198778,
|
||||
0.1442543837861,
|
||||
0.184661010229,
|
||||
0.1196473741182,
|
||||
0.01735304263064,
|
||||
-0.03003092329645,
|
||||
-0.003155003081181,
|
||||
0.0003259315989964
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 10000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_10k_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_10k_LPF =
|
||||
{
|
||||
.numStages = IIR_10k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.184297745178662,
|
||||
0.346275356901559,
|
||||
0.835935186979480,
|
||||
0.790382467146251,
|
||||
0.986915159126712,
|
||||
0.842177143803695,
|
||||
0.999207130498260,
|
||||
0.862058584401922
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.285756161122327,
|
||||
0.647395708199686,
|
||||
0.191311565499666,
|
||||
-0.164203854783080,
|
||||
-0.0319701390832776,
|
||||
0.00976034243199386,
|
||||
0.00225291674041372,
|
||||
-0.000117333004814757,
|
||||
-4.35613343882091e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20151022 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// This high pass filter is for the FM demodulator to extract high-frequency "triangle noise" energy
|
||||
// for the squelch algorithm.
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 6th order Elliptic highpass filter
|
||||
//
|
||||
//
|
||||
// -6dB point: 14.9 kHz
|
||||
// -20dB point: 14.5 kHz
|
||||
// -40dB point: 13.8 kHz
|
||||
// -60dB point: 13.3 kHz
|
||||
//
|
||||
/*
|
||||
#define IIR_15k_hpf_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_15k_hpf = {
|
||||
.numStages = IIR_15k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.513580159973,
|
||||
0.7246612586998,
|
||||
0.7246612586998,
|
||||
0.8107542886737,
|
||||
0.7534361820128,
|
||||
0.9529352399472,
|
||||
0.4826168836816
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.01068626058243,
|
||||
-0.04830879422708,
|
||||
0.1047720411744,
|
||||
-0.1152362519753,
|
||||
0.06014978280645,
|
||||
-0.003570328867624,
|
||||
-0.01351144592324
|
||||
}
|
||||
};
|
||||
*/
|
||||
// Sloped version - experimental, not used
|
||||
// -3dB: 20.0 kHz
|
||||
// -6dB: 19.0 kHz
|
||||
// -20dB: 15.6 kHz
|
||||
// -40dB: 13.9 kHz
|
||||
// -58dB: <13.2 kHz
|
||||
|
||||
#define IIR_15k_hpf_numStages 6
|
||||
#define IIR_15k_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_15k_hpf =
|
||||
{
|
||||
.numStages = IIR_15k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.08584448365242,
|
||||
0.298455698329,
|
||||
0.6057782760185,
|
||||
0.7115173863477,
|
||||
0.7698117813539,
|
||||
0.7879540958152
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00561889294652,
|
||||
-0.02629790457241,
|
||||
0.0684050306275,
|
||||
-0.1143219836396,
|
||||
0.1169486269215,
|
||||
-0.07287150832503,
|
||||
0.02534743920497
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 1400Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 150 - 1400Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_1k4_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_1k4_LPF =
|
||||
{
|
||||
.numStages = IIR_1k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.513121512033492,
|
||||
-0.848156725130716,
|
||||
0.912905355716368,
|
||||
-0.920457559093897,
|
||||
0.946299472905260,
|
||||
-0.874357776863127,
|
||||
0.991745064593748,
|
||||
-0.780050411952442,
|
||||
0.999672192852107,
|
||||
-0.747759230954469
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00303978190645145,
|
||||
0.00957370964334359,
|
||||
0.0192021255112258,
|
||||
0.0205518463597444,
|
||||
0.0157679250083878,
|
||||
0.00641323479251947,
|
||||
0.00194320223728067,
|
||||
0.000177526968367495,
|
||||
-0.000114188594530516,
|
||||
-1.00881138288648e-06,
|
||||
-1.61208577327586e-06
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_1k4_BPF =
|
||||
{
|
||||
.numStages = IIR_1k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.544472709123517,
|
||||
-0.846448469159389,
|
||||
0.914323381297358,
|
||||
-0.924099832753511,
|
||||
0.913728327779171,
|
||||
-0.906301509630351,
|
||||
0.986341377918403,
|
||||
-0.994060117939703,
|
||||
0.999689022223705,
|
||||
-0.996755741677070
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.00397159947826007,
|
||||
-0.0142756966456071,
|
||||
-0.0258501789268387,
|
||||
-0.0249409146677880,
|
||||
-0.00842585665202606,
|
||||
0.00150853661679518,
|
||||
0.00402678083172615,
|
||||
0.000247302313425797,
|
||||
-2.24256007699125e-05,
|
||||
-5.01381740295598e-07,
|
||||
1.79705759370541e-08
|
||||
}
|
||||
};
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 1100Hz - 2500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 1100 - 2500Hz
|
||||
//
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k4_SSTV =
|
||||
{
|
||||
.numStages = IIR_1k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.506305489868821,
|
||||
-0.530549016052929,
|
||||
0.852752516028665,
|
||||
-0.605615780849346,
|
||||
0.908798485793881,
|
||||
-0.609090038979443,
|
||||
0.898589845278408,
|
||||
-0.527324792497554,
|
||||
0.972399687849265,
|
||||
-0.806526221782603
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.00502583555949696,
|
||||
-0.0125105344886717,
|
||||
-0.00418751674186635,
|
||||
0.0213049813421346,
|
||||
0.0261437873033528,
|
||||
-0.00847633761697014,
|
||||
-0.0252946013159023,
|
||||
-0.00396151687990829,
|
||||
0.0111353202658218,
|
||||
0.00168003453028945,
|
||||
-0.000348271075749648
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 1600Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 150 - 1600Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_1k6_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_1k6_LPF =
|
||||
{
|
||||
.numStages = IIR_1k6_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.466488867417511,
|
||||
-0.806195990652699,
|
||||
0.886218044099720,
|
||||
-0.895050799512214,
|
||||
0.932962782640420,
|
||||
-0.830295375528087,
|
||||
0.990476931527691,
|
||||
-0.713094807516228,
|
||||
0.999609649167846,
|
||||
-0.674710639139313
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00389683132359987,
|
||||
0.0138226995337397,
|
||||
0.0295183362623048,
|
||||
0.0347590317564048,
|
||||
0.0274564574556244,
|
||||
0.0115668027741923,
|
||||
0.00266968736496351,
|
||||
0.000176086120205525,
|
||||
-0.000357042283087743,
|
||||
-5.34430276839977e-06,
|
||||
-3.16592076707485e-06
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_1k6_BPF =
|
||||
{
|
||||
.numStages = IIR_1k6_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.494195797915416,
|
||||
-0.803665234575735,
|
||||
0.885970320933212,
|
||||
-0.904522861950696,
|
||||
0.882497256186818,
|
||||
-0.879441652192076,
|
||||
0.985240463020393,
|
||||
-0.994220286123894,
|
||||
0.999679143098346,
|
||||
-0.996775926313658
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.00542804202987006,
|
||||
-0.0211221071946913,
|
||||
-0.0411248591148432,
|
||||
-0.0404574358824852,
|
||||
-0.0126311821394728,
|
||||
0.00603670441721448,
|
||||
0.00803948053906083,
|
||||
0.000449048992769978,
|
||||
-4.33255842577709e-05,
|
||||
-1.00733352962831e-06,
|
||||
3.58686948389447e-08
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// *** 12 KSPS Sample Rate!
|
||||
//
|
||||
// Nominal 1420 Hz center-frequency Filter:
|
||||
//
|
||||
// 10th order Elliptic bandpass filter, 0.5db ripple
|
||||
// Fpass: 582, 2250 Hz
|
||||
// -6dB points: 552, 2350 Hz
|
||||
// -20dB points: 500, 2525 500, 2519 Hz
|
||||
// -40dB points: 428, 2830
|
||||
// -60dB points: 384, 3030
|
||||
//
|
||||
#define IIR_1k8_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_1k425 =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3633117201536,
|
||||
-0.6014671698188,
|
||||
0.790691903771,
|
||||
-0.7552408736771,
|
||||
0.8655745295849,
|
||||
-0.7100967246513,
|
||||
0.8371692151707,
|
||||
-0.858604704342,
|
||||
0.9948942198536,
|
||||
-0.9504411745978
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.008451821550603,
|
||||
-0.03028239739489,
|
||||
-0.04383575807689,
|
||||
-0.005801028198445,
|
||||
0.0552803520222,
|
||||
0.0409926115824,
|
||||
-0.009867881161988,
|
||||
-0.01912289835012,
|
||||
-0.003305206206671,
|
||||
0.0001846251381343,
|
||||
0.0001533411723535
|
||||
}
|
||||
};
|
||||
//
|
||||
// -150 Hz, 1275 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_1k275 =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3615632509154,
|
||||
-0.6426687049878,
|
||||
0.8022155117307,
|
||||
-0.8033168968408,
|
||||
0.8624152554717,
|
||||
-0.7373416322104,
|
||||
0.8853268131748,
|
||||
-0.9382217524638,
|
||||
0.9974058005444,
|
||||
-0.9743269012915
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.008554020969071,
|
||||
-0.03290507946195,
|
||||
-0.05669748976757,
|
||||
-0.03112515335395,
|
||||
0.03458656760459,
|
||||
0.04515075118067,
|
||||
0.009972736163013,
|
||||
-0.008871404867662,
|
||||
-0.002779915015395,
|
||||
-3.149002424411e-05,
|
||||
3.311102598764e-05
|
||||
}
|
||||
};
|
||||
//
|
||||
// -300 Hz, 1125 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_1k125 =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3613452928877,
|
||||
-0.6810107467819,
|
||||
0.8170984050044,
|
||||
-0.8463544066134,
|
||||
0.8511170107767,
|
||||
-0.7821275475669,
|
||||
0.9480716019822,
|
||||
-0.9808799929708,
|
||||
0.9989026674026,
|
||||
-0.9900683804108
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.008566871148577,
|
||||
-0.03494144528,
|
||||
-0.06850457739963,
|
||||
-0.05800592969749,
|
||||
0.004948888629599,
|
||||
0.03640087677665,
|
||||
0.0202191966789,
|
||||
-0.0005739689668037,
|
||||
-0.0007471474016795,
|
||||
-1.814984183384e-05,
|
||||
2.538959875177e-06
|
||||
}
|
||||
};
|
||||
//
|
||||
// +150 Hz, 1575 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_1k575 =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3613452928877,
|
||||
-0.5528878303048,
|
||||
0.7775941425073,
|
||||
-0.6999131353729,
|
||||
0.8628162750942,
|
||||
-0.6773588830313,
|
||||
0.8145733229607,
|
||||
-0.7494991964062,
|
||||
0.9906935090308,
|
||||
-0.919454179607
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.008566871148577,
|
||||
-0.02836768723528,
|
||||
-0.03226930906751,
|
||||
0.01640676037123,
|
||||
0.0677730883021,
|
||||
0.02700913837121,
|
||||
-0.03345776958501,
|
||||
-0.02430295670566,
|
||||
0.001987515414669,
|
||||
0.001005716985531,
|
||||
0.0003676617652895
|
||||
}
|
||||
};
|
||||
//
|
||||
// +300 Hz, 1725 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_1k725 =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3624364166222,
|
||||
-0.5040846071146,
|
||||
0.7692947989321,
|
||||
-0.6409554520074,
|
||||
0.8607689220576,
|
||||
-0.6376837263631,
|
||||
0.8178885035622,
|
||||
-0.6240753437248,
|
||||
0.9834623152838,
|
||||
-0.8795808576955
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.008502787721249,
|
||||
-0.02559366076952,
|
||||
-0.0200387077241,
|
||||
0.03413786956908,
|
||||
0.06758199161391,
|
||||
0.004017644116835,
|
||||
-0.05236928020393,
|
||||
-0.01897401359474,
|
||||
0.01339055818279,
|
||||
0.002528542455842,
|
||||
0.0004151390011982
|
||||
}
|
||||
};
|
||||
//
|
||||
// low pass filter
|
||||
// DD4WH 2016-02-03
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_1k8_LPF =
|
||||
{
|
||||
.numStages = IIR_1k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.424104469409253,
|
||||
-0.760957161720464,
|
||||
0.856135458808337,
|
||||
-0.865387150235557,
|
||||
0.919773037078837,
|
||||
-0.777255196618113,
|
||||
0.989521498539331,
|
||||
-0.637962725222723,
|
||||
0.999554271439240,
|
||||
-0.594257795338158
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00500807056613645,
|
||||
0.0194715681066562,
|
||||
0.0436864315353799,
|
||||
0.0548773806707592,
|
||||
0.0438480552375318,
|
||||
0.0181134030340657,
|
||||
0.00228635234567699,
|
||||
-9.48681761683695e-05,
|
||||
-0.000791691993306771,
|
||||
-1.47032013899616e-05,
|
||||
-2.00621568867149e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 2020.04.27 by Y.Korenev UB8JDC using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR, structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - 12 KSPS Sample Rate
|
||||
// - Bandwidth 200 Hz (CW)
|
||||
// - 10th order Elliptic bandpass filter
|
||||
// - Single-precision floating-point
|
||||
// - Coefficients importing in reverse order!
|
||||
//
|
||||
#define IIR_200hz_numStages 10
|
||||
|
||||
//
|
||||
// 500 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_500 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.963869810104370,
|
||||
0.996652781963348,
|
||||
-0.966875314712524,
|
||||
0.998103320598602,
|
||||
-0.966414153575897,
|
||||
0.998208224773407,
|
||||
-0.963238596916199,
|
||||
0.998806416988373,
|
||||
-0.974526107311249
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.411297992803156e-04,
|
||||
-5.036837319494225e-05,
|
||||
-5.570459325099364e-05,
|
||||
1.687375879555475e-05,
|
||||
3.088041239607264e-06,
|
||||
-7.782410449408417e-08,
|
||||
6.467502089435584e-08,
|
||||
-6.034498056806115e-08,
|
||||
-1.506363478398498e-09,
|
||||
8.404459350686011e-10
|
||||
}
|
||||
};
|
||||
//
|
||||
// 550 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_550 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.956778883934021,
|
||||
0.996626973152161,
|
||||
-0.959783315658569,
|
||||
0.998106360435486,
|
||||
-0.959343314170837,
|
||||
0.998260438442230,
|
||||
-0.955788314342499,
|
||||
0.998634815216065,
|
||||
-0.967797458171845
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.356775458902121e-04,
|
||||
-3.839765849988908e-05,
|
||||
-5.141069777891971e-05,
|
||||
2.077420322166290e-05,
|
||||
3.698997488754685e-06,
|
||||
-3.446152732067276e-07,
|
||||
4.745169235320645e-08,
|
||||
-8.387807781673473e-08,
|
||||
-1.463176357852092e-09,
|
||||
1.550584771692343e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 600 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_600 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163441181183,
|
||||
-0.949032187461853,
|
||||
0.996607005596161,
|
||||
-0.952028572559357,
|
||||
0.998108685016632,
|
||||
-0.951605141162872,
|
||||
0.998302340507507,
|
||||
-0.947757005691528,
|
||||
0.998480916023254,
|
||||
-0.960332453250885
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.297210977412760e-04,
|
||||
-2.542124821047764e-05,
|
||||
-4.681734571931884e-05,
|
||||
2.481275623722468e-05,
|
||||
4.219968559482368e-06,
|
||||
-7.193478950284771e-07,
|
||||
1.889994472037415e-08,
|
||||
-1.111265959252705e-07,
|
||||
-8.176312404906128e-10,
|
||||
2.624878980839185e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 650 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_650 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163441181183,
|
||||
-0.940635085105896,
|
||||
0.996591269969940,
|
||||
-0.943617641925812,
|
||||
0.998110592365265,
|
||||
-0.943207502365112,
|
||||
0.998336255550385,
|
||||
-0.939133286476135,
|
||||
0.998344361782074,
|
||||
-0.9521484375
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.232644129544497e-04,
|
||||
-1.147407965618186e-05,
|
||||
-4.195252768113278e-05,
|
||||
2.893220880650915e-05,
|
||||
4.619471383193741e-06,
|
||||
-1.213774567077053e-06,
|
||||
-2.196506621032768e-08,
|
||||
-1.412249019949741e-07,
|
||||
7.775369237350560e-10,
|
||||
4.134683262435601e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 700 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_700 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.931593298912048,
|
||||
0.996578633785248,
|
||||
-0.934557318687439,
|
||||
0.998112142086029,
|
||||
-0.934159219264984,
|
||||
0.998363912105560,
|
||||
-0.929911017417908,
|
||||
0.998223781585693,
|
||||
-0.943260133266449
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.163121481426060e-04,
|
||||
3.405127927180729e-06,
|
||||
-3.684650437207893e-05,
|
||||
3.307369115645997e-05,
|
||||
4.866832114203135e-06,
|
||||
-1.836704200286476e-06,
|
||||
-7.566525539459690e-08,
|
||||
-1.728796519273601e-07,
|
||||
3.717674834646800e-09,
|
||||
6.120295381606411e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 750 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_750 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.921913087368012,
|
||||
0.996568322181702,
|
||||
-0.924854397773743,
|
||||
0.998113393783569,
|
||||
-0.924466073513031,
|
||||
0.998386681079865,
|
||||
-0.920087575912476,
|
||||
0.998117566108704,
|
||||
-0.933683097362518
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.088688435032964e-04,
|
||||
1.917585177579895e-05,
|
||||
-3.153051511617377e-05,
|
||||
3.717728759511374e-05,
|
||||
4.932894171361113e-06,
|
||||
-2.593397084638127e-06,
|
||||
-1.421764750375587e-07,
|
||||
-2.043928333250733e-07,
|
||||
8.421426223037543e-09,
|
||||
8.569696952065442e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 800 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_800 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163441181183,
|
||||
-0.911600947380066,
|
||||
0.996559858322144,
|
||||
-0.914516091346741,
|
||||
0.998114407062531,
|
||||
-0.914137363433838,
|
||||
0.998405635356903,
|
||||
-0.909662127494812,
|
||||
0.998024046421051,
|
||||
-0.923429787158966
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-7.009397377260029e-04,
|
||||
3.579455005819909e-05,
|
||||
-2.603746543172747e-05,
|
||||
4.118278593523428e-05,
|
||||
4.790668299392564e-06,
|
||||
-3.485065008135280e-06,
|
||||
-2.209152398791048e-07,
|
||||
-2.336709457040342e-07,
|
||||
1.530131932270251e-08,
|
||||
1.139929750593183e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 850 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_850 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.900664150714874,
|
||||
0.996552765369415,
|
||||
-0.903549790382385,
|
||||
0.998115241527557,
|
||||
-0.903179645538330,
|
||||
0.998421490192413,
|
||||
-0.898636579513550,
|
||||
0.997941672801971,
|
||||
-0.912513852119446
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-6.925304187461734e-04,
|
||||
5.321568824001588e-05,
|
||||
-2.040095569100231e-05,
|
||||
4.503029413172044e-05,
|
||||
4.415991497808136e-06,
|
||||
-4.508429356064880e-06,
|
||||
-3.106901544924767e-07,
|
||||
-2.583196021532785e-07,
|
||||
2.472552118604199e-08,
|
||||
1.443308850213043e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 900 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_900 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.889109969139099,
|
||||
0.996546864509583,
|
||||
-0.891963183879852,
|
||||
0.998116016387940,
|
||||
-0.891601264476776,
|
||||
0.998434960842133,
|
||||
-0.887013971805573,
|
||||
0.997869074344635,
|
||||
-0.900947272777557
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-6.836461834609509e-04,
|
||||
7.139224180718884e-05,
|
||||
-1.465528839617036e-05,
|
||||
4.866075323661789e-05,
|
||||
3.788073172472650e-06,
|
||||
-5.655422683048528e-06,
|
||||
-4.097164492122829e-07,
|
||||
-2.756989374574914e-07,
|
||||
3.697994799267690e-08,
|
||||
1.738840005316433e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 950 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_200hz_950 =
|
||||
{
|
||||
.numStages = IIR_200hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.907163500785828,
|
||||
-0.876946508884430,
|
||||
0.996541798114777,
|
||||
-0.879764497280121,
|
||||
0.998116612434387,
|
||||
-0.879410088062286,
|
||||
0.998446464538574,
|
||||
-0.874799072742462,
|
||||
0.997804880142212,
|
||||
-0.888742208480835
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-3.836439573206008e-04,
|
||||
-6.742936093360186e-04,
|
||||
9.027340274769813e-05,
|
||||
-8.836139386403374e-06,
|
||||
5.201709063840099e-05,
|
||||
2.890088126150658e-06,
|
||||
-6.912967364769429e-06,
|
||||
-5.156420570529008e-07,
|
||||
-2.830576022461173e-07,
|
||||
5.222612387001391e-08,
|
||||
1.986541775522710e-08
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 2100Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 150 - 2100Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_2k1_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_2k1_LPF =
|
||||
{
|
||||
.numStages = IIR_2k1_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.367665055229345,
|
||||
-0.688450049074435,
|
||||
0.805164789160803,
|
||||
-0.811607062793749,
|
||||
0.902007053621482,
|
||||
-0.678829166852664,
|
||||
0.988754839338072,
|
||||
-0.511291308813728,
|
||||
0.999489812346376,
|
||||
-0.461573314781018
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00731063001354271,
|
||||
0.0314121915186572,
|
||||
0.0739715509453205,
|
||||
0.0977625054614904,
|
||||
0.0764634076081996,
|
||||
0.0273892594750243,
|
||||
-0.00364458069285592,
|
||||
-0.00143162744212593,
|
||||
-0.00150600852899662,
|
||||
-3.00785390039450e-05,
|
||||
1.90133500787143e-05
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_2k1_BPF =
|
||||
{
|
||||
.numStages = IIR_2k1_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.388108085643651,
|
||||
-0.684535285919172,
|
||||
0.795328554327865,
|
||||
-0.851745126106827,
|
||||
0.786930711099640,
|
||||
-0.782402423654034,
|
||||
0.981748853637700,
|
||||
-0.994476024273642,
|
||||
0.999660553986239,
|
||||
-0.996813012539810
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0113057560156174,
|
||||
-0.0493258305692081,
|
||||
-0.101429131418656,
|
||||
-0.0939936931949645,
|
||||
-0.00933213227739606,
|
||||
0.0417064397734366,
|
||||
0.0245790863191006,
|
||||
0.00146913585763049,
|
||||
-0.000159569288036600,
|
||||
-4.03203149703518e-06,
|
||||
1.41762873655249e-07
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 12KSPS sample rate (e.g. 4x decimation)
|
||||
//
|
||||
// Example of the nominal 1412 Hz center-frequency Filter:
|
||||
//
|
||||
// 10th order Elliptic bandpass filter,
|
||||
//
|
||||
// Fpass: 320, 2480 Hz
|
||||
// -6dB points: 299, 2602 Hz
|
||||
// -20dB points: 264,2834
|
||||
// -40dB points: 218,3193
|
||||
// -60dB points: 194, 3424
|
||||
//
|
||||
#define IIR_2k3_numStages 10
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k3_1k412 =
|
||||
{
|
||||
.numStages = IIR_2k3_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.2701467400288,
|
||||
-0.5337350112524,
|
||||
0.6958962164633,
|
||||
-0.758453902622,
|
||||
0.7839709967998,
|
||||
-0.6094204682748,
|
||||
0.8900165832056,
|
||||
-0.9710784743018,
|
||||
0.9983628970738,
|
||||
-0.9859502653937
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01711398845885,
|
||||
-0.07116858148666,
|
||||
-0.1254973880951,
|
||||
-0.06367087681021,
|
||||
0.08889589696012,
|
||||
0.1046947051957,
|
||||
0.01366010226719,
|
||||
-0.008501456104369,
|
||||
-0.003625645738643,
|
||||
-9.123722957357e-05,
|
||||
2.159311905e-05
|
||||
}
|
||||
};
|
||||
//
|
||||
// 1275Hz Center Frequency (-150 Hz)
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k3_1k275 =
|
||||
{
|
||||
.numStages = IIR_2k3_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.2712876748428,
|
||||
-0.5735340804203,
|
||||
0.7173137797694,
|
||||
-0.8175461411882,
|
||||
0.7315460152375,
|
||||
-0.7167786129066,
|
||||
0.9767475626606,
|
||||
-0.9943753177254,
|
||||
0.9995379196189,
|
||||
-0.9965283982769
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01695089378394,
|
||||
-0.0754815863035,
|
||||
-0.1545067828949,
|
||||
-0.1337099532882,
|
||||
0.01250868380934,
|
||||
0.08652620679791,
|
||||
0.03662597834324,
|
||||
0.002809508493456,
|
||||
-0.0003479014294362,
|
||||
-1.019626375571e-05,
|
||||
3.955657094032e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 1562Hz Center Frequency (+150 Hz)
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k3_1k562 =
|
||||
{
|
||||
.numStages = IIR_2k3_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.2704722354583,
|
||||
-0.4930194577195,
|
||||
0.6788797346477,
|
||||
-0.6985554426272,
|
||||
0.8006644381482,
|
||||
-0.5854106964209,
|
||||
0.7723103700212,
|
||||
-0.9113575606699,
|
||||
0.9964165920158,
|
||||
-0.9679083606539
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01706725280562,
|
||||
-0.06549445078988,
|
||||
-0.09465636014278,
|
||||
-0.0006279147552571,
|
||||
0.1380031454132,
|
||||
0.08863098032502,
|
||||
-0.03386873453512,
|
||||
-0.03178190420391,
|
||||
-0.008447346315031,
|
||||
-3.073326593073e-05,
|
||||
0.0001862218852526
|
||||
}
|
||||
};
|
||||
//
|
||||
// 1712Hz Center Frequency (+300 Hz)
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k3_1k712 =
|
||||
{
|
||||
.numStages = IIR_2k3_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.2717781074202,
|
||||
-0.4503076240765,
|
||||
0.6654292686672,
|
||||
-0.6366299962827,
|
||||
0.8010323775887,
|
||||
-0.5867121495116,
|
||||
0.6883638854733,
|
||||
-0.7934171013092,
|
||||
0.9929975817319,
|
||||
-0.9418087297114
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01688140653005,
|
||||
-0.05893233949881,
|
||||
-0.06391130117223,
|
||||
0.05125151954747,
|
||||
0.1565612599346,
|
||||
0.0457952816904,
|
||||
-0.08390530500971,
|
||||
-0.04184467503704,
|
||||
-0.003607973662997,
|
||||
0.001058321053835,
|
||||
0.0006829825631745
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// low pass version
|
||||
// DD4WH 2016-02-03
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k3_LPF =
|
||||
{
|
||||
.numStages = IIR_2k3_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.334304700393179,
|
||||
-0.637973146829989,
|
||||
0.767879751187593,
|
||||
-0.768295057186220,
|
||||
0.892741024882815,
|
||||
-0.599613288253562,
|
||||
0.988679362407979,
|
||||
-0.418706450963394,
|
||||
0.999461427988613,
|
||||
-0.366491706976845
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00941076764313990,
|
||||
0.0423681593287898,
|
||||
0.101315269975374,
|
||||
0.134840512300872,
|
||||
0.100835720101395,
|
||||
0.0295355484872365,
|
||||
-0.0131806481791514,
|
||||
-0.00292265408570726,
|
||||
-0.00146862219082368,
|
||||
-2.39931441286178e-05,
|
||||
5.02684297614079e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 2500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 150 - 2500Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_2k5_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_2k5_LPF =
|
||||
{
|
||||
.numStages = IIR_2k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.304008884053488,
|
||||
-0.586479754574523,
|
||||
0.728707358729566,
|
||||
-0.717591127840479,
|
||||
0.886460005029009,
|
||||
-0.509239560057348,
|
||||
0.988906686305070,
|
||||
-0.320749263130520,
|
||||
0.999445512653576,
|
||||
-0.267299520678722
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0121126909328103,
|
||||
0.0563705089486983,
|
||||
0.135077706371490,
|
||||
0.177369645199308,
|
||||
0.122940273900304,
|
||||
0.0249807561603719,
|
||||
-0.0272356075029574,
|
||||
-0.00442102257133439,
|
||||
-0.000487963028261214,
|
||||
9.54073216847401e-06,
|
||||
8.24834253008722e-05
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_2k5_BPF =
|
||||
{
|
||||
.numStages = IIR_2k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.319949354758169,
|
||||
-0.584143220123557,
|
||||
0.699676230227154,
|
||||
-0.809140966154901,
|
||||
0.704873387106954,
|
||||
-0.653974039723370,
|
||||
0.976867907943965,
|
||||
-0.994591635529659,
|
||||
0.999649711777868,
|
||||
-0.996834233858384
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0194772962002087,
|
||||
-0.0868514981143777,
|
||||
-0.170190605680555,
|
||||
-0.131302479532905,
|
||||
0.0336504666821513,
|
||||
0.0956282907461719,
|
||||
0.0311274943500153,
|
||||
0.00344191566243132,
|
||||
-0.000363680054390594,
|
||||
-9.63538256713858e-06,
|
||||
3.36233973739775e-07
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// IIR filter
|
||||
// lattice ARMA coefficients designed with MATLAb fdatools
|
||||
// DD4WH 2016-03-05
|
||||
// inspired by Clint KA7OEI
|
||||
//
|
||||
// LPF 2k7
|
||||
#define IIR_2k7_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_2k7_LPF =
|
||||
{
|
||||
.numStages = IIR_2k7_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.276517739456119,
|
||||
-0.534458119364593,
|
||||
0.688627879533550,
|
||||
-0.657860665637030,
|
||||
0.883760854885895,
|
||||
-0.408163764378125,
|
||||
0.989378253422330,
|
||||
-0.218531341587163,
|
||||
0.999442039749756,
|
||||
-0.165077404674072
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0155856864050234,
|
||||
0.0740622771621721,
|
||||
0.175501156733159,
|
||||
0.222640088831044,
|
||||
0.137215023898017,
|
||||
0.0116117418712191,
|
||||
-0.0432897242829734,
|
||||
-0.00519209144189112,
|
||||
0.00156095841010052,
|
||||
6.72317701914359e-05,
|
||||
9.08341518316962e-05
|
||||
}
|
||||
};
|
||||
//
|
||||
// 120 - 2700Hz bandpass, 1410Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_2k7_BPF =
|
||||
{
|
||||
.numStages = IIR_2k7_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.286204893123822,
|
||||
-0.535401193365074,
|
||||
0.636552242537530,
|
||||
-0.801759238351553,
|
||||
0.632340313225578,
|
||||
-0.598674284342736,
|
||||
0.984168394137399,
|
||||
-0.996691132601798,
|
||||
0.999768009572177,
|
||||
-0.997990472561290
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0262124858208275,
|
||||
-0.117385216786601,
|
||||
-0.223626900059669,
|
||||
-0.159085812308114,
|
||||
0.0583824351916630,
|
||||
0.119904708047547,
|
||||
0.0261315687651823,
|
||||
0.00496617536907647,
|
||||
-0.000240288448030184,
|
||||
-6.41272493413780e-06,
|
||||
1.37062857848147e-07
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-03
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 2900Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_2k9_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_2k9_LPF =
|
||||
{
|
||||
.numStages = IIR_2k9_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
0.251607461238023,
|
||||
-0.482252659454225,
|
||||
0.649010601492657,
|
||||
-0.587098281132217,
|
||||
0.884933496818835,
|
||||
-0.297598183921305,
|
||||
0.990030999070584,
|
||||
-0.113255360948473,
|
||||
0.999450459548208,
|
||||
-0.0609467228813790
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
0.0200465239002972,
|
||||
0.0961515965852007,
|
||||
0.222315717811456,
|
||||
0.266325692682369,
|
||||
0.137175400914474,
|
||||
-0.0104425480557769,
|
||||
-0.0563674296455557,
|
||||
-0.00456438174446905,
|
||||
0.00418951198974554,
|
||||
0.000124467441153527,
|
||||
5.62783747425286e-05
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_2k9_BPF =
|
||||
{
|
||||
.numStages = IIR_2k9_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.263419613809752,
|
||||
-0.487748680969863,
|
||||
0.579151989014181,
|
||||
-0.766691138931688,
|
||||
0.644526948603595,
|
||||
-0.455099813849530,
|
||||
0.966822380971438,
|
||||
-0.994647491908158,
|
||||
0.999641053036454,
|
||||
-0.996851003050428
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0324231770435912,
|
||||
-0.140665197185480,
|
||||
-0.244988773730778,
|
||||
-0.127152356090031,
|
||||
0.127397853986530,
|
||||
0.136542957067850,
|
||||
0.00600155113876917,
|
||||
0.00834595632603165,
|
||||
-0.000738848558080582,
|
||||
-2.00888540803704e-05,
|
||||
6.96894635783540e-07
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20140927 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// This filter has relaxed band-stop properties and is designed for SSB audio TX filtering.
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 10th order Elliptic bandpass filter
|
||||
// Fstop: 200, 3250 Hz
|
||||
// Fpass: 300, 2700 Hz
|
||||
//
|
||||
// Amplitude responses - referenced to attenuation at 1.5 kHz:
|
||||
// -6dB points: 257, 2830 Hz
|
||||
// -10dB points: 254, 2885 Hz
|
||||
// -20dB points: 246, 2988 Hz
|
||||
// -30dB points: <225, >3060 Hz
|
||||
//
|
||||
// Low-end pre-emphasis added to offset effects of Hilbert transformer:
|
||||
// >=8.0dB: @ 280 Hz
|
||||
// >=7.0dB: <298 Hz
|
||||
// >=6.0dB: <355 Hz
|
||||
// >=5.0dB: <421 Hz
|
||||
// >=4.0dB: <521 Hz
|
||||
// >=3.0dB: <670 Hz
|
||||
// >=2.0dB: <870 Hz
|
||||
// >=1.0dB: <1130 Hz
|
||||
// >=0.5dB: <1340 Hz
|
||||
//
|
||||
// The above counteracts the rolloff to produce an overall flat response to approx. 1dB between 275 Hz and 2500 Hz.
|
||||
//
|
||||
// Pole/Zero Info:
|
||||
// 1: P0.98293, 0.36082; Z1, 0.40965
|
||||
// 2: P0.99849, 0.;035664; Z1, 0.030945
|
||||
// 3: P0.91702, 0.30422; Z1, 0.53916
|
||||
// 4: P0.98884, 0.038766; Z1, 0.023267
|
||||
// 5: P0.93128, 0.009238; Z (none)
|
||||
//
|
||||
//
|
||||
#define IIR_TX_numStages 10
|
||||
#define IIR_TX_2k7_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_2k7 =
|
||||
{
|
||||
.numStages = IIR_TX_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.6869176968793,
|
||||
-0.9512054401742,
|
||||
0.9748233658729,
|
||||
-0.9886769453802,
|
||||
0.9699856293614,
|
||||
-0.976965264625,
|
||||
0.9989051081887,
|
||||
-0.9994482291916,
|
||||
0.9999677314304,
|
||||
-0.9993834480784
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01873226419377,
|
||||
-0.0351077314033,
|
||||
-0.01181875664072,
|
||||
-0.0100003360675,
|
||||
-0.0005123880132686,
|
||||
-0.0002827366407254,
|
||||
6.374826243116e-05,
|
||||
3.655128410718e-06,
|
||||
-1.949876071716e-08,
|
||||
-5.55178847339e-10,
|
||||
3.472732518217e-12
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// IIR filter
|
||||
// lattice ARMA coefficients designed with MATLAb fdatools
|
||||
// bandpass 50 - 2750Hz
|
||||
#define IIR_TX_WIDE_BASS_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_WIDE_BASS =
|
||||
{
|
||||
.numStages = IIR_TX_WIDE_BASS_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.71896929903805900000,
|
||||
-0.95942907850625200000,
|
||||
0.97792311678973200000,
|
||||
-0.98088701203507700000,
|
||||
0.97297595879898900000,
|
||||
-0.99620090645682700000,
|
||||
0.99990501182910600000,
|
||||
-0.99996667856688500000,
|
||||
0.99998653853233900000,
|
||||
-0.99998543366088200000
|
||||
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
-0.00032448877846164900,
|
||||
-0.00117728102231410000,
|
||||
-0.00209099021086666000,
|
||||
-0.00223337754782698000,
|
||||
-0.00122619886193943000,
|
||||
-0.00046485618062794300,
|
||||
0.00001256926158546300,
|
||||
0.00000019091112216183,
|
||||
-0.00000000006469610177,
|
||||
-0.00000000000289012694,
|
||||
1.24E-15
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// 150 - 2850Hz bandpass
|
||||
//
|
||||
#define IIR_TX_WIDE_TREBLE_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_WIDE_TREBLE =
|
||||
{
|
||||
.numStages = IIR_TX_WIDE_TREBLE_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.71896929903807000000,
|
||||
-0.95701929433651100000,
|
||||
0.97688821391048500000,
|
||||
-0.97914462752169300000,
|
||||
0.97381210430161500000,
|
||||
-0.98932784460632400000,
|
||||
0.99918319918236100000,
|
||||
-0.99964609685921500000,
|
||||
0.99997374020338600000,
|
||||
-0.99980049691966100000
|
||||
|
||||
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
-0.00032448877846164000,
|
||||
-0.00117432406256116000,
|
||||
-0.00207458605133000000,
|
||||
-0.00219730703764023000,
|
||||
-0.00117629105002028000,
|
||||
-0.00042269171278772100,
|
||||
0.00003803127953775490,
|
||||
0.00000159703882026720,
|
||||
-0.00000000535014800171,
|
||||
-0.00000000013312786485,
|
||||
2.67655E-13
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// 250 - 2950Hz bandpass
|
||||
//
|
||||
#define IIR_TX_SOPRANO_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_SOPRANO =
|
||||
{
|
||||
.numStages = IIR_TX_SOPRANO_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
0.71987365385562700,
|
||||
-0.95478395730601100,
|
||||
0.97597041246871300,
|
||||
-0.97877331988142200,
|
||||
0.97311471309818900,
|
||||
-0.98013955262452800,
|
||||
0.99791087029646100,
|
||||
-0.99903556044544100,
|
||||
0.99994405075167400,
|
||||
-0.99944176350280300
|
||||
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
-0.00146489605640520,
|
||||
-0.00378491009751258,
|
||||
-0.00400350501493743,
|
||||
-0.00341201203499246,
|
||||
-0.00096809938766577,
|
||||
-0.00035554457716075,
|
||||
0.00007141442667891,
|
||||
0.00000426101940838,
|
||||
-0.00000003996117780,
|
||||
-0.00000000087267111,
|
||||
0.00000000000495626
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Filter designed 2020.05.03 by Y.Korenev UB8JDC using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR, structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - 48 KSPS Sample Rate
|
||||
// - 10th order Elliptic bandpass filter
|
||||
// - Fstop1,2: 100, 6000 Hz
|
||||
// - Single-precision floating-point
|
||||
// - Coefficients importing in reverse order!
|
||||
//
|
||||
#define IIR_TX_eSSB_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_eSSB_6k =
|
||||
{
|
||||
.numStages = IIR_TX_eSSB_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.488251596689224,
|
||||
-0.822531878948212,
|
||||
0.892727732658386,
|
||||
-0.927212417125702,
|
||||
0.841283917427063,
|
||||
-0.972716450691223,
|
||||
0.999650061130524,
|
||||
-0.999866247177124,
|
||||
0.999989390373230,
|
||||
-0.999913930892944
|
||||
},
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.005639570765197,
|
||||
-0.022809743881226,
|
||||
-0.047501564025879,
|
||||
-0.052696328610182,
|
||||
-0.026684369891882,
|
||||
-0.003642551833764,
|
||||
0.002113675698638,
|
||||
3.030856169061735e-05,
|
||||
-3.875512533113579e-08,
|
||||
-9.339896633875355e-10,
|
||||
8.066186607535997e-13
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Filter designed 2020.06.22 by Y.Korenev UB8JDC using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR, structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - 48 KSPS Sample Rate
|
||||
// - 10th order Elliptic bandpass filter
|
||||
// - Fstop1,2: 100, 5000 Hz
|
||||
// - Single-precision floating-point
|
||||
// - Coefficients importing in reverse order!
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_eSSB_5k =
|
||||
{
|
||||
.numStages = IIR_TX_eSSB_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.551112115383148,
|
||||
-0.873203039169312,
|
||||
0.926355421543121,
|
||||
-0.946738958358765,
|
||||
0.894358754158020,
|
||||
-0.980076730251312,
|
||||
0.999654591083527,
|
||||
-0.999865353107452,
|
||||
0.999989390373230,
|
||||
-0.999913752079010
|
||||
|
||||
},
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.003816125448793,
|
||||
-0.013906096108258,
|
||||
-0.026235999539495,
|
||||
-0.027811434119940,
|
||||
-0.013894244097173,
|
||||
-0.003450543386862,
|
||||
8.077293168753386e-04,
|
||||
1.270828852284467e-05,
|
||||
-1.620846745709059e-08,
|
||||
-3.871837017666024e-10,
|
||||
3.327377436079804e-13
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Filter designed 2020.06.22 by Y.Korenev UB8JDC using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR, structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - 48 KSPS Sample Rate
|
||||
// - 10th order Elliptic bandpass filter
|
||||
// - Fstop1,2: 100, 4000 Hz
|
||||
// - Single-precision floating-point
|
||||
// - Coefficients importing in reverse order!
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_eSSB_4k =
|
||||
{
|
||||
.numStages = IIR_TX_eSSB_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.622196376323700,
|
||||
-0.917002677917481,
|
||||
0.953354060649872,
|
||||
-0.964468061923981,
|
||||
0.935390412807465,
|
||||
-0.985710978507996,
|
||||
0.999658346176148,
|
||||
-0.999864161014557,
|
||||
0.999989271163940,
|
||||
-0.999913632869721
|
||||
|
||||
},
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.002526052994654,
|
||||
-0.008019731380045,
|
||||
-0.012725095264614,
|
||||
-0.012484691105783,
|
||||
-0.005546068772674,
|
||||
-0.001818265416659,
|
||||
2.339449711143971e-04,
|
||||
4.331307536631357e-06,
|
||||
-5.518487888878099e-09,
|
||||
-1.312840391953785e-10,
|
||||
1.149562216251621e-13
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 10th order Elliptic bandpass filter
|
||||
// Fstop: 200, 3250 Hz
|
||||
// Fpass: 300, 2575 Hz
|
||||
// -6dB points: 285, 2698 Hz
|
||||
// -10dB points: 281, 2745 Hz
|
||||
// -20dB points: 270, 2845 Hz
|
||||
// -30dB points: <265, >2915 Hz
|
||||
//
|
||||
#define IIR_TX_2k7_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_2k7 = {
|
||||
.numStages = IIR_TX_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.6630364568624,
|
||||
-0.9520893446293,
|
||||
0.9760332145655,
|
||||
-0.9865766256209,
|
||||
0.9831633680402,
|
||||
-0.9684840684235,
|
||||
0.9968012184072,
|
||||
-0.9991378973359,
|
||||
0.9999607252996,
|
||||
-0.9992727516361
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.01765590852027,
|
||||
-0.03197343698045,
|
||||
-0.009018268963126,
|
||||
-0.007790758301124,
|
||||
-0.0001813788700895,
|
||||
-0.0001640724508686,
|
||||
6.107606732009e-05,
|
||||
4.622811990096e-06,
|
||||
-3.806757115088e-08,
|
||||
-5.946272640944e-10,
|
||||
4.410607296057e-12
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20151024 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// This filter is designed for FM voice transmission, removing low-frequency audio
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 10th order Elliptic bandpass filter
|
||||
// Fpass: 225, 2700 Hz
|
||||
//
|
||||
// Amplitude responses - referenced to attenuation at top
|
||||
// Filter has 0 to -2 dB ripple, below referenced to "0" dB point:
|
||||
//
|
||||
// -6dB points: 216, 2786 Hz
|
||||
// -10dB points: 210, 2865 Hz
|
||||
// -20dB points: 193, 3216 Hz
|
||||
// -30dB points: 172, 3478 Hz
|
||||
// -50dB points: 136, 4436 Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_TX_2k7_FM_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_TX_2k7_FM =
|
||||
{
|
||||
.numStages = IIR_TX_2k7_FM_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.795992813347,
|
||||
-0.9682173169759,
|
||||
0.9817510589125,
|
||||
-0.9814547662913,
|
||||
0.9796499689423,
|
||||
-0.9856718628494,
|
||||
0.9982624972485,
|
||||
-0.9990433054892,
|
||||
0.9999481889194,
|
||||
-0.9995181953945
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.000247932512139,
|
||||
-0.000812969420294,
|
||||
-0.001204931403655,
|
||||
-0.001166250382325,
|
||||
-0.0005214249315797,
|
||||
-0.0001861038674673,
|
||||
2.552768869046e-05,
|
||||
1.619179380559e-06,
|
||||
-1.484109718886e-08,
|
||||
-3.31354298817e-10,
|
||||
1.62095434731e-12
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// *** 12 KSPS Sample Rate!
|
||||
//
|
||||
// Nominal 750 Hz center-frequency Filter:
|
||||
//
|
||||
// 10th order Least pth Norm. bandpass filter
|
||||
// Fstop: 500, 990 Hz
|
||||
// Fpass: 613, 885 Hz
|
||||
// -6dB points: 600, 895 Hz
|
||||
// -20dB points: 577, 918
|
||||
// -40dB points: 529, 962
|
||||
// -55dB points: 500, 990
|
||||
//
|
||||
#define IIR_300hz_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_750 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8420268438333,
|
||||
-0.9187411389087,
|
||||
0.991915422724,
|
||||
-0.9269206024542,
|
||||
0.9959665495021,
|
||||
-0.9250959581619,
|
||||
0.9968373894352,
|
||||
-0.9220079563995,
|
||||
0.9954523801454,
|
||||
-0.9320568982728
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-2.528177681235e-05,
|
||||
-0.0001284428108467,
|
||||
-0.0001826561498698,
|
||||
-4.680324147403e-05,
|
||||
-1.767058952639e-05,
|
||||
2.328514864098e-05,
|
||||
7.242100694031e-06,
|
||||
9.825932471565e-07,
|
||||
-2.827695963598e-07,
|
||||
-2.141975226444e-07,
|
||||
9.808568488673e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 800 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_800 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8503130225593,
|
||||
-0.9089732054814,
|
||||
0.9923678320648,
|
||||
-0.9163668504916,
|
||||
0.9961126531134,
|
||||
-0.9147111704054,
|
||||
0.9969873803036,
|
||||
-0.9116164217019,
|
||||
0.9952780046244,
|
||||
-0.9213976892508
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
1.33337610067e-06,
|
||||
7.453841937241e-05,
|
||||
0.0003852357535482,
|
||||
4.561173005598e-05,
|
||||
2.120264803625e-05,
|
||||
-2.713243679097e-05,
|
||||
-9.643727863849e-06,
|
||||
-9.410145539752e-07,
|
||||
3.219855720009e-07,
|
||||
2.507913128879e-07,
|
||||
-1.339507149753e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 850 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_850 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8619678311814,
|
||||
-0.8987132900478,
|
||||
0.9929800321291,
|
||||
-0.9050895035197,
|
||||
0.9962960753259,
|
||||
-0.9035803342684,
|
||||
0.9969741855608,
|
||||
-0.9009035751952,
|
||||
0.9955228844029,
|
||||
-0.9102181260169
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
1.015803230667e-05,
|
||||
7.384809547778e-06,
|
||||
0.0001261434545558,
|
||||
2.625658957163e-05,
|
||||
2.179481057242e-05,
|
||||
-2.078867283811e-05,
|
||||
-8.609229801913e-06,
|
||||
-9.671863254622e-07,
|
||||
2.923861090205e-07,
|
||||
2.778278512409e-07,
|
||||
-1.585347732762e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 900 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_900 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.866224538039,
|
||||
-0.887418184529,
|
||||
0.9931785952017,
|
||||
-0.8934071723653,
|
||||
0.9963609345788,
|
||||
-0.8919370163031,
|
||||
0.9969678377825,
|
||||
-0.8895111671316,
|
||||
0.9955938946628,
|
||||
-0.8983883276963
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
1.027538145593e-11,
|
||||
4.674412003285e-09,
|
||||
8.524980293762e-06,
|
||||
2.781783244349e-05,
|
||||
4.556993427775e-05,
|
||||
7.93734646008e-06,
|
||||
-1.149365906393e-05,
|
||||
-1.373938907669e-06,
|
||||
-5.614114019155e-07,
|
||||
1.999172180075e-07,
|
||||
1.135790394447e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 950 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_950 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8663610198931,
|
||||
-0.8752991478672,
|
||||
0.9931648301256,
|
||||
-0.8812152134726,
|
||||
0.9963683212431,
|
||||
-0.8797440121644,
|
||||
0.9969724019188,
|
||||
-0.8774017131206,
|
||||
0.99556189371,
|
||||
-0.8860148099453
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
1.712527337148e-07,
|
||||
-2.14605366217e-06,
|
||||
-1.282145120929e-06,
|
||||
5.302451577261e-07,
|
||||
3.408583271375e-05,
|
||||
1.981386748243e-05,
|
||||
-9.607488025739e-06,
|
||||
-9.045967855846e-07,
|
||||
-9.463603260528e-07,
|
||||
1.034195562155e-07,
|
||||
1.787682064218e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 700 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_700 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8591958395778,
|
||||
-0.9293736501052,
|
||||
0.9929514387125,
|
||||
-0.9360907399466,
|
||||
0.996226917283,
|
||||
-0.9346339462441,
|
||||
0.9969482667941,
|
||||
-0.931593651892,
|
||||
0.9956636725664,
|
||||
-0.9417304199344
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
5.747022992099e-06,
|
||||
-7.971034438356e-05,
|
||||
0.0001584707032297,
|
||||
1.393289629595e-05,
|
||||
3.190407921738e-05,
|
||||
-1.005193057782e-05,
|
||||
-6.474066693983e-06,
|
||||
-7.589205344351e-07,
|
||||
-1.03047035546e-07,
|
||||
1.28510713565e-07,
|
||||
1.528611528166e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 650 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_650 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8688818948709,
|
||||
-0.9388764394749,
|
||||
0.9934909324643,
|
||||
-0.9448433355565,
|
||||
0.9963549863567,
|
||||
-0.9435572556818,
|
||||
0.9969138747979,
|
||||
-0.9403384327629,
|
||||
0.9961526396361,
|
||||
-0.9518730710222
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-2.242398187584e-07,
|
||||
-4.638289856856e-06,
|
||||
-2.352878220094e-05,
|
||||
-3.080709449559e-05,
|
||||
-1.553328321254e-07,
|
||||
1.417306554582e-05,
|
||||
5.642654818196e-07,
|
||||
4.823112320132e-07,
|
||||
-2.795709228696e-07,
|
||||
-6.539576902733e-08,
|
||||
1.737131589792e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 600 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_600 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8688147751404,
|
||||
-0.947241849841,
|
||||
0.9935473550788,
|
||||
-0.9532141766403,
|
||||
0.9963398104956,
|
||||
-0.9519739167724,
|
||||
0.996893229241,
|
||||
-0.9488062379632,
|
||||
0.9962691170584,
|
||||
-0.960137003826
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.162998232666e-08,
|
||||
2.073677729923e-07,
|
||||
3.52975766574e-06,
|
||||
1.439908057934e-05,
|
||||
1.523851473567e-05,
|
||||
-1.145419163814e-05,
|
||||
-1.088670924934e-06,
|
||||
-5.660706791281e-07,
|
||||
8.554810603011e-08,
|
||||
6.021304731304e-08,
|
||||
-6.066270009946e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 550 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_550 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8541670807411,
|
||||
-0.9541636396546,
|
||||
0.9929236629498,
|
||||
-0.9612744078615,
|
||||
0.9960967701838,
|
||||
-0.9599796643954,
|
||||
0.9968957501619,
|
||||
-0.956635152364,
|
||||
0.9959046900614,
|
||||
-0.9670787808963
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-2.136357455248e-05,
|
||||
0.0001768380226792,
|
||||
0.0002313081587989,
|
||||
4.090518305717e-05,
|
||||
2.238176395873e-05,
|
||||
-9.82968044721e-06,
|
||||
-3.425509918938e-06,
|
||||
-5.382859003672e-07,
|
||||
-2.942934157295e-08,
|
||||
5.198121348388e-08,
|
||||
4.257484469579e-09
|
||||
}
|
||||
};
|
||||
//
|
||||
// 500 Hz center frequency
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_300hz_500 =
|
||||
{
|
||||
.numStages = IIR_300hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.8575481179465,
|
||||
-0.961400641792,
|
||||
0.9932114492888,
|
||||
-0.9681748236979,
|
||||
0.9961324948395,
|
||||
-0.9670693014466,
|
||||
0.9968413643764,
|
||||
-0.9634005824554,
|
||||
0.9964042135888,
|
||||
-0.9748600915123
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-2.891194366311e-07,
|
||||
0.0001916459337858,
|
||||
0.0002267903341803,
|
||||
5.926245389363e-05,
|
||||
2.256777174671e-05,
|
||||
-7.677432110101e-06,
|
||||
-2.587424315593e-06,
|
||||
-5.205542423312e-07,
|
||||
-2.808725036254e-08,
|
||||
3.187553831321e-08,
|
||||
2.504925658148e-09
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 3200Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter 150 - 3200Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_3k2_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k2_LPF =
|
||||
{
|
||||
.numStages = IIR_3k2_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.218694139928302,
|
||||
-0.403838779807303,
|
||||
0.594634035120532,
|
||||
-0.455295219667013,
|
||||
0.893598014796430,
|
||||
-0.118422108607239,
|
||||
0.991224652677821,
|
||||
0.0476094068099549,
|
||||
0.999483170165258,
|
||||
0.0963103336836062
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0292173064645854,
|
||||
0.139171967941396,
|
||||
0.302089953179196,
|
||||
0.315642874138601,
|
||||
0.0977262133806149,
|
||||
-0.0516806998414988,
|
||||
-0.0577240236966878,
|
||||
-0.000850928349123370,
|
||||
0.00696050225811562,
|
||||
0.000139795355880837,
|
||||
-5.20544243489754e-05
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k2_BPF =
|
||||
{
|
||||
.numStages = IIR_3k2_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.226940893639584,
|
||||
-0.423427683999446,
|
||||
0.469848234909221,
|
||||
-0.730589423377186,
|
||||
0.634876055736042,
|
||||
-0.254866265688223,
|
||||
0.950443823908253,
|
||||
-0.994637626804822,
|
||||
0.999635535930601,
|
||||
-0.996861601733971
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0465676087537323,
|
||||
-0.192308251979962,
|
||||
-0.291767361307907,
|
||||
-0.0757211101641522,
|
||||
0.218582885651641,
|
||||
0.124575788231386,
|
||||
-0.0337072066012442,
|
||||
0.0164385733761534,
|
||||
-0.00119735821375683,
|
||||
-3.26543663353371e-05,
|
||||
1.12878126917737e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// LPF:
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 3400Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// BPF:
|
||||
// bandpass filter 150 - 3400Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_3k4_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k4_LPF =
|
||||
{
|
||||
.numStages = IIR_3k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.199549437319537,
|
||||
-0.351164425170794,
|
||||
0.565426959446253,
|
||||
-0.347212945196544,
|
||||
0.903076937389513,
|
||||
0.00604837383458759,
|
||||
0.992097069597849,
|
||||
0.154906080441608,
|
||||
0.999516379489912,
|
||||
0.200159122143531
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0375360428960823,
|
||||
0.175514272047973,
|
||||
0.358379113282395,
|
||||
0.327274521409256,
|
||||
0.0418055459145037,
|
||||
-0.0747547603431524,
|
||||
-0.0419525359249555,
|
||||
0.00238252032207142,
|
||||
0.00672097481119971,
|
||||
8.86692474596773e-05,
|
||||
-0.000108177709927680
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k4_BPF =
|
||||
{
|
||||
.numStages = IIR_3k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.204719622771957,
|
||||
-0.386730932575186,
|
||||
0.387584200592573,
|
||||
-0.700090533739370,
|
||||
0.652085184091423,
|
||||
-0.105219888998415,
|
||||
0.929614073821885,
|
||||
-0.994586210742946,
|
||||
0.999632199294300,
|
||||
-0.996867967817777
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0587697225218063,
|
||||
-0.231747513031753,
|
||||
-0.311574476801376,
|
||||
-0.0140958795068678,
|
||||
0.276927602806913,
|
||||
0.0895259663386021,
|
||||
-0.0561390299585095,
|
||||
0.0254613257946724,
|
||||
-0.00162532862462556,
|
||||
-4.40492441641516e-05,
|
||||
1.51963288604756e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-02
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 3600Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_3k6_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_3k6_LPF =
|
||||
{
|
||||
.numStages = IIR_3k6_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.182604754397413,
|
||||
-0.297364372108114,
|
||||
0.545463598315966,
|
||||
-0.221554941171137,
|
||||
0.914413017285099,
|
||||
0.131148813295864,
|
||||
0.992992542452280,
|
||||
0.260698968055509,
|
||||
0.999556840879677,
|
||||
0.301864824451559
|
||||
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
|
||||
0.0481999578478482,
|
||||
0.218712180455229,
|
||||
0.412921909514823,
|
||||
0.313810309656850,
|
||||
-0.0329738792744796,
|
||||
-0.0858389869457352,
|
||||
-0.0158927513034342,
|
||||
0.00483419702063959,
|
||||
0.00477236245823653,
|
||||
1.66508193628068e-05,
|
||||
-0.000116754074820341
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// *** 12 KSPS Sample Rate!
|
||||
//
|
||||
//
|
||||
// 10th order Elliptic bandpass filter
|
||||
// Fpass: 150, 3465 Hz
|
||||
// -6dB points: 138, 3606 Hz
|
||||
// -20dB points: 120, 3853 Hz
|
||||
// -40dB points: 98, 4191 Hz
|
||||
// -60dB points: <85, >4385 Hz
|
||||
//
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k6_BPF =
|
||||
{
|
||||
.numStages = IIR_3k6_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.1309746791958,
|
||||
-0.3193816788598,
|
||||
0.2931126334419,
|
||||
-0.6722769249819,
|
||||
0.6365603289927,
|
||||
-0.03819195677896,
|
||||
0.9228154008907,
|
||||
-0.9953113565282,
|
||||
0.9995716337798,
|
||||
-0.9970944160657
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.07111514509409,
|
||||
-0.2707254278064,
|
||||
-0.3391742081774,
|
||||
0.0230826255569,
|
||||
0.3263161755735,
|
||||
0.07832215297698,
|
||||
-0.06606133406622,
|
||||
0.03330939215314,
|
||||
-0.001770560523546,
|
||||
-5.405998866079e-05,
|
||||
1.724784082002e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 3800Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
// bandpass filter BPF 150 - 3800Hz
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_3k8_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k8_LPF =
|
||||
{
|
||||
.numStages = IIR_3k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.167955275345335,
|
||||
-0.241109484666904,
|
||||
0.538161432993282,
|
||||
-0.0791711604545083,
|
||||
0.926560053717762,
|
||||
0.254092584645358,
|
||||
0.993888674387578,
|
||||
0.363673903035194,
|
||||
0.999602803572954,
|
||||
0.400290937647385
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0618636668587285,
|
||||
0.269123223807235,
|
||||
0.460519308028180,
|
||||
0.270623345085776,
|
||||
-0.114078077039268,
|
||||
-0.0809257862368131,
|
||||
0.0122835687057461,
|
||||
0.00564462194559656,
|
||||
0.00205421413782014,
|
||||
-3.85276331777984e-05,
|
||||
-8.31130731588567e-05
|
||||
}
|
||||
};
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_3k8_BPF =
|
||||
{
|
||||
.numStages = IIR_3k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.163149581231639,
|
||||
-0.334764418550643,
|
||||
0.204881267601001,
|
||||
-0.602380325621413,
|
||||
0.738422338450555,
|
||||
0.180850983309683,
|
||||
0.821590504163200,
|
||||
-0.994197577474067,
|
||||
0.999626101957683,
|
||||
-0.996879424958163
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-0.0919069404581591,
|
||||
-0.319576688929381,
|
||||
-0.305305278407872,
|
||||
0.164897561830671,
|
||||
0.348959586027291,
|
||||
-0.0157756061640711,
|
||||
-0.0440343211466503,
|
||||
0.0543351559597219,
|
||||
-0.00290737404995828,
|
||||
-7.64322618936331e-05,
|
||||
2.62841509104939e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// *** 12 KSPS Sample Rate!
|
||||
//
|
||||
//
|
||||
// 10th order Elliptic bandpass filter
|
||||
// Fpass: 150, 2700 Hz
|
||||
// -6dB points: 138, 3606 Hz
|
||||
// -20dB points: 120, 3853 Hz
|
||||
// -40dB points: 98, 4191 Hz
|
||||
// -60dB points: <85, >4385 Hz
|
||||
//
|
||||
|
||||
#define IIR_3k_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_3k =
|
||||
{
|
||||
.numStages = IIR_3k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00289573666141589550,
|
||||
0.02895736661415895100,
|
||||
0.13030814976371530000,
|
||||
0.34748839936990744000,
|
||||
0.60810469889733798000,
|
||||
0.72972563867680562000,
|
||||
0.60810469889733798000,
|
||||
0.34748839936990744000,
|
||||
0.13030814976371530000,
|
||||
0.02895736661415895100,
|
||||
0.00289573666141589550
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
1.00000000000000000000,
|
||||
0.00000000000000008232,
|
||||
1.34038326769903440000,
|
||||
-0.00000000000000008232,
|
||||
0.54535390952381724000,
|
||||
0.00000000000000009261,
|
||||
0.07704116610119554600,
|
||||
-0.00000000000000000322,
|
||||
0.00316548154834338670,
|
||||
-0.00000000000000000004,
|
||||
0.00001677879772667541
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-15
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 4200Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_4k2_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_4k2_LPF =
|
||||
{
|
||||
.numStages = IIR_4k2_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.146928213236347,
|
||||
-0.112037098760571,
|
||||
0.573308628506104,
|
||||
0.237996369839101,
|
||||
0.949903541125154,
|
||||
0.484079856668923,
|
||||
0.995620381648115,
|
||||
0.556090559967388,
|
||||
0.999703984324404,
|
||||
0.582944939913576
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.101763006075955,
|
||||
0.390529350317333,
|
||||
0.507373813109782,
|
||||
0.101105933174559,
|
||||
-0.219699891693221,
|
||||
-0.0341597848533599,
|
||||
0.0407495774164026,
|
||||
0.00298273384268377,
|
||||
-0.00135023483300145,
|
||||
-4.39812314239063e-05,
|
||||
-4.24250219673017e-06
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// filter designed with MATLAB fdatools by DD4WH 2016-02-03
|
||||
// initial idea for these filters: Clint KA7OEI
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 4400Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_4k4_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_4k4_LPF =
|
||||
{
|
||||
.numStages = IIR_4k4_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.142124344207148,
|
||||
-0.0322948634379783,
|
||||
0.618111817382185,
|
||||
0.397046008479189,
|
||||
0.960113543408077,
|
||||
0.587394367585518,
|
||||
0.996430642116453,
|
||||
0.643137617322656,
|
||||
0.999755612135519,
|
||||
0.665125140142304
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.130420860087981,
|
||||
0.458803381555481,
|
||||
0.490791158211600,
|
||||
-0.00438502468346513,
|
||||
-0.213305874865595,
|
||||
-0.00833743485729244,
|
||||
0.0354832807597507,
|
||||
0.00122731012273469,
|
||||
-0.00136446459308992,
|
||||
-2.19632806766068e-05,
|
||||
7.11876663672673e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-02
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 4600Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_4k6_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_4k6_LPF =
|
||||
{
|
||||
.numStages = IIR_4k6_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.143211048758245,
|
||||
0.0636595308157890,
|
||||
0.678384747001818,
|
||||
0.544299319747716,
|
||||
0.969133023383267,
|
||||
0.681014534387261,
|
||||
0.997187827029787,
|
||||
0.722612358980166,
|
||||
0.999805647018336,
|
||||
0.739954454035932
|
||||
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.167057909773121,
|
||||
0.527901313830262,
|
||||
0.437747419718857,
|
||||
-0.0980305392148662,
|
||||
-0.167408704264879,
|
||||
0.00853396918515870,
|
||||
0.0231579610435375,
|
||||
0.000144746230869686,
|
||||
-0.000845091312013047,
|
||||
-6.36386754826468e-06,
|
||||
5.95501329503367e-06
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// filter designed with MATLAB fdatools by DD4WH 2016-02-03
|
||||
// initial idea for these filters: Clint KA7OEI
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 4800Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_4k8_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_4k8_LPF =
|
||||
{
|
||||
.numStages = IIR_4k8_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.153116856877746,
|
||||
0.180701877352361,
|
||||
0.748242393147457,
|
||||
0.672766998956057,
|
||||
0.976991110647331,
|
||||
0.763856545049567,
|
||||
0.997879618771176,
|
||||
0.793537908808440,
|
||||
0.999852510953044,
|
||||
0.806593649345542
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.213846255224293,
|
||||
0.591813811815732,
|
||||
0.344831798189898,
|
||||
-0.157607874284224,
|
||||
-0.101315055088023,
|
||||
0.0140678532972274,
|
||||
0.0109533232815195,
|
||||
-0.000216944372851913,
|
||||
-0.000345510532658189,
|
||||
-3.13949510166722e-07,
|
||||
2.38332090327087e-06
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
// filter designed with MATLAB fdatools by DD4WH 2016-02-03
|
||||
// initial idea for these filters: Clint KA7OEI
|
||||
// 12k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass
|
||||
// Fpass 4000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
|
||||
#define IIR_4k_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_4k_LPF =
|
||||
{
|
||||
.numStages = IIR_4k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.155876536292444,
|
||||
-0.180325472152569,
|
||||
0.546715175591137,
|
||||
0.0762684731194015,
|
||||
0.938604917720414,
|
||||
0.372421515579738,
|
||||
0.994769037313590,
|
||||
0.462548368276089,
|
||||
0.999652456699243,
|
||||
0.494335639815055
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0793628035363237,
|
||||
0.326663427969449,
|
||||
0.494575679160066,
|
||||
0.197555516079231,
|
||||
-0.182792933325612,
|
||||
-0.0614448809184776,
|
||||
0.0331486325344859,
|
||||
0.00478157010758418,
|
||||
-0.000230235339343743,
|
||||
-5.64895267110011e-05,
|
||||
-3.66641450827987e-05
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20141202 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// Nominal 750 Hz center-frequency Filter:
|
||||
//
|
||||
// *** 12 KSPS Sample Rate!
|
||||
//
|
||||
// 10th order Least p-th Norm. bandpass filter
|
||||
// Fstop: 320, 1185 Hz
|
||||
// Fpass: 525, 975 Hz
|
||||
// -6dB points: 500, 998 480, 1034 Hz
|
||||
// -20dB points: 454, 1041 410, 1084 Hz
|
||||
// -40dB points: 370, 1125 <304, 1184 Hz
|
||||
// -55dB point: <320Hz -60 dB: >1283 Hz
|
||||
//
|
||||
#define IIR_500hz_numStages 10
|
||||
const arm_iir_lattice_instance_f32 IIR_500hz_750 =
|
||||
{
|
||||
.numStages = IIR_500hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.7450181244202,
|
||||
-0.9084574667981,
|
||||
0.9790083293996,
|
||||
-0.9303082589799,
|
||||
0.9883388157099,
|
||||
-0.9268194870575,
|
||||
0.9907447739419,
|
||||
-0.919714678964,
|
||||
0.9893355692757,
|
||||
-0.9435646976164
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.61639285742e-07,
|
||||
-2.532569769139e-06,
|
||||
-1.730815165529e-05,
|
||||
-6.199614625535e-05,
|
||||
-0.0001162330723378,
|
||||
-9.354099226825e-05,
|
||||
9.396401192372e-06,
|
||||
2.784282263339e-06,
|
||||
8.547158547822e-06,
|
||||
5.265868366272e-07,
|
||||
-7.389379416329e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 850 Hz center
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_500hz_850 =
|
||||
{
|
||||
.numStages = IIR_500hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.7401338925506,
|
||||
-0.8867593927342,
|
||||
0.9778465129623,
|
||||
-0.9094003580498,
|
||||
0.9883168161429,
|
||||
-0.9055217486004,
|
||||
0.9903863113441,
|
||||
-0.8954747103238,
|
||||
0.9912950685125,
|
||||
-0.9298872553011
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-4.410143019036e-06,
|
||||
-9.236919139671e-05,
|
||||
-0.0003954308979742,
|
||||
-0.0003955563639255,
|
||||
-0.0001628454905818,
|
||||
0.0001098763251995,
|
||||
6.339131935123e-05,
|
||||
2.488401959762e-05,
|
||||
-7.761948232174e-06,
|
||||
-3.463637105875e-06,
|
||||
3.023849497139e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 950 Hz center
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_500hz_950 =
|
||||
{
|
||||
.numStages = IIR_500hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.7561294931445,
|
||||
-0.8664471899292,
|
||||
0.9790444302334,
|
||||
-0.8864086051206,
|
||||
0.9889574393432,
|
||||
-0.8826528972432,
|
||||
0.9908739731213,
|
||||
-0.8721677687198,
|
||||
0.9905929406153,
|
||||
-0.9077406187546
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
-1.978764105412e-06,
|
||||
-4.109388008507e-05,
|
||||
-0.0002182934662175,
|
||||
-0.0002429079035953,
|
||||
-0.0002277987829458,
|
||||
0.0001122347644774,
|
||||
6.888195567177e-05,
|
||||
2.855449207125e-05,
|
||||
-6.041821715252e-06,
|
||||
-4.915517444392e-06,
|
||||
3.936206528372e-07
|
||||
}
|
||||
};
|
||||
//
|
||||
// 650 Hz center
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_500hz_650 =
|
||||
{
|
||||
.numStages = IIR_500hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.7629545983553,
|
||||
-0.9292246993992,
|
||||
0.9812440354719,
|
||||
-0.9481158800736,
|
||||
0.9886964977718,
|
||||
-0.9455424450397,
|
||||
0.9898872346552,
|
||||
-0.9387191189796,
|
||||
0.9935074333889,
|
||||
-0.9667663712751
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
7.913288912416e-08,
|
||||
-8.145261857675e-06,
|
||||
9.724845240669e-05,
|
||||
0.0002513968527392,
|
||||
0.0001566426842087,
|
||||
-1.692018078797e-05,
|
||||
-2.026140586575e-05,
|
||||
-1.410159029616e-05,
|
||||
-3.517554836743e-07,
|
||||
9.445267691075e-07,
|
||||
6.313896488397e-08
|
||||
}
|
||||
};
|
||||
//
|
||||
// 550 Hz center
|
||||
//
|
||||
const arm_iir_lattice_instance_f32 IIR_500hz_550 =
|
||||
{
|
||||
.numStages = IIR_500hz_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.7444824297014,
|
||||
-0.9426910512095,
|
||||
0.9809095416549,
|
||||
-0.9635826118077,
|
||||
0.9879143935335,
|
||||
-0.9619675085485,
|
||||
0.9892963956729,
|
||||
-0.9551745584075,
|
||||
0.9937943260814,
|
||||
-0.980312269594
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
6.54693860799e-11,
|
||||
-1.725286655686e-08,
|
||||
1.274335799922e-06,
|
||||
-2.347197649254e-05,
|
||||
0.0001149607579105,
|
||||
-5.20632558042e-05,
|
||||
-1.133152510209e-06,
|
||||
-9.492268935446e-06,
|
||||
3.245552848263e-08,
|
||||
5.879262051272e-07,
|
||||
-1.546228266662e-08
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 5500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_5k5_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_5k5_LPF =
|
||||
{
|
||||
.numStages = IIR_5k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.270056112170917,
|
||||
-0.521414453389724,
|
||||
0.678616912945954,
|
||||
-0.641289912968769,
|
||||
0.883688002282309,
|
||||
-0.381347496766270,
|
||||
0.989526871938782,
|
||||
-0.192450450475999,
|
||||
0.999443061271067,
|
||||
-0.139179149092653
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0165986011732628,
|
||||
0.0791435170266696,
|
||||
0.186630364068749,
|
||||
0.233915282634195,
|
||||
0.138804057676891,
|
||||
0.00684091782624835,
|
||||
-0.0470727830131718,
|
||||
-0.00518447562091082,
|
||||
0.00219719710580432,
|
||||
8.29160622089417e-05,
|
||||
8.64931555180915e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 5000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_5k_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_5k_LPF =
|
||||
{
|
||||
.numStages = IIR_5k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.304008884053488,
|
||||
-0.586479754574523,
|
||||
0.728707358729566,
|
||||
-0.717591127840479,
|
||||
0.886460005029009,
|
||||
-0.509239560057348,
|
||||
0.988906686305070,
|
||||
-0.320749263130520,
|
||||
0.999445512653576,
|
||||
-0.267299520678722
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0121126909328103,
|
||||
0.0563705089486983,
|
||||
0.135077706371490,
|
||||
0.177369645199308,
|
||||
0.122940273900304,
|
||||
0.0249807561603719,
|
||||
-0.0272356075029574,
|
||||
-0.00442102257133439,
|
||||
-0.000487963028261214,
|
||||
9.54073216847401e-06,
|
||||
8.24834253008722e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 6500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_6k5_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_6k5_LPF =
|
||||
{
|
||||
.numStages = IIR_6k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.213702079803504,
|
||||
-0.390726329295393,
|
||||
0.586645549319686,
|
||||
-0.429887036682493,
|
||||
0.895736972595422,
|
||||
-0.0875234251266855,
|
||||
0.991439058220713,
|
||||
0.0745020436698480,
|
||||
0.999490700886464,
|
||||
0.122410371569787
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0311072717160539,
|
||||
0.147645149046583,
|
||||
0.316095562243594,
|
||||
0.320547362746078,
|
||||
0.0859079982599722,
|
||||
-0.0582045525665189,
|
||||
-0.0550274347397058,
|
||||
-3.62573178755987e-05,
|
||||
0.00708241752078387,
|
||||
0.000130934259420401,
|
||||
-6.94896100042891e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 10th order IIR Elliptic lowpass LPF
|
||||
// Fpass 6000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_6k_numStages 10
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_6k_LPF =
|
||||
{
|
||||
.numStages = IIR_6k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.240061145139098,
|
||||
-0.456135423117119,
|
||||
0.629931199814858,
|
||||
-0.546874535504622,
|
||||
0.886954490804698,
|
||||
-0.239344357593924,
|
||||
0.990406694917175,
|
||||
-0.0598647009288412,
|
||||
0.999458839296527,
|
||||
-0.00852401189342987
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0227312628074594,
|
||||
0.109078946204801,
|
||||
0.247843364281694,
|
||||
0.285784016518540,
|
||||
0.129833944671845,
|
||||
-0.0238187084272364,
|
||||
-0.0598880195707474,
|
||||
-0.00364575842735154,
|
||||
0.00541066911948504,
|
||||
0.000142100013861043,
|
||||
2.39142895447318e-05
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 7500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_7k5_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_7k5_LPF =
|
||||
{
|
||||
.numStages = IIR_7k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.171676312284558,
|
||||
-0.248915944482148,
|
||||
0.554808670292421,
|
||||
-0.0804708303821426,
|
||||
0.937673773552786,
|
||||
0.255249586500978,
|
||||
0.996592749183544,
|
||||
0.364810653255913
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0631810509418012,
|
||||
0.273620653809899,
|
||||
0.462876563831051,
|
||||
0.260420336947869,
|
||||
-0.123177317150119,
|
||||
-0.0730805396001466,
|
||||
0.0163120102308616,
|
||||
0.00402985085145935,
|
||||
0.00101856811686258
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 7000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_7k_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_7k_LPF =
|
||||
{
|
||||
.numStages = IIR_7k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.190713577571592,
|
||||
-0.319871726375826,
|
||||
0.565395988442476,
|
||||
-0.255306414282902,
|
||||
0.924727833564385,
|
||||
0.104786836584826,
|
||||
0.995972585176399,
|
||||
0.237878968193324
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0464388990834632,
|
||||
0.211741818487612,
|
||||
0.403878817111474,
|
||||
0.311449064277157,
|
||||
-0.0264024657273338,
|
||||
-0.0789871827367324,
|
||||
-0.0150701534983805,
|
||||
0.00343825204070403,
|
||||
0.00335955618048627
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 8500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_8k5_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_8k5_LPF =
|
||||
{
|
||||
.numStages = IIR_8k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.147016458647620,
|
||||
-0.0800576834677209,
|
||||
0.607415025263421,
|
||||
0.311944568388449,
|
||||
0.961718465037911,
|
||||
0.531590985304236,
|
||||
0.997775367200182,
|
||||
0.597158407524272
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.116227477513591,
|
||||
0.426616080915722,
|
||||
0.501928042829669,
|
||||
0.0426267579687529,
|
||||
-0.221292633625496,
|
||||
-0.0171136752421530,
|
||||
0.0374419493102454,
|
||||
0.00134067435969376,
|
||||
-0.00112236216067886
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 8000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_8k_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_8k_LPF =
|
||||
{
|
||||
.numStages = IIR_8k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.156730412841056,
|
||||
-0.170860629143791,
|
||||
0.567767507488873,
|
||||
0.113051837961350,
|
||||
0.950299005264617,
|
||||
0.398693812045436,
|
||||
0.997198510683089,
|
||||
0.485296093326901
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0857789183340628,
|
||||
0.345903140429045,
|
||||
0.500262683274993,
|
||||
0.165780339808995,
|
||||
-0.198921078104878,
|
||||
-0.0482542902035035,
|
||||
0.0362835359961724,
|
||||
0.00297622750353344,
|
||||
-0.000691737718980207
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// Filter designed 20151022 by C. Turner, KA7OEI using MatLAB fdatools
|
||||
//
|
||||
// NOTE:
|
||||
// - IIR structure is Lattice Autoregressive Moving-Average (ARMA)
|
||||
// - ARM FIR/IIR algorithms require time reverse-order coefficients!!!
|
||||
//
|
||||
// 6th order Elliptic highpass filter
|
||||
//
|
||||
//
|
||||
// -6dB point: 8.4 kHz
|
||||
// -20dB point: 8.0 kHz
|
||||
// -40dB point: 7.4 kHz
|
||||
// -60dB point: <7.0 kHz
|
||||
//
|
||||
//#define NCoef 8
|
||||
#define IIR_8k5_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_8k5_hpf =
|
||||
{
|
||||
.numStages = IIR_8k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.3267431914313,
|
||||
0.2827426748037,
|
||||
0.6792677220421,
|
||||
-0.08412750477612,
|
||||
0.9796815399487,
|
||||
-0.3939883111528
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.07735072858385,
|
||||
-0.306940854114,
|
||||
0.4145882522999,
|
||||
-0.09894434429254,
|
||||
-0.1687647954502,
|
||||
0.01867899629887,
|
||||
0.02161688514499
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 9500Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_9k5_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_9k5_LPF =
|
||||
{
|
||||
.numStages = IIR_9k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.154589161975431,
|
||||
0.171214182840522,
|
||||
0.752540038804833,
|
||||
0.661446067312243,
|
||||
0.979967038791770,
|
||||
0.755243080342941,
|
||||
0.998791846173898,
|
||||
0.787213445621968
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.212160913842594,
|
||||
0.589885689317715,
|
||||
0.348337037956110,
|
||||
-0.155662625526521,
|
||||
-0.103203755044854,
|
||||
0.0134205375549463,
|
||||
0.0105947295297542,
|
||||
-0.000168431246632794,
|
||||
-0.000257624900844355
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// alternative filter designed with MATLAB fdatools by DD4WH 2016-02-18
|
||||
// 24k sampling rate, Lattice ARMA structure
|
||||
// 8th order IIR Elliptic lowpass LPF
|
||||
// Fpass 9000Hz
|
||||
// Astop 60dB
|
||||
// coefficients in reverse order than that spit out by MATLAB
|
||||
//
|
||||
//
|
||||
|
||||
#define IIR_9k_numStages 8
|
||||
|
||||
const arm_iir_lattice_instance_f32 IIR_9k_LPF =
|
||||
{
|
||||
.numStages = IIR_9k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.144843368057163,
|
||||
0.0311176821163535,
|
||||
0.671835107699585,
|
||||
0.499495871489971,
|
||||
0.971603001167062,
|
||||
0.651162915986589,
|
||||
0.998310568870827,
|
||||
0.698395145953468
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.157182890700946,
|
||||
0.510999353559437,
|
||||
0.454077934277190,
|
||||
-0.0776493551890845,
|
||||
-0.180998321432113,
|
||||
0.00575759072640292,
|
||||
0.0249744575699347,
|
||||
0.000197356170009044,
|
||||
-0.000725804365039828
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
//
|
||||
// IIR filter
|
||||
// lattice ARMA coefficients designed with MATLAb fdatools
|
||||
// DD4WH 2016-03-05
|
||||
// inspired by Clint KA7OEI
|
||||
//
|
||||
// LPF 5k elliptic, 60dB stopband, 48ksps
|
||||
|
||||
#define IIR_aa_5k_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_5k =
|
||||
{
|
||||
.numStages = IIR_aa_5k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.547564303565301,
|
||||
-0.874437851307620,
|
||||
0.929381964274064,
|
||||
-0.931756218288255,
|
||||
0.967791921156360,
|
||||
-0.855303237881406
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00321398613474079,
|
||||
0.0103775071609725,
|
||||
0.0204793631675465,
|
||||
0.0207411754628459,
|
||||
0.0142582715360116,
|
||||
0.00416771325172439,
|
||||
0.000586794199906653
|
||||
}
|
||||
};
|
||||
|
||||
// IIR elliptic 48ksps, 6th order, FStop = 10000Hz
|
||||
// -60dB stopband att, ARMA structure, coefficients in reversed order
|
||||
|
||||
#define IIR_aa_10k_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_10k =
|
||||
{
|
||||
.numStages = IIR_aa_10k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.301098203357079,
|
||||
-0.579105658407328,
|
||||
0.734150184329856,
|
||||
-0.671115797851337,
|
||||
0.939860662239371,
|
||||
-0.361103585037447
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0174468544108513,
|
||||
0.0830073641688922,
|
||||
0.190703913563757,
|
||||
0.218380125399821,
|
||||
0.102432703504841,
|
||||
-0.00776347779147436,
|
||||
-0.0322591772433757
|
||||
}
|
||||
};
|
||||
|
||||
// IIR elliptic 48ksps, 6th order, FStop = 8000Hz
|
||||
// -60dB stopband att, ARMA structure, coefficients in reversed order
|
||||
|
||||
#define IIR_aa_8k_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_8k =
|
||||
{
|
||||
.numStages = IIR_aa_8k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.382097471026454,
|
||||
-0.707860806497603,
|
||||
0.822488299956015,
|
||||
-0.809655940560093,
|
||||
0.943091324035883,
|
||||
-0.602154271982275
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.00902518911329759,
|
||||
0.0401957378835905,
|
||||
0.0934435150148285,
|
||||
0.114552126526293,
|
||||
0.0734506802740618,
|
||||
0.0130302613689033,
|
||||
-0.0115031852097110
|
||||
}
|
||||
};
|
||||
|
||||
// IIR elliptic 48ksps, 6th order, FStop = 8500Hz
|
||||
// -60dB stopband att, ARMA structure, coefficients in reversed order
|
||||
|
||||
#define IIR_aa_8k5_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_8k5 =
|
||||
{
|
||||
.numStages = IIR_aa_8k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.359939618704540,
|
||||
-0.676489478729843,
|
||||
0.801069829925990,
|
||||
-0.780419188957268,
|
||||
0.941052598112166,
|
||||
-0.546710306936035
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0106702880998750,
|
||||
0.0487135595564791,
|
||||
0.113867385924671,
|
||||
0.139020661730700,
|
||||
0.0847861503854092,
|
||||
0.0109690817210141,
|
||||
-0.0167288132890575
|
||||
}
|
||||
};
|
||||
// IIR elliptic 48ksps, 6th order, FStop = 9000Hz
|
||||
// -60dB stopband att, ARMA structure, coefficients in reversed order
|
||||
|
||||
#define IIR_aa_9k_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_9k =
|
||||
{
|
||||
.numStages = IIR_aa_9k_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.339100957220132,
|
||||
-0.644493816414106,
|
||||
0.779034723806422,
|
||||
-0.747849414036102,
|
||||
0.939827557980654,
|
||||
-0.487848762987584
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0125932272310938,
|
||||
0.0585929866522992,
|
||||
0.136927898008432,
|
||||
0.165069644706020,
|
||||
0.0942562014345331,
|
||||
0.00684027662013907,
|
||||
-0.0223862358637905
|
||||
}
|
||||
};
|
||||
|
||||
// IIR elliptic 48ksps, 6th order, FStop = 9500Hz
|
||||
// -60dB stopband att, ARMA structure, coefficients in reversed order
|
||||
|
||||
#define IIR_aa_9k5_numStages 6
|
||||
const arm_iir_lattice_instance_f32 IIR_aa_9k5 =
|
||||
{
|
||||
.numStages = IIR_aa_9k5_numStages,
|
||||
.pkCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.319509178478567,
|
||||
-0.611998056066153,
|
||||
0.756628846034883,
|
||||
-0.711556259037217,
|
||||
0.939435113760607,
|
||||
-0.425861390235328
|
||||
},
|
||||
|
||||
.pvCoeffs = (float*) (const float[])
|
||||
{
|
||||
0.0148361127984778,
|
||||
0.0699763422680422,
|
||||
0.162584450093266,
|
||||
0.191872694251187,
|
||||
0.100583774752231,
|
||||
0.000539571340153120,
|
||||
-0.0278287915752199
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,774 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "filters.h"
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* 10 kHz lowpass
|
||||
* Fc = 9.70 kHz
|
||||
*
|
||||
* -6dB @ 10.0 kHz
|
||||
* -20dB @ 10.45 kHz
|
||||
* -40dB @ 10.8 kHz
|
||||
* -60dB > 11.13 kHz
|
||||
*
|
||||
* 20141205 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*/
|
||||
|
||||
const float iq_rx_am_10k_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
0.000117722483050164,
|
||||
-0.000190826378141535,
|
||||
-0.000316454605198105,
|
||||
0.000084665259804020,
|
||||
0.000534437033829599,
|
||||
0.000223520439161135,
|
||||
-0.000632342517282613,
|
||||
-0.000725725616097602,
|
||||
0.000428204065620224,
|
||||
0.001280215798621918,
|
||||
0.000218375537426833,
|
||||
-0.001601721502248780,
|
||||
-0.001292161293926300,
|
||||
0.001330681506383581,
|
||||
0.002528032564646596,
|
||||
-0.000185878610189881,
|
||||
-0.003399805802419520,
|
||||
-0.001839090604793820,
|
||||
0.003240267262336325,
|
||||
0.004316174080536414,
|
||||
-0.001493992133713610,
|
||||
-0.006356339576212520,
|
||||
-0.001960308149814000,
|
||||
0.006786095910800701,
|
||||
0.006537642652845357,
|
||||
-0.004528723876747330,
|
||||
-0.010862593712668900,
|
||||
-0.000897173759372233,
|
||||
0.012971399058043866,
|
||||
0.008921931792469471,
|
||||
-0.010804921591446800,
|
||||
-0.017688783704440600,
|
||||
0.002879095183285337,
|
||||
0.024147999555009812,
|
||||
0.011076579092093660,
|
||||
-0.024429930878634200,
|
||||
-0.029750803160671700,
|
||||
0.014143913162437944,
|
||||
0.050329661474116855,
|
||||
0.012584602054512364,
|
||||
-0.069061533914324600,
|
||||
-0.071583230484314000,
|
||||
0.082176152223611229,
|
||||
0.306148763236497423,
|
||||
0.413192420891035361,
|
||||
0.306148763236497423,
|
||||
0.082176152223611229,
|
||||
-0.071583230484314000,
|
||||
-0.069061533914324600,
|
||||
0.012584602054512364,
|
||||
0.050329661474116855,
|
||||
0.014143913162437944,
|
||||
-0.029750803160671700,
|
||||
-0.024429930878634200,
|
||||
0.011076579092093660,
|
||||
0.024147999555009812,
|
||||
0.002879095183285337,
|
||||
-0.017688783704440600,
|
||||
-0.010804921591446800,
|
||||
0.008921931792469471,
|
||||
0.012971399058043866,
|
||||
-0.000897173759372233,
|
||||
-0.010862593712668900,
|
||||
-0.004528723876747330,
|
||||
0.006537642652845357,
|
||||
0.006786095910800701,
|
||||
-0.001960308149814000,
|
||||
-0.006356339576212520,
|
||||
-0.001493992133713610,
|
||||
0.004316174080536414,
|
||||
0.003240267262336325,
|
||||
-0.001839090604793820,
|
||||
-0.003399805802419520,
|
||||
-0.000185878610189881,
|
||||
0.002528032564646596,
|
||||
0.001330681506383581,
|
||||
-0.001292161293926300,
|
||||
-0.001601721502248780,
|
||||
0.000218375537426833,
|
||||
0.001280215798621918,
|
||||
0.000428204065620224,
|
||||
-0.000725725616097602,
|
||||
-0.000632342517282613,
|
||||
0.000223520439161135,
|
||||
0.000534437033829599,
|
||||
0.000084665259804020,
|
||||
-0.000316454605198105,
|
||||
-0.000190826378141535,
|
||||
0.000117722483050164
|
||||
};
|
||||
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* "2.3 kHz lowpass"
|
||||
*
|
||||
* NOTE: Because the actual bandpass is TWICE the lowpass, and the fact that one must off-
|
||||
* tune the receiver slightly to avoid the "zero-Hz" hole in the center of the passband,
|
||||
* this filter is somewhat narrower than "2.3 kHz"
|
||||
*
|
||||
* Fc = 1.78 kHz
|
||||
*
|
||||
* -6dB @ 1.99 kHz
|
||||
* -20dB @ 2.55 kHz
|
||||
* -40dB @ 2.90 kHz
|
||||
* -60dB > 3.09 kHz
|
||||
*
|
||||
* 20141205 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*/
|
||||
|
||||
const float iq_rx_am_2k3_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
-0.000196778133038791,
|
||||
-0.000275755280074211,
|
||||
-0.000353984612861587,
|
||||
-0.000418690075048854,
|
||||
-0.000454047164276299,
|
||||
-0.000442413394049822,
|
||||
-0.000366184434389176,
|
||||
-0.000210191425343778,
|
||||
0.000035537284709122,
|
||||
0.000372915408768254,
|
||||
0.000793177355713582,
|
||||
0.001274879514193310,
|
||||
0.001782913716894173,
|
||||
0.002268882448091475,
|
||||
0.002673096205319169,
|
||||
0.002928317701073665,
|
||||
0.002965203927037432,
|
||||
0.002719199905849284,
|
||||
0.002138436401413266,
|
||||
0.001192000201349910,
|
||||
-0.000122197108217858,
|
||||
-0.001770806410417120,
|
||||
-0.003680540305986990,
|
||||
-0.005736552692955240,
|
||||
-0.007784289231932950,
|
||||
-0.009635139756152750,
|
||||
-0.011075900709763000,
|
||||
-0.011881696038148500,
|
||||
-0.011831641788347900,
|
||||
-0.010726209478865100,
|
||||
-0.008404982146732770,
|
||||
-0.004763336656982600,
|
||||
0.000233449848468894,
|
||||
0.006540069844680653,
|
||||
0.014026193505423940,
|
||||
0.022477415356206891,
|
||||
0.031602482869331178,
|
||||
0.041046636023995359,
|
||||
0.050410360909975617,
|
||||
0.059272371807803176,
|
||||
0.067215232024002855,
|
||||
0.073851744736956312,
|
||||
0.078850120995801118,
|
||||
0.081955978437540142,
|
||||
0.083009440825973363,
|
||||
0.081955978437540142,
|
||||
0.078850120995801118,
|
||||
0.073851744736956312,
|
||||
0.067215232024002855,
|
||||
0.059272371807803176,
|
||||
0.050410360909975617,
|
||||
0.041046636023995359,
|
||||
0.031602482869331178,
|
||||
0.022477415356206891,
|
||||
0.014026193505423940,
|
||||
0.006540069844680653,
|
||||
0.000233449848468894,
|
||||
-0.004763336656982600,
|
||||
-0.008404982146732770,
|
||||
-0.010726209478865100,
|
||||
-0.011831641788347900,
|
||||
-0.011881696038148500,
|
||||
-0.011075900709763000,
|
||||
-0.009635139756152750,
|
||||
-0.007784289231932950,
|
||||
-0.005736552692955240,
|
||||
-0.003680540305986990,
|
||||
-0.001770806410417120,
|
||||
-0.000122197108217858,
|
||||
0.001192000201349910,
|
||||
0.002138436401413266,
|
||||
0.002719199905849284,
|
||||
0.002965203927037432,
|
||||
0.002928317701073665,
|
||||
0.002673096205319169,
|
||||
0.002268882448091475,
|
||||
0.001782913716894173,
|
||||
0.001274879514193310,
|
||||
0.000793177355713582,
|
||||
0.000372915408768254,
|
||||
0.000035537284709122,
|
||||
-0.000210191425343778,
|
||||
-0.000366184434389176,
|
||||
-0.000442413394049822,
|
||||
-0.000454047164276299,
|
||||
-0.000418690075048854,
|
||||
-0.000353984612861587,
|
||||
-0.000275755280074211,
|
||||
-0.000196778133038791
|
||||
};
|
||||
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* 3.6 kHz lowpass
|
||||
* Fc = 3.41 kHz
|
||||
*
|
||||
* -6dB @ 3.61 kHz
|
||||
* -20dB @ 4.15 kHz
|
||||
* -40dB @ 4.52 kHz
|
||||
* -60dB > 4.73 kHz
|
||||
*
|
||||
* 20141205 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*/
|
||||
|
||||
const float iq_rx_am_3k6_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
0.000194236006761998,
|
||||
0.000282693396615949,
|
||||
0.000320173787778202,
|
||||
0.000266033714965954,
|
||||
0.000094222201767759,
|
||||
-0.000191128727083006,
|
||||
-0.000544956187969324,
|
||||
-0.000880855390916938,
|
||||
-0.001084659388254350,
|
||||
-0.001042012424123070,
|
||||
-0.000675226060253367,
|
||||
0.000019767665763547,
|
||||
0.000948239863530163,
|
||||
0.001914701347780859,
|
||||
0.002651381830401708,
|
||||
0.002876822184755611,
|
||||
0.002374910694293840,
|
||||
0.001076052561405293,
|
||||
-0.000882983411525426,
|
||||
-0.003143324896504320,
|
||||
-0.005167612397018260,
|
||||
-0.006344612664735190,
|
||||
-0.006139510014581940,
|
||||
-0.004258448206719960,
|
||||
-0.000785356097214045,
|
||||
0.003751918439268481,
|
||||
0.008418658238655563,
|
||||
0.012024924259495225,
|
||||
0.013375473421118661,
|
||||
0.011573528596812616,
|
||||
0.006312844603313269,
|
||||
-0.001915215334099090,
|
||||
-0.011763413332218100,
|
||||
-0.021156533713089800,
|
||||
-0.027603877979735700,
|
||||
-0.028651610038411300,
|
||||
-0.022392825182070700,
|
||||
-0.007931207001952560,
|
||||
0.014305891795470664,
|
||||
0.042485370371458303,
|
||||
0.073554037962071023,
|
||||
0.103673924978429130,
|
||||
0.128835165244061745,
|
||||
0.145533526176055278,
|
||||
0.151381738212891748,
|
||||
0.145533526176055278,
|
||||
0.128835165244061745,
|
||||
0.103673924978429130,
|
||||
0.073554037962071023,
|
||||
0.042485370371458303,
|
||||
0.014305891795470664,
|
||||
-0.007931207001952560,
|
||||
-0.022392825182070700,
|
||||
-0.028651610038411300,
|
||||
-0.027603877979735700,
|
||||
-0.021156533713089800,
|
||||
-0.011763413332218100,
|
||||
-0.001915215334099090,
|
||||
0.006312844603313269,
|
||||
0.011573528596812616,
|
||||
0.013375473421118661,
|
||||
0.012024924259495225,
|
||||
0.008418658238655563,
|
||||
0.003751918439268481,
|
||||
-0.000785356097214045,
|
||||
-0.004258448206719960,
|
||||
-0.006139510014581940,
|
||||
-0.006344612664735190,
|
||||
-0.005167612397018260,
|
||||
-0.003143324896504320,
|
||||
-0.000882983411525426,
|
||||
0.001076052561405293,
|
||||
0.002374910694293840,
|
||||
0.002876822184755611,
|
||||
0.002651381830401708,
|
||||
0.001914701347780859,
|
||||
0.000948239863530163,
|
||||
0.000019767665763547,
|
||||
-0.000675226060253367,
|
||||
-0.001042012424123070,
|
||||
-0.001084659388254350,
|
||||
-0.000880855390916938,
|
||||
-0.000544956187969324,
|
||||
-0.000191128727083006,
|
||||
0.000094222201767759,
|
||||
0.000266033714965954,
|
||||
0.000320173787778202,
|
||||
0.000282693396615949,
|
||||
0.000194236006761998,
|
||||
};
|
||||
|
||||
/* alternative lowpass filter for AM demodulation
|
||||
*
|
||||
* the problem with the 5k filter is that heterodynes that occur
|
||||
* because of the 5k carrier spacing in broadcast stations
|
||||
* therefore this alternative filter with a cutoff at 4k5
|
||||
* 89 tap FIR lowpass filter
|
||||
* 4k5 lowpass ParkMcClellan
|
||||
*
|
||||
* -6dB @ 4.5kHz
|
||||
* -24dB @ 5kHz
|
||||
* Fc = 4.32kHz (0.1800)
|
||||
* Window off, transition width 0.06
|
||||
*
|
||||
*/
|
||||
const float iq_rx_am_4k5_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
12.62505461280822420E-6,
|
||||
-0.001023781148748946,
|
||||
-0.001379392726010002,
|
||||
-0.001857298885889991,
|
||||
-0.002007930982712860,
|
||||
-0.001645764802591053,
|
||||
-729.0049453258671970E-6,
|
||||
580.3247418821165410E-6,
|
||||
0.001921187006321661,
|
||||
0.002821439596649512,
|
||||
0.002854663846093201,
|
||||
0.001821006157654806,
|
||||
-121.3991924356805900E-6,
|
||||
-0.002433909268373769,
|
||||
-0.004320619640730387,
|
||||
-0.004979702734199301,
|
||||
-0.003909641145391516,
|
||||
-0.001164372205549721,
|
||||
0.002556303856712675,
|
||||
0.006045165075114637,
|
||||
0.007947771772716222,
|
||||
0.007246305410655999,
|
||||
0.003707127946145705,
|
||||
-0.001883752703394752,
|
||||
-0.007825126886278979,
|
||||
-0.011964484776280015,
|
||||
-0.012414164965104595,
|
||||
-0.008297951368073063,
|
||||
-261.8431451219605610E-6,
|
||||
0.009476671671323595,
|
||||
0.017635986356801487,
|
||||
0.020847250650268035,
|
||||
0.016840077425071362,
|
||||
0.005464567575098569,
|
||||
-0.010818978674222298,
|
||||
-0.027219933295235161,
|
||||
-0.037686443762518306,
|
||||
-0.036521090442195647,
|
||||
-0.020119645677827265,
|
||||
0.011696759647048831,
|
||||
0.055173533570635397,
|
||||
0.103180886473356048,
|
||||
0.146733643399102748,
|
||||
0.177107579650033015,
|
||||
0.187997676685657006,
|
||||
0.177107579650033015,
|
||||
0.146733643399102748,
|
||||
0.103180886473356048,
|
||||
0.055173533570635397,
|
||||
0.011696759647048831,
|
||||
-0.020119645677827265,
|
||||
-0.036521090442195647,
|
||||
-0.037686443762518306,
|
||||
-0.027219933295235161,
|
||||
-0.010818978674222298,
|
||||
0.005464567575098569,
|
||||
0.016840077425071362,
|
||||
0.020847250650268035,
|
||||
0.017635986356801487,
|
||||
0.009476671671323595,
|
||||
-261.8431451219605610E-6,
|
||||
-0.008297951368073063,
|
||||
-0.012414164965104595,
|
||||
-0.011964484776280015,
|
||||
-0.007825126886278979,
|
||||
-0.001883752703394752,
|
||||
0.003707127946145705,
|
||||
0.007246305410655999,
|
||||
0.007947771772716222,
|
||||
0.006045165075114637,
|
||||
0.002556303856712675,
|
||||
-0.001164372205549721,
|
||||
-0.003909641145391516,
|
||||
-0.004979702734199301,
|
||||
-0.004320619640730387,
|
||||
-0.002433909268373769,
|
||||
-121.3991924356805900E-6,
|
||||
0.001821006157654806,
|
||||
0.002854663846093201,
|
||||
0.002821439596649512,
|
||||
0.001921187006321661,
|
||||
580.3247418821165410E-6,
|
||||
-729.0049453258671970E-6,
|
||||
-0.001645764802591053,
|
||||
-0.002007930982712860,
|
||||
-0.001857298885889991,
|
||||
-0.001379392726010002,
|
||||
-0.001023781148748946,
|
||||
12.62505461280822420E-6
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* 5 kHz lowpass
|
||||
* Fc = 2.30 kHz (0.096)
|
||||
* BW = 5.09 kHz (0.212)
|
||||
* Phase = 0.0 Deg
|
||||
*
|
||||
* -6dB @ 5.0 kHz
|
||||
* -20dB @ 5.6 kHz
|
||||
* -40dB @ 6.0 kHz
|
||||
* -60dB > 6.2 kHz
|
||||
*
|
||||
* 20150724 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*
|
||||
*/
|
||||
|
||||
const float iq_rx_am_5k_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
-0.000045392289047881,
|
||||
-0.000004812442917794,
|
||||
0.000068727674699516,
|
||||
0.000141963927224663,
|
||||
0.000157520248119967,
|
||||
0.000060286967439699,
|
||||
-0.000162970122246712,
|
||||
-0.000451252675540791,
|
||||
-0.000669397068852781,
|
||||
-0.000655786056558042,
|
||||
-0.000308946001031250,
|
||||
0.000323862987296878,
|
||||
0.001009151276280870,
|
||||
0.001383767648753940,
|
||||
0.001108841899531180,
|
||||
0.000068694704026995,
|
||||
-0.001482086048715270,
|
||||
-0.002923873990383000,
|
||||
-0.003478042196892240,
|
||||
-0.002567012208450240,
|
||||
-0.000183058152703148,
|
||||
0.002927838581731980,
|
||||
0.005419014927265250,
|
||||
0.005850957020138160,
|
||||
0.003392366775186750,
|
||||
-0.001589789749145610,
|
||||
-0.007378579320778290,
|
||||
-0.011384168739919100,
|
||||
-0.011175196307323000,
|
||||
-0.005700279233064870,
|
||||
0.003842132441622350,
|
||||
0.013983598060774900,
|
||||
0.020024993830604200,
|
||||
0.017901468392382700,
|
||||
0.006217999161870360,
|
||||
-0.012402093620729800,
|
||||
-0.031370988485890300,
|
||||
-0.041832006141384800,
|
||||
-0.035588597131400500,
|
||||
-0.008295098525339310,
|
||||
0.038292174335735300,
|
||||
0.095971206103503100,
|
||||
0.151982896902598000,
|
||||
0.192635286648254000,
|
||||
0.207485090950182000,
|
||||
0.192635286648256000,
|
||||
0.151982896902602000,
|
||||
0.095971206103507900,
|
||||
0.038292174335739900,
|
||||
-0.008295098525336090,
|
||||
-0.035588597131399000,
|
||||
-0.041832006141385000,
|
||||
-0.031370988485891600,
|
||||
-0.012402093620731500,
|
||||
0.006217999161868930,
|
||||
0.017901468392382000,
|
||||
0.020024993830604300,
|
||||
0.013983598060775600,
|
||||
0.003842132441623320,
|
||||
-0.005700279233064020,
|
||||
-0.011175196307322600,
|
||||
-0.011384168739919100,
|
||||
-0.007378579320778620,
|
||||
-0.001589789749146100,
|
||||
0.003392366775186310,
|
||||
0.005850957020137900,
|
||||
0.005419014927265200,
|
||||
0.002927838581732100,
|
||||
-0.000183058152702952,
|
||||
-0.002567012208450050,
|
||||
-0.003478042196892130,
|
||||
-0.002923873990382970,
|
||||
-0.001482086048715290,
|
||||
0.000068694704026947,
|
||||
0.001108841899531140,
|
||||
0.001383767648753930,
|
||||
0.001009151276280870,
|
||||
0.000323862987296896,
|
||||
-0.000308946001031235,
|
||||
-0.000655786056558038,
|
||||
-0.000669397068852788,
|
||||
-0.000451252675540803,
|
||||
-0.000162970122246723,
|
||||
0.000060286967439694,
|
||||
0.000157520248119968,
|
||||
0.000141963927224668,
|
||||
0.000068727674699521,
|
||||
-0.000004812442917792,
|
||||
-0.000045392289047882
|
||||
};
|
||||
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* 6 kHz lowpass
|
||||
* Fc = 2.64 kHz (0.110)
|
||||
* BW = 638 kHz (0.266)
|
||||
* Phase = 0.0 Deg
|
||||
*
|
||||
* -6dB @ 6.0 kHz
|
||||
* -20dB @ 6.5 kHz
|
||||
* -40dB @ 7.0 kHz
|
||||
* -60dB > 7.2 kHz
|
||||
*
|
||||
* 20150724 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
*
|
||||
*/
|
||||
|
||||
const float iq_rx_am_6k_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
-0.000004880093665016,
|
||||
0.000056249601206470,
|
||||
0.000106631842609010,
|
||||
0.000081384254139970,
|
||||
-0.000058736957755522,
|
||||
-0.000272365414638255,
|
||||
-0.000425548359876376,
|
||||
-0.000357422252818966,
|
||||
-0.000005244245277373,
|
||||
0.000490974654661712,
|
||||
0.000803539254316524,
|
||||
0.000594128178328428,
|
||||
-0.000221469661023948,
|
||||
-0.001297764644188940,
|
||||
-0.001948810489192100,
|
||||
-0.001535669576006110,
|
||||
0.000035159562865781,
|
||||
0.002042237502232450,
|
||||
0.003191717421535510,
|
||||
0.002364285159575850,
|
||||
-0.000519165742550591,
|
||||
-0.004107368177389280,
|
||||
-0.006132446052393760,
|
||||
-0.004729819141807280,
|
||||
0.000138536384265303,
|
||||
0.006130339738902320,
|
||||
0.009466230734482630,
|
||||
0.007122248925836100,
|
||||
-0.000902500392804507,
|
||||
-0.010767353229646000,
|
||||
-0.016344468781221300,
|
||||
-0.012706451532127600,
|
||||
0.000277710569700882,
|
||||
0.016562752996003900,
|
||||
0.026194213119574000,
|
||||
0.020664397226820300,
|
||||
-0.001236820922091710,
|
||||
-0.030498087727862400,
|
||||
-0.050224694289173800,
|
||||
-0.042930930378686000,
|
||||
0.000379604033916306,
|
||||
0.073954541623616600,
|
||||
0.157507699515675000,
|
||||
0.223513877747226000,
|
||||
0.248565464214855000,
|
||||
0.223513877747230000,
|
||||
0.157507699515682000,
|
||||
0.073954541623623400,
|
||||
0.000379604033921383,
|
||||
-0.042930930378683800,
|
||||
-0.050224694289174300,
|
||||
-0.030498087727864600,
|
||||
-0.001236820922093990,
|
||||
0.020664397226819100,
|
||||
0.026194213119574100,
|
||||
0.016562752996005000,
|
||||
0.000277710569702140,
|
||||
-0.012706451532126900,
|
||||
-0.016344468781221300,
|
||||
-0.010767353229646500,
|
||||
-0.000902500392805126,
|
||||
0.007122248925835810,
|
||||
0.009466230734482780,
|
||||
0.006130339738902770,
|
||||
0.000138536384265717,
|
||||
-0.004729819141807150,
|
||||
-0.006132446052393960,
|
||||
-0.004107368177389690,
|
||||
-0.000519165742550966,
|
||||
0.002364285159575700,
|
||||
0.003191717421535620,
|
||||
0.002042237502232730,
|
||||
0.000035159562866079,
|
||||
-0.001535669576005930,
|
||||
-0.001948810489192080,
|
||||
-0.001297764644189040,
|
||||
-0.000221469661024093,
|
||||
0.000594128178328318,
|
||||
0.000803539254316486,
|
||||
0.000490974654661737,
|
||||
-0.000005244245277321,
|
||||
-0.000357422252818922,
|
||||
-0.000425548359876357,
|
||||
-0.000272365414638260,
|
||||
-0.000058736957755538,
|
||||
0.000081384254139956,
|
||||
0.000106631842609003,
|
||||
0.000056249601206470,
|
||||
-0.000004880093665013
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 89 tap FIR lowpass filter for AM demodulation
|
||||
* 7.5 kHz lowpass
|
||||
* Fc = 3.50 kHz (0.146)
|
||||
* BW = 7.73 kHz (0.322)
|
||||
* Phase = 0.0 Deg
|
||||
*
|
||||
* -6dB @ 7.5 kHz
|
||||
* -20dB @ 8.1 kHz
|
||||
* -40dB @ 8.5 kHz
|
||||
* -60dB > 8.7 kHz
|
||||
*
|
||||
* 20150724 by KA7OEI using Iowa Hills Hilbert Filter Designer
|
||||
|
||||
*/
|
||||
|
||||
const float iq_rx_am_7k5_coeffs[IQ_RX_NUM_TAPS] =
|
||||
{
|
||||
-0.000054368878976464,
|
||||
-0.000109470418324297,
|
||||
-0.000080800014418553,
|
||||
0.000057887247193655,
|
||||
0.000196248384784124,
|
||||
0.000143919934167119,
|
||||
-0.000166720581170554,
|
||||
-0.000516949697820653,
|
||||
-0.000513457595923984,
|
||||
0.000019591792777547,
|
||||
0.000715438143813412,
|
||||
0.000837678462105361,
|
||||
-0.000026672117250676,
|
||||
-0.001346407587573860,
|
||||
-0.001854545301167850,
|
||||
-0.000681925402542360,
|
||||
0.001516983112219140,
|
||||
0.002720057594104930,
|
||||
0.001264577750721170,
|
||||
-0.002218475374737490,
|
||||
-0.004716082694953130,
|
||||
-0.003290070348926000,
|
||||
0.001768705442798720,
|
||||
0.006257195418023830,
|
||||
0.005315470630396060,
|
||||
-0.001674768165904550,
|
||||
-0.009231015015775820,
|
||||
-0.009741273892250180,
|
||||
-0.000735938093829474,
|
||||
0.011162261151525300,
|
||||
0.014549180415936700,
|
||||
0.003582582016681460,
|
||||
-0.014560284217669600,
|
||||
-0.023377317298097500,
|
||||
-0.011097551616034700,
|
||||
0.016127337734989000,
|
||||
0.035061508247232000,
|
||||
0.023170836448327200,
|
||||
-0.018977720268267700,
|
||||
-0.060089752963952400,
|
||||
-0.055598189384657500,
|
||||
0.019293047057938800,
|
||||
0.145271104740461000,
|
||||
0.264027404678331000,
|
||||
0.312598578987250000,
|
||||
0.264027404678338000,
|
||||
0.145271104740472000,
|
||||
0.019293047057947600,
|
||||
-0.055598189384654300,
|
||||
-0.060089752963954300,
|
||||
-0.018977720268271600,
|
||||
0.023170836448324900,
|
||||
0.035061508247232500,
|
||||
0.016127337734991200,
|
||||
-0.011097551616033100,
|
||||
-0.023377317298097600,
|
||||
-0.014560284217671000,
|
||||
0.003582582016680210,
|
||||
0.014549180415936700,
|
||||
0.011162261151526300,
|
||||
-0.000735938093828361,
|
||||
-0.009741273892249770,
|
||||
-0.009231015015776210,
|
||||
-0.001674768165905220,
|
||||
0.005315470630395730,
|
||||
0.006257195418023980,
|
||||
0.001768705442799040,
|
||||
-0.003290070348925910,
|
||||
-0.004716082694953380,
|
||||
-0.002218475374737840,
|
||||
0.001264577750721040,
|
||||
0.002720057594105130,
|
||||
0.001516983112219500,
|
||||
-0.000681925402542081,
|
||||
-0.001854545301167810,
|
||||
-0.001346407587574020,
|
||||
-0.000026672117250873,
|
||||
0.000837678462105258,
|
||||
0.000715438143813428,
|
||||
0.000019591792777618,
|
||||
-0.000513457595923930,
|
||||
-0.000516949697820644,
|
||||
-0.000166720581170573,
|
||||
0.000143919934167101,
|
||||
0.000196248384784120,
|
||||
0.000057887247193660,
|
||||
-0.000080800014418548,
|
||||
-0.000109470418324297,
|
||||
-0.000054368878976467
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __IQ_TX_FILTER_H
|
||||
#define __IQ_TX_FILTER_H
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
#define IQ_TX_BLOCK_SIZE IQ_BLOCK_SIZE
|
||||
#define IQ_TX_NUM_TAPS 89
|
||||
#define IQ_TX_NUM_TAPS_WIDE 201
|
||||
#define IQ_TX_NUM_TAPS_MAX 201
|
||||
|
||||
|
||||
extern const IQ_FilterDescriptor iq_tx_narrow;
|
||||
extern const IQ_FilterDescriptor iq_tx_wide;
|
||||
extern const IQ_FilterDescriptor iq_tx_essb_4k; // Just for eSSB
|
||||
extern const IQ_FilterDescriptor iq_tx_essb_5k; // Just for eSSB
|
||||
extern const IQ_FilterDescriptor iq_tx_essb_6k; // Just for eSSB
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: Created October 2015, KA7OEI **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __SUBAUDIBLE_TONE_TABLE
|
||||
#define __SUBAUDIBLE_TONE_TABLE
|
||||
|
||||
|
||||
static const float fm_subaudible_tone_table[] =
|
||||
{
|
||||
0,
|
||||
67.0,
|
||||
69.3,
|
||||
71.9,
|
||||
74.4,
|
||||
77.0,
|
||||
79.7,
|
||||
82.5,
|
||||
85.4,
|
||||
88.5,
|
||||
91.5,
|
||||
94.8,
|
||||
97.4,
|
||||
100.0,
|
||||
103.5,
|
||||
107.2,
|
||||
110.9,
|
||||
114.8,
|
||||
118.8,
|
||||
123.0,
|
||||
127.3,
|
||||
131.8,
|
||||
136.5,
|
||||
141.3,
|
||||
146.2,
|
||||
150.0,
|
||||
151.4,
|
||||
156.7,
|
||||
159.8,
|
||||
162.2,
|
||||
165.5,
|
||||
167.9,
|
||||
171.3,
|
||||
173.8,
|
||||
177.3,
|
||||
179.9,
|
||||
183.5,
|
||||
186.2,
|
||||
189.9,
|
||||
192.8,
|
||||
196.6,
|
||||
199.5,
|
||||
203.5,
|
||||
206.5,
|
||||
210.7,
|
||||
213.8,
|
||||
218.1,
|
||||
221.3,
|
||||
225.7,
|
||||
229.1,
|
||||
233.6,
|
||||
237.1,
|
||||
241.8,
|
||||
245.5,
|
||||
250.3,
|
||||
254.1,
|
||||
0
|
||||
};
|
||||
|
||||
#endif
|
||||
+32023
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,435 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#include "ui_driver.h"
|
||||
#include "freedv_uhsdr.h"
|
||||
#include "ui_lcd_layouts.h"
|
||||
#include "profiling.h"
|
||||
#include "ui_lcd_hy28.h"
|
||||
#include "radio_management.h"
|
||||
|
||||
#if defined(USE_FREEDV) || defined(USE_ALTERNATE_NR)
|
||||
|
||||
MultiModeBuffer_t __MCHF_SPECIALMEM mmb;
|
||||
#endif
|
||||
|
||||
#ifdef USE_FREEDV
|
||||
|
||||
#include "freedv_api.h"
|
||||
|
||||
freedv_conf_t freedv_conf;
|
||||
|
||||
struct freedv *f_FREEDV;
|
||||
|
||||
|
||||
RingBuffer_DefineExtMem(fdv_demod_rb,sizeof(mmb.fdv_demod_buff)/sizeof(fdv_demod_rb_item_t), mmb.fdv_demod_buff)
|
||||
RingBuffer_DefineExtMem(fdv_iq_rb,sizeof(mmb.fdv_iq_buff)/sizeof(fdv_iq_rb_item_t), mmb.fdv_iq_buff)
|
||||
|
||||
#define FDV_AUDIO_MEM_SIZE ((FDV_BUFFER_SIZE*2)+IQ_BLOCK_SIZE)
|
||||
__MCHF_SPECIALMEM fdv_audio_rb_item_t fdv_audio_rb_mem[FDV_AUDIO_MEM_SIZE];
|
||||
RingBuffer_DefineExtMem(fdv_audio_rb, FDV_AUDIO_MEM_SIZE, fdv_audio_rb_mem)
|
||||
|
||||
typedef struct {
|
||||
int32_t start;
|
||||
int32_t offset;
|
||||
int32_t count;
|
||||
} flex_buffer;
|
||||
|
||||
static uint16_t freedv_display_x_offset;
|
||||
|
||||
/**
|
||||
* Returns the internal UHSDR configuration value in the value range for display and use with the freedv_api
|
||||
* @param freedv_conf_p
|
||||
* @return SNR in the range of -100 to 99
|
||||
*/
|
||||
|
||||
int32_t FreeDV_Get_Squelch_SNR(freedv_conf_t* freedv_conf_p)
|
||||
{
|
||||
return (int32_t)(freedv_conf_p->squelch_snr_thresh) + FDV_SQUELCH_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal UHSDR configuration value in the permitted value range
|
||||
* @param freedv_conf_p
|
||||
* @param squelch_snr SNR in the range of -100 to 99 , -100 represents OFF
|
||||
*/
|
||||
void FreeDV_Set_Squelch_SNR(freedv_conf_t* freedv_conf_p, int8_t squelch_snr)
|
||||
{
|
||||
int32_t internal_snr = squelch_snr - FDV_SQUELCH_OFFSET;
|
||||
if (internal_snr > FDV_SQUELCH_MAX)
|
||||
{
|
||||
internal_snr = FDV_SQUELCH_MAX;
|
||||
}
|
||||
else if (internal_snr < FDV_SQUELCH_OFF)
|
||||
{
|
||||
internal_snr = FDV_SQUELCH_OFF;
|
||||
}
|
||||
|
||||
freedv_conf_p->squelch_snr_thresh = internal_snr;
|
||||
}
|
||||
|
||||
int FreeDV_Is_Squelch_Enable(freedv_conf_t* freedv_conf_p)
|
||||
{
|
||||
return freedv_conf_p->squelch_snr_thresh != FDV_SQUELCH_OFF;
|
||||
}
|
||||
|
||||
void FreeDV_Squelch_Update(freedv_conf_t* freedv_conf_p)
|
||||
{
|
||||
UNUSED(freedv_conf_p);
|
||||
freedv_set_squelch_en(f_FREEDV, FreeDV_Is_Squelch_Enable(&freedv_conf));
|
||||
freedv_set_snr_squelch_thresh(f_FREEDV, FreeDV_Get_Squelch_SNR(&freedv_conf));
|
||||
}
|
||||
|
||||
static void FreeDv_DisplayBer(void)
|
||||
{
|
||||
int ber = 0;
|
||||
char ber_string[12];
|
||||
|
||||
|
||||
|
||||
ber = 1000*freedv_get_total_bit_errors(f_FREEDV)/freedv_get_total_bits(f_FREEDV);
|
||||
snprintf(ber_string,12,"0.%03d",ber); //calculate and display the bit error rate
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_BER.x + freedv_display_x_offset,ts.Layout->FREEDV_BER.y, ber_string,Yellow,Black, ts.Layout->FREEDV_FONT);
|
||||
|
||||
}
|
||||
|
||||
static void FreeDv_DisplaySnr(void)
|
||||
{
|
||||
static float SNR = 1;
|
||||
float SNR_est;
|
||||
char SNR_string[12];
|
||||
int sync;
|
||||
|
||||
freedv_get_modem_stats(f_FREEDV,&sync,&SNR_est);
|
||||
|
||||
SNR = 0.95*SNR + 0.05 * SNR_est; //some averaging to keep it more calm
|
||||
int32_t SNR_Int = roundf(SNR);
|
||||
|
||||
if (SNR_Int > 99)
|
||||
{
|
||||
SNR_Int = 99;
|
||||
}
|
||||
else if (SNR_Int < -99)
|
||||
{
|
||||
SNR_Int = -99;
|
||||
}
|
||||
|
||||
uint32_t clr_fg;
|
||||
if (FreeDV_Is_Squelch_Enable(&freedv_conf))
|
||||
{
|
||||
clr_fg = SNR_Int >= FreeDV_Get_Squelch_SNR(&freedv_conf)? Green:Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
clr_fg = Yellow;
|
||||
}
|
||||
|
||||
snprintf(SNR_string,12,"%-2ld",SNR_Int); //Display the current SNR and round it up to the next int
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_SNR.x + freedv_display_x_offset, ts.Layout->FREEDV_SNR.y ,SNR_string,clr_fg,Black, ts.Layout->FREEDV_FONT);
|
||||
}
|
||||
|
||||
void FreeDv_DisplayClear()
|
||||
{
|
||||
// UiLcdHy28_PrintText(ts.Layout->FREEDV_SNR.x, ts.Layout->FREEDV_SNR.y," ",Yellow,Black,ts.Layout->FREEDV_FONT);
|
||||
// UiLcdHy28_PrintText(ts.Layout->FREEDV_BER.x, ts.Layout->FREEDV_BER.y," ",Yellow,Black,ts.Layout->FREEDV_FONT);
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_SNR.x, ts.Layout->FREEDV_SNR.y," ",Yellow,Black,ts.Layout->FREEDV_FONT); //SNR=00
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_BER.x, ts.Layout->FREEDV_BER.y," ",Yellow,Black,ts.Layout->FREEDV_FONT); //BER=0.000 (max 9 chars)
|
||||
UiDriver_TextMsgClear();
|
||||
}
|
||||
|
||||
void FreeDv_DisplayPrepare()
|
||||
{
|
||||
UiDriver_TextMsgClear();
|
||||
freedv_display_x_offset = UiLcdHy28_TextWidth("SNR=", ts.Layout->FREEDV_FONT);
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_SNR.x, ts.Layout->FREEDV_SNR.y,"SNR=",Yellow,Black, ts.Layout->FREEDV_FONT);
|
||||
UiLcdHy28_PrintText(ts.Layout->FREEDV_BER.x, ts.Layout->FREEDV_BER.y,"BER=",Yellow,Black, ts.Layout->FREEDV_FONT);
|
||||
}
|
||||
|
||||
void FreeDv_DisplayUpdate()
|
||||
{
|
||||
FreeDv_DisplayBer();
|
||||
FreeDv_DisplaySnr();
|
||||
UiDriver_TextMsgDisplay();
|
||||
}
|
||||
|
||||
|
||||
void FreeDv_HandleFreeDv()
|
||||
{
|
||||
|
||||
// Freedv DL2FW
|
||||
// static FDV_Out_Buffer FDV_TX_out_im_buff;
|
||||
static bool tx_was_here = false;
|
||||
static bool rx_was_here = true;
|
||||
|
||||
|
||||
// we are always called, so check if there is FreeDV active
|
||||
if (ts.digital_mode == DigitalMode_FreeDV)
|
||||
{
|
||||
if ((ts.txrx_mode == TRX_MODE_TX)
|
||||
&& RingBuffer_GetData(&fdv_audio_rb) >= freedv_get_n_speech_samples(f_FREEDV)
|
||||
&& RingBuffer_GetRoom(&fdv_iq_rb) >= freedv_get_n_nom_modem_samples(f_FREEDV))
|
||||
{
|
||||
// ...and if we are transmitting and samples from dv_tx_processor are ready
|
||||
if (tx_was_here == false)
|
||||
{
|
||||
RingBuffer_ClearGetTail(&fdv_audio_rb);
|
||||
RingBuffer_ClearPutHead(&fdv_iq_rb);
|
||||
tx_was_here = true;
|
||||
rx_was_here = false;
|
||||
}
|
||||
COMP iq_buffer[freedv_get_n_nom_modem_samples(f_FREEDV)];
|
||||
int16_t audio_buffer[freedv_get_n_speech_samples(f_FREEDV)];
|
||||
|
||||
RingBuffer_GetSamples(&fdv_audio_rb, &audio_buffer, freedv_get_n_speech_samples(f_FREEDV));
|
||||
|
||||
profileTimedEventStart(7);
|
||||
freedv_comptx(f_FREEDV,
|
||||
iq_buffer,
|
||||
audio_buffer); // start the encoding process
|
||||
profileTimedEventStop(7);
|
||||
|
||||
for (int idx = 0; idx < freedv_get_n_nom_modem_samples(f_FREEDV); idx++)
|
||||
{
|
||||
fdv_iq_rb_item_t sample;
|
||||
sample.real = iq_buffer[idx].real;
|
||||
sample.imag = iq_buffer[idx].imag;
|
||||
|
||||
RingBuffer_PutSamples(&fdv_iq_rb, &sample, 1);
|
||||
}
|
||||
|
||||
}
|
||||
else if ((ts.txrx_mode == TRX_MODE_RX))
|
||||
{
|
||||
|
||||
|
||||
if (rx_was_here == false)
|
||||
{
|
||||
RingBuffer_ClearGetTail(&fdv_demod_rb);
|
||||
RingBuffer_ClearPutHead(&fdv_audio_rb);
|
||||
|
||||
freedv_set_total_bit_errors(f_FREEDV,0); //reset ber calculation after coming from TX
|
||||
freedv_set_total_bits(f_FREEDV,0);
|
||||
|
||||
rx_was_here = true; // this is used to clear buffers when going into TX
|
||||
tx_was_here = false;
|
||||
}
|
||||
|
||||
// these buffers are large enough to hold the requested/provided amount of data for freedv_comprx
|
||||
// these are larger than the FDV_BUFFER_SIZE since some more bytes may be asked for.
|
||||
#ifdef USE_SIMPLE_FREEDV_FILTERS
|
||||
#define input_rb fdv_iq_rb
|
||||
#define input_rb_item_t fdv_iq_rb_item_t
|
||||
#define FREEDV_RX_FUNC freedv_comprx
|
||||
#define FREEDV_RX_INPUT_T COMP
|
||||
#else
|
||||
#define input_rb fdv_demod_rb
|
||||
#define input_rb_item_t fdv_demod_rb_item_t
|
||||
#define FREEDV_RX_FUNC freedv_rx
|
||||
#define FREEDV_RX_INPUT_T int16_t
|
||||
#endif
|
||||
FREEDV_RX_INPUT_T input_buffer[freedv_get_n_max_modem_samples(f_FREEDV)];
|
||||
int16_t audio_buffer[freedv_get_n_max_modem_samples(f_FREEDV)];
|
||||
|
||||
// while makes this highest prio
|
||||
// if may give more responsiveness but can cause interrupted reception
|
||||
while (RingBuffer_GetData(&input_rb) >= freedv_nin(f_FREEDV)
|
||||
&& RingBuffer_GetRoom(&fdv_audio_rb) >= freedv_nin(f_FREEDV))
|
||||
{
|
||||
// MchfBoard_GreenLed(LED_STATE_OFF);
|
||||
// if we arrive here the rx_buffer is full enough and will be consumed now.
|
||||
#ifdef USE_SIMPLE_FREEDV_FILTERS
|
||||
for (int idx = 0; idx < freedv_nin(f_FREEDV); idx++ )
|
||||
{
|
||||
input_rb_item_t sample;
|
||||
RingBuffer_GetSamples(&input_rb, &sample, 1);
|
||||
input_buffer[idx].real = sample.real;
|
||||
input_buffer[idx].imag = sample.imag;
|
||||
}
|
||||
#else
|
||||
RingBuffer_GetSamples(&input_rb, &input_buffer, freedv_nin(f_FREEDV));
|
||||
#endif
|
||||
|
||||
int count = FREEDV_RX_FUNC(f_FREEDV, audio_buffer, input_buffer); // run the decoding process
|
||||
|
||||
if (freedv_get_sync(f_FREEDV) != 0)
|
||||
{
|
||||
RingBuffer_PutSamples(&fdv_audio_rb, &audio_buffer, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tx_was_here == true || rx_was_here == true)
|
||||
{
|
||||
tx_was_here = false;
|
||||
rx_was_here = false;
|
||||
RingBuffer_ClearGetTail(&fdv_iq_rb);
|
||||
RingBuffer_ClearGetTail(&fdv_audio_rb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FreeDV txt test - will be out of here
|
||||
typedef struct {
|
||||
char tx_str[80];
|
||||
char *ptx_str;
|
||||
} my_callback_state_t;
|
||||
|
||||
static my_callback_state_t my_cb_state;
|
||||
|
||||
static char my_get_next_tx_char(void *callback_state) {
|
||||
my_callback_state_t* pstate = (my_callback_state_t*)callback_state;
|
||||
|
||||
char c = *pstate->ptx_str++;
|
||||
|
||||
if (*pstate->ptx_str == 0) {
|
||||
pstate->ptx_str = pstate->tx_str;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static void my_put_next_rx_char(void *callback_state, char ch)
|
||||
{
|
||||
UNUSED(callback_state);
|
||||
UiDriver_TextMsgPutChar(ch);
|
||||
}
|
||||
|
||||
freedv_mode_desc_t freedv_modes[] =
|
||||
{
|
||||
{ "1600", "FD1600", FREEDV_MODE_1600 },
|
||||
#ifdef USE_FREEDV_700D
|
||||
{ "700D", "FD700D", FREEDV_MODE_700D },
|
||||
#endif
|
||||
};
|
||||
|
||||
const uint8_t freedv_modes_num = sizeof(freedv_modes)/sizeof(freedv_modes[0]);
|
||||
|
||||
|
||||
// FreeDV txt test - will be out of here
|
||||
void FreeDV_Init()
|
||||
{
|
||||
// Freedv Test DL2FW
|
||||
|
||||
// move this to ui_configuration;
|
||||
FreeDV_Set_Squelch_SNR(&freedv_conf,-2);
|
||||
freedv_conf.mode = 0; // 0 = 1600, 1 = 700D
|
||||
|
||||
FreeDV_SetMode(freedv_conf.mode, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if mode was activated, false if old mode is still active
|
||||
*/
|
||||
int32_t FreeDV_SetMode(uint8_t fdv_mode, int32_t firstTime)
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
// turn off rx audio processing to be able to disable and reenable FreeDV processing
|
||||
ads.af_disabled++;
|
||||
|
||||
// normal init starts
|
||||
if (fdv_mode >= freedv_modes_num)
|
||||
{
|
||||
fdv_mode = 0;
|
||||
}
|
||||
|
||||
// we don't switch if TX is currently active
|
||||
if (firstTime == false)
|
||||
{
|
||||
retval = (ts.txrx_mode == TRX_MODE_RX);
|
||||
if (retval == true && f_FREEDV != NULL && freedv_conf.mode != fdv_mode)
|
||||
{
|
||||
freedv_close(f_FREEDV);
|
||||
f_FREEDV = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// only if all went well AND we have not yet initialized the mode,
|
||||
// we are going to run the mode, so if same mode is being set, nothing happens
|
||||
// really
|
||||
if (retval && f_FREEDV == NULL)
|
||||
{
|
||||
f_FREEDV = freedv_open(freedv_modes[fdv_mode].freedv_id);
|
||||
|
||||
retval = f_FREEDV != NULL;
|
||||
if (retval)
|
||||
{
|
||||
sprintf(my_cb_state.tx_str, ts.special_functions_enabled == 1 ? FREEDV_TX_DF8OE_MESSAGE : FREEDV_TX_MESSAGE);
|
||||
|
||||
my_cb_state.ptx_str = my_cb_state.tx_str;
|
||||
freedv_set_callback_txt(f_FREEDV, &my_put_next_rx_char, &my_get_next_tx_char, &my_cb_state);
|
||||
|
||||
if (FreeDV_Is_Squelch_Enable(&freedv_conf))
|
||||
{
|
||||
freedv_set_squelch_en(f_FREEDV,1);
|
||||
freedv_set_snr_squelch_thresh(f_FREEDV, FreeDV_Get_Squelch_SNR(&freedv_conf));
|
||||
}
|
||||
else
|
||||
{
|
||||
freedv_set_squelch_en(f_FREEDV,0);
|
||||
}
|
||||
|
||||
freedv_set_tx_bpf(f_FREEDV, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
{
|
||||
freedv_conf.mode = fdv_mode;
|
||||
}
|
||||
|
||||
// turn on rx audio processing, FreeDV is ready for work
|
||||
ads.af_disabled--;
|
||||
|
||||
return retval;
|
||||
}
|
||||
int32_t FreeDV_Iq_Get_FrameLen()
|
||||
{
|
||||
return freedv_get_n_nom_modem_samples(f_FREEDV);
|
||||
}
|
||||
|
||||
int32_t FreeDV_Audio_Get_FrameLen()
|
||||
{
|
||||
return freedv_get_n_speech_samples(f_FREEDV);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_FREEDV
|
||||
void FreeDV_Test()
|
||||
{
|
||||
ts.digital_mode = DigitalMode_FreeDV;
|
||||
ts.txrx_mode = TRX_MODE_RX;
|
||||
while (1)
|
||||
{
|
||||
for (int idx = 0; idx < FREEDV_TEST_BUFFER_FRAME_SIZE*FREEDV_TEST_BUFFER_FRAME_COUNT; idx++)
|
||||
{
|
||||
int16_t sample[2];
|
||||
sample[0] = test_buffer[idx].real;
|
||||
sample[1] = test_buffer[idx].imag;
|
||||
|
||||
RingBuffer_PutSamples(&fdv_iq_rb,&sample,2);
|
||||
FreeDv_HandleFreeDv();
|
||||
RingBuffer_GetSamples(&fdv_audio_rb,sample,1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifndef __freedv_mchf__
|
||||
#define __freedv_mchf__
|
||||
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
#include "uhsdr_board.h"
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "comp.h"
|
||||
|
||||
#if defined(USE_FREEDV_700D)
|
||||
#define FDV_MAX_IQ_FRAME_LEN_MS 160
|
||||
#define FREEDV_MODE_UHSDR FREEDV_MODE_700D
|
||||
#elif defined(USE_FREEDV_1600)
|
||||
#define FDV_MAX_IQ_FRAME_LEN_MS 40
|
||||
#define FREEDV_MODE_UHSDR FREEDV_MODE_1600
|
||||
#endif
|
||||
// one need to set this to the highest frame length to be intended to use
|
||||
// FreeDV 700D requires 1280 samples for the 160ms frame, the audio size may be larger depending
|
||||
// on the algorithm
|
||||
// TODO: Explicitly list the variables in FreeDV to look at.
|
||||
|
||||
|
||||
#include "rb.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t real;
|
||||
int16_t imag;
|
||||
} COMP_int16_t;
|
||||
|
||||
RingBuffer_Declare(fdv_iq_rb, COMP_int16_t)
|
||||
RingBuffer_Declare(fdv_audio_rb, int16_t)
|
||||
RingBuffer_Declare(fdv_demod_rb, int16_t)
|
||||
|
||||
#define FDV_BUFFER_SIZE (FDV_MAX_IQ_FRAME_LEN_MS*8) // (160ms*8samples per ms)
|
||||
|
||||
#define NR_BUFFER_NUM 4
|
||||
#define NR_BUFFER_SIZE 256 // 4*256*8 -> 8192
|
||||
|
||||
typedef struct {
|
||||
COMP samples[NR_BUFFER_SIZE];
|
||||
} NR_Buffer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
fdv_demod_rb_item_t fdv_demod_buff[(FDV_BUFFER_SIZE * 3) + IQ_BLOCK_SIZE];
|
||||
fdv_iq_rb_item_t fdv_iq_buff[(FDV_BUFFER_SIZE * 2) + IQ_BLOCK_SIZE];
|
||||
NR_Buffer nr_audio_buff[NR_BUFFER_NUM];
|
||||
} MultiModeBuffer_t;
|
||||
|
||||
|
||||
#ifdef USE_FREEDV
|
||||
#ifdef DEBUG_FREEDV
|
||||
#define FREEDV_TEST_BUFFER_FRAME_COUNT 50
|
||||
#define FREEDV_TEST_BUFFER_FRAME_SIZE 320
|
||||
extern const COMP test_buffer[FREEDV_TEST_BUFFER_FRAME_SIZE*FREEDV_TEST_BUFFER_FRAME_COUNT];
|
||||
#endif
|
||||
|
||||
#define FREEDV_TX_MESSAGE " CQ CQ CQ UHSDR " TRX_NAME " SDR with integrated FreeDV codec calling!"
|
||||
#define FREEDV_TX_DF8OE_MESSAGE " DF8OE JO42jr using UHSDR " TRX_NAME " SDR with integrated FreeDV codec"
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
char* label;
|
||||
uint8_t freedv_id;
|
||||
} freedv_mode_desc_t;
|
||||
|
||||
extern freedv_mode_desc_t freedv_modes[];
|
||||
extern const uint8_t freedv_modes_num;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
#define FDV_SQUELCH_OFF 0
|
||||
#define FDV_SQUELCH_OFFSET (-100)
|
||||
#define FDV_SQUELCH_MIN (-99-FDV_SQUELCH_OFFSET) // equals -99 SNR
|
||||
#define FDV_SQUELCH_MAX (99-FDV_SQUELCH_OFFSET) // equals 99 SNR
|
||||
#define FDV_SQUELCH_DEFAULT (-2-FDV_SQUELCH_OFFSET) // equals -2 SNR
|
||||
|
||||
uint8_t squelch_snr_thresh;
|
||||
uint8_t mode;
|
||||
bool mute_if_squelched;
|
||||
} freedv_conf_t;
|
||||
|
||||
extern freedv_conf_t freedv_conf;
|
||||
|
||||
|
||||
void FreeDv_HandleFreeDv(void);
|
||||
void FreeDV_Init(void);
|
||||
int32_t FreeDV_SetMode(uint8_t fdv_mode, int32_t firstTime);
|
||||
void FreeDV_Test(void);
|
||||
|
||||
int32_t FreeDV_Iq_Get_FrameLen(void);
|
||||
int32_t FreeDV_Audio_Get_FrameLen(void);
|
||||
|
||||
|
||||
void FreeDv_DisplayClear(void);
|
||||
void FreeDv_DisplayPrepare(void);
|
||||
void FreeDv_DisplayUpdate(void);
|
||||
|
||||
int32_t FreeDV_Get_Squelch_SNR(freedv_conf_t* freedv_conf_p);
|
||||
void FreeDV_Set_Squelch_SNR(freedv_conf_t* freedv_conf_p, int8_t squelch_snr);
|
||||
int FreeDV_Is_Squelch_Enable(freedv_conf_t* freedv_conf_p);
|
||||
void FreeDV_Squelch_Update(freedv_conf_t* freedv_conf_p);
|
||||
|
||||
|
||||
#endif
|
||||
#if defined(USE_FREEDV) || defined(USE_ALTERNATE_NR)
|
||||
|
||||
|
||||
extern MultiModeBuffer_t mmb;
|
||||
|
||||
// we allow for one more pointer to a buffer as we have buffers
|
||||
// why? because our implementation will only fill up the fifo only to N-1 elements
|
||||
#define FDV_BUFFER_IQ_FIFO_SIZE (FDV_BUFFER_IQ_NUM+1)
|
||||
|
||||
#define NR_BUFFER_FIFO_SIZE (NR_BUFFER_NUM+1)
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include "freq_shift.h"
|
||||
#include "audio_driver.h" // only for IQ_BLOCK_SIZE and IQ_SAMPLE_RATE_F
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// The following refer to the software frequency conversion/translation done in receive and transmit to shift the signals away from the
|
||||
// "DC" IF
|
||||
|
||||
|
||||
typedef struct {
|
||||
float32_t Osc_Cos;
|
||||
float32_t Osc_Sin;
|
||||
float32_t Osc_Vect_Q;
|
||||
float32_t Osc_Vect_I;
|
||||
} fs_nco_approx_t;
|
||||
|
||||
/**
|
||||
* Prepare the configuration for use with specified shift frequency.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm.
|
||||
* @param nco_freq shift frequency in Hz (please note that shift direction, i.e. the positive/negative sign is not taken into account here!)
|
||||
* @param sample_rate sample rate of the incoming data in Hz
|
||||
* @param blockSize size of data to be processed
|
||||
*/
|
||||
static void FreqShift_Approx_Prepare(fs_nco_approx_t* confptr, float32_t nco_freq, float32_t sample_rate)
|
||||
{
|
||||
// Configure NCO for the frequency translate function
|
||||
|
||||
/*
|
||||
* using double here turned out in experiments to yield better precision of the results
|
||||
* and since we use it only when changing the frequency, there is not much harm in
|
||||
*/
|
||||
double rate = (2 * M_PI * nco_freq) / sample_rate;
|
||||
confptr->Osc_Cos = cos(rate);
|
||||
confptr->Osc_Sin = sin(rate);
|
||||
confptr->Osc_Vect_I = 0;
|
||||
confptr->Osc_Vect_Q = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency shift using a low overhead algorithm using (simple) complex arithmetic and gain control approximation algorithm.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm. It must have been configured using FreqShift_Approx_Prepare before!
|
||||
* @param I_buffer incoming i data
|
||||
* @param Q_buffer incoming q data
|
||||
* @param blockSize size of data to be processed
|
||||
* @param dir dir == SHIFT_UP moves receive frequency to the right in the spectrum, SHIFT_DOWN opposite direction
|
||||
*/
|
||||
static void FreqShift_Approx(fs_nco_approx_t* confptr, float32_t* I_buffer, float32_t* Q_buffer, const size_t blockSize, freq_shift_dir_t dir)
|
||||
{
|
||||
// KA7OEI: Below is the "on-the-fly" version of the frequency translator, generating a "live" version of the oscillator (NCO), which can be any
|
||||
// frequency
|
||||
// The values for the NCO are configured in the function "FreqShift_Approx_Prepare".
|
||||
|
||||
/*
|
||||
* URLs for algorithm information:
|
||||
* https://dsp.stackexchange.com/questions/124/how-to-implement-a-digital-oscillator (hint to recalc gain only from time to time)
|
||||
* https://dspguru.com/dsp/howtos/how-to-create-oscillators-in-software/ (see complex oscillator)
|
||||
*/
|
||||
|
||||
/*
|
||||
* *
|
||||
* Shift Down (shift == 1) => i = Q, q = I
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
* Shift Up (shift == 0) => q = I, q = Q
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
*/
|
||||
|
||||
float32_t* i_buffer = dir == FREQ_SHIFT_UP? I_buffer : Q_buffer;
|
||||
float32_t* q_buffer = dir == FREQ_SHIFT_UP? Q_buffer : I_buffer;
|
||||
|
||||
for(int i = 0; i < blockSize; i++) {
|
||||
// generate local oscillator on-the-fly: This takes a lot of processor time!
|
||||
float32_t Osc_Q = (confptr->Osc_Vect_Q * confptr->Osc_Cos) - (confptr->Osc_Vect_I * confptr->Osc_Sin); // Q channel of oscillator
|
||||
float32_t Osc_I = (confptr->Osc_Vect_I * confptr->Osc_Cos) + (confptr->Osc_Vect_Q * confptr->Osc_Sin); // I channel of oscillator
|
||||
|
||||
// do actual frequency conversion
|
||||
float32_t q_temp = q_buffer[i];
|
||||
float32_t i_temp = i_buffer[i]; // save temporary copies of data
|
||||
q_buffer[i] = (q_temp * Osc_Q) - (i_temp * Osc_I);
|
||||
i_buffer[i] = (i_temp * Osc_Q) + (q_temp * Osc_I); // multiply I/Q data by sine/cosine data to do translation
|
||||
confptr->Osc_Vect_Q = Osc_Q;
|
||||
confptr->Osc_Vect_I = Osc_I;
|
||||
}
|
||||
|
||||
float32_t Osc_Gain = (3 - ((confptr->Osc_Vect_Q * confptr->Osc_Vect_Q) + (confptr->Osc_Vect_I * confptr->Osc_Vect_I)))/2; // Amplitude control of oscillator
|
||||
// rotate vectors while maintaining constant oscillator amplitude
|
||||
confptr->Osc_Vect_Q = Osc_Gain * confptr->Osc_Vect_Q;
|
||||
confptr->Osc_Vect_I = Osc_Gain * confptr->Osc_Vect_I;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The oscillator implementation below is straightforward and based on calculating sin and cos using the normal library function.
|
||||
* And then simply do the appropriate complex math operations using the arm lib.
|
||||
* It supports 2 modes: one is using continuous recalculation of the sin/cos coeffs which is suitable for all shift frequencies
|
||||
* It also supports a special mode for rates which are a power of 2, where the coeffs are only calculated once, since the coeffs
|
||||
* repeat after blocksize length anyway.
|
||||
*
|
||||
* Downside is the memory usage which depends on the max blockSize (we need 6 x IQ_BLOCK_SIZE x sizeof(float32_t) as buffers)
|
||||
* and for continuous mode the high load due to permanent sin/cos calculations.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float32_t Osc_Sin_buffer[IQ_BLOCK_SIZE];
|
||||
float32_t Osc_Cos_buffer[IQ_BLOCK_SIZE];
|
||||
|
||||
// we need to use double here for continuous mode
|
||||
// otherwise the summation error grows to quickly
|
||||
// no harm for single calc mode, since we run it only once
|
||||
double rad_calc;
|
||||
double rad_increment;
|
||||
bool single_osc_calc;
|
||||
} fs_nco_sincos_t;
|
||||
|
||||
/**
|
||||
* Calculate the sin/cos values for the shift calculation.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm. It must have been configured using FreqShift_SinCos_Prepare before!
|
||||
* @param blockSize size of data to be processed
|
||||
*/
|
||||
static void FreqShift_SinCos_Coeffs(fs_nco_sincos_t* confptr, size_t blockSize)
|
||||
{
|
||||
for(int i = 0; i < blockSize; i++) // Now, let's do it!
|
||||
{
|
||||
confptr->rad_calc += confptr->rad_increment;
|
||||
if (confptr->rad_calc > 2*M_PI)
|
||||
{
|
||||
confptr->rad_calc -= 2*M_PI;
|
||||
}
|
||||
sincosf(confptr->rad_calc, &confptr->Osc_Sin_buffer[i], &confptr->Osc_Cos_buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the configuration for use with specified shift frequency.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm.
|
||||
* @param nco_freq shift frequency in Hz (please note that shift direction, i.e. the positive/negative sign is not taken into account here!)
|
||||
* @param sample_rate sample rate of the incoming data in Hz
|
||||
* @param single_osc_calc true == use precalculated values, requires frequency to be integer division of samplerate, false == arbitrary shift frequency
|
||||
* @param blockSize size of data to be processed
|
||||
*/
|
||||
static void FreqShift_SinCos_Prepare(fs_nco_sincos_t* confptr, float32_t nco_freq, float32_t sample_rate, bool single_osc_calc, size_t blockSize)
|
||||
{
|
||||
double rate = (2 * M_PI * nco_freq) / sample_rate;
|
||||
confptr->rad_increment = rate;
|
||||
confptr->single_osc_calc = single_osc_calc;
|
||||
if (single_osc_calc)
|
||||
{
|
||||
confptr->rad_calc = 0;
|
||||
FreqShift_SinCos_Coeffs(confptr, blockSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency shift using a trigonometric math. Single coeff calculation operation gives good performance, continuous mode not so much.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm. It must have been configured using FreqShift_SinCos_Prepare before!
|
||||
* @param I_buffer incoming i data
|
||||
* @param Q_buffer incoming q data
|
||||
* @param blockSize size of data to be processed
|
||||
* @param dir dir == SHIFT_UP moves receive frequency to the right in the spectrum, SHIFT_DOWN opposite direction
|
||||
*/
|
||||
static void FreqShift_SinCos(fs_nco_sincos_t* confptr, float32_t* I_buffer, float32_t* Q_buffer, size_t blockSize, uint16_t dir)
|
||||
{
|
||||
|
||||
/*
|
||||
* cos(i) + sin(q) for i channel
|
||||
* cos(q) - sin(i) for q channel
|
||||
*
|
||||
* Shift Down (shift == 1) => i = Q, q = I
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
* Shift Up (shift == 0) => q = I, q = Q
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
*/
|
||||
|
||||
float32_t* i_buffer = dir == FREQ_SHIFT_UP? I_buffer : Q_buffer;
|
||||
float32_t* q_buffer = dir == FREQ_SHIFT_UP? Q_buffer : I_buffer;
|
||||
|
||||
float32_t q_cos_buffer[blockSize];
|
||||
float32_t i_sin_buffer[blockSize];
|
||||
float32_t q_sin_buffer[blockSize];
|
||||
float32_t i_cos_buffer[blockSize];
|
||||
|
||||
if (confptr->single_osc_calc == false)
|
||||
{
|
||||
FreqShift_SinCos_Coeffs(confptr, blockSize);
|
||||
}
|
||||
|
||||
// Do frequency conversion using optimized ARM math functions [KA7OEI]
|
||||
arm_mult_f32(q_buffer, confptr->Osc_Cos_buffer, q_cos_buffer, blockSize); // multiply products for converted I channel
|
||||
arm_mult_f32(i_buffer, confptr->Osc_Sin_buffer, i_sin_buffer, blockSize);
|
||||
arm_mult_f32(q_buffer, confptr->Osc_Sin_buffer, q_sin_buffer, blockSize);
|
||||
arm_mult_f32(i_buffer, confptr->Osc_Cos_buffer, i_cos_buffer, blockSize); // multiply products for converted Q channel
|
||||
|
||||
arm_add_f32(i_cos_buffer, q_sin_buffer, i_buffer, blockSize); // cos(I) + sin(Q) for I channel
|
||||
arm_sub_f32(q_cos_buffer, i_sin_buffer, q_buffer, blockSize); // cos(Q) - sin(I) for Q channel
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency shift using a just complex add and sub. Shifts by a quarter of the sample frequency. Best performance, single shift frequency.
|
||||
* @param confptr stores all configuration and operational data of the shift algorithm. It must have been configured using FreqShift_SinCos_Prepare before!
|
||||
* @param I_buffer incoming i data
|
||||
* @param Q_buffer incoming q data
|
||||
* @param blockSize size of data to be processed
|
||||
* @param dir dir == FREQ_SHIFT_UP moves receive frequency to the right in the spectrum, FREQ_SHIFT_DOWN opposite direction
|
||||
*/
|
||||
static void FreqShift_QuarterFs(float32_t* I_buffer, float32_t* Q_buffer, int16_t blockSize, int16_t dir)
|
||||
{
|
||||
/**********************************************************************************
|
||||
* Frequency translation by Fs/4 without multiplication
|
||||
* Lyons (2011): chapter 13.1.2 page 646
|
||||
* this is supposed to be much more efficient than a standard quadrature oscillator
|
||||
* with precalculated sin waves
|
||||
* Thanks, Clint, for pointing my interest to this method!, DD4WH 2016_12_28
|
||||
**********************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* Shift Down (shift == 1) => i = Q, q = I *
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
* Shift Up (shift == 0) => q = I, q = Q
|
||||
* [moves receive frequency to the right in the spectrum display]
|
||||
*
|
||||
*/
|
||||
|
||||
float32_t* i_buffer = dir == FREQ_SHIFT_UP? I_buffer : Q_buffer;
|
||||
float32_t* q_buffer = dir == FREQ_SHIFT_UP? Q_buffer : I_buffer;
|
||||
|
||||
|
||||
for(int i = 0; i < blockSize; i += 4)
|
||||
{ // xnew(0) = xreal(0) + jximag(0)
|
||||
// leave as it is!
|
||||
// xnew(1) = ximag(1) - jxreal(1)
|
||||
float32_t hh1 = q_buffer[i + 1];
|
||||
float32_t hh2 = - i_buffer[i + 1];
|
||||
i_buffer[i + 1] = hh1;
|
||||
q_buffer[i + 1] = hh2;
|
||||
// xnew(2) = -xreal(2) - jximag(2)
|
||||
hh1 = - i_buffer[i + 2];
|
||||
hh2 = - q_buffer[i + 2];
|
||||
i_buffer[i + 2] = hh1;
|
||||
q_buffer[i + 2] = hh2;
|
||||
// xnew(3) = -ximag(3) + jxreal(3)
|
||||
hh1 = - q_buffer[i + 3];
|
||||
hh2 = i_buffer[i + 3];
|
||||
i_buffer[i + 3] = hh1;
|
||||
q_buffer[i + 3] = hh2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency shift using the best available algorithm. Handles changes to the shift frequency on the fly. This is
|
||||
* the front end for all the shift algorithms. Sample rate is fixed to IQ_SAMPLE_RATE, max buffer is IQ_BLOCK_SIZE
|
||||
* It cannot be called twice at the same time (i.e. must not be used in code running in different interrupt levels
|
||||
* which may interrupt each other or mixed in normal code and interrupt code)
|
||||
*
|
||||
* @param I_buffer incoming i data
|
||||
* @param Q_buffer incoming q data
|
||||
* @param blockSize size of data to be processed
|
||||
* @param shift > 0 SHIFT_UP moves receive frequency to the right in the spectrum, SHIFT_DOWN opposite direction
|
||||
*/
|
||||
void FreqShift(float32_t* i_buffer, float32_t* q_buffer, size_t blockSize, int32_t shift)
|
||||
{
|
||||
// keeps the generated data for frequency conversion
|
||||
static int32_t conversion_freq = 0;
|
||||
static bool single_osc_calc = false;
|
||||
static bool is_quarter_of_fs = false;
|
||||
|
||||
static fs_nco_sincos_t nco_sincos;
|
||||
static fs_nco_approx_t nco_approx;
|
||||
|
||||
|
||||
assert(blockSize <= IQ_BLOCK_SIZE);
|
||||
|
||||
int32_t new_conversion_freq = abs(shift);
|
||||
if (conversion_freq != new_conversion_freq || single_osc_calc == false)
|
||||
{
|
||||
if (conversion_freq != new_conversion_freq)
|
||||
{
|
||||
float32_t rate = new_conversion_freq / IQ_SAMPLE_RATE_F;
|
||||
|
||||
single_osc_calc = (rate == 0.25 || rate == 0.125 || rate == 0.0625 || rate == 0.03125);
|
||||
// if the sample frequency divider to get shift frequency is a power of two no larger
|
||||
// than the number of samples in the osc buffer
|
||||
// we can avoid continuous recalculation of sin/cos table because it repeats after blockSize entries
|
||||
|
||||
is_quarter_of_fs = rate == 0.25;
|
||||
// if we have shift equals a quarter of sample frequency, we can use a highly optimized formula, see below
|
||||
|
||||
conversion_freq = new_conversion_freq;
|
||||
|
||||
FreqShift_Approx_Prepare(&nco_approx, new_conversion_freq, IQ_SAMPLE_RATE_F);
|
||||
// this algorithm works always, but takes more time
|
||||
|
||||
single_osc_calc = false;
|
||||
if (single_osc_calc == true)
|
||||
{
|
||||
|
||||
// Pre-calculate quadrature sine wave(s) ONCE for the conversion
|
||||
FreqShift_SinCos_Prepare(&nco_sincos, new_conversion_freq, IQ_SAMPLE_RATE_F, single_osc_calc, blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool dir = shift > 0;
|
||||
if (is_quarter_of_fs == true)
|
||||
{
|
||||
FreqShift_QuarterFs(i_buffer, q_buffer, blockSize, dir);
|
||||
}
|
||||
else if (single_osc_calc == true) // 'not so optimized' frequency translation using sin/cos (+6kHz or -6kHz)
|
||||
{
|
||||
// Below is the call to frequency translation code that uses a "pre-calculated" sine wave - which means that the translation must be done at a sub-
|
||||
// multiple of the sample frequency. This pre-calculation eliminates the processor overhead required to generate a sine wave on the fly.
|
||||
// This also makes extensive use of the optimized ARM vector instructions for the calculation of the final I/Q vectors
|
||||
FreqShift_SinCos(&nco_sincos, i_buffer, q_buffer, blockSize, dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FreqShift_Approx(&nco_approx, i_buffer, q_buffer, blockSize, dir);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __FREQ_SHIFT_H
|
||||
#define __FREQ_SHIF_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FREQ_SHIFT_UP = 0,
|
||||
FREQ_SHIFT_DOWN = 1,
|
||||
} freq_shift_dir_t;
|
||||
|
||||
void FreqShift(float32_t* i_buffer, float32_t* q_buffer, size_t blockSize, int32_t shift);
|
||||
|
||||
#endif
|
||||
+885
@@ -0,0 +1,885 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include "psk.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "softdds.h"
|
||||
#include "uhsdr_digi_buffer.h"
|
||||
#include "ui_driver.h" // only necessary because of UiDriver_TextMsgPutChar
|
||||
#include "radio_management.h" // only necessary because of RadioManagement_Request_TxOff
|
||||
|
||||
|
||||
// RX,TX common constants
|
||||
#define PSK_SAMPLE_RATE 12000 // TODO This should come from elsewhere, to be fixed
|
||||
|
||||
// RX constants
|
||||
#define PSK_BND_FLT_LEN 5
|
||||
#define PSK_BUF_LEN (PSK_SAMPLE_RATE / PSK_OFFSET)
|
||||
// this must be an integer result without remainder and must be a multiple of 4
|
||||
|
||||
#define PSK_SHIFT_DIFF (1.0 * PSK_OFFSET / PSK_SAMPLE_RATE) // phase change between two samples of PSK_OFFSET Hz
|
||||
|
||||
// TX constants
|
||||
#define SAMPLE_MAX 32766 // max amplitude of generated samples
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t rate;
|
||||
|
||||
uint16_t tx_idx;
|
||||
uint8_t tx_char;
|
||||
uint16_t tx_bits;
|
||||
int16_t tx_wave_sign_next;
|
||||
int16_t tx_wave_sign_current;
|
||||
uint16_t tx_bit_phase;
|
||||
uint32_t tx_bit_len;
|
||||
int16_t tx_zeros;
|
||||
int16_t tx_ones;
|
||||
bool tx_win;
|
||||
|
||||
float32_t rx_phase;
|
||||
float32_t rx_samples_in[PSK_BND_FLT_LEN];
|
||||
float32_t rx_samples[PSK_BND_FLT_LEN];
|
||||
int16_t rx_bnd_idx;
|
||||
float32_t rx_cos_prod[PSK_BUF_LEN];
|
||||
float32_t rx_sin_prod[PSK_BUF_LEN];
|
||||
float32_t rx_scmix[PSK_BUF_LEN];
|
||||
int32_t rx_idx;
|
||||
int8_t rx_last_bit;
|
||||
float32_t rx_err; // could be of interest for tuning
|
||||
float32_t rx_last_symbol;
|
||||
int16_t rx_symbol_len; // how many buffers fit into one bit
|
||||
int16_t rx_symbol_idx;
|
||||
// float32_t rx_symbol_buf[PSK_MAX_SYMBOL_BUF];
|
||||
uint32_t rx_word;
|
||||
psk_modulator_t tx_mod_state;
|
||||
float32_t rx_sum_sin;
|
||||
float32_t rx_sum_cos;
|
||||
} PskState_Internal_t;
|
||||
|
||||
|
||||
// table courtesy of fldigi pskvaricode.cxx
|
||||
static const uint16_t psk_varicode[] = {
|
||||
0b1010101011, /* 0 - <NUL> */
|
||||
0b1011011011, /* 1 - <SOH> */
|
||||
0b1011101101, /* 2 - <STX> */
|
||||
0b1101110111, /* 3 - <ETX> */
|
||||
0b1011101011, /* 4 - <EOT> */
|
||||
0b1101011111, /* 5 - <ENQ> */
|
||||
0b1011101111, /* 6 - <ACK> */
|
||||
0b1011111101, /* 7 - <BEL> */
|
||||
0b1011111111, /* 8 - <BS> */
|
||||
0b11101111, /* 9 - <TAB> */
|
||||
0b11101, /* 10 - <LF> */
|
||||
0b1101101111, /* 11 - <VT> */
|
||||
0b1011011101, /* 12 - <FF> */
|
||||
0b11111, /* 13 - <CR> */
|
||||
0b1101110101, /* 14 - <SO> */
|
||||
0b1110101011, /* 15 - <SI> */
|
||||
0b1011110111, /* 16 - <DLE> */
|
||||
0b1011110101, /* 17 - <DC1> */
|
||||
0b1110101101, /* 18 - <DC2> */
|
||||
0b1110101111, /* 19 - <DC3> */
|
||||
0b1101011011, /* 20 - <DC4> */
|
||||
0b1101101011, /* 21 - <NAK> */
|
||||
0b1101101101, /* 22 - <SYN> */
|
||||
0b1101010111, /* 23 - <ETB> */
|
||||
0b1101111011, /* 24 - <CAN> */
|
||||
0b1101111101, /* 25 - <EM> */
|
||||
0b1110110111, /* 26 - <SUB> */
|
||||
0b1101010101, /* 27 - <ESC> */
|
||||
0b1101011101, /* 28 - <FS> */
|
||||
0b1110111011, /* 29 - <GS> */
|
||||
0b1011111011, /* 30 - <RS> */
|
||||
0b1101111111, /* 31 - <US> */
|
||||
0b1, /* 32 - <SPC> */
|
||||
0b111111111, /* 33 - ! */
|
||||
0b101011111, /* 34 - '"' */
|
||||
0b111110101, /* 35 - # */
|
||||
0b111011011, /* 36 - $ */
|
||||
0b1011010101, /* 37 - % */
|
||||
0b1010111011, /* 38 - & */
|
||||
0b101111111, /* 39 - ' */
|
||||
0b11111011, /* 40 - ( */
|
||||
0b11110111, /* 41 - ) */
|
||||
0b101101111, /* 42 - * */
|
||||
0b111011111, /* 43 - + */
|
||||
0b1110101, /* 44 - , */
|
||||
0b110101, /* 45 - - */
|
||||
0b1010111, /* 46 - . */
|
||||
0b110101111, /* 47 - / */
|
||||
0b10110111, /* 48 - 0 */
|
||||
0b10111101, /* 49 - 1 */
|
||||
0b11101101, /* 50 - 2 */
|
||||
0b11111111, /* 51 - 3 */
|
||||
0b101110111, /* 52 - 4 */
|
||||
0b101011011, /* 53 - 5 */
|
||||
0b101101011, /* 54 - 6 */
|
||||
0b110101101, /* 55 - 7 */
|
||||
0b110101011, /* 56 - 8 */
|
||||
0b110110111, /* 57 - 9 */
|
||||
0b11110101, /* 58 - : */
|
||||
0b110111101, /* 59 - ; */
|
||||
0b111101101, /* 60 - < */
|
||||
0b1010101, /* 61 - = */
|
||||
0b111010111, /* 62 - > */
|
||||
0b1010101111, /* 63 - ? */
|
||||
0b1010111101, /* 64 - @ */
|
||||
0b1111101, /* 65 - A */
|
||||
0b11101011, /* 66 - B */
|
||||
0b10101101, /* 67 - C */
|
||||
0b10110101, /* 68 - D */
|
||||
0b1110111, /* 69 - E */
|
||||
0b11011011, /* 70 - F */
|
||||
0b11111101, /* 71 - G */
|
||||
0b101010101, /* 72 - H */
|
||||
0b1111111, /* 73 - I */
|
||||
0b111111101, /* 74 - J */
|
||||
0b101111101, /* 75 - K */
|
||||
0b11010111, /* 76 - L */
|
||||
0b10111011, /* 77 - M */
|
||||
0b11011101, /* 78 - N */
|
||||
0b10101011, /* 79 - O */
|
||||
0b11010101, /* 80 - P */
|
||||
0b111011101, /* 81 - Q */
|
||||
0b10101111, /* 82 - R */
|
||||
0b1101111, /* 83 - S */
|
||||
0b1101101, /* 84 - T */
|
||||
0b101010111, /* 85 - U */
|
||||
0b110110101, /* 86 - V */
|
||||
0b101011101, /* 87 - W */
|
||||
0b101110101, /* 88 - X */
|
||||
0b101111011, /* 89 - Y */
|
||||
0b1010101101, /* 90 - Z */
|
||||
0b111110111, /* 91 - [ */
|
||||
0b111101111, /* 92 - \ */
|
||||
0b111111011, /* 93 - ] */
|
||||
0b1010111111, /* 94 - ^ */
|
||||
0b101101101, /* 95 - _ */
|
||||
0b1011011111, /* 96 - ` */
|
||||
0b1011, /* 97 - a */
|
||||
0b1011111, /* 98 - b */
|
||||
0b101111, /* 99 - c */
|
||||
0b101101, /* 100 - d */
|
||||
0b11, /* 101 - e */
|
||||
0b111101, /* 102 - f */
|
||||
0b1011011, /* 103 - g */
|
||||
0b101011, /* 104 - h */
|
||||
0b1101, /* 105 - i */
|
||||
0b111101011, /* 106 - j */
|
||||
0b10111111, /* 107 - k */
|
||||
0b11011, /* 108 - l */
|
||||
0b111011, /* 109 - m */
|
||||
0b1111, /* 110 - n */
|
||||
0b111, /* 111 - o */
|
||||
0b111111, /* 112 - p */
|
||||
0b110111111, /* 113 - q */
|
||||
0b10101, /* 114 - r */
|
||||
0b10111, /* 115 - s */
|
||||
0b101, /* 116 - t */
|
||||
0b110111, /* 117 - u */
|
||||
0b1111011, /* 118 - v */
|
||||
0b1101011, /* 119 - w */
|
||||
0b11011111, /* 120 - x */
|
||||
0b1011101, /* 121 - y */
|
||||
0b111010101, /* 122 - z */
|
||||
0b1010110111, /* 123 - { */
|
||||
0b110111011, /* 124 - | */
|
||||
0b1010110101, /* 125 - } */
|
||||
0b1011010111, /* 126 - ~ */
|
||||
0b1110110101, /* 127 - <DEL> */
|
||||
0b1110111101, /* 128 - */
|
||||
0b1110111111, /* 129 - */
|
||||
0b1111010101, /* 130 - */
|
||||
0b1111010111, /* 131 - */
|
||||
0b1111011011, /* 132 - */
|
||||
0b1111011101, /* 133 - */
|
||||
0b1111011111, /* 134 - */
|
||||
0b1111101011, /* 135 - */
|
||||
0b1111101101, /* 136 - */
|
||||
0b1111101111, /* 137 - */
|
||||
0b1111110101, /* 138 - */
|
||||
0b1111110111, /* 139 - */
|
||||
0b1111111011, /* 140 - */
|
||||
0b1111111101, /* 141 - */
|
||||
0b1111111111, /* 142 - */
|
||||
0b10101010101, /* 143 - */
|
||||
0b10101010111, /* 144 - */
|
||||
0b10101011011, /* 145 - */
|
||||
0b10101011101, /* 146 - */
|
||||
0b10101011111, /* 147 - */
|
||||
0b10101101011, /* 148 - */
|
||||
0b10101101101, /* 149 - */
|
||||
0b10101101111, /* 150 - */
|
||||
0b10101110101, /* 151 - */
|
||||
0b10101110111, /* 152 - */
|
||||
0b10101111011, /* 153 - */
|
||||
0b10101111101, /* 154 - */
|
||||
0b10101111111, /* 155 - */
|
||||
0b10110101011, /* 156 - */
|
||||
0b10110101101, /* 157 - */
|
||||
0b10110101111, /* 158 - */
|
||||
0b10110110101, /* 159 - */
|
||||
0b10110110111, /* 160 - */
|
||||
0b10110111011, /* 161 - */
|
||||
0b10110111101, /* 162 - */
|
||||
0b10110111111, /* 163 - */
|
||||
0b10111010101, /* 164 - */
|
||||
0b10111010111, /* 165 - */
|
||||
0b10111011011, /* 166 - */
|
||||
0b10111011101, /* 167 - */
|
||||
0b10111011111, /* 168 - */
|
||||
0b10111101011, /* 169 - */
|
||||
0b10111101101, /* 170 - */
|
||||
0b10111101111, /* 171 - */
|
||||
0b10111110101, /* 172 - */
|
||||
0b10111110111, /* 173 - */
|
||||
0b10111111011, /* 174 - */
|
||||
0b10111111101, /* 175 - */
|
||||
0b10111111111, /* 176 - */
|
||||
0b11010101011, /* 177 - */
|
||||
0b11010101101, /* 178 - */
|
||||
0b11010101111, /* 179 - */
|
||||
0b11010110101, /* 180 - */
|
||||
0b11010110111, /* 181 - */
|
||||
0b11010111011, /* 182 - */
|
||||
0b11010111101, /* 183 - */
|
||||
0b11010111111, /* 184 - */
|
||||
0b11011010101, /* 185 - */
|
||||
0b11011010111, /* 186 - */
|
||||
0b11011011011, /* 187 - */
|
||||
0b11011011101, /* 188 - */
|
||||
0b11011011111, /* 189 - */
|
||||
0b11011101011, /* 190 - */
|
||||
0b11011101101, /* 191 - */
|
||||
0b11011101111, /* 192 - */
|
||||
0b11011110101, /* 193 - */
|
||||
0b11011110111, /* 194 - */
|
||||
0b11011111011, /* 195 - */
|
||||
0b11011111101, /* 196 - */
|
||||
0b11011111111, /* 197 - */
|
||||
0b11101010101, /* 198 - */
|
||||
0b11101010111, /* 199 - */
|
||||
0b11101011011, /* 200 - */
|
||||
0b11101011101, /* 201 - */
|
||||
0b11101011111, /* 202 - */
|
||||
0b11101101011, /* 203 - */
|
||||
0b11101101101, /* 204 - */
|
||||
0b11101101111, /* 205 - */
|
||||
0b11101110101, /* 206 - */
|
||||
0b11101110111, /* 207 - */
|
||||
0b11101111011, /* 208 - */
|
||||
0b11101111101, /* 209 - */
|
||||
0b11101111111, /* 210 - */
|
||||
0b11110101011, /* 211 - */
|
||||
0b11110101101, /* 212 - */
|
||||
0b11110101111, /* 213 - */
|
||||
0b11110110101, /* 214 - */
|
||||
0b11110110111, /* 215 - */
|
||||
0b11110111011, /* 216 - */
|
||||
0b11110111101, /* 217 - */
|
||||
0b11110111111, /* 218 - */
|
||||
0b11111010101, /* 219 - */
|
||||
0b11111010111, /* 220 - */
|
||||
0b11111011011, /* 221 - */
|
||||
0b11111011101, /* 222 - */
|
||||
0b11111011111, /* 223 - */
|
||||
0b11111101011, /* 224 - */
|
||||
0b11111101101, /* 225 - */
|
||||
0b11111101111, /* 226 - */
|
||||
0b11111110101, /* 227 - */
|
||||
0b11111110111, /* 228 - */
|
||||
0b11111111011, /* 229 - */
|
||||
0b11111111101, /* 230 - */
|
||||
0b11111111111, /* 231 - */
|
||||
0b101010101011, /* 232 - */
|
||||
0b101010101101, /* 233 - */
|
||||
0b101010101111, /* 234 - */
|
||||
0b101010110101, /* 235 - */
|
||||
0b101010110111, /* 236 - */
|
||||
0b101010111011, /* 237 - */
|
||||
0b101010111101, /* 238 - */
|
||||
0b101010111111, /* 239 - */
|
||||
0b101011010101, /* 240 - */
|
||||
0b101011010111, /* 241 - */
|
||||
0b101011011011, /* 242 - */
|
||||
0b101011011101, /* 243 - */
|
||||
0b101011011111, /* 244 - */
|
||||
0b101011101011, /* 245 - */
|
||||
0b101011101101, /* 246 - */
|
||||
0b101011101111, /* 247 - */
|
||||
0b101011110101, /* 248 - */
|
||||
0b101011110111, /* 249 - */
|
||||
0b101011111011, /* 250 - */
|
||||
0b101011111101, /* 251 - */
|
||||
0b101011111111, /* 252 - */
|
||||
0b101101010101, /* 253 - */
|
||||
0b101101010111, /* 254 - */
|
||||
0b101101011011, /* 255 - */
|
||||
};
|
||||
|
||||
#define PSK_VARICODE_NUM (sizeof(psk_varicode)/sizeof(*psk_varicode))
|
||||
|
||||
|
||||
static const float32_t PskBndPassB_31[] = {
|
||||
6.6165543533213894e-05,
|
||||
0.0,
|
||||
-0.00013233108706642779,
|
||||
0.0,
|
||||
6.6165543533213894e-05
|
||||
};
|
||||
|
||||
static const float32_t PskBndPassA_31[] = {
|
||||
1.0,
|
||||
-3.8414813063247664,
|
||||
5.6662277107033248,
|
||||
-3.7972899991488904,
|
||||
0.9771256616899302
|
||||
};
|
||||
|
||||
static const float32_t PskBndPassB_63[] = {
|
||||
0.0002616526950658905,
|
||||
0.0,
|
||||
-0.000523305390131781,
|
||||
0.0,
|
||||
0.0002616526950658905
|
||||
};
|
||||
|
||||
static const float32_t PskBndPassA_63[] = {
|
||||
1.0,
|
||||
-3.8195192250239174,
|
||||
5.6013869366249818,
|
||||
-3.7321386869273105,
|
||||
0.95477455992103932
|
||||
};
|
||||
|
||||
static const float32_t PskBndPassB_125[] = {
|
||||
0.0010232176384709002,
|
||||
0.0,
|
||||
-0.0020464352769418003,
|
||||
0.0,
|
||||
0.0010232176384709002
|
||||
};
|
||||
|
||||
static const float32_t PskBndPassA_125[] = {
|
||||
1.0,
|
||||
-3.7763786572915334,
|
||||
5.4745855184361272,
|
||||
-3.6055008493327723,
|
||||
0.91159449659996006
|
||||
};
|
||||
|
||||
static soft_dds_t psk_dds;
|
||||
static soft_dds_t psk_bit_dds;
|
||||
static soft_dds_t psk_rx_dds;
|
||||
|
||||
|
||||
#if 0
|
||||
static void PskBufAdd(int len, float32_t buf[], float32_t v)
|
||||
{
|
||||
for (int i = len - 1; i > 0; i--)
|
||||
{
|
||||
buf[i] = buf[i-1];
|
||||
}
|
||||
buf[0] = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
static float32_t Psk_IirNext(const float32_t bpf_b[], const float32_t bpf_a[], float32_t x[], float32_t y[], int idx, int taps)
|
||||
{
|
||||
float32_t resp = 0;
|
||||
int iidx;
|
||||
|
||||
for (int i = 0; i < taps; i++)
|
||||
{
|
||||
iidx = (idx - i + taps) % taps;
|
||||
resp += bpf_b[i] * x[iidx];
|
||||
if (i>0)
|
||||
{
|
||||
resp -= bpf_a[i] * y[iidx];
|
||||
}
|
||||
}
|
||||
return resp / bpf_a[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const psk_speed_item_t psk_speeds[PSK_SPEED_NUM] =
|
||||
{
|
||||
{ .id =PSK_SPEED_31, .value = 31.25, .bpf_b = PskBndPassB_31, .bpf_a = PskBndPassA_31, .rate = 384, .label = " 31" },
|
||||
{ .id =PSK_SPEED_63, .value = 62.5, .bpf_b = PskBndPassB_63, .bpf_a = PskBndPassA_63, .rate = 192, .label = " 63" },
|
||||
{ .id =PSK_SPEED_125, .value = 125.0, .bpf_b = PskBndPassB_125, .bpf_a = PskBndPassA_125, .rate = 96, .label = "125" }
|
||||
};
|
||||
|
||||
psk_ctrl_t psk_ctrl_config =
|
||||
{
|
||||
.speed_idx = PSK_SPEED_31
|
||||
};
|
||||
|
||||
PskState_Internal_t psk_state;
|
||||
|
||||
static void Bpsk_ResetWin(void) {
|
||||
// little trick, we just reset the acc
|
||||
// which brings us back to the first sample
|
||||
psk_bit_dds.acc = 0;
|
||||
}
|
||||
|
||||
void Psk_Modulator_PrepareTx()
|
||||
{
|
||||
Psk_Modulator_SetState(PSK_MOD_PREAMBLE);
|
||||
}
|
||||
|
||||
void Bpsk_Demodulator_Init()
|
||||
{
|
||||
psk_state.rx_phase = 0;
|
||||
psk_state.rx_bnd_idx = 0;
|
||||
|
||||
for (int i = 0; i < PSK_BND_FLT_LEN; i++)
|
||||
{
|
||||
psk_state.rx_samples_in[i] = 0;
|
||||
psk_state.rx_samples[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < PSK_BUF_LEN; i++)
|
||||
{
|
||||
psk_state.rx_cos_prod[i] = 0;
|
||||
psk_state.rx_sin_prod[i] = 0;
|
||||
psk_state.rx_scmix[i] = 0;
|
||||
}
|
||||
|
||||
psk_state.rx_idx = 0;
|
||||
psk_state.rx_last_bit = 0;
|
||||
psk_state.rx_last_symbol = 0;
|
||||
psk_state.rx_symbol_len = psk_state.rate / PSK_BUF_LEN;
|
||||
psk_state.rx_symbol_idx = 0;
|
||||
|
||||
// for (int i = 0; i < psk_state.rx_symbol_len; i ++)
|
||||
// {
|
||||
// psk_state.rx_symbol_buf[i];
|
||||
// }
|
||||
|
||||
psk_state.rx_word = 0;
|
||||
}
|
||||
|
||||
|
||||
void Psk_Modem_Init(uint32_t output_sample_rate)
|
||||
{
|
||||
|
||||
psk_state.tx_idx = 0;
|
||||
|
||||
softdds_setFreqDDS(&psk_dds, PSK_OFFSET, output_sample_rate, true);
|
||||
softdds_setFreqDDS(&psk_rx_dds, PSK_OFFSET, PSK_SAMPLE_RATE, true);
|
||||
// we use a sine wave with a frequency of half of the bit rate
|
||||
// as envelope generator
|
||||
softdds_setFreqDDS(&psk_bit_dds, (float32_t)psk_speeds[psk_ctrl_config.speed_idx].value / 2.0, output_sample_rate, false);
|
||||
|
||||
psk_state.tx_bit_len = lround(output_sample_rate / psk_speeds[psk_ctrl_config.speed_idx].value * 2); // 480000 / 31.25 * 2 = 3072
|
||||
psk_state.rate = PSK_SAMPLE_RATE / psk_speeds[psk_ctrl_config.speed_idx].value;
|
||||
|
||||
Bpsk_Demodulator_Init();
|
||||
}
|
||||
|
||||
|
||||
static char Bpsk_DecodeVaricode(uint16_t code)
|
||||
{
|
||||
char result = '*';
|
||||
for (int i = 0; i<PSK_VARICODE_NUM; i++) {
|
||||
if (psk_varicode[i] == code)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint16_t Bpsk_FindCharReversed(uint8_t c)
|
||||
{
|
||||
uint16_t retval = 0;
|
||||
|
||||
uint16_t code = psk_varicode[c];
|
||||
|
||||
// bit reverse the code bit pattern, we need MSB of code to be LSB for shifting
|
||||
while(code > 0)
|
||||
{
|
||||
retval |= code & 0x1; // mask and transfer LSB
|
||||
retval <<= 1; // left shift
|
||||
code >>= 1; // right shift, next bit gets active
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Basically samples the phase every bit length based on a sample which is one full sine wave
|
||||
* of the carrier frequency. So it is not using multiple sampling points or anything.
|
||||
* We throw away a lot of phase differences symbols
|
||||
* using more of these should make the code more robust, shouldn't it?
|
||||
*
|
||||
* @param symbol_out averaged phase of the samples.
|
||||
*/
|
||||
|
||||
static void BpskDecoder_NextSymbol(float32_t symbol_out)
|
||||
{
|
||||
int8_t bit;
|
||||
|
||||
static float32_t symbol_store = 0;
|
||||
|
||||
// if (psk_state.rx_symbol_len - psk_state.rx_symbol_idx < 6)
|
||||
{
|
||||
symbol_store = symbol_out;
|
||||
}
|
||||
|
||||
psk_state.rx_symbol_idx += 1;
|
||||
if (psk_state.rx_symbol_idx >= psk_state.rx_symbol_len)
|
||||
{
|
||||
psk_state.rx_symbol_idx = 0;
|
||||
// TODO here should come additional part to check if timing of sampling should be moved
|
||||
if (psk_state.rx_last_symbol * symbol_store < 0)
|
||||
{
|
||||
bit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = 1;
|
||||
}
|
||||
|
||||
psk_state.rx_last_symbol = symbol_store;
|
||||
symbol_store = 0;
|
||||
|
||||
// have we found 2 consecutive 0 bits? And previously at least one received bit == 1?
|
||||
// indicates an end of character
|
||||
if (psk_state.rx_last_bit == 0 && bit == 0 && psk_state.rx_word != 0)
|
||||
{
|
||||
// we lookup up the bits received (minus the last zero, which we shift out to the right)
|
||||
// and put it into the buffer
|
||||
UiDriver_TextMsgPutChar(Bpsk_DecodeVaricode(psk_state.rx_word >> 1));
|
||||
|
||||
// clean out the stored bit pattern
|
||||
psk_state.rx_word = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
psk_state.rx_word = (psk_state.rx_word << 1) | bit;
|
||||
}
|
||||
|
||||
psk_state.rx_last_bit = bit;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static float32_t BpskDecoder_Bandpass(float32_t sample)
|
||||
{
|
||||
// save original sample in bpf's input buffer
|
||||
psk_state.rx_samples_in[psk_state.rx_bnd_idx] = sample;
|
||||
|
||||
// IIR bandpass for signal frequency range, implemented in a ring buffer
|
||||
float32_t retval = Psk_IirNext(psk_speeds[psk_ctrl_config.speed_idx].bpf_b, psk_speeds[psk_ctrl_config.speed_idx].bpf_a, psk_state.rx_samples_in,
|
||||
psk_state.rx_samples, psk_state.rx_bnd_idx, PSK_BND_FLT_LEN);
|
||||
|
||||
// save filtered sample in state buffer, used in next run;
|
||||
psk_state.rx_samples[psk_state.rx_bnd_idx] = retval;
|
||||
|
||||
// increment our ring buffer index
|
||||
psk_state.rx_bnd_idx++;
|
||||
psk_state.rx_bnd_idx %= PSK_BND_FLT_LEN;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an audio sample and decode signal.
|
||||
*
|
||||
* @param audio sample at PSK_SAMPLE_RATE
|
||||
*/
|
||||
void Psk_Demodulator_ProcessSample(float32_t sample)
|
||||
{
|
||||
float32_t fsample = BpskDecoder_Bandpass(sample);
|
||||
|
||||
// VCO generates a sine/cosine wave "carrier" with PSK_OFFSET Hz as frequency
|
||||
float32_t vco_sin, vco_cos;
|
||||
// we have to use a different DDS as for TX (different sample rates), IQ gives us sin and cos waves of PSK_OFFSET Hz
|
||||
softdds_genIQSingleTone(&psk_rx_dds, &vco_sin , &vco_cos, 1);
|
||||
|
||||
// we now multiple these carriers with our signal
|
||||
// this allows us to compare phase differences
|
||||
float32_t sin_mix = vco_sin * fsample;
|
||||
float32_t cos_mix = vco_cos * fsample;
|
||||
|
||||
// update sums by differences between old and new value in ringbuffer
|
||||
psk_state.rx_sum_sin += sin_mix - psk_state.rx_sin_prod[psk_state.rx_idx];
|
||||
psk_state.rx_sum_cos += cos_mix - psk_state.rx_cos_prod[psk_state.rx_idx];
|
||||
|
||||
// store new value
|
||||
psk_state.rx_sin_prod[psk_state.rx_idx] = sin_mix;
|
||||
psk_state.rx_cos_prod[psk_state.rx_idx] = cos_mix;
|
||||
|
||||
// we now calculate an average
|
||||
float32_t symbol_out = psk_state.rx_sum_sin / PSK_BUF_LEN;
|
||||
float32_t cos_out = psk_state.rx_sum_cos / PSK_BUF_LEN;
|
||||
|
||||
// GUESS: now try to estimate the frequency error of our VCO vs. the incoming signal
|
||||
float32_t rx_scmix = symbol_out * cos_out;
|
||||
psk_state.rx_err += rx_scmix - psk_state.rx_scmix[psk_state.rx_idx];
|
||||
psk_state.rx_scmix[psk_state.rx_idx] = rx_scmix;
|
||||
|
||||
|
||||
float32_t smax = 0;
|
||||
|
||||
for (int i = 0; i < PSK_BUF_LEN; i++)
|
||||
{
|
||||
if (fabsf(psk_state.rx_cos_prod[i]) > smax)
|
||||
{
|
||||
smax = fabsf(psk_state.rx_cos_prod[i]);
|
||||
}
|
||||
if (fabsf(psk_state.rx_sin_prod[i]) > smax)
|
||||
{
|
||||
smax = fabsf(psk_state.rx_sin_prod[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the final correction value from rx_err
|
||||
// avoid division by zero if smax is 0
|
||||
float32_t rx_err_corr = psk_state.rx_err/ (PSK_BUF_LEN * ((smax != 0) ? (smax * smax * 4.0) : 1.0));
|
||||
|
||||
// if the error is too large, we limit it to +/- 0.1
|
||||
if(fabsf(rx_err_corr) > 0.1)
|
||||
{
|
||||
rx_err_corr = (rx_err_corr > 0) ? 0.1 : -0.1;
|
||||
}
|
||||
rx_err_corr = 0;
|
||||
|
||||
// now advance our phase counter with our error correction
|
||||
psk_state.rx_phase += PSK_SHIFT_DIFF + rx_err_corr * PSK_SHIFT_DIFF;
|
||||
|
||||
|
||||
// we just passed one "full" offset frequency wave length?
|
||||
// now see if we have enough symbols to decide if it is a 1 or 0
|
||||
// the symbol is basically an averaged phase difference over the last PSK_BUF_LEN
|
||||
// samples.
|
||||
if (psk_state.rx_phase > 1)
|
||||
{
|
||||
psk_state.rx_phase -= 1;
|
||||
BpskDecoder_NextSymbol(symbol_out);
|
||||
}
|
||||
|
||||
if (psk_state.rx_phase < 0)
|
||||
{
|
||||
psk_state.rx_phase += 1;
|
||||
}
|
||||
|
||||
// we prepare us for the next sample in our ring buffer
|
||||
psk_state.rx_idx = (psk_state.rx_idx + 1) % PSK_BUF_LEN;
|
||||
}
|
||||
|
||||
static bool bit_start(uint16_t tx_bit_phase)
|
||||
{
|
||||
return tx_bit_phase == psk_state.tx_bit_len / 4;
|
||||
}
|
||||
|
||||
static bool bit_middle(uint16_t tx_bit_phase)
|
||||
{
|
||||
return tx_bit_phase == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a BPSK signal. Uses an oscillator for generating continous base signal of a
|
||||
* given frequency (defined in PSK_OFFSET). This signal is phase controlled by a variable
|
||||
* psk_state.tx_wave_sign_current. A second frequency generator provides an envelope shape based on a cosine
|
||||
* of half of the bpsk rate. For 0 bits to transmit the symbol is using the enveloped signal and shifts
|
||||
* in the middle.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int16_t Psk_Modulator_GenSample()
|
||||
{
|
||||
// tx_bit_len / 4 -> start of a bit
|
||||
// tx_bit_len / 0 -> middle of a bit
|
||||
// tx_bit_len / 2 -> end of a bit
|
||||
|
||||
int32_t retval = 0; // by default we produce silence
|
||||
|
||||
// check if the modulator is supposed to be active...
|
||||
if (Psk_Modulator_GetState() != PSK_MOD_OFF)
|
||||
{
|
||||
// try to find out what to transmit next
|
||||
if (bit_start(psk_state.tx_bit_phase))
|
||||
{
|
||||
// check if we still have bits to transmit
|
||||
if (psk_state.tx_bits == 0)
|
||||
{
|
||||
// no, all bits have been transmitted
|
||||
if (psk_state.tx_zeros < 2 || (Psk_Modulator_GetState() == PSK_MOD_PREAMBLE))
|
||||
{
|
||||
// send spacing zeros before anything else happens
|
||||
// normal characters don't have 2 zeros following each other
|
||||
psk_state.tx_zeros++;
|
||||
|
||||
// are we sending a preamble and have transmitted enough zeroes?
|
||||
// we do this for roughly a second, i.e. we simply use the rate as "timer"
|
||||
if ((Psk_Modulator_GetState() == PSK_MOD_PREAMBLE) && psk_state.tx_zeros >= psk_speeds[psk_ctrl_config.speed_idx].value)
|
||||
{
|
||||
Psk_Modulator_SetState(PSK_MOD_ACTIVE);
|
||||
}
|
||||
}
|
||||
else if (DigiModes_TxBufferHasData())
|
||||
{
|
||||
DigiModes_TxBufferRemove( &psk_state.tx_char, BPSK );
|
||||
Psk_Modulator_SetState(PSK_MOD_ACTIVE);
|
||||
if (psk_state.tx_char == 0x04) // EOT, stop tranmission
|
||||
{
|
||||
// we send from buffer, and nothing more is in the buffer
|
||||
// request sending the trailing sequence
|
||||
Psk_Modulator_SetState(PSK_MOD_POSTAMBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if all zeros have been sent, look for new
|
||||
// input from input buffer
|
||||
psk_state.tx_bits = Bpsk_FindCharReversed(psk_state.tx_char);
|
||||
// reset counter for spacing zeros
|
||||
psk_state.tx_zeros = 0;
|
||||
// reset counter for trailing postamble (which conclude a transmission)
|
||||
psk_state.tx_ones = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Psk_Modulator_GetState() == PSK_MOD_POSTAMBLE)
|
||||
{
|
||||
// this is for generating trailing postamble if the
|
||||
// input comes from a buffer or if we are asked to
|
||||
// switch off,
|
||||
// we do this for roughly a second, i.e. we simply use the rate as "timer"
|
||||
if (psk_state.tx_ones < psk_speeds[psk_ctrl_config.speed_idx].value)
|
||||
{
|
||||
psk_state.tx_ones+=16;
|
||||
psk_state.tx_bits = 0xffff; // we add 16 bits of postamble
|
||||
// so we may send a few more postamble than request, but who cares...
|
||||
}
|
||||
else
|
||||
{
|
||||
Psk_Modulator_SetState(PSK_MOD_INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we test the current bit. If it is a zero, and we have no more postamble to transmit
|
||||
// we alternate the phase of our signal phase (180 degree shift)
|
||||
if ((psk_state.tx_bits & 0x1) == 0 && psk_state.tx_ones == 0)
|
||||
{
|
||||
psk_state.tx_wave_sign_next *= -1;
|
||||
}
|
||||
|
||||
// if it is a phase shift, which equals a zero to transmit or we transmit our last bit
|
||||
if (psk_state.tx_wave_sign_next != psk_state.tx_wave_sign_current || Psk_Modulator_GetState() == PSK_MOD_INACTIVE)
|
||||
{
|
||||
// we have to shape the signal
|
||||
psk_state.tx_win = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it is a one and not the end, so we simply keep the full swing,
|
||||
// i.e. a constant amplitude signal
|
||||
psk_state.tx_win = false;
|
||||
}
|
||||
|
||||
psk_state.tx_bits >>= 1; // remove "used" bit
|
||||
}
|
||||
|
||||
// here we are in the middle of bit
|
||||
// we move the next sign in, since it may indicate a phase shift
|
||||
// in this case we are transmitting a zero
|
||||
if (bit_middle(psk_state.tx_bit_phase))
|
||||
{
|
||||
|
||||
psk_state.tx_wave_sign_current = psk_state.tx_wave_sign_next;
|
||||
|
||||
|
||||
// if we are in the middle of a bit AND it is a zero bit
|
||||
// we have to start our envelope from null
|
||||
if (psk_state.tx_win)
|
||||
{
|
||||
Bpsk_ResetWin(); // we start the envelope from 0 to max
|
||||
}
|
||||
if (Psk_Modulator_GetState() == PSK_MOD_INACTIVE)
|
||||
{
|
||||
// now turn us off, we're done.
|
||||
Psk_Modulator_SetState(PSK_MOD_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
// if we are shaping the signal envelope
|
||||
// we use the "slow" to generate our shape.
|
||||
// we use abs so that we are getting only the gain
|
||||
// not the phase from here
|
||||
// otherwise we use the SAMPLE_MAX as coeff for constant amplitude
|
||||
int32_t coeff = psk_state.tx_win ? abs(softdds_nextSample(&psk_bit_dds)) : SAMPLE_MAX;
|
||||
|
||||
// the bit length counter is incremented after each sample
|
||||
// and wraps around after one bit length
|
||||
psk_state.tx_bit_phase = (psk_state.tx_bit_phase + 1) % (psk_state.tx_bit_len / 2); // % 1576 == 1 bit length
|
||||
|
||||
|
||||
retval = (coeff * psk_state.tx_wave_sign_current * softdds_nextSample(&psk_dds)) / SAMPLE_MAX;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operational state of the PSK modulator
|
||||
* @return current state
|
||||
*/
|
||||
psk_modulator_t Psk_Modulator_GetState()
|
||||
{
|
||||
return psk_state.tx_mod_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the state of the psk modulator to a new operational state
|
||||
* If necessary, checks if state can be changed and executes code
|
||||
* for the state transistion such as resetting variables to a known etc.
|
||||
*
|
||||
* @param newState
|
||||
* @return the previous state
|
||||
*/
|
||||
psk_modulator_t Psk_Modulator_SetState(psk_modulator_t newState)
|
||||
{
|
||||
psk_modulator_t retval = psk_state.tx_mod_state;
|
||||
|
||||
switch(newState)
|
||||
{
|
||||
case PSK_MOD_PREAMBLE:
|
||||
psk_state.tx_ones = 0;
|
||||
psk_state.tx_win = true;
|
||||
psk_state.tx_char = '\0';
|
||||
psk_state.tx_bits = 0;
|
||||
psk_state.tx_wave_sign_next = 1;
|
||||
psk_state.tx_wave_sign_current = 1;
|
||||
psk_state.tx_bit_phase = 0;
|
||||
psk_state.tx_zeros = 0;
|
||||
psk_state.tx_mod_state = newState;
|
||||
break;
|
||||
case PSK_MOD_OFF:
|
||||
RadioManagement_Request_TxOff();
|
||||
psk_state.tx_mod_state = newState;
|
||||
break;
|
||||
default:
|
||||
psk_state.tx_mod_state = newState;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __PSK_H
|
||||
#define __PSK_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
// externally defined for UiSpectrum markers
|
||||
#define PSK_OFFSET 500
|
||||
#define PSK_SNAP_RANGE 100 // defines the range within which the SNAP algorithm in spectrum.c searches for the PSK carrier
|
||||
|
||||
|
||||
typedef enum {
|
||||
PSK_SPEED_31,
|
||||
PSK_SPEED_63,
|
||||
PSK_SPEED_125,
|
||||
PSK_SPEED_NUM
|
||||
} psk_speed_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
psk_speed_t id;
|
||||
float32_t value;
|
||||
const float32_t* bpf_b;
|
||||
const float32_t* bpf_a;
|
||||
uint16_t rate;
|
||||
char* label;
|
||||
} psk_speed_item_t;
|
||||
|
||||
|
||||
extern const psk_speed_item_t psk_speeds[PSK_SPEED_NUM];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
psk_speed_t speed_idx;
|
||||
} psk_ctrl_t;
|
||||
|
||||
extern psk_ctrl_t psk_ctrl_config;
|
||||
|
||||
typedef enum {
|
||||
PSK_MOD_OFF,
|
||||
PSK_MOD_PREAMBLE,
|
||||
PSK_MOD_ACTIVE,
|
||||
PSK_MOD_POSTAMBLE,
|
||||
PSK_MOD_INACTIVE
|
||||
} psk_modulator_t;
|
||||
|
||||
psk_modulator_t Psk_Modulator_GetState(void);
|
||||
psk_modulator_t Psk_Modulator_SetState(psk_modulator_t newState);
|
||||
|
||||
|
||||
void Psk_Modem_Init(uint32_t output_sample_rate);
|
||||
void Psk_Modulator_PrepareTx(void);
|
||||
void Psk_Demodulator_ProcessSample(float32_t sample);
|
||||
int16_t Psk_Modulator_GenSample(void);
|
||||
|
||||
#endif
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
#include "rb.h"
|
||||
|
||||
void RingBuffer_ClearGetTail(RingBuffer_data_t* buf)
|
||||
{
|
||||
do
|
||||
{
|
||||
buf->buffer_tail = buf->buffer_head;
|
||||
|
||||
} while (buf->buffer_tail != buf->buffer_head);
|
||||
}
|
||||
|
||||
void RingBuffer_ClearPutHead(RingBuffer_data_t* buf)
|
||||
{
|
||||
do
|
||||
{
|
||||
buf->buffer_head = buf->buffer_tail;
|
||||
|
||||
} while (buf->buffer_tail != buf->buffer_head);
|
||||
}
|
||||
|
||||
int32_t RingBuffer_GetRoom(RingBuffer_data_t* buf)
|
||||
{
|
||||
int32_t retval = ((buf->buffer_tail + buf->conf.size) - buf->buffer_head) % buf->conf.size;
|
||||
return retval == 0 ? buf->conf.size : retval;
|
||||
}
|
||||
|
||||
int32_t RingBuffer_GetData(RingBuffer_data_t* buf)
|
||||
{
|
||||
int32_t retval = ((buf->buffer_head + buf->conf.size) - buf->buffer_tail) % buf->conf.size;
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool RingBuffer_PutSamples(RingBuffer_data_t* buf, void* samples, int32_t len)
|
||||
{
|
||||
bool retval = false;
|
||||
if (len < RingBuffer_GetRoom(buf))
|
||||
{
|
||||
int32_t maxupper = buf->conf.size - buf->buffer_head;
|
||||
int32_t copylower = len - maxupper;
|
||||
int32_t copyupper = copylower > 0 ? maxupper : len;
|
||||
memcpy((char*)buf->conf.buffer + (buf->buffer_head * buf->conf.sizeofItem),(char*)samples,copyupper * buf->conf.sizeofItem);
|
||||
if (copylower > 0)
|
||||
{
|
||||
memcpy((char*)buf->conf.buffer,(char*)samples + (maxupper * buf->conf.sizeofItem),copylower * buf->conf.sizeofItem);
|
||||
}
|
||||
|
||||
|
||||
buf->buffer_head = (buf->buffer_head + len) % buf->conf.size;
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool RingBuffer_GetSamples(RingBuffer_data_t* buf, void* samples, int32_t len)
|
||||
{
|
||||
bool retval = false;
|
||||
if (len <= RingBuffer_GetData(buf))
|
||||
{
|
||||
int32_t maxupper = buf->conf.size - buf->buffer_tail;
|
||||
int32_t copylower = len - maxupper;
|
||||
int32_t copyupper = copylower > 0 ? maxupper : len;
|
||||
memcpy((char*)samples,(char*)buf->conf.buffer + (buf->buffer_tail * buf->conf.sizeofItem),copyupper * buf->conf.sizeofItem);
|
||||
if (copylower > 0)
|
||||
{
|
||||
memcpy(((char*)samples) + (maxupper * buf->conf.sizeofItem), (char*)buf->conf.buffer,copylower * buf->conf.sizeofItem);
|
||||
}
|
||||
|
||||
buf->buffer_tail = (buf->buffer_tail + len) % buf->conf.size;
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#ifndef __RING_BUFFER_H__
|
||||
#define __RING_BUFFER_H__
|
||||
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t size;
|
||||
int32_t sizeofItem;
|
||||
void* buffer; //buffer for filtered PCM data from Recv.
|
||||
} RingBuffer_conf_t;
|
||||
|
||||
typedef struct {
|
||||
volatile uint16_t buffer_tail;
|
||||
volatile uint16_t buffer_head;
|
||||
const RingBuffer_conf_t conf;
|
||||
} RingBuffer_data_t;
|
||||
|
||||
#define RingBuffer_Declare(name, type) typedef type name##_item_t; extern RingBuffer_data_t name;
|
||||
|
||||
#define RingBuffer_Define(name, buf_size) name##_item_t name##_buffer[(buf_size)]; RingBuffer_data_t name = { .buffer_tail = 0, .buffer_head = 0, .conf = { .size = (buf_size), .sizeofItem = sizeof(name##_item_t) , .buffer = name##_buffer } };
|
||||
#define RingBuffer_DefineExtMem(name, buf_size, buf_addr) RingBuffer_data_t name = { .buffer_tail = 0, .buffer_head = 0, .conf = { .size = (buf_size), .sizeofItem = sizeof(name##_item_t) , .buffer = (buf_addr) } };
|
||||
|
||||
void RingBuffer_ClearGetTail(RingBuffer_data_t* buf);
|
||||
void RingBuffer_ClearPutHead(RingBuffer_data_t* buf);
|
||||
int32_t RingBuffer_GetRoom(RingBuffer_data_t* buf);
|
||||
int32_t RingBuffer_GetData(RingBuffer_data_t* buf);
|
||||
bool RingBuffer_PutSamples(RingBuffer_data_t* buf, void* samples, int32_t len);
|
||||
bool RingBuffer_GetSamples(RingBuffer_data_t* buf, void* samples, int32_t len);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
+931
@@ -0,0 +1,931 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include <assert.h>
|
||||
#include "uhsdr_board.h"
|
||||
#include "profiling.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "softdds.h"
|
||||
#include "rtty.h"
|
||||
#include "ui_driver.h" // only necessary because of UiDriver_TextMsgPutChar
|
||||
#include "radio_management.h" // only necessary because of RadioManagement_Request_TxOff
|
||||
#include "uhsdr_digi_buffer.h"
|
||||
|
||||
// character tables borrowed from fldigi / rtty.cxx
|
||||
static const char RTTYLetters[] = {
|
||||
'\0', 'E', '\n', 'A', ' ', 'S', 'I', 'U',
|
||||
'\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K',
|
||||
'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q',
|
||||
'O', 'B', 'G', ' ', 'M', 'X', 'V', ' '
|
||||
};
|
||||
|
||||
static const char RTTYSymbols[32] = {
|
||||
'\0', '3', '\n', '-', ' ', '\a', '8', '7',
|
||||
'\r', '$', '4', '\'', ',', '!', ':', '(',
|
||||
'5', '"', ')', '2', '#', '6', '0', '1',
|
||||
'9', '?', '&', ' ', '.', '/', ';', ' '
|
||||
};
|
||||
|
||||
|
||||
|
||||
// bits 0-4 -> baudot, bit 5 1 == LETTER, 0 == NUMBER/FIGURE
|
||||
const uint8_t Ascii2Baudot[128] =
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0b001011, // BEL N
|
||||
0,
|
||||
0,
|
||||
0b000010, // \n NL
|
||||
0,
|
||||
0,
|
||||
0b001000, // \r NL
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0b100100, // NL
|
||||
0b001101, // ! N
|
||||
0b010001, // " N
|
||||
0b010100, // # N
|
||||
0b001001, // $ N
|
||||
0, // %
|
||||
0b011010, // & N
|
||||
0b000101, // ' N
|
||||
0b001111, // ( N
|
||||
0b010010, // ) N
|
||||
0, // *
|
||||
0, // +
|
||||
0b001100, // , N
|
||||
0b000011, // - N
|
||||
0b011100, // . N
|
||||
0b011101, // / N
|
||||
0b010110, // 0 N
|
||||
0b010111, // 1 N
|
||||
0b010011, // 2 N
|
||||
0b000001, // 3 N
|
||||
0b001010, // 4 N
|
||||
0b010000, // 5 N
|
||||
0b010101, // 6 N
|
||||
0b000111, // 7 N
|
||||
0b000110, // 8 N
|
||||
0b011000, // 9 N
|
||||
0b001110, // : N
|
||||
0b011110, // ; N
|
||||
0, // <
|
||||
0, // =
|
||||
0, // >
|
||||
0b011001, // ? N
|
||||
0, // @
|
||||
0b100011, // A L
|
||||
0b111001, // B L
|
||||
0b101110, // C L
|
||||
0b101001, // D L
|
||||
0b100001, // E L
|
||||
0b101101, // F L
|
||||
0b111010, // G L
|
||||
0b110100, // H L
|
||||
0b100110, // I L
|
||||
0b101011, // J L
|
||||
0b101111, // K L
|
||||
0b110010, // L L
|
||||
0b111100, // M L
|
||||
0b101100, // N L
|
||||
0b111000, // O L
|
||||
0b110110, // P L
|
||||
0b110111, // Q L
|
||||
0b101010, // R L
|
||||
0b100101, // S L
|
||||
0b110000, // T L
|
||||
0b100111, // U L
|
||||
0b111110, // V L
|
||||
0b110011, // W L
|
||||
0b111101, // X L
|
||||
0b110101, // Y L
|
||||
0b110001, // Z L
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0b100011, // A L
|
||||
0b111001, // B L
|
||||
0b101110, // C L
|
||||
0b101001, // D L
|
||||
0b100001, // E L
|
||||
0b101101, // F L
|
||||
0b111010, // G L
|
||||
0b110100, // H L
|
||||
0b100110, // I L
|
||||
0b101011, // J L
|
||||
0b101111, // K L
|
||||
0b110010, // L L
|
||||
0b111100, // M L
|
||||
0b101100, // N L
|
||||
0b111000, // O L
|
||||
0b110110, // P L
|
||||
0b110111, // Q L
|
||||
0b101010, // R L
|
||||
0b100101, // S L
|
||||
0b110000, // T L
|
||||
0b100111, // U L
|
||||
0b111110, // V L
|
||||
0b110011, // W L
|
||||
0b111101, // X L
|
||||
0b110101, // Y L
|
||||
0b110001, // Z L
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
#define RTTY_SYMBOL_CODE (0b11011)
|
||||
#define RTTY_LETTER_CODE (0b11111)
|
||||
|
||||
// RTTY Experiment based on code from the DSP Tutorial at http://dp.nonoo.hu/projects/ham-dsp-tutorial/18-rtty-decoder-using-iir-filters/
|
||||
// Used with permission from Norbert Varga, HA2NON under GPLv3 license
|
||||
|
||||
/*
|
||||
* Experimental Code
|
||||
*/
|
||||
#ifdef USE_RTTY_PROCESSOR
|
||||
|
||||
const rtty_speed_item_t rtty_speeds[RTTY_SPEED_NUM] =
|
||||
{
|
||||
{ .id =RTTY_SPEED_45, .value = 45.45, .label = "45" },
|
||||
{ .id =RTTY_SPEED_50, .value = 50, .label = "50" },
|
||||
};
|
||||
|
||||
const rtty_shift_item_t rtty_shifts[RTTY_SHIFT_NUM] =
|
||||
{
|
||||
{ RTTY_SHIFT_85, 85, " 85" },
|
||||
{ RTTY_SHIFT_170, 170, "170" },
|
||||
{ RTTY_SHIFT_200, 200, "200" },
|
||||
{ RTTY_SHIFT_425, 425, "425" },
|
||||
{ RTTY_SHIFT_450, 450, "450" },
|
||||
{ RTTY_SHIFT_850, 850, "850" },
|
||||
};
|
||||
|
||||
rtty_ctrl_t rtty_ctrl_config =
|
||||
{
|
||||
.shift_idx = RTTY_SHIFT_170,
|
||||
.speed_idx = RTTY_SPEED_45,
|
||||
.stopbits_idx = RTTY_STOP_1_5
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t gain;
|
||||
float32_t coeffs[4];
|
||||
uint16_t freq; // center freq
|
||||
} rtty_bpf_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t gain;
|
||||
float32_t coeffs[2];
|
||||
} rtty_lpf_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t xv[5];
|
||||
float32_t yv[5];
|
||||
} rtty_bpf_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t xv[3];
|
||||
float32_t yv[3];
|
||||
} rtty_lpf_data_t;
|
||||
|
||||
|
||||
|
||||
static float32_t RttyDecoder_bandPassFreq(float32_t sampleIn, const rtty_bpf_config_t* coeffs, rtty_bpf_data_t* data) {
|
||||
data->xv[0] = data->xv[1]; data->xv[1] = data->xv[2]; data->xv[2] = data->xv[3]; data->xv[3] = data->xv[4];
|
||||
data->xv[4] = sampleIn / coeffs->gain; // gain at centre
|
||||
data->yv[0] = data->yv[1]; data->yv[1] = data->yv[2]; data->yv[2] = data->yv[3]; data->yv[3] = data->yv[4];
|
||||
data->yv[4] = (data->xv[0] + data->xv[4]) - 2 * data->xv[2]
|
||||
+ (coeffs->coeffs[0] * data->yv[0]) + (coeffs->coeffs[1] * data->yv[1])
|
||||
+ (coeffs->coeffs[2] * data->yv[2]) + (coeffs->coeffs[3] * data->yv[3]);
|
||||
return data->yv[4];
|
||||
}
|
||||
|
||||
static float32_t RttyDecoder_lowPass(float32_t sampleIn, const rtty_lpf_config_t* coeffs, rtty_lpf_data_t* data) {
|
||||
data->xv[0] = data->xv[1]; data->xv[1] = data->xv[2];
|
||||
data->xv[2] = sampleIn / coeffs->gain; // gain at DC
|
||||
data->yv[0] = data->yv[1]; data->yv[1] = data->yv[2];
|
||||
data->yv[2] = (data->xv[0] + data->xv[2]) + 2 * data->xv[1]
|
||||
+ (coeffs->coeffs[0] * data->yv[0]) + (coeffs->coeffs[1] * data->yv[1]);
|
||||
return data->yv[2];
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
RTTY_RUN_STATE_WAIT_START = 0,
|
||||
RTTY_RUN_STATE_BIT,
|
||||
} rtty_run_state_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
RTTY_MODE_LETTERS = 0,
|
||||
RTTY_MODE_SYMBOLS
|
||||
} rtty_charSetMode_t;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
rtty_bpf_data_t bpfSpaceData;
|
||||
rtty_bpf_data_t bpfMarkData;
|
||||
rtty_lpf_data_t lpfData;
|
||||
rtty_bpf_config_t *bpfSpaceConfig;
|
||||
rtty_bpf_config_t *bpfMarkConfig;
|
||||
rtty_lpf_config_t *lpfConfig;
|
||||
|
||||
uint16_t oneBitSampleCount;
|
||||
int32_t DPLLOldVal;
|
||||
int32_t DPLLBitPhase;
|
||||
|
||||
uint8_t byteResult;
|
||||
uint16_t byteResultp;
|
||||
|
||||
rtty_charSetMode_t charSetMode;
|
||||
|
||||
rtty_run_state_t state;
|
||||
|
||||
soft_dds_t tx_dds[2];
|
||||
|
||||
const rtty_mode_config_t* config_p;
|
||||
|
||||
} rtty_decoder_data_t;
|
||||
|
||||
rtty_decoder_data_t rttyDecoderData;
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0 // 48Khz filters, not needed
|
||||
// this is for 48ksps sample rate
|
||||
// for filter designing, see http://www-users.cs.york.ac.uk/~fisher/mkfilter/
|
||||
// order 2 Butterworth, freqs: 865-965 Hz
|
||||
rtty_bpf_config_t rtty_bp_48khz_915 =
|
||||
{
|
||||
.gain = 2.356080041e+04, // gain at centre
|
||||
.coeffs = {-0.9816582826, 3.9166274264, -5.8882201843, 3.9530488323 },
|
||||
.freq = 915
|
||||
};
|
||||
|
||||
// order 2 Butterworth, freqs: 1035-1135 Hz
|
||||
rtty_bpf_config_t rtty_bp_48khz_1085 =
|
||||
{
|
||||
.gain = 2.356080365e+04,
|
||||
.coeffs = {-0.9816582826, 3.9051693660, -5.8653953990, 3.9414842213 },
|
||||
.freq = 1085
|
||||
};
|
||||
#endif
|
||||
|
||||
// order 2 Butterworth, freq: 50 Hz
|
||||
rtty_lpf_config_t rtty_lp_48khz_50 =
|
||||
{
|
||||
.gain = 9.381008646e+04,
|
||||
.coeffs = {-0.9907866988, 1.9907440595 }
|
||||
};
|
||||
|
||||
// this is for 12ksps sample rate
|
||||
// for filter designing, see http://www-users.cs.york.ac.uk/~fisher/mkfilter/
|
||||
// order 2 Butterworth, freqs: 865-965 Hz, centre: 915 Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_915 =
|
||||
{
|
||||
.gain = 1.513364755e+03,
|
||||
.coeffs = { -0.9286270861, 3.3584472566, -4.9635817596, 3.4851652468 },
|
||||
.freq = 915
|
||||
};
|
||||
|
||||
// order 2 Butterworth, freqs: 1315-1415 Hz, centre 1365Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1365 =
|
||||
{
|
||||
.gain = 1.513365019e+03,
|
||||
.coeffs = { -0.9286270861, 2.8583904591, -4.1263569881, 2.9662407442 },
|
||||
.freq = 1365
|
||||
};
|
||||
// order 2 Butterworth, freqs: 1035-1135 Hz, centre: 1085Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1085 =
|
||||
{
|
||||
.gain = 1.513364927e+03,
|
||||
.coeffs = { -0.9286270861, 3.1900687350, -4.6666321298, 3.3104336142 },
|
||||
.freq = 1085
|
||||
};
|
||||
// order 2 Butterworth, freqs: 1065-1165 Hz, centre: 1115Hz
|
||||
// for 200Hz shift
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1115 =
|
||||
{
|
||||
.gain = 1.513364944e+03,
|
||||
.coeffs = { -0.9286270861, 3.1576917276, -4.6112830458, 3.2768349860 },
|
||||
.freq = 1115
|
||||
};
|
||||
|
||||
// for 85Hz shift --> 915 + 85Hz = space = 1000Hz
|
||||
// 3dB bandwidth 50Hz
|
||||
// order 2 Butterworth, freqs: 975-1025 Hz, centre: 1000Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1000 =
|
||||
{
|
||||
.gain = 5.944465260e+03,
|
||||
.coeffs = { -0.9636529842, 3.3693752166, -4.9084595657, 3.4323354886 },
|
||||
.freq = 1000
|
||||
};
|
||||
|
||||
// for 425Hz shift --> 915 + 425Hz = space = 1340Hz
|
||||
// 3dB bandwidth 100Hz
|
||||
// order 2 Butterworth, freqs: 1290 - 1390 Hz, centre: 1340Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1340 =
|
||||
{
|
||||
.gain = 1.513365018e+03,
|
||||
.coeffs = { -0.9286270862, 2.8906128091, -4.1762457780, 2.9996788796 },
|
||||
.freq = 1340
|
||||
};
|
||||
|
||||
// for 850Hz shift --> 915 + 850Hz = space = 1765Hz
|
||||
// 3dB bandwidth 100Hz
|
||||
// order 2 Butterworth, freqs: 1715 - 1815 Hz, centre: 1765Hz
|
||||
static rtty_bpf_config_t rtty_bp_12khz_1765 =
|
||||
{
|
||||
.gain = 1.513365057e+03,
|
||||
.coeffs = { -0.9286270862, 2.1190223173, -3.1352567157, 2.1989754113 },
|
||||
.freq = 1765
|
||||
};
|
||||
|
||||
|
||||
static rtty_lpf_config_t rtty_lp_12khz_50 =
|
||||
{
|
||||
.gain = 5.944465310e+03,
|
||||
.coeffs = { -0.9636529842, 1.9629800894 }
|
||||
};
|
||||
|
||||
static rtty_mode_config_t rtty_mode_current_config;
|
||||
|
||||
|
||||
void Rtty_Modem_Init(uint32_t output_sample_rate)
|
||||
{
|
||||
|
||||
// TODO: pass config as parameter and make it changeable via menu
|
||||
rtty_mode_current_config.samplerate = 12000;
|
||||
rtty_mode_current_config.shift = rtty_shifts[rtty_ctrl_config.shift_idx].value;
|
||||
rtty_mode_current_config.speed = rtty_speeds[rtty_ctrl_config.speed_idx].value;
|
||||
rtty_mode_current_config.stopbits = rtty_ctrl_config.stopbits_idx;
|
||||
|
||||
rttyDecoderData.config_p = &rtty_mode_current_config;
|
||||
|
||||
// common config to all supported modes
|
||||
rttyDecoderData.oneBitSampleCount = (uint16_t)roundf(rttyDecoderData.config_p->samplerate/rttyDecoderData.config_p->speed);
|
||||
rttyDecoderData.charSetMode = RTTY_MODE_LETTERS;
|
||||
rttyDecoderData.state = RTTY_RUN_STATE_WAIT_START;
|
||||
|
||||
rttyDecoderData.bpfMarkConfig = &rtty_bp_12khz_915; // this is mark, or '1'
|
||||
rttyDecoderData.lpfConfig = &rtty_lp_12khz_50;
|
||||
|
||||
// now we handled the specifics
|
||||
switch (rttyDecoderData.config_p->shift)
|
||||
{
|
||||
case 85:
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1000;
|
||||
break;
|
||||
case 200:
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1115;
|
||||
break;
|
||||
case 425:
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1340;
|
||||
break;
|
||||
case 450:
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1365; // this is space or '0'
|
||||
break;
|
||||
case 850:
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1765; // this is space or '0'
|
||||
break;
|
||||
case 170:
|
||||
default:
|
||||
// all unsupported shifts are mapped to 170
|
||||
rttyDecoderData.bpfSpaceConfig = &rtty_bp_12khz_1085; // this is space or '0'
|
||||
}
|
||||
|
||||
// configure DDS for transmission
|
||||
softdds_setFreqDDS(&rttyDecoderData.tx_dds[0], rttyDecoderData.bpfSpaceConfig->freq, output_sample_rate, 0);
|
||||
softdds_setFreqDDS(&rttyDecoderData.tx_dds[1], rttyDecoderData.bpfMarkConfig->freq, output_sample_rate, 0);
|
||||
|
||||
}
|
||||
|
||||
float32_t decayavg(float32_t average, float32_t input, int weight)
|
||||
{ // adapted from https://github.com/ukhas/dl-fldigi/blob/master/src/include/misc.h
|
||||
float32_t retval;
|
||||
if (weight <= 1)
|
||||
{
|
||||
retval = input;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = ( ( input - average ) / (float32_t)weight ) + average ;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
// this function returns the bit value of the current sample
|
||||
static int RttyDecoder_demodulator(float32_t sample)
|
||||
{
|
||||
|
||||
float32_t space_mag = RttyDecoder_bandPassFreq(sample, rttyDecoderData.bpfSpaceConfig, &rttyDecoderData.bpfSpaceData);
|
||||
float32_t mark_mag = RttyDecoder_bandPassFreq(sample, rttyDecoderData.bpfMarkConfig, &rttyDecoderData.bpfMarkData);
|
||||
|
||||
float32_t v1 = 0.0;
|
||||
// calculating the RMS of the two lines (squaring them)
|
||||
space_mag *= space_mag;
|
||||
mark_mag *= mark_mag;
|
||||
|
||||
if(rtty_ctrl_config.atc_disable == false)
|
||||
{ // RTTY decoding with ATC = automatic threshold correction
|
||||
// FIXME: space & mark seem to be swapped in the following code
|
||||
// dirty fix
|
||||
float32_t helper = space_mag;
|
||||
space_mag = mark_mag;
|
||||
mark_mag = helper;
|
||||
static float32_t mark_env = 0.0;
|
||||
static float32_t space_env = 0.0;
|
||||
static float32_t mark_noise = 0.0;
|
||||
static float32_t space_noise = 0.0;
|
||||
// experiment to implement an ATC (Automatic threshold correction), DD4WH, 2017_08_24
|
||||
// everything taken from FlDigi, licensed by GNU GPLv2 or later
|
||||
// https://github.com/ukhas/dl-fldigi/blob/master/src/cw_rtty/rtty.cxx
|
||||
// calculate envelope of the mark and space signals
|
||||
// uses fast attack and slow decay
|
||||
mark_env = decayavg (mark_env, mark_mag,
|
||||
(mark_mag > mark_env) ? rttyDecoderData.oneBitSampleCount / 4 : rttyDecoderData.oneBitSampleCount * 16);
|
||||
space_env = decayavg (space_env, space_mag,
|
||||
(space_mag > space_env) ? rttyDecoderData.oneBitSampleCount / 4 : rttyDecoderData.oneBitSampleCount * 16);
|
||||
// calculate the noise on the mark and space signals
|
||||
mark_noise = decayavg (mark_noise, mark_mag,
|
||||
(mark_mag < mark_noise) ? rttyDecoderData.oneBitSampleCount / 4 : rttyDecoderData.oneBitSampleCount * 48);
|
||||
space_noise = decayavg (space_noise, space_mag,
|
||||
(space_mag < space_noise) ? rttyDecoderData.oneBitSampleCount / 4 : rttyDecoderData.oneBitSampleCount * 48);
|
||||
// the noise floor is the lower signal of space and mark noise
|
||||
float32_t noise_floor = (space_noise < mark_noise) ? space_noise : mark_noise;
|
||||
|
||||
// Linear ATC, section 3 of www.w7ay.net/site/Technical/ATC
|
||||
// v1 = space_mag - mark_mag - 0.5 * (space_env - mark_env);
|
||||
|
||||
// Compensating for the noise floor by using clipping
|
||||
float32_t mclipped = 0.0, sclipped = 0.0;
|
||||
mclipped = mark_mag > mark_env ? mark_env : mark_mag;
|
||||
sclipped = space_mag > space_env ? space_env : space_mag;
|
||||
if (mclipped < noise_floor)
|
||||
{
|
||||
mclipped = noise_floor;
|
||||
}
|
||||
if (sclipped < noise_floor)
|
||||
{
|
||||
sclipped = noise_floor;
|
||||
}
|
||||
|
||||
// we could add options for mark-only or space-only decoding
|
||||
// however, the current implementation with ATC already works quite well with mark-only/space-only
|
||||
/* switch (progdefaults.rtty_cwi) {
|
||||
case 1 : // mark only decode
|
||||
space_env = sclipped = noise_floor;
|
||||
break;
|
||||
case 2: // space only decode
|
||||
mark_env = mclipped = noise_floor;
|
||||
default : ;
|
||||
}
|
||||
*/
|
||||
|
||||
// Optimal ATC (Section 6 of of www.w7ay.net/site/Technical/ATC)
|
||||
v1 = (mclipped - noise_floor) * (mark_env - noise_floor) -
|
||||
(sclipped - noise_floor) * (space_env - noise_floor) -
|
||||
0.25 * ((mark_env - noise_floor) * (mark_env - noise_floor) -
|
||||
(space_env - noise_floor) * (space_env - noise_floor));
|
||||
|
||||
v1 = RttyDecoder_lowPass(v1, rttyDecoderData.lpfConfig, &rttyDecoderData.lpfData);
|
||||
|
||||
}
|
||||
else
|
||||
{ // RTTY without ATC, which works very well too!
|
||||
// inverting line 1
|
||||
mark_mag *= -1;
|
||||
|
||||
// summing the two lines
|
||||
v1 = mark_mag + space_mag;
|
||||
|
||||
// lowpass filtering the summed line
|
||||
v1 = RttyDecoder_lowPass(v1, rttyDecoderData.lpfConfig, &rttyDecoderData.lpfData);
|
||||
}
|
||||
|
||||
return (v1 > 0)?0:1;
|
||||
}
|
||||
|
||||
// this function returns true once at the half of a bit with the bit's value
|
||||
static bool RttyDecoder_getBitDPLL(float32_t sample, bool* val_p) {
|
||||
static bool phaseChanged = false;
|
||||
bool retval = false;
|
||||
|
||||
|
||||
if (rttyDecoderData.DPLLBitPhase < rttyDecoderData.oneBitSampleCount)
|
||||
{
|
||||
*val_p = RttyDecoder_demodulator(sample);
|
||||
|
||||
if (!phaseChanged && *val_p != rttyDecoderData.DPLLOldVal) {
|
||||
if (rttyDecoderData.DPLLBitPhase < rttyDecoderData.oneBitSampleCount/2)
|
||||
{
|
||||
// rttyDecoderData.DPLLBitPhase += rttyDecoderData.oneBitSampleCount/8; // early
|
||||
rttyDecoderData.DPLLBitPhase += rttyDecoderData.oneBitSampleCount/32; // early
|
||||
}
|
||||
else
|
||||
{
|
||||
//rttyDecoderData.DPLLBitPhase -= rttyDecoderData.oneBitSampleCount/8; // late
|
||||
rttyDecoderData.DPLLBitPhase -= rttyDecoderData.oneBitSampleCount/32; // late
|
||||
}
|
||||
phaseChanged = true;
|
||||
}
|
||||
rttyDecoderData.DPLLOldVal = *val_p;
|
||||
rttyDecoderData.DPLLBitPhase++;
|
||||
}
|
||||
|
||||
if (rttyDecoderData.DPLLBitPhase >= rttyDecoderData.oneBitSampleCount)
|
||||
{
|
||||
rttyDecoderData.DPLLBitPhase -= rttyDecoderData.oneBitSampleCount;
|
||||
retval = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// this function returns only true when the start bit is successfully received
|
||||
static bool RttyDecoder_waitForStartBit(float32_t sample) {
|
||||
bool retval = false;
|
||||
int bitResult;
|
||||
static int16_t wait_for_start_state = 0;
|
||||
static int16_t wait_for_half = 0;
|
||||
|
||||
bitResult = RttyDecoder_demodulator(sample);
|
||||
switch (wait_for_start_state)
|
||||
{
|
||||
case 0:
|
||||
// waiting for a falling edge
|
||||
if (bitResult != 0)
|
||||
{
|
||||
wait_for_start_state++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (bitResult != 1)
|
||||
{
|
||||
wait_for_start_state++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
wait_for_half = rttyDecoderData.oneBitSampleCount/2;
|
||||
wait_for_start_state ++;
|
||||
/* fall through */ // this is for the compiler, the following comment is for Eclipse
|
||||
/* no break */
|
||||
case 3:
|
||||
wait_for_half--;
|
||||
if (wait_for_half == 0)
|
||||
{
|
||||
retval = (bitResult == 0);
|
||||
wait_for_start_state = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//static const char RTTYLetters[] = "<E\nA SIU\nDRJNFCKTZLWHYPQOBG^MXV^";
|
||||
//static const char RTTYSymbols[] = "<3\n- ,87\n$4#,.:(5+)2.60197.^./=^";
|
||||
|
||||
// character tables borrowed from fldigi / rtty.cxx
|
||||
|
||||
void Rtty_Demodulator_ProcessSample(float32_t sample)
|
||||
{
|
||||
|
||||
switch(rttyDecoderData.state)
|
||||
{
|
||||
case RTTY_RUN_STATE_WAIT_START: // not synchronized, need to wait for start bit
|
||||
if (RttyDecoder_waitForStartBit(sample))
|
||||
{
|
||||
rttyDecoderData.state = RTTY_RUN_STATE_BIT;
|
||||
rttyDecoderData.byteResultp = 1;
|
||||
rttyDecoderData.byteResult = 0;
|
||||
}
|
||||
break;
|
||||
case RTTY_RUN_STATE_BIT:
|
||||
// reading 7 more bits
|
||||
if (rttyDecoderData.byteResultp < 8)
|
||||
{
|
||||
bool bitResult = false;
|
||||
if (RttyDecoder_getBitDPLL(sample, &bitResult))
|
||||
{
|
||||
switch (rttyDecoderData.byteResultp)
|
||||
{
|
||||
case 6: // stop bit 1
|
||||
|
||||
case 7: // stop bit 2
|
||||
if (bitResult == false)
|
||||
{
|
||||
// not in sync
|
||||
rttyDecoderData.state = RTTY_RUN_STATE_WAIT_START;
|
||||
}
|
||||
if (rttyDecoderData.config_p->stopbits != RTTY_STOP_2 && rttyDecoderData.byteResultp == 6)
|
||||
{
|
||||
// we pretend to be at the 7th bit after receiving the first stop bit if we have less than 2 stop bits
|
||||
// this omits check for 1.5 bit condition but we should be more or less safe here, may cause
|
||||
// a little more unaligned receive but without that shortcut we simply cannot receive these configurations
|
||||
// so it is worth it
|
||||
rttyDecoderData.byteResultp = 7;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// System.out.print(bitResult);
|
||||
rttyDecoderData.byteResult |= (bitResult?1:0) << (rttyDecoderData.byteResultp-1);
|
||||
}
|
||||
rttyDecoderData.byteResultp++;
|
||||
}
|
||||
}
|
||||
if (rttyDecoderData.byteResultp == 8 && rttyDecoderData.state == RTTY_RUN_STATE_BIT)
|
||||
{
|
||||
char charResult;
|
||||
|
||||
switch (rttyDecoderData.byteResult) {
|
||||
case RTTY_LETTER_CODE:
|
||||
rttyDecoderData.charSetMode = RTTY_MODE_LETTERS;
|
||||
// System.out.println(" ^L^");
|
||||
break;
|
||||
case RTTY_SYMBOL_CODE:
|
||||
rttyDecoderData.charSetMode = RTTY_MODE_SYMBOLS;
|
||||
// System.out.println(" ^F^");
|
||||
break;
|
||||
default:
|
||||
switch (rttyDecoderData.charSetMode)
|
||||
{
|
||||
case RTTY_MODE_SYMBOLS:
|
||||
charResult = RTTYSymbols[rttyDecoderData.byteResult];
|
||||
break;
|
||||
case RTTY_MODE_LETTERS:
|
||||
default:
|
||||
charResult = RTTYLetters[rttyDecoderData.byteResult];
|
||||
break;
|
||||
}
|
||||
UiDriver_TextMsgPutChar(charResult);
|
||||
break;
|
||||
}
|
||||
rttyDecoderData.state = RTTY_RUN_STATE_WAIT_START;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MSK_IDLE = 0,
|
||||
MSK_WAIT_FOR_NEG,
|
||||
MSK_WAIT_FOR_PLUS,
|
||||
MSK_WAIT_FOR_PLUSGRAD, // wait for the values growing towards max
|
||||
MSK_WAIT_FOR_MAX, // wait for the value after max, needs to be done one the growing part of the curve
|
||||
} msk_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t char_bit_idx;
|
||||
uint16_t char_bits;
|
||||
uint32_t char_bit_samples;
|
||||
uint16_t last_bit;
|
||||
int16_t last_value;
|
||||
uint8_t current_bit;
|
||||
msk_state_t msk_state;
|
||||
rtty_charSetMode_t char_mode;
|
||||
|
||||
} rtty_tx_encoder_state_t;
|
||||
|
||||
rtty_tx_encoder_state_t rtty_tx =
|
||||
{
|
||||
.last_bit = 1,
|
||||
.last_value = INT16_MIN,
|
||||
.char_mode = RTTY_MODE_LETTERS,
|
||||
|
||||
};
|
||||
|
||||
#define USE_RTTY_MSK
|
||||
#define RTTY_CODE_MODE_MASK (0b100000)
|
||||
#define RTTY_CODE_MODE_LETTER (RTTY_CODE_MODE_MASK)
|
||||
#define RTTY_CODE_MODE_SYMBOL (0)
|
||||
|
||||
static void Rtty_BaudotAdd(uint8_t bits)
|
||||
{
|
||||
uint8_t bitCount = rttyDecoderData.config_p->stopbits == RTTY_STOP_1?7:8;
|
||||
|
||||
bits <<= 1; // add stop bit
|
||||
|
||||
if (bitCount == 7)
|
||||
{
|
||||
bits |= 0b01000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// for 1.5 and 2 we use 2 bits for now
|
||||
bits |= 0b11000000;
|
||||
}
|
||||
|
||||
rtty_tx.char_bits |= bits << rtty_tx.char_bit_idx;
|
||||
// we add more bits towards the MSB if we already have bits
|
||||
|
||||
rtty_tx.char_bit_idx += bitCount;
|
||||
// now remember how many bits we added
|
||||
}
|
||||
|
||||
void Rtty_Modulator_Code2Bits(uint8_t baudot_info)
|
||||
{
|
||||
rtty_tx.char_bits = 0;
|
||||
rtty_tx.char_bit_idx = 0;
|
||||
|
||||
if ((baudot_info & RTTY_CODE_MODE_MASK) == RTTY_CODE_MODE_LETTER)
|
||||
{
|
||||
if(rtty_tx.char_mode != RTTY_MODE_LETTERS)
|
||||
{
|
||||
rtty_tx.char_mode = RTTY_MODE_LETTERS;
|
||||
Rtty_BaudotAdd(RTTY_LETTER_CODE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rtty_tx.char_mode != RTTY_MODE_SYMBOLS)
|
||||
{
|
||||
rtty_tx.char_mode = RTTY_MODE_SYMBOLS;
|
||||
Rtty_BaudotAdd(RTTY_SYMBOL_CODE);
|
||||
}
|
||||
}
|
||||
Rtty_BaudotAdd(baudot_info & ~RTTY_CODE_MODE_MASK);
|
||||
}
|
||||
|
||||
// MUST BE CALLED BEFORE WE START RTTY TX, i.e. in RX Mode !!!
|
||||
void Rtty_Modulator_StartTX()
|
||||
{
|
||||
rtty_tx.last_bit = 1;
|
||||
rtty_tx.last_value = INT16_MIN;
|
||||
rtty_tx.char_mode = RTTY_MODE_LETTERS;
|
||||
Rtty_Modulator_Code2Bits(RTTY_LETTER_CODE);
|
||||
}
|
||||
|
||||
const char rtty_test_string[] = " --- UHSDR FIRMWARE RTTY TX TEST DE DB4PLE --- ";
|
||||
|
||||
int16_t Rtty_Modulator_GenSample()
|
||||
{
|
||||
if (rtty_tx.char_bit_samples == 0)
|
||||
{
|
||||
rtty_tx.char_bit_samples = rttyDecoderData.oneBitSampleCount * 4;
|
||||
|
||||
rtty_tx.char_bits >>= 1;
|
||||
if (rtty_tx.char_bit_idx == 0)
|
||||
{
|
||||
// load the character and add the stop bits;
|
||||
bool bitsFilled = false;
|
||||
uint8_t current_ascii;
|
||||
while ( bitsFilled == false && DigiModes_TxBufferRemove( ¤t_ascii, RTTY ) )
|
||||
{
|
||||
if (current_ascii == 0x04 ) //EOT
|
||||
{
|
||||
RadioManagement_Request_TxOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t current_baudot = Ascii2Baudot[current_ascii & 0x7f];
|
||||
if (current_baudot > 0)
|
||||
{ // we have valid baudot code
|
||||
Rtty_Modulator_Code2Bits(current_baudot);
|
||||
bitsFilled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bitsFilled == false)
|
||||
{
|
||||
// IDLE
|
||||
Rtty_Modulator_Code2Bits(RTTY_LETTER_CODE | RTTY_CODE_MODE_LETTER);
|
||||
// we ensure that we will switch back to letter mode by making the switch symbol a letter
|
||||
#if 0
|
||||
for (uint8_t idx = 0; idx < sizeof(rtty_test_string); idx++)
|
||||
{
|
||||
DigiModes_TxBufferPutChar( rtty_test_string[idx] , CW );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
rtty_tx.char_bit_idx--;
|
||||
|
||||
rtty_tx.current_bit = rtty_tx.char_bits&1;
|
||||
#ifdef USE_RTTY_MSK
|
||||
if (rtty_tx.last_bit != rtty_tx.current_bit)
|
||||
{
|
||||
if (rtty_tx.last_bit == 1)
|
||||
{
|
||||
rtty_tx.msk_state = MSK_WAIT_FOR_NEG;
|
||||
// WAIT_FOR_NEG
|
||||
// WAIT_FOR_ZERO or plus
|
||||
rtty_tx.current_bit = rtty_tx.last_bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtty_tx.msk_state = MSK_WAIT_FOR_PLUSGRAD;
|
||||
rtty_tx.current_bit = rtty_tx.last_bit;
|
||||
rtty_tx.last_value = INT16_MIN;
|
||||
// WAIT_FOR_MAX
|
||||
}
|
||||
}
|
||||
#else
|
||||
rtty_tx.msk_state = MSK_IDLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
rtty_tx.char_bit_samples--;
|
||||
|
||||
int16_t current_value = softdds_nextSample(&rttyDecoderData.tx_dds[rtty_tx.current_bit]);
|
||||
|
||||
switch(rtty_tx.msk_state)
|
||||
{
|
||||
case MSK_WAIT_FOR_NEG:
|
||||
if (current_value < 0)
|
||||
{
|
||||
rtty_tx.msk_state = MSK_WAIT_FOR_PLUS;
|
||||
}
|
||||
break;
|
||||
case MSK_WAIT_FOR_PLUS:
|
||||
if (current_value >= 0)
|
||||
{
|
||||
rtty_tx.msk_state = MSK_IDLE;
|
||||
rtty_tx.current_bit = rtty_tx.char_bits&1;
|
||||
rttyDecoderData.tx_dds[rtty_tx.current_bit].acc = rttyDecoderData.tx_dds[rtty_tx.last_bit].acc;
|
||||
rtty_tx.last_bit = rtty_tx.current_bit;
|
||||
current_value = softdds_nextSample(&rttyDecoderData.tx_dds[rtty_tx.current_bit]);
|
||||
}
|
||||
break;
|
||||
case MSK_WAIT_FOR_PLUSGRAD:
|
||||
if (current_value > rtty_tx.last_value)
|
||||
{
|
||||
rtty_tx.msk_state = MSK_WAIT_FOR_MAX;
|
||||
}
|
||||
break;
|
||||
case MSK_WAIT_FOR_MAX:
|
||||
if (current_value >= rtty_tx.last_value)
|
||||
{
|
||||
rtty_tx.last_value = current_value;
|
||||
}
|
||||
else if (current_value < rtty_tx.last_value && rtty_tx.last_value > 0)
|
||||
{
|
||||
rtty_tx.msk_state = MSK_IDLE;
|
||||
rtty_tx.current_bit = rtty_tx.char_bits&1;
|
||||
rttyDecoderData.tx_dds[rtty_tx.current_bit].acc = rttyDecoderData.tx_dds[rtty_tx.last_bit].acc;
|
||||
rtty_tx.last_bit = rtty_tx.current_bit;
|
||||
current_value = softdds_nextSample(&rttyDecoderData.tx_dds[rtty_tx.current_bit]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rtty_tx.last_value = current_value;
|
||||
|
||||
return current_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR FIRMWARE **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** Licence: GNU GPLv3, see LICENSE.md **
|
||||
************************************************************************************/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __RTTY_H
|
||||
#define __RTTY_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
typedef enum {
|
||||
RTTY_STOP_1 = 0,
|
||||
RTTY_STOP_1_5,
|
||||
RTTY_STOP_2
|
||||
} rtty_stop_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float32_t speed;
|
||||
rtty_stop_t stopbits;
|
||||
uint16_t shift;
|
||||
float32_t samplerate;
|
||||
} rtty_mode_config_t;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
RTTY_SPEED_45,
|
||||
RTTY_SPEED_50,
|
||||
RTTY_SPEED_NUM
|
||||
} rtty_speed_t;
|
||||
|
||||
typedef enum {
|
||||
RTTY_SHIFT_85,
|
||||
RTTY_SHIFT_170,
|
||||
RTTY_SHIFT_200,
|
||||
RTTY_SHIFT_425,
|
||||
RTTY_SHIFT_450,
|
||||
RTTY_SHIFT_850,
|
||||
RTTY_SHIFT_NUM
|
||||
} rtty_shift_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rtty_speed_t id;
|
||||
float32_t value;
|
||||
char* label;
|
||||
} rtty_speed_item_t;
|
||||
|
||||
// TODO: Probably we should define just a few for the various value types and let
|
||||
// the id be an uint32_t
|
||||
typedef struct
|
||||
{
|
||||
rtty_shift_t id;
|
||||
uint32_t value;
|
||||
char* label;
|
||||
} rtty_shift_item_t;
|
||||
|
||||
|
||||
extern const rtty_speed_item_t rtty_speeds[RTTY_SPEED_NUM];
|
||||
extern const rtty_shift_item_t rtty_shifts[RTTY_SHIFT_NUM];
|
||||
extern float32_t decayavg(float32_t average, float32_t input, int weight);
|
||||
|
||||
// TODO: maybe this should be placed in the ui or radio management part
|
||||
typedef struct
|
||||
{
|
||||
rtty_shift_t shift_idx;
|
||||
rtty_speed_t speed_idx;
|
||||
rtty_stop_t stopbits_idx;
|
||||
bool atc_disable; // should the automatic level control be turned off?
|
||||
} rtty_ctrl_t;
|
||||
|
||||
extern rtty_ctrl_t rtty_ctrl_config;
|
||||
void Rtty_Modem_Init(uint32_t output_sample_rate);
|
||||
void Rtty_Demodulator_ProcessSample(float32_t sample);
|
||||
int16_t Rtty_Modulator_GenSample(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
#include "dds_table.h"
|
||||
|
||||
// this table represents 2*PI, i.e. a full sine wave
|
||||
const int16_t DDS_TABLE[DDS_TBL_SIZE] =
|
||||
{
|
||||
|
||||
// 1024 points
|
||||
0,
|
||||
201, 402, 603, 804, 1005, 1206, 1406, 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
|
||||
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
|
||||
6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
|
||||
9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
|
||||
12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
|
||||
15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
|
||||
18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
|
||||
20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
|
||||
23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
|
||||
25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
|
||||
27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
|
||||
28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
|
||||
30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297,
|
||||
31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
|
||||
32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
|
||||
32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
|
||||
32766, 32766, 32764, 32761, 32757, 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
|
||||
32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
|
||||
32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
|
||||
31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
|
||||
30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
|
||||
28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
|
||||
27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
|
||||
25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
|
||||
23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
|
||||
20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
|
||||
18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
|
||||
15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
|
||||
12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
|
||||
9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
|
||||
6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
|
||||
3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, 1607, 1406, 1206, 1005, 804, 603, 402, 201,
|
||||
0,
|
||||
-201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
|
||||
-3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
|
||||
-6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
|
||||
-9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
|
||||
-12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
|
||||
-15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
|
||||
-18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
|
||||
-20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
|
||||
-23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
|
||||
-25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
|
||||
-27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
|
||||
-28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
|
||||
-30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
|
||||
-31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
|
||||
-32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
|
||||
-32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
|
||||
-32766, -32766, -32764, -32761, -32757, -32751, -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
|
||||
-32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
|
||||
-32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
|
||||
-31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
|
||||
-30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
|
||||
-28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
|
||||
-27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
|
||||
-25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
|
||||
-23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
|
||||
-20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
|
||||
-18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
|
||||
-15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
|
||||
-12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
|
||||
-9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
|
||||
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
|
||||
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607, -1406, -1206, -1005, -804, -603, -402, -201
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __DDS_TABLE_H
|
||||
#define __DDS_TABLE_H
|
||||
|
||||
|
||||
#define DDS_TBL_BITS 10
|
||||
#define DDS_TBL_SIZE (1 << DDS_TBL_BITS) // 10 = 1024
|
||||
|
||||
extern const int16_t DDS_TABLE[DDS_TBL_SIZE];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,157 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
// Credits - SDR cube!!!
|
||||
|
||||
// Common
|
||||
#include "uhsdr_board.h"
|
||||
#include "dds_table.h"
|
||||
#include "softdds.h"
|
||||
|
||||
|
||||
// Two Tone Dds
|
||||
soft_dds_t dbldds[2];
|
||||
|
||||
uint32_t softdds_stepForSampleRate(float32_t freq, uint32_t samp_rate)
|
||||
{
|
||||
uint64_t freq64_shifted = freq * DDS_TBL_SIZE;
|
||||
freq64_shifted <<= SOFTDDS_ACC_SHIFT;
|
||||
uint64_t step = freq64_shifted / samp_rate;
|
||||
return step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize softdds for given frequency and sample rate
|
||||
*/
|
||||
void softdds_setFreqDDS(soft_dds_t* softdds_p, float32_t freq, uint32_t samp_rate,uint8_t smooth)
|
||||
{
|
||||
// Reset accumulator, if need smooth tone
|
||||
// transition, do not reset it (e.g. wspr)
|
||||
if(smooth == false)
|
||||
{
|
||||
softdds_p->acc = 0;
|
||||
}
|
||||
// Calculate new step
|
||||
softdds_p->step = softdds_stepForSampleRate(freq,samp_rate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize softdds for given frequency and sample rate
|
||||
*/
|
||||
|
||||
void softdds_configRunIQ(float freq[2],uint32_t samp_rate,uint8_t smooth)
|
||||
{
|
||||
softdds_setFreqDDS(&dbldds[0],freq[0],samp_rate,smooth);
|
||||
softdds_setFreqDDS(&dbldds[1],freq[1],samp_rate,smooth);
|
||||
}
|
||||
|
||||
void softdds_genIQSingleTone(soft_dds_t* dds, float32_t *i_buff,float32_t *q_buff,uint16_t size)
|
||||
{
|
||||
for(uint16_t i = 0; i < size; i++)
|
||||
{
|
||||
// Calculate next sample
|
||||
uint32_t k = softdds_nextSampleIndex(dds);
|
||||
|
||||
// Load I value (sin)
|
||||
*i_buff = DDS_TABLE[k];
|
||||
|
||||
// -90 degrees shift (cos)
|
||||
// Load Q value
|
||||
*q_buff = DDS_TABLE[softdds_phase_shift90(k)];
|
||||
|
||||
// Next ptr
|
||||
i_buff++;
|
||||
q_buff++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates the addition of two sinus frequencies as IQ data stream
|
||||
* min/max value is +/-2^15-1
|
||||
* Frequencies need to be configured using softdds_setfreq_dbl
|
||||
*/
|
||||
void softdds_genIQTwoTone(soft_dds_t* ddsA, soft_dds_t* ddsB, float *i_buff,float *q_buff,ushort size)
|
||||
{
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
uint32_t k[2];
|
||||
// Calculate next sample
|
||||
k[0] = softdds_nextSampleIndex(ddsA);
|
||||
k[1] = softdds_nextSampleIndex(ddsB);
|
||||
|
||||
// Load I value 0.5*(sin(a)+sin(b))
|
||||
*i_buff = ((int32_t)DDS_TABLE[k[0]] + (int32_t)DDS_TABLE[k[1]])/2;
|
||||
|
||||
*q_buff = ((int32_t)DDS_TABLE[softdds_phase_shift90(k[0])] + (int32_t)DDS_TABLE[softdds_phase_shift90(k[1])])/2;
|
||||
|
||||
// Next ptr
|
||||
i_buff++;
|
||||
q_buff++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlays an audio stream with a beep signal
|
||||
* @param dds The previously initialized dds configuration
|
||||
* @param buffer audio buffer of blockSize (mono/single channel) samples
|
||||
* @param blockSize
|
||||
* @param scaling scale the resulting sine wave with this factor
|
||||
*/
|
||||
|
||||
void softdds_addSingleTone(soft_dds_t* dds_ptr, float32_t* buffer, const size_t blockSize, float32_t scaling)
|
||||
{
|
||||
for(int i=0; i < blockSize; i++) // transfer to DMA buffer and do conversion to INT
|
||||
{
|
||||
buffer[i] += (float32_t)softdds_nextSample(dds_ptr) * scaling; // load indexed sine wave value, adding it to audio, scaling the amplitude and putting it on "b" - speaker (ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlays an audio stream with a beep signal
|
||||
* @param dds The previously initialized dds configuration
|
||||
* @param buffer1 audio buffer of blockSize (mono/single channel) samples
|
||||
* @param buffer2 audio buffer of blockSize (mono/single channel) samples
|
||||
* @param blockSize
|
||||
* @param scaling scale the resulting sine wave with this factor
|
||||
*/
|
||||
|
||||
void softdds_addSingleToneToTwobuffers(soft_dds_t* dds_ptr, float32_t* buffer1, float32_t* buffer2, const size_t blockSize, float32_t scaling)
|
||||
{
|
||||
float32_t Tone;
|
||||
for(int i=0; i < blockSize; i++) // transfer to DMA buffer and do conversion to INT
|
||||
{
|
||||
Tone=(float32_t) softdds_nextSample(dds_ptr) * scaling; // load indexed sine wave value, adding it to audio, scaling the amplitude and putting it on "b" - speaker (ONLY)
|
||||
buffer1[i] += Tone;
|
||||
buffer2[i] += Tone;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates the sinus frequencies as IQ data stream
|
||||
* min/max value is +/-2^15-1
|
||||
* Frequency needs to be configured using softdds_setfreq
|
||||
*/
|
||||
void softdds_runIQ(float32_t *i_buff,float32_t *q_buff,uint16_t size)
|
||||
{
|
||||
if (dbldds[1].step>0.0)
|
||||
{
|
||||
softdds_genIQTwoTone(&dbldds[0], &dbldds[1], i_buff, q_buff,size);
|
||||
}
|
||||
else
|
||||
{
|
||||
softdds_genIQSingleTone(&dbldds[0],i_buff,q_buff,size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __SOFTDDS_H
|
||||
#define __SOFTDDS_H
|
||||
|
||||
#include "dds_table.h"
|
||||
|
||||
// we use a 32 bit accumulator
|
||||
#define SOFTDDS_ACC_SHIFT (32-DDS_TBL_BITS)
|
||||
|
||||
// Soft DDS public structure
|
||||
typedef struct
|
||||
{
|
||||
// DDS accumulator
|
||||
uint32_t acc;
|
||||
|
||||
// DDS step - not working if part of the structure
|
||||
uint32_t step;
|
||||
} soft_dds_t;
|
||||
|
||||
|
||||
/**
|
||||
* Execute a single step in the sinus generation
|
||||
*/
|
||||
inline uint32_t softdds_nextSampleIndex(soft_dds_t* dds)
|
||||
{
|
||||
uint32_t retval = (dds->acc >> SOFTDDS_ACC_SHIFT)%DDS_TBL_SIZE;
|
||||
|
||||
dds->acc += dds->step;
|
||||
|
||||
// now scale down precision and make sure that
|
||||
// index wraps around properly
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the index which represents a -90 degree shift compared to
|
||||
* k, i.e. get k = sin(a) => cos(a)
|
||||
*/
|
||||
inline uint32_t softdds_phase_shift90(uint32_t k)
|
||||
{
|
||||
// make sure that
|
||||
// index wraps around properly
|
||||
return (k+(3*DDS_TBL_SIZE/4))%DDS_TBL_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a single step in the sinus generation and return actual sample value
|
||||
*/
|
||||
inline int16_t softdds_nextSample(soft_dds_t* dds)
|
||||
{
|
||||
return DDS_TABLE[softdds_nextSampleIndex(dds)];
|
||||
}
|
||||
|
||||
|
||||
void softdds_setFreqDDS(soft_dds_t* dds, float32_t freq, uint32_t samp_rate, uint8_t smooth);
|
||||
void softdds_genIQSingleTone(soft_dds_t* dds, float32_t *i_buff,float32_t *q_buff,uint16_t size);
|
||||
void softdds_genIQTwoTone(soft_dds_t* ddsA, soft_dds_t* ddsB, float *i_buff,float *q_buff,ushort size);
|
||||
|
||||
void softdds_addSingleTone(soft_dds_t* dds_ptr, float32_t* buffer, const size_t blockSize, float32_t scaling);
|
||||
void softdds_addSingleToneToTwobuffers(soft_dds_t* dds_ptr, float32_t* buffer1, float32_t* buffer2, const size_t blockSize, float32_t scaling);
|
||||
|
||||
void softdds_runIQ(float32_t *i_buff, float32_t *q_buff, uint16_t size);
|
||||
void softdds_configRunIQ(float32_t freq[2],uint32_t samp_rate,uint8_t smooth);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+1145
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __TX_PROCESSOR_H
|
||||
#define __TX_PROCESSOR_H
|
||||
|
||||
#include "uhsdr_board_config.h"
|
||||
#include "uhsdr_types.h"
|
||||
#include "audio_driver.h" // for types
|
||||
|
||||
void TxProcessor_Init(void);
|
||||
void TxProcessor_Set(uint8_t dmod_mode);
|
||||
void TxProcessor_PrepareRun(void);
|
||||
void TxProcessor_Run(AudioSample_t * const srcCodec, IqSample_t * const dst, AudioSample_t * const audioDst, uint16_t blockSize, bool external_mute);
|
||||
#endif
|
||||
+1384
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __CAT_DRIVER_H
|
||||
#define __CAT_DRIVER_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAT_DISCONNECTED = 0,
|
||||
CAT_CONNECTED
|
||||
} CatInterfaceState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
FT817 = 1
|
||||
} CatInterfaceProtocol;
|
||||
|
||||
|
||||
// Exports
|
||||
|
||||
CatInterfaceState CatDriver_GetInterfaceState(void);
|
||||
|
||||
int CatDriver_InterfaceBufferAddData(uint8_t c);
|
||||
|
||||
void CatDriver_HandleProtocol(void);
|
||||
|
||||
bool CatDriver_CloneOutStart(void);
|
||||
bool CatDriver_CloneInStart(void);
|
||||
|
||||
bool CatDriver_CWKeyPressed(void);
|
||||
bool CatDriver_CatPttActive(void);
|
||||
|
||||
#endif
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// This file is part of the µOS++ III distribution.
|
||||
// Copyright (c) 2014 Liviu Ionescu.
|
||||
//
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(TRACE)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "diag/Trace.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifndef OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE
|
||||
#define OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE (128)
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int
|
||||
trace_printf(const char* format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
// TODO: rewrite it to no longer use newlib, it is way too heavy
|
||||
|
||||
static char buf[OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE];
|
||||
|
||||
// Print to the local buffer
|
||||
ret = vsnprintf (buf, sizeof(buf), format, ap);
|
||||
if (ret > 0)
|
||||
{
|
||||
// Transfer the buffer to the device
|
||||
ret = trace_write (buf, (size_t)ret);
|
||||
}
|
||||
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
trace_puts(const char *s)
|
||||
{
|
||||
trace_write(s, strlen(s));
|
||||
return trace_write("\n", 1);
|
||||
}
|
||||
|
||||
int
|
||||
trace_putchar(int c)
|
||||
{
|
||||
trace_write((const char*)&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
trace_dump_args(int argc, char* argv[])
|
||||
{
|
||||
trace_printf("main(argc=%d, argv=[", argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
trace_printf(", ");
|
||||
}
|
||||
trace_printf("\"%s\"", argv[i]);
|
||||
}
|
||||
trace_printf("]);\n");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif // TRACE
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// This file is part of the µOS++ III distribution.
|
||||
// Copyright (c) 2014 Liviu Ionescu.
|
||||
//
|
||||
|
||||
#ifndef DIAG_TRACE_H_
|
||||
#define DIAG_TRACE_H_
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// The trace device is an independent output channel, intended for debug
|
||||
// purposes.
|
||||
//
|
||||
// The API is simple, and mimics the standard output calls:
|
||||
// - trace_printf()
|
||||
// - trace_puts()
|
||||
// - trace_putchar();
|
||||
//
|
||||
// The implementation is done in
|
||||
// - trace_write()
|
||||
//
|
||||
// Trace support is enabled by adding the TRACE definition.
|
||||
// By default the trace messages are forwarded to the ITM output,
|
||||
// but can be rerouted via any device or completely suppressed by
|
||||
// changing the definitions required in system/src/diag/trace_impl.c
|
||||
// (currently OS_USE_TRACE_ITM, OS_USE_TRACE_SEMIHOSTING_DEBUG/_STDOUT).
|
||||
//
|
||||
// When TRACE is not defined, all functions are inlined to empty bodies.
|
||||
// This has the advantage that the trace call do not need to be conditionally
|
||||
// compiled with #ifdef TRACE/#endif
|
||||
|
||||
|
||||
#if defined(TRACE)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void
|
||||
trace_initialize(void);
|
||||
|
||||
// Implementation dependent
|
||||
ssize_t
|
||||
trace_write(const char* buf, size_t nbyte);
|
||||
|
||||
// ----- Portable -----
|
||||
|
||||
int
|
||||
trace_printf(const char* format, ...);
|
||||
|
||||
int
|
||||
trace_puts(const char *s);
|
||||
|
||||
int
|
||||
trace_putchar(int c);
|
||||
|
||||
void
|
||||
trace_dump_args(int argc, char* argv[]);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // !defined(TRACE)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
inline void
|
||||
trace_initialize(void);
|
||||
|
||||
// Implementation dependent
|
||||
inline ssize_t
|
||||
trace_write(const char* buf, size_t nbyte);
|
||||
|
||||
inline int
|
||||
trace_printf(const char* format, ...);
|
||||
|
||||
inline int
|
||||
trace_puts(const char *s);
|
||||
|
||||
inline int
|
||||
trace_putchar(int c);
|
||||
|
||||
inline void
|
||||
trace_dump_args(int argc, char* argv[]);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void
|
||||
__attribute__((always_inline))
|
||||
trace_initialize(void)
|
||||
{
|
||||
}
|
||||
|
||||
// Empty definitions when trace is not defined
|
||||
inline ssize_t
|
||||
__attribute__((always_inline))
|
||||
trace_write(const char* buf __attribute__((unused)),
|
||||
size_t nbyte __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
__attribute__((always_inline))
|
||||
trace_printf(const char* format __attribute__((unused)), ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
__attribute__((always_inline))
|
||||
trace_puts(const char *s __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
__attribute__((always_inline))
|
||||
trace_putchar(int c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
inline void
|
||||
__attribute__((always_inline))
|
||||
trace_dump_args(int argc __attribute__((unused)),
|
||||
char* argv[] __attribute__((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
#endif // defined(TRACE)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif // DIAG_TRACE_H_
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// This file is part of the µOS++ III distribution.
|
||||
// Copyright (c) 2014 Liviu Ionescu.
|
||||
//
|
||||
|
||||
#ifndef ARM_SEMIHOSTING_H_
|
||||
#define ARM_SEMIHOSTING_H_
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Semihosting operations.
|
||||
enum OperationNumber
|
||||
{
|
||||
// Regular operations
|
||||
SEMIHOSTING_EnterSVC = 0x17,
|
||||
SEMIHOSTING_ReportException = 0x18,
|
||||
SEMIHOSTING_SYS_CLOSE = 0x02,
|
||||
SEMIHOSTING_SYS_CLOCK = 0x10,
|
||||
SEMIHOSTING_SYS_ELAPSED = 0x30,
|
||||
SEMIHOSTING_SYS_ERRNO = 0x13,
|
||||
SEMIHOSTING_SYS_FLEN = 0x0C,
|
||||
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
|
||||
SEMIHOSTING_SYS_HEAPINFO = 0x16,
|
||||
SEMIHOSTING_SYS_ISERROR = 0x08,
|
||||
SEMIHOSTING_SYS_ISTTY = 0x09,
|
||||
SEMIHOSTING_SYS_OPEN = 0x01,
|
||||
SEMIHOSTING_SYS_READ = 0x06,
|
||||
SEMIHOSTING_SYS_READC = 0x07,
|
||||
SEMIHOSTING_SYS_REMOVE = 0x0E,
|
||||
SEMIHOSTING_SYS_RENAME = 0x0F,
|
||||
SEMIHOSTING_SYS_SEEK = 0x0A,
|
||||
SEMIHOSTING_SYS_SYSTEM = 0x12,
|
||||
SEMIHOSTING_SYS_TICKFREQ = 0x31,
|
||||
SEMIHOSTING_SYS_TIME = 0x11,
|
||||
SEMIHOSTING_SYS_TMPNAM = 0x0D,
|
||||
SEMIHOSTING_SYS_WRITE = 0x05,
|
||||
SEMIHOSTING_SYS_WRITEC = 0x03,
|
||||
SEMIHOSTING_SYS_WRITE0 = 0x04,
|
||||
|
||||
// Codes returned by SEMIHOSTING_ReportException
|
||||
ADP_Stopped_ApplicationExit = ((2 << 16) + 38),
|
||||
ADP_Stopped_RunTimeError = ((2 << 16) + 35),
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// SWI numbers and reason codes for RDI (Angel) monitors.
|
||||
#define AngelSWI_ARM 0x123456
|
||||
#ifdef __thumb__
|
||||
#define AngelSWI 0xAB
|
||||
#else
|
||||
#define AngelSWI AngelSWI_ARM
|
||||
#endif
|
||||
// For thumb only architectures use the BKPT instruction instead of SWI.
|
||||
#if defined(__ARM_ARCH_7M__) \
|
||||
|| defined(__ARM_ARCH_7EM__) \
|
||||
|| defined(__ARM_ARCH_6M__)
|
||||
#define AngelSWIInsn "bkpt"
|
||||
#define AngelSWIAsm bkpt
|
||||
#else
|
||||
#define AngelSWIInsn "swi"
|
||||
#define AngelSWIAsm swi
|
||||
#endif
|
||||
|
||||
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
|
||||
// Testing the local semihosting handler cannot use another BKPT, since this
|
||||
// configuration cannot trigger HaedFault exceptions while the debugger is
|
||||
// connected, so we use an illegal op code, that will trigger an
|
||||
// UsageFault exception.
|
||||
#define AngelSWITestFault "setend be"
|
||||
#define AngelSWITestFaultOpCode (0xB658)
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
__attribute__ ((always_inline))
|
||||
call_host (int reason, void* arg)
|
||||
{
|
||||
int value;
|
||||
asm volatile (
|
||||
|
||||
" mov r0, %[rsn] \n"
|
||||
" mov r1, %[arg] \n"
|
||||
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
|
||||
" " AngelSWITestFault " \n"
|
||||
#else
|
||||
" " AngelSWIInsn " %[swi] \n"
|
||||
#endif
|
||||
" mov %[val], r0"
|
||||
|
||||
: [val] "=r" (value) /* Outputs */
|
||||
: [rsn] "r" (reason), [arg] "r" (arg), [swi] "i" (AngelSWI) /* Inputs */
|
||||
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
|
||||
// Clobbers r0 and r1, and lr if in supervisor mode
|
||||
);
|
||||
|
||||
// Accordingly to page 13-77 of ARM DUI 0040D other registers
|
||||
// can also be clobbered. Some memory positions may also be
|
||||
// changed by a system call, so they should not be kept in
|
||||
// registers. Note: we are assuming the manual is right and
|
||||
// Angel is respecting the APCS.
|
||||
return value;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Function used in _exit() to return the status code as Angel exception.
|
||||
static inline void
|
||||
__attribute__ ((always_inline,noreturn))
|
||||
report_exception (int reason)
|
||||
{
|
||||
call_host (SEMIHOSTING_ReportException, (void*) reason);
|
||||
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif // ARM_SEMIHOSTING_H_
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// This file is part of the µOS++ III distribution.
|
||||
// Copyright (c) 2014 Liviu Ionescu.
|
||||
//
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(TRACE)
|
||||
|
||||
#include "cmsis_device.h"
|
||||
#include "diag/Trace.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// One of these definitions must be passed via the compiler command line
|
||||
// Note: small Cortex-M0/M0+ might implement a simplified debug interface.
|
||||
|
||||
//#define OS_USE_TRACE_ITM
|
||||
//#define OS_USE_TRACE_SEMIHOSTING_DEBUG
|
||||
//#define OS_USE_TRACE_SEMIHOSTING_STDOUT
|
||||
|
||||
#if !(defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
|
||||
#if defined(OS_USE_TRACE_ITM)
|
||||
#undef OS_USE_TRACE_ITM
|
||||
#warning "ITM unavailable"
|
||||
#endif // defined(OS_USE_TRACE_ITM)
|
||||
#endif // !(defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
|
||||
|
||||
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT) || defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
|
||||
#error "Cannot debug semihosting using semihosting trace; use OS_USE_TRACE_ITM"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Forward definitions.
|
||||
|
||||
#if defined(OS_USE_TRACE_ITM)
|
||||
static ssize_t
|
||||
_trace_write_itm (const char* buf, size_t nbyte);
|
||||
#endif
|
||||
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
|
||||
static ssize_t
|
||||
_trace_write_semihosting_stdout(const char* buf, size_t nbyte);
|
||||
#endif
|
||||
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
|
||||
static ssize_t
|
||||
_trace_write_semihosting_debug(const char* buf, size_t nbyte);
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
trace_initialize(void)
|
||||
{
|
||||
// For regular ITM / semihosting, no inits required.
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This function is called from _write() for fd==1 or fd==2 and from some
|
||||
// of the trace_* functions.
|
||||
|
||||
ssize_t
|
||||
trace_write (const char* buf __attribute__((unused)),
|
||||
size_t nbyte __attribute__((unused)))
|
||||
{
|
||||
#if defined(OS_USE_TRACE_ITM)
|
||||
return _trace_write_itm (buf, nbyte);
|
||||
#elif defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
|
||||
return _trace_write_semihosting_stdout(buf, nbyte);
|
||||
#elif defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
|
||||
return _trace_write_semihosting_debug(buf, nbyte);
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(OS_USE_TRACE_ITM)
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
|
||||
// ITM is the ARM standard mechanism, running over SWD/SWO on Cortex-M3/M4
|
||||
// devices, and is the recommended setting, if available.
|
||||
//
|
||||
// The JLink probe and the GDB server fully support SWD/SWO
|
||||
// and the JLink Debugging plug-in enables it by default.
|
||||
// The current OpenOCD does not include support to parse the SWO stream,
|
||||
// so this configuration will not work on OpenOCD (will not crash, but
|
||||
// nothing will be displayed in the output console).
|
||||
|
||||
#if !defined(OS_INTEGER_TRACE_ITM_STIMULUS_PORT)
|
||||
#define OS_INTEGER_TRACE_ITM_STIMULUS_PORT (0)
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
_trace_write_itm (const char* buf, size_t nbyte)
|
||||
{
|
||||
for (size_t i = 0; i < nbyte; i++)
|
||||
{
|
||||
// Check if ITM or the stimulus port are not enabled
|
||||
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) == 0)
|
||||
|| ((ITM->TER & (1UL << OS_INTEGER_TRACE_ITM_STIMULUS_PORT)) == 0))
|
||||
{
|
||||
return (ssize_t)i; // return the number of sent characters (may be 0)
|
||||
}
|
||||
|
||||
// Wait until STIMx is ready...
|
||||
while (ITM->PORT[OS_INTEGER_TRACE_ITM_STIMULUS_PORT].u32 == 0)
|
||||
;
|
||||
// then send data, one byte at a time
|
||||
ITM->PORT[OS_INTEGER_TRACE_ITM_STIMULUS_PORT].u8 = (uint8_t) (*buf++);
|
||||
}
|
||||
|
||||
return (ssize_t)nbyte; // all characters successfully sent
|
||||
}
|
||||
|
||||
#endif // defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
|
||||
#endif // OS_USE_TRACE_ITM
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG) || defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
|
||||
|
||||
#include "arm/semihosting.h"
|
||||
|
||||
// Semihosting is the other output channel that can be used for the trace
|
||||
// messages. It comes in two flavours: STDOUT and DEBUG. The STDOUT channel
|
||||
// is the equivalent of the stdout in POSIX and in most cases it is forwarded
|
||||
// to the GDB server stdout stream. The debug channel is a separate
|
||||
// channel. STDOUT is buffered, so nothing is displayed until a \n;
|
||||
// DEBUG is not buffered, but can be slow.
|
||||
//
|
||||
// Choosing between semihosting stdout and debug depends on the capabilities
|
||||
// of your GDB server, and also on specific needs. It is recommended to test
|
||||
// DEBUG first, and if too slow, try STDOUT.
|
||||
//
|
||||
// The JLink GDB server fully support semihosting, and both configurations
|
||||
// are available; to activate it, use "monitor semihosting enable" or check
|
||||
// the corresponding button in the JLink Debugging plug-in.
|
||||
// In OpenOCD, support for semihosting can be enabled using
|
||||
// "monitor arm semihosting enable".
|
||||
//
|
||||
// Note: Applications built with semihosting output active normally cannot
|
||||
// be executed without the debugger connected and active, since they use
|
||||
// BKPT to communicate with the host. However, with a carefully written
|
||||
// HardFault_Handler, the semihosting BKPT calls can be processed, making
|
||||
// possible to run semihosting applications as standalone, without being
|
||||
// terminated with hardware faults.
|
||||
|
||||
#endif // OS_USE_TRACE_SEMIHOSTING_DEBUG_*
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
|
||||
|
||||
static ssize_t
|
||||
_trace_write_semihosting_stdout (const char* buf, size_t nbyte)
|
||||
{
|
||||
static int handle;
|
||||
void* block[3];
|
||||
int ret;
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
// On the first call get the file handle from the host
|
||||
block[0] = ":tt"; // special filename to be used for stdin/out/err
|
||||
block[1] = (void*) 4; // mode "w"
|
||||
// length of ":tt", except null terminator
|
||||
block[2] = (void*) (sizeof(":tt") - 1);
|
||||
|
||||
ret = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
|
||||
handle = ret;
|
||||
}
|
||||
|
||||
block[0] = (void*) handle;
|
||||
block[1] = (void*) buf;
|
||||
block[2] = (void*) nbyte;
|
||||
// send character array to host file/device
|
||||
ret = call_host (SEMIHOSTING_SYS_WRITE, (void*) block);
|
||||
// this call returns the number of bytes NOT written (0 if all ok)
|
||||
|
||||
// -1 is not a legal value, but SEGGER seems to return it
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
|
||||
// The compliant way of returning errors
|
||||
if (ret == (int) nbyte)
|
||||
return -1;
|
||||
|
||||
// Return the number of bytes written
|
||||
return (ssize_t) (nbyte) - (ssize_t) ret;
|
||||
}
|
||||
|
||||
#endif // OS_USE_TRACE_SEMIHOSTING_STDOUT
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
|
||||
|
||||
#define OS_INTEGER_TRACE_TMP_ARRAY_SIZE (16)
|
||||
|
||||
static ssize_t
|
||||
_trace_write_semihosting_debug (const char* buf, size_t nbyte)
|
||||
{
|
||||
// Since the single character debug channel is quite slow, try to
|
||||
// optimise and send a null terminated string, if possible.
|
||||
if (buf[nbyte] == '\0')
|
||||
{
|
||||
// send string
|
||||
call_host (SEMIHOSTING_SYS_WRITE0, (void*) buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, use a local buffer to speed things up
|
||||
char tmp[OS_INTEGER_TRACE_TMP_ARRAY_SIZE];
|
||||
size_t togo = nbyte;
|
||||
while (togo > 0)
|
||||
{
|
||||
unsigned int n = ((togo < sizeof(tmp)) ? togo : sizeof(tmp));
|
||||
unsigned int i = 0;
|
||||
for (; i < n; ++i, ++buf)
|
||||
{
|
||||
tmp[i] = *buf;
|
||||
}
|
||||
tmp[i] = '\0';
|
||||
|
||||
call_host (SEMIHOSTING_SYS_WRITE0, (void*) tmp);
|
||||
|
||||
togo -= n;
|
||||
}
|
||||
}
|
||||
|
||||
// All bytes written
|
||||
return (ssize_t) nbyte;
|
||||
}
|
||||
|
||||
#endif // OS_USE_TRACE_SEMIHOSTING_DEBUG
|
||||
|
||||
#endif // TRACE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
#
|
||||
# Generated sources
|
||||
#
|
||||
|
||||
set(D ${CMAKE_CURRENT_SOURCE_DIR}/codebook)
|
||||
|
||||
# lsp quantisers
|
||||
|
||||
set(CODEBOOKS
|
||||
${D}/lsp1.txt
|
||||
${D}/lsp2.txt
|
||||
${D}/lsp3.txt
|
||||
${D}/lsp4.txt
|
||||
${D}/lsp5.txt
|
||||
${D}/lsp6.txt
|
||||
${D}/lsp7.txt
|
||||
${D}/lsp8.txt
|
||||
${D}/lsp9.txt
|
||||
${D}/lsp10.txt
|
||||
)
|
||||
|
||||
# lspd quantisers
|
||||
|
||||
set(CODEBOOKSD
|
||||
${D}/dlsp1.txt
|
||||
${D}/dlsp2.txt
|
||||
${D}/dlsp3.txt
|
||||
${D}/dlsp4.txt
|
||||
${D}/dlsp5.txt
|
||||
${D}/dlsp6.txt
|
||||
${D}/dlsp7.txt
|
||||
${D}/dlsp8.txt
|
||||
${D}/dlsp9.txt
|
||||
${D}/dlsp10.txt
|
||||
)
|
||||
|
||||
set(CODEBOOKSJVM
|
||||
${D}/lspjvm1.txt
|
||||
${D}/lspjvm2.txt
|
||||
${D}/lspjvm3.txt
|
||||
)
|
||||
|
||||
set(CODEBOOKSMEL
|
||||
${D}/mel1.txt
|
||||
${D}/mel2.txt
|
||||
${D}/mel3.txt
|
||||
${D}/mel4.txt
|
||||
${D}/mel5.txt
|
||||
${D}/mel6.txt
|
||||
)
|
||||
|
||||
set(CODEBOOKSLSPMELVQ
|
||||
${D}/lspmelvq1.txt
|
||||
${D}/lspmelvq2.txt
|
||||
${D}/lspmelvq3.txt
|
||||
)
|
||||
|
||||
set(CODEBOOKSGE ${D}/gecb.txt)
|
||||
|
||||
# when crosscompiling we need a native executable
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(codec2_native
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}
|
||||
BUILD_COMMAND $(MAKE) generate_codebook
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy src/generate_codebook ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
add_executable(generate_codebook IMPORTED)
|
||||
set_target_properties(generate_codebook PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/generate_codebook)
|
||||
add_dependencies(generate_codebook codec2_native)
|
||||
else(CMAKE_CROSSCOMPILING)
|
||||
# Build code generator binaries. These do not get installed.
|
||||
# generate_codebook
|
||||
add_executable(generate_codebook generate_codebook.c)
|
||||
target_link_libraries(generate_codebook ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# genlspdtcb
|
||||
add_executable(genlspdtcb genlspdtcb.c)
|
||||
target_link_libraries(genlspdtcb ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Make native builds available for cross-compiling.
|
||||
export(TARGETS generate_codebook genlspdtcb
|
||||
FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake)
|
||||
endif(CMAKE_CROSSCOMPILING)
|
||||
|
||||
|
||||
# codebook.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebook.c
|
||||
COMMAND generate_codebook lsp_cb ${CODEBOOKS} > ${CMAKE_CURRENT_BINARY_DIR}/codebook.c
|
||||
DEPENDS generate_codebook ${CODEBOOKS}
|
||||
)
|
||||
|
||||
# codebookd.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookd.c
|
||||
COMMAND generate_codebook lsp_cbd ${CODEBOOKSD} > ${CMAKE_CURRENT_BINARY_DIR}/codebookd.c
|
||||
DEPENDS generate_codebook ${CODEBOOKSD}
|
||||
)
|
||||
|
||||
# codebookjvm.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookjvm.c
|
||||
COMMAND generate_codebook lsp_cbjvm ${CODEBOOKSJVM} > ${CMAKE_CURRENT_BINARY_DIR}/codebookjvm.c
|
||||
DEPENDS generate_codebook ${CODEBOOKSJVM}
|
||||
)
|
||||
|
||||
|
||||
# codebookmel.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookmel.c
|
||||
COMMAND generate_codebook mel_cb ${CODEBOOKSMEL} > ${CMAKE_CURRENT_BINARY_DIR}/codebookmel.c
|
||||
DEPENDS generate_codebook ${CODEBOOKSMEL}
|
||||
)
|
||||
|
||||
# codebooklspmelvq.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooklspmelvq.c
|
||||
COMMAND generate_codebook lspmelvq_cb ${CODEBOOKSLSPMELVQ} > ${CMAKE_CURRENT_BINARY_DIR}/codebooklspmelvq.c
|
||||
DEPENDS generate_codebook ${CODEBOOKSLSPMELVQ}
|
||||
)
|
||||
|
||||
# codebookge.c
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookge.c
|
||||
COMMAND generate_codebook ge_cb ${CODEBOOKSGE} > ${CMAKE_CURRENT_BINARY_DIR}/codebookge.c
|
||||
DEPENDS generate_codebook ${CODEBOOKSGE}
|
||||
)
|
||||
|
||||
#
|
||||
# codec2 library sources
|
||||
#
|
||||
|
||||
set(CODEC2_SRCS
|
||||
dump.c
|
||||
lpc.c
|
||||
nlp.c
|
||||
postfilter.c
|
||||
sine.c
|
||||
codec2.c
|
||||
cohpsk.c
|
||||
fifo.c
|
||||
fdmdv.c
|
||||
fm.c
|
||||
kiss_fft.c
|
||||
linreg.c
|
||||
interp.c
|
||||
lsp.c
|
||||
phase.c
|
||||
quantise.c
|
||||
pack.c
|
||||
codebook.c
|
||||
codebookd.c
|
||||
codebookjvm.c
|
||||
codebookmel.c
|
||||
codebooklspmelvq.c
|
||||
codebookge.c
|
||||
golay23.c
|
||||
freedv_api.c
|
||||
varicode.c
|
||||
modem_stats.c
|
||||
)
|
||||
|
||||
set(CODEC2_PUBLIC_HEADERS
|
||||
golay23.h
|
||||
codec2.h
|
||||
codec2_fdmdv.h
|
||||
codec2_cohpsk.h
|
||||
codec2_fm.h
|
||||
codec2_fifo.h
|
||||
comp.h
|
||||
comp_prim.h
|
||||
modem_stats.h
|
||||
kiss_fft.h
|
||||
freedv_api.h
|
||||
varicode.h
|
||||
freedv_api_internal.h
|
||||
)
|
||||
|
||||
#
|
||||
# Setup the codec2 library
|
||||
#
|
||||
add_library(codec2 ${CODEC2_SRCS})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(codec2 ${CMAKE_REQUIRED_LIBRARIES})
|
||||
set_target_properties(codec2 PROPERTIES
|
||||
SOVERSION ${SOVERSION}
|
||||
PUBLIC_HEADER "${CODEC2_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
add_executable(c2demo c2demo.c)
|
||||
target_link_libraries(c2demo ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(c2enc c2enc.c)
|
||||
target_link_libraries(c2enc ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(c2dec c2dec.c)
|
||||
target_link_libraries(c2dec ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(c2sim c2sim.c ampexp.c phaseexp.c)
|
||||
target_link_libraries(c2sim ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(fdmdv_get_test_bits fdmdv_get_test_bits.c fdmdv.c kiss_fft.c)
|
||||
target_link_libraries(fdmdv_get_test_bits ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(fdmdv_mod fdmdv_mod.c fdmdv.c kiss_fft.c)
|
||||
target_link_libraries(fdmdv_mod ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(fdmdv_demod fdmdv_demod.c fdmdv.c kiss_fft.c octave.c modem_stats.c)
|
||||
target_link_libraries(fdmdv_demod ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(fdmdv_put_test_bits fdmdv_put_test_bits.c fdmdv.c kiss_fft.c)
|
||||
target_link_libraries(fdmdv_put_test_bits ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(fdmdv_channel fdmdv_channel.c)
|
||||
target_link_libraries(fdmdv_channel ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(fdmdv_interleave fdmdv_interleave.c)
|
||||
target_link_libraries(fdmdv_interleave ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(insert_errors insert_errors.c)
|
||||
target_link_libraries(insert_errors ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(fec_enc fec_enc.c golay23.c)
|
||||
target_link_libraries(fec_enc ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(fec_dec fec_dec.c golay23.c)
|
||||
target_link_libraries(fec_dec ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(freedv_tx freedv_tx.c)
|
||||
target_link_libraries(freedv_tx ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(freedv_rx freedv_rx.c)
|
||||
target_link_libraries(freedv_rx ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(fm_demod fm_demod.c fm.c)
|
||||
target_link_libraries(fm_demod ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
add_executable(cohpsk_mod cohpsk_mod.c)
|
||||
target_link_libraries(cohpsk_mod ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(cohpsk_demod cohpsk_demod.c octave.c)
|
||||
target_link_libraries(cohpsk_demod ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(cohpsk_get_test_bits cohpsk_get_test_bits.c)
|
||||
target_link_libraries(cohpsk_get_test_bits ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(cohpsk_put_test_bits cohpsk_put_test_bits.c octave.c)
|
||||
target_link_libraries(cohpsk_put_test_bits ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
add_executable(cohpsk_ch cohpsk_ch.c)
|
||||
target_link_libraries(cohpsk_ch ${CMAKE_REQUIRED_LIBRARIES} codec2)
|
||||
|
||||
install(TARGETS codec2 EXPORT codec2-config
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/codec2
|
||||
)
|
||||
|
||||
#install(EXPORT codec2-config
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/codec2
|
||||
#)
|
||||
|
||||
install(TARGETS
|
||||
c2demo
|
||||
c2demo
|
||||
c2enc
|
||||
c2dec
|
||||
c2sim
|
||||
fdmdv_get_test_bits
|
||||
fdmdv_mod fdmdv_demod
|
||||
fm_demod
|
||||
fdmdv_put_test_bits
|
||||
fdmdv_interleave
|
||||
insert_errors
|
||||
fec_enc
|
||||
fec_dec
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
FILE....: HRA_112_112.c
|
||||
|
||||
Static arrays for LDPC codec HRA_112_112, generated by ldpc_gen_c_h_file.m.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "HRA_112_112.h"
|
||||
|
||||
const uint16_t HRA_112_112_H_rows[] = {
|
||||
22, 18, 15, 63, 16, 13, 1, 2, 29, 25, 28, 4, 36, 10, 38, 7, 60, 23, 11, 38, 28, 1, 12, 31, 57, 45, 57, 30, 23, 59, 67, 14, 16, 4, 14, 62, 15, 50, 7, 70, 64, 6, 42, 48, 9, 31, 19, 40, 49, 2, 25, 3, 41, 49, 36, 9, 29, 39, 31, 5, 17, 1, 29, 25, 11, 21, 18, 2, 8, 22, 39, 15, 8, 22, 13, 3, 19, 4, 21, 62, 34, 43, 6, 24, 17, 60, 8, 74, 6, 44, 60, 10, 33, 12, 26, 24, 45, 81, 69, 80, 41, 28, 23, 5, 10, 20, 52, 18, 13, 86, 3, 7, 59, 21, 65, 72, 34, 37, 26, 55, 47, 48, 34, 5, 44, 47, 68, 96, 82, 111, 61, 74, 30, 17, 55, 98, 81, 66, 89, 35, 74, 82, 91, 51, 55, 51, 30, 89, 61, 75, 40, 71, 73, 11, 56, 54, 19, 47, 94, 69, 64, 20, 64, 12, 54, 77, 42, 88, 36, 52, 90, 63, 70, 27, 32, 73, 91, 32, 56, 46, 9, 78, 51, 68, 88, 67, 20, 43, 40, 14, 66, 86, 39, 97, 38, 27, 50, 84, 54, 92, 61, 46, 67, 24, 58, 35, 58, 37, 98, 85, 73, 84, 48, 35, 57, 16, 26, 37, 65, 32, 72, 95, 107, 33, 77, 33, 85, 105, 106, 75, 56, 71, 79, 59, 52, 105, 79, 90, 93, 100, 88, 112, 86, 80, 65, 42, 106, 100, 93, 94, 99, 97, 93, 101, 111, 99, 83, 53, 85, 95, 108, 107, 41, 109, 84, 78, 104, 101, 69, 110, 98, 103, 80, 83, 77, 71, 76, 78, 87, 102, 104, 95, 96, 83, 87, 50, 110, 103, 112, 45, 58, 70, 94, 91, 89, 81, 101, 82, 63, 72, 100, 97, 76, 112, 53, 105, 49, 75, 109, 102, 66, 111, 68, 87, 92, 79, 96, 43, 90, 44, 110, 99, 102, 92, 103, 106, 62, 53, 27, 46, 108, 104, 107, 108, 109, 76
|
||||
};
|
||||
|
||||
const uint16_t HRA_112_112_H_cols[] = {
|
||||
7, 8, 52, 12, 12, 42, 16, 69, 45, 14, 19, 23, 6, 32, 3, 5, 22, 2, 45, 50, 2, 1, 18, 84, 10, 7, 62, 11, 9, 21, 24, 63, 2, 5, 28, 13, 6, 15, 58, 39, 39, 22, 76, 13, 26, 68, 9, 10, 49, 38, 32, 11, 34, 44, 8, 7, 25, 67, 1, 17, 19, 36, 4, 41, 3, 26, 31, 15, 45, 40, 8, 4, 41, 20, 6, 53, 1, 42, 9, 20, 25, 17, 33, 41, 3, 19, 55, 17, 27, 14, 31, 88, 15, 26, 36, 16, 28, 24, 27, 16, 30, 56, 48, 43, 4, 5, 38, 37, 40, 46, 18, 18, 22, 50, 76, 34, 60, 83, 39, 73, 56, 92, 42, 52, 75, 35, 37, 33, 61, 67, 47, 75, 66, 70, 29, 92, 51, 95, 84, 21, 57, 28, 46, 66, 93, 11, 94, 55, 96, 20, 71, 48, 53, 43, 82, 90, 66, 90, 14, 44, 54, 62, 34, 58, 81, 53, 23, 43, 27, 93, 10, 86, 37, 80, 60, 49, 21, 79, 74, 72, 48, 61, 40, 76, 64, 29, 38, 79, 51, 54, 13, 49, 72, 30, 50, 86, 35, 80, 61, 56, 36, 59, 65, 91, 25, 47, 58, 59, 78, 47, 32, 24, 44, 86, 64, 57, 12, 23, 109, 107, 85, 63, 31, 65, 62, 68, 111, 78, 104, 89, 112, 87, 69, 105, 65, 94, 109, 78, 72, 104, 85, 108, 77, 106, 79, 74, 103, 96, 64, 105, 105, 102, 63, 35, 59, 108, 112, 81, 102, 57, 106, 83, 81, 77, 101, 55, 94, 96, 97, 106, 46, 101, 83, 85, 71, 107, 104, 87, 33, 67, 103, 95, 30, 91, 89, 103, 75, 51, 107, 87, 91, 89, 99, 68, 52, 109, 99, 88, 84, 112, 54, 70, 92, 100, 98, 74, 60, 100, 98, 110, 90, 73, 71, 95, 70, 100, 29, 69, 110, 93, 82, 97, 98, 77, 73, 99, 101, 108, 82, 102, 111, 110, 111, 97, 88, 80
|
||||
};
|
||||
const float HRA_112_112_input[] = {
|
||||
-3.7496794787890972, 14.372112019392226, -7.5640452729302359, 6.9426063455159657, 5.3103644888713299, -6.9203550501252273, 8.4296575778653775, 13.495087143587781, 18.111520666852243, -9.9125748623510912, 10.601298534930972, -10.468591112149715, -9.0757329437720475, -14.471433733514324, 5.2048820572852641, -11.353785810284556, -9.4511008284496416, -9.5255219979484025, -2.0499245561876696, -9.8739646459388748, 22.03442141444015, -9.9745566449839878, -8.4276711655946226, -4.9811962116476307, -13.018434575859896, -5.3358535334627293, -5.6704294937789648, 14.243964608060018, -11.417925510314507, 9.1332657371467878, -14.380214782394296, 14.090409878618974, 6.5602278279998272, 15.53025696352436, -9.1752771765906616, -11.384503450560766, 12.240329442222599, -12.640059450058276, -11.824715154614376, -13.487656131954735, 15.38073452845444, -13.816294924566529, 6.3461114450644454, -2.5192445130977559, -11.916088712873863, 5.4360722876642518, 0.038031547223147381, -12.367220238860654, -2.747864039796549, -14.920508782249289, 16.487336720060863, -13.290002442259247, 19.142698450560925, -0.39443060583296108, 11.723442316413736, -3.6131702833965047, -4.6196487103817017, -11.794290650694531, -14.342351103186955, 2.8079943208330334, -15.290175151123936, 9.0801740558512414, 10.184385069676226, 8.400722260237572, 9.3504690108712936, -14.223531676384166, 11.752768386971752, 11.36995822251677, -15.285021241405444, -13.070613695054403, -11.869191325617697, 4.3191750845563401, 2.0836933404582791, -16.363829786416495, -5.7778094839806595, 11.06389861779129, 13.285433846434705, 9.2552396418849021, -11.065999403824057, -10.167040394420443, -7.0107225044503565, 2.3886881673282474, 5.0014484787306932, -9.2464083853314278, -12.043309174487364, -11.638411967211738, -16.302815497922911, 13.347129717938067, -4.1390259986125226, 0.7947480277507295, 11.538620744796759, -7.4410706619926028, 14.572449028311253, 12.392747919231169, -3.3027890746379289, -9.8431096813736687, 11.582657487369399, -7.85736442083219, -7.3780721969188443, -7.4006260265172212, -8.3937994980934327, -6.6804071011469555, 19.656301355404196, 1.1084340389939762, 3.6028635453146465, -4.5409495140900562, 7.3831459854578982, -5.5905999874445662, -13.852328482738232, 8.9999210644983041, 8.4742375282492315, 16.989947243749878, 7.5590035165610168, -6.154674423116183, 4.1119120658251855, 12.351217703790844, 11.070972687846792, 11.182587746846833, -4.9345619923565645, 9.0054892370887334, -10.841725474869696, 13.902796293412067, -6.7575171884905396, -5.8196703210757335, 1.9284357540668857, 9.9905382141440455, -13.983067199220674, -4.9130522479706453, -8.2369300184767908, 6.8953565265629644, 2.9285103862640871, -2.6303471135655325, -8.3563361642086047, 9.5712349244763715, 4.9728623009661161, -11.045088919587242, -5.7781337596219604, -17.732999074602972, 8.1353860976076646, -11.066240843831284, -1.7079574457159534, -16.411685365171998, -9.0471090651358299, -10.959376227315447, 8.5840398495674126, 6.6373658260736024, 11.422094029020409, 14.85785089306844, 13.185747281780415, 4.2063935223916191, -6.9166135608899282, 10.843153262137262, 5.3913075109409441, -10.744469667642237, -12.491640291445655, 14.141118162062066, 16.425476099516025, 9.8833761863476042, 2.8719064151687883, 14.982021915112442, 1.3588165304065343, -11.657839635726177, 11.066314862965077, -3.0565490195476204, 1.7820159270701772, -13.535333311782074, 4.4026933190218367, -11.097334550496313, -11.322820869044248, 16.418516996530371, 5.8239202459876136, 15.054905601216154, -9.3058742038490152, 8.48902767802557, -8.3853534273227748, -7.9255089736435176, -9.6156735881618811, 11.502594413898008, -6.0542015398269911, 7.1229229147355149, 0.31483632310264387, -11.482093481730768, -9.3225703551629309, 5.8001228713062831, -9.3515917458791051, 7.9778737065172969, 9.7095180444854847, -14.060064536791135, 4.9797253221020545, -6.9210799657794224, 6.6736460552213845, -7.7636429824024606, 10.233132490278882, 8.401747393605044, -10.861100567451366, 13.631509744686715, -15.723791754613185, -8.7931294115815923, -9.9520037489001609, -10.312792052906007, -8.0681893911111917, -15.411052087079765, 10.938779471602952, -8.751795633239853, -9.1302029882284419, -2.3357314769649777, -7.9130658335895596, 2.7508172894969509, -9.1666780515772324, 12.793063537524359, -13.39091818112591, 7.2827402370664842, -10.400778532411657, -1.90854156128735, -4.1272702472088971, 12.696932922959466, -4.0180403457213805, 10.828999052972396, 14.720617452742685, -8.3763729074389719, 3.955093172344033, 0.90932711822659873, -5.6696817865337819, -5.8822086115513805
|
||||
};
|
||||
const char HRA_112_112_detected_data[] = {
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
FILE....: HRA_112_112.h
|
||||
|
||||
Static arrays for LDPC codec HRA_112_112, generated by ldpc_gen_c_h_file.m.
|
||||
*/
|
||||
|
||||
#define HRA_112_112_NUMBERPARITYBITS 112
|
||||
#define HRA_112_112_MAX_ROW_WEIGHT 3
|
||||
#define HRA_112_112_CODELENGTH 224
|
||||
#define HRA_112_112_NUMBERROWSHCOLS 112
|
||||
#define HRA_112_112_MAX_COL_WEIGHT 3
|
||||
#define HRA_112_112_DEC_TYPE 0
|
||||
#define HRA_112_112_MAX_ITER 100
|
||||
|
||||
extern const uint16_t HRA_112_112_H_rows[];
|
||||
extern const uint16_t HRA_112_112_H_cols[];
|
||||
extern const float HRA_112_112_input[];
|
||||
extern const char HRA_112_112_detected_data[];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user