{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Digital Estimation\n\nConverting a stream of control signals into a estimate samples.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from cbadc.utilities import compute_power_spectral_density\nimport matplotlib.pyplot as plt\nimport cbadc\nimport numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Setting up the Analog System and Digital Control\n\nIn this example, we assume that we have access to a control signal\ns[k] generated by the interactions of an analog system and digital control.\nFurthermore, we assume a chain-of-integrators converter with corresponding\nanalog system and digital control.\n\n<img src=\"file://images/chainOfIntegratorsGeneral.svg\" width=\"500\" align=\"center\" alt=\"The chain of integrators ADC.\">\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Setup analog system and digital control\n\nN = 6\nM = N\nbeta = 6250.\nrho = - 1e-2\nkappa = - 1.0\nA = [[beta * rho, 0, 0, 0, 0, 0],\n     [beta, beta * rho, 0, 0, 0, 0],\n     [0, beta, beta * rho, 0, 0, 0],\n     [0, 0, beta, beta * rho, 0, 0],\n     [0, 0, 0, beta, beta * rho, 0],\n     [0, 0, 0, 0, beta, beta * rho]]\nB = [[beta], [0], [0], [0], [0], [0]]\nCT = np.eye(N)\nGamma = [[kappa * beta, 0, 0, 0, 0, 0],\n         [0, kappa * beta, 0, 0, 0, 0],\n         [0, 0, kappa * beta, 0, 0, 0],\n         [0, 0, 0, kappa * beta, 0, 0],\n         [0, 0, 0, 0, kappa * beta, 0],\n         [0, 0, 0, 0, 0, kappa * beta]]\nGamma_tildeT = np.eye(N)\nT = 1.0/(2 * beta)\n\nanalog_system = cbadc.analog_system.AnalogSystem(A, B, CT, Gamma, Gamma_tildeT)\ndigital_control = cbadc.digital_control.DigitalControl(T, M)\n\n# Summarize the analog system, digital control, and digital estimator.\nprint(analog_system, \"\\n\")\nprint(digital_control)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Creating a Placehold Control Signal\n\nWe could, of course, simulate the analog system and digital control above\nfor a given analog signal. However, this might not always be the use case;\ninstead, imagine we have acquired such a control signal from a previous\nsimulation or possibly obtained it from a hardware implementation.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# In principle, we can create a dummy generator by just\n\n\ndef dummy_control_sequence_signal():\n    while(True):\n        yield np.zeros(M, dtype=np.int8)\n# and then pass dummy_control_sequence_signal as the control_sequence\n# to the digital estimator.\n\n\n# Another way would be to use a random control signal. Such a generator\n# is already provided in the :func:`cbadc.utilities.random_control_signal`\n# function. Subsequently, a random (random 1-0 valued M tuples) control signal\n# of length\n\nsequence_length = 10\n\n# can conveniently be created as\n\ncontrol_signal_sequences = cbadc.utilities.random_control_signal(\n    M, stop_after_number_of_iterations=sequence_length, random_seed=42)\n\n# where random_seed and stop_after_number_of_iterations are fully optional"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Setting up the Filter\n\nTo produce estimates we need to compute the filter coefficients of the\ndigital estimator. This is part of the instantiation process of the\nDigitalEstimator class. However, these computations require us to\nspecify both the analog system, the digital control and the filter parameters\nsuch as eta2, the batch size K1, and possible the lookahead K2.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Set the bandwidth of the estimator\n\neta2 = 1e7\n\n# Set the batch size\n\nK1 = sequence_length\n\n# Instantiate the digital estimator (this is where the filter coefficients are\n# computed).\n\ndigital_estimator = cbadc.digital_estimator.DigitalEstimator(analog_system, digital_control, eta2, K1)\n\nprint(digital_estimator, \"\\n\")\n\n# Set control signal iterator\ndigital_estimator(control_signal_sequences)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Producing Estimates\n\nAt this point, we can produce estimates by simply calling the iterator\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "for i in digital_estimator:\n    print(i)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Batch Size and Lookahead\n\nNote that batch and lookahead sizes are automatically handled such that for\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "K1 = 5\nK2 = 1\nsequence_length = 11\ncontrol_signal_sequences = cbadc.utilities.random_control_signal(\n    M, stop_after_number_of_iterations=sequence_length, random_seed=42)\ndigital_estimator = cbadc.digital_estimator.DigitalEstimator(\n    analog_system, digital_control, eta2, K1, K2)\n\n# Set control signal iterator\ndigital_estimator(control_signal_sequences)\n\n# The iterator is still called the same way.\nfor i in digital_estimator:\n    print(i)\n# However, this time this iterator involves computing two batches each\n# involving a lookahead of size one."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Loading Control Signal from File\n\nNext, we will load an actual control signal to demonstrate the digital\nestimator's capabilities. To this end, we will use the\n`sinusodial_simulation.adcs` file that was produced in\n:doc:`./plot_b_simulate_a_control_bounded_adc`.\n\nThe control signal file is encoded as raw binary data so to unpack it\ncorrectly we will use the :func:`cbadc.utilities.read_byte_stream_from_file`\nand :func:`cbadc.utilities.byte_stream_2_control_signal` functions.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "byte_stream = cbadc.utilities.read_byte_stream_from_file('sinusodial_simulation.adcs', M)\ncontrol_signal_sequences = cbadc.utilities.byte_stream_2_control_signal(byte_stream, M)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Estimating the input\n\nFortunately, we used the same\nanalog system and digital controls as in this example so\n\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "stop_after_number_of_iterations = 1 << 17\nu_hat = np.zeros(stop_after_number_of_iterations)\nK1 = 1 << 10\nK2 = 1 << 11\ndigital_estimator = cbadc.digital_estimator.DigitalEstimator(\n    analog_system, digital_control,\n    eta2,\n    K1,\n    K2,\n    stop_after_number_of_iterations=stop_after_number_of_iterations\n)\n# Set control signal iterator\ndigital_estimator(control_signal_sequences)\nfor index, u_hat_temp in enumerate(digital_estimator):\n    u_hat[index] = u_hat_temp\n\nt = np.arange(u_hat.size)\nplt.plot(t, u_hat)\nplt.xlabel('$t / T$')\nplt.ylabel('$\\hat{u}(t)$')\nplt.title(\"Estimated input signal\")\nplt.grid()\nplt.xlim((0, 1500))\nplt.ylim((-1, 1))\nplt.tight_layout()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Plotting the PSD\n\nAs is typical for delta-sigma modulators, we often visualize the performance\nof the estimate by plotting the power spectral density (PSD).\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "f, psd = cbadc.utilities.compute_power_spectral_density(u_hat[K2:])\nplt.figure()\nplt.semilogx(f, 10 * np.log10(psd))\nplt.xlabel('frequency [Hz]')\nplt.ylabel('$ \\mathrm{V}^2 \\, / \\, \\mathrm{Hz}$')\nplt.xlim((f[1], f[-1]))\nplt.grid(which='both')"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "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.8.5"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}