Author: Hugo Marques and Annika Putt
Date: 2025-07-22

# Introduction to ORFID

#### Hugo Marques and Annika Putt

#### 2025-07-22

## Overview

ORFID is a package for compiling and summarizing passive integrated transponder (PIT) data collected using Oregon RFID (radio-frequency identification) ORMR (Oregon RFID Multi-Reader) and ORSR (Oregon RFID Single Reader) antenna readers.

## View field names

The output from Oregon RFID antenna readers is highly customizable. Available data fields and their descriptions can be viewed using `field_names()`.

    field_names()
    #>    Name                                                        Details
    #> 1   DTY Detection type, S = summary, I = individual, E = event
    #> 2   TCH Tag technology HDX, FDX, HF
    #> 3   TTY Tag type A = Animal, R = Read only, W = Writeable, P = Phantom
    #> 4   TAG Tag ID number
    #> 5   ANT Antenna number
    #> 6   ARR Arrival date and time
    #> 7   TRF Time reference G = GNSS, N = network, U = unreferenced
    #> 8   DEP Departure date and time
    #> 9   SSN Starting scan number (since midnight)
    #> 10  ESN Ending scan number
    #> 11  NCD Number of consecutive detections
    #> 12  EMP Number of empty scans preceding detection
    #> 13  LAT Latitude
    #> 14  LON Longitude
    #> 15  ALT Altitude meters
    #> 16  SIV Satellites in view
    #> 17  HDP Location horizontal accuracy (m)
    #> 18  TSS Tag signal strength
    #> 19  CPA Charge pulse amps
    #> 20  LSA Listen amps
    #> 21  EFA Effective amps
    #> 22  CPT Charge pulse time
    #> 23  LST Listen time
    #> 24  ANV Antenna voltage
    #> 25  ANA Antenna amperage
    #> 26  NOI Noise
    #> 27  DUR Duration
    #> 28  CLS Tag class
    #> 29  SPC Output one space character
    #> 30  SCD Site code

## Loading the data

ORFID requires raw (unedited) data downloaded directly from Oregon RFID ORMR and ORSR antenna readers. Data files must be delimited by tab, comma, or semicolon; space delimited data are not supported.

Data are loaded using one of three import functions:

- `import_ORFID()`: Imports detection records from ORMR and ORSR antenna readers
- `import_ORFID_events()`: Imports event data from ORMR and ORSR antenna readers
- `import_old_readers()`: Imports detection data from previous generations of Oregon RFID antenna readers

    dat <- import_ORFID(file = "~/reader_1.txt", delim = "\t")
    events <- import_ORFID_events(file = "~/reader_1.txt", delim = "\t")
    old_dat <- import_old_readers(file = "~/old_reader.txt", delim = "\t")

## Joining data into arrays

Multiple data files can be combined into an array representing all antennas within a designated study region. Individual files are combined into a list and joined using `join_multireader_data()`. A new data field is created, `LOC`, which combines the site code (`SCD`) and antenna number (`ANT`) into a unique location variable.

    reader_1 <- import_ORFID(file = "reader_1.txt", delim = "\t")
    reader_2 <- import_ORFID(file = "reader_2.txt", delim = "\t")
    reader_3 <- import_ORFID(file = "reader_3.txt", delim = "\t")

    dat_multi <- join_multireader_data(list(reader_1, reader_2, reader_3))
    #> A unique variable, LOC (location), was created by combining SCD (site code) and ANT (antenna).

## Summarize data

Data from `import_ORFID()` or `join_multireader_data()` can be summarized to view site information and tag detections.

    site_summary(dat_multi)
    #> # A tibble: 3 × 5
    #> # Groups:   LOC [3]
    #>   LOC      REC TAG_ID FIR                 LAS
    #>   <fct>  <int>  <int> <dttm>              <dttm>
    #> 1 BBB_A1  8590      7 2019-05-16 22:34:55 2019-05-17 04:59:13
    #> 2 AAA_A1   460      6 2019-05-17 04:50:52 2019-05-17 19:24:12
    #> 3 CCC_A1  1027      6 2019-10-31 09:45:56 2019-11-01 08:03:26

    tag_summary(dat_multi)
    #>
    #>         TAG: tag ID number
    #>         TTY: tag type (A = Animal (ICAR), R = Read-only, W = Writable, P = Phantom)
    #>         REC: number of detection records
    #>         FIR: first detection record
    #>         LAS: last detection record
    #>         mean_DUR: mean detection duration
    #>         first_LOC: location of first detection
    #>         last_LOC: location of last detection
    #>         count_LOC: number of antennas that detected the tag
    #>         all_LOC: character string of all antennas that detected the tag
    #>
    #> # A tibble: 13 × 10
    #>    TAG                 TTY     REC FIR                 LAS
    #>    <chr>               <chr> <int> <dttm>              <dttm>
    #>  1 "0000_000000005189" W      6408 2019-05-16 22:34:55 2019-05-17 19:23:39
    #>  2 "0000_247618116254" P      1063 2019-05-16 22:35:38 2019-05-17 02:49:55
    #>  3 "900_228000004988"  A       361 2019-05-16 23:00:02 2019-05-17 04:57:35
    #>  4 "900_228000004996"  A         8 2019-05-17 02:49:58 2019-05-17 04:55:59
    #>  5 "900_228000004991"  A         7 2019-05-17 02:50:27 2019-05-17 04:55:46
    #>  6 "0000_000000005972" W      1192 2019-05-17 02:53:47 2019-05-17 19:24:12
    #>  7 "900_230000087400"  A        11 2019-05-17 04:51:22 2019-05-17 04:59:13
    #>  8 "0000_000000004978" W      1019 2019-10-31 09:45:56 2019-11-01 08:03:26
    #>  9 "0000_000000002489" W         2 2019-10-31 13:13:02 2019-10-31 22:58:45
    #> 10 "0671_338237264481" W         1 2019-10-31 15:05:37 2019-10-31 15:05:37
    #> 11 "  0_000000002489"  A         3 2019-10-31 19:33:51 2019-11-01 04:55:33
    #> 12 "1209_450359747569" W         1 2019-10-31 23:34:07 2019-10-31 23:34:07
    #> 13 "2032_350284139216" W         1 2019-11-01 00:17:11 2019-11-01 00:17:11
    #>    mean_DUR first_LOC last_LOC count_LOC all_LOC
    #>    <drtn>   <fct>     <fct>        <int> <chr>
    #>  1 0.0 secs BBB_A1    AAA_A1           2 BBB_A1, AAA_A1
    #>  2 0.0 secs BBB_A1    BBB_A1           1 BBB_A1
    #>  3 0.7 secs BBB_A1    BBB_A1           2 BBB_A1, AAA_A1
    #>  4 1.4 secs BBB_A1    BBB_A1           2 BBB_A1, AAA_A1
    #>  5 1.1 secs BBB_A1    BBB_A1           2 BBB_A1, AAA_A1
    #>  6 0.0 secs BBB_A1    AAA_A1           2 BBB_A1, AAA_A1
    #>  7 1.5 secs AAA_A1    BBB_A1           2 AAA_A1, BBB_A1
    #>  8 0.0 secs CCC_A1    CCC_A1           1 CCC_A1
    #>  9 0.0 secs CCC_A1    CCC_A1           1 CCC_A1
    #> 10 0.0 secs CCC_A1    CCC_A1           1 CCC_A1
    #> 11 0.0 secs CCC_A1    CCC_A1           1 CCC_A1
    #> 12 0.0 secs CCC_A1    CCC_A1           1 CCC_A1
    #> 13 0.0 secs CCC_A1    CCC_A1           1 CCC_A1

