blob: f5cc5e55a07fcd4c8a6d4e8a87ca81c200fb92cb [file] [log] [blame]
bungeman@google.com0abbff92013-07-27 20:37:56 +00001#!/usr/bin/python
2
3'''
4Copyright 2013 Google Inc.
5
6Use of this source code is governed by a BSD-style license that can be
7found in the LICENSE file.
8'''
9
10import math
11import pprint
12
13def withinStdDev(n):
14 """Returns the percent of samples within n std deviations of the normal."""
15 return math.erf(n / math.sqrt(2))
16
17def withinStdDevRange(a, b):
18 """Returns the percent of samples within the std deviation range a, b"""
19 if b < a:
20 return 0;
21
22 if a < 0:
23 if b < 0:
24 return (withinStdDev(-a) - withinStdDev(-b)) / 2;
25 else:
26 return (withinStdDev(-a) + withinStdDev(b)) / 2;
27 else:
28 return (withinStdDev(b) - withinStdDev(a)) / 2;
29
30
Ben Wagner483c7722018-02-20 17:06:07 -050031# We have some smudged samples which represent the average coverage of a range.
32# We have a 'center' which may not line up with those samples.
33# From center make a normal where 5 sample widths out is at 3 std deviations.
34# The first and last samples may not be fully covered.
bungeman@google.com0abbff92013-07-27 20:37:56 +000035
Ben Wagner483c7722018-02-20 17:06:07 -050036# This is the sub-sample shift for each set of FIR coefficients
37# (the centers of the lcds in the samples)
38# Each subpxl takes up 1/3 of a pixel,
39# so they are centered at x=(i/n+1/2n), or 1/6, 3/6, 5/6 of a pixel.
40# Each sample takes up 1/4 of a pixel,
41# so the results fall at (x*4)%1, or 2/3, 0, 1/3 of a sample.
bungeman@google.com0abbff92013-07-27 20:37:56 +000042samples_per_pixel = 4
43subpxls_per_pixel = 3
44#sample_offsets is (frac, int) in sample units.
Ben Wagner483c7722018-02-20 17:06:07 -050045sample_offsets = [
46 math.modf(
47 (float(subpxl_index)/subpxls_per_pixel + 1.0/(2.0*subpxls_per_pixel))
48 * samples_per_pixel
49 ) for subpxl_index in range(subpxls_per_pixel)
50]
bungeman@google.com0abbff92013-07-27 20:37:56 +000051
52#How many samples to consider to the left and right of the subpxl center.
53sample_units_width = 5
54
55#The std deviation at sample_units_width.
56std_dev_max = 3
57
58#The target sum is in some fixed point representation.
59#Values larger the 1 in fixed point simulate ink spread.
60target_sum = 0x110
61
62for sample_offset, sample_align in sample_offsets:
63 coeffs = []
64 coeffs_rounded = []
65
66 #We start at sample_offset - sample_units_width
67 current_sample_left = sample_offset - sample_units_width
68 current_std_dev_left = -std_dev_max
69
70 done = False
71 while not done:
72 current_sample_right = math.floor(current_sample_left + 1)
73 if current_sample_right > sample_offset + sample_units_width:
74 done = True
75 current_sample_right = sample_offset + sample_units_width
Ben Wagner483c7722018-02-20 17:06:07 -050076 current_std_dev_right = current_std_dev_left + (
77 (current_sample_right - current_sample_left) / sample_units_width
78 ) * std_dev_max
bungeman@google.com0abbff92013-07-27 20:37:56 +000079
80 coverage = withinStdDevRange(current_std_dev_left, current_std_dev_right)
81 coeffs.append(coverage * target_sum)
82 coeffs_rounded.append(int(round(coverage * target_sum)))
83
84 current_sample_left = current_sample_right
85 current_std_dev_left = current_std_dev_right
86
Ben Wagner483c7722018-02-20 17:06:07 -050087 # Have the numbers, but rounding needs to add up to target_sum.
bungeman@google.com0abbff92013-07-27 20:37:56 +000088 delta = 0
89 coeffs_rounded_sum = sum(coeffs_rounded)
90 if coeffs_rounded_sum > target_sum:
Ben Wagner483c7722018-02-20 17:06:07 -050091 # The coeffs add up to too much.
92 # Subtract 1 from the ones which were rounded up the most.
bungeman@google.com0abbff92013-07-27 20:37:56 +000093 delta = -1
94
95 if coeffs_rounded_sum < target_sum:
Ben Wagner483c7722018-02-20 17:06:07 -050096 # The coeffs add up to too little.
97 # Add 1 to the ones which were rounded down the most.
bungeman@google.com0abbff92013-07-27 20:37:56 +000098 delta = 1
99
100 if delta:
101 print "Initial sum is 0x%0.2X, adjusting." % (coeffs_rounded_sum,)
102 coeff_diff = [(coeff_rounded - coeff) * delta
103 for coeff, coeff_rounded in zip(coeffs, coeffs_rounded)]
104
105 class IndexTracker:
106 def __init__(self, index, item):
107 self.index = index
108 self.item = item
109 def __lt__(self, other):
110 return self.item < other.item
111 def __repr__(self):
112 return "arr[%d] == %s" % (self.index, repr(self.item))
113
114 coeff_pkg = [IndexTracker(i, diff) for i, diff in enumerate(coeff_diff)]
115 coeff_pkg.sort()
116
Ben Wagner483c7722018-02-20 17:06:07 -0500117 # num_elements_to_force_round better be < (2 * sample_units_width + 1) or
bungeman@google.com0abbff92013-07-27 20:37:56 +0000118 # * our math was wildy wrong
119 # * an awful lot of the curve is out side our sample
120 # either is pretty bad, and probably means the results will not be useful.
121 num_elements_to_force_round = abs(coeffs_rounded_sum - target_sum)
122 for i in xrange(num_elements_to_force_round):
Ben Wagner483c7722018-02-20 17:06:07 -0500123 print "Adding %d to index %d to force round %f." % (
124 delta, coeff_pkg[i].index, coeffs[coeff_pkg[i].index])
bungeman@google.com0abbff92013-07-27 20:37:56 +0000125 coeffs_rounded[coeff_pkg[i].index] += delta
126
127 print "Prepending %d 0x00 for allignment." % (sample_align,)
128 coeffs_rounded_aligned = ([0] * int(sample_align)) + coeffs_rounded
129
Ben Wagner483c7722018-02-20 17:06:07 -0500130 print ', '.join(["0x%0.2X" % coeff_rounded
131 for coeff_rounded in coeffs_rounded_aligned])
bungeman@google.com0abbff92013-07-27 20:37:56 +0000132 print sum(coeffs), hex(sum(coeffs_rounded))
133 print