iq_svcl: test -> master (FFT csv)

pull/43/head
Zilog80 2021-04-27 18:55:55 +02:00
rodzic 22ef6e1370
commit 2ce01d8b9a
10 zmienionych plików z 686 dodań i 111 usunięć

Wyświetl plik

@ -23,16 +23,23 @@ receive IF stream from baseband IQ via TCP, default `PORT=1280 (iq_svcl.h)`<br /
&nbsp;&nbsp;&nbsp;&nbsp; `-0.5 < fq < 0.5`: (relative) frequency, `fq=frequency/sr` <br />
&nbsp;&nbsp;&nbsp;&nbsp; `<if_sr>`: IF sample rate <br />
&nbsp;&nbsp;&nbsp;&nbsp; `<bo>=8,16,32`: output/IF bits per (real) sample (u8, s16 or f32) <br />
down-converts up to `MAX_FQ=(4+1) (iq_base.h)` channels/signals. More signals than number of CPUs/cores is not recommended.<br />
down-converts up to `MAX_FQ=(4+1) (iq_base.h)` channels/signals. (On older CPUs, more signals than number of CPU cores is not recommended.)<br />
(Note: If the baseband sample rate has no appropriate factors (e.g. if prime), the IF sample rate might be high and IF-processing slow.)<br />
One channel can be used for scanning, `--fft <fft.txt>` makes FFT (2 seconds average).
The FFT is saved in `<fft.txt>` as `<fq>;<dB>`, approx. 200 Hz per bin.<br />
One channel can be used for scanning, e.g. `./iq_server --fft_avg <m> <fft_avg.csv>` makes *m* rows of avg-FFT (FFT_AVG=2 seconds average), and
this channel will be reused for client FFT requests. Only one channel/thread can be used for FFT/scanning. A client can request a new FFT,
if the last FFT has finished.<br />
There are two kinds of FFTs, `fft_all` and `fft_avg`. `fft_avg` integrates over FFT_AVG=2 seconds and can be used for signal peak scanning.
For waterfall display, `--fft_all <m> <fft_all.csv>` produces *m*\*FFT_AVG\*FFT_FPS/2 rows of FFT (FFT_AVG seconds, FFT_FPS/2 per sec).
The FFT is saved in `<fft.csv>` as<br />
&nbsp;&nbsp; `sec.ms,freq_min,freq_max,Hz/bin,N_bins, db_1,...,db_N`<br />
approx. 200 Hz per bin.
Choose `filename="-"` for `stdout`.<br />
If no output bps is chosen (`--bo [8,16,32]`), the IF bps is equal to the baseband bps. It is recommended to use
`--bo 32` (i.e. float32) output, then no quantization noise is introduced when converting from internal float32 samples.<br />
- Ex.2<br />
[terminal 1]<br />
`T1$ rtl_sdr -f 403.0M -s 1920000 - | ./iq_server --fft fft_server.txt --bo 32 - 1920000 8`<br />
`T1$ rtl_sdr -f 403.0M -s 1920000 - | ./iq_server --fft_avg 1 fft_server.csv --bo 32 - 1920000 8`<br />
[terminal 2]<br />
`T2$ ./iq_client --freq -0.3125 | ./m10mod -c -vv --IQ 0.0 - 48000 32`<br />
[terminal 3]<br />
@ -41,7 +48,17 @@ receive IF stream from baseband IQ via TCP, default `PORT=1280 (iq_svcl.h)`<br /
`T4$ ./iq_client -1` &nbsp;&nbsp; (*close channel 1*)<br />
`T4$ ./iq_client --stop` &nbsp;&nbsp; (*close all clients and stop server*)<br />
The `iq_server` `--fft` option immediately starts reading the IQ stream (so buffering is reduced).<br />
`./iq_client --fft <fft_cl.txt>` can also request FFT.<br />
The IF sample rate `if_sr` is at least 48000 such that the baseband sample rate `sr` is a multiple of `if_sr`.
- The `iq_server` FFT options immediately start reading the IQ stream (so buffering is reduced).<br />
`./iq_client <fft_opt> <m> <fft_cl.txt>`, where `<fft_opt>=--fft_avg_cl` or `--fft_all_cl`, requests FFT from the server.<br />
(`<fft_opt>=--fft_avg_sv/--fft_all_sv` would save the FFT at the server, but only if `./iq_server --enable_clsv_out`.)<br />
The IF sample rate `if_sr` is at least 48000 and such that the baseband sample rate `sr` is a multiple of `if_sr`.
- Ex.3<br />
[terminal 1]<br />
`T1$ rtl_sdr -f 404550k -s 2048000 - | ./iq_server --fft_avg 1 fft_avg.csv --bo 32 - 2048000 8`<br />
(scan FFT: `./scan_fft fft_avg.csv`)<br />
[terminal 3]<br />
`T3$ ./iq_client --fft_all_cl -1 - | python plot_fft_ani.py 3 -`<br />
![FFT image](fft3-1.png "FFT")

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 212 KiB

Wyświetl plik

@ -34,7 +34,10 @@ typedef struct {
double xlt_fq;
float complex *blk;
int used;
//
int fft;
int stop_fft;
int fft_num;
} thd_t;
@ -97,6 +100,7 @@ typedef struct {
thd_t thd;
int fd;
char *fname;
FILE *fpo;
} thargs_t;

