hackrf-rkt git repo

My project wasn’t big enough yet for Savannah, and I don’t like any of the other hosting options I’m familiar with, so I set up a git daemon for my libhackrf Racket bindings project:

git clone git://git.librehacker.com/pub/hackrf-rkt.git

This was something of an adventure, as (1) I found, and had to fix myself, a bug in Debian Stretch’s git-daemon-run package, and (2) the git-daemon config syntax was not quite intuitive to me, such that I had to tweak my parameters about five times while watching the system log, in order to export my repo.

Anyway, the clone should work from any IPv4 or IPv6 address, though I only tested IPv6. Let me know if there is a problem with IPv4 access.

New Project: libhackrf Racket bindings

I’m fond of my HackRF radio, but lost interest in working through GnuRadio Companion, because I don’t want to do any Python programming to extend the blocks. So I started looking into scheme bindings for libhackrf. There is a learning curve, for sure, but it appears that this shouldn’t be too difficult, using the Racket FFI. Here is some code (minus some important error checking) that pulls the hackrf_device_list, i.e., the struct containing information about what HackRF devices are currently plugged in to your USB:

#lang racket/base

(require ffi/unsafe
(define-ffi-definer define-hackrf (ffi-lib "libhackrf"))

(define-hackrf hackrf_init (_fun -> _int))
(define-hackrf hackrf_exit (_fun -> _int))

(define _hackrf_device_list_t-pointer (_cpointer 'hackrf_device_list_t))

(define-hackrf hackrf_device_list (_fun -> _hackrf_device_list_t-pointer))

(define-cstruct _hackrf_device_list_st ([serial_numbers _pointer]
                                        [usb_board_ids _pointer]
                                        [usb_device_index _pointer]
                                        [devicecount _int32]
                                        [usb_devices _pointer]
                                        [usb_devicecount _int32]))

This ties into the C API from hackrf.h (ADDAPI and ADDCALL are blank except in Windows):

struct hackrf_device_list {
	char **serial_numbers;
	enum hackrf_usb_board_id *usb_board_ids;
	int *usb_device_index;
	int devicecount;
	void **usb_devices;
	int usb_devicecount;
typedef struct hackrf_device_list hackrf_device_list_t;

extern ADDAPI int ADDCALL hackrf_init();
extern ADDAPI int ADDCALL hackrf_exit();

extern ADDAPI hackrf_device_list_t* ADDCALL hackrf_device_list();

And here is a demo function to get the device count:

(define (hackrf-device-count)
   (ptr-ref (hackrf_device_list)

With my HackRF plugged in:

racket@hackrf-ffi.rkt> (hackrf_init)
 racket@hackrf-ffi.rkt> (hackrf-device-count)

After unplugging it:

racket@hackrf-ffi.rkt> (hackrf-device-count)

Elliptic Pencil

I wanted to play around with generating an “elliptic pencil of circles” starting with the Hermatian matrices. An elliptic pencil of circles are all the circles (or some of them) which all intersect at two specific points. Here is a simple one, where the points of intersection are at (0,1) and (0,-1), or ±i in the complex plane.

You see there is the unit circle, plus the other circles branching off to each side:

The Hermatian matrix template for this particular pencil is elegant:

\begin{bmatrix} 1 & -n \\ -n & -1 \end{bmatrix}

where n is the x coordinate of the center of each circle (or the complex number center, not having an imaginary component).

Here is Racket code used to generate the plot:

(require math/array)
(require math/matrix)
(require plot)

(define (matrix-circle-radius M)
  (let ([A (array-ref M #[0 0])]
        [d (matrix-determinant M)])
    (sqrt (/ d (* -1 (* A A))))))

(define (matrix-circle-center M)
  (let ([C (array-ref M #[1 0])]
        [A (array-ref M #[0 0])])
    (/ C (* -1 A))))

(define (circle-isoline x y r c)
   (lambda (x_ y_) (sqrt (+ (sqr (- x_ x)) (sqr (- y_ y))))) r
   #:color c
   #:width 2))

(define (elipt-plot-demo)
   (map (lambda (C)
          (circle-isoline (real-part (first C))
                          (imag-part (first C))
                          (second C)
                          (list 30 160 210)
        (map (lambda (M)
               (list (matrix-circle-center M)
                     (matrix-circle-radius M)))
             (map (lambda (n)
                     (matrix-scale (array #[#[0 1] #[1 0]]) n)
                     (array #[#[1 0] #[0 -1]])))
                  (range 2.5 -3 -0.5))))
   #:x-min -5
   #:x-max 5
   #:y-min -5
   #:y-max 5
   #:width 400
   #:height 400))

Circles Common Invariant

Schwerdteger describes an interesting “invariant” relationship between any two circles:

\frac{\Delta_{12}}{\sqrt{\Delta_1} \sqrt{\Delta_2}}


\Delta_1 = | \mathfrak{C}_1 |, \Delta_2 = | \mathfrak{C}_2 |, and 2 \Delta_{12} = A_1 D_2 + A_2 D_1 - B_1 C_2 - B_2 C_1

with the circles represented as Hermitian matrices \begin{bmatrix} A & B \\ C & D \end{bmatrix}.

The point is, in the end you come up with this single number which represents whether the smaller circle is inside the first, overlapping the first, just touching the first, or outside the first. Here are the cases:

common invariant > 1 : smaller circle contained withing the greater circle

common invariant = 1 : touching from the inside

-1 > common invariant > 1 : overlapping at two points

common invariant = -1 : touching from the outside

common invariant < -1 : completely outside

Here is Racket code used for calculations and plotting:

(require math/array)
(require math/matrix)
(require plot)

(define (circle-to-matrix zC r)
  (let ([B (* -1 (conjugate zC))]
        [mzC (magnitude zC)])
    (matrix [[ 1             B                       ]
             [ (conjugate B) (- (* mzC mzC) (* r r)) ]])))

;; gothic C - 212d
;; delta - 394
(define (invariant ℭ1 ℭ2)
  (let* ([Δ1 (matrix-determinant ℭ1)]
         [Δ2 (matrix-determinant ℭ2)]
         [A1 (array-ref ℭ1 #[0 0])]
         [B1 (array-ref ℭ1 #[0 1])]
         [C1 (array-ref ℭ1 #[1 0])]
         [D1 (array-ref ℭ1 #[1 1])]
         [A2 (array-ref ℭ2 #[0 0])]
         [B2 (array-ref ℭ2 #[0 1])]
         [C2 (array-ref ℭ2 #[1 0])]
         [D2 (array-ref ℭ2 #[1 1])]
         [Δ12 (* 0.5 (+ (* A1 D2)
                        (* A2 D1)
                        (* -1 B1 C2)
                        (* -1 B2 C1)))])
    (/ Δ12 (* (sqrt Δ1) (sqrt Δ2)))))

(define (circle-isoline x y r)
   (lambda (x_ y_) (sqrt (+ (sqr (- x_ x)) (sqr (- y_ y))))) r))

(define (circles-invariant-plot x1 y1 r1 x2 y2 r2 min max)
  (let ([C1 (circle-to-matrix (make-rectangular x1 y1) r1)]
        [C2 (circle-to-matrix (make-rectangular x2 y2) r2)])
      (circle-isoline x1 y1 r1)
      (circle-isoline x2 y2 r2)
      (point-label (vector (+ min (* (- max min) 0.1))
                           (+ min (* (- max min) 0.9)))
                   (number->string (invariant C1 C2)) #:point-size 0))
     #:x-min min
     #:x-max max
     #:y-min min
     #:y-max max
     #:width 400
     #:height 400)))

Off-On Fourier Series

I have been fascinated lately with the concept of frequency spectrum and the idea that all periodic signals can be approximated by an infinite sum of sinusoidal functions. There are many introductory videos on this subject, usually titled as introductions to the Fourier transform.

As far as the actual math involved, this YouTube* video was very helpful:
Compute Fourier Series Representation of a Function

I don’t actually use the YouTube Website directly because of the massive amounts of proprietary JavaScript involved, but instead use youtube-dl to download the video.)

He converts an off-on type of function to a fourier series. After the integration, we get this:

I translated that into some plots in Racket, to give the visual idea. Say we only add in a single sinusoid:

Then, another:

And a few more:

And a lot more:

And finally, hundreds of them:

It cannot quite perfectly represent the function, because the Fourier series adds an extra point in between the switch from off to on (and back), whereas the original just jumps from 0 to 1 (and back).

Here is the Racket code for those interested (I did not bother to optimize):

#lang racket

(require plot)

(define (pulse x l)
  (letrec ([pulse_ 
            (lambda (acc n)
              (if (> n l) acc
                   (+ acc
                      (/ (* 2
                            (sin (* (+ (* 2 n) 1) pi x)))
                         (* (+ (* 2 n) 1) pi)))
                      (+ n 1))))])
    (pulse_ 0.5 0)))
(define (pulseplot l)
   (function (lambda (x) (pulse x l)) -1 3)))