PyQa40x-i2c 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/PKG-INFO +1 -1
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/RELEASE_NOTES.md +8 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/_version.py +3 -3
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/analyzer.py +128 -4
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/control.py +1 -1
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/stream.py +24 -3
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/wave.py +1 -1
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/PKG-INFO +1 -1
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/scm_file_list.json +32 -32
- pyqa40x_i2c-0.2.2/src/PyQa40x_i2c.egg-info/scm_version.json +8 -0
- pyqa40x_i2c-0.2.0/src/PyQa40x_i2c.egg-info/scm_version.json +0 -8
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/.github/workflows/code_checker.yml +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/.github/workflows/publish_package.yml +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/.github/workflows/unit_tests.yml +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/.gitignore +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/.pylint_ignore +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LICENSE +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/FirstPrinciples.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_acoustic_chirp_spl_bt.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_acoustic_dbspl.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_acoustic_energy_decay_bt.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_coherent_averaging.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_cross_correlation.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_freq_response_with_mask.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_pinknoise.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/PyQa40x_thdn.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/mask_freq.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/LibTest/mask_phase.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/MANIFEST.in +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/README.md +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/_ci/is_dev_version.sh +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/pyproject.toml +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/requirements-dev.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/requirements-test.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/requirements.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/setup.cfg +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/__init__.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/analyzer_params.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/bluetooth.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/cross_correlation.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/fft_processor.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/freq_series_plotter.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/helpers.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/math_chirp.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/math_energy.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/math_general.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/math_sines.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/math_windows.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/registers.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/series_plotter.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/sig_proc.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/wave_chirp.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x/wave_sine.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x.egg-info/PKG-INFO +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x.egg-info/SOURCES.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x.egg-info/dependency_links.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x.egg-info/requires.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x.egg-info/top_level.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/SOURCES.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/dependency_links.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/requires.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/src/PyQa40x_i2c.egg-info/top_level.txt +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/tests/__init__.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/tests/test_template.py +0 -0
- {pyqa40x_i2c-0.2.0 → pyqa40x_i2c-0.2.2}/tox.ini +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 2)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gf75dc49b9'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
import logging
|
|
3
|
+
import struct
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
import usb1 # pip install libusb1
|
|
@@ -11,13 +12,20 @@ from PyQa40x.stream import Stream
|
|
|
11
12
|
from PyQa40x.helpers import *
|
|
12
13
|
from PyQa40x.analyzer_params import AnalyzerParams
|
|
13
14
|
from PyQa40x.bluetooth import BluetoothAudioDevice
|
|
15
|
+
from PyQa40x.wave_sine import Wave
|
|
14
16
|
|
|
15
17
|
logger = logging.getLogger(__name__)
|
|
16
18
|
|
|
19
|
+
# Sample rate Hz vs bytes per USB transfer
|
|
20
|
+
TRANSFER_BYTES_MAP = {
|
|
21
|
+
44100: Stream.DEFAULT_TRANSFER_BYTES,
|
|
22
|
+
48000: Stream.DEFAULT_TRANSFER_BYTES,
|
|
23
|
+
96000: 32768,
|
|
24
|
+
192000: 65536,
|
|
25
|
+
}
|
|
17
26
|
|
|
18
|
-
class Analyzer:
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
class Analyzer:
|
|
21
29
|
|
|
22
30
|
def __init__(self):
|
|
23
31
|
"""
|
|
@@ -25,6 +33,7 @@ class Analyzer:
|
|
|
25
33
|
"""
|
|
26
34
|
self.params: AnalyzerParams | None = None
|
|
27
35
|
self.context: usb1.USBContext | None = None
|
|
36
|
+
self.chunk_size: int | None = None
|
|
28
37
|
self.device: usb1.USBDeviceHandle | None = None
|
|
29
38
|
self.registers: Registers | None = None
|
|
30
39
|
self.control: Control | None = None
|
|
@@ -78,6 +87,7 @@ class Analyzer:
|
|
|
78
87
|
)
|
|
79
88
|
self.context = usb1.USBContext()
|
|
80
89
|
self.context.open()
|
|
90
|
+
self.chunk_size = TRANSFER_BYTES_MAP.get(sample_rate, Stream.DEFAULT_TRANSFER_BYTES)
|
|
81
91
|
|
|
82
92
|
# Attempt to open QA402 or QA403 device
|
|
83
93
|
self.device = self.context.openByVendorIDAndProductID(0x16C0, 0x4E37) # QA402
|
|
@@ -92,7 +102,7 @@ class Analyzer:
|
|
|
92
102
|
|
|
93
103
|
self.registers = Registers(self.device)
|
|
94
104
|
self.control = Control(self.registers)
|
|
95
|
-
self.stream = Stream(self.context, self.device, self.registers)
|
|
105
|
+
self.stream = Stream(self.context, self.device, self.registers, self.chunk_size)
|
|
96
106
|
|
|
97
107
|
# Load calibration data
|
|
98
108
|
self.cal_data = self.control.load_calibration()
|
|
@@ -212,7 +222,7 @@ class Analyzer:
|
|
|
212
222
|
"""Continuously submit zero-DAC / ADC-read transfer pairs while capturing."""
|
|
213
223
|
while self._capturing and self.stream.running:
|
|
214
224
|
try:
|
|
215
|
-
self.stream.write_zeros(self.
|
|
225
|
+
self.stream.write_zeros(self.chunk_size)
|
|
216
226
|
except Exception as exc: # pylint: disable=broad-except
|
|
217
227
|
# Racing with stop() is expected; a real failure while we still
|
|
218
228
|
# expect to run is recorded in the post-loop reconciliation below.
|
|
@@ -277,6 +287,120 @@ class Analyzer:
|
|
|
277
287
|
if self._dac_writer is not None:
|
|
278
288
|
self._dac_writer.join(timeout=5.0)
|
|
279
289
|
|
|
290
|
+
def send_receive(self, left_wave: Wave, right_wave: Wave) -> tuple[Wave, Wave]:
|
|
291
|
+
"""
|
|
292
|
+
Sends DAC data to the device and receives ADC data.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
left_wave (Wave): Wave instance with left channel DAC data.
|
|
296
|
+
right_wave (Wave): Wave instance with right channel DAC data.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
tuple[Wave, Wave]: Tuple containing Wave instances with left and right channel ADC data.
|
|
300
|
+
"""
|
|
301
|
+
left_dac_data = left_wave.get_buffer()
|
|
302
|
+
right_dac_data = right_wave.get_buffer()
|
|
303
|
+
|
|
304
|
+
# On QA402 and QA403, outputs need to be swapped
|
|
305
|
+
left_dac_data, right_dac_data = right_dac_data, left_dac_data
|
|
306
|
+
|
|
307
|
+
left_peak = np.max(left_dac_data)
|
|
308
|
+
|
|
309
|
+
# Get calibration factors for outgoing data
|
|
310
|
+
cal_dac_left, cal_dac_right = self.control.get_dac_cal(
|
|
311
|
+
self.cal_data, self.params.max_output_level
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Convert to dBFS. Note the 3 dB adjustment--dBFS is peak, while dBV is RMS
|
|
315
|
+
dac_dbfs_adjustment = 10 ** -((self.params.max_output_level + 3) / 20)
|
|
316
|
+
|
|
317
|
+
# Apply calibration and dBFS scaling
|
|
318
|
+
left_dac_data = left_dac_data * dac_dbfs_adjustment * cal_dac_left
|
|
319
|
+
right_dac_data = right_dac_data * dac_dbfs_adjustment * cal_dac_right
|
|
320
|
+
|
|
321
|
+
# Convert incoming doubles to float
|
|
322
|
+
left_dac_data_float = left_dac_data.astype(np.float32)
|
|
323
|
+
right_dac_data_float = right_dac_data.astype(np.float32)
|
|
324
|
+
|
|
325
|
+
# Interleave the left and right channels
|
|
326
|
+
interleaved_dac_data = np.empty(
|
|
327
|
+
(left_dac_data_float.size + right_dac_data_float.size,), dtype=np.float32
|
|
328
|
+
)
|
|
329
|
+
interleaved_dac_data[0::2] = left_dac_data_float
|
|
330
|
+
interleaved_dac_data[1::2] = right_dac_data_float
|
|
331
|
+
|
|
332
|
+
# Convert to bytes, multiplying by max int value
|
|
333
|
+
max_int_value = 2 ** 31 - 1
|
|
334
|
+
interleaved_dac_data = (interleaved_dac_data * max_int_value).astype(np.int32)
|
|
335
|
+
|
|
336
|
+
num_ints_per_chunk = self.chunk_size // 4 # 32-bit ints, so 4 bytes per int
|
|
337
|
+
total_chunks = len(interleaved_dac_data) // num_ints_per_chunk
|
|
338
|
+
|
|
339
|
+
self.stream.start()
|
|
340
|
+
|
|
341
|
+
# Play wave on Bluetooth if available
|
|
342
|
+
bt_thread = None
|
|
343
|
+
if self.bt_device:
|
|
344
|
+
# Play both left and right waves on Bluetooth
|
|
345
|
+
bt_thread = self.bt_device.play_wave_background(left_wave, right_wave)
|
|
346
|
+
|
|
347
|
+
try:
|
|
348
|
+
for i in range(total_chunks):
|
|
349
|
+
chunk = interleaved_dac_data[
|
|
350
|
+
i * num_ints_per_chunk: (i + 1) * num_ints_per_chunk
|
|
351
|
+
]
|
|
352
|
+
buffer = struct.pack("<%di" % len(chunk), *chunk)
|
|
353
|
+
self.stream.write(buffer)
|
|
354
|
+
finally:
|
|
355
|
+
self.stream.stop()
|
|
356
|
+
|
|
357
|
+
# Collect ADC data. This is bytes
|
|
358
|
+
interleaved_adc_data = self.stream.collect_remaining_adc_data()
|
|
359
|
+
|
|
360
|
+
# Wait for the Bluetooth thread to finish after processing
|
|
361
|
+
if bt_thread:
|
|
362
|
+
bt_thread.join()
|
|
363
|
+
|
|
364
|
+
# Convert collected ADC data back to int
|
|
365
|
+
interleaved_adc_data = np.frombuffer(interleaved_adc_data, dtype=np.int32)
|
|
366
|
+
|
|
367
|
+
# Separate interleaved ADC data into left and right channels. This is int
|
|
368
|
+
left_adc_data_int = interleaved_adc_data[0::2]
|
|
369
|
+
right_adc_data_int = interleaved_adc_data[1::2]
|
|
370
|
+
|
|
371
|
+
# Convert left and right channels back to double
|
|
372
|
+
left_adc_data = left_adc_data_int.astype(np.float64) / max_int_value
|
|
373
|
+
right_adc_data = right_adc_data_int.astype(np.float64) / max_int_value
|
|
374
|
+
|
|
375
|
+
# Get calibration factors for incoming data
|
|
376
|
+
cal_adc_left, cal_adc_right = self.control.get_adc_cal(
|
|
377
|
+
self.cal_data, self.params.max_input_level
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# Convert from dBFS to dBV. Note the 6 dB factor--the ADC is differential
|
|
381
|
+
adc_dbfs_correction = 10 ** ((self.params.max_input_level - 6) / 20)
|
|
382
|
+
|
|
383
|
+
# Apply calibration and dBFS scaling
|
|
384
|
+
left_adc_data = left_adc_data * cal_adc_left * adc_dbfs_correction
|
|
385
|
+
right_adc_data = right_adc_data * cal_adc_right * adc_dbfs_correction
|
|
386
|
+
|
|
387
|
+
# Ensure the buffer matches the expected shape. Is this needed?
|
|
388
|
+
expected_shape = (
|
|
389
|
+
self.params.pre_buf + self.params.fft_size + self.params.post_buf,
|
|
390
|
+
)
|
|
391
|
+
if left_adc_data.shape[0] != expected_shape[0]:
|
|
392
|
+
left_adc_data = np.resize(left_adc_data, expected_shape)
|
|
393
|
+
if right_adc_data.shape[0] != expected_shape[0]:
|
|
394
|
+
right_adc_data = np.resize(right_adc_data, expected_shape)
|
|
395
|
+
|
|
396
|
+
# Create instances of Wave with the full buffers
|
|
397
|
+
left_wave = Wave(self.params)
|
|
398
|
+
right_wave = Wave(self.params)
|
|
399
|
+
left_wave.set_buffer(left_adc_data)
|
|
400
|
+
right_wave.set_buffer(right_adc_data)
|
|
401
|
+
|
|
402
|
+
return left_wave, right_wave
|
|
403
|
+
|
|
280
404
|
def capture(self, total_samples: int) -> tuple[np.ndarray, np.ndarray]:
|
|
281
405
|
"""
|
|
282
406
|
Captures ``total_samples`` samples from both ADC input channels without
|
|
@@ -46,7 +46,7 @@ class Control:
|
|
|
46
46
|
"""
|
|
47
47
|
val = self.samplerate2reg[rate]
|
|
48
48
|
self.registers.write(9, val)
|
|
49
|
-
time.sleep(0.
|
|
49
|
+
time.sleep(0.2) # A small delay to ensure the sample rate is set
|
|
50
50
|
|
|
51
51
|
def load_calibration(self):
|
|
52
52
|
"""
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
import queue
|
|
3
|
+
import time
|
|
4
|
+
|
|
3
5
|
import usb1
|
|
4
6
|
import logging
|
|
5
7
|
from typing import Callable
|
|
@@ -27,7 +29,7 @@ class Stream:
|
|
|
27
29
|
"""
|
|
28
30
|
|
|
29
31
|
TRANSFER_TIMEOUT_MS = 1000 # Timeout for USB transfers in milliseconds
|
|
30
|
-
|
|
32
|
+
DEFAULT_TRANSFER_BYTES = 16384 # 16 kB per USB bulk transfer (hardware chunk size)
|
|
31
33
|
# cap on unread ADC data before overflow
|
|
32
34
|
MAX_BUFFERED_BYTES = 256 * 1024 * 1024
|
|
33
35
|
|
|
@@ -36,6 +38,7 @@ class Stream:
|
|
|
36
38
|
context: usb1.USBContext,
|
|
37
39
|
device: usb1.USBDeviceHandle,
|
|
38
40
|
registers: Registers,
|
|
41
|
+
transfer_bytes_size: int = DEFAULT_TRANSFER_BYTES
|
|
39
42
|
) -> None:
|
|
40
43
|
"""
|
|
41
44
|
Initialize the Stream.
|
|
@@ -44,10 +47,12 @@ class Stream:
|
|
|
44
47
|
context (usb1.USBContext): The USB context.
|
|
45
48
|
device (usb1.USBDeviceHandle): The USB device handle.
|
|
46
49
|
registers (Registers): The Registers instance for control writes.
|
|
50
|
+
transfer_bytes_size (int):
|
|
47
51
|
"""
|
|
48
52
|
self.context = context
|
|
49
53
|
self.device = device
|
|
50
54
|
self.registers = registers
|
|
55
|
+
self.transfer_bytes_size = transfer_bytes_size # USB bulk transfer (hardware chunk size)
|
|
51
56
|
self.endpoint_read = usb1.ENDPOINT_IN | 0x02 # EP2 in
|
|
52
57
|
self.endpoint_write = usb1.ENDPOINT_OUT | 0x02 # EP2 out
|
|
53
58
|
self.dacQueue = queue.Queue(
|
|
@@ -79,7 +84,7 @@ class Stream:
|
|
|
79
84
|
self._adc_data_carry = bytearray() # leftover ADC bytes between consume_adc calls
|
|
80
85
|
# latched, raised by consume_adc
|
|
81
86
|
self._overflow_error: AdcOverflowError | None = None
|
|
82
|
-
self._max_queued_chunks = self.MAX_BUFFERED_BYTES // self.
|
|
87
|
+
self._max_queued_chunks = self.MAX_BUFFERED_BYTES // self.transfer_bytes_size
|
|
83
88
|
|
|
84
89
|
@property
|
|
85
90
|
def overflow_error(self) -> "AdcOverflowError | None":
|
|
@@ -205,10 +210,26 @@ class Stream:
|
|
|
205
210
|
self.dacQueue.put(dac)
|
|
206
211
|
self.adcQueue.put(read)
|
|
207
212
|
|
|
208
|
-
def write_zeros(self, chunk_bytes: int =
|
|
213
|
+
def write_zeros(self, chunk_bytes: int = DEFAULT_TRANSFER_BYTES) -> None:
|
|
209
214
|
"""Feed the ADC pipeline with a zero DAC buffer (continuous capture)."""
|
|
210
215
|
self.write(bytes(chunk_bytes))
|
|
211
216
|
|
|
217
|
+
def collect_remaining_adc_data(self):
|
|
218
|
+
"""
|
|
219
|
+
Waits for all remaining ADC transfers to complete and returns the collected data.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
bytearray: The collected ADC data.
|
|
223
|
+
"""
|
|
224
|
+
while not self.adcQueue.empty():
|
|
225
|
+
time.sleep(0.01)
|
|
226
|
+
|
|
227
|
+
while not self._adc_data.empty():
|
|
228
|
+
chunk = self._adc_data.get()
|
|
229
|
+
self._adc_data_carry.extend(chunk)
|
|
230
|
+
|
|
231
|
+
return self._adc_data_carry
|
|
232
|
+
|
|
212
233
|
def consume_adc(
|
|
213
234
|
self,
|
|
214
235
|
need_bytes: int,
|
|
@@ -26,7 +26,7 @@ class Wave:
|
|
|
26
26
|
|
|
27
27
|
self.amplitude_unit: str = amplitude_unit # Lowercase. Use dbv or dbu
|
|
28
28
|
self.distortion_unit: str = distortion_unit # Lowercase. Use db or pct
|
|
29
|
-
self.energy_unit: str = energy_unit # Lowercase. Use dbv, dbu, V
|
|
29
|
+
self.energy_unit: str = energy_unit # Lowercase. Use dbv, dbu, V or V^2
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def set_buffer(self, buffer: np.ndarray):
|
|
@@ -1,58 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
|
-
".
|
|
4
|
-
"README.md",
|
|
5
|
-
".pylint_ignore",
|
|
6
|
-
"requirements-test.txt",
|
|
3
|
+
"tox.ini",
|
|
7
4
|
"requirements.txt",
|
|
5
|
+
"requirements-test.txt",
|
|
8
6
|
"requirements-dev.txt",
|
|
9
|
-
"tox.ini",
|
|
10
|
-
"pyproject.toml",
|
|
11
7
|
"MANIFEST.in",
|
|
12
|
-
"
|
|
8
|
+
"pyproject.toml",
|
|
9
|
+
".pylint_ignore",
|
|
13
10
|
"LICENSE",
|
|
11
|
+
"RELEASE_NOTES.md",
|
|
12
|
+
"README.md",
|
|
13
|
+
".gitignore",
|
|
14
|
+
".github/workflows/code_checker.yml",
|
|
15
|
+
".github/workflows/unit_tests.yml",
|
|
16
|
+
".github/workflows/publish_package.yml",
|
|
17
|
+
"tests/__init__.py",
|
|
18
|
+
"tests/test_template.py",
|
|
19
|
+
"src/PyQa40x/sig_proc.py",
|
|
14
20
|
"src/PyQa40x/wave.py",
|
|
15
|
-
"src/PyQa40x/
|
|
16
|
-
"src/PyQa40x/fft_processor.py",
|
|
17
|
-
"src/PyQa40x/wave_sine.py",
|
|
21
|
+
"src/PyQa40x/helpers.py",
|
|
18
22
|
"src/PyQa40x/freq_series_plotter.py",
|
|
19
|
-
"src/PyQa40x/analyzer_params.py",
|
|
20
|
-
"src/PyQa40x/sig_proc.py",
|
|
21
|
-
"src/PyQa40x/control.py",
|
|
22
23
|
"src/PyQa40x/math_sines.py",
|
|
23
|
-
"src/PyQa40x/
|
|
24
|
-
"src/PyQa40x/helpers.py",
|
|
24
|
+
"src/PyQa40x/wave_sine.py",
|
|
25
25
|
"src/PyQa40x/registers.py",
|
|
26
|
-
"src/PyQa40x/cross_correlation.py",
|
|
27
|
-
"src/PyQa40x/series_plotter.py",
|
|
28
26
|
"src/PyQa40x/math_windows.py",
|
|
29
|
-
"src/PyQa40x/bluetooth.py",
|
|
30
27
|
"src/PyQa40x/math_energy.py",
|
|
31
28
|
"src/PyQa40x/math_chirp.py",
|
|
32
|
-
"src/PyQa40x/
|
|
29
|
+
"src/PyQa40x/analyzer.py",
|
|
30
|
+
"src/PyQa40x/analyzer_params.py",
|
|
33
31
|
"src/PyQa40x/__init__.py",
|
|
32
|
+
"src/PyQa40x/math_general.py",
|
|
33
|
+
"src/PyQa40x/control.py",
|
|
34
|
+
"src/PyQa40x/wave_chirp.py",
|
|
35
|
+
"src/PyQa40x/series_plotter.py",
|
|
36
|
+
"src/PyQa40x/fft_processor.py",
|
|
34
37
|
"src/PyQa40x/stream.py",
|
|
35
|
-
"src/PyQa40x
|
|
38
|
+
"src/PyQa40x/cross_correlation.py",
|
|
39
|
+
"src/PyQa40x/bluetooth.py",
|
|
36
40
|
"src/PyQa40x.egg-info/SOURCES.txt",
|
|
37
|
-
"src/PyQa40x.egg-info/top_level.txt",
|
|
38
41
|
"src/PyQa40x.egg-info/dependency_links.txt",
|
|
42
|
+
"src/PyQa40x.egg-info/requires.txt",
|
|
39
43
|
"src/PyQa40x.egg-info/PKG-INFO",
|
|
40
|
-
".
|
|
41
|
-
".github/workflows/code_checker.yml",
|
|
42
|
-
".github/workflows/publish_package.yml",
|
|
44
|
+
"src/PyQa40x.egg-info/top_level.txt",
|
|
43
45
|
"_ci/is_dev_version.sh",
|
|
44
|
-
"LibTest/
|
|
45
|
-
"LibTest/PyQa40x_acoustic_chirp_spl_bt.py",
|
|
46
|
-
"LibTest/PyQa40x_acoustic_dbspl.py",
|
|
46
|
+
"LibTest/PyQa40x_thdn.py",
|
|
47
47
|
"LibTest/PyQa40x_freq_response_with_mask.py",
|
|
48
|
-
"LibTest/PyQa40x_pinknoise.py",
|
|
49
|
-
"LibTest/PyQa40x_acoustic_energy_decay_bt.py",
|
|
50
48
|
"LibTest/mask_phase.txt",
|
|
51
49
|
"LibTest/PyQa40x_coherent_averaging.py",
|
|
52
|
-
"LibTest/PyQa40x_thdn.py",
|
|
53
50
|
"LibTest/FirstPrinciples.py",
|
|
51
|
+
"LibTest/PyQa40x_cross_correlation.py",
|
|
52
|
+
"LibTest/PyQa40x_pinknoise.py",
|
|
54
53
|
"LibTest/mask_freq.txt",
|
|
55
|
-
"
|
|
56
|
-
"
|
|
54
|
+
"LibTest/PyQa40x_acoustic_energy_decay_bt.py",
|
|
55
|
+
"LibTest/PyQa40x_acoustic_dbspl.py",
|
|
56
|
+
"LibTest/PyQa40x_acoustic_chirp_spl_bt.py"
|
|
57
57
|
]
|
|
58
58
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|