acoular 24.3__py3-none-any.whl → 24.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. acoular/__init__.py +118 -50
  2. acoular/calib.py +29 -38
  3. acoular/configuration.py +116 -73
  4. acoular/demo/__init__.py +10 -4
  5. acoular/demo/acoular_demo.py +78 -53
  6. acoular/environments.py +265 -262
  7. acoular/fastFuncs.py +361 -191
  8. acoular/fbeamform.py +1460 -1404
  9. acoular/grids.py +501 -545
  10. acoular/h5cache.py +50 -59
  11. acoular/h5files.py +154 -137
  12. acoular/internal.py +10 -11
  13. acoular/microphones.py +57 -53
  14. acoular/sdinput.py +47 -52
  15. acoular/signals.py +167 -179
  16. acoular/sources.py +818 -693
  17. acoular/spectra.py +349 -359
  18. acoular/tbeamform.py +414 -413
  19. acoular/tfastfuncs.py +178 -101
  20. acoular/tools/__init__.py +25 -0
  21. acoular/tools/aiaa.py +186 -0
  22. acoular/tools/helpers.py +189 -0
  23. acoular/tools/metrics.py +165 -0
  24. acoular/tprocess.py +1201 -1143
  25. acoular/traitsviews.py +513 -501
  26. acoular/trajectory.py +50 -52
  27. acoular/version.py +5 -6
  28. acoular/xml/minidsp_uma-16.xml +20 -0
  29. acoular/xml/{minidsp_uma16.xml → minidsp_uma-16_mirrored.xml} +3 -0
  30. {acoular-24.3.dist-info → acoular-24.5.dist-info}/METADATA +45 -46
  31. acoular-24.5.dist-info/RECORD +50 -0
  32. {acoular-24.3.dist-info → acoular-24.5.dist-info}/WHEEL +1 -1
  33. acoular-24.5.dist-info/licenses/LICENSE +28 -0
  34. acoular/fileimport.py +0 -380
  35. acoular/nidaqimport.py +0 -273
  36. acoular/tests/reference_data/BeamformerBase.npy +0 -0
  37. acoular/tests/reference_data/BeamformerBaseFalse1.npy +0 -0
  38. acoular/tests/reference_data/BeamformerBaseFalse2.npy +0 -0
  39. acoular/tests/reference_data/BeamformerBaseFalse3.npy +0 -0
  40. acoular/tests/reference_data/BeamformerBaseFalse4.npy +0 -0
  41. acoular/tests/reference_data/BeamformerBaseTrue1.npy +0 -0
  42. acoular/tests/reference_data/BeamformerBaseTrue2.npy +0 -0
  43. acoular/tests/reference_data/BeamformerBaseTrue3.npy +0 -0
  44. acoular/tests/reference_data/BeamformerBaseTrue4.npy +0 -0
  45. acoular/tests/reference_data/BeamformerCMFLassoLarsBIC.npy +0 -0
  46. acoular/tests/reference_data/BeamformerCMFNNLS.npy +0 -0
  47. acoular/tests/reference_data/BeamformerCapon.npy +0 -0
  48. acoular/tests/reference_data/BeamformerClean.npy +0 -0
  49. acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
  50. acoular/tests/reference_data/BeamformerCleant.npy +0 -0
  51. acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
  52. acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
  53. acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
  54. acoular/tests/reference_data/BeamformerDamas.npy +0 -0
  55. acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
  56. acoular/tests/reference_data/BeamformerEig.npy +0 -0
  57. acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
  58. acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
  59. acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
  60. acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
  61. acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
  62. acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
  63. acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
  64. acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
  65. acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
  66. acoular/tests/reference_data/BeamformerGIB.npy +0 -0
  67. acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
  68. acoular/tests/reference_data/BeamformerMusic.npy +0 -0
  69. acoular/tests/reference_data/BeamformerOrth.npy +0 -0
  70. acoular/tests/reference_data/BeamformerSODIX.npy +0 -0
  71. acoular/tests/reference_data/BeamformerTime.npy +0 -0
  72. acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
  73. acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
  74. acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
  75. acoular/tests/reference_data/Environment.npy +0 -0
  76. acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
  77. acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
  78. acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  79. acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
  80. acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
  81. acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
  82. acoular/tests/reference_data/FiltOctave__.npy +0 -0
  83. acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  84. acoular/tests/reference_data/Filter__.npy +0 -0
  85. acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
  86. acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
  87. acoular/tests/reference_data/OpenJet.npy +0 -0
  88. acoular/tests/reference_data/PointSource.npy +0 -0
  89. acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
  90. acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
  91. acoular/tests/reference_data/RotatingFlow.npy +0 -0
  92. acoular/tests/reference_data/SlotJet.npy +0 -0
  93. acoular/tests/reference_data/TimeAverage__.npy +0 -0
  94. acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
  95. acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
  96. acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
  97. acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
  98. acoular/tests/reference_data/TimeInOut__.npy +0 -0
  99. acoular/tests/reference_data/TimePower__.npy +0 -0
  100. acoular/tests/reference_data/TimeReverse__.npy +0 -0
  101. acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
  102. acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
  103. acoular/tests/run_tests.sh +0 -18
  104. acoular/tests/run_tests_osx.sh +0 -16
  105. acoular/tests/test.npy +0 -0
  106. acoular/tests/test_beamformer_results.py +0 -213
  107. acoular/tests/test_classes.py +0 -60
  108. acoular/tests/test_digest.py +0 -125
  109. acoular/tests/test_environments.py +0 -73
  110. acoular/tests/test_example1.py +0 -124
  111. acoular/tests/test_grid.py +0 -92
  112. acoular/tests/test_integrate.py +0 -102
  113. acoular/tests/test_signals.py +0 -60
  114. acoular/tests/test_sources.py +0 -65
  115. acoular/tests/test_spectra.py +0 -38
  116. acoular/tests/test_timecache.py +0 -35
  117. acoular/tests/test_tprocess.py +0 -90
  118. acoular/tests/test_traj_beamformer_results.py +0 -164
  119. acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
  120. acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
  121. acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
  122. acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
  123. acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
  124. acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
  125. acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
  126. acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
  127. acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
  128. acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
  129. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
  130. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
  131. acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
  132. acoular/tests/unsupported/functionalBeamformer.py +0 -123
  133. acoular/tests/unsupported/precisionTest.py +0 -153
  134. acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
  135. acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
  136. acoular/tools.py +0 -422
  137. acoular-24.3.dist-info/RECORD +0 -148
  138. acoular-24.3.dist-info/licenses/LICENSE +0 -29
  139. {acoular-24.3.dist-info → acoular-24.5.dist-info}/licenses/AUTHORS.rst +0 -0
