OutputWaveform::voltageCurrent

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-05-24 16:52:29 -06:00
parent 9b4315eb64
commit e56baf44ad
3 changed files with 232 additions and 64 deletions

View File

@ -362,6 +362,7 @@ public:
bool &extrapolated) const;
float findValue(float axis_value1) const;
float findValueClip(float axis_value1) const;
float findValueClipZero(float axis_value1) const;
FloatSeq *values() const { return values_; }
using Table::findValue;
@ -506,6 +507,9 @@ public:
Table1 *ref_times);
~OutputWaveforms();
const RiseFall *rf() const { return rf_; }
TableAxisPtr slewAxis() const { return slew_axis_; }
TableAxisPtr capAxis() const { return cap_axis_; }
// Column.
bool inBounds(float in_slew,
float load_cap) const;
Table1 voltageWaveform(float in_slew,
@ -515,6 +519,12 @@ public:
float voltage);
const Table1 *currentWaveform(float slew,
float cap);
float timeCurrent(float slew,
float cap,
float time);
float voltageCurrent(float slew,
float cap,
float volt);
float referenceTime(float slew);
void setVdd(float vdd);
static bool checkAxes(TableTemplate *tbl_template);
@ -525,6 +535,10 @@ private:
float cap);
FloatSeq *voltageTimes(size_t wave_index,
float cap);
void findVoltages(size_t wave_index,
float cap);
const Table1 *voltageCurrents(size_t wave_index,
float cap);
// Row.
TableAxisPtr slew_axis_;
@ -532,6 +546,7 @@ private:
TableAxisPtr cap_axis_;
const RiseFall *rf_;
Table1Seq current_waveforms_;
Table1Seq voltage_currents_;
FloatTable voltage_times_;
Table1 *ref_times_;
float vdd_;

View File