## View marker tag data

Marker tags are stationary tags used to constantly monitor the effectiveness of Oregon RFID antenna readers. Marker tags are detected at regular time intervals, which are set by the user.

Data from individual marker tags can be viewed and plotted using ORFID marker tag functions. The optional `gap` argument represents the minimum time gap between detections. If `gap` is specified, only detections where the time gap was greater than `gap` are retained by `marker_tag()`, and periods where the time gap was greater than `gap` are highlighted in red by `marker_tag_plot()`. This allows the user to identify periods when marker tags were not detected as frequently as expected.

The plot object produced by `marker_tag_plot()` is a `ggplot2` object, and can be edited using additional `ggplot2` functions, such as `theme()`.

    marker_tag(dat_multi, tag = "0000_000000005972")
    #> # A tibble: 1,192 × 5
    #>    TAG               ARR                 DUR    GAP        NCD
    #>    <chr>             <dttm>              <drtn> <drtn>   <dbl>
    #>  1 0000_000000005972 2019-05-17 02:53:47 0 secs  NA secs     2
    #>  2 0000_000000005972 2019-05-17 02:53:50 0 secs 3.0 secs     2
    #>  3 0000_000000005972 2019-05-17 02:53:53 0 secs 3.0 secs     2
    #>  4 0000_000000005972 2019-05-17 02:53:56 0 secs 3.0 secs     2
    #>  5 0000_000000005972 2019-05-17 02:53:59 0 secs 2.9 secs     3
    #>  6 0000_000000005972 2019-05-17 02:54:02 0 secs 3.0 secs     3
    #>  7 0000_000000005972 2019-05-17 02:54:05 0 secs 3.0 secs     3
    #>  8 0000_000000005972 2019-05-17 02:54:08 0 secs 3.0 secs     2
    #>  9 0000_000000005972 2019-05-17 02:54:11 0 secs 3.0 secs     2
    #> 10 0000_000000005972 2019-05-17 02:54:14 0 secs 3.0 secs     2
    #> # ℹ 1,182 more rows

    marker_tag_plot(dat_multi, tag = "0000_000000005972", gap = 60*10) # Ten minute time gap

## Summarize directional data

PIT antennas are sometimes deployed along a linear migration route to monitor the directional movement of tagged individuals. ORFID has several functions that can be used to summarize directional data.

`tag_direction()` is used to determine the direction of movement whenever an individual is detected at a new/subsequent antenna. The function requires a vector describing the order of locations an individual encounters as it travels along a directional gradient (e.g., from downstream to upstream). The column, `DIR`, is created, where U and D designate upstream and downstream movements, respectively, and S designates a consecutive detection at the same antenna.

