Notes on audio capture trials using a BT878

Last modified Tuesday, 22-Jul-2008 18:00:53 UTC
I'm just jotting these notes down as I go along, so refresh from time to time to get the latest progress...

Hardware
[root@sb ~]# cat /proc/cpuinfo
...
processor       : 3
vendor_id       : GenuineIntel
cpu family      : 15
model           : 4
model name      : Intel(R) Xeon(TM) CPU 3.20GHz
stepping        : 1
cpu MHz         : 3193.937
cache size      : 1024 KB
...
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge \
                  mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 \
                  ss ht tm pbe nx lm pni monitor ds_cpl cid xtpr
bogomips        : 6373.37

Linux version
[root@sb ~]# cat /proc/version
Linux version 2.6.9-1.667smp (bhcompile@tweety.build.redhat.com) \
(gcc version 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)) \
#1 SMP Tue Nov 2 14:59:52 EST 2004

Card installed, unmodified
[root@sb rh]# lspci
...
06:00.0 Multimedia video controller: Brooktree Corporation Bt878 \
        Video Capture (rev 02)
06:00.1 Multimedia controller: Brooktree Corporation Bt878 \
        Audio Capture (rev 02)

[root@sb ~]# cd /proc/asound
[root@sb asound]# cat cards
0 [Bt878          ]: Bt87x - Brooktree Bt878
                     Brooktree Bt878 at 0xd0001000, irq 209

[root@sb asound]# ls card0
id  oss_mixer  pcm0c  pcm1c

[root@sb asound]# cat card0/pcm0c/info
card: 0
device: 0
subdevice: 0
stream: CAPTURE
id: Bt87x Digital
name: Bt87x Digital
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1

[root@sb asound]# cat card0/pcm1c/info
card: 0
device: 1
subdevice: 0
stream: CAPTURE
id: Bt87x Analog
name: Bt87x Analog
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1

Modules - Linux has kindly figured out which modules to load - phew!
[root@sb ~]# lsmod | grep snd
snd_bt87x              16649  0 
snd_pcm_oss            50809  0 
snd_mixer_oss          20929  1 snd_pcm_oss
snd_pcm                89669  2 snd_bt87x,snd_pcm_oss
snd_timer              27077  1 snd_pcm
snd                    54821  5 snd_bt87x,snd_pcm_oss,snd_mixer_oss,\
                                snd_pcm,snd_timer
soundcore              12961  1 snd
snd_page_alloc         13641  2 snd_bt87x,snd_pcm

Default mixer settings,
[root@sb ~]# amixer -c 0
Simple mixer control 'FM',0
  Capabilities: cswitch cswitch-joined cswitch-exclusive
  Capture exclusive group: 0
  Capture channels: Mono
  Mono: Capture [off]
Simple mixer control 'Mic/Line',0
  Capabilities: cswitch cswitch-joined cswitch-exclusive
  Capture exclusive group: 0
  Capture channels: Mono
  Mono: Capture [off]
Simple mixer control 'Capture',0
  Capabilities: cvolume
  Capture channels: Mono
  Limits: Capture 0 - 15
  Mono: Capture 0 [0%]
Simple mixer control 'Capture Boost',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [off]
Simple mixer control 'TV Tuner',0
  Capabilities: cswitch cswitch-joined cswitch-exclusive
  Capture exclusive group: 0
  Capture channels: Mono
  Mono: Capture [on]

Use amixer to turn the line input on, and bring up line and capture gains:-
[root@sb ~]# amixer -c 0 sset 'Mic/Line',0 60% unmute cap
Simple mixer control 'Mic/Line',0
  Capabilities: cswitch cswitch-joined cswitch-exclusive
  Capture exclusive group: 0
  Capture channels: Mono
  Mono: Capture [on]

[root@sb ~]# amixer -c 0 sset 'Capture',0 15
Simple mixer control 'Capture',0
  Capabilities: cvolume
  Capture channels: Mono
  Limits: Capture 0 - 15
  Mono: Capture 15 [100%]

