/******************************************************************************!
* \file plot-gnuplot.c
* \author Sebastien Beaugrand
* \sa http://beaugrand.chez.com/
* \copyright CeCILL 2.1 Free Software license
******************************************************************************/
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <complex.h>
#include <fftw3.h>
#include "debug.h"
static unsigned int gLoop = 1;
static fftw_complex* gPlotSamples = NULL;
static fftw_complex* gPlotSamplesFFT = NULL;
static fftw_complex* gPlotOutputFFT = NULL;
static pthread_t gThreadPlotFFT = 0;
static sem_t gSemFFT;
static FILE* gPlotFileFFT = NULL;
static pthread_t gThreadPlotSamples = 0;
static sem_t gSemSamples;
static FILE* gPlotFileSamples = NULL;
static unsigned int gPlotSamplesMin = 0;
static unsigned int gPlotSamplesMax = 0;
#ifdef PLOT_DEBUG
static FILE* gPlotDebug = NULL;
#endif
/******************************************************************************!
* \fn threadPlotSamples
******************************************************************************/
void*
threadPlotSamples(void* arg)
{
static unsigned int last;
unsigned int pos;
arg = arg;
for (;;) {
sem_wait(&gSemSamples);
if (! gLoop) {
break;
}
if (gPlotSamplesMin == 0 ||
gPlotSamplesMin < last) {
fprintf(gPlotFileSamples, "unset multiplot\n");
fprintf(gPlotFileSamples, "set multiplot\n");
} else {
--gPlotSamplesMin;
}
fprintf(gPlotFileSamples, "plot '-' w l\n");
for (pos = gPlotSamplesMin;
pos < gPlotSamplesMax; ++pos) {
fprintf(gPlotFileSamples,
"%u %f\n", pos, cimag(gPlotSamples[pos]));
}
fprintf(gPlotFileSamples, "e\n");
last = gPlotSamplesMax;
}
return NULL;
}
/******************************************************************************!
* \fn threadPlotFFT
******************************************************************************/
void*
threadPlotFFT(void* arg)
{
const unsigned int SAMPLES_SIZE = *((unsigned int*) arg);
unsigned int samplesPos;
double duree;
for (;;) {
sem_wait(&gSemFFT);
if (! gLoop) {
break;
}
duree = (creal(gPlotSamplesFFT[SAMPLES_SIZE - 1]) -
creal(gPlotSamplesFFT[0]));
DEBUG("%d par seconde\n", (int) (SAMPLES_SIZE / duree));
fprintf(gPlotFileFFT, "plot '-' w l\n");
# ifdef PLOT_DEBUG
fprintf(gPlotDebug, "plot '-' w l, (%f-%f)*x/%u+%f\n",
creal(gPlotSamplesFFT[(SAMPLES_SIZE >> 1) - 1]),
creal(gPlotSamplesFFT[0]),
(SAMPLES_SIZE >> 1),
creal(gPlotSamplesFFT[0]));
# endif
for (samplesPos = 1; samplesPos < (SAMPLES_SIZE >> 1); ++samplesPos) {
fprintf(gPlotFileFFT, "%f %f\n",
samplesPos / duree,
cabs(gPlotOutputFFT[samplesPos]));
# ifdef PLOT_DEBUG
fprintf(gPlotDebug, "%f\n",
creal(gPlotSamplesFFT[samplesPos]));
# endif
}
fprintf(gPlotFileFFT, "e\n");
# ifdef PLOT_DEBUG
fprintf(gPlotDebug, "e\n");
# endif
}
return NULL;
}
/******************************************************************************!
* \fn plotInit
******************************************************************************/
void
plotInit(unsigned int samplesSize,
const char* min,
const char* max)
{
static unsigned int SAMPLES_SIZE = 0;
gPlotFileFFT = popen("gnuplot", "w");
setlinebuf(gPlotFileFFT);
fprintf(gPlotFileFFT, "set mxtics\n");
fprintf(gPlotFileFFT, "set xtics out 10\n");
fprintf(gPlotFileFFT, "set xrange[%s:%s]\n", min, max);
gPlotFileSamples = popen("gnuplot", "w");
setlinebuf(gPlotFileSamples);
fprintf(gPlotFileSamples, "set xrange[0:%u]\n", samplesSize);
fprintf(gPlotFileSamples, "set yrange[-10:2500]\n");
fprintf(gPlotFileSamples, "set multiplot\n");
# ifdef PLOT_DEBUG
gPlotDebug = popen("gnuplot", "w");
setlinebuf(gPlotDebug);
# endif
if (SAMPLES_SIZE == 0) {
SAMPLES_SIZE = samplesSize;
}
if (pthread_create(&gThreadPlotSamples, NULL,
&threadPlotSamples, (void*) &SAMPLES_SIZE) != 0) {
ERROR("pthread_create");
exit(EXIT_FAILURE);
}
sem_init(&gSemSamples, 0, 0);
if (pthread_create(&gThreadPlotFFT, NULL,
&threadPlotFFT, (void*) &SAMPLES_SIZE) != 0) {
ERROR("pthread_create");
exit(EXIT_FAILURE);
}
sem_init(&gSemFFT, 0, 0);
}
/******************************************************************************!
* \fn plotShowSamples
******************************************************************************/
void
plotShowSamples(fftw_complex* samples,
unsigned int min,
unsigned int max)
{
int semValue;
sem_getvalue(&gSemSamples, &semValue);
if (semValue <= 0) {
gPlotSamples = samples;
gPlotSamplesMin = min;
gPlotSamplesMax = max;
sem_post(&gSemSamples);
}
}
/******************************************************************************!
* \fn plotShowFFT
******************************************************************************/
void
plotShowFFT(fftw_complex* samples,
fftw_complex* output)
{
int semValue;
sem_getvalue(&gSemFFT, &semValue);
if (semValue <= 0) {
gPlotSamplesFFT = samples;
gPlotOutputFFT = output;
sem_post(&gSemFFT);
}
}
/******************************************************************************!
* \fn plotQuit
******************************************************************************/
void
plotQuit()
{
void* res;
if (gPlotFileFFT != 0) {
fclose(gPlotFileFFT);
}
if (gPlotFileSamples != 0) {
fclose(gPlotFileSamples);
}
# ifdef PLOT_DEBUG
if (gPlotDebug != 0) {
fclose(gPlotDebug);
}
# endif
gLoop = 0;
sem_post(&gSemSamples);
pthread_join(gThreadPlotSamples, &res);
sem_post(&gSemFFT);
pthread_join(gThreadPlotFFT, &res);
}