/* * ratecal1.cc -- Sound card sampling rate calibrator (for LINUX) * * Copyright (C) 1999-2004 Pawel Jalocha, SP9VRC * * This file is part of MT63. * * MT63 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MT63 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MT63; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // file: ratecal1.cc, modified on 29-AUG-1999 // to compile you need as well these files: // dsp.h, dsp.cc, sound.h, sound.cc, stdinr.h, stdinr.cc // // The purpose of this program is to measure the sampling rate // of a soundcard. I find the sampling rate may be off by // more than one percent which is not acceptable for // my DSP experiments. // To give an example: when I request 8000 Hz from my SoundMan (PAS16) // it tells me it can do 8007 Hz instead, but in reality it does // 7910.3 Hz => so a 90 Hz error. // I think this is a "bug" in the LiNUX PAS16 device driver // which sets the divisor to N while it should set it to N-1, // but the corrected driver makes still an error of 0.2% // so one needs the rate calibration anyway. // // The program has been tuned to work with the HF timing standards // which transmit short pulses each second. I used the signals on // 4996.0, 9996.0 and 14996.0 kHz. I set the HF receiver in the USB mode // and 1.0 kHz below the frequency to get pulses at 1000 Hz audio. // In principle any signal having a periodic envelope // with a known period can be used, so an AMTOR/SITOR station is OK, // if you change the reference period to 0.450 sec with -T0.450 option. // What counts is the envelope of the signal around the frequency // given by -F and within the bandwidth given by -B. // The calibrator will try to match the delay which gives the smallest // differential error. This procedure ussually gives you the rate // within 0.5 Hz (at 8000 Hz sampling). // // For more accuracy multiply the repetition time: for example // give -T4.0 thus 4 second reference period; a signal with period // of T is as well periodic over time = N*T where N is an integer. // If your sampling rate error is large (like with my card) // tell the program the (about) true rate with the -R option. // for example for my card I run the more precise test: // // ratecal1 -r8000 -R7910 -T4.0 -I40 -B200 // // The most precise test I have ever done was by typing: // // ratecal1 -r8000 -R7910.3 -T300 -I60.0 -B500 -D4 // // and leaving it for 10 minutes on the 14995.0 USB. // // After the calibration is done put down the two values: // the rate you request (-r) and the true rate you get. // You may try different requested rates (-r) so you get // the real rate close to what you like. // For example with my card, I need to request 8100 Hz to get // real rate of 8018.2 Hz which is closest to the 8000 Hz // which I want for my applications. // // Timing signals on 4996, 9996 and 14996 kHz are not ideally periodic // because some pulses are longer, some are doubled, etc. // This has certainly negative effect on the calibration result. // The pulses there are not transmitted all the time but according // to certain schedule thus we can not apply too long integration times too. // Still rate measurement with an error about 10^-5 is possible. // #include #include #include #include #ifdef __linux__ #include // for usleep() #endif #ifdef __FreeBSD__ #include #endif // #ifdef __MSDOS__ // #include // for delay() // #endif #include #include #include #include "stdinr.h" // raw keyboard mode #include "sound.h" // sound input/output #include "dsp.h" // sound processing // ============================================================================ /* void PrintFcmpxBuff(fcmpx_buff *Buff) { int i,len; fcmpx *data; len=Buff->Len; data=Buff->Data; for(i=0; iLen; data=Buff->Data; for(col=0,i=0; i72) { printf("\n"); col=0; } } if(col) printf("\n"); } */ // ============================================================================ // the parameters char DevName[32]=""; // the name of the sound device char UseDevice=0; int ReqRate=8000; // we request 8000 Hz sampling float DevRate=0; // the device gives us a possibly different rate float UserRate=0.0; // user provided rate (overrides the DevRate) int ReadFromFile=0; // read real audio or playback from a file char *PlaybackFile=NULL; // file to read audio from in playback mode int SaveToFile=0; // save audio to a file char *SaveFile=NULL; // file to save audio int DetectEnvelope=1; // insert envelope detector float CenterFreq=1000.0; // tone centered on 700 Hz float BandWidth=1000.0; // signal bandwidth 500 Hz int FilterLen=64; // input filter length int DecimRate=2; // decimation rate float RepTime=1.00; // 1.0 second between pulses in our timing reference float IntegTime=10.0; // integrate over 10 seconds int ScanRange=128; // we check 128 different delays // to see the best periodic match int FitRange=2; // parabole fit range around the best match int Correlate=0; // 0 => minimize differences, 1 => maximize correlation int CorrelPos=0; // correlate only rising edges of the envelope // ============================================================================ SoundDevice AudioInput; // our sound input #define BuffLen 512 // we process data in blocks short int InpBuff[BuffLen]; // the input buffer float_buff InpFloat; QuadrSplit InpSplit; // input filter, I/Q splitter, decimator float_buff EnvBuff; DelayLine EnvLine; double *IntegMid=NULL; double *IntegOut=NULL; float W1,W2,W5; // ============================================================================ int main(int argc, char *argv[]) { int arg; int ValueI; float ValueF; int err,wr,Level,InpLen; int i,s,delay; int PulsePeriod,MaxEnvLineDelay; FILE *DataLog; long LogTime,LogPeriod; float Diff,Diff1,Diff2; int InpFileNo,OutFileNo; printf("\n\ Sound card sampling rate calibrator, (c) 1999 Pawel Jalocha\n\ Made for time stations running on 4996, 9996 and 14996 kHz\n\ but in principle any station sending periodic signals should do.\n\ \n"); if(argc<=1) { printf("\ Usage: ratecal1 \n\ the options:\n\ -d input/output dsp device number or name [default = none]\n\ -d => /dev/dsp, -d1 => /dev/dsp1, etc.\n\ or: -d/dev/dsp, -d/dev/dsp1, etc.\n\ -p playback audio from a file & monitor it on -d device\n\ -s save audio to a file\n\ -r request given sampling rate from device [8000 Hz]\n\ -R the true sampling rate (if you know it already)\n\ -T