For example, a study array is composed of two antennas, downstream_A1 and upstream_A1, and animals move in an upstream direction (i.e., passing over the downstream antenna, then the upstream antenna).

    dat_multi <- join_multireader_data(list(reader_us, reader_ds), verbose = FALSE)
    #> A unique variable, LOC (location), was created by combining SCD (site code) and ANT (antenna).

    tag_direction(dat_multi, LOC_vec = c("downstream_A1", "upstream_A1")) %>%
        filter(TAG == "900_228000369764")
    #> # A tibble: 8 × 19
    #>   LOC           LOC_NUM DTY   ARR                 TRF   DUR    TTY
    #>   <chr>           <dbl> <chr> <dttm>              <chr> <drtn> <chr>
    #> 1 downstream_A1       1 S     2020-08-17 04:42:11 G     1 secs A
    #> 2 downstream_A1       1 S     2020-08-17 04:42:16 G     0 secs A
    #> 3 upstream_A1         2 S     2020-08-17 04:42:39 G     2 secs A
    #> 4 upstream_A1         2 S     2020-08-17 04:42:44 G     0 secs A
    #> 5 upstream_A1         2 S     2020-08-17 04:42:48 G     0 secs A
    #> 6 upstream_A1         2 S     2020-09-16 22:09:46 G     0 secs A
    #> 7 downstream_A1       1 S     2020-09-16 22:10:06 G     0 secs A
    #> 8 downstream_A1       1 S     2020-09-16 22:10:10 G     0 secs A
    #>   TAG              SCD          NCD   EFA TCH   ANT     EMP TSS       SPV   NOI
    #>   <chr>            <fct>      <dbl> <dbl> <chr> <fct> <dbl> <chr>   <dbl> <dbl>
    #> 1 900_228000369764 downstream    18   0.7 HDX   A1    65534 496/601 1265    332
    #> 2 900_228000369764 downstream     9   0.6 HDX   A1       32 549/603 1266.   366
    #> 3 900_228000369764 upstream      30   0.9 HDX   A1    65534 553/641 1274    356
    #> 4 900_228000369764 upstream       1   0.8 HDX   A1       25 560/560 1274.   356
    #> 5 900_228000369764 upstream      10   0.9 HDX   A1       35 572/632 1274    382
    #> 6 900_228000369764 upstream       6   0.9 HDX   A1    65534 605/616 1284.   386
    #> 7 900_228000369764 downstream     5   0.7 HDX   A1    30366 600/601 1276.   361
    #> 8 900_228000369764 downstream     1   0.7 HDX   A1       39 552/552 1278.   316
    #>   CLS   DIR
    #>   <chr> <chr>
    #> 1 " B " S
    #> 2 " B " S
    #> 3 " B " U
    #> 4 " B " S
    #> 5 " B " S
    #> 6 " B " S
    #> 7 " B " D
    #> 8 " B " S

`direction_summary()` can then be used to summarize the time difference between the first and last detections for each unique tag within the system. For example, this function can be used to determine residence time above or below an antenna.

