brainwagon "There is much pleasure in useless knowledge." — Bertrand Russell

26Jul/080

Writing a tunable bandpass filter…

Today, I decided to code up a little test of something that I've been meaning to do for quite some time: to write an implementation of a tunable bandpass filter. The algorithm is actually pretty darned simple, at least if you have a couple of pieces of code available. Let's say you want to create a 500hz wide filter. You begin by designing a low pass filter with a cutoff at 250hz or so. If you don't know how to do that, you can start by using this excellent webpage, which allows you to enter a filter specification and which dumps out code for the filtering operation. Once you have this, the algorithm is pretty simple: you generate two signals (which we will call I and Q) by multiplying your real-valued input signal by a sine and cosine at the frequency you wish to be the center of the bandpass. You then low pass filter each I and Q signals, and then remultiply them again by the sine and cosine as before. You then add the two channels back together, and voila! You're done. Here's the spectrogram of an original signal:


And then after filtering...

It works! Here's the basic code, compressed down. It uses the libsndfile library to read and write .wav files.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sndfile.h>
SNDFILE*sf_inp,*sf_out;SF_INFO sf_info_inp;SF_INFO sf_info_out;
#define NZEROS 6
#define NPOLES 6
#define GAIN 1.602073263e+06
double cx[NZEROS+1],sx[NZEROS+1];double cy[NPOLES+1],sy[NPOLES+1];static double
filter(double xv[NZEROS+1],double yv[NPOLES+1],double n){xv[0]=xv[1];xv[1]=xv[2
];xv[2]=xv[3];xv[3]=xv[4];xv[4]=xv[5];xv[5]=xv[6];xv[6]=n/GAIN;yv[0]=yv[1];yv[1
]=yv[2];yv[2]=yv[3];yv[3]=yv[4];yv[4]=yv[5];yv[5]=yv[6];yv[6]=(xv[0]+xv[6])+6*(
xv[1]+xv[5])+15*(xv[2]+xv[4])+20*xv[3]+(-0.4675793776*yv[0])+(3.1600883661*yv[1
])+(-8.9237117766*yv[2])+(13.4798197900*yv[3])+(-11.4902571630*yv[4])+(
5.2416002121*yv[5]);return yv[6];}
#define BUFFERSIZE (8192)
main(){int i;double din[BUFFERSIZE];double dout[BUFFERSIZE];sf_count_t total,n;
double ang=0.0,dang;double s,c;sf_inp=sf_open("input.wav",SFM_READ,&sf_info_inp
);sf_info_out.channels=1;sf_info_out.samplerate=sf_info_inp.samplerate;
sf_info_out.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;sf_out=sf_open("output.wav",
SFM_WRITE,&sf_info_out);dang=2.0*M_PI*1000.0/sf_info_inp.samplerate;total=0;
while(total<sf_info_inp.frames){n=sf_read_double(sf_inp,din,BUFFERSIZE);for(i=0
;i<n;i++){s=sin(ang);c=cos(ang);dout[i]=2.0*(c*filter(cx,cy,c*din[i])+s*filter(
sx,sy,s*din[i]));ang+=dang;ang=fmod(ang,2.0*M_PI);}sf_write_double(sf_out,dout,
n);total+=n;}sf_close(sf_inp);sf_close(sf_out);}
Filed under: General No Comments
26Jul/080

Magnetic Loop Antennas

DJ1YFK suggested this site for info on small magnetic loop antennas. I should check this out.

Magnetic Loop Antennas, Magnetic Loop Info, How to Build A Magnetic Loop, W2BRI Loops

Filed under: General No Comments
26Jul/080

VLF Paper Archive

Just stashing a link to some papers on VLF radio that came across a mailing list.

Index of /~talves/VLF

Filed under: General No Comments