1e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#!/usr/bin/python 2e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 3e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger''' 4e27eefc4844477cee5d32f51ab45ff62020cdb36Derek SollenbergerCopyright 2013 Google Inc. 5e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 6e27eefc4844477cee5d32f51ab45ff62020cdb36Derek SollenbergerUse of this source code is governed by a BSD-style license that can be 7e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerfound in the LICENSE file. 8e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger''' 9e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 10e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerimport math 11e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerimport pprint 12e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 13e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerdef withinStdDev(n): 14e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger """Returns the percent of samples within n std deviations of the normal.""" 15e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return math.erf(n / math.sqrt(2)) 16e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 17e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerdef withinStdDevRange(a, b): 18e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger """Returns the percent of samples within the std deviation range a, b""" 19e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if b < a: 20e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return 0; 21e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 22e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if a < 0: 23e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if b < 0: 24e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return (withinStdDev(-a) - withinStdDev(-b)) / 2; 25e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger else: 26e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return (withinStdDev(-a) + withinStdDev(b)) / 2; 27e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger else: 28e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return (withinStdDev(b) - withinStdDev(a)) / 2; 29e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 30e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 31e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#We have a bunch of smudged samples which represent the average coverage of a range. 32e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#We have a 'center' which may not line up with those samples. 33e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#From the 'center' we want to make a normal approximation where '5' sample width out we're at '3' std deviations. 34e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#The first and last samples may not be fully covered. 35e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 36e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#This is the sub-sample shift for each set of FIR coefficients (the centers of the lcds in the samples) 37e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#Each subpxl takes up 1/3 of a pixel, so they are centered at x=(i/n+1/2n), or 1/6, 3/6, 5/6 of a pixel. 38e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#Each sample takes up 1/4 of a pixel, so the results fall at (x*4)%1, or 2/3, 0, 1/3 of a sample. 39e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergersamples_per_pixel = 4 40e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergersubpxls_per_pixel = 3 41e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#sample_offsets is (frac, int) in sample units. 42e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergersample_offsets = [math.modf((float(subpxl_index)/subpxls_per_pixel + 1.0/(2.0*subpxls_per_pixel))*samples_per_pixel) for subpxl_index in range(subpxls_per_pixel)] 43e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 44e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#How many samples to consider to the left and right of the subpxl center. 45e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergersample_units_width = 5 46e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 47e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#The std deviation at sample_units_width. 48e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerstd_dev_max = 3 49e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 50e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#The target sum is in some fixed point representation. 51e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger#Values larger the 1 in fixed point simulate ink spread. 52e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergertarget_sum = 0x110 53e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 54e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenbergerfor sample_offset, sample_align in sample_offsets: 55e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs = [] 56e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs_rounded = [] 57e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 58e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger #We start at sample_offset - sample_units_width 59e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_sample_left = sample_offset - sample_units_width 60e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_std_dev_left = -std_dev_max 61e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 62e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger done = False 63e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger while not done: 64e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_sample_right = math.floor(current_sample_left + 1) 65e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if current_sample_right > sample_offset + sample_units_width: 66e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger done = True 67e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_sample_right = sample_offset + sample_units_width 68e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_std_dev_right = current_std_dev_left + ((current_sample_right - current_sample_left) / sample_units_width) * std_dev_max 69e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 70e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coverage = withinStdDevRange(current_std_dev_left, current_std_dev_right) 71e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs.append(coverage * target_sum) 72e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs_rounded.append(int(round(coverage * target_sum))) 73e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 74e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_sample_left = current_sample_right 75e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger current_std_dev_left = current_std_dev_right 76e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 77e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # Now we have the numbers we want, but our rounding needs to add up to target_sum. 78e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger delta = 0 79e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs_rounded_sum = sum(coeffs_rounded) 80e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if coeffs_rounded_sum > target_sum: 81e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # The coeffs add up to too much. Subtract 1 from the ones which were rounded up the most. 82e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger delta = -1 83e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 84e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if coeffs_rounded_sum < target_sum: 85e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # The coeffs add up to too little. Add 1 to the ones which were rounded down the most. 86e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger delta = 1 87e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 88e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger if delta: 89e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print "Initial sum is 0x%0.2X, adjusting." % (coeffs_rounded_sum,) 90e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeff_diff = [(coeff_rounded - coeff) * delta 91e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger for coeff, coeff_rounded in zip(coeffs, coeffs_rounded)] 92e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 93e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger class IndexTracker: 94e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger def __init__(self, index, item): 95e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger self.index = index 96e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger self.item = item 97e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger def __lt__(self, other): 98e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return self.item < other.item 99e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger def __repr__(self): 100e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger return "arr[%d] == %s" % (self.index, repr(self.item)) 101e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 102e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeff_pkg = [IndexTracker(i, diff) for i, diff in enumerate(coeff_diff)] 103e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeff_pkg.sort() 104e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 105e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # num_elements_to_force_round had better be < (2 * sample_units_width + 1) or 106e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # * our math was wildy wrong 107e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # * an awful lot of the curve is out side our sample 108e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger # either is pretty bad, and probably means the results will not be useful. 109e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger num_elements_to_force_round = abs(coeffs_rounded_sum - target_sum) 110e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger for i in xrange(num_elements_to_force_round): 111e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print "Adding %d to index %d to force round %f." % (delta, coeff_pkg[i].index, coeffs[coeff_pkg[i].index]) 112e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs_rounded[coeff_pkg[i].index] += delta 113e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 114e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print "Prepending %d 0x00 for allignment." % (sample_align,) 115e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger coeffs_rounded_aligned = ([0] * int(sample_align)) + coeffs_rounded 116e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger 117e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print ', '.join(["0x%0.2X" % coeff_rounded for coeff_rounded in coeffs_rounded_aligned]) 118e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print sum(coeffs), hex(sum(coeffs_rounded)) 119e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger print 120