`direction_summary()` has an optional argument `include_stationary`. If `include_stationary = TRUE`, all detections will be included in the summary. For example, if a tag is detected multiple times at the same antenna before making an upwards movement, its first direction is stationary. If `include_stationary = FALSE`, only detections with known direction will be included. For example, if a tag is detected multiple times at the same antenna before making an upwards movement, the stationary movements will be ignored and its first direction will be up.

    dir <- tag_direction(dat_multi, LOC_vec = c("downstream_A1", "upstream_A1"))

    direction_summary(dir)
    #> # A tibble: 55 × 9
    #>    TAG                   first_DET           first_LOC     first_DIR
    #>    <chr>                 <dttm>              <chr>         <chr>
    #>  1 900_230000009506      2020-07-09 19:33:18 upstream_A1   U
    #>  2 900_226000980150      2020-08-10 16:05:03 downstream_A1 D
    #>  3 900_226000584318      2020-08-11 11:45:02 upstream_A1   U
    #>  4 0000_0000000168273013 2020-08-11 13:35:25 upstream_A1   U
    #>  5 900_230000079824      2020-08-13 00:23:52 upstream_A1   U
    #>  6 900_228000586262      2020-08-13 03:03:13 upstream_A1   U
    #>  7 900_228000369675      2020-08-13 03:46:19 upstream_A1   U
    #>  8 900_228000586311      2020-08-15 21:43:42 upstream_A1   U
    #>  9 900_230000077653      2020-08-15 23:20:40 upstream_A1   U
    #> 10 900_228000369764      2020-08-17 04:42:39 upstream_A1   U
    #>    last_DET            last_LOC      last_DIR tdiff_sec     tdiff_day
    #>    <dttm>              <chr>         <chr>    <drtn>            <dbl>
    #>  1 2021-08-12 13:49:48 downstream_A1 D        34452990 secs     399.
    #>  2 2020-08-10 17:57:55 upstream_A1   U            6772 secs       0.1
    #>  3 2021-08-12 13:51:01 downstream_A1 D        31629959 secs     366.
    #>  4 2021-08-12 13:51:18 downstream_A1 D        31623353 secs     366
    #>  5 2020-09-11 04:15:00 downstream_A1 D         2519468 secs      29.2
    #>  6 2020-08-13 03:03:13 upstream_A1   U               0 secs       0
    #>  7 2020-09-14 21:27:48 downstream_A1 D         2828489 secs      32.7
    #>  8 2020-08-15 21:43:42 upstream_A1   U               0 secs       0
    #>  9 2020-09-19 23:29:18 downstream_A1 D         3024518 secs      35
    #> 10 2020-09-16 22:10:06 downstream_A1 D         2654847 secs      30.7
    #> # ℹ 45 more rows

    direction_summary(dir, include_stationary = TRUE)
    #> # A tibble: 64 × 9
    #>    TAG                   first_DET           first_LOC     first_DIR
    #>    <chr>                 <dttm>              <chr>         <chr>
    #>  1 900_226000584318      2020-06-07 15:59:39 downstream_A1 S
    #>  2 900_230000009506      2020-06-07 16:01:43 downstream_A1 S
    #>  3 900_226000980150      2020-07-09 19:33:37 upstream_A1   S
    #>  4 900_228000541363      2020-08-10 21:12:05 upstream_A1   S
    #>  5 0000_0000000168273013 2020-08-11 13:03:07 downstream_A1 S
    #>  6 0000_0000000183227019 2020-08-11 14:44:11 upstream_A1   S
    #>  7 900_230000079824      2020-08-13 00:23:26 downstream_A1 S
    #>  8 900_228000586262      2020-08-13 03:02:35 downstream_A1 S
    #>  9 900_228000369675      2020-08-13 03:46:00 downstream_A1 S
    #> 10 900_228000586311      2020-08-15 21:43:22 downstream_A1 S
    #>    last_DET            last_LOC      last_DIR tdiff_sec     tdiff_day
    #>    <dttm>              <chr>         <chr>    <drtn>            <dbl>
    #>  1 2021-08-12 13:51:01 downstream_A1 D        37230682 secs     431.
    #>  2 2021-08-12 13:51:48 downstream_A1 S        37230605 secs     431.
    #>  3 2020-08-11 14:44:36 upstream_A1   S         2833859 secs      32.8
    #>  4 2020-08-10 21:12:14 upstream_A1   S               9 secs       0
    #>  5 2021-08-12 13:51:25 downstream_A1 S        31625298 secs     366
    #>  6 2020-08-11 14:44:17 upstream_A1   S               6 secs       0
    #>  7 2020-09-11 04:15:04 downstream_A1 S         2519498 secs      29.2
    #>  8 2020-09-18 04:52:05 upstream_A1   S         3116970 secs      36.1
    #>  9 2020-09-14 21:27:53 downstream_A1 S         2828513 secs      32.7
    #> 10 2020-08-15 21:43:46 upstream_A1   S              24 secs       0
    #> # ℹ 54 more rows

`ant_efficiency()` is used to determine the efficiency for each antenna within a directional array. As with `tag_direction()`, a vector is required that describes the order of locations an individual encounters along a linear migration route. Efficiency is calculated as the number of shared detections at location x and at any location after x, divided by the number of detections after location x. Efficiency cannot be calculated for the final antenna as there are no subsequent detections. Reversing the order of the location vector can inform efficiency in systems with movement in multiple directions.

    ant_efficiency(dat_multi, LOC_vec = c("downstream_A1", "upstream_A1"))
    #>             LOC LOC_NUM shared_tags tags_above det_eff
    #> 1 downstream_A1       1          55         59    0.93
    #> 2   upstream_A1       2           0          0     NaN

## Export data

Any data frame created using ORFID functions can be exported to the working directory as a .csv or .xlsx file.

    export_ORFID(dat_multi, name = "multi_data_compiled", extension = ".xlsx")