Quick trial using my rxr program
http://abelian.org/vlf/README.txt
Will use the 2nd device of the card, 'hw:0,1', which is the analogue device.
[root@sb rh]#  rxr -d 'hw:0,1' -r 32000 -rd 1
starting device hw:0,1
requested sample rate: 32000
rate min 119466 max 448000
BAILOUT: cannot set channel count (Invalid argument)

The sample rates are there! But rxr always tries to read the card in stereo mode even when running just one channel - will have to alter that to deal with this 'mono only' device.

Quick alteration to rxr, added a -cm 1 option to specify mono operation of the soundcard, try again...
starting device hw:0,1
requested sample rate: 32000
rate min 119466 max 448000
actual sample rate: 119466
rawfile 20080722-075301_119466
rms 0.1392 0.0000   max 0.2356 0.0000
rms 0.1428 0.0000   max 0.2368 0.0000
rms 0.1427 0.0000   max 0.2283 0.0000
rms 0.1427 0.0000   max 0.2355 0.0000
rms 0.1427 0.0000   max 0.2349 0.0000
rms 0.1427 0.0000   max 0.2359 0.0000
rms 0.1428 0.0000   max 0.2378 0.0000

The above is with a 1.4kHz tone at 35mV RMS into the line input. The driver has overriden my request for 32k sample rate and applied its min rate of 119466. The 50mV peak signal shows 0.238 of full scale, so the input will clip (with gain set at 60%) at about 200mV peak.

Now with line input shorted,
rms 0.0098 0.0000   max 0.0320 0.0000
rms 0.0097 0.0000   max 0.0312 0.0000
rms 0.0095 0.0000   max 0.0194 0.0000
rms 0.0098 0.0000   max 0.0310 0.0000
S/N ratio of the 35mV 1.4kHz tone is therefore 20 * log10( 0.143/0.01) which is about 23dB, not bad considering the RMS is taken over the full bandwidth.

Sig gen reconnected, now at 55kHz, 35mV RMS,
rms 0.1173 0.0000   max 0.1992 0.0000
rms 0.1174 0.0000   max 0.2033 0.0000
rms 0.1174 0.0000   max 0.1976 0.0000
rms 0.1174 0.0000   max 0.1973 0.0000
rms 0.1174 0.0000   max 0.1932 0.0000
rms 0.1175 0.0000   max 0.2079 0.0000

Nice, only 20 * log10( 0.117/0.143) = -1.7dB at 55kHz compared with 1.4kHz.
[root@sb ~]# top
top - 09:25:42 up  2:14,  3 users,  load average: 0.05, 0.04, 0.00
Tasks:  79 total,   1 running,  78 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.3% us,  0.7% sy,  0.0% ni, 98.9% id,  0.1% wa,  0.0% hi,  0.0% si
Mem:   1033444k total,  1029652k used,     3792k free,   227604k buffers
Swap:        0k total,        0k used,        0k free,   511576k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
 2796 root      15   0  8556 5072 2628 S  2.0  0.5   0:45.87 rxr
 4099 root      16   0  2388  944 1664 R  0.3  0.1   0:01.21 top

Fine, only 2% of a 3.2GHz cpu is occupied by rxr running at 119k/sec.

Now restarting rxr at the max soundcard rate, sig gen still at 55kHz, 35mV RMS:
[root@sb raw]#  rxr -d 'hw:0,1' -cm 1 -r 448000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 448000
rate min 119466 max 448000
actual sample rate: 448000
rawfile 20080722-082856_448000
rms 0.1385 0.0000   max 0.2200 0.0000
rms 0.1389 0.0000   max 0.2310 0.0000
rms 0.1389 0.0000   max 0.2279 0.0000
rms 0.1389 0.0000   max 0.2290 0.0000

