OutputWaveforms

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-12-31 14:05:58 -07:00
parent e83607d661
commit 308512670e
2 changed files with 152 additions and 130 deletions

View File

@ -344,7 +344,6 @@ 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;
@ -499,23 +498,35 @@ public:
float timeCurrent(float slew,
float cap,
float time);
float timeVoltage(float slew,
float cap,
float time);
float voltageCurrent(float slew,
float cap,
float volt);
float currentVoltage(float slew,
float cap,
float current);
float referenceTime(float slew);
void setVdd(float vdd);
static bool checkAxes(const TableTemplate *tbl_template);
private:
float waveformValue(float slew,
float cap,
float axis_value,
Table1Seq &waveforms);
float voltageTime1(float voltage,
size_t wave_index,
float cap);
FloatSeq *voltageTimes(size_t wave_index,
float cap);
size_t wave_index);
void ensureVoltages();
void findVoltages(size_t wave_index,
float cap);
const Table1 *voltageCurrents(size_t wave_index,
float cap);
void waveformMinMaxTime(float slew,
float cap,
Table1Seq &waveforms,
// Return values.
float &min_time,
float &max_time);
// Row.
TableAxisPtr slew_axis_;
@ -523,7 +534,9 @@ private:
TableAxisPtr cap_axis_;
const RiseFall *rf_;
Table1Seq current_waveforms_;
Table1Seq voltage_waveforms_;
Table1Seq voltage_currents_;
Table1Seq current_voltages_;
FloatTable voltage_times_;
Table1 *ref_times_;
float vdd_;

View File

