Added and tested real time signal viewer

This commit is contained in:
Anne de Jong 2024-10-07 20:45:11 +02:00
parent 172356055c
commit 58093dd5cd
15 changed files with 725 additions and 92 deletions

View File

@ -10,85 +10,27 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"id": "6c06a0c3-dcf7-4d21-b1f3-eced84e31218",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🍹 Building a mixed python/rust project\n",
"🔗 Found pyo3 bindings\n",
"🐍 Found CPython 3.10 at /home/anne/.pyenv/versions/lasprs/bin/python\n",
"Requirement already satisfied: numpy in /home/anne/.pyenv/versions/lasprs/lib/python3.10/site-packages (1.26.4)\n",
"\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-build-config v0.21.2\n",
"\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-macros-backend v0.21.2 178/189: pyo3-build-config \n",
"\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-ffi v0.21.2=======> ] 178/189: pyo3-macros-backend, pyo3...\n",
"\u001b[1m\u001b[32m Compiling\u001b[0m pyo3 v0.21.2\n",
"\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-macros v0.21.2=====> ] 183/189: pyo3-macros-backend, pyo3...\n",
"\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m numpy v0.21.0===========> ] 186/189: pyo3 \n",
"\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m lasprs v0.6.1 (/home/anne/wip/mycode/lasprs) \n",
"\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: type alias `Vc` is never used\u001b[0m \n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/config.rs:63:10\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m63\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub type Vc = Vec<Cflt>;\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0m\u001b[1mnote\u001b[0m\u001b[0m: `#[warn(dead_code)]` on by default\u001b[0m\n",
"\n",
"\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: type alias `Cmat` is never used\u001b[0m \n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/config.rs:75:10\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m75\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub type Cmat = Array2<Cflt>;\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^\u001b[0m\n",
"\n",
"\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: methods `ninchannels` and `noutchannels` are never used\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/daq/api/mod.rs:25:8\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m20\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub trait Stream {\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m------\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mmethods in this trait\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m...\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m25\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m fn ninchannels(&self) -> usize;\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m...\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m28\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m fn noutchannels(&self) -> usize;\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n",
"\n",
"\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: method `setPreFilter` is never used\u001b[0m \n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/siggen.rs:320:12\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m318\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mimpl SiggenChannelConfig {\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m------------------------\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mmethod in this implementation\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m319\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m /// Set new pre-filter that filters the source signal\u001b[0m\n",
"\u001b[0m\u001b[1m\u001b[38;5;12m320\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m pub fn setPreFilter(&mut self, pref: Option<Box<dyn Filter>>) {\u001b[0m\n",
"\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n",
"\n",
"\u001b[K\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m:\u001b[0m `lasprs` (lib) generated 4 warningssprs \n",
"\u001b[1m\u001b[32m Finished\u001b[0m \u001b]8;;https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles\u001b\\`dev` profile [unoptimized + debuginfo]\u001b]8;;\u001b\\ target(s) in 6.04s\n",
"📦 Built wheel for CPython 3.10 to /tmp/.tmp03vGw7/lasprs-0.6.1-cp310-cp310-linux_x86_64.whl\n",
"✏️ Setting installed package as editable\n",
"🛠 Installed lasprs-0.6.1\n"
]
}
],
"outputs": [],
"source": [
"!cd .. && maturin develop -F python-bindings"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "3e651371-e7a5-4013-a265-ab80f8b1eb41",
"metadata": {},
"outputs": [],
"source": [
"from lasprs import WindowType"
"from lasprs import WindowType, ApsSettings, AvPowerSpectra, ApsMode, Overlap, FreqWeighting"
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"id": "9d6bdf3b-40f8-4c3b-85ac-4ff8b8c7dcae",
"metadata": {},
"outputs": [],
@ -98,27 +40,46 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"id": "3a31899d-37de-4653-9b6e-61dcf7c683f4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[WindowType.Hann,\n",
" WindowType.Hamming,\n",
" WindowType.Rect,\n",
" WindowType.Bartlett,\n",
" WindowType.Blackman]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"w"
"settings = ApsSettings(ApsMode.AllAveraging(), Overlap.NoOverlap(), WindowType.Hann, FreqWeighting.A, 2048, 48000)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b4771bde-f3f3-4639-bbe6-96f49e004b3d",
"metadata": {},
"outputs": [],
"source": [
"aps = AvPowerSpectra(settings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "86cac094-5969-4a75-83c3-49b486687bb1",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"signal = np.zeros(48000)\n",
"signal[200] = 1\n",
"import matplotlib.pyplot as plt\n",
"plt.plot(aps.compute(signal[:,None])[:,0,0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8d72aa7b-0cff-463c-be57-666cf74f6793",
"metadata": {},
"outputs": [],
"source": [
"#!pip install matplotlib"
]
}
],
@ -138,7 +99,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -127,7 +127,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -102,7 +102,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -0,0 +1,97 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "ec44a8b1-7508-470b-bb2e-f26c7ad8e851",
"metadata": {},
"outputs": [],
"source": [
"!cd .. && maturin develop -F python-bindings"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29b4422e-844b-4944-a391-313ef0ed26e4",
"metadata": {},
"outputs": [],
"source": [
"from lasprs import StreamMgr, ClipState, PPM"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a12659c7-5ec9-4011-accc-423c4c660701",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"smgr = StreamMgr()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "709aa842-0c47-422c-806b-edf2bf97df4b",
"metadata": {},
"outputs": [],
"source": [
"smgr.startDefaultInputStream()\n",
"ppm = PPM(smgr)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2eb1bf1a-8133-421a-ac3e-d609e83ad763",
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"N = 0\n",
"while N < 60:\n",
" try:\n",
" print(ppm.getState(), end='\\r')\n",
" except KeyboardInterrupt:\n",
" break\n",
" time.sleep(0.1)\n",
" N += 1\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7d94d2fb-c03e-415e-b58b-86dc70865c2e",
"metadata": {},
"outputs": [],
"source": [
"del ppm"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,95 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "7ad7512c-d605-4c9f-acd5-5f6a1c22cc1a",
"metadata": {},
"outputs": [],
"source": [
"!cd .. && maturin develop -F python-bindings"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92d7023d-3168-4d55-841a-01d8f6d03bab",
"metadata": {},
"outputs": [],
"source": [
"from lasprs import WindowType, ApsSettings, AvPowerSpectra, ApsMode, Overlap, FreqWeighting, StreamMgr, RtAps"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "faf909e7-5c45-43c4-9687-0d33eb939e5f",
"metadata": {},
"outputs": [],
"source": [
"settings = ApsSettings(ApsMode.AllAveraging(), Overlap.NoOverlap(), WindowType.Hann, FreqWeighting.A, 2048, 48000)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "814dafd3-4e84-4e62-8d30-6d07d4bf75ae",
"metadata": {},
"outputs": [],
"source": [
"smgr = StreamMgr()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ba155e1-7481-4f77-bc6b-e3096be539ce",
"metadata": {},
"outputs": [],
"source": [
"smgr.startDefaultInputStream()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7edbd928-b0e7-4b22-afaf-96e247d2672c",
"metadata": {},
"outputs": [],
"source": [
"rt = RtAps(smgr,settings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7ef4f826-aa05-4d71-a866-29c9491b478b",
"metadata": {},
"outputs": [],
"source": [
"rt.get_last()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,89 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "7ad7512c-d605-4c9f-acd5-5f6a1c22cc1a",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"!cd .. && maturin develop -F python-bindings"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92d7023d-3168-4d55-841a-01d8f6d03bab",
"metadata": {},
"outputs": [],
"source": [
"from lasprs import StreamMgr, RtViewer"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "814dafd3-4e84-4e62-8d30-6d07d4bf75ae",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"smgr = StreamMgr()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ba155e1-7481-4f77-bc6b-e3096be539ce",
"metadata": {},
"outputs": [],
"source": [
"smgr.startDefaultInputStream()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7edbd928-b0e7-4b22-afaf-96e247d2672c",
"metadata": {},
"outputs": [],
"source": [
"rt = RtViewer(smgr, 2, 600, 0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7ef4f826-aa05-4d71-a866-29c9491b478b",
"metadata": {},
"outputs": [],
"source": [
"rt.get_last()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -140,7 +140,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -0,0 +1,162 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "afa2bdda-0748-4a76-ad5c-d19859f833f6",
"metadata": {},
"outputs": [],
"source": [
"from lasprs import DaqConfig, StreamMgr"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "2b47552e-823e-48ba-8853-7f58fc1f90de",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"Cannot connect to server socket err = No such file or directory\n",
"Cannot connect to server request channel\n",
"jack server is not running or cannot be started\n",
"JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n",
"JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n",
"Cannot connect to server socket err = No such file or directory\n",
"Cannot connect to server request channel\n",
"jack server is not running or cannot be started\n",
"JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n",
"JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n",
"ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp\n",
"ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n",
"ALSA lib pcm_dsnoop.c:541:(snd_pcm_dsnoop_open) The dsnoop plugin supports only capture stream\n",
"ALSA lib pcm_dsnoop.c:541:(snd_pcm_dsnoop_open) The dsnoop plugin supports only capture stream\n"
]
}
],
"source": [
"s = StreamMgr()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "39d4c156-8304-4ed6-b9da-1d8a14d3bbe8",
"metadata": {},
"outputs": [],
"source": [
"ds = s.getDeviceInfo()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "a6f28472-a52c-4ccf-b65f-2a44b2eb59e1",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[DeviceInfo { api: Cpal, device_name: \"pipewire\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"pulse\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"default\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=3\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=7\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=8\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=9\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=0\", avDataTypes: [I8, I16, I32, F32, F64, I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=3\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=7\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=8\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=9\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"sysdefault:CARD=PCH\", avDataTypes: [I8, I16, I32, F32, F64, I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"front:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"surround40:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"surround51:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"surround71:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=0\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=1\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=2\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=3\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=0\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=3\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=7\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=8\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=9\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n",
" DeviceInfo { api: Cpal, device_name: \"dsnoop:CARD=PCH,DEV=0\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 0, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number }]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "00635264-6cbc-4391-b207-308e859fd109",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -140,7 +140,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
"version": "3.12.3"
}
},
"nbformat": 4,

View File

@ -80,6 +80,7 @@ fn lasprs(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<rt::PPM>()?;
m.add_class::<rt::ClipState>()?;
m.add_class::<rt::RtAps>()?;
m.add_class::<rt::RtViewer>()?;
Ok(())
}

View File

@ -5,7 +5,10 @@ use crate::config::*;
use ndarray::ArrayView1;
/// Compute maximum value of an array of float values
pub fn max(arr: ArrayView1<Flt>) -> Flt {
pub fn max<T>(arr: ArrayView<Flt, T>) -> Flt
where
T: ndarray::Dimension,
{
arr.fold(
-Flt::INFINITY,
|acc, new| if *new > acc { *new } else { acc },
@ -13,7 +16,10 @@ pub fn max(arr: ArrayView1<Flt>) -> Flt {
}
/// Compute minimum value of an array of float values
pub fn min(arr: ArrayView1<Flt>) -> Flt {
pub fn min<T>(arr: ArrayView<Flt, T>) -> Flt
where
T: ndarray::Dimension,
{
arr.fold(
Flt::INFINITY,
|acc, new| if *new < acc { *new } else { acc },
@ -21,6 +27,9 @@ pub fn min(arr: ArrayView1<Flt>) -> Flt {
}
/// Compute maximum absolute value of an array of float values
pub fn maxabs(arr: ArrayView1<Flt>) -> Flt {
pub fn maxabs<T>(arr: ArrayView<Flt, T>) -> Flt
where
T: ndarray::Dimension,
{
arr.fold(0., |acc, new| if new.abs() > acc { new.abs() } else { acc })
}

View File

@ -7,7 +7,7 @@
mod aps;
mod fft;
mod ps;
mod timebuffer;
pub mod timebuffer;
mod window;
mod freqweighting;
mod apssettings;

View File

@ -3,5 +3,7 @@
//! (Spectrograms, Auto powers, ..., or )
mod ppm;
mod rtaps;
mod rtview;
pub use ppm::{PPM, ClipState};
pub use rtaps::{RtAps, RtApsResult};
pub use rtview::RtViewer;

View File

@ -9,7 +9,6 @@ use parking_lot::Mutex;
use rayon::ThreadPool;
use std::ops::Deref;
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::time::Duration;
type SharedRtApsStatus = Arc<Mutex<Option<RtApsResult>>>;
@ -92,7 +91,7 @@ impl RtAps {
}
// Check for messages and act accordingly
if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(10)).ok() {
if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(1)).ok() {
match msg {
RtApsMessage::StopThread => {
let mut status = status.lock();
@ -169,6 +168,7 @@ mod test {
use super::*;
use crate::{daq::StreamMgr, ps::ApsSettingsBuilder};
use std::thread;
#[test]
fn test_rtaps1() -> Result<(), anyhow::Error> {
{

217
src/rt/rtview.rs Normal file
View File

@ -0,0 +1,217 @@
use crate::config::*;
use crate::daq::{InStreamMsg, StreamHandler, StreamMetaData, StreamMgr};
use crate::math::{max, min};
use crate::ps::timebuffer::TimeBuffer;
use anyhow::{anyhow, bail, Result};
use crossbeam::channel::{unbounded, Receiver, Sender};
use parking_lot::Mutex;
use std::sync::Arc;
use std::time::Duration;
type RtViewUpdate = Array2<Flt>;
type SharedRtViewerStatus = Arc<Mutex<Option<Result<RtViewUpdate>>>>;
/// Real time viewer that tracks the signal and the envelope of the signal, in
#[cfg_attr(feature = "python-bindings", pyclass)]
#[derive(Debug)]
pub struct RtViewer {
/// The computed time step per output (inverse of 'sampling frequency') in \[s\]
pub T: Flt,
/// The number of samples in the time buffer
pub N: usize,
sender: Sender<RtMsg>,
status: SharedRtViewerStatus,
}
impl RtViewer {
/// Create new real time signal viewer. Outputs buffers of the signal envelopOutputs buffers of the signal envelope as a function of time.
///
/// # Args
///
/// - `t_hist` - The time history to show in \[s\].
/// - `resolution` - The number of samples within this history. This should
/// correspond more / less to the amount of pixels used in the viewer.
///
pub fn new(
smgr: &mut StreamMgr,
t_hist: Flt,
resolution: usize,
channel: usize,
) -> Result<RtViewer> {
if t_hist <= 0. {
bail!("The time history to show in [s] should be > 0.")
}
if resolution <= 1 {
bail!("Invalid resolution. Please use value > 1");
}
let status = Arc::new(Mutex::new(None));
let (sender, rxmsg) = unbounded();
Self::startThread(smgr, rxmsg, t_hist, resolution, channel, status.clone());
Ok(RtViewer {
T: t_hist,
N: resolution,
sender,
status,
})
}
fn startThread(
smgr: &mut StreamMgr,
rxmsg: Receiver<RtMsg>,
t_hist: Flt,
N: usize,
channel: usize,
status: SharedRtViewerStatus,
) {
let (tx, rxstream) = unbounded();
smgr.addInQueue(tx);
rayon::spawn(move || {
let mut buf = Array2::zeros((N, 2).f());
let zero_out = |mut arr: ArrayViewMut2<Flt>| {
arr.mapv_inplace(|_| 0.);
};
let mut circbuf = TimeBuffer::new();
// Placeholder value, should be updated when stream is started.
let mut nsamples_per_output = 1;
let T = t_hist / N as Flt;
'mainloop: loop {
if let Some(msg) = rxstream.recv_timeout(Duration::from_millis(10)).ok() {
match msg {
InStreamMsg::StreamStarted(new_meta) => {
if channel >= new_meta.nchannels() {
// The chosen channel is too high. We stop and
// kill here.
*status.lock() = Some(Err(anyhow!("Invalid channel. Chosen channel is higher than maximum amount of channels in stream, which is {}", new_meta.nchannels())));
return;
}
// Calculate the number of samples per timestamp of
// output
let T_ac = 1. / new_meta.samplerate;
nsamples_per_output = std::cmp::max((T / T_ac) as usize, 1);
}
InStreamMsg::StreamStopped | InStreamMsg::StreamError(_) => {
circbuf = TimeBuffer::new();
zero_out(buf.view_mut());
*status.lock() = None;
}
InStreamMsg::InStreamData(id) => {
// Push data on circular buffer
let fd = id.getFloatData();
let dat = fd.column(channel);
circbuf.push(dat.slice(s![.., NewAxis]));
}
}
}
// See if we can update the time buffer
let mut nnew = circbuf.nsamples() / nsamples_per_output;
if nnew > 0 {
// Rotate back samples, and add new.
buf.column_mut(0).as_slice_mut().unwrap().rotate_left(nnew);
buf.column_mut(1).as_slice_mut().unwrap().rotate_left(nnew);
while let Some(samples) = circbuf.pop(nsamples_per_output, 0) {
let max = max(samples.view());
let min = min(samples.view());
buf[[N - nnew, 0]] = min;
buf[[N - nnew, 1]] = max;
nnew -= 1;
}
let new = Ok(buf.clone());
*status.lock() = Some(new);
}
// Check for messages and act accordingly
if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(1)).ok() {
match msg {
RtMsg::StopThread => {
let mut status = status.lock();
*status = None;
break 'mainloop;
}
}
}
}
});
}
/// Returns an array of time instances corresponding to the output data.
pub fn getTimeArray(&self) -> Dcol {
Dcol::linspace(-self.T * ((self.N - 1) as Flt) / self.N as Flt, 0., self.N)
}
/// Get the last updated value of the array of mins / max, or an error from
/// the system.
pub fn get_last(&self) -> Option<Result<RtViewUpdate>> {
if let Some(x) = self.status.lock().take() {
Some(x)
} else {
None
}
}
}
#[cfg(feature = "python-bindings")]
#[cfg_attr(feature = "python-bindings", pymethods)]
impl RtViewer {
#[new]
fn new_py(
smgr: &mut StreamMgr,
t_hist: Flt,
resolution: usize,
channel: usize,
) -> Result<RtViewer> {
RtViewer::new(smgr, t_hist, resolution, channel)
}
#[pyo3(name = "getTimeArray")]
fn getTimeArray_py<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray1<Flt>> {
self.getTimeArray().to_pyarray_bound(py)
}
#[pyo3(name = "get_last")]
fn get_last_py<'py>(&self, py: Python<'py>) -> PyResult<Option<Bound<'py, PyArray2<Flt>>>> {
if let Some(res) = self.get_last() {
let res = res?;
return Ok(Some(res.to_pyarray_bound(py)));
}
Ok(None)
}
}
impl Drop for RtViewer {
fn drop(&mut self) {
self.sender.send(RtMsg::StopThread).unwrap();
}
}
enum RtMsg {
StopThread,
}
#[cfg(test)]
mod test {
use crate::daq::StreamMgr;
use super::RtViewer;
#[test]
fn test_rtviewer1() {
let mut smgr = StreamMgr::new();
let t_hist = 10.;
let resolution = 10;
let channel = 0;
let a = RtViewer::new(&mut smgr, t_hist, resolution, channel)
.unwrap()
.getTimeArray();
dbg!(&a);
assert_eq!(a.last(), Some(&0.));
assert_eq!(a.first(), Some(&-9.));
}
}