[media] dib8000: make a better estimation for dBm
authorMauro Carvalho Chehab <m.chehab@samsung.com>
Tue, 17 Dec 2013 00:45:19 +0000 (21:45 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 19 Dec 2013 10:17:46 +0000 (08:17 -0200)
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>
Acked-by: Patrick Boettcher <pboettcher@kernellabs.com>
drivers/media/dvb-frontends/dib8000.c

index faf469d1d4379918a965b38b0df4871626cb4513..7b10b73befbe0653a05f6d0516183846d011034e 100644 (file)
@@ -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))