OutputWaveforms
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
e83607d661
commit
308512670e
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue