Tuesday 13 February 2018

Bat Call Logger: implementing pre-capture

My bat call logger uses a very simple/crude means to trigger recording.


This seems to work, but a few recordings are blank, as if the triggering signal has stopped before the recorder kicked in.


By having a pre-capture function, I should be able to capture a sequence before the trigger takes affect.

My original system for capturing recordings uses a Gambas program to simply count detected pulses within a short time-frame. Typically I'm looking for (say) 50 transitions within a 50ms window, where a transition is a change from negative to positive or positive to negative.

I figured that this 'window' needed to be short in order to get a reasonably fast reaction time. The threshold (the number of transitions to trigger a recording) was arrived at by trial an error. I am rather surprised that it works as well as it does. But when I get a blank recording I know that the bat detector has produced an output, although the logger was not quick enough to capture it.

The output from the bat detector that I use for this trigger is the received frequency divided by 8. So in order to create a trigger, I'm clocking up a minimum of 50 transition x 8 / 2 = 200cycles within a 50ms window. Which is approximately the equivalent of 200 x 1000/50 = 4kHz.

This figure of 4kHz looks much too low, as most of the bat signals of interest are above 20kHz. However the problem is that these high frequency bat calls are typically very short in duration. For example (using data from "British Bat Calls" by Jon Russ) a typical common pipistrelle call may have a peak frequency of 47kHz but only have a duration of between 3 - 9ms. If my maths is correct, this means each call may contain roughly between 140 to 420 cycles. Don't forget the output used is divided-by-8 and I'm using transitions, so this means a count range of only 35 to 106.

Bat Call Data Jon Russ


In addition, as my software is not synchronised to the bat call, I may only catch a fraction of this call and not accumulate enough pulses to trigger capture. Or I might miss the first call (burst of signal) but get lucky with a subsequent call within the sequence (in the case of a common pipistrelle, the call may get repeated at 50 to 200ms intervals).

There are clearly many shortcomings with my simple approach to capture, but if I can save a recording before the trigger point as well as after the trigger, at least I can see what I would otherwise have missed.

the implementation


My Bat Call Logger consists of a bat detector and a Raspberry Pi logger running some simple Gambas code (see earlier posts via "Bats" selector at top of page). Pre-capture is achieved by making continual short recordings and only saving the one before and the one after a trigger point.

As the Raspberry Pi uses an SD card, I record initially to system RAM and then copy just the required pre-recordings to the SD card. This saves a lot of unnecessary write/erase operations which may limit the life of the SD card.

The easy way to save a file to RAM is to first create a RAM drive by editing the /etc/fstab file, which just requires this additional line of text:-

tmpfs      /home/pi/ramstore      tmpfs      defaults,rw,size=20m      0      0

...then create a new directory via file manager: /home/pi/ramstore

Reboot, and then check that you can save a file to this new folder (i.e. make sure there are no permissions issues).

The recording timer in the original Gambas code has been modified, such that it now makes a short recording to RAM which is either overwritten if not required, or saved to disk (SD card).

Public Sub tmrStopRecorder_Timer()
'stop recorder when timer is allowed to timeout (i.e. timer can be extended by further activity)
Dim strRamFile As String
Dim strTempFile As String
Dim strDiskFile As String

  If IsProcessRunning("arecord") Then
    hRecorder.Kill()
    lblStatus.Text = "Listening..."
  Endif
  strRamFile = (RAM_PATH & "/" & RAM_FILE)
  If blnDetection Then
    blnDetection = False
    strTempFile = AUDIO_PATH & "/" & Format(Now(), "yyyy_mmm_dd_T_hh_nn_ss")
    strDiskFile = strTempFile & ".wav"
    hRecorder = Exec ["arecord", "-t", "wav", "-f", "S16_LE", "-c", "2", "-r", "192000", "-D", "hw:0,0", strDiskFile]

    If Exist(strRamFile) Then
     'save RAM file to disk
      Copy strRamFile To (strTempFile & "_pre.wav")
      Kill strRamFile
    Endif
    lblStatus.Text = "Recording: " & strDiskFile
  Else
    'record to RAM file
    hRecorder = Exec ["arecord", "-t", "wav", "-f", "S16_LE", "-c", "2", "-r", "192000", "-D", "hw:0,0", strRamFile]
  Endif
  
Catch
  Me.Text = "File error??? " & Error.Text
  Event(Me.Text)
End

As you can see, pre-capture files include "_pre" in the time-stamped file name.

I may now be able to increase the sample time and play around with a few ideas. As its difficult to generate a meaningful bat call simulation, I'll probably need to wait until the bats are active once again in my local area.

No comments:

Post a Comment