-
Notifications
You must be signed in to change notification settings - Fork 141
/
pyivi_specan.py
1598 lines (1312 loc) · 71.7 KB
/
pyivi_specan.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""
This file contains a wrapper for pyivi for spectrum analyzers using the IVI interface.
The main class is ::PyIviSpecAn::
Example configuration
hardware:
n9000a:
module.Class: 'scope.pyivi_specan.PyIviSpecAn'
uri: 'TCPIP::192.168.1.1::INSTR'
Optional parameter:
model: str: Model of the spectrum analyzer. Default: determine using VISA.
flavour: either 'IVI-COM' or 'IVI-C', two of the interfaces IVI supports. Default: IVI-COM.
simulate: boolean
Qudi is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Qudi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Qudi. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/>
"""
from interface.ivi import specan_interface as specan_ivi_interface
from .._pyivi_base import PyIviBase
from .._pyivi_base import QtInterfaceMetaclass
from .._ivi_core import Namespace
import abc
from qtpy.QtCore import QObject
from qtpy.QtCore import Signal
from comtypes.safearray import safearray_as_ndarray
import numpy
class _Specan(specan_ivi_interface.SpecAnIviInterface):
"""
"""
@Namespace
class level(QObject, specan_ivi_interface.SpecAnIviInterface.level, metaclass=QtInterfaceMetaclass):
amplitude_units_changed = Signal(specan_ivi_interface.AmplitudeUnits)
attenuation_changed = Signal(float)
attenuation_auto_changed = Signal(bool)
input_impedance_changed = Signal(int)
reference_changed = Signal(float)
reference_offset_changed = Signal(float)
@property
def amplitude_units(self):
"""
Specifies the amplitude units for input, output and display amplitude.
"""
return specan_ivi_interface.AmplitudeUnits(self.root.driver.level.amplitude_units - 1)
@amplitude_units.setter
def amplitude_units(self, value):
self.root.driver.level.amplitude_units = value.value + 1
self.amplitude_units_changed.emit(value)
@property
def attenuation(self):
"""
Specifies the input attenuation (in positive dB).
"""
return self.root.driver.level.attenuation
@attenuation.setter
def attenuation(self, value):
self.root.driver.level.attenuation = value
self.attenuation_changed.emit(value)
@property
def attenuation_auto(self):
"""
Selects attenuation automatically.
If set to True, attenuation is automatically selected. If set to False, attenuation is manually selected.
"""
return self.root.driver.level.attenuation_auto
@attenuation_auto.setter
def attenuation_auto(self, value):
self.root.driver.level.attenuation_auto = value
self.attenuation_auto_changed.emit(value)
@property
def input_impedance(self):
"""
Specifies the value of input impedance.
Specifies the value of input impedance, in ohms, expected at the active input port. This is typically
50 ohms or 75 ohms.
"""
return self.root.driver.level.input_impedance
@input_impedance.setter
def input_impedance(self, value):
self.root.driver.level.input_impedance = value
self.input_impedance_changed.emit(value)
@property
def reference(self):
"""
The calibrated vertical position of the captured data used as a reference for amplitude measurements. This
is typically set to a value slightly higher than the highest expected signal level. The units are
determined by the Amplitude Units attribute.
"""
return self.root.driver.level.reference
@reference.setter
def reference(self, value):
self.root.driver.level.reference = value
self.reference_changed.emit(value)
@property
def reference_offset(self):
"""
Specifies an offset for the Reference Level attribute.
This value is used to adjust the reference level for external signal gain or loss. A positive value
corresponds to a gain while a negative number corresponds to a loss. The value is in dB.
"""
return self.root.driver.level.reference_offset
@reference_offset.setter
def reference_offset(self, value):
self.root.driver.level.reference_offset = value
self.reference_offset_changed.emit(value)
def configure(self, amplitude_units, input_impedance, reference_level, reference_level_offset, attenuation):
"""
:param amplitude_units: Specifies the amplitude units for input, output and display. The driver uses this
value to set the Amplitude Units attribute. See the attribute description for more
details.
:param input_impedance: Specifies the input impedance. The driver uses this value to set the Input Impedance
attribute. See the attribute description for more details.
:param reference_level: Specifies the amplitude value of the reference level. The driver uses this value to
set the Reference Level attribute. See the attribute description for more details.
:param reference_level_offset: Specifies the offset value to the reference level. The driver uses this
value to set the Reference Level Offset attribute. See the attribute
description for more details.
:param attenuation: either boolean, Enables or disables auto attenuation. The driver uses this value to
set the Attenuation Auto attribute. See the attribute description for
more details.
or double, Specifies the attenuation level. The driver uses this value to set the
Attenuation attribute. See the attribute description for more details.
"""
self.root.driver.level.configure(amplitude_units,
input_impedance,
reference_level,
reference_level_offset,
attenuation)
@Namespace
class acquisition(QObject, specan_ivi_interface.SpecAnIviInterface.acquisition, metaclass=QtInterfaceMetaclass):
detector_type_changed = Signal(specan_ivi_interface.DetectorType)
detector_type_auto_changed = Signal(bool)
number_of_sweeps_changed = Signal(int)
sweep_mode_continuous_changed = Signal(bool)
vertical_scale_changed = Signal(specan_ivi_interface.VerticalScale)
@property
def detector_type(self):
"""
Specifies the detector type.
Specifies the detection method used to capture and process the signal. This governs the data acquisition
for a particular sweep, but does not have any control over how multiple sweeps are processed.
"""
return specan_ivi_interface.DetectorType(self.root.driver.sc.detector_type - 1)
@detector_type.setter
def detector_type(self, value):
self.root.driver.sc.detector_type = value.value + 1
self.detector_type_changed.emit(value)
@property
def detector_type_auto(self):
"""
Select detector type automatically.
If set to True, the detector type is automatically selected. The relationship between Trace Type and
Detector Type is not defined by the specification when the Detector Type Auto is set to True. If set to
False, the detector type is manually selected.
"""
return self.root.driver.acquisition.detector_type_auto
@detector_type_auto.setter
def detector_type_auto(self, value):
self.root.driver.acquisition.detector_type_auto = value
self.detector_type_auto_changed.emit(value)
@property
def number_of_sweeps(self):
"""
This attribute defines the number of sweeps.
This attribute value has no effect if the Trace Type attribute is set to the value Clear Write.
"""
return self.root.driver.sc.number_of_sweeps
@number_of_sweeps.setter
def number_of_sweeps(self, value):
self.root.driver.sc.number_of_sweeps = value
self.number_of_sweeps_changed.emit(value)
@property
def sweep_mode_continuous(self):
"""
Is the sweep mode continuous?
If set to True, the sweep mode is continuous If set to False, the sweep mode is not continuous.
"""
return self.root.driver.acquisition.sweep_mode_continuous
@sweep_mode_continuous.setter
def sweep_mode_continuous(self, value):
self.root.driver.acquisition.sweep_mode_continuous = value
self.sweep_mode_continuous_changed.emit(value)
@property
def vertical_scale(self):
"""
Specifies the vertical scale of the measurement hardware (use of log amplifiers versus linear amplifiers).
"""
return specan_ivi_interface.VerticalScale(self.root.driver.acquisition.vertical_scale - 1)
@vertical_scale.setter
def vertical_scale(self, value):
self.root.driver.acquisition.vertical_scale = value.value + 1
self.vertical_scale_changed.emit(value)
def configure(self, sweep_mode_continuous, number_of_sweeps, detector_type_auto, detector_type,
vertical_scale):
"""
This function configures the acquisition attributes of the spectrum analyzer.
:param sweep_mode_continuous: Enables or disables continuous sweeping. The driver uses this value to set the
Sweep Mode Continuous attribute. See the attribute description for more
details.
:param number_of_sweeps: Specifies the number of sweeps to take. The driver uses this value to set the
Number Of Sweeps attribute. See the attribute description for more details.
:param detector_type_auto: Enables or Disables the auto detector. The driver uses this value to set the
Detector Type Auto attribute. See the attribute description for more details.
:param detector_type: Specifies the method of capturing and processing signal data. The driver uses this
value to set the Detector Type attribute. See the attribute description for more
details.
:param vertical_scale: Specifies the vertical scale. The driver uses this value to set the Vertical Scale
attribute. See the attribute description for more details.
"""
self.root.driver.acquisition.configure(sweep_mode_continuous,
number_of_sweeps,
detector_type_auto,
detector_type.value+1)
@Namespace
class frequency(QObject, specan_ivi_interface.SpecAnIviInterface.frequency, metaclass=QtInterfaceMetaclass):
start_changed = Signal(float)
stop_changed = Signal(float)
offset_changed = Signal(float)
@property
def start(self):
"""
Start frequency.
Specifies the left edge of the frequency domain in Hertz. This is used in conjunction with the Frequency
Stop attribute to define the frequency domain. If the Frequency Start attribute value is equal to the
Frequency Stop attribute value then the spectrum analyzer's horizontal attributes are in time-domain.
"""
return self.root.driver.sc.frequency_start
@start.setter
def start(self, value):
self.root.driver.sc.frequency_start = value
self.start_changed.emit(value)
@property
def stop(self):
"""
Stop frequency.
Specifies the right edge of the frequency domain in Hertz. This is used in conjunction with the Frequency
Start attribute to define the frequency domain. If the Frequency Start attribute value is equal to the
Frequency Stop attribute value then the spectrum analyzer's horizontal attributes are in time-domain.
"""
return self.root.driver.sc.frequency_stop
@stop.setter
def stop(self, value):
self.root.driver.sc.frequency_stop = value
self.stop_changed.emit(value)
@property
def offset(self):
"""
Frequency offset.
Specifies an offset value, in Hertz, that is added to the frequency readout. The offset is used to
compensate for external frequency conversion. This changes the driver's Frequency Start and Frequency Stop
attributes.
The equations relating the affected values are:
Frequency Start = Actual Start Frequency + Frequency Offset
Frequency Stop = Actual Stop Frequency + Frequency Offset
Marker Position = Actual Marker Frequency + Frequency Offset
"""
return self.root.driver.frequency.offset
@offset.setter
def offset(self, value):
self.root.driver.frequency.offset = value
self.offset_changed.emit(value)
def configure_center_span(self, center_frequency, span):
"""
This function configures the frequency range defining the center frequency and the frequency span. If the
span corresponds to zero Hertz, then the spectrum analyzer operates in time-domain mode. Otherwise, the
spectrum analyzer operates in frequency-domain mode.
This function modifies the Frequency Start and Frequency Stop attributes as follows:
Frequency Start = CenterFrequency - Span / 2
Frequency Stop = CenterFrequency + Span / 2
:param center_frequency: Specifies the center frequency of the frequency sweep. The units are Hertz.
:param span: Specifies the frequency span of the frequency sweep. The units are Hertz.
"""
self.root.driver.frequency.configure_center_span(center_frequency, span)
self.start_changed.emit(self.start)
self.stop_changed.emit(self.stop)
def configure_start_stop(self, start_frequency, stop_frequency):
"""
This function configures the frequency range defining its start frequency and its stop frequency. If the
start frequency is equal to the stop frequency, then the spectrum analyzer operates in time-domain mode.
Otherwise, the spectrum analyzer operates in frequency-domain mode.
:param start_frequency: Specifies the start frequency of the frequency sweep (in Hertz). The driver uses
this value to set the Frequency Start attribute. See the attribute description for
more details.
:param stop_frequency: Specifies the stop frequency of the frequency sweep (in Hertz). The driver uses this
value to set the Frequency Stop attribute. See the attribute description for more
details.
"""
self.root.driver.frequency.configure_start_stop(start_frequency, stop_frequency)
self.start_changed.emit(self.start)
self.stop_changed.emit(self.stop)
@Namespace
class sweep_coupling(QObject,
specan_ivi_interface.SpecAnIviInterface.sweep_coupling,
metaclass=QtInterfaceMetaclass):
resolution_bandwidth_changed = Signal(float)
resolution_bandwidth_auto_changed = Signal(bool)
sweep_time_changed = Signal(float)
sweep_time_auto_changed = Signal(bool)
video_bandwidth_changed = Signal(float)
video_bandwidth_auto_changed = Signal(bool)
@property
def resolution_bandwidth(self):
"""
Specifies the resolution bandwidth.
Specifies the width of the IF filter in Hertz. For more information see Section 4.1.1, Sweep Coupling
Overview.
"""
return self.root.driver.sc.resolution_bandwidth
@resolution_bandwidth.setter
def resolution_bandwidth(self, value):
self.root.driver.sc.resolution_bandwidth = value
self.resolution_bandwidth_changed.emit(value)
@property
def resolution_bandwidth_auto(self):
"""
Select resolution bandwidth automatically.
If set to True, the resolution bandwidth is automatically selected. If set to False, the resolution
bandwidth is manually selected.
"""
return self.root.driver.sweep_coupling.resolution_bandwidth_auto
@resolution_bandwidth_auto.setter
def resolution_bandwidth_auto(self, value):
self.root.driver.sweep_coupling.resolution_bandwidth_auto = value
self.resolution_bandwidth_auto_changed.emit(value)
@property
def sweep_time(self):
"""
Specifies the sweep time.
Specifies the length of time to sweep from the left edge to the right edge of the current domain.
The units are seconds.
"""
return self.root.driver.sc.sweep_time
@sweep_time.setter
def sweep_time(self, value):
self.root.driver.sc.sweep_time = value
self.sweep_time_changed.emit(value)
@property
def sweep_time_auto(self):
"""
Select sweep time automatically.
If set to True, the sweep time is automatically selected If set to False, the sweep time is manually
selected.
"""
return self.root.driver.sweep_coupling.sweep_time_auto
@sweep_time_auto.setter
def sweep_time_auto(self, value):
self.root.driver.sweep_coupling.sweep_time_auto = value
self.sweep_time_auto_changed.emit(value)
@property
def video_bandwidth(self):
"""
Specifies the video bandwidth of the post-detection filter in Hertz.
"""
return self.root.driver.sweep_coupling.video_bandwidth
@video_bandwidth.setter
def video_bandwidth(self, value):
self.root.driver.sweep_coupling.video_bandwidth = value
self.video_bandwidth_changed.emit(value)
@property
def video_bandwidth_auto(self):
"""
Select video bandwidth automatically.
If set to True, the video bandwidth is automatically selected. If set to False, the video bandwidth is
manually selected.
"""
return self.root.driver.sweep_coupling.video_bandwidth_auto
@video_bandwidth_auto.setter
def video_bandwidth_auto(self, value):
self.root.driver.sweep_coupling.video_bandwidth_auto = value
self.video_bandwidth_auto_changed.emit(value)
def configure(self, resolution_bandwidth, video_bandwidth, sweep_time):
"""
This function configures the coupling and sweeping attributes. For additional sweep coupling information
refer to Section 4.1.1, Sweep Coupling Overview.
:param resolution_bandwidth: either boolean True, Enables resolution bandwidth auto coupling. The
driver uses this value to set the Resolution Bandwidth Auto
attribute. See the attribute description for more details.
or float, Specifies the measurement resolution bandwidth in Hertz. The driver
uses this value to set the Resolution Bandwidth attribute and
disables auto coupling. See the attribute description for more
details.
:param video_bandwidth: either boolean True, Enables video bandwidth auto coupling. The driver uses
this value to set the Video Bandwidth Auto attribute. See the
attribute description for more details.
or float, Specifies the video bandwidth of the postdetection filter in Hertz.
The driver uses this value to set the Video Bandwidth attribute and
disables auto coupling. See the attribute description for more details.
:param sweep_time: either boolean True, Enables sweep time auto coupling. The driver uses this value
to set the Sweep Time Auto attribute. See the attribute description for
more details.
or float, Specifies the length of time to sweep from the left edge to the right edge of
the current domain. Units are seconds. The driver uses this value to set the
Sweep Time attribute and disables auto coupling. See the attribute description
for more details.
"""
resolution_bandwidth_auto = False
video_bandwidth_auto = False
sweep_time_auto = False
if resolution_bandwidth == True:
resolution_bandwidth_auto = True
resolution_bandwidth = 0
if video_bandwidth == True:
video_bandwidth_auto = True
video_bandwidth = 0
if sweep_time == True:
sweep_time_auto = True
sweep_time = 0
self.root.driver.sweep_coupling.configure(resolution_bandwidth_auto,
resolution_bandwidth,
video_bandwidth_auto,
video_bandwidth,
sweep_time_auto,
sweep_time)
self.resolution_bandwidth_auto_changed.emit(resolution_bandwidth_auto)
self.resolution_bandwidth_changed.emit(resolution_bandwidth)
self.video_bandwidth_auto_changed.emit(video_bandwidth_auto)
self.video_bandwidth_changed.emit(video_bandwidth)
self.sweep_time_auto_changed.emit(sweep_time_auto)
self.sweep_time_changed.emit(sweep_time)
class trace(specan_ivi_interface.SpecAnIviInterface.trace):
"""
Repeated capability, attribute name traces.
"""
@property
def name(self):
"""
Name of trace.
Returns the physical repeated capability identifier defined by the specific driver for the trace that
corresponds to the index that the user specifies. If the driver defines a qualified trace name, this
property returns the qualified name.
"""
self.root.driver.sc.trace_idx = self.index + 1
return self.root.driver.sc.trace_name
@property
def type(self):
"""
Specifies the representation of the acquired data.
"""
self.root.driver.sc.trace_idx = self.index + 1
return specan_ivi_interface.TraceType(self.root.driver.sc.tr_type - 1)
@type.setter
def type(self, value):
self.root.driver.sc.trace_idx = self.index + 1
self.root.driver.sc.tr_type = value.value + 1
def fetch_y(self):
"""
Fetches y values from last measurement.
This function returns the trace the spectrum analyzer acquires. The trace is from a previously initiated
acquisition. The user calls the Initiate function to start an acquisition. The user calls the
Acquisition Status function to determine when the acquisition is complete.
The user may call the Read Y Trace function instead of the Initiate function. This function starts an
acquisition, waits for the acquisition to complete, and returns the trace in one function call.
The Amplitude array returns data that represents the amplitude of the signals obtained by sweeping from
the start frequency to the stop frequency (in frequency domain, in time domain the amplitude array is
ordered from beginning of sweep to end). The Amplitude Units attribute determines the units of the points
in the Amplitude array.
This function does not check the instrument status. The user calls the Error Query function at the
conclusion of the sequence to check the instrument status.
:return: (numpy array of frequencies, numpy array of amplitude values)
"""
self.root.driver.sc.trace_idx = self.index + 1
with safearray_as_ndarray:
return self.root.driver.sc.fetch()
def read_y(self, maximum_time):
"""
Read y values after initiating an acquisition.
This function initiates a signal acquisition based on the present instrument configuration. It then waits
for the acquisition to complete, and returns the trace as an array of amplitude values. The amplitude array
returns data that represent the amplitude of the signals obtained by sweeping from the start frequency to
the stop frequency (in frequency domain, in time domain the amplitude array is ordered from beginning of
sweep to end). The Amplitude Units attribute determines the units of the points in the amplitude array.
This function resets the sweep count.
If the spectrum analyzer did not complete the acquisition within the time period the user specified with
the MaxTime parameter, the function raises the Max Time Exceeded error.
:param maximum_time: MAX_TIME_IMMEDIATE: The function returns immediately. If no valid measurement value
exists, the function raises an error.
MAX_TIME_INDEFINITE: The function waits indefinitely for the measurement to complete.
otherwise: time the functions waits before raising a timeout error in milliseconds.
:return: (numpy array of frequencies, numpy array of amplitude values)
"""
self.root.driver.sc.trace_idx = self.index + 1
with safearray_as_ndarray:
y_trace = self.root.driver.traces[self.name].read_y(int(maximum_time))
if self.root.frequency.start == self.root.frequency.stop:
x_start = 0
x_stop = self.root.sweep_coupling.sweep_time
else:
x_start = self.root.frequency.start
x_stop = self.root.frequency.stop
size = self.root.driver.traces[self.root.driver.sc.trace_name].size
x_trace = numpy.linspace(x_start, x_stop, size, True)
return x_trace, y_trace
class traces(specan_ivi_interface.SpecAnIviInterface.traces):
def initiate(self):
"""
This function initiates an acquisition.
After calling this function, the spectrum analyzer leaves the idle state.
This function does not check the instrument status. The user calls the Acquisition Status function to
determine when the acquisition is complete.
"""
self.root.driver.session.traces.Initiate()
def abort(self):
"""
Aborts a running measurement.
This function aborts a previously initiated measurement and returns the spectrum analyzer to the idle
state. This function does not check instrument status.
"""
self.root.driver.session.traces.Abort()
def acquisition_status(self):
"""
This function determines and returns the status of an acquisition.
"""
return specan_ivi_interface.AcquisitionStatus(self.root.driver.session.traces.AcquisitionStatus())
# endregion
# region Extensions
class MultitraceExtension(specan_ivi_interface.MultitraceExtensionInterface):
"""
Extension IVI methods for spectrum analyzers supporting simple mathematical operations on traces
"""
class traces:
@Namespace
class math(QObject,
specan_ivi_interface.MultitraceExtensionInterface.traces.math,
metaclass=QtInterfaceMetaclass):
"""
The math namespace is supposed to be implemented as traces.math and not as repeated capability.
"""
def add(self, dest_trace, trace1, trace2):
"""
Adds two traces.
This function modifies a trace to be the point by point sum of two other traces. Any data in the
destination trace is deleted.
DestinationTrace = Trace1 + Trace2
:param dest_trace: Specifies the name of the result
:param trace1: Specifies the name of first trace operand.
:param trace2: Specifies the name of the second trace operand.
:return:
"""
self.root.driver.traces.math.add(dest_trace, trace1, trace2)
def copy(self, dest_trace, src_trace):
"""
Copies a trace.
This function copies the data array from one trace into another trace. Any data in the Destination
Trace is deleted.
:param dest_trace: Specifies the name of the trace into which the array is copied.
:param src_trace: Specifies the name of the trace to be copied.
:return:
"""
self.root.driver.traces.math.copy(dest_trace, src_trace)
def exchange(self, trace1, trace2):
"""
Exchanges two traces.
This function exchanges the data arrays of two traces.
:param trace1: Specifies the name of the first trace to be exchanged.
:param trace2: Specifies the name of the second trace to be exchanged.
:return:
"""
self.root.driver.traces.math.exchange(trace1, trace2)
def subtract(self, dest_trace, trace1, trace2):
"""
Subtracts two traces.
This function modifies a trace to be the point by point difference of two other traces. Any data in the
destination trace is deleted.
DestinationTrace = Trace1 - Trace2
:param dest_trace: Specifies the name of the result
:param trace1: Specifies the name of first trace operand.
:param trace2: Specifies the name of the second trace operand.
:return:
"""
self.root.driver.traces.math.subtract(dest_trace, trace1, trace2)
class MarkerExtension(specan_ivi_interface.MarkerExtensionInterface):
"""
The IviSpecAnMarker extension group supports spectrum analyzers that have markers. Markers are applied
to traces and used for a wide range of operations. Some operations are simple, such as reading an
amplitude value at an X-axis position, while others operations are complex, such as signal tracking.
"""
class marker(specan_ivi_interface.MarkerExtensionInterface.marker):
"""
Contains all marker functions. Repeated namespace.
"""
enabled_changed = Signal(bool)
position_changed = Signal(float)
threshold_changed = Signal(float)
trace_changed = Signal(str)
peak_excursion_changed = Signal(float)
signal_track_enabled_changed = Signal(bool)
@property
def amplitude(self):
"""
Marker amplitude.
Returns the amplitude of the marker. The units are specified by the Amplitude Units attribute, except
when the Marker Type attribute is set to Delta. Then the units are dB. If the Marker Enabled attribute is
set to False, any attempt to read this attribute returns the Marker Not Enabled error.
:return: Query Marker
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.amplitude
@property
def enabled(self):
"""
Marker enabled.
If set to True, the marker is enabled. When False, the marker is disabled.
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.enabled
@enabled.setter
def enabled(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.enabled = value
self.enabled_changed.emit(value)
@Namespace
class frequency_counter(QObject,
specan_ivi_interface.MarkerExtensionInterface.marker.frequency_counter,
metaclass=QtInterfaceMetaclass):
enabled_changed = Signal(bool)
resolution_changed = Signal(float)
@property
def enabled(self):
"""
Frequency counter enabled.
Enables/disables the marker frequency counter for greater marker measurement accuracy. If set to True,
the marker frequency counter is enabled. If set to False, the marker frequency counter is disabled. This
attribute returns the Marker Not Enabled error if the Marker Enabled attribute is set to False..
"""
self.root.driver.marker.active_marker = self.parent_namespace.name
return self.root.driver.marker.frequency_counter.enabled
@enabled.setter
def enabled(self, value):
self.root.driver.marker.active_marker = self.parent_namespace.name
self.root.driver.marker.frequency_counter.enabled = value
self.enabled_changed.emit(value)
@property
def resolution(self):
"""
Frequency counter resolution.
Specifies the resolution of the frequency counter in Hertz. The measurement gate time is the reciprocal
of the specified resolution.
"""
self.root.driver.marker.active_marker = self.parent_namespace.name
return self.root.driver.marker.frequency_counter.resolution
@resolution.setter
def resolution(self, value):
self.root.driver.marker.active_marker = self.parent_namespace.name
self.root.driver.marker.frequency_counter.resolution = value
self.resolution_changed.emit(value)
def configure(self, enabled, resolution):
"""
This function sets the marker frequency counter resolution and enables or disables the marker frequency
counter.
:param enabled: Enables or disables the marker frequency counter. The driver uses this value to set
the Marker Frequency Counter Enabled attribute. See the attribute description for more
details.
:param resolution: Specifies the frequency counter resolution in Hertz. This value is ignored when
Enabled is False. The driver uses this value to set the Marker Frequency Counter
Resolution attribute. See the attribute description for more details.
:return:
"""
self.root.driver.marker.active_marker = self.parent_namespace.name
self.root.driver.marker.frequency_counter.configure(enabled, resolution)
self.enabled_changed.emit(enabled)
self.resolution_changed.emit(resolution)
@property
def name(self):
"""
This property returns the marker identifier.
"""
return self.root.driver.marker.name(self.index + 1)
@property
def position(self):
"""
Marker position.
Specifies the frequency in Hertz or time position in seconds of the marker (depending on the mode in
which the analyzer is operating, frequency or time-domain). This attribute returns the Marker Not
Enabled error if the marker is not enabled.
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.position
@position.setter
def position(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.position = value
self.position_changed.emit(value)
@property
def threshold(self):
"""
Specifies the lower limit of the search domain vertical range for the Marker Search function.
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.threshold
@threshold.setter
def threshold(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.threshold = value
self.threshold_changed.emit(value)
@property
def trace(self):
"""
Specifies the Trace for the marker.
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.trace
@trace.setter
def trace(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.trace = value
self.trace_changed.emit(value)
@property
def peak_excursion(self):
"""
Specifies the minimum amplitude variation of the signal in dB that the Marker Search function can
identify as a peak.
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.peak_excursion
@peak_excursion.setter
def peak_excursion(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.peak_excursion = value
self.peak_excursion_changed.emit(value)
@property
def signal_track_enabled(self):
"""
Track the signal.
If set to True, the spectrum analyzer centers the signal after each sweep. This process invalidates the
Frequency Start and Frequency Stop attributes. If set to False, the spectrum analyzer does not center
the signal after each sweep.
Operations on this attribute return the Marker Not Enabled error if the marker is not enabled.
Note: Signal tracking can only be enabled on one marker at any given time. The driver is responsible for
enforcing this policy
"""
self.root.driver.marker.active_marker = self.name
return self.root.driver.marker.signal_track_enabled
@signal_track_enabled.setter
def signal_track_enabled(self, value):
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.signal_track_enabled = value
self.signal_track_enabled_changed.emit(value)
def configure_enabled(self, enabled, trace):
"""
This function enables the marker on the specified Trace.
:param enabled: Enables or disables the marker. The driver uses this value to set the Marker Enabled
attribute. See the attribute description for more details.
:param trace: Specifies the trace name. The driver uses this value to set the Marker Trace attribute.
See the attribute description for more details.
:return:
"""
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.configure_enabled(enabled, trace)
self.enabled_changed.emit(enabled)
self.trace_changed.emit(trace)
def configure_search(self, peak_excursion, marker_threshold):
"""
This function configures the Peak Excursion and Marker Threshold attribute values.
:param peak_excursion: Minimum amplitude variation of the signal that the marker can recognize as a peak
in dB. The driver uses this value to set the Peak Excursion attribute. See the
attribute description for more details.
:param marker_threshold: Minimum amplitude below which a peak will not be detected. The driver uses this
value to set the Marker Threshold attribute. See the attribute description for
more details.
:return:
"""
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.configure_search(peak_excursion, marker_threshold)
self.peak_excursion_changed.emit(peak_excursion)
self.threshold_changed.emit(marker_threshold)
def search(self, search_type):
"""
This function specifies the type of marker search and performs the search. This function returns the Marker
Not Enabled error if the Marker Enabled attribute is set to False.
:param search_type: Specifies the type of marker search.
"""
self.root.driver.marker.active_marker = self.name
self.root.driver.marker.search(search_type.value + 1)
def query(self):
"""
This function returns the horizontal position and the amplitude level of the marker.
:return: set (marker position, marker amplitude)
"""
self.root.driver.marker.active_marker = self.name
return set(self.root.driver.marker.query())
class markers(specan_ivi_interface.MarkerExtensionInterface.markers):
def disable_all(self):
"""
This function disables all markers.
"""
self.root.driver.marker.disable_all()
class TriggerExtension(specan_ivi_interface.TriggerExtensionInterface):
"""
This extension group specifies the source of the trigger signal that causes the analyzer to leave the
Wait-For-Trigger state.
"""
class trigger(specan_ivi_interface.TriggerExtensionInterface.trigger):
source_changed = Signal(specan_ivi_interface.TriggerSource)
@property
def source(self):
"""
Specifies the source of the trigger signal that causes the analyzer to leave the Wait-For-Trigger state.
"""
return specan_ivi_interface.TriggerSource(self.root.driver.trigger.source - 1)
@source.setter
def source(self, value):
self.root.driver.trigger.source = value.value + 1
self.source_changed.emit(value)
class ExternalTriggerExtension(specan_ivi_interface.ExternalTriggerExtensionInterface):
"""
This extension group specifies the external trigger level and external trigger slope when the Trigger Source
Attribute is set to external, which causes the analyzer to leave the Wait-For-Trigger state.
"""
class trigger:
class external(QObject,
specan_ivi_interface.ExternalTriggerExtensionInterface.trigger.external,
metaclass=QtInterfaceMetaclass):
level_changed = Signal(float)
slope_changed = Signal(specan_ivi_interface.Slope)
@property
def level(self):
"""
Specifies the level, in Volts, that the external trigger signal shall reach to trigger the acquisition.