acoular/spectra.py CHANGED
@@ -1,48 +1,76 @@
1
- # -*- coding: utf-8 -*-
2
- #pylint: disable-msg=E0611, E1101, E1103, C0103, R0901, R0902, R0903, R0904
3
- #pylint: disable-msg=W0232
4
- #------------------------------------------------------------------------------
1
+ # ------------------------------------------------------------------------------
5
2
  # Copyright (c) Acoular Development Team.
6
- #------------------------------------------------------------------------------
7
- """Estimation of power spectra and related tools
3
+ # ------------------------------------------------------------------------------
4
+ """Estimation of power spectra and related tools.
8
5
 
9
6
  .. autosummary::
10
7
  :toctree: generated/
11
8
 
12
9
  BaseSpectra
13
- FFTSpectra
10
+ FFTSpectra
14
11
  PowerSpectra
15
12
  synthetic
16
13
  PowerSpectraImport
17
14
  """
15
+
18
16
  from warnings import warn
19
17
 
20
- from numpy import array, ones, hanning, hamming, bartlett, blackman, \
21
- dot, newaxis, zeros, empty, linalg, sqrt,real, imag,\
22
- searchsorted, isscalar, fill_diagonal, arange, zeros_like, sum, ndarray
18
+ from numpy import (
19
+ arange,
20
+ array,
21
+ bartlett,
22
+ blackman,
23
+ dot,
24
+ empty,
25
+ fill_diagonal,
26
+ hamming,
27
+ hanning,
28
+ imag,
29
+ isscalar,
30
+ linalg,
31
+ ndarray,
32
+ newaxis,
33
+ ones,
34
+ real,
35
+ searchsorted,
36
+ sqrt,
37
+ sum,
38
+ zeros,
39
+ zeros_like,
40
+ )
23
41
  from scipy import fft
24
- from traits.api import HasPrivateTraits, Int, Property, Instance, Trait, \
25
- Bool, cached_property, property_depends_on, Delegate, Float, Enum, \
26
- CArray
42
+ from traits.api import (
43
+ Bool,
44
+ CArray,
45
+ Delegate,
46
+ Enum,
47
+ Float,
48
+ HasPrivateTraits,
49
+ Instance,
50
+ Int,
51
+ Property,
52
+ Trait,
53
+ cached_property,
54
+ property_depends_on,
55
+ )
27
56
 
57
+ from .calib import Calib
58
+ from .configuration import config
28
59
  from .fastFuncs import calcCSM
29
60
  from .h5cache import H5cache
30
61
  from .h5files import H5CacheFileBase
31
62
  from .internal import digest
32
63
  from .tprocess import SamplesGenerator, TimeInOut
33
- from .calib import Calib
34
- from .configuration import config
35
-
36
64
 
37
- class BaseSpectra( HasPrivateTraits ):
38
65
 
66
+ class BaseSpectra(HasPrivateTraits):
39
67
  #: Data source; :class:`~acoular.sources.SamplesGenerator` or derived object.
40
68
  source = Trait(SamplesGenerator)
41
69
 
42
70
  #: Sampling frequency of output signal, as given by :attr:`source`.
43
71
  sample_freq = Delegate('source')
44
72
 
45
- #: Number of time data channels
73
+ #: Number of time data channels
46
74
  numchannels = Delegate('source')
47
75
 
48
76
  #: Window function for FFT, one of:
@@ -51,117 +79,121 @@ class BaseSpectra( HasPrivateTraits ):
51
79
  #: * 'Hamming'
52
80
  #: * 'Bartlett'
53
81
  #: * 'Blackman'
54
- window = Trait('Rectangular',
55
- {'Rectangular':ones,
56
- 'Hanning':hanning,
57
- 'Hamming':hamming,
58
- 'Bartlett':bartlett,
59
- 'Blackman':blackman},
60
- desc="type of window for FFT")
82
+ window = Trait(
83
+ 'Rectangular',
84
+ {'Rectangular': ones, 'Hanning': hanning, 'Hamming': hamming, 'Bartlett': bartlett, 'Blackman': blackman},
85
+ desc='type of window for FFT',
86
+ )
61
87
 
62
88
  #: Overlap factor for averaging: 'None'(default), '50%', '75%', '87.5%'.
63
- overlap = Trait('None', {'None':1, '50%':2, '75%':4, '87.5%':8},
64
- desc="overlap of FFT blocks")
65
-
89
+ overlap = Trait('None', {'None': 1, '50%': 2, '75%': 4, '87.5%': 8}, desc='overlap of FFT blocks')
90
+
66
91
  #: FFT block size, one of: 128, 256, 512, 1024, 2048 ... 65536,
67
92
  #: defaults to 1024.
68
- block_size = Trait(1024, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
69
- desc="number of samples per FFT block")
70
-
71
- #: The floating-number-precision of entries of csm, eigenvalues and
93
+ block_size = Trait(
94
+ 1024,
95
+ 128,
96
+ 256,
97
+ 512,
98
+ 1024,
99
+ 2048,
100
+ 4096,
101
+ 8192,
102
+ 16384,
103
+ 32768,
104
+ 65536,
105
+ desc='number of samples per FFT block',
106
+ )
107
+
108
+ #: The floating-number-precision of entries of csm, eigenvalues and
72
109
  #: eigenvectors, corresponding to numpy dtypes. Default is 64 bit.
73
- precision = Trait('complex128', 'complex64',
74
- desc="precision of the fft")
75
-
110
+ precision = Trait('complex128', 'complex64', desc='precision of the fft')
111
+
76
112
  # internal identifier
77
- digest = Property( depends_on = ['precision','block_size',
78
- 'window','overlap'])
113
+ digest = Property(depends_on=['precision', 'block_size', 'window', 'overlap'])
79
114
 
80
115
  @cached_property
81
- def _get_digest( self ):
116
+ def _get_digest(self):
82
117
  return digest(self)
83
118
 
84
- def fftfreq ( self ):
85
- """
86
- Return the Discrete Fourier Transform sample frequencies.
87
-
119
+ def fftfreq(self):
120
+ """Return the Discrete Fourier Transform sample frequencies.
121
+
88
122
  Returns
89
123
  -------
90
124
  f : ndarray
91
125
  Array of length *block_size/2+1* containing the sample frequencies.
126
+
92
127
  """
93
128
  if self.source is not None:
94
- return abs(fft.fftfreq(self.block_size, 1./self.source.sample_freq)\
95
- [:int(self.block_size/2+1)])
96
- else:
97
- return None
129
+ return abs(fft.fftfreq(self.block_size, 1.0 / self.source.sample_freq)[: int(self.block_size / 2 + 1)])
130
+ return None
98
131
 
99
- #generator that yields the time data blocks for every channel (with optional overlap)
132
+ # generator that yields the time data blocks for every channel (with optional overlap)
100
133
  def get_source_data(self):
101
134
  bs = self.block_size
102
- temp = empty((2*bs, self.numchannels))
135
+ temp = empty((2 * bs, self.numchannels))
103
136
  pos = bs
104
- posinc = bs/self.overlap_
137
+ posinc = bs / self.overlap_
105
138
  for data_block in self.source.result(bs):
106
139
  ns = data_block.shape[0]
107
- temp[bs:bs+ns] = data_block # fill from right
108
- while pos+bs <= bs+ns:
109
- yield temp[int(pos):int(pos+bs)]
140
+ temp[bs : bs + ns] = data_block # fill from right
141
+ while pos + bs <= bs + ns:
142
+ yield temp[int(pos) : int(pos + bs)]
110
143
  pos += posinc
111
144
  else:
112
- temp[0:bs] = temp[bs:] # copy to left
145
+ temp[0:bs] = temp[bs:] # copy to left
113
146
  pos -= bs
114
147
 
115
148
 
116
- class FFTSpectra( BaseSpectra,TimeInOut ):
117
- """Provides the spectra of multichannel time data.
118
-
119
- Returns Spectra per block over a Generator.
149
+ class FFTSpectra(BaseSpectra, TimeInOut):
150
+ """Provides the spectra of multichannel time data.
151
+
152
+ Returns Spectra per block over a Generator.
120
153
  """
121
-
154
+
122
155
  # internal identifier
123
- digest = Property( depends_on = ['source.digest','precision','block_size',
124
- 'window','overlap'])
156
+ digest = Property(depends_on=['source.digest', 'precision', 'block_size', 'window', 'overlap'])
125
157
 
126
158
  @cached_property
127
- def _get_digest( self ):
159
+ def _get_digest(self):
128
160
  return digest(self)
129
161
 
130
- #generator that yields the fft for every channel
162
+ # generator that yields the fft for every channel
131
163
  def result(self):
132
- """
133
- Python generator that yields the output block-wise.
134
-
164
+ """Python generator that yields the output block-wise.
165
+
135
166
  Parameters
136
167
  ----------
137
168
  num : integer
138
169
  This parameter defines the size of the blocks to be yielded
139
170
  (i.e. the number of samples per block).
140
-
171
+
141
172
  Returns
142
173
  -------
143
- Samples in blocks of shape (numfreq, :attr:`numchannels`).
174
+ Samples in blocks of shape (numfreq, :attr:`numchannels`).
144
175
  The last block may be shorter than num.
145
- """
146
- wind = self.window_( self.block_size )
147
- weight=sqrt(2)/self.block_size*sqrt(self.block_size/dot(wind,wind))*wind[:, newaxis]
176
+
177
+ """
178
+ wind = self.window_(self.block_size)
179
+ weight = sqrt(2) / self.block_size * sqrt(self.block_size / dot(wind, wind)) * wind[:, newaxis]
148
180
  for data in self.get_source_data():
149
- ft = fft.rfft(data*weight, None, 0).astype(self.precision)
181
+ ft = fft.rfft(data * weight, None, 0).astype(self.precision)
150
182
  yield ft
151
183
 
152
184
 
153
- class PowerSpectra( BaseSpectra ):
185
+ class PowerSpectra(BaseSpectra):
154
186
  """Provides the cross spectral matrix of multichannel time data
155
187
  and its eigen-decomposition.
156
-
188
+
157
189
  This class includes the efficient calculation of the full cross spectral
158
- matrix using the Welch method with windows and overlap. It also contains
159
- the CSM's eigenvalues and eigenvectors and additional properties.
160
-
190
+ matrix using the Welch method with windows and overlap. It also contains
191
+ the CSM's eigenvalues and eigenvectors and additional properties.
192
+
161
193
  The result is computed only when needed, that is when the :attr:`csm`,
162
194
  :attr:`eva`, or :attr:`eve` attributes are acturally read.
163
- Any change in the input data or parameters leads to a new calculation,
164
- again triggered when an attribute is read. The result may be
195
+ Any change in the input data or parameters leads to a new calculation,
196
+ again triggered when an attribute is read. The result may be
165
197
  cached on disk in HDF5 files and need not to be recomputed during
166
198
  subsequent program runs with identical input data and parameters. The
167
199
  input data is taken to be identical if the source has identical parameters
@@ -171,155 +203,140 @@ class PowerSpectra( BaseSpectra ):
171
203
  # Shadow trait, should not be set directly, for internal use.
172
204
  _source = Trait(SamplesGenerator)
173
205
 
174
- #: Data source; :class:`~acoular.sources.SamplesGenerator` or derived object.
175
- source = Property(_source,
176
- desc="time data object")
206
+ #: Data source; :class:`~acoular.sources.SamplesGenerator` or derived object.
207
+ source = Property(_source, desc='time data object')
177
208
 
178
209
  #: The :class:`~acoular.tprocess.SamplesGenerator` object that provides the data.
179
- time_data = Property(_source,
180
- desc="deprecated attribute holding the time data object. Use PowerSpectra.source instead!")
210
+ time_data = Property(
211
+ _source,
212
+ desc='deprecated attribute holding the time data object. Use PowerSpectra.source instead!',
213
+ )
181
214
 
182
- #: The :class:`~acoular.calib.Calib` object that provides the calibration data,
215
+ #: The :class:`~acoular.calib.Calib` object that provides the calibration data,
183
216
  #: defaults to no calibration, i.e. the raw time data is used.
184
217
  #:
185
- #: **deprecated**: use :attr:`~acoular.sources.TimeSamples.calib` property of
218
+ #: **deprecated**: use :attr:`~acoular.sources.TimeSamples.calib` property of
186
219
  #: :class:`~acoular.sources.TimeSamples` objects
187
220
  calib = Instance(Calib)
188
221
 
189
222
  # Shadow trait, should not be set directly, for internal use.
190
- _ind_low = Int(1,
191
- desc="index of lowest frequency line")
223
+ _ind_low = Int(1, desc='index of lowest frequency line')
192
224
 
193
225
  # Shadow trait, should not be set directly, for internal use.
194
- _ind_high = Trait(-1,(Int,None),
195
- desc="index of highest frequency line")
226
+ _ind_high = Trait(-1, (Int, None), desc='index of highest frequency line')
196
227
 
197
228
  #: Index of lowest frequency line to compute, integer, defaults to 1,
198
229
  #: is used only by objects that fetch the csm, PowerSpectra computes every
199
230
  #: frequency line.
200
- ind_low = Property(_ind_low,
201
- desc="index of lowest frequency line")
231
+ ind_low = Property(_ind_low, desc='index of lowest frequency line')
202
232
 
203
- #: Index of highest frequency line to compute, integer,
233
+ #: Index of highest frequency line to compute, integer,
204
234
  #: defaults to -1 (last possible line for default block_size).
205
- ind_high = Property(_ind_high,
206
- desc="index of lowest frequency line")
235
+ ind_high = Property(_ind_high, desc='index of lowest frequency line')
207
236
 
208
237
  # Stores the set lower frequency, for internal use, should not be set directly.
209
238
  _freqlc = Float(0)
210
239
 
211
240
  # Stores the set higher frequency, for internal use, should not be set directly.
212
- _freqhc = Trait(0,(Float,None))
241
+ _freqhc = Trait(0, (Float, None))
213
242
 
214
243
  # Saves whether the user set indices or frequencies last, for internal use only,
215
244
  # not to be set directly, if True (default), indices are used for setting
216
245
  # the freq_range interval.
217
246
  _index_set_last = Bool(True)
218
-
247
+
219
248
  #: Flag, if true (default), the result is cached in h5 files and need not
220
249
  #: to be recomputed during subsequent program runs.
221
- cached = Bool(True,
222
- desc="cached flag")
250
+ cached = Bool(True, desc='cached flag')
223
251
 
224
252
  #: Number of FFT blocks to average, readonly
225
253
  #: (set from block_size and overlap).
226
- num_blocks = Property(
227
- desc="overall number of FFT blocks")
254
+ num_blocks = Property(desc='overall number of FFT blocks')
228
255
 
229
- #: 2-element array with the lowest and highest frequency. If set,
256
+ #: 2-element array with the lowest and highest frequency. If set,
230
257
  #: will overwrite :attr:`_freqlc` and :attr:`_freqhc` according to
231
- #: the range.
258
+ #: the range.
232
259
  #: The freq_range interval will be the smallest discrete frequency
233
260
  #: inside the half-open interval [_freqlc, _freqhc[ and the smallest
234
261
  #: upper frequency outside of the interval.
235
262
  #: If user chooses the higher frequency larger than the max frequency,
236
263
  #: the max frequency will be the upper bound.
237
- freq_range = Property(
238
- desc = "frequency range" )
239
-
240
- #: Array with a sequence of indices for all frequencies
264
+ freq_range = Property(desc='frequency range')
265
+
266
+ #: Array with a sequence of indices for all frequencies
241
267
  #: between :attr:`ind_low` and :attr:`ind_high` within the result, readonly.
242
- indices = Property(
243
- desc = "index range" )
244
-
268
+ indices = Property(desc='index range')
269
+
245
270
  #: Name of the cache file without extension, readonly.
246
- basename = Property( depends_on = '_source.digest',
247
- desc="basename for cache file")
271
+ basename = Property(depends_on='_source.digest', desc='basename for cache file')
248
272
 
249
- #: The cross spectral matrix,
273
+ #: The cross spectral matrix,
250
274
  #: (number of frequencies, numchannels, numchannels) array of complex;
251
275
  #: readonly.
252
- csm = Property(
253
- desc="cross spectral matrix")
254
-
276
+ csm = Property(desc='cross spectral matrix')
277
+
255
278
  #: Eigenvalues of the cross spectral matrix as an
256
279
  #: (number of frequencies) array of floats, readonly.
257
- eva = Property(
258
- desc="eigenvalues of cross spectral matrix")
280
+ eva = Property(desc='eigenvalues of cross spectral matrix')
259
281
 
260
282
  #: Eigenvectors of the cross spectral matrix as an
261
283
  #: (number of frequencies, numchannels, numchannels) array of floats,
262
284
  #: readonly.
263
- eve = Property(
264
- desc="eigenvectors of cross spectral matrix")
285
+ eve = Property(desc='eigenvectors of cross spectral matrix')
265
286
 
266
287
  # internal identifier
267
- digest = Property(
268
- depends_on = ['_source.digest', 'calib.digest', 'block_size',
269
- 'window', 'overlap', 'precision'],
270
- )
288
+ digest = Property(
289
+ depends_on=['_source.digest', 'calib.digest', 'block_size', 'window', 'overlap', 'precision'],
290
+ )
271
291
 
272
292
  # hdf5 cache file
273
- h5f = Instance( H5CacheFileBase, transient = True )
274
-
293
+ h5f = Instance(H5CacheFileBase, transient=True)
294
+
275
295
  @property_depends_on('_source.numsamples, block_size, overlap')
276
- def _get_num_blocks ( self ):
277
- return self.overlap_*self._source.numsamples/self.block_size-\
278
- self.overlap_+1
296
+ def _get_num_blocks(self):
297
+ return self.overlap_ * self._source.numsamples / self.block_size - self.overlap_ + 1
279
298
 
280
299
  @property_depends_on('_source.sample_freq, block_size, ind_low, ind_high')
281
- def _get_freq_range ( self ):
300
+ def _get_freq_range(self):
282
301
  fftfreq = self.fftfreq()
283
302
  if fftfreq is not None:
284
303
  if self._ind_high is None:
285
- return array([fftfreq[self.ind_low],None])
286
- else:
287
- return fftfreq[[ self.ind_low, self.ind_high ]]
304
+ return array([fftfreq[self.ind_low], None])
305
+ return fftfreq[[self.ind_low, self.ind_high]]
306
+ return None
288
307
 
289
- def _set_freq_range( self, freq_range ):# by setting this the user sets _freqlc and _freqhc
308
+ def _set_freq_range(self, freq_range): # by setting this the user sets _freqlc and _freqhc
290
309
  self._index_set_last = False
291
310
  self._freqlc = freq_range[0]
292
311
  self._freqhc = freq_range[1]
293
312
 
294
- @property_depends_on( '_source.sample_freq, block_size, _ind_low, _freqlc' )
295
- def _get_ind_low( self ):
313
+ @property_depends_on('_source.sample_freq, block_size, _ind_low, _freqlc')
314
+ def _get_ind_low(self):
296
315
  fftfreq = self.fftfreq()
297
316
  if fftfreq is not None:
298
317
  if self._index_set_last:
299
- return min(self._ind_low, fftfreq.shape[0]-1)
300
- else:
301
- return searchsorted(fftfreq[:-1], self._freqlc)
318
+ return min(self._ind_low, fftfreq.shape[0] - 1)
319
+ return searchsorted(fftfreq[:-1], self._freqlc)
320
+ return None
302
321
 
303
- @property_depends_on( '_source.sample_freq, block_size, _ind_high, _freqhc' )
304
- def _get_ind_high( self ):
322
+ @property_depends_on('_source.sample_freq, block_size, _ind_high, _freqhc')
323
+ def _get_ind_high(self):
305
324
  fftfreq = self.fftfreq()
306
325
  if fftfreq is not None:
307
326
  if self._index_set_last:
308
- if self._ind_high is None:
309
- return None
310
- else:
311
- return min(self._ind_high, fftfreq.shape[0]-1)
312
- else:
313
- if self._freqhc is None:
327
+ if self._ind_high is None:
314
328
  return None
315
- else:
316
- return searchsorted(fftfreq[:-1], self._freqhc)
329
+ return min(self._ind_high, fftfreq.shape[0] - 1)
330
+ if self._freqhc is None:
331
+ return None
332
+ return searchsorted(fftfreq[:-1], self._freqhc)
333
+ return None
317
334
 
