ccs table model

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-05-06 15:34:41 -07:00
parent 7f82c152d9
commit ffec2a1db0
2 changed files with 73 additions and 136 deletions

View File

@ -507,7 +507,7 @@ public:
const RiseFall *rf() const { return rf_; } const RiseFall *rf() const { return rf_; }
Table1 voltageWaveform(float in_slew, Table1 voltageWaveform(float in_slew,
float load_cap); float load_cap);
float timeToVoltage(float in_slew, float voltageTime(float in_slew,
float load_cap, float load_cap,
float voltage); float voltage);
const Table1 *currentWaveform(float slew, const Table1 *currentWaveform(float slew,
@ -516,11 +516,10 @@ public:
static bool checkAxes(TableTemplate *tbl_template); static bool checkAxes(TableTemplate *tbl_template);
private: private:
float timeToVoltage(const Table1 *waveform, float voltageTime1(float voltage,
float voltage); size_t wave_index,
size_t findValueIndex(const Table1 *table, float cap);
float value); FloatSeq *voltageTimes(size_t wave_index,
Table1 *voltageWaveform(size_t wave_index,
float cap); float cap);
// Row. // Row.
@ -529,8 +528,10 @@ private:
TableAxisPtr cap_axis_; TableAxisPtr cap_axis_;
const RiseFall *rf_; const RiseFall *rf_;
Table1Seq current_waveforms_; Table1Seq current_waveforms_;
Table1Seq voltage_waveforms_; FloatTable voltage_times_;
Table1 *ref_times_; Table1 *ref_times_;
float voltage_max_;
static constexpr size_t voltage_waveform_step_count_ = 20;
}; };
class DriverWaveform class DriverWaveform

View File

@ -1586,7 +1586,7 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
cap_axis_(cap_axis), cap_axis_(cap_axis),
rf_(rf), rf_(rf),
current_waveforms_(current_waveforms), current_waveforms_(current_waveforms),
voltage_waveforms_(current_waveforms.size()), voltage_times_(current_waveforms.size()),
ref_times_(ref_times) ref_times_(ref_times)
{ {
} }
@ -1594,7 +1594,7 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
OutputWaveforms::~OutputWaveforms() OutputWaveforms::~OutputWaveforms()
{ {
current_waveforms_.deleteContents(); current_waveforms_.deleteContents();
voltage_waveforms_.deleteContents(); voltage_times_.deleteContents();
delete ref_times_; delete ref_times_;
} }
@ -1632,7 +1632,7 @@ OutputWaveforms::referenceTime(float slew)
} }
float float
OutputWaveforms::timeToVoltage(float slew, OutputWaveforms::voltageTime(float slew,
float cap, float cap,
float volt) float volt)
{ {
@ -1645,12 +1645,6 @@ OutputWaveforms::timeToVoltage(float slew,
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1); size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
float cap0 = cap_axis_->axisValue(cap_index); float cap0 = cap_axis_->axisValue(cap_index);
float cap1 = cap_axis_->axisValue(cap_index + 1); float cap1 = cap_axis_->axisValue(cap_index + 1);
const Table1 *values00 = voltageWaveform(wave_index00, cap0);
const Table1 *values01 = voltageWaveform(wave_index01, cap1);
const Table1 *values10 = voltageWaveform(wave_index10, cap0);
const Table1 *values11 = voltageWaveform(wave_index11, cap1);
TableAxisPtr time_axis00 = values00->axis1();
// Interpolate waveform samples at voltage steps. // Interpolate waveform samples at voltage steps.
size_t index1 = slew_index; size_t index1 = slew_index;
@ -1664,10 +1658,10 @@ OutputWaveforms::timeToVoltage(float slew,
float x2u = cap_axis_->axisValue(index2 + 1); float x2u = cap_axis_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l); float dx2 = (x2 - x2l) / (x2u - x2l);
float y00 = timeToVoltage(values00, volt); float y00 = voltageTime1(volt, wave_index00, cap0);
float y01 = timeToVoltage(values01, volt); float y01 = voltageTime1(volt, wave_index01, cap1);
float y10 = timeToVoltage(values10, volt); float y10 = voltageTime1(volt, wave_index10, cap0);
float y11 = timeToVoltage(values11, volt); float y11 = voltageTime1(volt, wave_index11, cap1);
float time float time
= (1 - dx1) * (1 - dx2) * y00 = (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10 + dx1 * (1 - dx2) * y10
@ -1680,128 +1674,49 @@ Table1
OutputWaveforms::voltageWaveform(float slew, OutputWaveforms::voltageWaveform(float slew,
float cap) float cap)
{ {
size_t slew_index = slew_axis_->findAxisIndex(slew); float volt_step = voltage_max_ / voltage_waveform_step_count_;
size_t cap_index = cap_axis_->findAxisIndex(cap); FloatSeq *times = new FloatSeq;
size_t slew_count = slew_axis_->size(); FloatSeq *volts = new FloatSeq;
size_t wave_index00 = slew_index * slew_count + cap_index; for (size_t v = 0; v <= voltage_waveform_step_count_; v++) {
size_t wave_index01 = slew_index * slew_count + (cap_index + 1); float volt = v * volt_step;
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index; float time = voltageTime(slew, cap, volt);
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1); times->push_back(time);
float cap0 = cap_axis_->axisValue(cap_index); volts->push_back(volt);
float cap1 = cap_axis_->axisValue(cap_index + 1);
const Table1 *values00 = voltageWaveform(wave_index00, cap0);
const Table1 *values01 = voltageWaveform(wave_index01, cap1);
const Table1 *values10 = voltageWaveform(wave_index10, cap0);
const Table1 *values11 = voltageWaveform(wave_index11, cap1);
TableAxisPtr time_axis00 = values00->axis1();
size_t volt_step_count = 20;
float volt_max = values00->value(time_axis00->size() - 1);
float volt_step = volt_max / volt_step_count;
FloatSeq *time_values = new FloatSeq;
TableAxisPtr time_axis = make_shared<TableAxis>(time_axis00->variable(),
time_values);
// 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);
FloatSeq *values = new FloatSeq;
float prev_time = 0.0;
for (size_t i = 0; i <= volt_step_count; i++) {
float volt = volt_step * i;
float y00 = timeToVoltage(values00, volt);
float y01 = timeToVoltage(values01, volt);
float y10 = timeToVoltage(values10, volt);
float y11 = timeToVoltage(values11, volt);
float time
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
if (i == 0 || time > prev_time) {
time_values->push_back(time);
values->push_back(volt);
} }
prev_time = time; TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time, times);
} return Table1(volts, time_axis);
return Table1(values, time_axis);
} }
float float
OutputWaveforms::timeToVoltage(const Table1 *waveform, OutputWaveforms::voltageTime1(float voltage,
float voltage) size_t wave_index,
float cap)
{ {
size_t index1 = findValueIndex(waveform, voltage); FloatSeq *voltage_times = voltageTimes(wave_index, cap);
TableAxisPtr axis = waveform->axis1(); float volt_step = voltage_max_ / voltage_waveform_step_count_;
float axis_value1 = axis->axisValue(index1); size_t volt_idx = voltage / volt_step;
float axis_value2 = axis->axisValue(index1 + 1); float time0 = (*voltage_times)[volt_idx];
float time1 = (*voltage_times)[volt_idx + 1];
float x1 = voltage; float time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx);
float x1l = waveform->value(index1); return time;
float x1u = waveform->value(index1 + 1);
float y1 = axis_value1;
float y2 = axis_value2;
float dx1 = (x1 - x1l) / (x1u - x1l);
return (1 - dx1) * y1 + dx1 * y2;
}
// Bisection search.
// Assumes monotonic table entries
// Copies TableAxis::findAxisIndex.
size_t
OutputWaveforms::findValueIndex(const Table1 *table,
float value)
{
FloatSeq *values_ = table->values();
int index_max = static_cast<int>(values_->size()) - 1;
if (value <= (*values_)[0] || index_max == 0)
return 0;
else if (value >= (*values_)[index_max])
// Return max-1 for value too large so interpolation pts are index,index+1.
return index_max - 1;
else {
int lower = -1;
int upper = index_max + 1;
bool ascend = ((*values_)[index_max] >= (*values_)[0]);
while (upper - lower > 1) {
int mid = (upper + lower) / 2;
if ((value >= (*values_)[mid]) == ascend)
lower = mid;
else
upper = mid;
}
return lower;
}
} }
// Integrate current waveform to find voltage waveform. // Integrate current waveform to find voltage waveform.
// i = C dv/dt // i = C dv/dt
Table1 * FloatSeq *
OutputWaveforms::voltageWaveform(size_t wave_index, OutputWaveforms::voltageTimes(size_t wave_index,
float cap) float cap)
{ {
Table1 *voltages = voltage_waveforms_[wave_index]; FloatSeq *voltage_times = voltage_times_[wave_index];
if (voltages == nullptr) { if (voltage_times == nullptr) {
FloatSeq *voltages1 = new FloatSeq; FloatSeq volts;
Table1 *currents = current_waveforms_[wave_index]; Table1 *currents = current_waveforms_[wave_index];
voltages = new Table1(voltages1, currents->axis1());
voltage_waveforms_[wave_index] = voltages;
TableAxisPtr time_axis = currents->axis1(); TableAxisPtr time_axis = currents->axis1();
float prev_time = time_axis->axisValue(0); float prev_time = time_axis->axisValue(0);
float prev_current = currents->value(0); float prev_current = currents->value(0);
float voltage = 0.0; float voltage = 0.0;
voltages1->push_back(voltage); volts.push_back(voltage);
bool always_rise = true; bool always_rise = true;
bool invert = (always_rise && rf_ == RiseFall::fall()); bool invert = (always_rise && rf_ == RiseFall::fall());
for (size_t i = 1; i < time_axis->size(); i++) { for (size_t i = 1; i < time_axis->size(); i++) {
@ -1809,16 +1724,37 @@ OutputWaveforms::voltageWaveform(size_t wave_index,
float current = currents->value(i); float current = currents->value(i);
float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap; float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap;
voltage += invert ? -dv : dv; voltage += invert ? -dv : dv;
voltages1->push_back(voltage); volts.push_back(voltage);
prev_time = time; prev_time = time;
prev_current = current; prev_current = current;
} }
if (!always_rise && rf_ == RiseFall::fall()) { voltage_max_ = volts[volts.size() - 1];
for (size_t i = 0; i < voltages1->size(); i++)
(*voltages1)[i] -= voltage; // Sample voltage waveform a uniform intervals to speed up time to voltage lookup.
voltage_times = new FloatSeq;
float volt_step = voltage_max_ / 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()) {
time0 = time1;
volt0 = volt1;
i++;
time1 = time_axis->axisValue(i);
volt1 = volts[i];
} }
float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0);
//printf("%.2f %.2e\n", volt3, time3);
voltage_times->push_back(time3);
} }
return voltages; voltage_times_[wave_index] = voltage_times;
}
return voltage_times;
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////