Skip to content

Latest commit

 

History

History
273 lines (218 loc) · 9.05 KB

arrington_prisma.org

File metadata and controls

273 lines (218 loc) · 9.05 KB

Arrington/Avotech @ MRRC Prisma 2

library(ggplot)
pdir <- getwd()
# https://github.com/LabNeuroCogDevel/autoeyescore
setwd("/mnt/hdd/home/foranw/src/work/autoeyescore")
source("score_arrington.R")
setwd(pdir)

Testing with eye calibration tasks

We ran an eye calibration task first with the 32 channel head coil (once). Then with the 64 (three times).

The second 64 channel collection had the mirror tilled such that the projected screen was especially low in the field of view (“low”). The third 64 run was with the screen reflecting on the top of the mirror (“high”).

echo "time(PM) filename"
perl -MFile::Basename=basename -lne 'if(m/TimeStamp.*?([0-9:]+) PM/){$t=$1; print $t, " ", (basename($ARGV) =~ s/sub-will|_.*//gr)}' ~/scratch/sub-will*|sort

The task is a visually guided saccade/fixation calibration run configured so a yellow circle (“dot”) appears for 2s. The small dot is positioned on the horizontal meridian from 90% left of the screen edge to 90% right excluding 20% on either side of center. A 2 second center fixation cross (“iti”) is between each dot.

There should have been 10 dot events with positions evenly distributed (2s dot + 2s iti * 10 == 40s total), but the last trial was never presented. (The last screen flipped w/o a wait, so the program ended early.)

eyetxts <- Sys.glob("~/scratch/sub-will*.txt")
tracking_list <- lapply(eyetxts, \(f) read_arr(f) %>%
        # msg is 'iti' or like '1 dot .9'
        separate(msg,c("trial","event","pos"),sep=" ") %>%
        mutate(event=ifelse(is.na(event), 'iti',event),
               trial=as.numeric(trial),
               pos=round(as.numeric(pos),2),
               # include where data comes from
               fname=gsub('.*/sub-will|_.*','',f)) %>%
        fill(trial, pos, .direction="up") %>%
        group_by(trial) %>%
        mutate(t=TotalTime-first(TotalTime)))

tracking_list %>%
  lapply(\(x) x%>%group_by(fname) %>%
        summarise(trials=max(trial,na.rm=T), time=max(TotalTime), samples=n()))%>%
  bind_rows
fnametrialstimesamples
32test937.81962265
64screen2test-high937.86972267
64screentest-low937.9032262
64test937.9032273

Quality

Time series traces

There were two especially bad runs. With the 32 channel coil arrington’s software could not get a stable pupil lock. In the “low” version of 64 channel coil run, the pupil tracking was less noisy but also frequent periods of no tracking.

# many plots into grid. prefer facet_wrap version
plots <- lapply(tracking_list,
   \(d) ggplot(d %>% filter(!is.na(trial)) +
   aes(x=t, y=X_CorrectedGaze, color=event) +
   geom_point() +
   facet_wrap(~pos) +
   theme(legend.position='none')+
   ggtitle(d$fname[1]))
do.call(cowplot::plot_grid, plots)
d_all <- tracking_list %>% bind_rows %>% filter(!is.na(trial))
d_median <- d_all %>%
  group_by(fname,trial,event,pos) %>%
  summarise(x_median=median(X_CorrectedGaze,na.rm=T))

raw_plot <- ggplot(d_all) +
   aes(x=t, y=X_CorrectedGaze, color=event) +
   geom_point(size=.5) +
   facet_grid(fname~pos) +
   geom_hline(data=d_median,aes(yintercept=x_median, linetype=event)) +
   lims(y=c(-1.5,1.5),x=c(1,4)) +
   cowplot::theme_cowplot() +
   labs(y="eye x pos (corrected)", x="time (s)",
        title="[VGS] Per trial-position horz. eye time series; median event lines")
print(raw_plot)

dot distance from iti

Surprisingly, even the noisy 32 channel coil’s median fixation can correctly identify at least the side of the dot during fixation.

med_vals <- d_median %>%
  spread(event,x_median) %>%
  mutate(dist=iti-dot) %>%
  rbind(data.frame(
      fname='ideal', pos=c(-.9,.9),
      dist=c(.5-.05, .5-.95))) %>%
  mutate(type=case_when(
           grepl('64',fname)~ '64 channel coil', 
           grepl('32',fname)~ '32 channel coil', 
           grepl('ideal',fname)~ 'ideal',
           TRUE ~ 'oops'))

ggplot(med_vals) +
  aes(x=pos, y=dist, color=fname, linetype=type) +
  geom_hline(yintercept=0, alpha=.5) +
  geom_point() +
  geom_line(aes(group=fname)) +
  scale_linetype_manual(values=c(5,3,1)) +
  cowplot::theme_cowplot() +
  labs(x="presented dot's horz. position (-1 left, 1 right)",
       y="median center fix (iti) - median dot fix",
       linetype="head coil",
       color="data from",
       title="horz gaze side discrimination")

Noise

d_in1sec <- d_median %>%
  inner_join(d_all) %>% group_by(fname, pos, trial, event) %>%
  mutate(event_t=TotalTime - first(TotalTime)) %>%
  filter(event_t>1)# %>%

base_box <- function(d) ggplot(d) +
  aes(y=X_CorrectedGaze-x_median, fill=fname) +
  geom_boxplot() +
  cowplot::theme_cowplot() +
  scale_x_discrete(labels = NULL, breaks = NULL) +
  labs(y="diff from median. 1s after onset", fill="data from")

cowplot::plot_grid(
  d_in1sec %>% filter(event=='dot') %>% base_box +
   facet_grid(.~pos) + theme(legend.position="none") +
   labs(y="", title="eye tracking quality: range around median fixation point"),
  base_box(d_in1sec) + facet_grid(.~event),
  nrow=2)

Previously collected data

LNCDR::ld8from(txtfiles)

Okay !?

11878 was a single 8 min run with bad tracking.

plot_overview(dr_list[[1]])

Too noisy

11880 has noisy data. Small head with coil center obstructing eye. Participant might have also ignored all neutral trials. complicating averaging.

plot_overview(dr_list[[2]])
plot_overview(dr_list[[3]])