RingDetector.cc revision 10447
110447Snilay@cs.wisc.edu#include "model/optical/RingDetector.h"
210447Snilay@cs.wisc.edu
310447Snilay@cs.wisc.edu#include <cmath>
410447Snilay@cs.wisc.edu
510447Snilay@cs.wisc.edu#include "util/Constants.h"
610447Snilay@cs.wisc.edu#include "model/PortInfo.h"
710447Snilay@cs.wisc.edu#include "model/TransitionInfo.h"
810447Snilay@cs.wisc.edu#include "model/EventInfo.h"
910447Snilay@cs.wisc.edu#include "model/std_cells/StdCell.h"
1010447Snilay@cs.wisc.edu#include "model/std_cells/StdCellLib.h"
1110447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalWaveguide.h"
1210447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalDetector.h"
1310447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalFilter.h"
1410447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalDriver.h"
1510447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalNet.h"
1610447Snilay@cs.wisc.edu
1710447Snilay@cs.wisc.edunamespace DSENT
1810447Snilay@cs.wisc.edu{
1910447Snilay@cs.wisc.edu    // TODOs for this model
2010447Snilay@cs.wisc.edu    // Add the other receiver topologies from [Georgas, CICC 2011]
2110447Snilay@cs.wisc.edu    // Split integ_time_ratio = SA integ time ratio
2210447Snilay@cs.wisc.edu    // Right now perfect clock gating is assumed...may not be what we want
2310447Snilay@cs.wisc.edu
2410447Snilay@cs.wisc.edu    // Constants
2510447Snilay@cs.wisc.edu    const String RingDetector::INTEGRATINGSENSEAMP = "INTSA";
2610447Snilay@cs.wisc.edu
2710447Snilay@cs.wisc.edu    RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_)
2810447Snilay@cs.wisc.edu        : OpticalModel(instance_name_, tech_model_), OpticalReceiver()
2910447Snilay@cs.wisc.edu    {
3010447Snilay@cs.wisc.edu        initParameters();
3110447Snilay@cs.wisc.edu        initProperties();
3210447Snilay@cs.wisc.edu    }
3310447Snilay@cs.wisc.edu
3410447Snilay@cs.wisc.edu    RingDetector::~RingDetector()
3510447Snilay@cs.wisc.edu    {}
3610447Snilay@cs.wisc.edu
3710447Snilay@cs.wisc.edu    void RingDetector::initParameters()
3810447Snilay@cs.wisc.edu    {
3910447Snilay@cs.wisc.edu        addParameterName("DataRate");
4010447Snilay@cs.wisc.edu        addParameterName("InStart");
4110447Snilay@cs.wisc.edu        addParameterName("InEnd");
4210447Snilay@cs.wisc.edu        addParameterName("DetStart");
4310447Snilay@cs.wisc.edu        addParameterName("DetEnd");
4410447Snilay@cs.wisc.edu        addParameterName("DropAll");
4510447Snilay@cs.wisc.edu        addParameterName("Topology");
4610447Snilay@cs.wisc.edu        return;
4710447Snilay@cs.wisc.edu    }
4810447Snilay@cs.wisc.edu
4910447Snilay@cs.wisc.edu    void RingDetector::initProperties()
5010447Snilay@cs.wisc.edu    {
5110447Snilay@cs.wisc.edu        return;
5210447Snilay@cs.wisc.edu    }
5310447Snilay@cs.wisc.edu
5410447Snilay@cs.wisc.edu    void RingDetector::constructModel()
5510447Snilay@cs.wisc.edu    {
5610447Snilay@cs.wisc.edu        // Get parameters
5710447Snilay@cs.wisc.edu        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
5810447Snilay@cs.wisc.edu        WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd"));
5910447Snilay@cs.wisc.edu        int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1;
6010447Snilay@cs.wisc.edu        bool drop_all = getParameter("DropAll");
6110447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
6210447Snilay@cs.wisc.edu
6310447Snilay@cs.wisc.edu        // Set some generated properties
6410447Snilay@cs.wisc.edu        getGenProperties()->set("NumberWavelengths", number_wavelengths);
6510447Snilay@cs.wisc.edu
6610447Snilay@cs.wisc.edu        // Create device area result
6710447Snilay@cs.wisc.edu        addAreaResult(new AtomicResult("Photonic"));
6810447Snilay@cs.wisc.edu        // Create electrical results
6910447Snilay@cs.wisc.edu        createElectricalAtomicResults();
7010447Snilay@cs.wisc.edu        if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive"));
7110447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
7210447Snilay@cs.wisc.edu
7310447Snilay@cs.wisc.edu        // Create optical ports
7410447Snilay@cs.wisc.edu        createOpticalInputPort(         "In",   in_wavelengths);
7510447Snilay@cs.wisc.edu        createOpticalOutputPort(        "Out",  in_wavelengths);
7610447Snilay@cs.wisc.edu        // Create the filter and modulator
7710447Snilay@cs.wisc.edu        createFilter(                   "RingFilter",   in_wavelengths, drop_all, det_wavelengths);
7810447Snilay@cs.wisc.edu        createDetector(                 "RingDetector", det_wavelengths, this);
7910447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
8010447Snilay@cs.wisc.edu        OpticalDetector* ring_detector = getDetector("RingDetector");
8110447Snilay@cs.wisc.edu        // Connect the filter and modulator
8210447Snilay@cs.wisc.edu        getWaveguide("In")->addDownstreamNode(ring_filter);
8310447Snilay@cs.wisc.edu        ring_filter->addDownstreamNode(getWaveguide("Out"));
8410447Snilay@cs.wisc.edu        ring_filter->setDropPort(ring_detector);
8510447Snilay@cs.wisc.edu
8610447Snilay@cs.wisc.edu        // Create electrical ports
8710447Snilay@cs.wisc.edu        createOutputPort("Out", makeNetIndex(0, number_wavelengths-1));
8810447Snilay@cs.wisc.edu        // Create net
8910447Snilay@cs.wisc.edu        createNet("OutVFO");
9010447Snilay@cs.wisc.edu        // Create output driver
9110447Snilay@cs.wisc.edu        createDriver("OutDriver", false);
9210447Snilay@cs.wisc.edu        // Connect driver
9310447Snilay@cs.wisc.edu        getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO"));
9410447Snilay@cs.wisc.edu        // Connect output
9510447Snilay@cs.wisc.edu        assignVirtualFanout("Out", "OutVFO");
9610447Snilay@cs.wisc.edu
9710447Snilay@cs.wisc.edu        // Precompute some technology values
9810447Snilay@cs.wisc.edu        precomputeTech();
9910447Snilay@cs.wisc.edu
10010447Snilay@cs.wisc.edu        return;
10110447Snilay@cs.wisc.edu    }
10210447Snilay@cs.wisc.edu
10310447Snilay@cs.wisc.edu    void RingDetector::updateModel()
10410447Snilay@cs.wisc.edu    {
10510447Snilay@cs.wisc.edu        // Get some generated properties
10610447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
10710447Snilay@cs.wisc.edu
10810447Snilay@cs.wisc.edu        // Get tech model numbers
10910447Snilay@cs.wisc.edu        double ring_area = getTechModel()->get("Ring->Area");
11010447Snilay@cs.wisc.edu        double thru_loss = getTechModel()->get("Ring->ThroughLoss");
11110447Snilay@cs.wisc.edu        double drop_loss = getTechModel()->get("Ring->DropLoss");
11210447Snilay@cs.wisc.edu        double pd_loss = getTechModel()->get("Photodetector->Loss");
11310447Snilay@cs.wisc.edu        double pd_responsivity = getTechModel()->get("Photodetector->Responsivity");
11410447Snilay@cs.wisc.edu
11510447Snilay@cs.wisc.edu        // Design the receiver
11610447Snilay@cs.wisc.edu        designReceiver();
11710447Snilay@cs.wisc.edu
11810447Snilay@cs.wisc.edu        // Update losses
11910447Snilay@cs.wisc.edu        // Connect the filter and modulator
12010447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
12110447Snilay@cs.wisc.edu        OpticalDetector* ring_detector = getDetector("RingDetector");
12210447Snilay@cs.wisc.edu        ring_filter->setLoss(thru_loss * number_wavelengths);
12310447Snilay@cs.wisc.edu        ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths);
12410447Snilay@cs.wisc.edu        ring_detector->setLoss(pd_loss);
12510447Snilay@cs.wisc.edu        ring_detector->setResponsivity(pd_responsivity);
12610447Snilay@cs.wisc.edu        // Update device area
12710447Snilay@cs.wisc.edu        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
12810447Snilay@cs.wisc.edu
12910447Snilay@cs.wisc.edu        return;
13010447Snilay@cs.wisc.edu    }
13110447Snilay@cs.wisc.edu
13210447Snilay@cs.wisc.edu    void RingDetector::useModel()
13310447Snilay@cs.wisc.edu    {
13410447Snilay@cs.wisc.edu        // Get parameters
13510447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
13610447Snilay@cs.wisc.edu
13710447Snilay@cs.wisc.edu        // Get some generated properties
13810447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
13910447Snilay@cs.wisc.edu
14010447Snilay@cs.wisc.edu        // Get optical input transition info
14110447Snilay@cs.wisc.edu        const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo();
14210447Snilay@cs.wisc.edu
14310447Snilay@cs.wisc.edu        // Get tech models
14410447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
14510447Snilay@cs.wisc.edu        // Get caps
14610447Snilay@cs.wisc.edu        double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble();
14710447Snilay@cs.wisc.edu        double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
14810447Snilay@cs.wisc.edu        double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
14910447Snilay@cs.wisc.edu        double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
15010447Snilay@cs.wisc.edu
15110447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
15210447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
15310447Snilay@cs.wisc.edu        {
15410447Snilay@cs.wisc.edu            // Use ratios from the receiver published in [Georgas, ESSCIRC 2011]
15510447Snilay@cs.wisc.edu            // Note:
15610447Snilay@cs.wisc.edu            // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers),
15710447Snilay@cs.wisc.edu            // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative
15810447Snilay@cs.wisc.edu            // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or
15910447Snilay@cs.wisc.edu            // the extra output flops (since receiver structure is already a posedge flop functionally).
16010447Snilay@cs.wisc.edu            // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver.
16110447Snilay@cs.wisc.edu            // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really
16210447Snilay@cs.wisc.edu            // need in the receiver.
16310447Snilay@cs.wisc.edu
16410447Snilay@cs.wisc.edu            // Gate caps
16510447Snilay@cs.wisc.edu            double c_gate_sampler = unit_gate_cap * (4 * 2.0 + 2 * 1.0 + 2 * 3.0 + 2 * 5.0) + unit_gate_cap * (2 * 6.0 + 2 * 1.0) + inv_x1_gate_cap;
16610447Snilay@cs.wisc.edu            double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap;
16710447Snilay@cs.wisc.edu            // Drain caps
16810447Snilay@cs.wisc.edu            double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap;
16910447Snilay@cs.wisc.edu            double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap;
17010447Snilay@cs.wisc.edu            // Sum up cap switched for the sampler
17110447Snilay@cs.wisc.edu            double c_sampler = c_gate_sampler + c_drain_sampler;
17210447Snilay@cs.wisc.edu            double c_rslatch = c_gate_rslatch + c_drain_rslatch;
17310447Snilay@cs.wisc.edu            // Average cap switched
17410447Snilay@cs.wisc.edu            // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability
17510447Snilay@cs.wisc.edu            double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1();
17610447Snilay@cs.wisc.edu
17710447Snilay@cs.wisc.edu            // Get parameters corresponding to a unit-inverter
17810447Snilay@cs.wisc.edu            double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
17910447Snilay@cs.wisc.edu            double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");
18010447Snilay@cs.wisc.edu
18110447Snilay@cs.wisc.edu            // Approximate leakage (curve fit with design)
18210447Snilay@cs.wisc.edu            double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43;
18310447Snilay@cs.wisc.edu
18410447Snilay@cs.wisc.edu            // Create results
18510447Snilay@cs.wisc.edu            getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths);
18610447Snilay@cs.wisc.edu            getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths);
18710447Snilay@cs.wisc.edu
18810447Snilay@cs.wisc.edu        }
18910447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
19010447Snilay@cs.wisc.edu
19110447Snilay@cs.wisc.edu        return;
19210447Snilay@cs.wisc.edu    }
19310447Snilay@cs.wisc.edu
19410447Snilay@cs.wisc.edu    void RingDetector::propagateTransitionInfo()
19510447Snilay@cs.wisc.edu    {
19610447Snilay@cs.wisc.edu        // Propagate probabilities from optical input to electrical output port
19710447Snilay@cs.wisc.edu        getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo());
19810447Snilay@cs.wisc.edu
19910447Snilay@cs.wisc.edu        return;
20010447Snilay@cs.wisc.edu    }
20110447Snilay@cs.wisc.edu
20210447Snilay@cs.wisc.edu    void RingDetector::precomputeTech()
20310447Snilay@cs.wisc.edu    {
20410447Snilay@cs.wisc.edu        // Get parameters
20510447Snilay@cs.wisc.edu        const double data_rate = getParameter("DataRate");
20610447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
20710447Snilay@cs.wisc.edu
20810447Snilay@cs.wisc.edu        // Get tech model numbers
20910447Snilay@cs.wisc.edu        double pd_cap = getTechModel()->get("Photodetector->Cap");
21010447Snilay@cs.wisc.edu        double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap");
21110447Snilay@cs.wisc.edu        double apd = getTechModel()->get("Photodetector->AvalancheGain");
21210447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
21310447Snilay@cs.wisc.edu
21410447Snilay@cs.wisc.edu        // Constants shortcuts
21510447Snilay@cs.wisc.edu        double pi = Constants::pi;
21610447Snilay@cs.wisc.edu        double k = Constants::k;
21710447Snilay@cs.wisc.edu        double q = Constants::q;
21810447Snilay@cs.wisc.edu        double T = getTechModel()->get("Temperature");
21910447Snilay@cs.wisc.edu
22010447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
22110447Snilay@cs.wisc.edu        {
22210447Snilay@cs.wisc.edu            // Get more tech parameters
22310447Snilay@cs.wisc.edu            double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio");
22410447Snilay@cs.wisc.edu            double BER = getTechModel()->get("SenseAmp->BER");
22510447Snilay@cs.wisc.edu            double CMRR = getTechModel()->get("SenseAmp->CMRR");
22610447Snilay@cs.wisc.edu            double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits");
22710447Snilay@cs.wisc.edu            double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd;
22810447Snilay@cs.wisc.edu            double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd;
22910447Snilay@cs.wisc.edu            double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd;
23010447Snilay@cs.wisc.edu            double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin");
23110447Snilay@cs.wisc.edu            double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio");
23210447Snilay@cs.wisc.edu
23310447Snilay@cs.wisc.edu            // Approximate tao using FO4
23410447Snilay@cs.wisc.edu            double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
23510447Snilay@cs.wisc.edu            double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
23610447Snilay@cs.wisc.edu            double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
23710447Snilay@cs.wisc.edu            double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
23810447Snilay@cs.wisc.edu            // Calculate sense amp tau from sense amp output loading
23910447Snilay@cs.wisc.edu            double tau = r_o * (c_g + c_d);
24010447Snilay@cs.wisc.edu            // Set output inverter drive strength
24110447Snilay@cs.wisc.edu            getDriver("OutDriver")->setOutputRes(r_o);
24210447Snilay@cs.wisc.edu
24310447Snilay@cs.wisc.edu            // Calculate sense amp input cap based on schematic
24410447Snilay@cs.wisc.edu            double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0);
24510447Snilay@cs.wisc.edu
24610447Snilay@cs.wisc.edu            // Residual offset
24710447Snilay@cs.wisc.edu            double v_residual = 3 * offset / pow(2, offset_comp_bits);
24810447Snilay@cs.wisc.edu            // Noise
24910447Snilay@cs.wisc.edu            double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR);
25010447Snilay@cs.wisc.edu            // Sense amp voltage build-up minimum
25110447Snilay@cs.wisc.edu            double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR;
25210447Snilay@cs.wisc.edu            // Sigmas corresponding to BER
25310447Snilay@cs.wisc.edu            double sigma = calcInvNormCdf(BER);
25410447Snilay@cs.wisc.edu
25510447Snilay@cs.wisc.edu            //K_int is the time the bit is valid for evaluation
25610447Snilay@cs.wisc.edu
25710447Snilay@cs.wisc.edu            // Total input cap load
25810447Snilay@cs.wisc.edu            double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap;
25910447Snilay@cs.wisc.edu            double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int
26010447Snilay@cs.wisc.edu
26110447Snilay@cs.wisc.edu            // Store precalculated values
26210447Snilay@cs.wisc.edu            m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio);
26310447Snilay@cs.wisc.edu            m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate;
26410447Snilay@cs.wisc.edu            m_quad_b2_ = -2 * v_sense / (z_int * apd);
26510447Snilay@cs.wisc.edu            m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise));
26610447Snilay@cs.wisc.edu        }
26710447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
26810447Snilay@cs.wisc.edu
26910447Snilay@cs.wisc.edu        return;
27010447Snilay@cs.wisc.edu    }
27110447Snilay@cs.wisc.edu
27210447Snilay@cs.wisc.edu    void RingDetector::designReceiver()
27310447Snilay@cs.wisc.edu    {
27410447Snilay@cs.wisc.edu        // Get some generated properties
27510447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
27610447Snilay@cs.wisc.edu
27710447Snilay@cs.wisc.edu        // Get relevant properties/parameters
27810447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
27910447Snilay@cs.wisc.edu
28010447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
28110447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
28210447Snilay@cs.wisc.edu        {
28310447Snilay@cs.wisc.edu            // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is
28410447Snilay@cs.wisc.edu            // about the right size for just the sense amp in the layout
28510447Snilay@cs.wisc.edu            double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
28610447Snilay@cs.wisc.edu            double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
28710447Snilay@cs.wisc.edu            getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths);
28810447Snilay@cs.wisc.edu            getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths);
28910447Snilay@cs.wisc.edu        }
29010447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
29110447Snilay@cs.wisc.edu
29210447Snilay@cs.wisc.edu        return;
29310447Snilay@cs.wisc.edu    }
29410447Snilay@cs.wisc.edu
29510447Snilay@cs.wisc.edu    double RingDetector::getSensitivity(double ER_dB_) const
29610447Snilay@cs.wisc.edu    {
29710447Snilay@cs.wisc.edu        // Get parameters
29810447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
29910447Snilay@cs.wisc.edu        // Turn extinction ratio into a ratio from dB scale
30010447Snilay@cs.wisc.edu        double ER = pow(10, ER_dB_ / 10);
30110447Snilay@cs.wisc.edu
30210447Snilay@cs.wisc.edu        // Initialize sensitivity
30310447Snilay@cs.wisc.edu        double sensitivity = 1e99;
30410447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
30510447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
30610447Snilay@cs.wisc.edu        {
30710447Snilay@cs.wisc.edu            // Scale photodetector shot noise using ER, add rest of noise source
30810447Snilay@cs.wisc.edu            double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_;
30910447Snilay@cs.wisc.edu
31010447Snilay@cs.wisc.edu            // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a
31110447Snilay@cs.wisc.edu            sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_));
31210447Snilay@cs.wisc.edu        }
31310447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
31410447Snilay@cs.wisc.edu
31510447Snilay@cs.wisc.edu        return sensitivity;
31610447Snilay@cs.wisc.edu    }
31710447Snilay@cs.wisc.edu
31810447Snilay@cs.wisc.edu    double RingDetector::calcInvNormCdf(double num_)
31910447Snilay@cs.wisc.edu    {
32010447Snilay@cs.wisc.edu        // 53 bit precision for double FP
32110447Snilay@cs.wisc.edu        unsigned int num_iterations = 20;
32210447Snilay@cs.wisc.edu        // Upperbound the step
32310447Snilay@cs.wisc.edu        double step = 20;
32410447Snilay@cs.wisc.edu        double out = step;
32510447Snilay@cs.wisc.edu        // Iteratively guess and check calculation
32610447Snilay@cs.wisc.edu        for (unsigned int i = 0; i < num_iterations; ++i)
32710447Snilay@cs.wisc.edu        {
32810447Snilay@cs.wisc.edu            double current = 0.5 * erfc(out / sqrt(2));
32910447Snilay@cs.wisc.edu            if (current > num_) out += step;
33010447Snilay@cs.wisc.edu            else out -= step;
33110447Snilay@cs.wisc.edu            step = step * 0.5;
33210447Snilay@cs.wisc.edu        }
33310447Snilay@cs.wisc.edu
33410447Snilay@cs.wisc.edu        return out;
33510447Snilay@cs.wisc.edu    }
33610447Snilay@cs.wisc.edu
33710447Snilay@cs.wisc.edu} // namespace DSENT
33810447Snilay@cs.wisc.edu
339