Generates a synthetic two-image forced-choice (2IFC) dataset that
is shape-compatible with every check_*(), run_diagnostics(),
ci_from_responses_2ifc(), and reliability/discriminability
function in the package. Useful as a quickstart sandbox and as a
building block for simulation studies (power, calibration of
reliability and discriminability metrics, sensitivity to
contamination).
The function generates the noise pool on the fly via
rcicr::generateNoisePattern() and rcicr::generateNoiseImage(),
so it requires the rcicr package to be installed. With default
arguments (50 participants per condition, 500 trials, 256-pixel
images) the noise generation step takes one to a few minutes; a
progress bar is shown.
Usage
simulate_2ifc_data(
n_per_condition = 50L,
conditions = c("target", "control"),
n_trials = 500L,
img_size = 256L,
base_image = NULL,
signal_strength = "weak",
signal_region = "eyes",
rt_contamination_fast = 0.02,
rt_contamination_slow = 0.02,
noise_type = "sinusoid",
nscales = 5L,
sigma = 25,
rdata_dir = NULL,
seed = NULL,
progress = TRUE
)Arguments
- n_per_condition
Integer. Participants per condition. Default
50.- conditions
Character vector. Default
c("target", "control").- n_trials
Integer. Trials per participant; equals the noise pool size (each pool item shown once per participant). Default
500.- img_size
Integer. Side length of square images, in pixels. Default
256(matches the bundled base face). Setting this higher (e.g.512) requires you to also pass a matchingbase_image.- base_image
Path to a square PNG, or a numeric matrix in
[0, 1]of dimensionimg_size x img_size. DefaultNULLuses the bundledinst/extdata/sim_base_face.png(a 256x256 grayscale artificial face).- signal_strength
One of
"none","weak","strong", or a numeric coefficient (thebetain the logistic above). Default"weak".- signal_region
Region passed to
make_face_mask(). Default"eyes".- rt_contamination_fast, rt_contamination_slow
Numeric in
[0, 1]. Fraction of trials replaced by uniform-fast (50-200 ms) and uniform-slow (5000-20000 ms) contaminants. Default0.02each.- noise_type, nscales, sigma
Forwarded to
rcicr::generateNoisePattern(). Defaults match rcicr's defaults ("sinusoid",5,25).- rdata_dir
Optional directory in which to write the rcicr-format
.Rdatastimuli file with a stable filename (rcisignal_sim_2ifc_stimuli.Rdata). WhenNULL(default) the file goes to a session tempdir and the returned$rdata_pathbecomes invalid after the R session ends. Pass an explicit directory to persist the simulation across sessions. See Details.- seed
Integer or
NULL. WhenNULL, a random seed is drawn and stored on the result so the run is reproducible.- progress
Logical. Show a
cliprogress bar during noise generation. DefaultTRUE.
Value
An object of class "rcisignal_sim" with elements:
data— a data.table::data.table with one row per trial and columnsparticipant_id,condition,trial,stimulus,response,rt. Compatible withrun_diagnostics()andci_from_responses_2ifc().noise_matrix—(img_size^2) x n_trialsnumeric matrix.base_face—img_size x img_sizenumeric matrix.params—n_trials x ncoefmatrix of per-trial sinusoid coefficients (the rcicrstimuli_params).p— the rcicr noise basis (generateNoisePattern()output); pair withparamsto regenerate any noise image.rdata_path— path to an rcicr-format.Rdatafile written either to a session tempdir (whenrdata_dir = NULL) or to the user-suppliedrdata_dir. Suitable forci_from_responses_2ifc()/compute_infoval_summary()and other downstream functions that take anrdataargument. Not portable across R sessions whenrdata_dir = NULL.base_image_path— path to a standalone PNG ofbase_facewritten next to the.Rdata(rcisignal_sim_2ifc_base_face.pngfor 2IFC,rcisignal_sim_briefrc_base_face.pngfor Brief-RC). Same persistence story asrdata_path: persists whenrdata_diris supplied, lives in a session tempdir otherwise. Most users prefer the matrix formbase_facedirectly; the path is provided for symmetry with rcicr's standard workflow.stimuli— a self-contained list (base_face,params,p, etc.) that downstream consumers accept via theirstimuli =argument as a portable alternative tordata_path. Round-trips throughsaveRDS()/readRDS().signal— pixel-level signal vector used to plant the response bias.meta— list of method,n_per_condition,conditions,n_trials,img_size,signal_strength,signal_region,seed,elapsed_secs.
Details
When rdata_dir = NULL, the returned $rdata_path points at a
session tempdir and becomes invalid after the R session ends.
Persist the simulation across sessions (caching with
saveRDS(), knitr cache=TRUE, sharing with collaborators)
either by passing an explicit rdata_dir such as "simdata/",
or by handing the returned $stimuli list to
ci_from_responses_2ifc() (and the other infoval-dependent
helpers) in place of rdata_path. $stimuli is a
self-contained in-memory representation of the rcicr stimuli
env, so the sim object round-trips through
saveRDS()/readRDS() without a file dependency.
Signal model
Each trial t shows two stimuli, image_a = base + noiset and
image_b = base - noiset. The participant chooses one. With
signal_strength = "none" choices are uniform random (P(+1) = 0.5); with "weak" / "strong" (or a custom numeric beta),
the log-odds of choosing image_a are
beta * (noise[, t] %*% s) / scale, where s is a binary mask
from make_face_mask() over the requested signal_region and
scale = sqrt(sum(s)) keeps the per-pixel signal magnitude
comparable across regions of different size.
RT model
Shifted lognormal: rt = round(exp(rnorm(n, log(800), 0.5)) + 150), in ms. A small fraction of fast (<200 ms) and slow
(>5000 ms) contaminants are mixed in (default 2% each) so the
diagnostic functions (check_rt()) have something to flag.
Examples
if (FALSE) { # \dontrun{
# `sim$data` is a plain data frame (columns: participant_id, stimulus,
# response, condition, rt) — same shape ci_from_responses_2ifc() and
# the check_*() functions expect from your own CSV.
sim <- simulate_2ifc_data(n_per_condition = 10, n_trials = 60, seed = 1)
run_diagnostics(sim$data, method = "2ifc", col_rt = "rt")
cis <- ci_from_responses_2ifc(sim$data, rdata_path = sim$rdata_path)
run_reliability(cis$signal_matrix, n_permutations = 200L, seed = 1)
} # }