or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

area-detectors.mdcore-framework.mdepics-integration.mdflyers-continuous-scanning.mdindex.mdmotors-positioners.mdsimulation-testing.mdspecialized-devices.md

specialized-devices.mddocs/

0

# Specialized Devices

1

2

Pre-built device classes for common laboratory instruments including scalers, multi-channel analyzers, and electrometers. These devices provide standardized interfaces to specific hardware types commonly found in scientific facilities.

3

4

## Capabilities

5

6

### Scalers

7

8

EPICS scaler devices for counting applications and beam monitoring.

9

10

```python { .api }

11

class EpicsScaler(Device):

12

"""

13

EPICS scaler record interface for multi-channel counting.

14

15

Provides access to EPICS scaler records with multiple counting

16

channels, preset values, and timing control.

17

18

Parameters:

19

- prefix (str): EPICS scaler record prefix

20

- name (str): Scaler device name

21

"""

22

def __init__(self, prefix, *, name, **kwargs): ...

23

24

def stage(self):

25

"""

26

Stage scaler for data acquisition.

27

28

Configures channels and preset values.

29

"""

30

31

def unstage(self):

32

"""Unstage scaler after acquisition."""

33

34

def trigger(self):

35

"""

36

Trigger scaler counting sequence.

37

38

Returns:

39

StatusBase: Status tracking count completion

40

"""

41

42

def stop(self):

43

"""Stop scaler counting."""

44

45

def read(self):

46

"""

47

Read all enabled scaler channels.

48

49

Returns:

50

dict: Channel readings with counts and count rates

51

"""

52

53

@property

54

def preset_time(self):

55

"""

56

Preset counting time.

57

58

Returns:

59

EpicsSignal: Preset time signal

60

"""

61

62

@property

63

def elapsed_real_time(self):

64

"""

65

Elapsed real counting time.

66

67

Returns:

68

EpicsSignalRO: Real time readback

69

"""

70

71

@property

72

def elapsed_live_time(self):

73

"""

74

Elapsed live counting time.

75

76

Returns:

77

EpicsSignalRO: Live time readback

78

"""

79

80

class ScalerChannel(Device):

81

"""

82

Individual scaler channel with counting and configuration.

83

84

Represents a single channel of a multi-channel scaler.

85

"""

86

def __init__(self, prefix, *, ch_num, **kwargs): ...

87

88

@property

89

def s(self):

90

"""

91

Channel counts.

92

93

Returns:

94

EpicsSignalRO: Count value

95

"""

96

97

@property

98

def preset(self):

99

"""

100

Channel preset value.

101

102

Returns:

103

EpicsSignal: Preset count or rate

104

"""

105

106

@property

107

def gate(self):

108

"""

109

Channel gate control.

110

111

Returns:

112

EpicsSignal: Gate enable/disable

113

"""

114

115

# Alias for ScalerChannel

116

ScalerCH = ScalerChannel

117

```

118

119

### Multi-Channel Analyzers (MCA)

120

121

Devices for energy-dispersive spectroscopy and pulse height analysis.

122

123