@ -876,7 +876,7 @@ Table1::findValueClip(float axis_value1) const
float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(axis_index1 + 1);
if (x1 < x1l)
return this->value(0);
return 0.0;
else if (x1 > x1u)
return this->value(axis1_->size() - 1);
else {
@ -888,27 +888,6 @@ 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 LibertyCell *cell,
@ -1588,8 +1567,6 @@ 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)
{
@ -1598,7 +1575,9 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
OutputWaveforms::~OutputWaveforms()
{
current_waveforms_.deleteContents();
voltage_waveforms_.deleteContents();
voltage_currents_.deleteContents();
current_voltages_.deleteContents();
voltage_times_.deleteContents();
delete ref_times_;
}
@ -1634,6 +1613,42 @@ float
OutputWaveforms::timeCurrent(float slew,
float cap,
float time)
{
return waveformValue(slew, cap, time, current_waveforms_);
}
float
OutputWaveforms::timeVoltage(float slew,
float cap,
float time)
{
ensureVoltages();
return waveformValue(slew, cap, time, voltage_waveforms_);
}
float
OutputWaveforms::voltageCurrent(float slew,
float cap,
float volt)
{
ensureVoltages();
return waveformValue(slew, cap, volt, voltage_currents_);
}
float
OutputWaveforms::currentVoltage(float slew,
float cap,
float current)
{
ensureVoltages();
return waveformValue(slew, cap, current, current_voltages_);
}
float
OutputWaveforms::waveformValue(float slew,
float cap,
float axis_value,
Table1Seq &waveforms)
{
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
@ -1643,10 +1658,10 @@ OutputWaveforms::timeCurrent(float slew,
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
size_t wave_index11 = (slew_index + 1) * cap_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];
const Table1 *waveform00 = waveforms[wave_index00];
const Table1 *waveform01 = waveforms[wave_index01];
const Table1 *waveform10 = waveforms[wave_index10];
const Table1 *waveform11 = waveforms[wave_index11];
// Interpolate waveform samples at voltage steps.
size_t index1 = slew_index;
@ -1660,16 +1675,16 @@ OutputWaveforms::timeCurrent(float slew,
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
float y00 = waveform00->findValueClip(axis_value);
float y01 = waveform01->findValueClip(axis_value);
float y10 = waveform10->findValueClip(axis_value);
float y11 = waveform11->findValueClip(axis_value);
float wave_value
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
return current;
return wave_value;
}
float
@ -1688,12 +1703,15 @@ Table1
OutputWaveforms::voltageWaveform(float slew,
float cap)
{
float volt_step = vdd_ / voltage_waveform_step_count_;
ensureVoltages();
float min_time, max_time;
waveformMinMaxTime(slew, cap, voltage_waveforms_, min_time, max_time);
float time_step = (max_time - min_time) / 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);
for (size_t i = 0; i < voltage_waveform_step_count_; i++) {
float time = min_time + i * time_step;
float volt = timeVoltage(slew, cap, time);
times->push_back(time);
volts->push_back(volt);
}
@ -1701,10 +1719,13 @@ OutputWaveforms::voltageWaveform(float slew,
return Table1(volts, time_axis);
}
float
OutputWaveforms::voltageTime(float slew,
float cap,
float volt)
void
OutputWaveforms::waveformMinMaxTime(float slew,
float cap,
Table1Seq &waveforms,
// Return values.
float &min_time,
float &max_time)
{
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
@ -1713,8 +1734,36 @@ OutputWaveforms::voltageTime(float slew,
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1);
float cap0 = cap_axis_->axisValue(cap_index);
float cap1 = cap_axis_->axisValue(cap_index + 1);
const Table1 *waveform00 = waveforms[wave_index00];
const Table1 *waveform01 = waveforms[wave_index01];
const Table1 *waveform10 = waveforms[wave_index10];
const Table1 *waveform11 = waveforms[wave_index11];
min_time = waveform00->axis1()->min();
min_time = min(min_time, waveform01->axis1()->min());
min_time = min(min_time, waveform10->axis1()->min());
min_time = min(min_time, waveform11->axis1()->min());
max_time = waveform00->axis1()->max();
max_time = max(max_time, waveform01->axis1()->max());
max_time = max(max_time, waveform10->axis1()->max());
max_time = max(max_time, waveform11->axis1()->max());
}
float
OutputWaveforms::voltageTime(float slew,
float cap,
float volt)
{
ensureVoltages();
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
size_t cap_count = cap_axis_->size();
size_t wave_index00 = slew_index * cap_count + cap_index;
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1);
// Interpolate waveform samples at voltage steps.
size_t index1 = slew_index;
@ -1728,10 +1777,10 @@ OutputWaveforms::voltageTime(float slew,
float x2u = cap_axis_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
float y00 = voltageTime1(volt, wave_index00, cap0);
float y01 = voltageTime1(volt, wave_index01, cap1);
float y10 = voltageTime1(volt, wave_index10, cap0);
float y11 = voltageTime1(volt, wave_index11, cap1);
float y00 = voltageTime1(volt, wave_index00);
float y01 = voltageTime1(volt, wave_index01);
float y10 = voltageTime1(volt, wave_index10);
float y11 = voltageTime1(volt, wave_index11);
float time
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
@ -1742,10 +1791,9 @@ OutputWaveforms::voltageTime(float slew,
float
OutputWaveforms::voltageTime1(float voltage,
size_t wave_index,
float cap)
size_t wave_index)
{
FloatSeq *voltage_times = voltageTimes(wave_index, cap);
FloatSeq *voltage_times = voltage_times_[wave_index];
float volt_step = vdd_ / voltage_waveform_step_count_;
size_t volt_idx = voltage / volt_step;
float time0 = (*voltage_times)[volt_idx];
@ -1754,16 +1802,23 @@ OutputWaveforms::voltageTime1(float voltage,
return time;
}
FloatSeq *
OutputWaveforms::voltageTimes(size_t wave_index,
float cap)
void
OutputWaveforms::ensureVoltages()
{
FloatSeq *voltage_times = voltage_times_[wave_index];
if (voltage_times == nullptr) {
findVoltages(wave_index, cap);
voltage_times = voltage_times_[wave_index];
if (voltage_waveforms_.empty()) {
size_t size = current_waveforms_.size();
voltage_waveforms_.resize(size);
voltage_currents_.resize(size);
current_voltages_.resize(size);
voltage_times_.resize(size);
size_t cap_count = cap_axis_->size();
for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) {
for (size_t cap_index = 0; cap_index < cap_axis_->size(); cap_index++) {
size_t wave_index = slew_index * cap_count + cap_index;
findVoltages(wave_index, cap_axis_->axisValue(cap_index));
}
}
}
return voltage_times;
}
void
@ -1774,13 +1829,13 @@ OutputWaveforms::findVoltages(size_t wave_index,
criticalError(239, "output waveform vdd = 0.0");
// Integrate current waveform to find voltage waveform.
// i = C dv/dt
FloatSeq volts;
FloatSeq *volts = new FloatSeq;
Table1 *currents = current_waveforms_[wave_index];
const TableAxis *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);
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++) {
@ -1788,37 +1843,47 @@ OutputWaveforms::findVoltages(size_t wave_index,
float current = currents->value(i);
float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap;
voltage += invert ? -dv : dv;
volts.push_back(voltage);
volts->push_back(voltage);
prev_time = time;
prev_current = current;
}
Table1 *volt_table = new Table1(volts, currents->axis1ptr());
voltage_waveforms_[wave_index] = volt_table;
// Make voltage -> current table.
FloatSeq *axis_volts = new FloatSeq(volts);
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;
// Make current -> voltage table.
FloatSeq *axis_currents = new FloatSeq(*currents->values());
TableAxisPtr current_axis =
make_shared<TableAxis>(TableAxisVariable::input_voltage, axis_currents);
FloatSeq *volts1 = new FloatSeq(*volts);
Table1 *current_volts = new Table1(volts1, current_axis);
current_voltages_[wave_index] = current_volts;
// 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];
float volt0 = (*volts)[i];
i = 1;
float time1 = time_axis->axisValue(i);
float volt1 = volts[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) {
while (volt3 > volt1 && i < volts->size() - 1) {
time0 = time1;
volt0 = volt1;
i++;
time1 = time_axis->axisValue(i);
volt1 = volts[i];
volt1 = (*volts)[i];
}
float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0);
voltage_times->push_back(time3);
@ -1826,62 +1891,6 @@ OutputWaveforms::findVoltages(size_t wave_index,
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 cap_count = cap_axis_->size();
size_t wave_index00 = slew_index * cap_count + cap_index;
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
size_t wave_index11 = (slew_index + 1) * cap_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,