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