kopia lustrzana https://gitlab.com/sane-project/backends
Merge branch 'genesys-analog-devices-adc-calibration' into 'master'
genesys: Implement gain calibration for Analog-Devices ADC See merge request sane-project/backends!176merge-requests/177/merge
commit
7a8da5c40b
|
@ -3069,40 +3069,17 @@ static void gl843_coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sen
|
|||
// pick target value at 95th percentile of all values. There may be a lot of black values
|
||||
// in transparency scans for example
|
||||
std::sort(values.begin(), values.end());
|
||||
uint16_t target_value = values[unsigned((values.size() - 1) * 0.95)];
|
||||
uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)];
|
||||
if (bpp == 16) {
|
||||
target_value /= 256;
|
||||
curr_output /= 256;
|
||||
}
|
||||
float target_value = calib_sensor.gain_white_ref * coeff;
|
||||
|
||||
/* the flow of data through the frontend ADC is as follows (see e.g. VM8192 datasheet)
|
||||
input
|
||||
-> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
|
||||
-> apply gain (o = i * 208/(283-PGA[7:0])
|
||||
-> ADC
|
||||
|
||||
Here we have some input data that was acquired with zero gain (PGA==0).
|
||||
We want to compute gain such that the output would approach full ADC range (controlled by
|
||||
gain_white_ref).
|
||||
|
||||
We want to solve the following for {PGA}:
|
||||
|
||||
{input} * 208 / (283 - 0) = {output}
|
||||
{input} * 208 / (283 - {PGA}) = {target output}
|
||||
|
||||
The solution is the following equation:
|
||||
|
||||
{PGA} = 283 * (1 - {output} / {target output})
|
||||
*/
|
||||
float gain = ((float) target_value / (calib_sensor.gain_white_ref*coeff));
|
||||
int code = 283 * (1 - gain);
|
||||
if (code > 255)
|
||||
code = 255;
|
||||
else if (code < 0)
|
||||
code = 0;
|
||||
int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type);
|
||||
dev->frontend.set_gain(j, code);
|
||||
|
||||
DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, target_value,
|
||||
gain, code);
|
||||
DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, j, curr_output,
|
||||
(int) target_value, code);
|
||||
}
|
||||
|
||||
if (dev->model->is_cis) {
|
||||
|
|
|
@ -1387,6 +1387,65 @@ void compute_session(Genesys_Device* dev, ScanSession& s, const Genesys_Sensor&
|
|||
compute_session_buffer_sizes(dev->model->asic_type, s);
|
||||
}
|
||||
|
||||
std::uint8_t compute_frontend_gain_wolfson(float value, float target_value)
|
||||
{
|
||||
/* the flow of data through the frontend ADC is as follows (see e.g. WM8192 datasheet)
|
||||
input
|
||||
-> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
|
||||
-> apply gain (o = i * 208/(283-PGA[7:0])
|
||||
-> ADC
|
||||
|
||||
Here we have some input data that was acquired with zero gain (PGA==0).
|
||||
We want to compute gain such that the output would approach full ADC range (controlled by
|
||||
target_value).
|
||||
|
||||
We want to solve the following for {PGA}:
|
||||
|
||||
{value} = {input} * 208 / (283 - 0)
|
||||
{target_value} = {input} * 208 / (283 - {PGA})
|
||||
|
||||
The solution is the following equation:
|
||||
|
||||
{PGA} = 283 * (1 - {value} / {target_value})
|
||||
*/
|
||||
float gain = value / target_value;
|
||||
int code = 283 * (1 - gain);
|
||||
return clamp(code, 0, 255);
|
||||
}
|
||||
|
||||
std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value)
|
||||
{
|
||||
/* The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet)
|
||||
input
|
||||
-> apply offset (o = i + 300mV * (OFFSET[8] ? 1 : -1) * (OFFSET[7:0] / 127)
|
||||
-> apply gain (o = i * 6 / (1 + 5 * ( 63 - PGA[5:0] ) / 63 ) )
|
||||
-> ADC
|
||||
|
||||
We want to solve the following for {PGA}:
|
||||
|
||||
{value} = {input} * 6 / (1 + 5 * ( 63 - 0) / 63 ) )
|
||||
{target_value} = {input} * 6 / (1 + 5 * ( 63 - {PGA}) / 63 ) )
|
||||
|
||||
The solution is the following equation:
|
||||
|
||||
{PGA} = (378 / 5) * ({target_value} - {value} / {target_value})
|
||||
*/
|
||||
int code = static_cast<int>((378.0f / 5.0f) * ((target_value - value) / target_value));
|
||||
return clamp(code, 0, 63);
|
||||
}
|
||||
|
||||
std::uint8_t compute_frontend_gain(float value, float target_value,
|
||||
FrontendType frontend_type)
|
||||
{
|
||||
if (frontend_type == FrontendType::WOLFSON) {
|
||||
return compute_frontend_gain_wolfson(value, target_value);
|
||||
}
|
||||
if (frontend_type == FrontendType::ANALOG_DEVICES) {
|
||||
return compute_frontend_gain_analog_devices(value, target_value);
|
||||
}
|
||||
throw SaneException("Unknown frontend to compute gain for");
|
||||
}
|
||||
|
||||
const SensorProfile& get_sensor_profile(AsicType asic_type, const Genesys_Sensor& sensor,
|
||||
unsigned dpi, unsigned ccd_size_divisor)
|
||||
{
|
||||
|
|
|
@ -640,6 +640,9 @@ void compute_session(Genesys_Device* dev, ScanSession& s, const Genesys_Sensor&
|
|||
|
||||
void genesys_fill_segmented_buffer(Genesys_Device* dev, uint8_t* work_buffer_dst, size_t size);
|
||||
|
||||
std::uint8_t compute_frontend_gain(float value, float target_value,
|
||||
FrontendType frontend_type);
|
||||
|
||||
const SensorProfile& get_sensor_profile(AsicType asic_type, const Genesys_Sensor& sensor,
|
||||
unsigned dpi, unsigned ccd_size_divisor);
|
||||
|
||||
|
@ -672,6 +675,16 @@ inline uint64_t multiply_by_depth_ceil(uint64_t pixels, uint64_t depth)
|
|||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T clamp(const T& value, const T& lo, const T& hi)
|
||||
{
|
||||
if (value < lo)
|
||||
return lo;
|
||||
if (value > hi)
|
||||
return hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* ASIC specific functions declarations */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
Ładowanie…
Reference in New Issue