1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Improved calculating signal strength and quality

This commit is contained in:
Klaus Schmidinger 2018-02-12 14:05:22 +01:00
parent 68f0f24670
commit 78831a72d5
3 changed files with 239 additions and 5 deletions

View File

@ -3546,3 +3546,6 @@ Daniel Scheller <d.scheller@gmx.net>
Onur Sentürk <onur@sentek.org> Onur Sentürk <onur@sentek.org>
for making the MTD mapper avoid immediately reusing unique PIDs when switching channels for making the MTD mapper avoid immediately reusing unique PIDs when switching channels
Helmut Binder <cco@aon.at>
for improving calculating signal strength and quality

View File

@ -9162,7 +9162,7 @@ Video Disk Recorder Revision History
a subdirectory. a subdirectory.
- SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details). - SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details).
2018-02-10: Version 2.3.9 2018-02-12: Version 2.3.9
- Updated the Italian OSD texts (thanks to Diego Pierotto). - Updated the Italian OSD texts (thanks to Diego Pierotto).
- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
@ -9270,3 +9270,4 @@ Video Disk Recorder Revision History
correct position in the list, rather than first being added at the end and then correct position in the list, rather than first being added at the end and then
jumping to the proper offset. jumping to the proper offset.
- Fixed getting the info of a newly edited recording (reported by Matthias Senzel). - Fixed getting the info of a newly edited recording (reported by Matthias Senzel).
- Improved calculating signal strength and quality (thanks to Helmut Binder).

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.c 4.14 2018/01/25 15:09:17 kls Exp $ * $Id: dvbdevice.c 4.15 2018/02/12 14:05:22 kls Exp $
*/ */
#include "dvbdevice.h" #include "dvbdevice.h"
@ -699,6 +699,212 @@ int dB1000toPercent(int dB1000, int Low, int High)
return 100 - v * v; return 100 - v * v;
} }
#define REF_S1(q1) (mod == QPSK) ? q1 : 0
#define REF_S2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == PSK_8) ? q2 : (mod == APSK_16) ? q3 : (mod == APSK_32) ? q4 : 0
#define REF_T1(q1, q2, q3) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : 0
#define REF_T2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_256) ? q4 : 0
#define REF_C1(q1, q2, q3, q4, q5) (mod == QAM_16) ? q1 : (mod == QAM_32) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_128) ? q4 : (mod == QAM_256) ? q5: 0
int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
{
// Strength in 0.001dBm (dBm x 1000)
cDvbTransponderParameters dtp(Channel->Parameters());
int ssi = 0; // 0-100
int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
if (Channel->IsTerr()) {
int pref = 0;
// NorDig Unified Ver. 2.6 - 3.4.4.6 Page 43 ff.
// reference values : pref-15dBm = 0%, pref+35dBm = 100%
if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
fec = cod; // adjustment for DVB-T
if (mod == QAM_AUTO) mod = QPSK;
switch (fec) { // dBm: Q4 Q16 Q64
case FEC_1_2: pref = REF_T1(-93, -87, -82); break;
default:
case FEC_2_3: pref = REF_T1(-91, -85, -80); break;
case FEC_3_4: pref = REF_T1(-90, -84, -78); break;
case FEC_5_6: pref = REF_T1(-89, -83, -77); break;
case FEC_7_8: pref = REF_T1(-88, -82, -76); break;
}
}
else { // DVB-T2
if (mod == QAM_AUTO) mod = QAM_64;
switch (fec) { // dBm: Q4 Q16 Q64 Q256
case FEC_1_2: pref = REF_T2(-96, -91, -86, -82); break;
default:
case FEC_3_5: pref = REF_T2(-95, -89, -85, -80); break;
case FEC_2_3: pref = REF_T2(-94, -88, -83, -78); break;
case FEC_3_4: pref = REF_T2(-93, -87, -82, -76); break;
case FEC_4_5: pref = REF_T2(-92, -86, -81, -75); break;
case FEC_5_6: pref = REF_T2(-92, -86, -80, -74); break;
}
}
if (pref) {
int prel = (Strength / 1000) - pref;
ssi = (prel < -15) ? 0 :
(prel < 0) ? (prel + 15) * 2 / 3 : // 0% - 10%
(prel < 20) ? prel * 4 + 10 : // 10% - 90%
(prel < 35) ? (prel - 20) * 2 / 3 + 90 : // 90% - 100%
100;
#ifdef DEBUG_SIGNALSTRENGTH
fprintf(stderr, "SSI: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(sys:%d, mod:%d, fec:%d)\n", Strength, pref, prel, ssi, dtp.System(), mod, fec);
#endif
}
}
else if (Channel->IsCable())
ssi = dB1000toPercent(Strength, -95000, -20000); // defaults
else if (Channel->IsSat())
ssi = dB1000toPercent(Strength, -95000, -20000); // defaults
return ssi;
}
#define IGNORE_BER 0
#define BER_ERROR_FREE (1000*1000*1000) // 1/10^-9
int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
{
#if IGNORE_BER
Ber = BER_ERROR_FREE; // assume/pretend to be biterror free
#endif
// Signal in 0.001dB (dB x 1000)
cDvbTransponderParameters dtp(Channel->Parameters());
int sqi = 0; // 0-100
int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
if (Channel->IsTerr()) { // QEF: BER 10^-6
int cnref = 0;
// NorDig Unified Ver. 2.6 - 3.4.4.7 Page 45 ff.
// reference values for QEF (BER 10^-11 at MPEG2 demux input)
if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
fec = cod; // adjustment for DVB-T
if (mod == QAM_AUTO) mod = QPSK;
switch (fec) { // 0.1 dB Q4 Q16 Q64 (Hierarchy=None)
case FEC_1_2: cnref = REF_T1(51, 108, 165); break;
default:
case FEC_2_3: cnref = REF_T1(69, 131, 187); break;
case FEC_3_4: cnref = REF_T1(79, 146, 202); break;
case FEC_5_6: cnref = REF_T1(89, 156, 216); break;
case FEC_7_8: cnref = REF_T1(97, 160, 225); break;
}
}
else { // DVB-T2
if (mod == QAM_AUTO) mod = QAM_64;
switch (fec) { // 0.1 dB Q4 Q16 Q64 Q256
case FEC_1_2: cnref = REF_T2(35, 87, 130, 170); break;
default:
case FEC_3_5: cnref = REF_T2(47, 101, 148, 194); break;
case FEC_2_3: cnref = REF_T2(56, 114, 162, 208); break;
case FEC_3_4: cnref = REF_T2(66, 125, 177, 229); break;
case FEC_4_5: cnref = REF_T2(72, 133, 187, 243); break;
case FEC_5_6: cnref = REF_T2(77, 138, 194, 251); break;
}
}
if (cnref) {
int cnrel = (Signal/100) - cnref; // 0.1 dB
int ber_sqi = 100; // 100%
int cnr_sqi = 0; // 0%
if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
(Ber >= 10000000) ? 100 : // <= 10^-7
(int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
// scale: -7dB/+3dB to reference-value
cnr_sqi = (cnrel < -70) ? 0 :
(cnrel < +30) ? (100 + (cnrel - 30)) :
100;
sqi = (cnr_sqi * ber_sqi) / 100;
// alternative: stretched scale: cnref-7dB = 0%, 30dB = 100%
// sqi = dB1000toPercent(Signal, (100*cnref)-7000, 30000);
}
else { // DVB-T2
ber_sqi = (Ber < 10000) ? 0 : // > 10^-4
(Ber >= 10000000) ? 100 * 100 / 6 : // <= 10^-7 : 16.67% -> SQI 0% .. 100%
(100 * 100 / 15); // 6.67% -> SQI 0% .. 40% || 100%
// scale: -3dB/+3dB to reference-value
sqi = (cnrel < -30) ? 0 :
(cnrel <= +30) ? (cnrel + 30) * ber_sqi / 1000 : // (0 .. 6) * 16,67 || 6.67
100;
// alternative: stretched scale: cnref-3dB = 0%, 32dB = 100%
// sqi = dB1000toPercent(Signal, (100*cnref)-3000, 32000);
}
#ifdef DEBUG_SIGNALQUALITY
fprintf(stderr, "SQI-T: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
#endif
}
}
else if (Channel->IsCable()) { // ! COMPLETELY UNTESTED !
if (mod == QAM_AUTO) mod = QAM_64;
// 0.1 dB Q16 Q32 Q64 Q128 Q256
int cnref = REF_C1(200, 230, 260, 290, 320); // minimum for BER<10^-4
if (cnref) {
int cnrel = (Signal / 100) - cnref; // 0.1 dB
int ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
(Ber >= 10000000) ? 100 : // <= 10^-7
(int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
// scale: -7dB/+3dB to reference-value
int cnr_sqi = (cnrel < -70) ? 0 :
(cnrel < +30) ? (100 + (cnrel - 30)) :
100;
sqi = (cnr_sqi * ber_sqi) / 100;
// alternative: stretched scale: cnref-7dB = 0%, 40dB = 100%
// sqi = dB1000toPercent(Signal, (100*cnref)-7000, 40000);
#ifdef DEBUG_SIGNALQUALITY
dsyslog("SQI-C: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
#endif
}
}
else if (Channel->IsSat()) {
int cnref = 0;
if (dtp.System() == DVB_SYSTEM_1) { // DVB-S
if (mod == QAM_AUTO) mod = QPSK;
switch (fec) { // 0.1 dB: Q4 : 10^-7
case FEC_1_2: cnref = REF_S1(38); break;
default:
case FEC_2_3: cnref = REF_S1(56); break;
case FEC_3_4: cnref = REF_S1(67); break;
case FEC_5_6: cnref = REF_S1(77); break;
case FEC_7_8: cnref = REF_S1(84); break;
}
if (cnref) {
//cnrel = (Signal/100) - cnref; // 0.1 dB
// scale: cnref-4dB = 0%, 15dB = 100%
sqi = dB1000toPercent(Signal, (100*cnref)-4000, 15000);
#ifdef DEBUG_SIGNALQUALITY
dsyslog("SQI-S1: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
#endif
}
}
else { // DVB-S2
if (mod == QAM_AUTO) mod = QAM_64;
switch (fec) { // 0.1 dB Q4 Q8 16A* 32A*
//case FEC_1_4: cnref = REF_S2(-14, 65, 90, 126); break;
//case FEC_1_3: cnref = REF_S2( -2, 65, 90, 126); break;
case FEC_2_5: cnref = REF_S2( 7, 65, 90, 126); break;
case FEC_1_2: cnref = REF_S2( 20, 65, 90, 126); break;
case FEC_3_5: cnref = REF_S2( 32, 65, 90, 126); break;
default:
case FEC_2_3: cnref = REF_S2( 41, 76, 90, 126); break;
case FEC_3_4: cnref = REF_S2( 50, 66, 102, 126); break;
case FEC_4_5: cnref = REF_S2( 57, 89, 110, 136); break;
case FEC_5_6: cnref = REF_S2( 62, 104, 116, 143); break;
case FEC_8_9: cnref = REF_S2( 72, 117, 129, 157); break;
case FEC_9_10: cnref = REF_S2( 74, 120, 131, 161); break;
}
if (cnref) {
// cnrel = (Signal/100) - cnref; // 0.1 dB
// scale: cnref-4dB = 0%, 20dB = 100%
sqi = dB1000toPercent(Signal, (100*cnref)-4000, 20000);
#ifdef DEBUG_SIGNALQUALITY
dsyslog("SQI-S2: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
#endif
}
}
}
return sqi;
}
int cDvbTuner::GetSignalStrength(void) const int cDvbTuner::GetSignalStrength(void) const
{ {
ClearEventQueue(); ClearEventQueue();
@ -710,14 +916,20 @@ int cDvbTuner::GetSignalStrength(void) const
memset(&CmdSeq, 0, sizeof(CmdSeq)); memset(&CmdSeq, 0, sizeof(CmdSeq));
CmdSeq.props = Props; CmdSeq.props = Props;
SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0); SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
SETCMD(DTV_MODULATION, 0);
SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
SETCMD(DTV_INNER_FEC, 0);
if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) { if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
esyslog("ERROR: frontend %d/%d: %m", adapter, frontend); esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
return -1; return -1;
} }
int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
int Signal = 0; int Signal = 0;
if (Props[0].u.st.len > 0) { if (Props[0].u.st.len > 0) {
switch (Props[0].u.st.stat[0].scale) { switch (Props[0].u.st.stat[0].scale) {
case FE_SCALE_DECIBEL: Signal = dB1000toPercent(Props[0].u.st.stat[0].svalue, -95000, -20000); // TODO use different values for DVB-S, -T, -C? case FE_SCALE_DECIBEL: Signal = StrengthToSSI(&channel, Props[0].u.st.stat[0].svalue, FeMod, FeCod, FeFec);
break; break;
case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF; case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
break; break;
@ -768,14 +980,32 @@ int cDvbTuner::GetSignalQuality(void) const
memset(&CmdSeq, 0, sizeof(CmdSeq)); memset(&CmdSeq, 0, sizeof(CmdSeq));
CmdSeq.props = Props; CmdSeq.props = Props;
SETCMD(DTV_STAT_CNR, 0); SETCMD(DTV_STAT_CNR, 0);
SETCMD(DTV_MODULATION, 0);
SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
SETCMD(DTV_INNER_FEC, 0);
SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) { if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
esyslog("ERROR: frontend %d/%d: %m", adapter, frontend); esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
return -1; return -1;
} }
int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
int Ber = BER_ERROR_FREE; // 1/10^-9
if (Props[4].u.st.len > 0 && Props[4].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[5].u.st.len > 0 && Props[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
uint64_t ebc = Props[4].u.st.stat[0].uvalue; // error bit count
uint64_t tbc = Props[5].u.st.stat[0].uvalue; // total bit count
if (ebc > 0) {
uint64_t BerRev = tbc / ebc; // reversed, for integer arithmetic
if (BerRev < BER_ERROR_FREE)
Ber = (int)BerRev;
}
}
int Cnr = 0; int Cnr = 0;
if (Props[0].u.st.len > 0) { if (Props[0].u.st.len > 0) {
switch (Props[0].u.st.stat[0].scale) { switch (Props[0].u.st.stat[0].scale) {
case FE_SCALE_DECIBEL: Cnr = dB1000toPercent(Props[0].u.st.stat[0].svalue, 5000, 20000); // TODO use different values for DVB-S, -T, -C? case FE_SCALE_DECIBEL: Cnr = SignalToSQI(&channel, Props[0].u.st.stat[0].svalue, Ber, FeMod, FeCod, FeFec);
break; break;
case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF; case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
break; break;
@ -1116,13 +1346,13 @@ bool cDvbTuner::SetFrontend(void)
SETCMD(DTV_HIERARCHY, dtp.Hierarchy()); SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
if (frontendType == SYS_DVBT2) { if (frontendType == SYS_DVBT2) {
// DVB-T2 // DVB-T2
SETCMD(DTV_INNER_FEC, dtp.CoderateH());
if (DvbApiVersion >= 0x0508) { if (DvbApiVersion >= 0x0508) {
SETCMD(DTV_STREAM_ID, dtp.StreamId()); SETCMD(DTV_STREAM_ID, dtp.StreamId());
} }
else if (DvbApiVersion >= 0x0503) else if (DvbApiVersion >= 0x0503)
SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId()); SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId());
} }
tuneTimeout = DVBT_TUNE_TIMEOUT; tuneTimeout = DVBT_TUNE_TIMEOUT;
lockTimeout = DVBT_LOCK_TIMEOUT; lockTimeout = DVBT_LOCK_TIMEOUT;
} }