Captain's Universe Home
Captain's Universe Home
Cosmic Ray Muon DetectorTeleGarden Pages
Time on MarsBryophyllum Plants
Jupiter Radio AstronomyAncient Pages
Salzburg Tourist GuideEarth Magnetometer
  H O M E     AJAX & MORE     LINUX & MORE     RTAI     XENOMAI     ADEOS IPIPE      
    JAVA & BROWSERS     *NIX     ELECTRONICS     REVIEWS     ARTEMIA     FAIRY SHRIMP      



Spectrograms with the FFTW FFT-Spectrograph library and GNUplot on Linux

FFTW (fftw.org) is a very nice library to perform FFT (Fast Fourier Transforms).
This page presents a quick hack to perform a FFT over a wav-file.



The C-program reads the data from the wav-file, performs the FFT and writes the raw data and the FFT values to "data.raw" and "data.dat". The perl script invokes GNUplot - GNUplot uses "data.dat" to plot the spectrum as PS (postscript) and PNG image file. This is a very convenient way to perform FFT periodically, i.e. as a spectrum analyzer cron job or other means of batch processing data.

The wav-file used in this example is available here (187kB).
(sound-sample source: MPIfR LOPES Project)

Compile fftux.c with compile.sh. Download the wav-sample and save it into the directory with fftux.c. Run "fftux" - this will produce data.raw and data.dat. Run "generate-plots.pl" - this will produce "data.ps" and "data.png".

If all went well, you get this PNG-image with the power spectrum: (the original au-file had a sampling rate of only 4000/s, hence the limitation of the plot to 2000Hz)
Spectrogram with the FFTW FFT-Spectrograph library and GNUplot




fftux.c:
// FFTW demo with wav file
// (C) 2005 www.captain.at

#include <stdio.h>
#include <stdlib.h>
#include <fftw3.h>

static double *rdata = NULL, *idata = NULL;
static fftw_plan rplan, iplan;
static int last_fft_size = 0;

double A[8192];
int n = 8192;

int i,m,k;
char erg[35];
char erg2[35];
double absval;
int is16bitfile = 1;

int main() {
	double cc;
	int v, val, val2;
	char inc[n];
	FILE *infile;
	FILE *file;
	FILE *file2;
	int samplerate = 44100;
	int bandwidth = samplerate / 2;
	int nhalf = n / 2;
	double correction = (double)samplerate / (double)n;

	infile = fopen("theevent-zoom.wav", "r");
	file = fopen("data.dat", "w");
	file2 = fopen("data.raw", "w");
	// skip wav file header
	fgets(inc,37,infile);
	fgets(inc,9,infile);

	// read data and fill "A"-array
	for (v=0;v<n;v++) {
		val = fgetc(infile);
		if (is16bitfile) {
			val2 = fgetc(infile);
			if (val2 > 127) { val2 = val2 - 255; }
			A[v] = 256*val2 + val;
		} else {
			A[v] = val;
		}
		sprintf(erg2, "%d %f\n", v, A[v]);
		fputs(erg2, file2);
	}
	
	// prepare fft with fftw
	rdata = (double *)fftw_malloc(n * sizeof(double));
	idata = (double *)fftw_malloc(n * sizeof(double));
	// create the fftw plan
	rplan = fftw_plan_r2r_1d(n, rdata, idata, FFTW_R2HC, FFTW_FORWARD); 

	// we have no imaginary data, so clear idata
	memset((void *)idata, 0, n * sizeof(double));
	// fill rdata with actual data
	for (i = 0; i < n; i++) { rdata[i] = A[i]; }
	// make fft
	fftw_execute(rplan);
	
	// post-process FFT data: make absolute values, and calculate
	//   real frequency of each power line in the spectrum
	m = 0;
	for (i = 0; i < (n-2); i++) {
		absval = sqrt(idata[i] * idata[i]);
		cc = (double)m * correction;
		sprintf(erg, "%f %f\n", cc, absval);
		fputs(erg, file);
		m++;
	}

	// housekeeping
	fclose(file);
	fclose(file2);
	fclose(infile);
	fftw_destroy_plan(rplan);
	fftw_free(rdata);
	fftw_free(idata);
	return 1;
}
compile.sh: (shell script to compile fftux.c)
#!/bin/sh
gcc -o fftux fftux.c -lfftw3 -lm




generate-plots.pl: (perl script to generate plots)
#!/usr/bin/perl

# Generate postscript and png plot with GNUplot
# (C) 2005 www.captain.at

# set custom font path
$ENV{GDFONTPATH} = "/usr/share/fonts/truetype/ttf-bitstream-vera/";

# GNUPLOT POSTSCRIPT
open (GNUPLOT, "|gnuplot");
print GNUPLOT <<EOPLOT;
set term post color "Courier" 12
set output "data.ps"
set size 1 ,1
set nokey
set data style line
set xlabel "frequency [Hz]" font "Courier,14"
set xrange [0:2000]
set yrange [0:4000000]
set title "FFT" font "Courier,14"
set grid xtics ytics
set xtics 100
plot "data.dat" using 1:2 w lines 1
EOPLOT
close(GNUPLOT);

# GNUPLOT PNG
open (GNUPLOT, "|gnuplot");
print GNUPLOT <<EOPLOT;
set term png small xFFFFFF font "VeraMono" 8
set output "data.png"
set size 1 ,1
set nokey
set data style line
set xlabel "frequency [Hz]" font "VeraMono,10"
set xrange [0:2000]
set yrange [0:4000000]
set title "FFT" font "VeraMono,10"
set grid xtics ytics
set xtics 100
plot "data.dat" using 1:2 w lines 1
EOPLOT
close(GNUPLOT);


Last-Modified: Sat, 04 Feb 2006 16:03:16 GMT

Google
 
Web www.captain.at
go to top
© 1996-2010 . All rights reserved.
No reproduction, distribution, publishing or transmission of the copyrighted materials at this site is permitted. Policy
go to top