@ -908,6 +908,27 @@ Table1::findValueClip(float axis_value1) const
}
}
float
Table1::findValueClipZero(float axis_value1) const
{
if (axis1_->size() == 1)
return this->value(axis_value1);
else {
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
float x1 = axis_value1;
float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(axis_index1 + 1);
if (x1 < x1l || x1 > x1u)
return 0.0;
else {
float y1 = this->value(axis_index1);
float y2 = this->value(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
return (1 - dx1) * y1 + dx1 * y2;
}
}
}
string
Table1::reportValue(const char *result_name, const
LibertyLibrary *library,
@ -1592,6 +1613,7 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
cap_axis_(cap_axis),
rf_(rf),
current_waveforms_(current_waveforms),
voltage_currents_(current_waveforms.size()),
voltage_times_(current_waveforms.size()),
ref_times_(ref_times),
vdd_(0.0)
@ -1601,6 +1623,7 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
OutputWaveforms::~OutputWaveforms()
{
current_waveforms_.deleteContents();
voltage_currents_.deleteContents();
voltage_times_.deleteContents();
delete ref_times_;
}
@ -1640,6 +1663,48 @@ OutputWaveforms::currentWaveform(float slew,
return current_waveforms_[wave_index];
}
float
OutputWaveforms::timeCurrent(float slew,
float cap,
float time)
{
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
size_t slew_count = slew_axis_->size();
size_t wave_index00 = slew_index * slew_count + cap_index;
size_t wave_index01 = slew_index * slew_count + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index;
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
const Table1 *waveform00 = current_waveforms_[wave_index00];
const Table1 *waveform01 = current_waveforms_[wave_index01];
const Table1 *waveform10 = current_waveforms_[wave_index10];
const Table1 *waveform11 = current_waveforms_[wave_index11];
// Interpolate waveform samples at voltage steps.
size_t index1 = slew_index;
size_t index2 = cap_index;
float x1 = slew;
float x2 = cap;
float x1l = slew_axis_->axisValue(index1);
float x1u = slew_axis_->axisValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
float x2l = cap_axis_->axisValue(index2);
float x2u = cap_axis_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
float y00 = waveform00->findValueClipZero(time);
float y01 = waveform01->findValueClipZero(time);
float y10 = waveform10->findValueClipZero(time);
float y11 = waveform11->findValueClipZero(time);
float current
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
return current;
}
float
OutputWaveforms::referenceTime(float slew)
{
@ -1652,6 +1717,23 @@ OutputWaveforms::setVdd(float vdd)
vdd_ = vdd;
}
Table1
OutputWaveforms::voltageWaveform(float slew,
float cap)
{
float volt_step = vdd_ / voltage_waveform_step_count_;
FloatSeq *times = new FloatSeq;
FloatSeq *volts = new FloatSeq;
for (size_t v = 0; v <= voltage_waveform_step_count_; v++) {
float volt = v * volt_step;
float time = voltageTime(slew, cap, volt);
times->push_back(time);
volts->push_back(volt);
}
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time, times);
return Table1(volts, time_axis);
}
float
OutputWaveforms::voltageTime(float slew,
float cap,
@ -1691,23 +1773,6 @@ OutputWaveforms::voltageTime(float slew,
return time;
}
Table1
OutputWaveforms::voltageWaveform(float slew,
float cap)
{
float volt_step = vdd_ / voltage_waveform_step_count_;
FloatSeq *times = new FloatSeq;
FloatSeq *volts = new FloatSeq;
for (size_t v = 0; v <= voltage_waveform_step_count_; v++) {
float volt = v * volt_step;
float time = voltageTime(slew, cap, volt);
times->push_back(time);
volts->push_back(volt);
}
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time, times);
return Table1(volts, time_axis);
}
float
OutputWaveforms::voltageTime1(float voltage,
size_t wave_index,
@ -1728,57 +1793,128 @@ OutputWaveforms::voltageTimes(size_t wave_index,
{
FloatSeq *voltage_times = voltage_times_[wave_index];
if (voltage_times == nullptr) {
// Integrate current waveform to find voltage waveform.
// i = C dv/dt
FloatSeq volts;
Table1 *currents = current_waveforms_[wave_index];
TableAxisPtr time_axis = currents->axis1();
float prev_time = time_axis->axisValue(0);
float prev_current = currents->value(0);
float voltage = 0.0;
volts.push_back(voltage);
bool always_rise = true;
bool invert = (always_rise && rf_ == RiseFall::fall());
for (size_t i = 1; i < time_axis->size(); i++) {
float time = time_axis->axisValue(i);
float current = currents->value(i);
float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap;
voltage += invert ? -dv : dv;
volts.push_back(voltage);
prev_time = time;
prev_current = current;
}
// Sample the voltage waveform at uniform intervals to speed up
// voltage time lookup.
voltage_times = new FloatSeq;
float volt_step = vdd_ / voltage_waveform_step_count_;
size_t i = 0;
float time0 = time_axis->axisValue(i);
float volt0 = volts[i];
i = 1;
float time1 = time_axis->axisValue(i);
float volt1 = volts[i];
for (size_t v = 0; v <= voltage_waveform_step_count_; v++) {
float volt3 = v * volt_step;
while (volt3 > volt1 && i < volts.size() - 1) {
time0 = time1;
volt0 = volt1;
i++;
time1 = time_axis->axisValue(i);
volt1 = volts[i];
}
float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0);
if (time3 < 0.0)
printf("luse\n");
//printf("%.2f %.2e\n", volt3, time3);
voltage_times->push_back(time3);
}
voltage_times_[wave_index] = voltage_times;
findVoltages(wave_index, cap);
voltage_times = voltage_times_[wave_index];
}
return voltage_times;
}
void
OutputWaveforms::findVoltages(size_t wave_index,
float cap)
{
if (vdd_ == 0.0)
criticalError(239, "output waveform vdd = 0.0");
// Integrate current waveform to find voltage waveform.
// i = C dv/dt
FloatSeq volts;
Table1 *currents = current_waveforms_[wave_index];
TableAxisPtr time_axis = currents->axis1();
float prev_time = time_axis->axisValue(0);
float prev_current = currents->value(0);
float voltage = 0.0;
volts.push_back(voltage);
bool always_rise = true;
bool invert = (always_rise && rf_ == RiseFall::fall());
for (size_t i = 1; i < time_axis->size(); i++) {
float time = time_axis->axisValue(i);
float current = currents->value(i);
float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap;
voltage += invert ? -dv : dv;
volts.push_back(voltage);
prev_time = time;
prev_current = current;
}
// Make voltage -> current table.
FloatSeq *axis_volts = new FloatSeq(volts);
TableAxisPtr volt_axis =
make_shared<TableAxis>(TableAxisVariable::input_voltage, axis_volts);
FloatSeq *currents1 = new FloatSeq(*currents->values());
Table1 *volt_currents = new Table1(currents1, volt_axis);
voltage_currents_[wave_index] = volt_currents;
// Sample the voltage waveform at uniform intervals to speed up
// voltage time lookup.
FloatSeq *voltage_times = new FloatSeq;
float volt_step = vdd_ / voltage_waveform_step_count_;
size_t i = 0;
float time0 = time_axis->axisValue(i);
float volt0 = volts[i];
i = 1;
float time1 = time_axis->axisValue(i);
float volt1 = volts[i];
for (size_t v = 0; v <= voltage_waveform_step_count_; v++) {
float volt3 = v * volt_step;
while (volt3 > volt1 && i < volts.size() - 1) {
time0 = time1;
volt0 = volt1;
i++;
time1 = time_axis->axisValue(i);
volt1 = volts[i];
}
float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0);
voltage_times->push_back(time3);
}
voltage_times_[wave_index] = voltage_times;
}
float
OutputWaveforms::voltageCurrent(float slew,
float cap,
float volt)
{
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
size_t slew_count = slew_axis_->size();
size_t wave_index00 = slew_index * slew_count + cap_index;
size_t wave_index01 = slew_index * slew_count + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index;
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
float cap0 = cap_axis_->axisValue(cap_index);
float cap1 = cap_axis_->axisValue(cap_index + 1);
// Interpolate waveform samples at voltage steps.
size_t index1 = slew_index;
size_t index2 = cap_index;
float x1 = slew;
float x2 = cap;
float x1l = slew_axis_->axisValue(index1);
float x1u = slew_axis_->axisValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
float x2l = cap_axis_->axisValue(index2);
float x2u = cap_axis_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
const Table1 *waveform00 = voltageCurrents(wave_index00, cap0);
const Table1 *waveform01 = voltageCurrents(wave_index01, cap1);
const Table1 *waveform10 = voltageCurrents(wave_index10, cap0);
const Table1 *waveform11 = voltageCurrents(wave_index11, cap1);
float y00 = waveform00->findValueClipZero(volt);
float y01 = waveform01->findValueClipZero(volt);
float y10 = waveform10->findValueClipZero(volt);
float y11 = waveform11->findValueClipZero(volt);
float current
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
return current;
}
const Table1 *
OutputWaveforms::voltageCurrents(size_t wave_index,
float cap)
{
const Table1 *waveform = voltage_currents_[wave_index];
if (waveform == nullptr) {
findVoltages(wave_index, cap);
waveform = voltage_currents_[wave_index];
}
return waveform;
}
////////////////////////////////////////////////////////////////
DriverWaveform::DriverWaveform(const char *name,

View File

@ -5725,6 +5725,23 @@ current_waveform(float in_slew,
return nullptr;
}
float
voltage_current(float in_slew,
float load_cap,
float voltage)
{
GateTableModel *gate_model = dynamic_cast<GateTableModel*>(self->model());
if (gate_model) {
OutputWaveforms *waveforms = gate_model->outputWaveforms();
if (waveforms) {
waveforms->setVdd(.7);
float current = waveforms->voltageCurrent(in_slew, load_cap, voltage);
return current;
}
}
return 0.0;
}
} // TimingArc methods
%extend Instance {