```python { .api }

124

class EpicsMCA(Device):

125

"""

126

EPICS Multi-Channel Analyzer for energy spectroscopy.

127

128

Provides interface to MCA records for pulse height analysis

129

and energy-dispersive measurements.

130

131

Parameters:

132

- prefix (str): EPICS MCA record prefix

133

- name (str): MCA device name

134

"""

135

def __init__(self, prefix, *, name, **kwargs): ...

136

137

def erase(self):

138

"""

139

Erase (clear) MCA spectrum data.

140

141

Returns:

142

StatusBase: Erase completion status

143

"""

144

145

def start(self):

146

"""

147

Start MCA data acquisition.

148

149

Returns:

150

StatusBase: Start completion status

151

"""

152

153

def stop(self):

154

"""Stop MCA data acquisition."""

155

156

def read(self):

157

"""

158

Read MCA spectrum data.

159

160

Returns:

161

dict: Spectrum data and metadata

162

"""

163

164

@property

165

def spectrum(self):

166

"""

167

MCA spectrum data array.

168

169

Returns:

170

EpicsSignalRO: Spectrum counts per channel

171

"""

172

173

@property

174

def preset_real_time(self):

175

"""

176

Preset real counting time.

177

178

Returns:

179

EpicsSignal: Preset time setting

180

"""

181

182

@property

183

def preset_live_time(self):

184

"""

185

Preset live counting time.

186

187

Returns:

188

EpicsSignal: Preset live time setting

189

"""

190

191

@property

192

def elapsed_real_time(self):

193

"""

194

Elapsed real counting time.

195

196

Returns:

197

EpicsSignalRO: Actual real time

198

"""

199

200

@property

201

def elapsed_live_time(self):

202

"""

203

Elapsed live counting time.

204

205

Returns:

206

EpicsSignalRO: Actual live time

207

"""

208

209

class ROI(Device):

210

"""

211

Region of Interest for MCA spectrum analysis.

212

213

Defines energy windows for peak integration and analysis.

214

"""

215

def __init__(self, prefix, *, roi_num, **kwargs): ...

216

217

@property

218

def count(self):

219

"""

220

ROI integrated counts.

221

222

Returns:

223

EpicsSignalRO: Total counts in ROI

224

"""

225

226

@property

227

def net_count(self):

228

"""

229

ROI net counts (background subtracted).

230

231

Returns:

232

EpicsSignalRO: Net counts in ROI

233

"""

234

235

@property

236

def preset_count(self):

237

"""

238

ROI preset count value.

239

240

Returns:

241

EpicsSignal: Preset counts for ROI

242

"""

243

244

class EpicsDXP(Device):

245

"""

246

Digital X-ray Processor interface for advanced MCA systems.

247

248

Provides control of DXP-based multi-element detector systems

249

with advanced signal processing capabilities.

250

"""

251

def __init__(self, prefix, *, name, **kwargs): ...

252

253

def erase(self):

254

"""Erase all DXP spectrum data."""

255

256

def start(self):

257

"""Start DXP acquisition."""

258

259

def stop(self):

260

"""Stop DXP acquisition."""

261

```

262

263

### Quad Electrometers

264

265

Four-channel electrometers for current measurement and beam monitoring.

266

267

```python { .api }

268

class QuadEM(Device):

269

"""

270

Base class for quad electrometer devices.

271

272

Provides four-channel current measurement with position

273

calculation capabilities for beam monitoring.

274

275

Parameters:

276

- prefix (str): Device PV prefix

277

- name (str): Device name

278

"""

279

def __init__(self, prefix, *, name, **kwargs): ...

280

281

def stage(self):

282

"""Stage electrometer for acquisition."""

283

284

def unstage(self):

285

"""Unstage electrometer."""

286

287

def trigger(self):

288

"""

289

Trigger electrometer reading.

290

291

Returns:

292

StatusBase: Trigger completion status

293

"""

294

295

def read(self):

296

"""

297

Read all electrometer channels and computed values.

298

299

Returns:

300

dict: Current readings and position calculations

301

"""

302

303

@property

304

def current1(self):

305

"""

306

Channel 1 current reading.

307

308

Returns:

309

EpicsSignalRO: Current in amperes

310

"""

311

312

@property

313

def current2(self):

314

"""

315

Channel 2 current reading.

316

317

Returns:

318

EpicsSignalRO: Current in amperes

319

"""

320

321

@property

322

def current3(self):

323

"""

324

Channel 3 current reading.

325

326

Returns:

327

EpicsSignalRO: Current in amperes

328

"""

329

330

@property

331

def current4(self):

332

"""

333

Channel 4 current reading.

334

335

Returns:

336

EpicsSignalRO: Current in amperes

337

"""

338

339

@property

340

def sum_all(self):

341

"""

342

Sum of all four channels.

343

344

Returns:

345

EpicsSignalRO: Total current

346

"""

347

348

@property

349

def pos_x(self):

350

"""

351

Calculated X position from quad currents.

352

353

Returns:

354

EpicsSignalRO: X position

355

"""

356

357

@property

358

def pos_y(self):

359

"""

360

Calculated Y position from quad currents.

361

362

Returns:

363

EpicsSignalRO: Y position

364

"""

365

366

class NSLS_EM(QuadEM):

367

"""

368

NSLS-style electrometer implementation.

369

370

Specific implementation for NSLS (National Synchrotron Light Source)

371

electrometer hardware and control systems.

372

"""

373

def __init__(self, prefix, *, name, **kwargs): ...

374

375

class TetrAMM(QuadEM):

376

"""

377

TetrAMM electrometer device.

378

379

Interface to TetrAMM (Tetrode Ammeter) hardware for

380

four-channel current measurement.

381

"""

382

def __init__(self, prefix, *, name, **kwargs): ...

383

384

class APS_EM(QuadEM):

385

"""

386

APS-style electrometer implementation.

387

388

Specific implementation for APS (Advanced Photon Source)

389

electrometer hardware and control systems.

390

"""

391

def __init__(self, prefix, *, name, **kwargs): ...

392

393

class QuadEMPort(Device):

394

"""

395

Individual port/channel of a quad electrometer.

396

397

Represents a single current input channel with its

398

associated configuration and readback values.

399

"""

400

def __init__(self, prefix, *, port_name, **kwargs): ...

401

```