And the CPU load at this sample rate is
[root@sb ~]# top
top - 09:33:46 up  2:22,  3 users,  load average: 0.14, 0.13, 0.04
Tasks:  79 total,   1 running,  78 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2% us,  2.1% sy,  0.0% ni, 96.9% id,  0.8% wa,  0.0% hi,  0.0% si
Mem:   1033444k total,   551876k used,   481568k free,   196304k buffers
Swap:        0k total,        0k used,        0k free,   280796k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 4869 root      16   0  7796 5068 2628 S  8.6  0.5   0:25.34 rxr
 5141 root      16   0  1884  944 1664 R  0.7  0.1   0:00.02 top

Oh boy this thing eats disk space when recording raw,
[root@sb ~]# ls -l /raw
total 1020948
drwxr-xr-x   2 root root      4096 Jul 22 09:28 .
drwxr-xr-x  34 root root      4096 Jul 22 07:11 ..
-rw-r--r--   1 root root 510550016 Jul 22 09:28 20080722-075301_119466.1
-rw-r--r--   1 root root 533823488 Jul 22 09:38 20080722-082856_448000.1
-rw-r--r--   1 root root     25853 Jul 22 09:38 20080722.log

Yikes, I've clocked up a Gbyte in about 30 mins of operation! Here's a spectrum,


Wonder how many of those spikes are coming from the signal generator. I'll add a second trace with the input terminated in a 50 ohm dummy load:-


Well, disconnecting the Thurlby Thandar has lowered the noise floor a few dB. Nice and flat up to 200kHz by the looks of it.
rxr's log file reports two soundcard overruns in 1400 seconds of operation at 448k/sec. Maybe the driver's buffer sizes need a bit of a tweak but I'll live with it for now.

Okay let's connect a VLF receiver, bypassing the isolating transformer in the shack,
rms 0.6589 0.0000   max 1.0000 0.0000
rms 0.8040 0.0000   max 1.0000 0.0000
rms 0.8025 0.0000   max 1.0000 0.0000
rms 0.7414 0.0000   max 1.0000 0.0000
rms 0.7856 0.0000   max 1.0000 0.0000

Hmm, clipping! Will have to tweak the line input gain ... had to put in an attenuator and set the capture gain to 20%.
rms 0.1957 0.0000   max 0.8816 0.0000
rms 0.1979 0.0000   max 0.8444 0.0000
rms 0.1952 0.0000   max 0.8296 0.0000
rms 0.1929 0.0000   max 0.8276 0.0000
rms 0.1927 0.0000   max 0.8292 0.0000
rms 0.1923 0.0000   max 0.8280 0.0000

And here's the spectrum!


Obviously there's not much coming down the cable from the VLF receiver above about 25kHz or so, the aggressive high-frequency roll-off built into the receiver is doing its job - unfortunately! But we can see what looks like the BBC at around 198kHz.
Is that MSF that we can see at 60kHz? Here's a close look at around 60kHz,


Either we're not getting anything from the antenna at 60kHz, or the BT878 sample rate is way off. Here are the alpha signals,


at 11910, 12650, and 14880. They seem pretty close.

Will adjourn and set up a suitable antenna to feed the BT878 directly. We should at least get a good signal at 60kHz from MSF.

Why can't I see MSF? Mystery solved, http://www.npl.co.uk/server.php?show=ConWebDoc.1001 "The annual 48 hour shutdown of the MSF service will take place over the period 08:00 BST 22nd July 2008 to 08:00 BST 24th July"

So there, no MSF, what good timing!

I dragged an old loop antenna out of the shed and set that up in the garden,


Coil is a couple of hundred metres of cheap speaker wire, frame is 1 metre per side, 53mH, 30 ohms, and the coax back to the BT878 is 1.67nF. There is no resonance because of the low (I guess 600 ohms?) input Z of the line input. It's held up by tent pegs and string.

Here's the spectrum



Let's try DCF at 77.5 kHz


which reads 77.6kHz on this BT787, so +0.13% sample rate error.
How about HBG at 75kHz? Nothing shows when I plot that part of the spectrum.
The BBC transmitter on 198kHz shows up very well,



The peak shows at 198.248 on the BT878, an error of +0.125%.
Here's the lower part of the band,



An immense spectrum of hum harmonics, worse than I expected, even though the antenna is right next to the house. I wonder just how linear this card is. From the signal generator test earlier, the 2nd and 3rd harmonics were about 30dB down, but TTI generator isn't any cleaner than that.