318
- def _set_ind_high(self, ind_high):# by setting this the user sets the lower index
335
+ def _set_ind_high(self, ind_high): # by setting this the user sets the lower index
319
336
  self._index_set_last = True
320
337
  self._ind_high = ind_high
321
338
 
322
- def _set_ind_low( self, ind_low):# by setting this the user sets the higher index
339
+ def _set_ind_low(self, ind_low): # by setting this the user sets the higher index
323
340
  self._index_set_last = True
324
341
  self._ind_low = ind_low
325
342
 
@@ -335,194 +352,178 @@ class PowerSpectra( BaseSpectra ):
335
352
  def _get_source(self):
336
353
  return self._source
337
354
 
338
- @property_depends_on( 'block_size, ind_low, ind_high' )
339
- def _get_indices ( self ):
355
+ @property_depends_on('block_size, ind_low, ind_high')
356
+ def _get_indices(self):
340
357
  fftfreq = self.fftfreq()
341
358
  if fftfreq is not None:
342
359
  try:
343
- indices = arange(fftfreq.shape[0],dtype=int)
360
+ indices = arange(fftfreq.shape[0], dtype=int)
344
361
  if self.ind_high is None:
345
- return indices[ self.ind_low:]
346
- else:
347
- return indices[ self.ind_low: self.ind_high ]
362
+ return indices[self.ind_low :]
363
+ return indices[self.ind_low : self.ind_high]
348
364
  except IndexError:
349
365
  return range(0)
366
+ return None
350
367
 
351
368
  @cached_property
352
- def _get_digest( self ):
353
- return digest( self )
369
+ def _get_digest(self):
370
+ return digest(self)
354
371
 
355
372
  @cached_property
356
- def _get_basename( self ):
373
+ def _get_basename(self):
357
374
  if 'basename' in self._source.all_trait_names():
358
375
  return self._source.basename
359
- else:
360
- return self._source.__class__.__name__ + self._source.digest
376
+ return self._source.__class__.__name__ + self._source.digest
361
377
 
362
- def calc_csm( self ):
363
- """ csm calculation """
378
+ def calc_csm(self):
379
+ """Csm calculation."""
364
380
  t = self.source
365
- wind = self.window_( self.block_size )
366
- weight = dot( wind, wind )
367
- wind = wind[newaxis, :].swapaxes( 0, 1 )
368
- numfreq = int(self.block_size/2 + 1)
381
+ wind = self.window_(self.block_size)
382
+ weight = dot(wind, wind)
383
+ wind = wind[newaxis, :].swapaxes(0, 1)
384
+ numfreq = int(self.block_size / 2 + 1)
369
385
  csm_shape = (numfreq, t.numchannels, t.numchannels)
370
386
  csmUpper = zeros(csm_shape, dtype=self.precision)
371
- #print "num blocks", self.num_blocks
387
+ # print "num blocks", self.num_blocks
372
388
  # for backward compatibility
373
389
  if self.calib and self.calib.num_mics > 0:
374
390
  if self.calib.num_mics == t.numchannels:
375
391
  wind = wind * self.calib.data[newaxis, :]
376
392
  else:
377
- raise ValueError(
378
- "Calibration data not compatible: %i, %i" % \
379
- (self.calib.num_mics, t.numchannels))
393
+ raise ValueError('Calibration data not compatible: %i, %i' % (self.calib.num_mics, t.numchannels))
380
394
  # get time data blockwise
381
395
  for data in self.get_source_data():
382
- ft = fft.rfft(data*wind, None, 0).astype(self.precision)
396
+ ft = fft.rfft(data * wind, None, 0).astype(self.precision)
383
397
  calcCSM(csmUpper, ft) # only upper triangular part of matrix is calculated (for speed reasons)
384
398
  # create the full csm matrix via transposing and complex conj.
385
- csmLower = csmUpper.conj().transpose(0,2,1)
399
+ csmLower = csmUpper.conj().transpose(0, 2, 1)
386
400
  [fill_diagonal(csmLower[cntFreq, :, :], 0) for cntFreq in range(csmLower.shape[0])]
387
401
  csm = csmLower + csmUpper
388
402
  # onesided spectrum: multiplication by 2.0=sqrt(2)^2
389
- csm = csm*(2.0/self.block_size/weight/self.num_blocks)
390
- return csm
391
-
392
- def calc_ev ( self ):
393
- """ eigenvalues / eigenvectors calculation """
394
- if self.precision == 'complex128': eva_dtype = 'float64'
395
- elif self.precision == 'complex64': eva_dtype = 'float32'
396
- # csm = self.csm #trigger calculation
403
+ return csm * (2.0 / self.block_size / weight / self.num_blocks)
404
+
405
+ def calc_ev(self):
406
+ """Eigenvalues / eigenvectors calculation."""
407
+ if self.precision == 'complex128':
408
+ eva_dtype = 'float64'
409
+ elif self.precision == 'complex64':
410
+ eva_dtype = 'float32'
411
+ # csm = self.csm #trigger calculation
397
412
  csm_shape = self.csm.shape
398
413
  eva = empty(csm_shape[0:2], dtype=eva_dtype)
399
414
  eve = empty(csm_shape, dtype=self.precision)
400
415
  for i in range(csm_shape[0]):
401
- (eva[i], eve[i])=linalg.eigh(self.csm[i])
402
- return (eva,eve)
416
+ (eva[i], eve[i]) = linalg.eigh(self.csm[i])
417
+ return (eva, eve)
403
418
 
404
- def calc_eva( self ):
405
- """ calculates eigenvalues of csm """
419
+ def calc_eva(self):
420
+ """Calculates eigenvalues of csm."""
406
421
  return self.calc_ev()[0]
407
-
408
- def calc_eve( self ):
409
- """ calculates eigenvectors of csm """
422
+
423
+ def calc_eve(self):
424
+ """Calculates eigenvectors of csm."""
410
425
  return self.calc_ev()[1]
411
-
426
+
412
427
  def _handle_dual_calibration(self):
413
- obj = self.source # start with time_data obj
428
+ obj = self.source # start with time_data obj
414
429
  while obj:
415
- if 'calib' in obj.all_trait_names(): # at original source?
430
+ if 'calib' in obj.all_trait_names(): # at original source?
416
431
  if obj.calib and self.calib:
417
432
  if obj.calib.digest == self.calib.digest:
418
- self.calib = None # ignore it silently
433
+ self.calib = None # ignore it silently
419
434
  else:
420
- raise ValueError("Non-identical dual calibration for "\
421
- "both TimeSamples and PowerSpectra object")
435
+ msg = 'Non-identical dual calibration for both TimeSamples and PowerSpectra object'
436
+ raise ValueError(msg)
422
437
  obj = None