402

403

### Ion Chambers and Current Monitors

404

405

Additional specialized current measurement devices.

406

407

```python { .api }

408

class IonChamber(Device):

409

"""

410

Ion chamber device for X-ray intensity monitoring.

411

412

Provides current measurement and voltage control for

413

gas-filled ion chambers used in X-ray beam monitoring.

414

"""

415

def __init__(self, prefix, *, name, **kwargs): ...

416

417

@property

418

def current(self):

419

"""

420

Ion chamber current reading.

421

422

Returns:

423

EpicsSignalRO: Current in amperes

424

"""

425

426

@property

427

def voltage(self):

428

"""

429

Ion chamber bias voltage.

430

431

Returns:

432

EpicsSignal: Bias voltage setting

433

"""

434

435

class CurrentAmplifier(Device):

436

"""

437

Current amplifier device for low-level current measurement.

438

439

Provides amplification and measurement of small currents

440

from photodiodes, ion chambers, and other current sources.

441

"""

442

def __init__(self, prefix, *, name, **kwargs): ...

443

444

@property

445

def current(self):

446

"""

447

Amplified current reading.

448

449

Returns:

450

EpicsSignalRO: Current measurement

451

"""

452

453

@property

454

def gain(self):

455

"""

456

Amplifier gain setting.

457

458

Returns:

459

EpicsSignal: Gain value

460

"""

461

```

462

463

## Usage Examples

464

465

### Scaler Usage

466

467

```python

468

from ophyd import EpicsScaler

469

from ophyd.status import wait

470

471

# Create scaler device

472

scaler = EpicsScaler('XF:28IDC:SCALER:', name='scaler')

473

scaler.wait_for_connection()

474

475

# Configure counting time

476

scaler.preset_time.put(1.0) # 1 second counting

477

478

# Stage and trigger counting

479

scaler.stage()

480

status = scaler.trigger()

481

wait(status) # Wait for counting to complete

482

483

# Read results

484

reading = scaler.read()

485

for channel_name, data in reading.items():

486

print(f"{channel_name}: {data['value']} counts")

487

488

# Get individual channel data

489

ch1_counts = scaler.channels.chan1.s.get()

490

print(f"Channel 1: {ch1_counts} counts")

491

492

scaler.unstage()

493

```

494

495

### MCA Spectroscopy

496

497

```python

498

from ophyd import EpicsMCA

499

from ophyd.status import wait

500

501

# Create MCA device

502

mca = EpicsMCA('XF:28IDC:MCA:', name='mca')

503

mca.wait_for_connection()

504

505

# Configure acquisition

506

mca.preset_real_time.put(10.0) # 10 second acquisition

507

mca.erase() # Clear previous data

508

509

# Start acquisition

510

status = mca.start()

511

wait(status)

512

513

# Read spectrum

514

spectrum_data = mca.spectrum.get()

515

print(f"Spectrum shape: {spectrum_data.shape}")

516

print(f"Total counts: {spectrum_data.sum()}")

517

518

# Work with ROIs

519

roi1 = mca.rois.roi1

520

roi1.left.put(100) # Set ROI start channel

521

roi1.right.put(200) # Set ROI end channel

522

523

roi_counts = roi1.count.get()

524

net_counts = roi1.net_count.get()

525

print(f"ROI counts: {roi_counts}, Net: {net_counts}")

526

```

527

528

### Quad Electrometer Monitoring

529

530

```python

531

from ophyd import NSLS_EM

532

from ophyd.status import wait

533

534

# Create quad electrometer

535

qem = NSLS_EM('XF:28IDC:QEM:', name='quadem')

536

qem.wait_for_connection()

537

538

# Configure acquisition parameters

539

qem.acquire_mode.put('Single')

540

qem.averaging_time.put(0.1) # 100ms averaging

541

542

# Stage and trigger reading

543

qem.stage()

544

status = qem.trigger()

545

wait(status)

546

547

# Read all channels

548

reading = qem.read()

549

550

# Get individual currents

551

i1 = qem.current1.get()

552

i2 = qem.current2.get()

553

i3 = qem.current3.get()

554

i4 = qem.current4.get()

555

556

print(f"Currents: I1={i1:.3e}, I2={i2:.3e}, I3={i3:.3e}, I4={i4:.3e}")

557

558

# Get computed position

559

x_pos = qem.pos_x.get()

560

y_pos = qem.pos_y.get()

561

total_current = qem.sum_all.get()

562

563

print(f"Position: X={x_pos:.3f}, Y={y_pos:.3f}")

564

print(f"Total current: {total_current:.3e} A")

565

566

qem.unstage()

567

```