Here are the overall signal levels reported by rxr,
rms 0.0116 0.0000   max 0.0557 0.0000
rms 0.0118 0.0000   max 0.0650 0.0000
rms 0.0117 0.0000   max 0.0509 0.0000
rms 0.0120 0.0000   max 0.0594 0.0000

As you can see, we need about another 20dB of gain in order to make use of the card's full dynamic range. This antenna needs to go down into the field on a long coax, and a 30dB preamp will just do nicely to drive a long cable.

There's a bunch of strong signals between 60khz and 70kHz, can anyone help ID them?



A quick look at the source for the BT878 driver reveals that my version doesn't have the CONFIG_SND_BT87X_OVERCLOCK option mentioned in http://www.linuxhq.com/kernel/v2.6/11/Documentation/sound/alsa/Bt87x.txt
But no worries, inspecting the code, it is easy to see how the sample rates are fiddled to go higher, ... from bt87x.c,
       static ratnum_t analog_clock = {
                .num = 1792000,
                .den_min = 4,
                .den_max = 15,
                .den_step = 1
        };
Obviously the thing uses a master clock at 1792 kHz and allowable divisors are from 4 to 15, giving 448k to 119.466k. We just need to alter the '4' to a '1' :)

But first I must download the entire kernel source - just so I can recompile bt87x ... there we go:
[root@sb ~]# ls -l linux*
-rw-r--r--  1 root root 45930201 Jul 22 15:48 linux-2.6.9.tar.gz

There we go, the entire linux kernel source in 46Mbytes - beat that M$ :)
Now, just unpack, copy in my current kernel config, and recompile just the modules...
[root@sb ~]# tar xzf linux-2.6.9.tar.gz
[root@sb ~]# cd linux*
[root@sb linux-2.6.9]# cp /boot/config-2.6.9-1.667smp .config
[root@sb linux-2.6.9]# make modules

Well, that didn't work, there's a complaint when I insmod the freshly built snd-bt87x, I guess I'll have to go get the *exact* kernel revision, my fault for being lazy and trying shortcuts!

Ah, here we are, kernel-2.6.9-1.667.src.rpm from Red Hat...
[root@sb ~]# rpm -i ./kernel-2.6.9-1.667.src.rpm
[root@sb ~]# cd /usr/src/redhat/SPECS
[root@sb SPECS]# rpmbuild -bp --target=i686 kernel-2.6.spec
[root@sb SPECS]# cd /usr/src/redhat/BUILD/kernel-2.6.9
[root@sb kernel-2.6.9]# cp -rf linux-2.6.9 /root
[root@sb kernel-2.6.9]# cd /root/linux-2.6.9
[root@sb linux-2.6.9]# cp /boot/config-2.6.9-1.667smp .config
[root@sb linux-2.6.9]# make modules
[root@sb linux-2.6.9]# rmmod snd-bt87x
[root@sb linux-2.6.9]# insmod sound/pci/snd-bt87x.ko


Okay, the freshly built bt878 driver module is loaded, and after re-issuing the 'amixer' commands, a quick check to make sure it is working...
[root@sb ~]# rxr -d 'hw:0,1' -cm 1 -r 448000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 448000
rate min 119466 max 448000
actual sample rate: 448000
rawfile 20080722-164643_448000
rms 0.0108 0.0000   max 0.0440 0.0000
rms 0.0110 0.0000   max 0.0483 0.0000
rms 0.0109 0.0000   max 0.0508 0.0000


Looks good. Now to change a 4 to a 2 in bt87x.c,
[root@sb ~]# cd linux-2.6.9
[root@sb linux-2.6.9]# vi sound/pci/bt87x.c
[root@sb linux-2.6.9]# make modules
[root@sb linux-2.6.9]# rmmod snd-bt87x
[root@sb linux-2.6.9]# insmod sound/pci/snd-bt87x.ko

