Multichannel CW decoder implemented for FLDIGI.

master
AG1LE Mauri 2014-07-17 20:47:50 -04:00
rodzic 41ed8623a5
commit 8578ee44ce
4 zmienionych plików z 120 dodań i 12 usunięć

25
README
Wyświetl plik

@ -88,7 +88,30 @@ MORSE - PROJECT IDEAS
http://orgmode.org/worg/org-contrib/babel/examples/data-collection-analysis.html
3. CW Skimmer type functionality
Automatically detect CW signals in the baseband
- initialize
do
- get input buffer (512 samples * 1/Fs) (Fs=4000 Hz)
- calculate FFT
- find peaks in power spectrum Ps
- Fpeak = peak_detect(Ps,delta)
- integrate Fpeak over N timeslots (64 .. 128 ms ? )
- calculate noise floor level
- noisemax => frequency bins from 1 to first detected peak
- fbin => freq bin size
- Pxx => power spectrum
=> Nrms = sqrt(sum(Pxx(1:noisemax)*fbin)) / sqrt(f(noisemax));
- update delta & threshold
- calculate SNR of found Fpeak
- integrate Srms = sqrt(sum(Fpeak +/- 10 Hz)*fbin))
- SNR = Srms / Nrms
if (SNR > threshold )
Run decoder instance on detected signal frequency
while (timer >

Wyświetl plik

@ -58,7 +58,7 @@
int bfv; // 0
double frequency; // 600
double sample_duration; // 5
double sample_rate; // 0
double sample_rate; // 4000
double delta; // 10.0
double amplify; // 0.0
int fft; // 0
@ -275,6 +275,21 @@ void apply_window (double * data, int datalen)
return ;
} /* apply_window */
double calc_SNR(double *data, int len, double fbin)
{
double CG,NG;
int i;
for (i=0; i< len; i++) {
CG += data[i];
NG += data[i]*data[i];
}
CG = CG/N;
NG = NG/N;
}
void interp_spec (float * mag, int maglen, const double *spec, int speclen)
{
int k, lastspec = 0 ;
@ -360,9 +375,76 @@ void process_data(double x)
int rx_FFTprocess(const double *buf, int len)
{
complex z, *zp;
int n,i;
int n,i,speclen,Hz;
static int smpl_ctr = 0;
static double FFTvalue,FFTphase =0.0;
fftw_plan plan;
double single_max,noise_sum,sig_sum,Nrms,Srms,fbin;
double time_domain[1024];
double freq_domain[1024];
double single_mag_spec[1024];
struct PEAKS p;
p.delta = params.delta;
speclen = 512;
for (i=0; i< len; i++)
time_domain[i] = buf[i];
plan = fftw_plan_r2r_1d (2*speclen, time_domain, freq_domain, FFTW_R2HC, FFTW_MEASURE | FFTW_PRESERVE_INPUT) ;
if (plan == NULL)
{ printf ("%s : line %d : create plan failed.\n", __FILE__, __LINE__) ;
exit (1) ;
} ;
// calculate FFT
apply_window (time_domain, 2*speclen) ;
fftw_execute (plan) ;
single_max = calc_magnitude (freq_domain, 2*speclen, single_mag_spec) ;
// find peaks in power spectrum Ps
// - Fpeak = peak_detect(Ps,delta)
// - integrate Fpeak over N timeslots (64 .. 128 ms ? )
peak_detect(single_mag_spec, 2*speclen, &p);
// print found freq peaks - only once
if (1 ) {
for (i=0; i <p.mxcount; i++) {
Hz = (p.mxpos[i]*(4000/2))/(speclen);
printf("peak[%d]:%f\tHz:%d\tmaxcount:%d\n",p.mxpos[i],p.mx[i],Hz,p.mxcount);
}
}
params.frequency = Hz;
/*
- calculate noise floor level
- noisemax => frequency bins from 1 to first detected peak
- fbin => freq bin size
- Pxx => power spectrum 512
=> Nrms = sqrt(sum(Pxx(1:noisemax)*fbin)) / sqrt(f(noisemax));
- update delta & threshold
*/
fbin = 4000./1024;
noise_sum = 0.;
for (i = 10; i<p.mxpos[0]-10; i++) {
noise_sum += single_mag_spec[i];
}
printf("\n noise_sum:%f bins:%d",noise_sum,p.mxpos[0]-10);
Nrms = sqrt(noise_sum* fbin)/sqrt(Hz);
sig_sum = 0.;
for (i = p.mxpos[0]-5; i< p.mxpos[0]+5; i++) {
sig_sum += single_mag_spec[i];
}
Srms = sqrt (sig_sum*fbin);
printf("\n SNR = %5.2f S:%f ss:%f N:%f Hz:%d", Srms/Nrms, Srms, sig_sum,Nrms,Hz);
/* - calculate SNR of found Fpeak
- integrate Srms = sqrt(sum(Fpeak +/- 10 Hz)*fbin))
- SNR = Srms / Nrms
*/
while (len-- > 0) {
// convert CW signal to baseband

Wyświetl plik

@ -57,7 +57,7 @@ struct TREE { // Tree structure to decode dit/dah sequence to corresponding char
{55,00,"Z"}, // --..
{57,00,"Q"}, // --.-
{54,00,"Ö"}, // ---. Ö
{56,57,"Š"}, // ---- Š
{56,57,"*----*"}, // ---- Š
{00,00,"5"}, // .....
{00,00,"4"}, // ....-
{00,60,"*...-.*"}, // ...-.
@ -68,36 +68,39 @@ struct TREE { // Tree structure to decode dit/dah sequence to corresponding char
{00,00,"2"}, // ..---
{00,00,"*.-...*"}, // .-...
{00,00,"e"}, // .-..-
{00,63,"+"}, // .-.-.
{00,00,"*.-.--*"}, // .-.--
{00,63,"<AR>"}, // .-.-.
{00,00,"*"}, // .-.--
{00,00,"*.--..*"}, // .--..
{59,00,"a"}, // .--.-
{00,00,"*.---.*"}, // .---.
{00,00,"1"}, // .----
{00,00,"6"}, // -....
{61,00,"="}, // -...-
{61,00,"<BT>"}, // -...-
{00,00,"/"}, // -..-.
{00,00,"*-..--*"}, // -..--
{00,00,"*-.-..*"}, // -.-..
{00,00,"^H"}, // -.-.-
{00,00,"~N"}, // -.--.
{00,00,"<KN>"}, // -.--.
{00,00,"8"}, // ---..
{00,00,"7"}, // --...
{00,00,"9"}, // ----.
{00,00,"0"}, // -----
{00,00,"?"}, // ..--..
{00,00,"@"}, // .--.-.
{00,00,"SK"}, // ...-.-
{00,00,"<SK>"}, // ...-.-
{00,62,"*-...-.*"}, // -...-.
{00,00,"BK"}, // -...-.-
{00,00,"."} // .-.-.-
{00,00,"<BK>"}, // -...-.-
{00,00,"."}, // .-.-.-
{00,65,"*--..-*"}, // --..-
{00,00,","}, // --..--
{00,00,"'"} // .----.
};
//***********************************************************************************
// (c) 2013 AG1LE Mauri Niininen
// (c) 2013,2014 AG1LE Mauri Niininen
//
//
int morse::transl_(int *ltr)

Plik binarny nie jest wyświetlany.