568

569

### Multi-Element DXP System

570

571

```python

572

from ophyd import EpicsDXP

573

574

# Create DXP system

575

dxp = EpicsDXP('XF:28IDC:DXP:', name='dxp_detector')

576

dxp.wait_for_connection()

577

578

# Configure acquisition for all elements

579

dxp.preset_real_time.put(60.0) # 60 second count

580

dxp.erase() # Clear all spectra

581

582

# Start acquisition

583

status = dxp.start()

584

wait(status)

585

586

# Read data from all elements

587

reading = dxp.read()

588

589

# Access individual detector elements

590

for i in range(4): # Assuming 4-element detector

591

element = getattr(dxp, f'mca{i+1}')

592

spectrum = element.spectrum.get()

593

dead_time = element.elapsed_dead_time.get()

594

595

print(f"Element {i+1}:")

596

print(f" Total counts: {spectrum.sum()}")

597

print(f" Dead time: {dead_time:.1f}%")

598

599

# Get element-specific ROIs

600

roi = element.rois.roi1

601

roi_counts = roi.count.get()

602

print(f" ROI 1 counts: {roi_counts}")

603

```

604

605

### Beam Position Monitoring

606

607

```python

608

from ophyd import TetrAMM

609

import time

610

611

# Create beam position monitor

612

bpm = TetrAMM('XF:28IDC:BPM:', name='beam_position_monitor')

613

bpm.wait_for_connection()

614

615

# Monitor beam position continuously

616

print("Monitoring beam position (Ctrl+C to stop):")

617

618

try:

619

while True:

620

# Trigger reading

621

bpm.stage()

622

status = bpm.trigger()

623

wait(status)

624

625

# Get position and intensity

626

x_pos = bpm.pos_x.get()

627

y_pos = bpm.pos_y.get()

628

intensity = bpm.sum_all.get()

629

630

print(f"Position: X={x_pos:+6.3f} mm, Y={y_pos:+6.3f} mm, "

631

f"Intensity: {intensity:.2e} A")

632

633

bpm.unstage()

634

time.sleep(1.0) # Update every second

635

636

except KeyboardInterrupt:

637

print("Monitoring stopped")

638

```

639

640

### Custom Multi-Device Setup

641

642

```python

643

from ophyd import Device, Component

644

from ophyd import EpicsScaler, NSLS_EM, EpicsMCA

645

646

class BeamlineInstruments(Device):

647

"""Combined beamline instrumentation."""

648

649

# Intensity monitoring

650

scaler = Component(EpicsScaler, 'SCALER:')

651

ion_chamber = Component(NSLS_EM, 'IC1:')

652

653

# Spectroscopy

654

mca = Component(EpicsMCA, 'MCA:')

655

656

def monitor_beam(self, count_time=1.0):

657

"""Monitor beam intensity and position."""

658

659

# Configure devices

660

self.scaler.preset_time.put(count_time)

661

self.ion_chamber.averaging_time.put(count_time)

662

663

# Stage all devices

664

self.scaler.stage()

665

self.ion_chamber.stage()

666

667

# Trigger simultaneously

668

scaler_status = self.scaler.trigger()

669

ic_status = self.ion_chamber.trigger()

670

671

# Wait for completion

672

wait([scaler_status, ic_status])

673

674

# Read results

675

scaler_reading = self.scaler.read()

676

ic_reading = self.ion_chamber.read()

677

678

# Unstage

679

self.scaler.unstage()

680

self.ion_chamber.unstage()

681

682

return {

683

'scaler': scaler_reading,

684

'ion_chamber': ic_reading

685

}

686

687

# Use combined instrument

688

instruments = BeamlineInstruments('XF:28IDC:', name='instruments')

689

instruments.wait_for_connection()

690

691

# Monitor beam conditions

692

results = instruments.monitor_beam(count_time=0.5)

693

print("Beam monitoring results:")

694

print(results)

695

```