// Numeric details of one selected block: every event it references, with // the library parameters spelled out in display units. import type { ParsedSeq } from '../seq/types.ts' import type { Reconstructed } from '../seq/reconstruct.ts' import { formatNumber, formatTime, GAMMA } from './format' export interface BlockInspectorProps { seq: ParsedSeq rec: Reconstructed blockIndex: number onNavigate: (index: number) => void } const RF_USE: Record = { e: 'excitation', r: 'refocusing', i: 'inversion', s: 'saturation', p: 'preparation', o: 'other', u: 'undefined', } function gradCell(seq: ParsedSeq, id: number): React.ReactNode { if (id === 0) return — const g = seq.grads.get(id) if (!g) return missing #{id} const mTm = (g.amp / GAMMA) * 1e3 if (g.kind === 'trap') { return ( <> trap #{g.id}: {formatNumber(g.amp, 6)} Hz/m ({mTm.toFixed(2)} mT/m), rise{' '} {formatTime(g.rise, 3)}, flat {formatTime(g.flat, 3)}, fall {formatTime(g.fall, 3)} {g.delay > 0 ? `, delay ${formatTime(g.delay, 3)}` : ''} ) } const shape = seq.shapes.get(g.shapeId) return ( <> arbitrary #{g.id}: peak {formatNumber(g.amp, 6)} Hz/m ({mTm.toFixed(2)} mT/m), shape # {g.shapeId} ({shape?.numSamples ?? '?'} samples) {g.timeShapeId !== 0 ? `, time shape #${g.timeShapeId}` : ''} {g.delay > 0 ? `, delay ${formatTime(g.delay, 3)}` : ''} ) } export default function BlockInspector({ seq, rec, blockIndex, onNavigate }: BlockInspectorProps) { const block = seq.blocks[blockIndex] const span = rec.blockSpans[blockIndex] if (!block || !span) return null const rf = block.rfId !== 0 ? seq.rf.get(block.rfId) : undefined const adc = block.adcId !== 0 ? seq.adcs.get(block.adcId) : undefined // Resolve the extension linked list into readable entries const extEntries: string[] = [] let extId = block.extId let guard = 0 while (extId !== 0 && guard++ < 100) { const ref = seq.extensions.get(extId) if (!ref) break const spec = seq.extensionSpecs.find((s) => s.typeId === ref.type) if (spec) { const row = spec.rows.find((r) => Number(r[0]) === ref.ref) extEntries.push(`${spec.name} ${row ? row.slice(1).join(' ') : `#${ref.ref}`}`) } else { extEntries.push(`type ${ref.type} #${ref.ref}`) } extId = ref.next } return (
block {block.id} of {seq.blocks.length} · start {formatTime(span.start)} · duration{' '} {formatTime(span.duration)}
RF {rf ? ( <> #{rf.id}: {RF_USE[rf.use] ?? rf.use}, peak {formatNumber(rf.amp, 5)} Hz, delay{' '} {formatTime(rf.delay, 3)} {Number.isFinite(rf.center) ? `, center ${formatTime(rf.center, 3)}` : ''} {rf.freq !== 0 ? `, freq ${formatNumber(rf.freq, 5)} Hz` : ''} {rf.phase !== 0 ? `, phase ${formatNumber(rf.phase, 5)} rad` : ''} {`, shapes m#${rf.magShapeId}/p#${rf.phaseShapeId}` + (rf.timeShapeId !== 0 ? `/t#${rf.timeShapeId}` : '')} ) : ( — )}
GX {gradCell(seq, block.gxId)}
GY {gradCell(seq, block.gyId)}
GZ {gradCell(seq, block.gzId)}
ADC {adc ? ( <> #{adc.id}: {adc.num} samples, dwell {formatNumber(adc.dwell * 1e9, 6)} ns, delay{' '} {formatTime(adc.delay, 3)} {adc.freq !== 0 ? `, freq ${formatNumber(adc.freq, 5)} Hz` : ''} {adc.phase !== 0 ? `, phase ${formatNumber(adc.phase, 5)} rad` : ''} ) : ( — )}
Extensions {extEntries.length > 0 ? extEntries.join(' · ') : —}
) }