use super::{Position3D, SensorLayout, SensorSite};
pub fn neuropixels_1_0() -> SensorLayout {
const X: [f32; 4] = [43.0, 11.0, 59.0, 27.0];
let contacts = (0..384)
.map(|i| SensorSite {
channel_id: i,
device_index: i,
group_id: 0,
shank_id: 0,
position: Position3D::new(X[i % 4], (i / 2) as f32 * 20.0, 0.0),
enabled: true,
})
.collect();
SensorLayout::new("Neuropixels 1.0 (Standard 384)", contacts)
}
const NP2_SHANKS: usize = 4;
const NP2_SITES_PER_SHANK: usize = 96;
const NP2_SHANK_PITCH_UM: f32 = 250.0;
const NP2_COLUMN_PITCH_UM: f32 = 32.0;
const NP2_ROW_PITCH_UM: f32 = 15.0;
pub fn neuropixels_2_0() -> SensorLayout {
let sites = (0..NP2_SHANKS * NP2_SITES_PER_SHANK)
.map(|i| {
let (shank_id, on_shank) = (i / NP2_SITES_PER_SHANK, i % NP2_SITES_PER_SHANK);
let (col, row) = (on_shank % 2, on_shank / 2);
let x = shank_id as f32 * NP2_SHANK_PITCH_UM + col as f32 * NP2_COLUMN_PITCH_UM;
SensorSite {
channel_id: i,
device_index: i,
group_id: shank_id,
shank_id,
position: Position3D::new(x, row as f32 * NP2_ROW_PITCH_UM, 0.0),
enabled: true,
}
})
.collect();
SensorLayout::new("Neuropixels 2.0 (4-Shank 384)", sites)
}
pub fn hdemg_grid(name: &str, rows: usize, cols: usize, pitch_um: f32) -> SensorLayout {
let contacts = (0..rows * cols)
.map(|ch| SensorSite::new(ch, Position3D::new((ch % cols) as f32 * pitch_um, (ch / cols) as f32 * pitch_um, 0.0), 0))
.collect();
SensorLayout::new(name, contacts)
}
pub fn hdemg_4x8(pitch_um: f32) -> SensorLayout {
hdemg_grid("HDEMG-4x8", 4, 8, pitch_um)
}
pub fn hdemg_8x8(pitch_um: f32) -> SensorLayout {
hdemg_grid("HDEMG-8x8", 8, 8, pitch_um)
}
const TETRODE_HALF_SPACING_UM: f32 = 12.5;
pub fn tetrode() -> SensorLayout {
let h = TETRODE_HALF_SPACING_UM;
let positions = [(-h, 0.0), (h, 0.0), (0.0, -h), (0.0, h)];
let sites = positions.iter().enumerate().map(|(c, &(x, y))| SensorSite::new(c, Position3D::new(x, y, 0.0), 0)).collect();
SensorLayout::new("Tetrode (4-Channel)", sites)
}
const UTAH_SIDE: usize = 10;
const UTAH_PITCH_UM: f32 = 400.0;
pub fn utah_array() -> SensorLayout {
let last = UTAH_SIDE - 1;
let sites = (0..UTAH_SIDE * UTAH_SIDE)
.map(|i| (i / UTAH_SIDE, i % UTAH_SIDE))
.filter(|&(row, col)| !((row == 0 || row == last) && (col == 0 || col == last)))
.enumerate()
.map(|(ch, (row, col))| SensorSite::new(ch, Position3D::new(col as f32 * UTAH_PITCH_UM, row as f32 * UTAH_PITCH_UM, 0.0), 0))
.collect();
SensorLayout::new("Utah Array (96-Channel)", sites)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preset_shapes() {
assert_eq!(neuropixels_2_0().total_channels(), 384);
assert_eq!(neuropixels_2_0().contacts[96].position, Position3D::new(250.0, 0.0, 0.0));
let grid = hdemg_4x8(100.0);
assert_eq!(grid.total_channels(), 32);
assert_eq!(grid.contacts[7].position, Position3D::new(700.0, 0.0, 0.0));
assert_eq!(grid.contacts[8].position, Position3D::new(0.0, 100.0, 0.0));
assert_eq!(tetrode().total_channels(), 4);
assert_eq!(utah_array().total_channels(), 96);
}
}