diff mbox

[3/6,media] dib8000: make a better estimation for dBm

Message ID 1387294246-10155-4-git-send-email-m.chehab@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mauro Carvalho Chehab Dec. 17, 2013, 3:30 p.m. UTC
Use multiple linear segments to better interpolate the dBm
for the signal strength.

The table that converts from linear strength to dB was
empirically determinated with the help of a signal generator
(DTA-2111).

The entries from -35dBm to -22.5dBm were taken using just
the signal generator and the board.

For the entries from -36dBm to -51dBm, a 16 dB tap was used,
in order to extend its range.

Signals below to -51dBm are just linearly interpolated.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/dvb-frontends/dib8000.c | 111 ++++++++++++++++++++++++++++------
 1 file changed, 92 insertions(+), 19 deletions(-)
diff mbox

Patch

diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index faf469d1d437..7b10b73befbe 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -3843,35 +3843,108 @@  static const struct per_layer_regs per_layer_regs[] = {
 	{ 556, 581, 583 },
 };
 
+struct linear_segments {
+	unsigned x;
+	signed y;
+};
+
+/*
+ * Table to estimate signal strength in dBm.
+ * This table was empirically determinated by measuring the signal
+ * strength generated by a DTA-2111 RF generator directly connected into
+ * a dib8076 device (a PixelView PV-D231U stick), using a good quality
+ * 3 meters RC6 cable and good RC6 connectors.
+ * The real value can actually be different on other devices, depending
+ * on several factors, like if LNA is enabled or not, if diversity is
+ * enabled, type of connectors, etc.
+ * Yet, it is better to use this measure in dB than a random non-linear
+ * percentage value, especially for antenna adjustments.
+ * On my tests, the precision of the measure using this table is about
+ * 0.5 dB, with sounds reasonable enough.
+ */
+static struct linear_segments strength_to_db_table[] = {
+	{ 55953, 108500 },	/* -22.5 dBm */
+	{ 55394, 108000 },
+	{ 53834, 107000 },
+	{ 52863, 106000 },
+	{ 52239, 105000 },
+	{ 52012, 104000 },
+	{ 51803, 103000 },
+	{ 51566, 102000 },
+	{ 51356, 101000 },
+	{ 51112, 100000 },
+	{ 50869,  99000 },
+	{ 50600,  98000 },
+	{ 50363,  97000 },
+	{ 50117,  96000 },	/* -35 dBm */
+	{ 49889,  95000 },
+	{ 49680,  94000 },
+	{ 49493,  93000 },
+	{ 49302,  92000 },
+	{ 48929,  91000 },
+	{ 48416,  90000 },
+	{ 48035,  89000 },
+	{ 47593,  88000 },
+	{ 47282,  87000 },
+	{ 46953,  86000 },
+	{ 46698,  85000 },
+	{ 45617,  84000 },
+	{ 44773,  83000 },
+	{ 43845,  82000 },
+	{ 43020,  81000 },
+	{ 42010,  80000 },	/* -51 dBm */
+	{     0,      0 },
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+			     unsigned len)
+{
+	u64 tmp64;
+	u32 dx;
+	s32 dy;
+	int i, ret;
+
+	if (value >= segments[0].x)
+		return segments[0].y;
+	if (value < segments[len-1].x)
+		return segments[len-1].y;
+
+	for (i = 1; i < len - 1; i++) {
+		/* If value is identical, no need to interpolate */
+		if (value == segments[i].x)
+			return segments[i].y;
+		if (value > segments[i].x)
+			break;
+	}
+
+	/* Linear interpolation between the two (x,y) points */
+	dy = segments[i - 1].y - segments[i].y;
+	dx = segments[i - 1].x - segments[i].x;
+
+	tmp64 = value - segments[i].x;
+	tmp64 *= dy;
+	do_div(tmp64, dx);
+	ret = segments[i].y + tmp64;
+
+	return ret;
+}
+
 static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
 {
 	struct dib8000_state *state = fe->demodulator_priv;
 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
 	int i, lock;
-	u64 tmp;
 	u32 snr, val;
+	s32 db;
 	u16 strength;
 
 	/* Get Signal strength */
 	dib8000_read_signal_strength(fe, &strength);
-
-	/*
-	 * Estimate it in dBm
-	 * This calculus was empirically determinated by measuring the signal
-	 * strength generated by a DTA-2111 RF generator directly connected into
-	 * a dib8076 device. The real value can actually be different on other
-	 * devices, depending if LNA is enabled or not, if diversity is enabled,
-	 * etc.
-	 */
-	if (strength == 65535) {
-		c->strength.stat[0].svalue = -22000;
-	} else {
-		tmp = strength * 25000L;
-		do_div(tmp, 11646);
-		c->strength.stat[0].svalue = tmp - 142569;
-		if (c->strength.stat[0].svalue > -22000)
-			c->strength.stat[0].svalue = -22000;
-	}
+	val = strength;
+	db = interpolate_value(val,
+			       strength_to_db_table,
+			       ARRAY_SIZE(strength_to_db_table)) - 131000;
+	c->strength.stat[0].svalue = db;
 
 	/* Check if 1 second was elapsed */
 	if (!time_after(jiffies, state->get_stats_time))