Search code examples
roptimizationmaximization

optimization algorithm for circular data


Background: I am interested in localizing a sound source from a suite of audio recorders. Each audio array consists of 6 directional microphones spaced evenly every 60 degrees (0, 60, 120, 180, 240, 300 degrees). I am interested in finding the neighboring pair of microphones with the maximum set of signal strengths. Data consists of a time stamp, antenna number and bearing, and signal strength. Below I have attached a simplified dataset.

    df <- data.frame(ant.bearing = seq(0,300, by=60), sig = c(98, 60, 44, 67, 58, 91), ts=1)

Goals: From this dataset, I would like use a function to extract the two neighboring antennas with the maximal set of signal strengths (i.e. antennas with bearings 0 and 300 degrees in above sample code) while accounting for the fact that this data is circular in nature and antennas 0 and 300 are neighbors. Output would be the two rows of data that satisfy the above task e.g. rows 1 and 6 in the above case.

What I've tried:

direction.finder <- function(dat){
    # finding bearing with max signal strength
    max <- dat[dat$sig == max(dat$sig),][1,]

    # finding signal strengths of neighbor antennas and pulling out which has highest

    left  = dat[dat$ant.bearing==max$ant.bearing-60,]
    right = dat[dat$ant.bearing==max$ant.bearing+60,]

    if(max$ant.bearing==0)
        left = dat[dat$ant.bearing==300,]
    if(max$ant.bearing==300)
        right = dat[dat$ant.bearing==0,]

    sub = right

    if(left$sig > right$sig)
        sub = left

    dat <- rbind(max, sub)
} 

This current function serves as an okay workaround for my task but its not ideal. Any suggestions or tips for improving the functionality of my code would be greatly appreciated.


Solution

  • I would compute all the pairs of rows in df:

    (pairs <- cbind(1:nrow(df), c(2:nrow(df), 1)))
    #      [,1] [,2]
    # [1,]    1    2
    # [2,]    2    3
    # [3,]    3    4
    # [4,]    4    5
    # [5,]    5    6
    # [6,]    6    1
    

    You can find the best pairing with which.max:

    (best.row <- which.max(df$sig[pairs[,1]] + df$sig[pairs[,2]]))
    # [1] 6
    

    Finally, you can look up the corresponding antenna bearings:

    df$ant.bearing[pairs[best.row,]]
    # [1] 300   0
    

    If you had missing values, you could slightly adjust the code by creating NA values for the missing entries:

    # Data
    df <- data.frame(ant.bearing = seq(0,180, by=60), sig = c(44, 67,88, 52), ts=2)
    #   ant.bearing sig ts
    # 1           0  44  2
    # 2          60  67  2
    # 3         120  88  2
    # 4         180  52  2
    
    (pairs <- cbind(1:6, c(2:6, 1)))
    #      [,1] [,2]
    # [1,]    1    2
    # [2,]    2    3
    # [3,]    3    4
    # [4,]    4    5
    # [5,]    5    6
    # [6,]    6    1
    
    sig <- rep(NA, 6)
    sig[1+df$ant.bearing/60] <- df$sig
    sig
    # [1] 44 67 88 52 NA NA
    

    Now the rest of the process is similar:

    (best.row <- which.max(sig[pairs[,1]] + sig[pairs[,2]]))
    # [1] 2
    60*(pairs[best.row,]-1)
    # [1]  60 120