{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# define hostname\n",
    "HOSTNAME = \"192.168.1.100\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "\n",
    "pyrpl_folder = os.environ[\"pyrpl_path\"]\n",
    "sys.path.insert(0, pyrpl_folder)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyrpl import Pyrpl\n",
    "\n",
    "p = Pyrpl(\n",
    "    config=\"\",  # do not use a configfile\n",
    "    hostname=HOSTNAME,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "p.rp.iq2.setup?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "iq = p.rp.iq2\n",
    "print('Retrieved iq module \"%s\"' % iq.name)\n",
    "\n",
    "# setup the iq module iq2 so that both demodulation quadratures are visible on the scope\n",
    "iq.setup(\n",
    "    input=\"in1\",\n",
    "    amplitude=0.5,\n",
    "    output_direct=\"out1\",\n",
    "    output_signal=\"quadrature\",\n",
    "    frequency=2**14,  # set the frequency to half the demodulation\n",
    "    phase=0,  # tune the phase as necessary\n",
    "    modulation_at_2f=\"off\",\n",
    "    demodulation_at_2f=\"on\",\n",
    "    acbandwidth=500,\n",
    ")\n",
    "\n",
    "scope = p.rp.scope\n",
    "scope.setup(\n",
    "    input1=\"iq2\",\n",
    "    input2=\"iq2_2\",\n",
    "    duration=8,\n",
    "    average=True,\n",
    "    trigger_source=\"immediately\",\n",
    "    rolling_mode=True,\n",
    ")\n",
    "\n",
    "# now you can view the measurement on the scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# possibly tune the demodulation phase or quadrature_factor, or frequency\n",
    "iq.phase = 90\n",
    "iq.quadrature_factor = 100\n",
    "iq.frequency -= 0.1\n",
    "print(iq.frequency)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Continuous low-level readout of the IQ accumulator magnitude and phase"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# How it works:\n",
    "# When iq.frequency is written, the accumulator waits for iq._na_sleepcycles clock cycles (a 8 ns)\n",
    "# and then averages over iq._na_averages clock cycles, the resulting sum being ready in iq._nadata_total\n",
    "print(iq._na_sleepcycles, iq._na_averages, iq._nadata_total)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Example\n",
    "from pyrpl.async_utils import sleep\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "iq._na_sleepcycles = (\n",
    "    0  # we need no sleep cycles, since there is no transient behaviour in our setup\n",
    ")\n",
    "\n",
    "avg_duration = 0.1  # average over 0.1 s\n",
    "iq._na_averages = avg_duration / 8e-9  # set number of averages of accumulator\n",
    "\n",
    "print(\"Sleep for\", iq._na_sleepcycles, \"cycles\")\n",
    "print(\"Average for\", iq._na_averages, \"cycles\\n\")\n",
    "\n",
    "# make a local storage of iq.frquency, amplitude, _na_averages to save the\n",
    "# comminucation time needed to read those values all over again\n",
    "frequency = iq.frequency\n",
    "na_averages = iq._na_averages\n",
    "amplitude = iq.amplitude\n",
    "\n",
    "# Acquisition\n",
    "print(\"Magnitude\\t phase\")\n",
    "for i in range(5):  # acquisition loop, take 5 samples\n",
    "    iq.frequency = frequency  # writing to the frequency register triggers the next averaging run\n",
    "    sleep(na_averages * 8e-9)  # wait for averaging to finish\n",
    "    signal = iq._nadata_total / na_averages  # result is stored in iq._nadata\n",
    "    dB = 20 * np.log10(signal / amplitude)  # conversion in dB w.r.t. drive amplitude\n",
    "    mag = np.abs(signal)  # magnitude\n",
    "    phase = np.angle(signal, deg=True) % 360  # phase in degrees\n",
    "    print(\"%.2e\\t %.1f\" % (mag, phase))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "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": "ipython",
   "version": "3.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