And now the moment of truth, rxr should report now the extended range of sample rates...
[root@sb ~]#  rxr -d 'hw:0,1' -cm 1 -r 448000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 448000
rate min 119466 max 448000
actual sample rate: 448000
rawfile 20080722-165332_448000

Darn, it doesn't. Hmm, better take a closer look at the driver source ... ah, there's another line that needs altering:-
static snd_pcm_hardware_t snd_bt87x_analog_hw = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
        .rates = SNDRV_PCM_RATE_KNOT,
        .rate_min = 119466,
        .rate_max = 448000,
        .channels_min = 1,
        .channels_max = 1,
        .buffer_bytes_max = 255 * 4092,
        .period_bytes_min = 32,
        .period_bytes_max = 4092,
        .periods_min = 2,
        .periods_max = 255,
};

A quick edit of .rate_max to 896000 and another make modules... and a reload of the driver...
[root@sb ~]# rxr -d 'hw:0,1' -cm 1 -r 448000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 448000
rate min 119466 max 896000
actual sample rate: 448000
rawfile 20080722-165758_448000
rms 0.0226 0.0000   max 0.0425 0.0000
rms 0.0112 0.0000   max 0.0594 0.0000
rms 0.0113 0.0000   max 0.0613 0.0000

That's better, it's showing the new high rate. Now we'll get rxr to try it...
[root@sb ~]# rxr -d 'hw:0,1' -cm 1 -r 896000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 896000
rate min 119466 max 896000
actual sample rate: 896000
rawfile 20080722-165941_896000
rms 0.0024 0.0000   max 0.0208 0.0000
rms 0.0008 0.0000   max 0.0031 0.0000
rms 0.0008 0.0000   max 0.0040 0.0000
rms 0.0008 0.0000   max 0.0669 0.0000
rms 0.0008 0.0000   max 0.0075 0.0000
rms 0.0008 0.0000   max 0.0036 0.0000

Well, it took the command, but what's happened to the signal? The RMS has dropped to a background level. I don't think we'll get a spectrum out of that. Oh,....



Well, we got something, but we've lost about 20dB or thereabouts overall.

Let's try the divisor 3,
[root@sb ~]# rxr -d 'hw:0,1' -cm 1 -r 597333 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 597333
rate min 119466 max 896000
actual sample rate: 597333
rawfile 20080722-170532_597333
rms 0.0026 0.0000   max 0.0107 0.0000
rms 0.0041 0.0000   max 0.0172 0.0000
rms 0.0041 0.0000   max 0.0332 0.0000
rms 0.0041 0.0000   max 0.0169 0.0000
rms 0.0042 0.0000   max 0.4163 0.0000
rms 0.0040 0.0000   max 0.0465 0.0000
rms 0.0040 0.0000   max 0.0208 0.0000

Well we've got a bit more signal now, and the spectrum is



Well, it's running, but the RMS is down about a factor of 3 or more below the level when clocking at 448k. I guess the sound card's input filter is not designed for it. Still, there may be a useful S/N ratio up above 224k. Have to break off this now and contemplate making a preamp/line driver so we can get a decent VLF level into the card. Then we'll see how it looks.

Wait, I'll just do one more run with the dummy load attached, at the full rate...
[root@sb ~]# rxr -d 'hw:0,1' -cm 1 -r 896000 -rd 1
soundcard mode: mono
starting device hw:0,1
requested sample rate: 896000
rate min 119466 max 896000
actual sample rate: 896000
rawfile 20080722-172158_896000
rms 0.0014 0.0000   max 0.0067 0.0000
rms 0.0007 0.0000   max 0.0025 0.0000
rms 0.0007 0.0000   max 0.0025 0.0000
rms 0.0007 0.0000   max 0.0020 0.0000
rms 0.0007 0.0000   max 0.0022 0.0000


which gives the graph, combined with the earlier run at 896k,



Some funny little resonances at 275kHz and 377kHz, sharper with a 50 ohm load than with the antenna connected. Crikey do we have to worry about getting an impedance match into the line input in order to get a flat response above 224kHz?

Hey - and I didn't crash or have to reboot the PC at all :)