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
```