diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 48091fc..d276868 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -19,6 +19,7 @@ jobs: ./.github/scripts/install_libiio.sh pip install -r requirements_dev.txt pip install -r doc/requirements.txt + pip install ".[cli,web]" - name: Build doc run: | @@ -41,6 +42,7 @@ jobs: ./.github/scripts/install_libiio.sh pip install -r requirements_dev.txt pip install -r doc/requirements.txt + pip install ".[cli,web]" - name: Check doc build run: | @@ -80,6 +82,7 @@ jobs: ./.github/scripts/install_libiio.sh pip install -r requirements_dev.txt pip install -r doc/requirements.txt + pip install ".[cli,web]" - name: Build doc and release run: | @@ -111,6 +114,7 @@ jobs: ./.github/scripts/install_libiio.sh pip install -r requirements_dev.txt pip install -r doc/requirements.txt + pip install ".[cli,web]" - name: Build doc and release run: | @@ -151,6 +155,7 @@ jobs: pip install -r requirements_dev.txt pip install -r doc/requirements.txt pip install setuptools wheel twine build + pip install ".[cli,web]" - name: Build doc and release run: | diff --git a/.github/workflows/pyinstallers.yml b/.github/workflows/pyinstallers.yml new file mode 100644 index 0000000..87dbac6 --- /dev/null +++ b/.github/workflows/pyinstallers.yml @@ -0,0 +1,36 @@ +# Generate pyinstaller executables for Windows, macOS, and Linux +name: Generate PyInstaller + +on: [push, pull_request] + +jobs: + Windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: conda-incubator/setup-miniconda@v2 + with: + auto-update-conda: true + python-version: "3.8" + - name: Conda info + shell: bash -l {0} + run: conda info + - name: Conda list + shell: pwsh + run: conda list + - name: Dependencies + run: | + conda activate test + python --version + conda install -c conda-forge pylibiio + pip install -r requirements_dev.txt + pip install -r doc/requirements.txt + pip install pyinstaller + - name: Generate Windows executable + run: | + pyinstaller --onefile --name=pybenchiio cli.py + - name: Upload Windows executable + uses: actions/upload-artifact@v4 + with: + name: pybenchiio + path: dist/pybenchiio.exe diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe3d289..e6f450d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,10 +6,11 @@ repos: - id: codespell entry: codespell --ignore-words=.codespell-whitelist --skip="*.pyc,*.xml" - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.20 + rev: v5.5.4 hooks: - id: isort additional_dependencies: ["toml"] + args: ["--profile", "black"] #- repo: https://github.com/pre-commit/mirrors-mypy # rev: v0.720 # hooks: diff --git a/README.md b/README.md index 08428b8..c71e23f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ # pybench Interfaces to control instruments in python + +## Web backend development + +```bash +fastapi dev bench/web/app.py +``` diff --git a/bench/cli/iiotools.py b/bench/cli/iiotools.py index b8079e9..15259d9 100644 --- a/bench/cli/iiotools.py +++ b/bench/cli/iiotools.py @@ -1,4 +1,11 @@ +import os +import subprocess +import time + import click +import requests + +from bench.keysight.dwta.data_capture import capture_iq_datafile try: import iio @@ -9,15 +16,11 @@ @click.group() @click.option("--uri", "-u", help="URI of target device/board") -@click.option("--device", "-d", help="Device driver to use") -@click.option("--complex", "-x", is_flag=True, help="Use complex mode") @click.pass_context -def cli(ctx, uri, device, complex): +def cli(ctx, uri): """Command line interface for pybench IIO based boards""" ctx.obj = {} ctx.obj["uri"] = uri - ctx.obj["device"] = device - ctx.obj["complex"] = complex @cli.command() @@ -27,17 +30,19 @@ def cli(ctx, uri, device, complex): @click.option( "--amplitude", "-a", help="Set the amplitude of the DDS in 0->1", required=True ) +@click.option("--device", "-d", help="IIO device driver name to use") @click.option("--channel", "-c", help="Set the channel of the DDS", required=True) +@click.option("--complex", "-x", is_flag=True, help="Use complex mode") @click.pass_context -def set_dds(ctx, frequency, amplitude, channel): +def set_dds(ctx, frequency, amplitude, device, channel, complex): """Configure DDS""" iioctx = iio.Context(ctx.obj["uri"]) if not iioctx: click.echo("No context") return - dev = iioctx.find_device(ctx.obj["device"]) + dev = iioctx.find_device(device) if not dev: - click.echo(f"Device {ctx.obj['device']} not found") + click.echo(f"Device {device} not found") return dds_channels = [ch.id for ch in dev.channels if "altvoltage" in ch.id] # Set all the DDS scales to 0 @@ -49,7 +54,7 @@ def set_dds(ctx, frequency, amplitude, channel): return chan.attrs["scale"].value = "0" # Set the desired DDS scale - if ctx.obj["complex"]: + if complex: # Channels are groups of 4 ch = int(channel) * 4 channels = [ch, ch + 1] @@ -64,7 +69,7 @@ def set_dds(ctx, frequency, amplitude, channel): return chan.attrs["frequency"].value = frequency chan.attrs["scale"].value = amplitude - if ctx.obj["complex"]: + if complex: # i is odd if i % 2: chan.attrs["phase"].value = "90000" @@ -72,3 +77,221 @@ def set_dds(ctx, frequency, amplitude, channel): chan.attrs["phase"].value = "0" click.echo(f"Set DDS of channel {channel} to {frequency}Hz and {amplitude} scale") + + +@cli.command() +@click.option("--filename", "-f", help="Name of file to write data to", required=True) +@click.option("--device", "-d", help="Name of device to configure", required=True) +@click.option( + "--channel", + "-c", + help="Channel index to capture data from. Starts from 0", + required=True, +) +@click.option("--samples", "-s", help="Number of samples to capture", required=True) +@click.argument( + "props", nargs=-1, required=False, +) +@click.pass_context +def capture_data(ctx, filename, device, channel, samples, props): + """Capture IQ data to a file in DWTA format + + PROPS is a list of property=value pairs to set device properties. These are + the properties available in the pyadi-iio class interface for the device. + + Example usage with ADALM-PLUTO: + + pybenchiio -u ip:analog.local capture_data -f data.csv -d Pluto -c 0 -s 1024 sample_rate=1000000 + """ + # Checks + samples = int(samples) + channel = int(channel) + + # Parse properties + if props: + oprops = {} + for prop in props: + if "=" not in prop: + raise ValueError( + f"Invalid property: {prop}. Must be in the form key=value" + ) + k, v = prop.split("=") + if v.isdigit(): + v = int(v) + oprops[k] = v + props = oprops + + capture_iq_datafile( + filename, device, channel, samples, ctx.obj["uri"], **dict(props) + ) + + +@cli.command() +@click.option("--filename", "-f", help="Name of file to write data to", required=True) +@click.option("--device", "-d", help="Name of device to configure", required=True) +@click.option("--channel", "-c", help="Channel to capture data from", required=True) +@click.option( + "--server-ip", + "-s", + help="IP address of the server", + required=False, + default="localhost", +) +@click.option( + "--server-port", "-p", help="Port of the server", required=False, default=12345 +) +@click.argument("props", nargs=-1) +@click.pass_context +def transmit_data(ctx, filename, device, channel, server_ip, server_port, props): + """Transmit IQ data file to device through backend server + + File must be in DWTA format, where the first two lines are sample rate and + center frequency, and the rest of the lines are IQ data in the format + I, Q per line. + + Example usage with ADALM-PLUTO: + + pybenchiio -u ip:analog.local transmit_data -f data.csv -d Pluto -c 0 sample_rate=1000000 + """ + + # Checks + channel = int(channel) + + # Parse properties + # if props: + # oprops = {} + # for prop in props: + # if "=" not in prop: + # raise ValueError( + # f"Invalid property: {prop}. Must be in the form key=value" + # ) + # k, v = prop.split("=") + # if v.isdigit(): + # v = int(v) + # oprops[k] = v + # props = oprops + + # transmit_iq_datafile( + # filename, device, channel, ctx.obj["uri"], **dict(props) + # ) + + import os + + import requests + + # Send post request to localhost + url = f"http://{server_ip}:{server_port}/writebuffer" + json_data = { + "uri": ctx.obj["uri"], + "device": device, + "channel": channel, + "data_filename": filename, + "do_scaling": False, + "cycle": True, + "data_complex": True, + "properties": props, + } + r = requests.post(url, json=json_data) + assert r.status_code == 200, f"Failed to send data: {r.json()}" + + +@cli.command() +@click.option( + "--server-ip", + "-s", + help="IP address of the server", + required=False, + default="localhost", +) +@click.option( + "--server-port", "-p", help="Port of the server", required=False, default=12345 +) +def transmit_data_clear(server_ip, server_port): + """Clear the transmit buffer on the server""" + + url = f"http://{server_ip}:{server_port}/clearbuffer" + r = requests.post(url) + assert r.status_code == 200, f"Failed to clear buffer: {r.json()}" + + +@cli.command() +@click.option( + "--host", + "-h", + help="Host to start the server on", + required=False, + default="localhost", +) +@click.option( + "--port", "-p", help="Port to start the server on", required=False, default=12345 +) +def start_server(host, port): + + # Start the server as a subprocess + import os + import subprocess + + loc = os.path.dirname(os.path.realpath(__file__)) + web_app = os.path.join(loc, "..", "web", "app.py") + web_app = os.path.abspath(web_app) + + # Get location of python executable + python = "python" + if "CONDA_PREFIX" in os.environ: + python = os.path.join(os.environ["CONDA_PREFIX"], "bin", "python") + elif "VIRTUAL_ENV" in os.environ: + python = os.path.join(os.environ["VIRTUAL_ENV"], "bin", "python") + elif "PYTHON" in os.environ: + python = os.environ["PYTHON"] + + command = [ + python, + "-m", + "fastapi", + "run", + web_app, + "--host", + str(host), + "--port", + str(port), + ] + # Start process and verify running after 5 seconds + p = subprocess.Popen(command) + time.sleep(5) + assert p.poll() is None, "Failed to start server" + print(f"Server started on {host}:{port} with PID {p.pid}") + + +# Stop server +@cli.command() +@click.option( + "--server-port", "-p", help="Port of the server", required=False, default=12345 +) +def stop_server(server_port): + """Stop the server""" + # Find the process using the port and kill it + if os.name == "nt": + # Query for the process ID + pid = subprocess.run( + f"netstat -aon | findstr {server_port}", shell=True, stdout=subprocess.PIPE + ) + if pid.returncode != 0: + print("Server not running") + return + pid = pid.stdout.decode().split(" ")[-1] + # Kill the process + subprocess.run(f"taskkill /F /PID {pid}", shell=True) + else: + # Query for the process ID + pid = subprocess.run( + f"lsof -t -i:{server_port}", shell=True, stdout=subprocess.PIPE + ) + if pid.returncode != 0: + print("Server not running") + return + pid = pid.stdout.decode().strip() + print(f"Server found on port {server_port} with PID {pid}") + # Kill the process + subprocess.run(f"kill -9 {pid}", shell=True) + + print(f"Server on port {server_port} stopped") diff --git a/bench/hittite/hmct2220.py b/bench/hittite/hmct2220.py index e962290..3ac3b8e 100644 --- a/bench/hittite/hmct2220.py +++ b/bench/hittite/hmct2220.py @@ -1,6 +1,7 @@ import logging import pyvisa + from bench.common import Common, check_connected hmct2220_logger = logging.getLogger(__name__) diff --git a/bench/keysight/__init__.py b/bench/keysight/__init__.py index d99e115..f07521a 100644 --- a/bench/keysight/__init__.py +++ b/bench/keysight/__init__.py @@ -1,2 +1,3 @@ +from .dwta import utils from .e36233a import E36233A from .n9040b import N9040B diff --git a/bench/keysight/dwta/__init__.py b/bench/keysight/dwta/__init__.py new file mode 100644 index 0000000..a7769eb --- /dev/null +++ b/bench/keysight/dwta/__init__.py @@ -0,0 +1,3 @@ +from .utils import data_to_iq_datafile + +supported_devices = ["Pluto", "ad9081", "ad9084"] diff --git a/bench/keysight/dwta/data_capture.py b/bench/keysight/dwta/data_capture.py new file mode 100644 index 0000000..40e944f --- /dev/null +++ b/bench/keysight/dwta/data_capture.py @@ -0,0 +1,47 @@ +"""Keysight DWTA data capture module.""" + +import adi + +from ..dwta import supported_devices +from .utils import data_to_iq_datafile + + +def capture_iq_datafile( + filename: str, device_name: str, channel: int, samples: int, uri: str, **kwargs +) -> None: + """Capture IQ data to a file. + + Args: + filename: The filename to write to. + device_name: The device name. + channel: The channel to capture data from. + samples: The number of samples to capture. + uri: The URI of the device. + *args: Additional arguments. + **kwargs: Additional keyword arguments. + """ + # Checks + assert ( + device_name in supported_devices + ), f"Device not supported: {device_name}.\n Supported devices: {supported_devices}" + assert samples > 0, "Number of samples must be greater than 0" + if "ip:" not in uri and "usb:" not in uri: + raise ValueError(f"URI must start with 'ip:' or 'usb:'. Got: {uri}") + + # Create device + device = getattr(adi, device_name)(uri) + + # Assume kwargs are attributes to set + for key, value in kwargs.items(): + print(f"Setting {key} to {value}") + if not hasattr(device, key): + raise AttributeError(f"Device does not have attribute: {key}") + setattr(device, key, value) + + # Capture data + device.rx_enabled_channels = [channel] + device.rx_buffer_size = samples + data = device.rx() + + # Write data to file + data_to_iq_datafile(device, data, filename, device_check=False) diff --git a/bench/keysight/dwta/utils.py b/bench/keysight/dwta/utils.py new file mode 100644 index 0000000..a83ddf1 --- /dev/null +++ b/bench/keysight/dwta/utils.py @@ -0,0 +1,57 @@ +""""Utilities for the Keysight DWTA.""" + +import os +import subprocess +from typing import List, Union + +import adi +import numpy as np + + +def data_to_iq_datafile( + device, data: np.ndarray, filename: str, device_check: bool = True +) -> None: + """Write data to a file in IQ data format. + + Args: + device: Device object from pyadi-iio library. + data: The data to write. + filename: The filename to write to. + device_check: Check if specific class is supported. Default is True. + """ + # Checks + assert data.dtype == np.complex128, "Data must be complex" + assert device._complex_data, "Device does not support complex data" + if device_check: + supported_devices = ["Pluto", "ad9081"] + assert any( + dev in device.__class__.__name__ for dev in supported_devices + ), f"Device not supported. Supported devices: {supported_devices}" + + # Get sample rate and carrier frequencies + if hasattr(device, "sample_rate"): + sample_rate = device.sample_rate + elif hasattr(device, "rx_sample_rate"): + sample_rate = device.rx_sample_rate + else: + raise AttributeError("Device does not have sample rate attribute") + + if type(device) in [adi.Pluto]: + center_frequency = int(device.rx_lo) # FIXME + elif type(device) in [adi.ad9081, adi.ad9084]: + channel = device.rx_enabled_channels[0] + f1 = device.rx_channel_nco_frequencies + f2 = device.rx_main_nco_frequencies + center_frequency = f1[channel] + f2[channel] + else: + raise NotImplementedError("Center frequency not implemented for this device") + + assert device._complex_data, "Device does not support complex data" + + with open(filename, "w") as f: + f.write(f"SampleRate={sample_rate}\n") + f.write(f"CenterFrequency={center_frequency}\n") + for d in data: + f.write(f"{d.real},{d.imag}\n") + + print(f"Data written to {filename}") diff --git a/bench/keysight/e36233a.py b/bench/keysight/e36233a.py index f06a3dc..69ea935 100644 --- a/bench/keysight/e36233a.py +++ b/bench/keysight/e36233a.py @@ -1,6 +1,7 @@ import logging import pyvisa + from bench.common import Common, check_connected diff --git a/bench/keysight/n9040b.py b/bench/keysight/n9040b.py index 216254d..68e13f4 100644 --- a/bench/keysight/n9040b.py +++ b/bench/keysight/n9040b.py @@ -4,6 +4,7 @@ from typing import Union import pyvisa + from bench.common import Common diff --git a/bench/plugin.py b/bench/plugin.py index f52ac66..e8621e2 100644 --- a/bench/plugin.py +++ b/bench/plugin.py @@ -2,9 +2,10 @@ import logging import os -import bench import pytest import yaml + +import bench from bench.common import Common as bcom p_logger = logging.getLogger("PYBENCH-PLUGGIN") diff --git a/bench/rs/sma100a.py b/bench/rs/sma100a.py index 92f73a7..4940c90 100644 --- a/bench/rs/sma100a.py +++ b/bench/rs/sma100a.py @@ -1,6 +1,7 @@ import logging import pyvisa + from bench.common import Common diff --git a/bench/web/app.py b/bench/web/app.py new file mode 100644 index 0000000..867f3df --- /dev/null +++ b/bench/web/app.py @@ -0,0 +1,110 @@ +"""Web backend for the bench""" + +import os +import threading +from typing import List, Union + +import adi +import numpy as np +import uvicorn +from fastapi import FastAPI, Request, Response +from fastapi.responses import HTMLResponse +from fastapi.templating import Jinja2Templates +from pydantic import BaseModel + +from bench.keysight.dwta.data_capture import supported_devices + + +class SharedState: + def __init__(self): + self.buffer = None + self.device = None + + +state = SharedState() + + +def read_state(prop): + global state + return getattr(state, prop) + + +def write_state(prop, value): + global state + setattr(state, prop, value) + + +class BufferWrite(BaseModel): + uri: str + device: str + channel: int + data_filename: str + do_scaling: bool + cycle: bool + data_complex: bool + properties: List[str] + + +app = FastAPI() + + +@app.post("/clearbuffer") +async def clearbuffer(): + write_state("buffer", None) + write_state("device", None) + return {"status": "ok"} + + +@app.post("/writebuffer") +async def writebuffer(bufferwrite: BufferWrite): + # Checks + if bufferwrite.device not in supported_devices: + return { + "status": f"Device not supported: {bufferwrite.device}. Supported devices: {supported_devices}" + } + + # Create device + device = getattr(adi, bufferwrite.device)(bufferwrite.uri) + device.tx_enabled_channels = [bufferwrite.channel] + for prop in bufferwrite.properties: + key, value = prop.split("=") + if not hasattr(device, key): + return {"status": f"Device does not have attribute: {key}"} + if value.isdigit(): + value = int(value) + setattr(device, key, value) + + # Read data from file + # CSV file where first two rows are sample rate and center frequency + # Rest of the rows are IQ data in format: I, Q + with open(bufferwrite.data_filename, "r") as f: + sample_rate = int(f.readline().split("=")[1].replace("\n", "")) + center_frequency = int(float(f.readline().split("=")[1].replace("\n", ""))) + i_list = [] + q_list = [] + for line in f: + i, q = line.split(",") + i = float(i) + q = float(q) + i_list.append(int(i)) + q_list.append(int(q)) + complex_data = np.array(i_list) + 1j * np.array(q_list) + + if type(device) in [adi.Pluto]: + device.sample_rate = sample_rate + device.tx_lo = center_frequency + elif type(device) in [adi.ad9081, adi.ad9084]: + assert device.tx_sample_rate == sample_rate, "Sample rate mismatch" + + # Write data to buffer + device.tx_cyclic_buffer = bufferwrite.cycle + device.tx(complex_data) + + # Save device state + write_state("device", device) + + return {"status": "ok"} + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/bench/web/iq_data.csv b/bench/web/iq_data.csv new file mode 100644 index 0000000..b90a875 --- /dev/null +++ b/bench/web/iq_data.csv @@ -0,0 +1,1026 @@ +SampleRate=1000000 +CenterFrequency=299804.6875 +16384.0,0.0 +-5043.808502440504,15588.311383556234 +-13278.530736170518,-9597.712096566287 +13219.390317261606,-9679.006955255796 +5139.361634695453,15557.069710836307 +-16383.691575830137,100.5303340917635 +4948.06547364623,-15618.966165163112 +13337.171225902252,9516.055889441015 +-13159.752195778867,9759.937404804054 +-5234.721272889618,-15525.242323234665 +16382.766314932544,-201.05688327326845 +-4852.136152983487,15649.032901521761 +-13395.30957867555,-9434.041408189973 +13099.618617063905,-9840.500398225324 +5329.883826786494,15492.83041903447 +-16381.22425214277,301.57586277675597 +4756.02415213705,-15678.51046063653 +13452.943605614304,9351.671740612006 +-13038.991845111927,9920.692902368499 +-5424.845713569918,-15459.835218525523 +16379.065445518609,-402.08348811946126 +-4659.733089669456,15707.397732693966 +-13510.071136829909,-9268.94998787864 +12977.874162486647,-10000.511898031096 +5519.603357978142,15426.25796395861 +-16376.289976337908,502.57597524609736 +4563.266590884672,-15735.69363010464 +13566.69002150307,9185.879264417157 +-12916.267870234346,10079.954380072953 +-5614.153192439741,-15392.09991949827 +16372.897949095515,-603.0495406713226 +-4466.628287692022,15763.39708754396 +-13622.798127964974,-9102.462697793055 +12854.17528779682,-10159.017357529889 +5708.491657206885,15357.362371175572 +-16368.889491499342,703.5004016220702 +4369.821818468665,-15790.507061992506 +13678.393343776932,9018.703428593211 +-12791.59875292506,10237.697853725029 +-5802.61520048937,-15322.046626839696 +16364.264754465537,-803.9247761805493 +-4272.850827923676,15817.022532774996 +-13733.473575810493,-8934.60461030677 +12728.540621590166,-10315.992906382256 +5896.520278589425,15286.154016108292 +-16359.02391211286,904.3188834253529 +4175.718966960264,-15842.942501598884 +13788.03675032624,8850.169409206414 +-12665.00326789507,10393.899567737182 +-5990.203356033501,-15249.685890318036 +16353.167161756035,-1004.6789435755509 +-4078.429892537873,15868.265992592054 +-13842.080813051243,-8765.401004230134 +12600.98908398508,-10471.41490464822 +6083.6609057069,15212.643622473166 +-16346.694723898416,1105.0011781313701 +3980.987267535166,-15892.992052339387 +13895.603729257335,8680.302586860073 +-12536.500479958333,10548.535998706384 +-6176.889408986129,-15175.028607193957 +16339.606842223646,-1205.2818100171496 +-3883.394760611448,15917.119749918813 +-13948.603483836601,-8594.877361004137 +12471.539883774176,-10625.259946346254 +6269.88535586987,15136.842260664824 +-16331.903783586451,1305.51706372401 +3785.656046070121,-15940.64817693599 +14001.07808137873,8509.12854287301 +-12406.109741162034,10701.58385895492 +-6362.645245113931,-15098.086020579864 +16323.585838002635,-1405.7031654513025 +-3687.7748037183214,15963.576447558997 +-14053.025546244533,-8423.05936086162 +12340.212515530402,-10777.504862979502 +6455.16558436048,15058.76134608979 +-16314.653318638104,1505.8363432493863 +3589.754718729727,-15985.903698551348 +14104.443922641203,8336.673055426227 +-12273.850687872278,10853.020100037464 +-6547.442890271253,-15018.869717746285 +16305.106561797247,-1605.9128271597851 +-3491.5994815049103,16007.629089304719 +-14155.331274696284,-8249.9728789618 +12207.026756672654,-10928.126727023158 +6639.4736886578385,14978.412637446609 +-16294.945926910024,1705.928849359907 +3393.312787533075,-16028.751801870429 +14205.685686529263,8162.962095681787 +-12139.743237815392,11002.821916213834 +-6731.254514613116,-14937.391628376774 +16284.171796518594,-1805.8806443030453 +-3294.8983372526977,16049.271040990285 +-14255.505262325232,-8075.643981492597 +12072.002664486636,-11077.102855378187 +6822.781912640014,14895.80823495497 +-16272.784576262877,1905.7644488606138 +3196.359835912207,-16069.186034126535 +14304.78812640532,7988.021823871876 +-12003.807587080686,11150.966747880839 +-6914.052436784153,-14853.664022772264 +16260.784694865224,-2005.5765024642874 +-3097.7009934304847,16088.496031490942 +-14353.532423297547,-7900.098921744337 +11935.160573103663,-11224.410812787986 +7005.062650761885,14810.960578534428 +-16248.172604114437,2105.313047246199 +2998.9255242567297,-16107.200306073104 +14401.73631780669,7811.878585357546 +-11866.064207076844,11297.432284972094 +-7095.809128090515,-14767.699510001798 +16234.948778848668,-2204.9703281813477 +-2900.037147232443,16125.298153667482 +-14449.39799508336,-7723.364136157311 +11796.521090439355,-11370.02841521601 +7186.288452215618,14723.882445929554 +-16221.113716937405,2304.544593229895 +2801.0395854486715,-16142.788892900431 +14496.515660692568,7634.5589066622 +-11726.533841449584,11442.196470317125 +-7276.497216642204,-14679.511036005193 +16206.667939262914,-2404.0320934770407 +-2701.9365661076617,16159.671865255505 +-14543.08754068061,-7545.466240339321 +11656.105095089191,-11513.93373318762 +7366.43202506086,14634.58695078743 +-16191.611989700625,2503.4290832741717 +2602.7318203820787,-16175.946435098336 +14589.111881642315,7456.089491477621 +-11585.237502960028,11585.237502960761 +-7456.089491478543,-14589.111881641844 +16175.94643509832,-2602.731820382182 +-2503.4290832740685,16191.611989700641 +-14634.586950787687,-7366.4320250603505 +11513.933733187214,-11656.105095089593 +7545.466240339827,14543.087540680348 +-16159.671865255412,2701.936566108224 +2404.0320934760166,-16206.667939263065 +14679.511036005653,7276.497216641275 +-11442.19647031605,11726.533841450631 +-7634.558906662292,-14496.51566069252 +16142.788892900413,-2801.0395854487742 +-2304.5445932284083,16221.113716937616 +-14723.882445930212,-7186.2884522142695 +11370.028415216604,-11796.521090438782 +7723.364136157403,14449.39799508331 +-16125.298153667381,2900.037147233004 +2204.9703281803218,-16234.948778848808 +14767.699510002247,7095.8091280895815 +-11297.432284971681,11866.064207077237 +-7811.8785853580475,-14401.736317806417 +16107.200306072915,-2998.9255242577474 +-2105.3130472447106,16248.17260411463 +-14810.96057853487,-7005.0626507609495 +11224.41081278791,-11935.160573103734 +7900.098921744428,14353.532423297498 +-16088.496031490922,3097.700993430587 +2005.576502463722,-16260.784694865293 +14853.664022772506,6914.052436783636 +-11150.96674788042,12003.807587081074 +-7988.021823872375,-14304.788126405041 +16069.186034126424,-3196.3598359127664 +-1905.764448859123,16272.784576263051 +-14895.8082349554,-6822.781912639072 +11077.10285537811,-12072.002664486705 +8075.643981493498,14255.505262324721 +-16049.271040990265,3294.8983372528 +1805.8806443020162,-16284.171796518709 +14937.391628377009,6731.254514612597 +-11002.821916213412,12139.743237815774 +-8162.962095682282,-14205.68568652898 +16028.75180187031,-3393.3127875336327 +-1705.9288493584138,16294.94592691018 +-14978.41263744684,-6639.473688657317 +10928.12672702308,-12207.026756672725 +8249.972878962695,14155.331274695764 +-16007.629089304697,3491.599481505012 +1605.9128271587545,-16305.106561797349 +15018.869717746327,6547.442890271158 +-10853.020100036687,12273.850687872964 +-8336.673055427118,-14104.443922640676 +15985.903698551223,-3589.754718730283 +-1505.8363432478914,16314.653318638242 +-15058.761346090016,-6455.1655843599565 +10777.504862979073,-12340.212515530779 +8423.05936086211,14053.02554624424 +-15963.576447558973,3687.774803718423 +1405.7031654507348,-16323.585838002684 +15098.086020580266,6362.645245112977 +-10701.583858954136,12406.10974116271 +-8509.128542873696,-14001.078081378311 +15940.648176935912,-3785.6560460704495 +-1305.5170637229778,16331.903783586533 +-15136.842260664953,-6269.885355869558 +10625.259946346176,-12471.539883774243 +8594.877361004226,13948.603483836547 +-15917.119749918458,3883.3947606129063 +1205.2818100165812,-16339.606842223688 +15175.028607194261,6176.889408985386 +-10548.535998705947,12536.5004799587 +-8680.302586860753,-13895.603729256909 +15892.992052339248,-3980.987267535719 +-1105.001178130337,16346.694723898485 +-15212.643622473119,-6083.660905707019 +10471.41490464814,-12600.989083985145 +8765.401004230222,13842.080813051187 +-15868.265992591798,4078.429892538876 +1004.6789435752145,-16353.167161756055 +15249.685890318498,5990.203356032321 +-10393.899567736922,12665.003267895283 +-8850.169409206894,-13788.036750325933 +15842.942501598502,-4175.7189669617155 +-904.3188834247837,16359.02391211289 +-15286.154016108581,-5896.520278588677 +10315.992906381633,-12728.540621590671 +8934.604610306662,13733.473575810562 +-15817.022532774727,4272.850827924675 +803.9247761804452,-16364.264754465543 +15322.046626840063,5802.615200488402 +-10237.69785372404,12791.598752925851 +-9018.703428593493,-13678.393343776746 +15790.507061992168,-4369.821818469887 +-703.5004016217333,16368.889491499356 +-15357.36237117577,-5708.491657206351 +10159.01735752935,-12854.175287797245 +9102.462697792851,13622.798127965109 +-15763.397087543806,4466.628287692571 +603.049540671451,-16372.89794909551 +15392.099919498545,5614.1531924389865 +-10079.95438007232,12916.26787023484 +-9185.879264417918,-13566.690021502553 +15735.693630104353,-4563.266590885666 +-502.5759752458768,16376.289976337916 +-15426.257963958684,-5519.603357977935 +10000.511898030829,-12977.874162486853 +9268.949987879014,13510.071136829652 +-15707.397732693837,4659.73308966989 +402.0834881179605,-16379.065445518645 +15459.83521852575,5424.845713569271 +-9920.692902367951,13038.991845112341 +-9351.671740612666,-13452.943605613846 +15678.510460636278,-4756.024152137873 +-301.5758627749058,16381.224252142803 +-15492.830419034464,-5329.883826786505 +9840.50039822524,-13099.618617063967 +9434.041408190868,13395.30957867492 +-15649.03290152168,4852.136152983753 +201.0568832720001,-16382.76631493256 +15525.242323234792,5234.721272889244 +-9759.937404804414,13159.7521957786 +-9516.055889441432,-13337.171225901953 +15618.966165163212,-4948.065473645914 +-100.53033409014589,16383.691575830147 +-15557.069710836253,-5139.361634695617 +9679.006955254385,-13219.39031726264 +9597.712096567015,13278.530736169992 +-15588.311383555936,5043.808502441423 +-1.0355875733818267e-09,-16384.0 +15588.311383556287,5043.808502440339 +-9597.712096565336,13278.530736171206 +-9679.006955256056,-13219.390317261415 +15557.069710836187,-5139.361634695815 +100.53033409221702,16383.691575830135 +-15618.966165163276,-4948.0654736457145 +9516.055889440504,-13337.171225902615 +9759.93740480533,13159.75219577792 +-15525.242323234725,5234.721272889441 +-201.05688327313987,-16382.766314932545 +15649.032901522016,4852.1361529826645 +-9434.041408189936,13395.309578675577 +-9840.500398226151,-13099.618617063283 +15492.830419034095,-5329.8838267875835 +301.57586277790773,16381.224252142749 +-15678.51046063688,-4756.024152135891 +9351.671740610966,-13452.943605615028 +9920.692902369601,13038.991845111088 +-15459.835218525064,5424.845713571225 +-402.08348812096204,-16379.065445518572 +15707.397732693897,4659.73308966969 +-9268.949987878841,13510.07113682977 +-10000.511898030994,-12977.874162486725 +15426.257963958613,-5519.6033579781315 +502.57597524608525,16376.289976337908 +-15735.693630105188,-4563.266590882783 +9185.879264416973,-13566.690021503193 +10079.954380074687,12916.267870232992 +-15392.099919498154,5614.153192440058 +-603.049540669798,-16372.89794909557 +15763.397087544117,4466.628287691474 +-9102.462697792678,13622.798127965225 +-10159.017357530245,-12854.175287796537 +15357.362371175373,-5708.49165720742 +703.5004016228721,16368.889491499307 +-15790.507061992721,-4369.821818467891 +9018.70342859254,-13678.393343777374 +10237.697853725656,12791.598752924558 +-15322.04662683867,5802.6152004920805 +-803.9247761815836,-16364.264754465486 +15817.022532774781,4272.850827924473 +-8934.604610305707,13733.473575811184 +-10315.992906381796,-12728.540621590539 +15286.154016107836,-5896.5202785906085 +904.318883424992,16359.02391211288 +-15842.942501599267,-4175.718966958812 +8850.169409205151,-13788.036750327052 +10393.899567738523,12665.00326789397 +-15249.685890317402,5990.203356035116 +-1004.6789435754226,-16353.167161756042 +15868.265992592082,4078.429892537772 +-8765.401004230045,13842.0808130513 +-10471.4149046483,-12600.989083985012 +15212.64362247304,-6083.660905707213 +1105.0011781314743,16346.694723898408 +-15892.992052339525,-3980.9872675346137 +8680.302586858206,-13895.6037292585 +10548.53599870682,12536.500479957966 +-15175.02860719383,6176.889408986442 +-1205.281810017718,-16339.606842223604 +15917.119749918507,3883.3947606127035 +-8594.877361003255,13948.603483837143 +-10625.259946347043,-12471.539883773505 +15136.842260664516,-6269.885355870611 +1305.5170637231856,16331.903783586517 +-15940.648176936607,-3785.656046067528 +8509.128542871926,-14001.078081379388 +10701.583858955704,12406.10974116136 +-15098.086020579462,6362.645245114885 +-1405.7031654509426,-16323.585838002666 +15963.57644755923,3687.7748037173124 +-8423.059360860332,14053.025546245304 +-10777.504862980632,-12340.212515529416 +15058.761346089934,-6455.165584360148 +1505.8363432490264,16314.653318638138 +-15985.903698551676,-3589.754718728262 +8336.673055424533,-14104.443922642204 +10853.020100037542,12273.85068787221 +-15018.869717746244,6547.44289027135 +-1605.9128271598888,-16305.106561797238 +16007.62908930474,3491.5994815048084 +-8249.972878961711,14155.331274696337 +-10928.126727023237,-12207.026756672585 +14978.412637446378,-6639.47368865836 +1705.9288493586212,16294.945926910159 +-16028.751801870932,-3393.3127875306955 +8162.962095681293,-14205.685686529549 +11002.821916214258,12139.743237815008 +-14937.391628376541,6731.254514613635 +-1805.8806443022233,-16284.171796518685 +16049.271040990494,3294.898337251683 +-8075.643981491696,14255.505262325743 +-11077.10285537895,-12072.002664485935 +14895.808234955313,-6822.7819126392615 +1905.764448860255,16272.78457626292 +-16069.186034126828,-3196.359835910735 +7988.021823870566,-14304.788126406052 +11150.966747880573,12003.807587080932 +-14853.664022772417,6914.052436783825 +-2005.5765024657774,-16260.78469486504 +16088.496031490962,3097.7009934303824 +-7900.098921742613,14353.532423298497 +-11224.41081278806,-11935.16057310359 +14810.960578534383,-7005.06265076198 +2105.313047247688,16248.172604114245 +-16107.200306073464,-2998.9255242547956 +7811.878585357045,-14401.73631780696 +11297.432284972507,11866.064207076452 +-14767.699510001752,7095.809128090608 +-2204.970328181451,-16234.948778848653 +16125.298153667583,2900.037147231882 +-7723.364136156397,14449.39799508385 +-11370.028415216755,-11796.521090438637 +14723.882445930121,-7186.288452214457 +2304.544593232303,16221.113716937063 +-16142.788892900608,-2801.039585447651 +7634.558906661284,-14496.51566069305 +11442.196470317533,11726.533841449185 +-14679.51103600556,7276.497216641463 +-2404.0320934780652,-16206.667939262761 +16159.671865255752,2701.936566106181 +-7545.466240338402,14543.087540681086 +-11513.93373318703,-11656.105095089773 +14634.586950787385,-7366.432025060953 +2503.4290832761153,16191.611989700325 +-16175.946435098649,-2602.731820380137 +7456.089491477943,-14589.111881642151 +11585.237502960505,11585.237502960284 +-14589.111881641162,7456.08949147988 +-2602.7318203822847,-16175.946435098303 +16191.611989700941,2503.429083272125 +-7366.432025060673,14634.586950787525 +-11656.105095089993,-11513.933733186808 +14543.087540679227,-7545.466240341986 +2701.9365661101638,16159.671865255086 +-16206.66793926308,-2404.0320934759134 +7276.497216641183,-14679.511036005699 +11726.533841450704,11442.196470315976 +-14496.515660692037,7634.558906663208 +-2801.0395854497947,-16142.788892900237 +16221.11371693763,2304.544593228305 +-7186.288452214176,14723.882445930258 +-11796.521090438855,-11370.02841521653 +14449.397995082823,-7723.364136158316 +2900.0371472340235,16125.298153667198 +-16234.948778848946,-2204.9703281792954 +7095.809128090326,-14767.699510001888 +11866.064207076666,11297.432284972281 +-14401.736317805924,7811.878585358958 +-2998.9255242569343,-16107.200306073066 +16248.172604114763,2105.3130472436833 +-7005.062650761697,14810.960578534517 +-11935.160573103805,-11224.410812787833 +14353.532423296549,-7900.098921746151 +3097.7009934325183,16088.496031490551 +-16260.784694865306,-2005.5765024636185 +6914.052436783541,-14853.66402277255 +12003.807587082412,11150.96674787898 +-14304.78812640499,7988.021823872466 +-3196.359835912868,-16069.186034126404 +16272.784576262957,1905.7644488599442 +-6822.781912638977,14895.808234955444 +-12072.002664486146,-11077.10285537872 +14255.505262323752,-8075.643981495209 +3294.898337253814,16049.271040990056 +-16284.17179651872,-1805.8806443019125 +6731.254514611653,-14937.391628377434 +12139.743237816469,11002.821916212646 +-14205.685686528464,8162.9620956831795 +-3393.312787534646,-16028.751801870096 +16294.945926910192,1705.9288493583101 +-6639.473688658074,14978.412637446505 +-12207.026756674037,-10928.126727021616 +14155.331274695242,-8249.97287896359 +3491.599481506934,16007.629089304279 +-16305.106561797269,-1605.9128271595775 +6547.442890267648,-15018.869717747859 +12273.85068787365,10853.020100035912 +-14104.443922641096,8336.673055426405 +-3589.754718732202,-15985.903698550792 +16314.653318638166,1505.836343248715 +-6455.165584359861,15058.761346090057 +-12340.212515532072,-10777.50486297759 +14053.025546243229,-8423.059360863796 +3687.774803719432,15963.57644755874 +-16323.585838002693,-1405.7031654506309 +6362.6452451111645,-15098.08602058103 +12406.10974116278,10701.583858954056 +-14001.078081378259,8509.128542873785 +-3785.656046071457,-15940.648176935674 +16331.903783586542,1305.517063722874 +-6269.885355870323,15136.842260664636 +-12471.539883774914,-10625.259946345386 +13948.603483836003,-8594.877361005107 +3883.3947606130077,15917.119749918433 +-16339.606842223628,-1205.281810017406 +6176.889408984426,-15175.02860719465 +12536.500479959366,10548.535998705156 +-13895.603729257347,8680.30258686005 +-3980.9872675367237,-15892.992052338996 +16346.694723898428,1105.001178131162 +-6083.660905705193,15212.64362247385 +-12600.989083986404,-10471.414904646626 +13842.080813050135,-8765.401004231884 +4078.4298925380754,15868.265992592003 +-16353.167161756062,-1004.6789435751103 +5990.203356031357,-15249.685890318879 +12665.00326789535,10393.899567736842 +-13788.036750325877,8850.169409206981 +-4175.718966960916,-15842.942501598713 +16359.023912112896,904.3188834246796 +-5896.5202785885795,15286.15401610862 +-12728.540621591908,-10315.992906380105 +13733.473575809998,-8934.60461030753 +4272.850827924775,15817.0225327747 +-16364.264754465685,-803.9247761775504 +5802.615200488304,-15322.0466268401 +12791.598752925916,10237.697853723957 +-13678.393343776175,9018.703428594357 +-4369.821818469988,-15790.50706199214 +16368.889491499322,703.5004016225597 +-5708.491657205381,15357.362371176132 +-12854.175287797887,-10159.017357528537 +13622.798127964017,-9102.462697794486 +4466.628287691775,15763.397087544032 +-16372.89794909565,-603.0495406676241 +5614.153192438014,-15392.0999194989 +12916.267870234331,10079.954380072972 +-13566.690021501972,9185.879264418774 +-4563.266590884872,-15735.693630104583 +16376.289976337976,502.5759752439108 +-5519.603357976082,15426.257963959346 +-12977.874162488053,-10000.511898029272 +13510.071136829592,-9268.9499878791 +4659.7330896699905,15707.397732693807 +-16379.06544551867,-402.0834881169252 +5424.845713567414,-15459.835218526401 +13038.991845112405,9920.69290236787 +-13452.943605613787,9351.671740612752 +-4756.02415213619,-15678.51046063679 +16381.224252142823,301.57586277387037 +-5329.883826785526,15492.830419034803 +-13099.618617064589,-9840.500398224412 +13395.309578675933,-9434.04140818943 +4852.136152986522,15649.03290152082 +-16382.766314932584,-201.05688327003335 +5234.721272888262,-15525.242323235123 +13159.752195778661,9759.93740480433 +-13337.171225902433,9516.055889440759 +-4948.065473649564,-15618.966165162057 +16383.691575830147,100.53033409004162 +-5139.361634693749,15557.069710836871 +-13219.390317261601,-9679.006955255803 +13278.530736169385,-9597.712096567855 +5043.808502442409,15588.311383555618 +-16384.0,2.0711751467636534e-09 +5043.80850244024,-15588.31138355632 +13278.53073617072,9597.712096566007 +-13219.390317259154,9679.006955259147 +-5139.361634697682,-15557.06971083557 +16383.691575830133,-100.53033409232128 +-4948.065473645615,15618.966165163307 +-13337.171225903758,-9516.055889438903 +13159.752195778414,-9759.937404804665 +5234.721272892188,15525.242323233799 +-16382.766314932533,201.0568832741754 +4852.136152984344,-15649.032901521496 +13395.309578676173,9434.041408189089 +-13099.6186170621,9840.500398227725 +-5329.883826787682,-15492.83041903406 +16381.224252142747,-301.575862778012 +-4756.0241521340095,15678.510460637452 +-13452.943605615088,-9351.67174061088 +13038.991845112152,-9920.6929023682 +5424.845713571323,15459.83521852503 +-16379.065445518614,402.0834881192042 +4659.733089667805,-15707.397732694455 +13510.071136830882,9268.949987877219 +-12977.874162486662,10000.511898031076 +-5519.603357978229,-15426.257963958578 +16376.289976337848,-502.57597524805124 +-4563.266590882683,15735.693630105217 +-13566.690021503251,-9185.879264416888 +12916.267870232929,-10079.95438007477 +5614.153192443656,15392.099919496843 +-16372.89794909543,603.049540673625 +4466.628287691374,-15763.397087544145 +13622.798127966318,9102.462697791043 +-12854.175287796474,10159.017357530327 +-5708.491657209263,-15357.362371174688 +16368.889491499303,-703.5004016229764 +-4369.821818465995,15790.507061993245 +-13678.39334377743,-9018.703428592455 +12791.598752923328,-10237.697853727192 +5802.615200490436,15322.046626839292 +-16364.26475446539,803.9247761835481 +4272.850827922575,-15817.022532775294 +13733.473575810225,8934.60461030718 +-12728.540621589302,10315.992906383324 +-5896.520278588969,-15286.154016108469 +16359.02391211277,-904.3188834269558 +-4175.718966960513,15842.942501598818 +-13788.036750327108,-8850.169409205064 +12665.003267895085,-10393.899567737164 +5990.203356035213,15249.685890317363 +-16353.167161756035,1004.6789435755267 +4078.429892535867,-15868.265992592571 +13842.080813053348,8765.401004226811 +-12600.989083983755,10471.414904649811 +-6083.660905707309,-15212.643622473002 +16346.694723898276,-1105.0011781334365 +-3980.987267530899,15892.992052340454 +-13895.603729258555,-8680.302586858117 +12536.500479957898,-10548.535998706899 +6176.889408984813,15175.028607194494 +-16339.60684222387,1205.2818100141067 +3883.3947606089832,-15917.119749919415 +13948.6034838372,8594.877361003166 +-12471.539883774645,10625.259946345705 +-6269.885355870708,-15136.842260664476 +16331.903783586213,-1305.517063727003 +-3785.656046069239,15940.6481769362 +-14001.078081378475,-8509.128542873428 +12406.10974116129,-10701.583858955782 +6362.645245113265,15098.086020580144 +-16323.585838002497,1405.703165452902 +3687.774803715396,-15963.576447559672 +14053.025546245359,8423.059360860243 +-12340.212515530571,10777.504862979307 +-6455.1655843619565,-15058.761346089159 +16314.653318637786,-1505.8363432528397 +-3589.7547187281607,15985.9036985517 +-14104.443922641309,-8336.673055426047 +12273.850687868438,-10853.020100041806 +6547.44289027486,15018.869717744714 +-16305.106561797045,1605.9128271618463 +3491.5994815047065,-16007.629089304764 +14155.33127469545,8249.97287896323 +-12207.026756672516,10928.126727023313 +-6639.473688660158,-14978.412637445581 +16294.945926909953,-1705.9288493605775 +-3393.312787534238,16028.751801870183 +-14205.6856865296,-8162.962095681203 +12139.743237813687,-11002.821916215715 +6731.254514613731,14937.391628376497 +-16284.171796518674,1805.880644302327 +3294.8983372515813,-16049.271040990516 +14255.505262326713,8075.643981489985 +-12072.002664485864,11077.102855379027 +-6822.781912642743,-14895.80823495372 +16272.784576262691,-1905.7644488622084 +-3196.3598359088055,16069.186034127211 +-14304.788126406102,-7988.021823870475 +12003.807587078325,-11150.96674788338 +6914.052436785608,14853.664022771587 +-16260.784694865255,2005.5765024640323 +3097.7009934284506,-16088.496031491333 +14353.532423297649,7900.098921744154 +-11935.160573104797,11224.41081278678 +-7005.062650762074,-14810.96057853434 +16248.17260411423,-2105.3130472477915 +-2998.9255242565246,16107.200306073142 +-14401.7363178079,-7811.878585355316 +11866.064207076379,-11297.432284972583 +7095.809128089024,14767.699510002514 +-16234.948778848639,2204.9703281815546 +2900.037147229946,-16125.29815366793 +14449.397995083898,7723.364136156305 +-11796.521090439857,11370.028415215489 +-7186.288452219572,-14723.882445927624 +16221.113716937572,-2304.544593228718 +-2801.0395854475482,16142.788892900626 +-14496.515660692232,-7634.558906662839 +11726.533841449113,-11442.196470317607 +7276.497216644894,14679.51103600386 +-16206.667939262747,2404.0320934781685 +2701.936566107915,-16159.671865255463 +14543.087540679418,7545.466240341616 +-11656.105095087081,11513.933733189755 +-7366.43202506271,-14634.586950786499 +16191.611989700594,-2503.4290832743777 +-2602.731820380034,16175.946435098665 +-14589.111881643894,-7456.089491474533 +11585.237502958893,-11585.237502961896 +7456.089491481632,14589.111881640267 +-16175.946435098584,2602.731820380549 +2503.4290832738625,-16191.611989700674 +14634.586950790084,7366.432025055589 +-11513.933733186734,11656.105095090066 +-7545.466240342079,-14543.087540679178 +16159.671865255377,-2701.9365661084294 +-2404.0320934739675,16206.667939263369 +-14679.5110360074,-7276.497216637751 +11442.196470314568,-11726.53384145208 +7634.558906663301,14496.515660691988 +-16142.788892900537,2801.039585448062 +2304.544593228202,-16221.113716937647 +14723.88244593112,7186.288452212408 +-11370.028415215113,11796.52109044022 +-7723.36413616005,-14449.397995081896 +16125.29815366718,-2900.0371472341258 +-2204.9703281773463,16234.948778849212 +-14767.69951000274,-7095.809128088554 +11297.432284972205,-11866.064207076739 +7811.87858535905,14401.736317805873 +-16107.200306073048,2998.925524257037 +2105.31304724358,-16248.172604114776 +14810.960578536155,7005.062650758235 +-11224.410812789114,11935.160573102601 +-7900.098921747874,-14353.5324232956 +16088.496031490531,-3097.7009934326206 +-2005.5765024635148,16260.784694865319 +-14853.664022773379,-6914.052436781758 +11150.966747880268,-12003.807587081215 +7988.021823874183,14304.788126404032 +-16069.186034126384,3196.3598359129705 +1905.7644488579906,-16272.784576263184 +14895.808234955488,6822.781912638882 +-11077.102855375897,12072.002664488735 +-8075.643981493679,-14255.50526232462 +16049.27104099041,-3294.898337252092 +-1805.8806443018088,16284.17179651873 +-14937.391628378242,-6731.254514609859 +11002.821916212568,-12139.74323781654 +8162.962095684885,14205.685686527484 +-16028.751801870845,3393.3127875311034 +1705.9288493600588,-16294.945926910008 +14978.412637448811,6639.47368865287 +-10928.126727022925,12207.026756672863 +-8249.972878963681,-14155.331274695189 +16007.629089304653,-3491.599481505216 +-1605.91282715762,16305.106561797462 +-15018.8697177479,-6547.442890267553 +10853.020100035834,-12273.850687873719 +8336.673055426496,14104.443922641043 +-15985.903698551585,3589.754718728669 +1505.8363432449016,-16314.653318638519 +15058.761346090832,6455.165584358053 +-10777.504862978914,12340.212515530915 +-8423.059360863885,-14053.025546243174 +15963.576447557878,-3687.774803723163 +-1405.7031654486711,16323.585838002862 +-15098.086020581793,-6362.645245109352 +10701.583858955388,-12406.10974116163 +8509.128542873874,14001.078081378204 +-15940.64817693608,3785.656046069746 +1305.5170637227698,-16331.903783586551 +15136.8422606661,6269.885355866784 +-10625.259946345308,12471.539883774984 +-8594.877361006782,-13948.603483834971 +15917.119749917525,-3883.394760616728 +-1205.281810017302,16339.606842223635 +-15175.02860719469,-6176.88940898433 +10548.5359987065,-12536.500479958235 +8680.302586861719,13895.603729256305 +-15892.992052338517,3980.987267538632 +1105.0011781291996,-16346.694723898561 +15212.643622473197,6083.660905706825 +-10471.414904646546,12600.98908398647 +-8765.401004233545,-13842.080813049082 +15868.265992591514,-4078.4298925399803 +-1004.6789435750063,16353.167161756068 +-15249.685890318917,-5990.20335603126 +10393.899567736762,-12665.003267895416 +8850.169409208636,13788.036750324814 +-15842.942501597736,4175.7189669646195 +904.3188834264354,-16359.0239121128 +15286.154016109997,5896.520278585006 +-10315.992906380025,12728.540621591976 +-8934.604610307617,-13733.47357580994 +15817.022532774186,-4272.850827926674 +-803.9247761793067,16364.2647544656 +-15322.046626840796,-5802.615200486464 +10237.697853723876,-12791.598752925982 +9018.70342859289,13678.393343777143 +-15790.507061992112,4369.821818470088 +703.5004016187337,-16368.889491499485 +15357.362371176168,5708.4916572052825 +-10159.017357529918,12854.175287796796 +-9102.462697794574,-13622.798127963959 +15763.397087542988,-4466.628287695459 +-603.0495406693813,16372.897949095586 +-15392.099919499575,-5614.153192436166 +10079.95438007436,-12916.267870233249 +9185.879264417319,13566.690021502958 +-15735.693630102998,4563.266590890339 +502.57597524566836,-16376.289976337921 +15426.25796395938,5519.603357975984 +-10000.511898030663,12977.87416248698 +-9268.949987880722,-13510.07113682848 +15707.397732692718,-4659.733089673662 +-402.08348811682094,16379.065445518672 +-15459.835218525819,-5424.845713569074 +9920.692902369268,-13038.991845111339 +9351.671740612837,13452.943605613727 +-15678.510460635678,4756.024152139856 +301.5758627756284,-16381.22425214279 +15492.830419035441,5329.883826783666 +-9840.500398221351,13099.618617066888 +-9434.041408192561,-13395.309578673729 +15649.032901521341,-4852.136152984842 +-201.0568832736541,16382.76631493254 +-15525.242323235156,-5234.721272888163 +9759.937404804246,-13159.752195778723 +9516.055889442361,13337.171225901291 +-15618.966165162024,4948.0654736496635 +100.53033409366257,-16383.691575830126 +15557.069710837488,5139.361634691882 +-9679.006955251212,13219.390317264964 +-9597.712096566429,-13278.530736170416 +15588.311383555585,-5043.808502442508 +3.1279499629904453e-10,16384.0 +-15588.311383556926,-5043.808502438368 +9597.712096562904,-13278.530736172965 +9679.006955257728,13219.390317260193 +-15557.069710836124,5139.3616346960125 +-100.53033409428815,-16383.691575830122 +15618.966165164464,4948.065473641965 +-9516.055889438818,13337.17122590382 +-9759.937404804748,-13159.752195778352 +15525.242323233766,-5234.721272892286 +201.05688327427964,16382.76631493253 +-15649.03290152263,-4852.136152980686 +9434.041408185958,-13395.309578678378 +9840.500398224829,13099.618617064276 +-15492.830419032814,5329.883826791303 +-301.5758627762539,-16381.22425214278 +15678.51046063694,4756.024152135692 +-9351.671740609265,13452.94360561621 +-9920.692902369767,-13038.99184511096 +15459.835218524378,-5424.84571357318 +402.08348812117055,16379.065445518567 +-15707.397732693957,-4659.73308966949 +9268.949987877133,-13510.071136830942 +10000.51189803411,12977.874162484324 +-15426.257963957916,5519.6033579800815 +-502.5759752462937,-16376.289976337901 +15735.693630105246,4563.266590882583 +-9185.879264413716,13566.690021505397 +-10079.954380074852,-12916.267870232865 +15392.099919496806,-5614.153192443753 +603.0495406700064,16372.897949095563 +-15763.397087544174,-4466.628287691273 +9102.462697790956,-13622.798127966376 +10159.017357530409,12854.175287796408 +-15357.362371174651,5708.491657209361 +-703.5004016230805,-16368.889491499298 +15790.507061993272,4369.821818465895 +-9018.703428589257,13678.393343779539 +-10237.697853724365,-12791.59875292559 +15322.046626839256,-5802.615200490533 +803.9247761799315,16364.264754465568 +-15817.022532775321,-4272.850827922474 +8934.60461030397,-13733.473575812313 +10315.992906383404,12728.540621589236 +-15286.154016108432,5896.520278589066 +-904.3188834307796,-16359.02391211256 +15842.942501599795,4175.71896695681 +-8850.169409204975,13788.036750327165 +-10393.899567737244,-12665.00326789502 +15249.685890315963,-5990.203356038777 +1004.6789435756307,16353.16716175603 +-15868.265992592596,-4078.429892535766 +8765.401004226722,-13842.080813053404 +10471.414904647027,12600.989083986069 +-15212.64362247158,6083.660905710865 +-1105.0011781372575,-16346.694723898017 +15892.992052339576,3980.9872675344113 +-8680.30258685803,13895.60372925861 +-10548.535998706979,-12536.500479957833 +15175.02860719305,-6176.88940898836 +1205.2818100216411,16339.606842223315 +-15917.11974991944,-3883.394760608882 +8594.877361003078,-13948.603483837254 +10625.259946348619,12471.53988377216 +-15136.842260664436,6269.885355870804 +-1305.517063727107,-16331.903783586204 +15940.648176936225,3785.6560460691376 +-8509.128542870156,14001.078081380463 +-10701.583858955863,-12406.109741161223 +15098.086020578656,-6362.645245116794 +1405.7031654492946,16323.585838002808 +-15963.576447558857,-3687.774803718924 +8423.059360856958,-14053.025546247327 +10777.504862979387,12340.212515530504 +-15058.761346089117,6455.165584362052 +-1505.8363432529436,-16314.653318637776 +15985.903698551723,3589.754718728059 +-8336.67305542275,14104.443922643257 +-10853.020100039093,-12273.850687870838 +15018.869717746162,-6547.442890271541 +1605.91282716195,16305.106561797034 +-16007.629089304786,-3491.5994815046047 +8249.972878959921,-14155.33127469738 +10928.126727023391,12207.026756672447 +-14978.412637445539,6639.473688660253 +-1705.9288493643862,-16294.945926909555 +16028.751801870976,3393.3127875304913 +-8162.962095681112,14205.685686529652 +-11002.821916213032,-12139.74323781612 +14937.391628376454,-6731.254514613825 +1805.8806443061333,16284.171796518252 +-16049.271040990536,-3294.898337251479 +8075.643981489894,-14255.505262326764 +11077.102855376359,12072.002664488313 +-14895.808234953676,6822.781912642838 +-1905.7644488660121,-16272.784576262246 +16069.186034126506,3196.359835912357 +-7988.021823870384,14304.788126406153 +-11150.966747886185,-12003.807587075718 +14853.664022771543,-6914.052436785702 +2005.576502467833,16260.784694864788 +-16088.496031491353,-3097.7009934283483 +7900.098921744062,-14353.532423297698 +11224.410812792285,11935.16057309962 +-14810.9605785327,7005.062650765536 +-2105.3130472478947,-16248.172604114217 +16107.200306073162,2998.925524256422 +-7811.878585355225,14401.736317807949 +-11297.432284972658,-11866.064207076308 +14767.699510000855,-7095.8091280924755 +2204.970328185349,16234.948778848124 +-16125.29815366729,-2900.03714723351 +7723.364136152928,-14449.397995085703 +11370.028415215564,11796.521090439785 +-14723.882445929212,7186.288452216319 +-2304.5445932325097,-16221.113716937034 +16142.788892900644,2801.0395854474455 +-7634.558906659451,14496.515660694016 +-11442.196470320348,-11726.533841446439 +14679.511036005468,-7276.497216641649 +2404.0320934782712,16206.66793926273 +-16159.671865256094,-2701.936566104138 +7545.466240338217,-14543.087540681183 +11513.93373318983,11656.105095087009 +-14634.586950786454,7366.4320250628025 +-2503.4290832781626,-16191.611989700008 +16175.946435098682,2602.731820379931 +-7456.08949147444,14589.111881643941 +-11585.237502959335,-11585.237502961454 +14589.111881641915,-7456.089491478408 +2602.7318203843297,16175.946435097974 +-16191.611989700688,-2503.4290832737597 +7366.4320250588235,-14634.586950788456 +11656.105095092758,11513.933733184009 +-14543.087540679131,7545.466240342172 +-2701.9365661122065,-16159.671865254746 +16206.667939262838,2404.0320934775496 +-7276.497216640995,14679.511036005792 +-11726.533841452152,-11442.196470314493 +14496.515660691939,-7634.558906663393 +2801.039585451835,16142.788892899882 +-16221.113716937662,-2304.5445932280986 +7186.288452215662,-14723.882445929532 +11796.521090442877,11370.028415212357 +-14449.397995081847,7723.364136160142 +-2900.0371472342285,-16125.298153667161 +16234.948778848724,2204.9703281809343 +-7095.809128085102,14767.699510004399 +-11866.064207079378,-11297.43228496943 +14401.736317805824,-7811.878585359142 +2998.925524260802,16107.200306072345 +-16248.17260411431,-2105.3130472471707 +7005.062650758141,-14810.960578536198 +11935.160573107776,11224.410812783612 +-14353.532423297347,7900.098921744701 +-3097.7009934327234,-16088.496031490511 +16260.784694865331,2005.5765024634113 +-6914.052436781663,14853.664022773422 +-12003.807587083822,-11150.966747877463 +14304.78812640398,-7988.021823874274 +3196.359835913073,16069.186034126364 +-16272.78457626363,-1905.764448854187 +6822.781912638788,-14895.808234955532 +12072.002664488806,11077.10285537582 +-14255.505262324568,8075.64398149377 +-3294.898337255843,-16049.271040989639 +16284.171796518744,1805.8806443017052 +-6731.254514609764,14937.391628378286 +-12139.743237816609,-11002.821916212491 +14205.685686529288,-8162.962095681745 +3393.3127875384944,16028.75180186928 +-16294.945926910019,-1705.9288493599552 +6639.4736886561805,-14978.412637447344 +12207.026756675417,10928.126727020071 +-14155.331274695136,8249.97287896377 +-3491.5994815089575,-16007.629089303837 +16305.106561797837,1605.9128271538088 +-6547.442890270871,15018.869717746453 +-12273.850687873788,-10853.020100035756 +14104.44392264099,-8336.673055426585 +3589.7547187324058,15985.903698550746 +-16314.653318638528,-1505.8363432447977 +6455.165584357957,-15058.761346090872 +12340.212515533434,10777.504862976031 +-14053.025546243121,8423.059360863974 +-3687.774803719635,-15963.576447558693 +16323.585838002551,1405.7031654522789 +-6362.6452451092555,15098.086020581834 +-12406.109741164131,-10701.583858952488 +14001.07808137815,-8509.128542873963 +3785.656046073472,15940.648176935196 +-16331.903783586262,-1305.5170637263793 +6269.885355866688,-15136.84226066614 +12471.539883777466,10625.259946342392 +-13948.60348383687,8594.877361003699 +-3883.39476061321,-15917.119749918384 +16339.60684222419,1205.2818100097677 +-6176.889408984233,15175.02860719473 +-12536.5004799607,-10548.53599870357 +13895.60372925625,-8680.302586861808 +3980.9872675351194,15892.992052339398 +-16346.69472389882,-1105.0011781253788 +6083.66090570327,-15212.643622474618 +12600.989083986537,10471.414904646466 +-13842.08081305102,8765.401004230485 +-4078.4298925400813,-15868.265992591487 +16353.167161756302,1004.6789435711839 +-5990.203356031163,15249.685890318955 +-12665.003267897846,-10393.8995677338 +13788.03675032677,-8850.16940920559 +4175.71896696472,15842.94250159771 +-16359.02391211301,-904.3188834226116 +5896.520278588385,-15286.154016108694 +12728.540621594386,10315.992906377049 +-13733.473575809883,8934.604610307704 +-4272.850827926775,-15817.02253277416 +16364.264754465787,803.9247761754817 +-5802.615200489851,15322.046626839514 +-12791.598752928374,-10237.697853720887 +13678.393343777087,-9018.703428592977 +4369.821818470189,15790.507061992084 +-16368.889491499649,-703.5004016149076 +5708.491657205185,-15357.362371176205 +12854.175287799171,10159.017357526913 +-13622.79812796597,9102.462697791563 +-4466.628287695559,-15763.397087542959 +16372.897949095726,603.0495406655543 +-5614.153192439568,15392.099919498334 +-12916.267870235604,-10079.95438007134 +13566.690021504988,-9185.879264414321 +4563.266590886861,15735.693630104006 +-16376.28997633804,-502.57597524184064 +5519.603357979394,-15426.257963958162 +12977.874162489317,10000.511898027631 +-13510.071136826313,9268.94998788388 +-4659.733089670191,-15707.397732693747 +16379.065445518767,402.08348811299254 +-5424.845713568976,15459.835218525854 +-13038.991845113658,-9920.692902366221 +13452.943605609415,-9351.67174061904 +4756.0241521363905,15678.51046063673 +-16381.224252142862,-301.5758627717995 +5329.883826787091,-15492.830419034264 +13099.618617064714,9840.500398224247 +-13395.309578671522,9434.041408195691 +-4852.136152984942,-15649.03290152131 +16382.766314932585,201.05688326982485 +-5234.721272891595,15525.242323233999 +-13159.752195781006,-9759.93740480117 +13337.171225899068,-9516.055889445477 +4948.065473646212,15618.966165163118 +-16383.691575830171,-100.53033408610787 +5139.3616346917825,-15557.06971083752 +13219.390317262825,9679.006955254134 +-13278.530736168172,9597.712096569532 +-5043.808502439063,-15588.3113835567 diff --git a/bench/web/test_data_send.py b/bench/web/test_data_send.py new file mode 100644 index 0000000..8cf6321 --- /dev/null +++ b/bench/web/test_data_send.py @@ -0,0 +1,60 @@ +# flake8: noqa +import os +import time + +import numpy as np +import requests + +# Generate some data +fs = int(1e6) +N = 1024 +fc = int(300000 / (fs / N)) * (fs / N) +ts = 1 / float(fs) +t = np.arange(0, N * ts, ts) +i = np.cos(2 * np.pi * t * fc) * 2 ** 14 +q = np.sin(2 * np.pi * t * fc) * 2 ** 14 +iq = i + 1j * q + +# Create CSV file +filename = "iq_data.csv" +with open(filename, "w") as f: + f.write(f"SampleRate={fs}\n") + f.write(f"CenterFrequency={fc}\n") + for i, q in zip(i, q): + f.write(f"{i},{q}\n") + + +# Send post request to localhost +url = "http://localhost:8000/writebuffer" +# uri: str +# device: str +# channel: int +# data_filename: str +# do_scaling: bool +# cycle: bool +# data_complex: bool +# properties: List[str] + +file_location = os.path.dirname(os.path.realpath(__file__)) + +data = { + "uri": "ip:pluto.local", + "device": "Pluto", + "channel": 0, + "data_filename": os.path.join(file_location, filename), + "do_scaling": False, + "cycle": True, + "data_complex": True, + "properties": ["sample_rate=" + str(fs)], +} +r = requests.post(url, json=data) +print(f"Status: {r.status_code}") +print(r.json()) + +for _ in range(10): + print(".", end="") + time.sleep(1) +print() +url = "http://localhost:8000/clearbuffer" +r = requests.post(url) +print(f"Status: {r.status_code}") diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..7799a7e --- /dev/null +++ b/cli.py @@ -0,0 +1,4 @@ +"""pyinstaller entry point for IIO-Tools CLI""" +from bench.cli import iiotools + +iiotools.cli() diff --git a/doc/source/cli.md b/doc/source/cli.md index b738729..5d8e3ba 100644 --- a/doc/source/cli.md +++ b/doc/source/cli.md @@ -10,6 +10,14 @@ There are two command line tools available: - [`pybenchiio`](#pybenchiiocli) - A command line tool for interfacing with libiio devices. - [`pybench`](#pybenchcli) - A command line tool for querying VISA based instruments. +## Keysight DMX + +One of the main use cases for the CLI pybench tools is to support the Keysight Device Manager eXpert (DMX) software. The DMX software is a tool for managing and configuring Keysight instruments. The `pybench` CLI tool provides a way for the DMX software to communicate with pybench instruments and devices. + +Since the DMX software uses single commands to perform data capture and data generation this required additional infrastructure specifically for IIO based systems. IIO based systems do not maintain persistent buffer when leveraging custom data vectors through DMA channels. Essentially, when the contexts are closed the buffers clear and the IIO based system will revert back to the DDS data generation state. To solve this problem a backend server was implemented to maintain these buffers that is controlled by the `pybenchiio` CLI tool. See the [pybenchiio](#pybenchiiocli) section for more information. + + +## Reference APIs (pybenchiiocli)= ```{eval-rst} diff --git a/doc/source/conf.py b/doc/source/conf.py index 39d05c1..726881f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -41,6 +41,8 @@ exclude_patterns = [] remove_from_toctrees = ["instruments/bench.common.rst"] +# Keysight blocks curl requests +linkcheck_ignore = [r"https://www.keysight.com/.*", r"https://keysight.com/.*"] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/pyproject.toml b/pyproject.toml index e05613f..20fa9ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,8 @@ pybenchiio = "bench.cli.iiotools:cli" pybench = "bench.cli.visatools:cli" [project.optional-dependencies] -cli = ["click", "pylibiio>=0.23.1"] +cli = ["click", "pyadi-iio>=0.0.17", "requests"] +web = ["fastapi[standard]", "uvicorn", "pydantic", "jinja2", "starlette"] [project.entry-points.pytest11] pybench = "bench.plugin" @@ -72,7 +73,7 @@ ignore_missing_imports="true" [tool.pytest.ini_options] minversion = "6.0" -# addopts = "--custom-hw-map=test/emu/hardware_map.yml --emu-xml-dir=test/emu/devices" +addopts = "--adi-hw-map" testpaths = [ "tests", ] diff --git a/requirements_dev.txt b/requirements_dev.txt index 6d86a1a..f302b1e 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -8,7 +8,7 @@ scapy scipy pytest-cov coveralls -# pytest-libiio>=0.0.18 +pytest-libiio>=0.0.18 bump2version pytest-html==3.2.0 plotly-express diff --git a/setup.cfg b/setup.cfg index a0273c5..d5fba04 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,3 +4,7 @@ max-line-length = 88 max-complexity = 18 select = B,C,E,F,W,T4 exclude = test/*,examples/*,doc/*,images/* + +[tool:isort] +profile = black +skip_glob=bench/web/app.py diff --git a/tests/ref_data/test_iq.csv b/tests/ref_data/test_iq.csv new file mode 100644 index 0000000..07a4151 --- /dev/null +++ b/tests/ref_data/test_iq.csv @@ -0,0 +1,1026 @@ +SampleRate=30720000 +CenterFrequency=1000000000 +-90.0,73.0 +-135.0,2.0 +-47.0,-2.0 +-48.0,-16.0 +-102.0,149.0 +-61.0,94.0 +-5.0,-63.0 +70.0,-48.0 +132.0,-46.0 +45.0,142.0 +14.0,103.0 +136.0,-14.0 +122.0,-83.0 +-12.0,-78.0 +-141.0,75.0 +-69.0,42.0 +5.0,0.0 +-40.0,123.0 +-38.0,136.0 +-79.0,55.0 +-188.0,21.0 +-123.0,-4.0 +73.0,45.0 +137.0,-69.0 +-3.0,-9.0 +-101.0,-117.0 +108.0,-51.0 +57.0,71.0 +73.0,18.0 +66.0,25.0 +-3.0,35.0 +35.0,-49.0 +22.0,6.0 +41.0,51.0 +37.0,64.0 +34.0,-79.0 +56.0,-120.0 +156.0,-119.0 +181.0,11.0 +-69.0,-78.0 +-48.0,-121.0 +-71.0,-100.0 +-97.0,-228.0 +107.0,-37.0 +5.0,181.0 +-55.0,14.0 +8.0,-26.0 +-15.0,75.0 +-45.0,62.0 +82.0,111.0 +118.0,-4.0 +-9.0,-46.0 +70.0,12.0 +85.0,70.0 +-18.0,27.0 +2.0,-72.0 +66.0,5.0 +15.0,89.0 +-131.0,-18.0 +14.0,-43.0 +-24.0,107.0 +-124.0,46.0 +-79.0,-63.0 +1.0,27.0 +65.0,8.0 +47.0,-156.0 +47.0,-114.0 +-59.0,-58.0 +-58.0,-60.0 +-57.0,27.0 +98.0,27.0 +237.0,154.0 +-89.0,120.0 +-76.0,-127.0 +59.0,-67.0 +105.0,-19.0 +31.0,63.0 +-54.0,79.0 +-70.0,54.0 +-139.0,20.0 +-93.0,-42.0 +91.0,-52.0 +193.0,24.0 +184.0,107.0 +5.0,23.0 +-27.0,-140.0 +-26.0,-55.0 +-129.0,0.0 +48.0,113.0 +77.0,149.0 +-103.0,107.0 +-149.0,57.0 +-39.0,-32.0 +27.0,-22.0 +-30.0,40.0 +16.0,-36.0 +74.0,-23.0 +76.0,-78.0 +59.0,-33.0 +-51.0,-6.0 +8.0,-79.0 +35.0,-25.0 +75.0,-8.0 +-22.0,4.0 +-26.0,12.0 +-8.0,-54.0 +34.0,-60.0 +79.0,-117.0 +31.0,0.0 +25.0,-19.0 +16.0,-11.0 +-153.0,95.0 +-148.0,-53.0 +77.0,-79.0 +14.0,93.0 +-179.0,-60.0 +-131.0,-88.0 +13.0,-48.0 +-14.0,17.0 +-33.0,27.0 +-29.0,-41.0 +-87.0,-42.0 +1.0,20.0 +214.0,-5.0 +157.0,-41.0 +-15.0,-88.0 +-56.0,-18.0 +-38.0,1.0 +-75.0,80.0 +-138.0,35.0 +-91.0,10.0 +-12.0,-70.0 +29.0,-126.0 +74.0,8.0 +20.0,5.0 +-80.0,59.0 +-146.0,103.0 +-177.0,-14.0 +-38.0,14.0 +-31.0,-24.0 +-26.0,-91.0 +-52.0,-7.0 +-22.0,-15.0 +22.0,-42.0 +0.0,-14.0 +31.0,-81.0 +-13.0,-133.0 +24.0,7.0 +34.0,18.0 +-25.0,-12.0 +-26.0,-58.0 +97.0,72.0 +4.0,195.0 +-18.0,-13.0 +-51.0,3.0 +-48.0,89.0 +29.0,64.0 +61.0,-2.0 +-7.0,-60.0 +88.0,14.0 +-9.0,111.0 +-55.0,14.0 +73.0,-53.0 +34.0,-44.0 +-45.0,-93.0 +1.0,-4.0 +26.0,85.0 +-144.0,0.0 +-31.0,-25.0 +80.0,19.0 +-11.0,16.0 +-69.0,-8.0 +-75.0,-50.0 +44.0,13.0 +142.0,120.0 +-28.0,-60.0 +-30.0,-63.0 +51.0,3.0 +90.0,4.0 +-33.0,92.0 +-96.0,73.0 +42.0,32.0 +153.0,-2.0 +188.0,-45.0 +28.0,76.0 +-73.0,121.0 +-128.0,40.0 +12.0,-28.0 +9.0,8.0 +-61.0,48.0 +88.0,50.0 +111.0,57.0 +-26.0,-7.0 +-30.0,-117.0 +1.0,-78.0 +73.0,138.0 +52.0,138.0 +-55.0,19.0 +-42.0,-24.0 +-32.0,-33.0 +41.0,-151.0 +50.0,-40.0 +-24.0,-3.0 +-5.0,-67.0 +-52.0,-57.0 +70.0,-9.0 +198.0,31.0 +56.0,-26.0 +-67.0,93.0 +-98.0,112.0 +-136.0,-72.0 +-90.0,-56.0 +-13.0,-1.0 +27.0,72.0 +11.0,124.0 +-43.0,131.0 +30.0,73.0 +89.0,16.0 +11.0,-17.0 +-106.0,-38.0 +-88.0,-51.0 +9.0,-26.0 +-9.0,-79.0 +-78.0,28.0 +-6.0,41.0 +63.0,-25.0 +61.0,83.0 +-45.0,107.0 +-47.0,8.0 +-44.0,-131.0 +122.0,-37.0 +90.0,33.0 +-8.0,58.0 +-8.0,45.0 +26.0,46.0 +39.0,-76.0 +100.0,-94.0 +66.0,-23.0 +-79.0,36.0 +-127.0,37.0 +-106.0,-5.0 +-92.0,49.0 +41.0,71.0 +20.0,-17.0 +105.0,-84.0 +39.0,72.0 +-139.0,98.0 +9.0,46.0 +102.0,46.0 +114.0,95.0 +60.0,-127.0 +0.0,-97.0 +-25.0,32.0 +52.0,49.0 +143.0,20.0 +97.0,-12.0 +-32.0,-102.0 +84.0,-18.0 +25.0,44.0 +-177.0,-125.0 +-104.0,-69.0 +-4.0,-131.0 +-31.0,-57.0 +-99.0,-16.0 +-21.0,-30.0 +-23.0,-24.0 +-40.0,69.0 +6.0,38.0 +-24.0,-7.0 +88.0,-97.0 +152.0,-38.0 +51.0,-78.0 +60.0,-43.0 +75.0,123.0 +6.0,-52.0 +53.0,-35.0 +2.0,120.0 +-46.0,157.0 +-79.0,44.0 +50.0,-1.0 +109.0,99.0 +-116.0,-19.0 +-81.0,-99.0 +15.0,-45.0 +26.0,17.0 +-64.0,90.0 +-45.0,8.0 +-67.0,-93.0 +-71.0,-165.0 +26.0,-61.0 +40.0,30.0 +-55.0,-49.0 +19.0,-44.0 +38.0,144.0 +-78.0,48.0 +6.0,-113.0 +124.0,-133.0 +8.0,24.0 +-68.0,31.0 +103.0,47.0 +9.0,31.0 +-119.0,-41.0 +-72.0,-169.0 +25.0,-126.0 +74.0,0.0 +114.0,-77.0 +78.0,-98.0 +69.0,-25.0 +40.0,21.0 +15.0,-75.0 +136.0,-12.0 +25.0,51.0 +-135.0,4.0 +-83.0,-10.0 +-87.0,32.0 +-139.0,42.0 +90.0,43.0 +51.0,-72.0 +-46.0,-142.0 +8.0,-11.0 +87.0,51.0 +47.0,-30.0 +-55.0,-123.0 +-7.0,-84.0 +-73.0,-142.0 +16.0,-79.0 +-83.0,-24.0 +-80.0,-208.0 +41.0,-172.0 +38.0,-17.0 +-21.0,-12.0 +-104.0,26.0 +-23.0,101.0 +34.0,26.0 +30.0,36.0 +-40.0,-21.0 +-105.0,-1.0 +81.0,-45.0 +-34.0,-61.0 +-120.0,-47.0 +44.0,71.0 +43.0,27.0 +-7.0,74.0 +94.0,53.0 +61.0,41.0 +-58.0,59.0 +-111.0,-46.0 +-57.0,-112.0 +-62.0,-33.0 +-152.0,-80.0 +-101.0,-145.0 +-43.0,-137.0 +34.0,-75.0 +157.0,-71.0 +115.0,55.0 +-1.0,-83.0 +68.0,-194.0 +-16.0,-126.0 +-112.0,-94.0 +28.0,-25.0 +-42.0,37.0 +-119.0,30.0 +-25.0,-76.0 +-10.0,-146.0 +-34.0,-106.0 +11.0,20.0 +36.0,-54.0 +4.0,-46.0 +75.0,-3.0 +126.0,95.0 +-99.0,70.0 +-89.0,41.0 +84.0,86.0 +-31.0,2.0 +-9.0,-46.0 +60.0,-5.0 +-12.0,52.0 +-40.0,34.0 +60.0,7.0 +11.0,87.0 +11.0,-21.0 +-17.0,-46.0 +-33.0,108.0 +61.0,-26.0 +-41.0,-9.0 +-100.0,-66.0 +-70.0,-31.0 +0.0,30.0 +59.0,-2.0 +9.0,19.0 +-9.0,41.0 +-21.0,94.0 +63.0,-36.0 +88.0,21.0 +-2.0,123.0 +-25.0,118.0 +50.0,119.0 +-27.0,39.0 +-164.0,-24.0 +-50.0,-167.0 +121.0,-66.0 +22.0,86.0 +-40.0,117.0 +78.0,46.0 +15.0,-119.0 +-14.0,-94.0 +-37.0,-1.0 +-4.0,18.0 +29.0,53.0 +-54.0,10.0 +-96.0,-61.0 +23.0,-56.0 +-7.0,-112.0 +91.0,-42.0 +55.0,19.0 +-70.0,-17.0 +-13.0,-33.0 +70.0,137.0 +-51.0,118.0 +-33.0,-10.0 +-25.0,-62.0 +-138.0,95.0 +-199.0,170.0 +-37.0,75.0 +124.0,70.0 +7.0,-17.0 +-123.0,-56.0 +18.0,19.0 +-42.0,-15.0 +-157.0,-44.0 +10.0,76.0 +-11.0,41.0 +-9.0,-109.0 +172.0,4.0 +18.0,78.0 +-125.0,-18.0 +-70.0,73.0 +-28.0,13.0 +-19.0,-37.0 +44.0,-53.0 +-130.0,-15.0 +-4.0,-61.0 +114.0,-9.0 +-32.0,89.0 +85.0,151.0 +96.0,82.0 +18.0,119.0 +120.0,108.0 +132.0,15.0 +7.0,-26.0 +-24.0,47.0 +-77.0,-5.0 +-48.0,-16.0 +25.0,-84.0 +-89.0,-12.0 +-85.0,21.0 +35.0,-73.0 +43.0,-70.0 +-104.0,61.0 +-75.0,72.0 +-14.0,83.0 +-56.0,-54.0 +-38.0,-98.0 +-38.0,-69.0 +86.0,-25.0 +24.0,106.0 +-64.0,56.0 +-27.0,-35.0 +42.0,-75.0 +85.0,-56.0 +118.0,-93.0 +39.0,-59.0 +24.0,-9.0 +70.0,-108.0 +103.0,-146.0 +86.0,-11.0 +-46.0,77.0 +-79.0,-16.0 +-34.0,-33.0 +-12.0,44.0 +-3.0,40.0 +8.0,-4.0 +-101.0,-75.0 +-201.0,-36.0 +8.0,-95.0 +112.0,-84.0 +70.0,24.0 +29.0,-37.0 +72.0,114.0 +62.0,66.0 +66.0,-23.0 +38.0,96.0 +14.0,-91.0 +31.0,-2.0 +83.0,103.0 +-31.0,90.0 +-110.0,94.0 +27.0,-78.0 +132.0,-181.0 +-61.0,-33.0 +-161.0,39.0 +-68.0,-27.0 +63.0,-5.0 +-8.0,146.0 +-20.0,84.0 +3.0,-66.0 +-58.0,-3.0 +-32.0,57.0 +69.0,20.0 +34.0,0.0 +-37.0,61.0 +3.0,44.0 +81.0,-39.0 +29.0,-99.0 +95.0,-115.0 +79.0,-83.0 +-3.0,-3.0 +-16.0,-68.0 +-66.0,-117.0 +55.0,-161.0 +23.0,-69.0 +-84.0,-92.0 +-90.0,-69.0 +-14.0,-2.0 +-5.0,-30.0 +-9.0,-72.0 +74.0,-2.0 +0.0,125.0 +-136.0,77.0 +-144.0,-101.0 +-58.0,-98.0 +-44.0,-116.0 +112.0,-48.0 +148.0,-51.0 +4.0,-89.0 +-14.0,48.0 +36.0,6.0 +120.0,-29.0 +105.0,166.0 +3.0,55.0 +36.0,-118.0 +104.0,-93.0 +88.0,-28.0 +-7.0,21.0 +-96.0,-23.0 +-62.0,-54.0 +32.0,53.0 +91.0,155.0 +169.0,57.0 +167.0,25.0 +57.0,-143.0 +100.0,-171.0 +-15.0,-35.0 +-105.0,-43.0 +56.0,-71.0 +100.0,-109.0 +54.0,-17.0 +-14.0,65.0 +-11.0,0.0 +37.0,-34.0 +-12.0,-67.0 +-30.0,-92.0 +-79.0,-66.0 +-77.0,-70.0 +-114.0,-50.0 +-27.0,-20.0 +82.0,21.0 +74.0,67.0 +-46.0,-46.0 +-45.0,-18.0 +32.0,-10.0 +63.0,-38.0 +24.0,-33.0 +-29.0,-24.0 +-19.0,-56.0 +85.0,22.0 +31.0,97.0 +-8.0,-20.0 +-24.0,-77.0 +27.0,12.0 +-47.0,1.0 +3.0,-72.0 +127.0,-18.0 +39.0,28.0 +-84.0,3.0 +-8.0,-147.0 +114.0,-198.0 +-72.0,68.0 +-133.0,28.0 +-118.0,-118.0 +-85.0,-73.0 +56.0,-38.0 +83.0,-58.0 +96.0,-24.0 +93.0,58.0 +-42.0,88.0 +-132.0,-9.0 +-157.0,50.0 +-66.0,-28.0 +-126.0,-60.0 +-178.0,-30.0 +-134.0,29.0 +-2.0,94.0 +26.0,67.0 +22.0,-90.0 +77.0,-110.0 +94.0,44.0 +64.0,18.0 +98.0,109.0 +-20.0,110.0 +43.0,91.0 +145.0,90.0 +-83.0,20.0 +-131.0,-233.0 +152.0,-193.0 +94.0,-53.0 +-41.0,-100.0 +4.0,52.0 +103.0,69.0 +43.0,15.0 +-45.0,-39.0 +-74.0,-41.0 +-9.0,-20.0 +170.0,-49.0 +64.0,-14.0 +-31.0,-112.0 +-33.0,-33.0 +-82.0,-6.0 +-76.0,14.0 +-226.0,6.0 +-51.0,-1.0 +111.0,-42.0 +-14.0,84.0 +-81.0,187.0 +-41.0,106.0 +65.0,27.0 +87.0,79.0 +-59.0,19.0 +-66.0,-61.0 +-61.0,11.0 +-40.0,77.0 +-94.0,143.0 +-69.0,107.0 +3.0,53.0 +18.0,-40.0 +-20.0,-10.0 +-47.0,-46.0 +97.0,-80.0 +102.0,49.0 +-57.0,-56.0 +-59.0,-136.0 +-34.0,-76.0 +19.0,-119.0 +-42.0,65.0 +-115.0,64.0 +99.0,114.0 +59.0,112.0 +-3.0,-82.0 +36.0,-131.0 +-132.0,-11.0 +-129.0,-128.0 +70.0,-153.0 +98.0,-30.0 +-67.0,-4.0 +-86.0,64.0 +-2.0,45.0 +19.0,-6.0 +-36.0,66.0 +-36.0,90.0 +56.0,18.0 +80.0,-47.0 +41.0,-109.0 +33.0,-79.0 +67.0,-71.0 +18.0,-38.0 +-42.0,18.0 +17.0,-31.0 +18.0,2.0 +18.0,21.0 +-18.0,-57.0 +-70.0,15.0 +-161.0,25.0 +15.0,-36.0 +43.0,16.0 +-20.0,-71.0 +20.0,-73.0 +28.0,17.0 +-6.0,63.0 +5.0,-57.0 +88.0,-15.0 +114.0,-63.0 +83.0,-59.0 +-94.0,-56.0 +-139.0,-99.0 +29.0,-124.0 +114.0,-39.0 +39.0,62.0 +-88.0,59.0 +-49.0,-19.0 +119.0,-12.0 +64.0,-31.0 +57.0,-5.0 +28.0,60.0 +123.0,118.0 +-59.0,97.0 +-172.0,25.0 +-39.0,13.0 +-26.0,9.0 +-105.0,-34.0 +-30.0,-64.0 +-4.0,-74.0 +77.0,-27.0 +21.0,131.0 +-30.0,92.0 +85.0,93.0 +25.0,84.0 +-164.0,71.0 +-145.0,-69.0 +103.0,-64.0 +49.0,86.0 +-26.0,-151.0 +-161.0,-213.0 +-32.0,-26.0 +142.0,45.0 +75.0,107.0 +112.0,39.0 +25.0,-61.0 +43.0,-116.0 +65.0,0.0 +-14.0,134.0 +3.0,90.0 +-63.0,58.0 +-88.0,80.0 +-221.0,56.0 +-42.0,27.0 +-10.0,-3.0 +-174.0,-8.0 +-79.0,86.0 +-14.0,62.0 +-88.0,-5.0 +-78.0,-34.0 +-151.0,-45.0 +-42.0,-45.0 +89.0,23.0 +206.0,75.0 +120.0,48.0 +-41.0,-38.0 +79.0,-55.0 +40.0,30.0 +-58.0,45.0 +-73.0,-42.0 +5.0,-6.0 +25.0,18.0 +41.0,38.0 +-48.0,24.0 +91.0,55.0 +169.0,-13.0 +85.0,14.0 +-59.0,82.0 +-77.0,-77.0 +31.0,-175.0 +10.0,-109.0 +-53.0,-62.0 +-40.0,-90.0 +25.0,-79.0 +64.0,-34.0 +-16.0,89.0 +-87.0,39.0 +-41.0,62.0 +-16.0,-20.0 +114.0,-123.0 +44.0,1.0 +-13.0,85.0 +-88.0,9.0 +-22.0,11.0 +17.0,64.0 +-32.0,8.0 +-21.0,-47.0 +73.0,24.0 +30.0,165.0 +36.0,63.0 +-3.0,86.0 +84.0,115.0 +61.0,-80.0 +33.0,-69.0 +81.0,54.0 +23.0,84.0 +-42.0,16.0 +30.0,137.0 +68.0,-36.0 +64.0,-174.0 +89.0,-29.0 +-50.0,32.0 +85.0,48.0 +107.0,66.0 +-26.0,-109.0 +-5.0,-142.0 +49.0,63.0 +60.0,78.0 +42.0,32.0 +-23.0,13.0 +-66.0,60.0 +-49.0,89.0 +-14.0,-20.0 +44.0,12.0 +40.0,111.0 +16.0,56.0 +80.0,49.0 +52.0,113.0 +10.0,5.0 +91.0,-80.0 +100.0,63.0 +102.0,128.0 +109.0,187.0 +11.0,131.0 +6.0,-67.0 +109.0,-47.0 +141.0,48.0 +100.0,97.0 +-22.0,100.0 +-96.0,-62.0 +-46.0,-47.0 +-51.0,-44.0 +-68.0,21.0 +1.0,0.0 +39.0,119.0 +-15.0,67.0 +67.0,-133.0 +106.0,-5.0 +70.0,99.0 +65.0,55.0 +-1.0,40.0 +5.0,-4.0 +79.0,29.0 +98.0,50.0 +48.0,122.0 +-40.0,61.0 +-64.0,-86.0 +52.0,-142.0 +58.0,-66.0 +68.0,79.0 +-80.0,18.0 +-100.0,-80.0 +52.0,81.0 +57.0,89.0 +9.0,-50.0 +3.0,-90.0 +31.0,-20.0 +64.0,59.0 +-127.0,36.0 +-139.0,-86.0 +46.0,-131.0 +139.0,50.0 +96.0,69.0 +-12.0,20.0 +11.0,8.0 +36.0,119.0 +-103.0,-23.0 +0.0,-53.0 +-51.0,111.0 +-101.0,68.0 +36.0,-54.0 +-55.0,17.0 +-191.0,105.0 +-99.0,111.0 +46.0,94.0 +3.0,33.0 +24.0,128.0 +92.0,61.0 +45.0,-81.0 +-15.0,-120.0 +-15.0,-20.0 +-2.0,6.0 +7.0,-45.0 +66.0,-60.0 +109.0,-19.0 +14.0,-9.0 +-61.0,-28.0 +-76.0,52.0 +-132.0,35.0 +-184.0,-69.0 +8.0,-73.0 +-21.0,22.0 +49.0,43.0 +127.0,85.0 +-70.0,136.0 +-21.0,-33.0 +11.0,-177.0 +-4.0,26.0 +-35.0,83.0 +-12.0,47.0 +60.0,39.0 +-65.0,-7.0 +-75.0,-44.0 +148.0,9.0 +137.0,79.0 +21.0,31.0 +40.0,-36.0 +-25.0,-40.0 +-133.0,-18.0 +-36.0,-45.0 +18.0,-18.0 +37.0,18.0 +62.0,19.0 +25.0,-65.0 +86.0,-127.0 +112.0,-49.0 +19.0,1.0 +-96.0,60.0 +-113.0,-24.0 +-129.0,4.0 +-167.0,117.0 +-13.0,41.0 +25.0,-44.0 +-46.0,-152.0 +-10.0,-2.0 +-56.0,16.0 +49.0,-57.0 +12.0,-38.0 +12.0,-73.0 +174.0,66.0 +144.0,48.0 +-2.0,-12.0 +15.0,-35.0 +69.0,71.0 +-53.0,-66.0 +-43.0,-95.0 +13.0,3.0 +-104.0,22.0 +-108.0,100.0 +-13.0,73.0 +-19.0,-34.0 +-91.0,-1.0 +-125.0,34.0 +-10.0,38.0 +99.0,-13.0 +37.0,33.0 +-58.0,31.0 +-57.0,73.0 +34.0,-63.0 +125.0,4.0 +-25.0,-4.0 +-49.0,20.0 +-38.0,48.0 +1.0,19.0 +56.0,64.0 +-20.0,-82.0 +-37.0,-111.0 +52.0,-28.0 +13.0,5.0 +-110.0,-27.0 +-171.0,48.0 +-36.0,8.0 +35.0,18.0 +-91.0,4.0 +-109.0,-26.0 +-65.0,51.0 +43.0,65.0 +69.0,51.0 +25.0,6.0 +8.0,11.0 +33.0,89.0 +55.0,136.0 +-24.0,9.0 +-49.0,-106.0 +9.0,-87.0 +186.0,-111.0 +77.0,176.0 +-48.0,92.0 +-8.0,-89.0 +-129.0,-34.0 +-144.0,46.0 +40.0,-67.0 +34.0,-4.0 +-63.0,-53.0 +-17.0,20.0 +-30.0,111.0 +-110.0,-19.0 +-28.0,-50.0 +104.0,99.0 +-16.0,80.0 +-54.0,-15.0 +59.0,32.0 +65.0,91.0 +8.0,12.0 +49.0,-26.0 +64.0,-77.0 +18.0,-36.0 +-59.0,2.0 +-5.0,-3.0 +39.0,71.0 +-49.0,24.0 +34.0,-73.0 +68.0,20.0 +-35.0,31.0 +-123.0,131.0 +-51.0,66.0 +7.0,94.0 +-59.0,104.0 +2.0,-37.0 +-43.0,2.0 +-57.0,49.0 +-1.0,171.0 +-39.0,139.0 +-26.0,13.0 +-55.0,-96.0 +19.0,-15.0 +-59.0,69.0 +-32.0,-11.0 +19.0,-13.0 +1.0,140.0 +3.0,115.0 +23.0,30.0 +-13.0,73.0 +9.0,106.0 +-57.0,50.0 +4.0,-62.0 +80.0,9.0 +50.0,85.0 +-40.0,163.0 +56.0,-104.0 +91.0,-82.0 +25.0,43.0 +138.0,-25.0 diff --git a/tests/test_dwta.py b/tests/test_dwta.py new file mode 100644 index 0000000..6e214ac --- /dev/null +++ b/tests/test_dwta.py @@ -0,0 +1,33 @@ +"""Test the DWTA class.""" + +import os + +import adi +import pytest + +import bench + +hardware = ["pluto", "pluto_rev_c"] + +loc = os.path.dirname(os.path.realpath(__file__)) +ref_data_folder = os.path.join(loc, "ref_data") + + +@pytest.mark.iio_hardware(hardware) +def test_iq_datafile_gen(iio_uri, tmpdir): + """Test the IQ datafile generation.""" + dev = adi.Pluto(iio_uri) + dev.rx_buffer_size = 2 ** 10 + data = dev.rx() + + filename = tmpdir.join("test_iq.csv") + bench.keysight.dwta.utils.data_to_iq_datafile(dev, data, tmpdir.join("test_iq.csv")) + + # Check structure + assert os.path.exists(filename) + assert os.path.getsize(filename) > 0 + with open(filename, "r") as f: + lines = f.readlines() + assert len(lines) == dev.rx_buffer_size + 2 + assert lines[0] == f"SampleRate={dev.sample_rate}\n" + assert lines[1] == f"CenterFrequency={dev.rx_lo}\n"