423
438
  else:
424
439
  try:
425
- obj = obj.source # traverse down until original data source
440
+ obj = obj.source # traverse down until original data source
426
441
  except AttributeError:
427
442
  obj = None
428
443
 
429
- def _get_filecache( self, traitname ):
430
- """
431
- function handles result caching of csm, eigenvectors and eigenvalues
432
- calculation depending on global/local caching behaviour.
444
+ def _get_filecache(self, traitname):
445
+ """Function handles result caching of csm, eigenvectors and eigenvalues
446
+ calculation depending on global/local caching behaviour.
433
447
  """
434
448
  if traitname == 'csm':
435
449
  func = self.calc_csm
436
- numfreq = int(self.block_size/2 + 1)
450
+ numfreq = int(self.block_size / 2 + 1)
437
451
  shape = (numfreq, self._source.numchannels, self._source.numchannels)
438
452
  precision = self.precision
439
453
  elif traitname == 'eva':
440
454
  func = self.calc_eva
441
455
  shape = self.csm.shape[0:2]
442
- if self.precision == 'complex128': precision = 'float64'
443
- elif self.precision == 'complex64': precision = 'float32'
456
+ if self.precision == 'complex128':
457
+ precision = 'float64'
458
+ elif self.precision == 'complex64':
459
+ precision = 'float32'
444
460
  elif traitname == 'eve':
445
461
  func = self.calc_eve
446
462
  shape = self.csm.shape
447
463
  precision = self.precision
448
464
 
449
- H5cache.get_cache_file( self, self.basename )
450
- if not self.h5f: # in case of global caching readonly
451
- return func()
465
+ H5cache.get_cache_file(self, self.basename)
466
+ if not self.h5f: # in case of global caching readonly
467
+ return func()
452
468
 
453
- nodename = traitname + '_' + self.digest
469
+ nodename = traitname + '_' + self.digest
454
470
  if config.global_caching == 'overwrite' and self.h5f.is_cached(nodename):
455
- #print("remove existing node",nodename)
456
- self.h5f.remove_data(nodename) # remove old data before writing in overwrite mode
457
-
458
- if not self.h5f.is_cached(nodename):
459
- if config.global_caching == 'readonly':
471
+ # print("remove existing node",nodename)
472
+ self.h5f.remove_data(nodename) # remove old data before writing in overwrite mode
473
+
474
+ if not self.h5f.is_cached(nodename):
475
+ if config.global_caching == 'readonly':
460
476
  return func()
461
- # print("create array, data not cached for",nodename)
462
- self.h5f.create_compressible_array(nodename,shape,precision)
463
-
477
+ # print("create array, data not cached for",nodename)
478
+ self.h5f.create_compressible_array(nodename, shape, precision)
479
+
464
480
  ac = self.h5f.get_data_by_reference(nodename)
465
- if ac[:].sum() == 0: # only initialized
466
- # print("write {} to:".format(traitname),nodename)
481
+ if ac[:].sum() == 0: # only initialized
482
+ # print("write {} to:".format(traitname),nodename)
467
483
  ac[:] = func()
468
484
  self.h5f.flush()
469
485
  return ac
470
-
486
+
471
487
  @property_depends_on('digest')
472
- def _get_csm ( self ):
473
- """
474
- Main work is done here:
488
+ def _get_csm(self):
489
+ """Main work is done here:
475
490
  Cross spectral matrix is either loaded from cache file or
476
491
  calculated and then additionally stored into cache.
477
492
  """
478
493
  self._handle_dual_calibration()
479
- if (
480
- config.global_caching == 'none' or
481
- (config.global_caching == 'individual' and self.cached is False)
482
- ):
494
+ if config.global_caching == 'none' or (config.global_caching == 'individual' and self.cached is False):
483
495
  return self.calc_csm()
484
- else:
485
- return self._get_filecache('csm')
486
-
496
+ return self._get_filecache('csm')
497
+
487
498
  @property_depends_on('digest')
488
- def _get_eva ( self ):
489
- """
490
- Eigenvalues of cross spectral matrix are either loaded from cache file or
499
+ def _get_eva(self):
500
+ """Eigenvalues of cross spectral matrix are either loaded from cache file or
491
501
  calculated and then additionally stored into cache.
492
502
  """
493
- if (
494
- config.global_caching == 'none' or
495
- (config.global_caching == 'individual' and self.cached is False)
496
- ):
503
+ if config.global_caching == 'none' or (config.global_caching == 'individual' and self.cached is False):
497
504
  return self.calc_eva()
498
- else:
499
- return self._get_filecache('eva')
505
+ return self._get_filecache('eva')
500
506
 
501
507
  @property_depends_on('digest')
502
- def _get_eve ( self ):
503
- """
504
- Eigenvectors of cross spectral matrix are either loaded from cache file or
508
+ def _get_eve(self):
509
+ """Eigenvectors of cross spectral matrix are either loaded from cache file or
505
510
  calculated and then additionally stored into cache.
506
511
  """
507
- if (
508
- config.global_caching == 'none' or
509
- (config.global_caching == 'individual' and self.cached is False)
510
- ):
512
+ if config.global_caching == 'none' or (config.global_caching == 'individual' and self.cached is False):
511
513
  return self.calc_eve()
512
- else:
513
- return self._get_filecache('eve')
514
+ return self._get_filecache('eve')
514
515
 
515
- def synthetic_ev( self, freq, num=0):
516
+ def synthetic_ev(self, freq, num=0):
516
517
  """Return synthesized frequency band values of the eigenvalues.
517
-
518
+
518
519
  Parameters
519
520
  ----------
520
- freq : float
521
+ freq : float
521
522
  Band center frequency for which to return the results.
522
523
  num : integer
523
524
  Controls the width of the frequency bands considered; defaults to
524
525
  3 (third-octave band).
525
-
526
+
526
527
  === =====================
527
528
  num frequency band width
528
529
  === =====================
@@ -534,39 +535,36 @@ class PowerSpectra( BaseSpectra ):
534
535
 
535
536
  Returns
536
537
  -------
537
- float
538
+ float
538
539
  Synthesized frequency band value of the eigenvalues (the sum of
539
540
  all values that are contained in the band).
541
+
540
542
  """
541
543
  f = self.fftfreq()
542
544
  if num == 0:
543
545
  # single frequency line
544
546
  return self.eva[searchsorted(f, freq)]
545
- else:
546
- f1 = searchsorted(f, freq*2.**(-0.5/num))
547
- f2 = searchsorted(f, freq*2.**(0.5/num))
548
- if f1 == f2:
549
- return self.eva[f1]
550
- else:
551
- return sum(self.eva[f1:f2], 0)
547
+ f1 = searchsorted(f, freq * 2.0 ** (-0.5 / num))
548
+ f2 = searchsorted(f, freq * 2.0 ** (0.5 / num))
549
+ if f1 == f2:
550
+ return self.eva[f1]
551
+ return sum(self.eva[f1:f2], 0)
552
552
 
553
553
 
554
+ def synthetic(data, freqs, f, num=3):
555
+ """Returns synthesized frequency band values of spectral data.
554
556
 
555
- def synthetic (data, freqs, f, num=3):
556
- """
557
- Returns synthesized frequency band values of spectral data.
558
-
559
- If used with :meth:`Beamformer.result()<acoular.fbeamform.BeamformerBase.result>`
560
- and only one frequency band, the output is identical to the result of the intrinsic
557
+ If used with :meth:`Beamformer.result()<acoular.fbeamform.BeamformerBase.result>`
558
+ and only one frequency band, the output is identical to the result of the intrinsic
561
559
  :meth:`Beamformer.synthetic<acoular.fbeamform.BeamformerBase.synthetic>` method.
562
- It can, however, also be used with the
560
+ It can, however, also be used with the
563
561
  :meth:`Beamformer.integrate<acoular.fbeamform.BeamformerBase.integrate>`
564
562
  output and more frequency bands.
565
-
563
+
566
564
  Parameters
567
565
  ----------
568
566
  data : array of floats
569
- The spectral data (squared sound pressures in Pa^2) in an array with one value
567
+ The spectral data (squared sound pressures in Pa^2) in an array with one value
570
568
  per frequency line.
571
569
  The number of entries must be identical to the number of
572
570
  grid points.
@@ -579,7 +577,7 @@ def synthetic (data, freqs, f, num=3):
579
577
  num : integer
580
578
  Controls the width of the frequency bands considered; defaults to
581
579
  3 (third-octave band).
582
-
580
+
583
581
  === =====================
584
582
  num frequency band width
585
583
  === =====================
@@ -592,46 +590,55 @@ def synthetic (data, freqs, f, num=3):
592
590
  Returns
593
591
  -------
594
592
  array of floats
595
- Synthesized frequency band values of the beamforming result at
593
+ Synthesized frequency band values of the beamforming result at
596
594
  each grid point (the sum of all values that are contained in the band).
597
- Note that the frequency resolution and therefore the bandwidth
598
- represented by a single frequency line depends on
599
- the :attr:`sampling frequency<acoular.tprocess.SamplesGenerator.sample_freq>`
595
+ Note that the frequency resolution and therefore the bandwidth
596
+ represented by a single frequency line depends on
597
+ the :attr:`sampling frequency<acoular.tprocess.SamplesGenerator.sample_freq>`
600
598
  and used :attr:`FFT block size<acoular.spectra.PowerSpectra.block_size>`.
599
+
601
600
  """
602
601
  if isscalar(f):
603
602
  f = (f,)
604
603
  if num == 0:
605
604
  # single frequency lines
606
- res = list()
605
+ res = []
607
606
  for i in f:
608
607
  ind = searchsorted(freqs, i)
609
608
  if ind >= len(freqs):
610
- warn('Queried frequency (%g Hz) not in resolved '
611
- 'frequency range. Returning zeros.' % i,
612
- Warning, stacklevel = 2)
609
+ warn(
610
+ 'Queried frequency (%g Hz) not in resolved frequency range. Returning zeros.' % i,
611
+ Warning,
612
+ stacklevel=2,
613
+ )
613
614
  h = zeros_like(data[0])
614
615
  else:
615
616
  if freqs[ind] != i:
616
- warn('Queried frequency (%g Hz) not in set of '
617
- 'discrete FFT sample frequencies. '
618
- 'Using frequency %g Hz instead.' % (i,freqs[ind]),
619
- Warning, stacklevel = 2)
617
+ warn(
618
+ f'Queried frequency ({i:g} Hz) not in set of '
619
+ 'discrete FFT sample frequencies. '
620
+ f'Using frequency {freqs[ind]:g} Hz instead.',
621
+ Warning,
622
+ stacklevel=2,
623
+ )
620
624
  h = data[ind]
621
- res += [h]
625
+ res += [h]
622
626
  else:
623
627
  # fractional octave bands
624
- res = list()
628
+ res = []
625
629
  for i in f:
626
- f1 = i*2.**(-0.5/num)
627
- f2 = i*2.**(+0.5/num)
630
+ f1 = i * 2.0 ** (-0.5 / num)
631
+ f2 = i * 2.0 ** (+0.5 / num)
628
632
  ind1 = searchsorted(freqs, f1)
629
633
  ind2 = searchsorted(freqs, f2)
630
634
  if ind1 == ind2:
631
- warn('Queried frequency band (%g to %g Hz) does not '
632
- 'include any discrete FFT sample frequencies. '
633
- 'Returning zeros.' % (f1,f2),
634
- Warning, stacklevel = 2)
635
+ warn(
636
+ f'Queried frequency band ({f1:g} to {f2:g} Hz) does not '
637
+ 'include any discrete FFT sample frequencies. '
638
+ 'Returning zeros.',
639
+ Warning,
640
+ stacklevel=2,
641
+ )
635
642
  h = zeros_like(data[0])
636
643
  else:
637
644
  h = sum(data[ind1:ind2], 0)
@@ -639,140 +646,123 @@ def synthetic (data, freqs, f, num=3):
639
646
  return array(res)
640
647
 
641
648
 
642
- class PowerSpectraImport( PowerSpectra ):
649
+ class PowerSpectraImport(PowerSpectra):
643
650
  """Provides a dummy class for using pre-calculated cross-spectral
644
- matrices.
651
+ matrices.
645
652
 
646
- This class does not calculate the cross-spectral matrix. Instead,
647
- the user can inject one or multiple existing CSMs by setting the
653
+ This class does not calculate the cross-spectral matrix. Instead,
654
+ the user can inject one or multiple existing CSMs by setting the
648
655
  :attr:`csm` attribute. This can be useful when algorithms shall be
649
656
  evaluated with existing CSM matrices.
650
- The frequency or frequencies contained by the CSM must be set via the
657
+ The frequency or frequencies contained by the CSM must be set via the
651
658
  attr:`frequencies` attribute. The attr:`numchannels` attributes
652
- is determined on the basis of the CSM shape.
653
- In contrast to the PowerSpectra object, the attributes
659
+ is determined on the basis of the CSM shape.
660
+ In contrast to the PowerSpectra object, the attributes
654
661
  :attr:`sample_freq`, :attr:`time_data`, :attr:`source`,
655
- :attr:`block_size`, :attr:`calib`, :attr:`window`,
662
+ :attr:`block_size`, :attr:`calib`, :attr:`window`,
656
663
  :attr:`overlap`, :attr:`cached`, and :attr:`num_blocks`
657
- have no functionality.
664
+ have no functionality.
658
665
  """
659
666
 
660
- #: The cross spectral matrix,
667
+ #: The cross spectral matrix,
661
668
  #: (number of frequencies, numchannels, numchannels) array of complex;
662
- csm = Property(
663
- desc="cross spectral matrix")
669
+ csm = Property(desc='cross spectral matrix')
664
670
 
665
671
  #: frequencies included in the cross-spectral matrix in ascending order.
666
672
  #: Compound trait that accepts arguments of type list, array, and float
667
- frequencies = Trait(None,(CArray,Float),
668
- desc="frequencies included in the cross-spectral matrix")
673
+ frequencies = Trait(None, (CArray, Float), desc='frequencies included in the cross-spectral matrix')
669
674
 
670
- #: Number of time data channels
675
+ #: Number of time data channels
671
676
  numchannels = Property(depends_on=['digest'])
672
677
 
673
- time_data = Enum(None,
674
- desc="PowerSpectraImport cannot consume time data")
678
+ time_data = Enum(None, desc='PowerSpectraImport cannot consume time data')
675
679
 
676
- source = Enum(None,
677
- desc="PowerSpectraImport cannot consume time data")
680
+ source = Enum(None, desc='PowerSpectraImport cannot consume time data')
678
681
 
679
682
  # Sampling frequency of the signal, defaults to None
680
- sample_freq = Enum(None,
681
- desc="sampling frequency")
683
+ sample_freq = Enum(None, desc='sampling frequency')
682
684
 
683
- block_size = Enum(None,
684
- desc="PowerSpectraImport does not operate on blocks of time data")
685
+ block_size = Enum(None, desc='PowerSpectraImport does not operate on blocks of time data')
685
686
 
686
- calib = Enum(None,
687
- desc="PowerSpectraImport cannot calibrate the time data")
687
+ calib = Enum(None, desc='PowerSpectraImport cannot calibrate the time data')
688
688
 
689
- window = Enum(None,
690
- desc="PowerSpectraImport does not perform windowing")
689
+ window = Enum(None, desc='PowerSpectraImport does not perform windowing')
691
690
 
692
- overlap = Enum(None,
693
- desc="PowerSpectraImport does not consume time data")
691
+ overlap = Enum(None, desc='PowerSpectraImport does not consume time data')
694
692
 
695
- cached = Enum(False,
696
- desc="PowerSpectraImport has no caching capabilities")
693
+ cached = Enum(False, desc='PowerSpectraImport has no caching capabilities')
697
694
 
698
- num_blocks = Enum(None,
699
- desc="PowerSpectraImport cannot determine the number of blocks")
695
+ num_blocks = Enum(None, desc='PowerSpectraImport cannot determine the number of blocks')
700
696
 
701
697
  # Shadow trait, should not be set directly, for internal use.
702
- _ind_low = Int(0,
703
- desc="index of lowest frequency line")
698
+ _ind_low = Int(0, desc='index of lowest frequency line')
704
699
 
705
700
  # Shadow trait, should not be set directly, for internal use.
706
- _ind_high = Trait(None,(Int,None),
707
- desc="index of highest frequency line")
701
+ _ind_high = Trait(None, (Int, None), desc='index of highest frequency line')
708
702
 
709
703
  # internal identifier
710
- digest = Property(
711
- depends_on = ['_csmsum',
712
- ],
713
- )
704
+ digest = Property(
705
+ depends_on=[
706
+ '_csmsum',
707
+ ],
708
+ )
714
709
 
715
710
  #: Name of the cache file without extension, readonly.
716
- basename = Property( depends_on = 'digest',
717
- desc="basename for cache file")
711
+ basename = Property(depends_on='digest', desc='basename for cache file')
718
712
 
719
713
  # csm shadow trait, only for internal use.
720
714
  _csm = CArray()
721
-
715
+
722
716
  # CSM checksum to trigger digest calculation, only for internal use.
723
- _csmsum = Float()
717
+ _csmsum = Float()
724
718
 
725
- def _get_basename( self ):
726
- return "csm_import_"+self.digest
719
+ def _get_basename(self):
720
+ return 'csm_import_' + self.digest
727
721
 
728
722
  @cached_property
729
- def _get_digest( self ):
730
- return digest( self )
723
+ def _get_digest(self):
724
+ return digest(self)
731
725
 
732
- def _get_numchannels( self ):
726
+ def _get_numchannels(self):
733
727
  return self.csm.shape[1]
734
728
 
735
- def _get_csm ( self ):
729
+ def _get_csm(self):
736
730
  return self._csm
737
731
 
738
- def _set_csm (self, csm):
732
+ def _set_csm(self, csm):
739
733
  if (len(csm.shape) != 3) or (csm.shape[1] != csm.shape[2]):
740
- raise ValueError(
741
- "The cross spectral matrix must have the following shape: (number of frequencies, numchannels, numchannels)!")
742
- self._csmsum = real(self._csm).sum() + (imag(self._csm)**2).sum() # to trigger new digest creation
734
+ msg = 'The cross spectral matrix must have the following shape: (number of frequencies, numchannels, numchannels)!'
735
+ raise ValueError(msg)
736
+ self._csmsum = real(self._csm).sum() + (imag(self._csm) ** 2).sum() # to trigger new digest creation
743
737
  self._csm = csm
744
738
 
745
739
  @property_depends_on('digest')
746
- def _get_eva ( self ):
747
- """
748
- Eigenvalues of cross spectral matrix are either loaded from cache file or
740
+ def _get_eva(self):
741
+ """Eigenvalues of cross spectral matrix are either loaded from cache file or
749
742
  calculated and then additionally stored into cache.
750
743
  """
751
744
  return self.calc_eva()
752
745
 
753
746
  @property_depends_on('digest')
754
- def _get_eve ( self ):
755
- """
756
- Eigenvectors of cross spectral matrix are either loaded from cache file or
747
+ def _get_eve(self):
748
+ """Eigenvectors of cross spectral matrix are either loaded from cache file or
757
749
  calculated and then additionally stored into cache.
758
750
  """
759
751
  return self.calc_eve()
760
752
 
761
- def fftfreq ( self ):
762
- """
763
- Return the Discrete Fourier Transform sample frequencies.
764
-
753
+ def fftfreq(self):
754
+ """Return the Discrete Fourier Transform sample frequencies.
755
+
765
756
  Returns
766
757
  -------
767
758
  f : ndarray
768
759
  Array containing the frequencies.
760
+
769
761
  """
770
- if isinstance(self.frequencies,float):
762
+ if isinstance(self.frequencies, float):
771
763
  return array([self.frequencies])
772
- elif isinstance(self.frequencies,ndarray):
773
- return self.frequencies
774
- elif self.frequencies is None:
775
- warn("No frequencies defined for PowerSpectraImport object!")
764
+ if isinstance(self.frequencies, ndarray):
776
765
  return self.frequencies
777
- else:
778
- return self.frequencies
766
+ if self.frequencies is None:
767
+ warn('No frequencies defined for PowerSpectraImport object!', stacklevel=1)
768
+ return self.frequencies