Wyświetl plik

@ -4,6 +4,27 @@
*
* gcc -O2 iq_client.c -o iq_client
*
* usage:
* (request IF IQ samples)
* ./iq_client [--ip <ip_adr>] [--port <pn>] --freq <fq> # -0.5 < fq < 0.5
*
* (request FFT)
* ./iq_client <fft_opt> <m> <filename> # FFT csv output
* <fft_opt>:
* --fft_avg_cl # client out
* --fft_all_cl # client out
* --fft_avg_sv # server out (if iq_server --enable_clsv_out)
* --fft_avg_sv # server out (if iq_server --enable_clsv_out)
* <m>:
* _avg_: m avg-FFTs
* _all_: m*FFT_FPS/2 FFTs
* m = -1 : continuous FFT output
* <filename>:
* csv filename ("-": stdout)
*
* ./iq_client -<n> # close client <n>
* ./iq_client --stop # close all clients, stop server
*
* author: zilog80
*/
@ -49,17 +70,24 @@ int main(int argc, char *argv[]) {
}
else serv_port = port;
}
else if (strcmp(*argv, "--fft0") == 0) {
sprintf(sendln, "%s", "--fft0");
}
else if (strcmp(*argv, "--fft") == 0) {
sprintf(sendln, "%s", "--fft");
++argv;
if (*argv) {
fname_fft = *argv;
else if (strncmp(*argv, "--fft", 5) == 0) {
char *arg_fft = *argv;
int fft_num = 0;
int opt_fft_cl = 0;
if (strncmp(arg_fft+5, "_avg", 4) == 0) opt_fft_cl = OPT_FFT_AVG;
else if (strncmp(arg_fft+5, "_all", 4) != 0) return -1;
if (strncmp(arg_fft+5+4, "_cl", 3) == 0) {
opt_fft_cl |= OPT_FFT_CLNT;
re = 2;
}
else if (strncmp(arg_fft+5+4, "_sv", 3) == 0) opt_fft_cl |= OPT_FFT_SERV;
else return -1;
re = 2;
++argv;
if (*argv) fft_num = atoi(*argv); else return -1;
++argv;
if (*argv) fname_fft = *argv; else return -1;
//sprintf(sendln, "%s_%s_%s", "--fft", (opt_fft_cl & OPT_FFT_AVG) ? "avg" : "all", (opt_fft_cl & OPT_FFT_CLNT) ? "cl" : "sv");
sprintf(sendln, "%s %d %s", arg_fft, fft_num, fname_fft);
}
else if (strcmp(*argv, "--freq") == 0) {
++argv;
@ -155,7 +183,9 @@ int main(int argc, char *argv[]) {
else if ( re == 2 )
{
// fft data
FILE *fpo = fopen(fname_fft, "wb");
FILE *fpo = NULL;
if (fname_fft[0] == '-') fpo = stdout;
else fpo = fopen(fname_fft, "wb");
if (fpo != NULL) {
memset(recvln, 0, LINELEN+1);

Wyświetl plik

@ -7,6 +7,24 @@
*
* (gcc -O2 iq_client.c -o iq_client)
*
* usage:
* ./iq_server [--enable_clsv_out] [--port <pn>] [iq_baseband.wav]
* no wav-file: stdin
*
* ./iq_server [--bo <b>] - <sr> <bs> [iq_baseband.raw]
* <b>=8,16,32 bit client/IF output
*
* ./iq_server <fft_opt> <m> <filename> [iq_baseband.wav] # FFT csv output
* <fft_opt>:
* --fft_avg
* --fft_all
* <m>:
* _avg: m avg-FFTs
* _all: m*FFT_FPS/2 FFTs
* m = -1 : continuous FFT output
* <filename>:
* csv filename ("-": stdout)
*
* author: zilog80
*/
@ -27,13 +45,13 @@
#include "iq_svcl.h"
#include "iq_base.h"
#define FFT_AVG 2 // fft_avg: integrate FFT_AVG seconds, 2*FFT_FPS FFTs
#define FFT_FPS 16 // fft_all: output (ca.) FFT_FPS/2 per sec
#define FPOUT stderr
#define OPT_FFT_SERV 1 // server
#define OPT_FFT_CLSV 2 // server (client request)
#define OPT_FFT_CLNT 3 // server -> client
static int option_dbg = 0;
static int option_clsv_out = 0;
static int tcp_eof = 0;
@ -275,21 +293,82 @@ static void *thd_IF(void *targs) { // pcm_t *pcm, double xlt_fq
return NULL;
}
#define FFT_SEC 2
#define FFT_FPS 20
static int fft_txt_prn(FILE *fpo, dft_t *dft, float *db) {
int j;
fprintf(fpo, "# <freq/sr>;<dB> ## sr:%d , N:%d\n", dft->sr, dft->N);
for (j = dft->N/2; j < dft->N/2 + dft->N; j++) {
fprintf(fpo, "%+11.8f;%7.2f\n", bin2fq(dft, j % dft->N), db[j % dft->N]);
}
return 0;
}
static int fft_txt_tcp(int fd, dft_t *dft, float *db) {
char sendln[LINELEN+1];
int sendln_len;
int j, l;
snprintf(sendln, LINELEN, "# <freq/sr>;<dB> ## sr:%d , N:%d\n", dft->sr, dft->N);
sendln_len = strlen(sendln);
l = write(fd, sendln, sendln_len);
for (j = dft->N/2; j < dft->N/2 + dft->N; j++) {
memset(sendln, 0, LINELEN+1);
snprintf(sendln, LINELEN, "%+11.8f;%7.2f\n", bin2fq(dft, j % dft->N), db[j % dft->N]);
sendln_len = strlen(sendln);
l = write(fd, sendln, sendln_len);
}
return 0;
}
static int fft_csv_prn(FILE *fpo, dft_t *dft, float *db, double t_sec) {
int j;
fprintf(fpo, "%7.3f, ", t_sec);
fprintf(fpo, "%d, %d, ", (int)bin2freq(dft, dft->N/2), (int)bin2freq(dft, dft->N/2 - 1));
fprintf(fpo, "%.2f, ", dft->sr/(double)dft->N);
fprintf(fpo, "%d, ", dft->N);
for (j = dft->N/2; j < dft->N/2 + dft->N; j++) {
fprintf(fpo, "%7.2f%c", db[j % dft->N], j < dft->N/2 + dft->N-1 ? ',' : '\n');
}
return 0;
}
static int fft_csv_tcp(int fd, dft_t *dft, float *db, double t_sec) {
char sendln[LINELEN+1];
int sendln_len;
int j, l;
snprintf(sendln, LINELEN, "%7.3f, %d, %d, %.2f, %d, ",
t_sec, (int)bin2freq(dft, dft->N/2), (int)bin2freq(dft, dft->N/2 - 1), dft->sr/(double)dft->N, dft->N);
sendln_len = strlen(sendln);
l = write(fd, sendln, sendln_len);
for (j = dft->N/2; j < dft->N/2 + dft->N; j++) {
memset(sendln, 0, LINELEN+1);
snprintf(sendln, LINELEN, "%7.2f%c", db[j % dft->N], j < dft->N/2 + dft->N-1 ? ',' : '\n');
sendln_len = strlen(sendln);
l = write(fd, sendln, sendln_len);
}
return 0;
}
static void *thd_FFT(void *targs) {
thargs_t *tharg = targs;
pcm_t *pcm = &(tharg->pcm);
FILE *fpo = NULL;
char *fname_fft = "db_fft.txt";
int k;
int bitQ = 0;
float complex *z = NULL;
float *db = NULL;
float *all_rZ = NULL;
float *avg_rZ = NULL;
float *avg_db = NULL;
@ -312,7 +391,6 @@ static void *thd_FFT(void *targs) {
dsp.bps_out = pcm->bps_out;
//(dsp.thd)->fft = 1;
if (option_dbg) {
fprintf(stderr, "init FFT buffers\n");
}
@ -326,6 +404,8 @@ static void *thd_FFT(void *targs) {
z = calloc(dsp.decM+1, sizeof(float complex)); if (z == NULL) goto exit_thread;
db = calloc(dsp.DFT.N+1, sizeof(float)); if (db == NULL) goto exit_thread;
all_rZ = calloc(dsp.DFT.N+1, sizeof(float)); if (all_rZ == NULL) goto exit_thread;
avg_rZ = calloc(dsp.DFT.N+1, sizeof(float)); if (avg_rZ == NULL) goto exit_thread;
avg_db = calloc(dsp.DFT.N+1, sizeof(float)); if (avg_db == NULL) goto exit_thread;
@ -334,12 +414,16 @@ static void *thd_FFT(void *targs) {
int len = dsp.DFT.N / dsp.decM;
int mlen = len*dsp.decM;
int sum_n = 0;
int sec = FFT_SEC;
int fft_step = dsp.sr_base/(dsp.DFT.N*FFT_FPS);
int sum_fft = 0;
int avg_sec = FFT_AVG;
int fft_step = (int)(dsp.sr_base/(double)(dsp.DFT.N*FFT_FPS) + 0.5);
int n_fft = 0;
int th_used = 0;
int readSamples = 1;
int n_out = 0;
bitQ = 0;
while ( bitQ != EOF )
{
@ -367,65 +451,95 @@ static void *thd_FFT(void *targs) {
n++;
if (n == len) { // mlen = len * decM <= DFT.N
n_fft += 1;
if ((dsp.thd)->fft && sum_n*n_fft*mlen < sec*dsp.sr_base && n_fft >= fft_step)
if ( (dsp.thd)->fft )
{
for (j = 0; j < mlen; j++) {
dsp.DFT.Z[j] *= dsp.DFT.win[j];
if ((dsp.thd)->fft_num == 0)
{
if ( tharg->fpo ) { fclose(tharg->fpo); tharg->fpo = NULL; }
else if ( tharg->fd > STDIN_FILENO ) { close(tharg->fd); tharg->fd = -1; }
(dsp.thd)->fft = 0;
}
while (j < dsp.DFT.N) dsp.DFT.Z[j++] = 0.0; // dft(Z[...]) != 0
raw_dft(&(dsp.DFT), dsp.DFT.Z);
n_fft += 1;
for (j = 0; j < dsp.DFT.N; j++) avg_rZ[j] += cabs(dsp.DFT.Z[j]);
if (sum_n*n_fft*mlen < avg_sec*dsp.sr_base && n_fft >= fft_step) {
n_fft = fft_step;
sum_n++;
n_fft = 0;
}
if (sum_n*fft_step*mlen >= sec*dsp.sr_base) {
for (j = 0; j < dsp.DFT.N; j++) avg_rZ[j] /= dsp.DFT.N*(float)sum_n;
for (j = 0; j < dsp.DFT.N; j++) avg_db[j] = 20.0*log10(avg_rZ[j]+1e-20);
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: FFT>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
if ( (dsp.thd)->fft == OPT_FFT_CLNT ) { // send FFT data to client
char sendln[LINELEN+1];
int sendln_len;
int l;
snprintf(sendln, LINELEN, "# <freq/sr>;<dB> ## sr:%d , N:%d\n", dsp.DFT.sr, dsp.DFT.N);
sendln_len = strlen(sendln);
l = write(tharg->fd, sendln, sendln_len);
for (j = dsp.DFT.N/2; j < dsp.DFT.N/2 + dsp.DFT.N; j++) {
memset(sendln, 0, LINELEN+1);
snprintf(sendln, LINELEN, "%+11.8f;%7.2f\n", bin2fq(&(dsp.DFT), j % dsp.DFT.N), avg_db[j % dsp.DFT.N]);
sendln_len = strlen(sendln);
l = write(tharg->fd, sendln, sendln_len);
if (sum_fft == 0) {
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: FFT_START>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
}
}
else { // save FFT at server
if ( (dsp.thd)->fft == OPT_FFT_SERV ) fname_fft = tharg->fname;
else /* OPT_FFT_CLSV */ fname_fft = "db_fft_cl.txt";
fpo = fopen(fname_fft, "wb");
if (fpo != NULL) {
fprintf(fpo, "# <freq/sr>;<dB> ## sr:%d , N:%d\n", dsp.DFT.sr, dsp.DFT.N);
for (j = dsp.DFT.N/2; j < dsp.DFT.N/2 + dsp.DFT.N; j++) {
fprintf(fpo, "%+11.8f;%7.2f\n", bin2fq(&(dsp.DFT), j % dsp.DFT.N), avg_db[j % dsp.DFT.N]);
for (j = 0; j < mlen; j++) {
dsp.DFT.Z[j] *= dsp.DFT.win[j];
}
while (j < dsp.DFT.N) dsp.DFT.Z[j++] = 0.0; // dft(Z[...]) != 0
raw_dft(&(dsp.DFT), dsp.DFT.Z);
for (j = 0; j < dsp.DFT.N; j++) {
float rZ = cabs(dsp.DFT.Z[j]);
avg_rZ[j] += rZ;
all_rZ[j] += rZ;
}
if ( (sum_fft&1)==1 && ((dsp.thd)->fft & OPT_FFT_AVG) == 0 ) {
double t_sec = sum_fft*n_fft*mlen / (double)dsp.sr_base;
for (j = 0; j < dsp.DFT.N; j++) { // if sum_fft odd,
db[j] = 20.0*log10(0.5*all_rZ[j]/dsp.DFT.N+1e-20); // 0.5: rZ_0+rZ_1
all_rZ[j] = 0.0f;
}
// sec.ms, freq_min, freq_max, Hz/bin, N_bins, db_1, ..., db_N
if ( tharg->fpo ) { // save FFT at server
fft_csv_prn(tharg->fpo, &(dsp.DFT), db, t_sec);
}
else if ( tharg->fd > STDIN_FILENO ) {
fft_csv_tcp(tharg->fd, &(dsp.DFT), db, t_sec);
}
fclose(fpo);
}
else {
fprintf(stderr, "error: open %s\n", fname_fft);
}
}
if ( (dsp.thd)->fft != OPT_FFT_SERV ) close(tharg->fd);
(dsp.thd)->fft = 0;
sum_n = 0;
sum_n++;
sum_fft++;
n_fft = 0;
}
if (sum_n*fft_step*mlen >= avg_sec*dsp.sr_base) {
float nN = 1.0/(dsp.DFT.N*(float)sum_n);
for (j = 0; j < dsp.DFT.N; j++) {
avg_db[j] = 20.0*log10(nN*avg_rZ[j]+1e-20);
avg_rZ[j] = 0.0f;
}
if ( (dsp.thd)->fft & OPT_FFT_AVG ) {
double t_sec = sum_fft*fft_step*mlen / (double)dsp.sr_base;
if ( tharg->fpo ) { // send FFT data to client
fft_csv_prn(tharg->fpo, &(dsp.DFT), avg_db, t_sec);
}
else if ( tharg->fd > STDIN_FILENO ) {
fft_csv_tcp(tharg->fd, &(dsp.DFT), avg_db, t_sec);
}
}
n_out++;
if ((dsp.thd)->fft_num > 0 && n_out >= (dsp.thd)->fft_num)
{
if ( tharg->fpo ) { fclose(tharg->fpo); tharg->fpo = NULL; }
else if ( tharg->fd > STDIN_FILENO ) { close(tharg->fd); tharg->fd = -1; }
(dsp.thd)->fft = 0;
sum_fft = 0;
n_out = 0;
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: FFT_STOP>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
}
sum_n = 0;
}
}
#ifdef FFT_READ_SINK_MIN
@ -445,12 +559,39 @@ static void *thd_FFT(void *targs) {
if ( (dsp.thd)->used == 0 )
{
(dsp.thd)->fft = 0;
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: CLOSE>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
break;
}
if ( (dsp.thd)->stop_fft > 0 )
{
if ( tharg->fpo ) { fclose(tharg->fpo); tharg->fpo = NULL; }
else if ( tharg->fd > STDIN_FILENO ) { close(tharg->fd); tharg->fd = -1; }
(dsp.thd)->fft = 0;
(dsp.thd)->stop_fft = 0;
sum_fft = 0;
sum_n = 0;
n_out = 0;
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: STOP_FFT>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
}
}
if ((dsp.thd)->fft_num < 0)
{
if ( tharg->fpo ) { fclose(tharg->fpo); tharg->fpo = NULL; }
else if ( tharg->fd > STDIN_FILENO ) { close(tharg->fd); tharg->fd = -1; }
(dsp.thd)->fft = 0;
pthread_mutex_lock( (dsp.thd)->mutex );
fprintf(FPOUT, "<%d: FFT_STOP>\n", (dsp.thd)->tn);
pthread_mutex_unlock( (dsp.thd)->mutex );
}
if (bitQ == EOF) {
@ -465,6 +606,8 @@ static void *thd_FFT(void *targs) {
exit_thread:
if (z) { free(z); z = NULL; }
if (db) { free(db); db = NULL; }
if (all_rZ) { free(all_rZ); all_rZ = NULL; }
if (avg_rZ) { free(avg_rZ); avg_rZ = NULL; }
if (avg_db) { free(avg_db); avg_db = NULL; }
@ -496,6 +639,8 @@ int main(int argc, char **argv) {
char tcp_buf[TCPBUF_LEN];
int th_used = 0;
int tn_fft = -1;
int opt_fft = 0;
int fft_num = 0;
pcm_t pcm = {0};
@ -510,11 +655,15 @@ int main(int argc, char **argv) {
for (k = 0; k < MAX_FQ; k++) base_fqs[k] = 0.0;
// server options
++argv;
while ((*argv) && (!wavloaded)) {
if (strcmp(*argv, "--dbg") == 0) {
option_dbg = 1;
}
else if (strcmp(*argv, "--enable_clsv_out") == 0) {
option_clsv_out = 1;
}
else if (strcmp(*argv, "--port") == 0) {
int port = 0;
++argv;
@ -524,7 +673,11 @@ int main(int argc, char **argv) {
}
else serv_port = port;
}
else if (strcmp(*argv, "--fft") == 0) {
else if (strncmp(*argv, "--fft", 5) == 0) {
char *arg_fft = *argv;
if (strncmp(arg_fft+5, "_avg", 4) == 0) opt_fft = OPT_FFT_SERV | OPT_FFT_AVG;
else if (strncmp(arg_fft+5, "_all", 4) == 0) opt_fft = OPT_FFT_SERV;
else return -1;
if (xlt_cnt < MAX_FQ) {
base_fqs[xlt_cnt] = 0.0;
rstype[xlt_cnt] = thd_FFT;
@ -532,6 +685,8 @@ int main(int argc, char **argv) {
xlt_cnt++;
}
++argv;
if (*argv) fft_num = atoi(*argv); else return -1;
++argv;
if (*argv) fname_fft = *argv; else return -1;
}
else if (strcmp(*argv, "-") == 0) {
@ -597,8 +752,21 @@ int main(int argc, char **argv) {
for (k = 0; k < xlt_cnt; k++) {
if (k == tn_fft) {
tharg[k].thd.fft = OPT_FFT_SERV;
tharg[k].thd.fft = opt_fft;
tharg[k].fname = fname_fft;
tharg[k].thd.fft_num = fft_num;
tharg[k].thd.stop_fft = 0;
if ( (tharg[k].thd.fft & 0xF) == OPT_FFT_SERV ) { // save FFT at server
if (fname_fft) {
if (fname_fft[0] == '-') tharg[k].fpo = stdout;
else tharg[k].fpo = fopen(fname_fft, "wb");
}
else return -1;
if (tharg[k].fpo == NULL) {
fprintf(stderr, "error: open %s\n", fname_fft);
}
}
}
tharg[k].thd.tn = k;
tharg[k].thd.tn_bit = (1<<k);
@ -686,6 +854,7 @@ int main(int argc, char **argv) {
//if (th_used == 0) break;
// client commands
if ( l > 1 ) {
char *freq = tcp_buf;
while (l > 1 && tcp_buf[l-1] < 0x20) l--;
@ -701,23 +870,76 @@ int main(int argc, char **argv) {
break;
}
else if ( strncmp(tcp_buf, "--fft", 5) == 0 ) {
opt_fft = 0;
if (strncmp(tcp_buf+5, "_avg", 4) == 0) opt_fft = OPT_FFT_AVG;
else if (strncmp(tcp_buf+5, "_all", 4) != 0) return -1;
if (strncmp(tcp_buf+5+4, "_cl", 3) == 0) opt_fft |= OPT_FFT_CLNT;
else if (strncmp(tcp_buf+5+4, "_sv", 3) == 0) {
if (option_clsv_out) opt_fft |= OPT_FFT_SERV;
else {
pthread_mutex_lock( &mutex );
fprintf(FPOUT, "<NO CLSV OUT>\n");
pthread_mutex_unlock( &mutex );
close(conn_fd);
continue;
}
}
else return -1;
if (tcp_buf+5+4+4) fft_num = atoi(tcp_buf+5+4+4); else fft_num = 0;
char *fname_fft_cl = "db_fft_cl.txt";
int opt_fft = strcmp(tcp_buf, "--fft0") == 0 ? OPT_FFT_CLSV : OPT_FFT_CLNT;
//close(conn_fd);
char *pbuf = tcp_buf;
for (pbuf = tcp_buf+5+4+4; *pbuf; pbuf++) {
if (*pbuf == ' ') break;
}
if (*pbuf == ' ') {
fname_fft_cl = pbuf+1;
}
if ( !tcp_eof )
{
if (tn_fft >= 0) {
tharg[tn_fft].thd.fft = opt_fft;
tharg[tn_fft].fname = fname_fft_cl;
tharg[tn_fft].fd = conn_fd;
if (tharg[tn_fft].thd.fft == 0) {
tharg[tn_fft].thd.fft_num = fft_num;
tharg[tn_fft].thd.stop_fft = 0;
tharg[tn_fft].fname = fname_fft_cl;
tharg[tn_fft].fd = conn_fd;
if ( (opt_fft & 0xF) == OPT_FFT_SERV ) { // save FFT at server
if (fname_fft_cl) {
if (fname_fft_cl[0] == '-') tharg[tn_fft].fpo = stdout;
else tharg[tn_fft].fpo = fopen(fname_fft_cl, "wb");
}
else return -1;
if (tharg[tn_fft].fpo == NULL) {
fprintf(stderr, "error: open %s\n", fname_fft_cl);
}
close(tharg[tn_fft].fd); tharg[tn_fft].fd = -1; // tharg[tn_fft].fd == conn_fd
}
else { // (opt_fft & 0xF) == OPT_FFT_CLNT : send FFT to client
tharg[tn_fft].fpo = NULL;
}
tharg[tn_fft].thd.fft = opt_fft;
}
else {
pthread_mutex_lock( &mutex );
fprintf(FPOUT, "<%d: FFT running>\n", tn_fft);
pthread_mutex_unlock( &mutex );
close(conn_fd);
}
}
else {
for (k = 0; k < MAX_FQ; k++) {
if (tharg[k].thd.used == 0) break;
if (tharg[k].thd.used == 0) {
if (k != tn_fft) break;
}
}
if (k < MAX_FQ) {
tharg[k].thd.fft = opt_fft;
tharg[k].thd.fft_num = fft_num;
tharg[k].thd.stop_fft = 0;
tharg[k].fname = fname_fft_cl;
tharg[k].fd = conn_fd;
tn_fft = k;
tharg[k].thd.tn = k;
tharg[k].thd.tn_bit = (1<<k);
@ -726,12 +948,26 @@ int main(int argc, char **argv) {
//tharg[k].thd.lock = &lock;
tharg[k].thd.blk = block_decMB;
tharg[k].thd.xlt_fq = 0.0;
tharg[k].pcm = pcm;
tharg[k].fd = conn_fd;
if ( (opt_fft & 0xF) == OPT_FFT_SERV ) { // save FFT at server
if (fname_fft_cl) {
if (fname_fft_cl[0] == '-') tharg[k].fpo = stdout;
else tharg[k].fpo = fopen(fname_fft_cl, "wb");
}
else return -1;
if (tharg[k].fpo == NULL) {
fprintf(stderr, "error: open %s\n", fname_fft_cl);
}
close(tharg[k].fd); tharg[k].fd = -1; // tharg[k].fd == conn_fd
}
else { // (opt_fft & 0xF) == OPT_FFT_CLNT : send FFT to client
tharg[k].fpo = NULL;
}
rbf1 |= tharg[k].thd.tn_bit;
tharg[k].thd.used = 1;
tharg[k].thd.fft = opt_fft;
pthread_create(&tharg[k].thd.tid, NULL, thd_FFT, &tharg[k]);
@ -753,9 +989,14 @@ int main(int argc, char **argv) {
else if (tcp_buf[0] == '-') { // -<n> : close <n>
int num = atoi(tcp_buf+1);
if (num >= 0 && num < MAX_FQ) {
if (num != tn_fft) {
if (num != tn_fft)
{
tharg[num].thd.used = 0;
}
else
{
tharg[num].thd.stop_fft = 1;
}
}
close(conn_fd);
}
@ -789,6 +1030,7 @@ int main(int argc, char **argv) {
rbf1 |= tharg[k].thd.tn_bit;
tharg[k].thd.used = 1;
tharg[k].thd.fft = 0;
tharg[k].thd.stop_fft = 0;
pthread_create(&tharg[k].thd.tid, NULL, thd_IF, &tharg[k]);

Wyświetl plik

@ -6,6 +6,10 @@
#include <arpa/inet.h>
#define OPT_FFT_SERV 1 // server
#define OPT_FFT_CLNT 2 // server -> client
#define OPT_FFT_AVG 0x100
#define TCPBUF_LEN 1024
#define SERV_BACKLOG 6

Wyświetl plik

@ -8,7 +8,7 @@ import matplotlib.ticker as ticker
if len(sys.argv) < 2:
print("usage:")
print("\tpython %s <fft_file>" % sys.argv[0])
print("\tpython %s <fft_file.csv>" % sys.argv[0])
sys.exit()
fft_file = sys.argv[1]
@ -18,10 +18,17 @@ if not os.path.isfile(fft_file):
sys.exit()
data = np.genfromtxt( fft_file, delimiter=';', names=['fq','db'] , skip_header=1 )
raw_data = np.genfromtxt( fft_file, delimiter=',', max_rows=1)
data1 = raw_data[:] # max_rows=2: raw_data[0,:]
print(data1)
fq = data['fq']
db = data['db']
db = data1[5:]
sr = -2.0*data1[1]
freq_min = data1[1] / sr
freq_max = data1[2] / sr
fq = np.arange(freq_min, freq_max, 1.0/(data1[4]+1))
N = len(db)
m = np.mean(db)

Wyświetl plik

@ -0,0 +1,186 @@
import os
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
if len(sys.argv) < 3:
print("usage:")
print("\tpython <1/2/3> %s <fft_all.csv>" % sys.argv[0])
sys.exit()
OPT_FFT_L = 1
OPT_FFT_W = 2
OPT_FFT_B = 3
OPT_FFT = OPT_FFT_B
if (sys.argv[1] == '1'):
OPT_FFT = OPT_FFT_L
elif (sys.argv[1] == '2'):
OPT_FFT = OPT_FFT_W
fft_file = sys.argv[2]
if (fft_file == "-"):
f = sys.stdin
else:
try:
f = open(fft_file)
except IOError:
print("error: open %s" % fft_file)
sys.exit()
FFT_FPS = 16/2
WIN_SEC = 10
win = WIN_SEC*FFT_FPS
line = f.readline()
#line = f.readline()
row = np.fromstring(line, dtype=float, sep=',')
data = row[5:]
l = len(data)
m = np.mean(data)
data5 = np.full([win,l], m)
for x in range(2, l-2):
data5[0,x] = (data[x-2]+data[x-1]+data[x]+data[x+1]+data[x+2])/5.0
min_db = np.min(data5)
max_db = np.max(data5)
sr = -2.0*row[1]
freq_min = row[1]
freq_max = row[2]
N = row[4]
limits = [freq_min/1e3, freq_max/1e3, WIN_SEC, 0.0]
fq = np.arange(freq_min/sr, freq_max/sr, 1.0/(row[4]+1))
################################################################################################
if (OPT_FFT == OPT_FFT_L):
fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(111)
ax1.set_xlim([fq[0], fq[-1]])
ax1.set_ylim([-110.0, -30.0])
lp, = ax1.plot( fq, data5[0,:], color='g', linewidth=0.4)
count = 0
def animate_lp(i):
line = f.readline()
if line:
row = np.fromstring(line, dtype=float, sep=',')
data = row[5:]
global count
count += 1
global data5
#data5 = np.roll(data5, 1, axis=0)
for x in range(2, l-2):
data5[0,x] = (data[x-2]+data[x-1]+data[x]+data[x+1]+data[x+2])/5.0
lp.set_data(fq, data5[0,:])
return [lp]
ani = animation.FuncAnimation(fig, animate_lp, interval=10, blit=True)
################################################################################################
elif (OPT_FFT == OPT_FFT_W):
fig = plt.figure(figsize=(12, 5))
ax2 = fig.add_subplot(111)
ax2.set_xlabel('Frequency (kHz)')
ax2.set_ylabel('Time (s)')
im = ax2.imshow(data5, vmin=-110.0, vmax=-50.0, extent=limits, animated=True)
ax2.set_aspect('auto')
fig.colorbar(im, orientation='vertical')
count = 0
def animate_im(i):
line = f.readline()
if line:
row = np.fromstring(line, dtype=float, sep=',')
data = row[5:]
global count
count += 1
global data5
data5 = np.roll(data5, 1, axis=0)
for x in range(2, l-2):
data5[0,x] = (data[x-2]+data[x-1]+data[x]+data[x+1]+data[x+2])/5.0
im.set_data(data5)
# update vmin/vmax
if (count % win == 0):
min_db = np.min(data5)
max_db = np.max(data5)
im.set_clim(vmin=min_db, vmax=max_db)
return [im]
ani = animation.FuncAnimation(fig, animate_im, interval=10, blit=True)
################################################################################################
else:
fig = plt.figure(figsize=(12, 8))
ax1 = fig.add_subplot(211)
ax1.set_xlim([fq[0], fq[-1]])
ax1.set_ylim([-110.0, -30.0])
ax2 = fig.add_subplot(212)
ax2.set_xlabel('Frequency (kHz)')
ax2.set_ylabel('Time (s)')
lp, = ax1.plot( fq, data5[0,:], color='g', linewidth=0.4)
im = ax2.imshow(data5, vmin=-110.0, vmax=-50.0, extent=limits, animated=True)
ax2.set_aspect('auto')
count = 0
def animate(i):
line = f.readline()
if line:
row = np.fromstring(line, dtype=float, sep=',')
data = row[5:]
global count
count += 1
global data5
data5 = np.roll(data5, 1, axis=0)
for x in range(2, l-2):
data5[0,x] = (data[x-2]+data[x-1]+data[x]+data[x+1]+data[x+2])/5.0
im.set_data(data5)
lp.set_data(fq, data5[0,:])
# update vmin/vmax
if (count % win == 0):
min_db = np.min(data5)
max_db = np.max(data5)
im.set_clim(vmin=min_db, vmax=max_db)
return [lp,im]
ani = animation.FuncAnimation(fig, animate, interval=10, blit=True)
################################################################################################
plt.show()

Wyświetl plik

@ -0,0 +1,52 @@
import os
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
if len(sys.argv) < 2:
print("usage:")
print("\tpython %s <wfft_file>" % sys.argv[0])
sys.exit()
fft_file = sys.argv[1]
if not os.path.isfile(fft_file):
print("error: %s not found" % fft_file)
sys.exit()
raw_data = np.genfromtxt( fft_file, delimiter=',')
data = raw_data[:,5:]
dim = np.shape(data)
m = np.mean(data)
data5 = np.full(dim, m)
for y in range(dim[0]):
for x in range(2, dim[1]-2):
data5[y,x] = (data[y,x-2]+data[y,x-1]+data[y,x]+data[y,x+1]+data[y,x+2])/5.0
freq_min = raw_data[0,1] / 1e3
freq_max = raw_data[0,2] / 1e3
N = raw_data[0,4]
tmin = raw_data[dim[0]-1,0]
tmax = raw_data[0,0]
limits = [freq_min, freq_max, tmin, tmax]
fig = plt.figure(figsize=(15, 5))
ax = fig.add_subplot(111)
ax.set_title('Waterfall')
ax.set_xlabel('Frequency (kHz)')
ax.set_ylabel('Time (s)')
plt.imshow(data5, extent=limits)
ax.set_aspect('auto')
plt.colorbar(orientation='vertical')
plt.show()

Wyświetl plik

@ -52,7 +52,7 @@ int main(int argc, char **argv) {
if (argv[1] == NULL) {
fprintf(stderr, "usage:\n");
fprintf(stderr, "\t%s <fft_file>\n", argv[0]);
fprintf(stderr, "\t%s <fft_avg.csv>\n", argv[0]);
return 1;
}
fp = fopen(argv[1], "rb");
@ -61,9 +61,34 @@ int main(int argc, char **argv) {
return 1;
}
memset(line, 0, LINELEN+1);
N = 0;
j = 0;
n = 0;
// sec.ms,freq_min,freq_max,Hz/bin,N_bins, ...
while ( (c = fgetc(fp)) != EOF) {
if (c == '\n') N++;
if (c == '\n') break;
if (c == ' ') continue;
if (c == ',') {
if (n == 1) {
int freq_min = atoi(line);
sr = -2*freq_min;
}
if (n == 4) {
N = atoi(line);
break;
}
n++;
memset(line, 0, LINELEN+1);
j = 0;
}
else {
line[j] = c;
j++;
}
}
db = calloc(N+1, sizeof(float)); if (db == NULL) return 2;
@ -73,20 +98,30 @@ int main(int argc, char **argv) {
intdb = calloc(N+1, sizeof(float)); if (intdb == NULL) return 2;
peak = calloc(N+1, sizeof(float)); if (peak == NULL) return 2;
fseek(fp, 0, SEEK_SET);
pbuf = fgets(line, LINELEN, fp);
p1 = strstr(line, "sr:");
if (p1) sr = atoi(p1+3);
for (n = 0; n < N; n++) {
memset(line, 0, LINELEN+1);
pbuf = fgets(line, LINELEN, fp);
p1 = strstr(line, ";"); //p2 = strstr(p1+1, ";");
if (p1) {
fq[n] = atof(line); //freq[n] = atof(p1+1);
db[n] = atof(p1+1); //atof(p2+1);
// ..., db_1,...,db_N:
memset(line, 0, LINELEN+1);
j = 0;
n = 0;
while ( (c = fgetc(fp)) != EOF) {
if (c == '\n') break;
if (c == ' ') continue;
if (c == ',') {
if (n < N) {
db[n] = atof(line);
fq[n] = -0.5 + n/(float)N;
}
n++;
memset(line, 0, LINELEN+1);
j = 0;
}
else {
line[j] = c;
j++;
}
}
f0 = N/2;
globmin = 0.0;
@ -94,14 +129,12 @@ int main(int argc, char **argv) {
float db_spike3 = 10.0;
int spike_wl3 = 3; //freq2bin(&DFT, 200); // 3 // 200 Hz
int spike_wl5 = 5; //freq2bin(&DFT, 200); // 3 // 200 Hz
//float db_spike1 = 15.0;
//int spike_wl1 = 1; //freq2bin(&DFT, 200); // 3 // 200 Hz
dx = 200.0;
if (sr) dx = sr*(fq[f0+1]-fq[f0]); //freq[f0+1]-freq[f0];
dn = 2*(int)(2400.0/dx)+1; // (odd/symmetric) integration width: 4800+dx Hz
if (option_verbose > 1) fprintf(stderr, "dn = %d\n", dn);
//for (j = 0; j < N; j++) db[j] /= (float)n;
// dc-spike (N-1,)N,0,1(,2): subtract mean/avg
// spikes in general: