Lab043: add hardware diagnostics and HackRF comparison tools
This commit is contained in:
17
data/processed/lab043_diagnostics/capture_triplets.csv
Normal file
17
data/processed/lab043_diagnostics/capture_triplets.csv
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
source,triplet,count,bit_errors,ber,mean_i,mean_q,median_i,median_q,std_i,std_q,mean_amplitude,mean_phase_error_deg,mean_distance_to_ideal,decision_cross_fraction,raw_mean_i,raw_mean_q,fitted_gain_i,fitted_gain_q
|
||||||
|
lab043_prbs11_s_20260819_134831,000,618,26,0.042071197411003236,-0.383010551932381,0.02764562694974822,-0.3665048003985516,0.029452696638587655,0.23064885120898107,0.31028090419369436,0.49896947141893955,-7.8956708685012496,0.6944003153099989,0.042071197411003236,-0.383010551932381,0.02764562694974822,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,001,626,8,0.012779552715654952,-0.4912906363346837,0.018636267614070716,-0.4764967027338469,0.026144887267764125,0.24269006389944242,0.30667428490022475,0.586409195973437,-5.494314642423132,0.5998968119242502,0.012779552715654952,-0.4912906363346837,0.018636267614070716,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,010,625,0,0.0,1.6246814910527565,0.021540864870758254,1.6232689830218876,0.024312702015861856,0.24557868253488369,0.33923505401863113,1.6592362427400138,0.18194257569663422,0.7093629876140989,0.0,1.6246814910527565,0.021540864870758254,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,011,623,0,0.0,1.507888339613931,0.027362614438028364,1.499955117966784,0.02131274610695385,0.2323442921990874,0.31797487033373506,1.540917677274962,0.5236092842361051,0.599722415704199,0.0,1.507888339613931,0.027362614438028364,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,100,626,0,0.0,-0.8627782853937753,-0.2999262964156233,-0.8705450786019031,-0.30817634309654046,0.2368292067405127,0.31394777549671404,0.9578798163510112,17.143319552998086,0.4677097487796899,0.0,-0.8627782853937753,-0.2999262964156233,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,101,622,0,0.0,-0.9853183896444535,-0.290203005512205,-0.9745048898520654,-0.30930749839713845,0.22008895048116267,0.31972987963350635,1.069647529275547,14.80231929336532,0.4353899021808402,0.0,-0.9853183896444535,-0.290203005512205,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,110,624,0,0.0,1.1217639844594565,-0.3035772157066439,1.1310492864236945,-0.29087932020583385,0.27164792642941604,0.33523556914475766,1.2139708847640265,-15.592910444294075,0.48678001136541427,0.0,1.1217639844594565,-0.3035772157066439,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,111,634,0,0.0,1.0177963357632442,-0.2857254059392602,0.9787287867259802,-0.30392693232926526,0.28513896636571545,0.3301477780970683,1.1124010421708548,-16.389369324426834,0.4743368758003392,0.0,1.0177963357632442,-0.2857254059392602,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,000,618,22,0.03559870550161812,-0.46422854876395536,-0.1034304947322828,-0.450617540491747,-0.08384365846908659,0.2970812100005612,0.2764371342120699,0.5552113454902189,4.975489960217222,0.6374530970020094,0.03559870550161812,-0.46422854876395536,-0.1034304947322828,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,001,626,5,0.007987220447284345,-0.6086025098841648,-0.09102967026250966,-0.593154030437537,-0.07621843397472354,0.2969390097675917,0.28426567583901835,0.679352068931168,3.5118628297753047,0.527946124467199,0.007987220447284345,-0.6086025098841648,-0.09102967026250966,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,010,625,0,0.0,1.543937892189543,-0.0866919401911572,1.5401352267056545,-0.08580489080415578,0.296974183803192,0.29581951510651777,1.5765627581653052,-4.197559508608589,0.6421798718369047,0.0,1.543937892189543,-0.0866919401911572,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,011,623,0,0.0,1.3844334140042036,-0.08532571149356706,1.3744620638063159,-0.08924519261103618,0.26685328732688507,0.2844049814454168,1.4183308010699238,-4.696533674284714,0.5093696634103756,0.0,1.3844334140042036,-0.08532571149356706,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,100,626,0,0.0,-0.9614469278519722,-0.2996346771243095,-0.9507264001164575,-0.2877579356042255,0.2858999743426548,0.2780537590113996,1.0354745742870346,15.35184388016101,0.45571081471161806,0.0,-0.9614469278519722,-0.2996346771243095,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,101,622,0,0.0,-1.1028098132631565,-0.2865285029053816,-1.0971437080692867,-0.28672431820918576,0.2777319065206098,0.2773121159933899,1.164923379747912,12.850190789658376,0.43898765209393537,0.0,-1.1028098132631565,-0.2865285029053816,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,110,624,0,0.0,1.0473064096865614,-0.30446287638539515,1.0398500615588286,-0.30154972207819863,0.31726665642731866,0.31265493779409337,1.145036505689775,-17.636126072712916,0.48953383056372857,0.0,1.0473064096865614,-0.30446287638539515,1.0,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,111,634,0,0.0,0.8838047295662679,-0.2988072133215322,0.8598290716063504,-0.31001570377948856,0.30258146260956686,0.2954051290073809,0.9925463363278624,-20.654607590716907,0.47726234856311894,0.0,0.8838047295662679,-0.2988072133215322,1.0,0.0
|
||||||
|
3
data/processed/lab043_diagnostics/dc_iq_metrics.csv
Normal file
3
data/processed/lab043_diagnostics/dc_iq_metrics.csv
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
capture,raw_bpsk_mean_i,raw_bpsk_mean_q,coarse_before_rrc_mean_i,coarse_before_rrc_mean_q,matched_mean_i,matched_mean_q,positive_center_i,positive_center_q,negative_center_i,negative_center_q,symbol_dc_i,symbol_dc_q,positive_distance_from_zero,negative_distance_from_zero,positive_decision_margin_i,negative_decision_margin_i,residual_std_i,residual_std_q,iq_std_ratio,iq_correlation,ellipse_axis_ratio,cluster_phase_separation_deg,negative_is_closer_to_boundary
|
||||||
|
lab043_prbs11_s_20260819_134831,-0.000737236196254884,-0.0009993250003590963,-0.0035866184049641804,-0.0020547927693326117,-0.039057998243808414,-0.022376535029459025,1.316916651234259,-0.135555308255011,-0.6813036323127601,-0.1363165494566035,0.3178065094607494,-0.13593592885580724,1.3238748837764716,0.6948070531149747,1.316916651234259,0.6813036323127601,0.3528092065580048,0.3591613286621408,0.9823140143517195,0.4949299078201867,1.720973769005295,162.80857605270015,True
|
||||||
|
lab043_prbs11_s_20260819_150001,-0.0006657749906019511,-0.0009936757629662666,-0.003953464860272102,0.0015903730102091952,-0.0430650724829096,0.017323925058185086,1.2138202803903815,-0.1941434021582646,-0.7849789639235105,-0.1952336579265019,0.21442065823343548,-0.19468853004238323,1.2292482799209319,0.8088931666108884,1.2138202803903815,0.7849789639235105,0.3918420026998634,0.3061660076990989,1.2798350987578189,0.5683356891913195,2.0067883608694936,156.94608113337333,True
|
||||||
|
49
data/processed/lab043_diagnostics/ideal_channel_triplets.csv
Normal file
49
data/processed/lab043_diagnostics/ideal_channel_triplets.csv
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
source,triplet,count,bit_errors,ber,mean_i,mean_q,median_i,median_q,std_i,std_q,mean_amplitude,mean_phase_error_deg,mean_distance_to_ideal,decision_cross_fraction,raw_mean_i,raw_mean_q,fitted_gain_i,fitted_gain_q,sample_phase,marker_score
|
||||||
|
без искажений,000,618,0,0.0,-1.0002931436799982,-3.231550594878434e-17,-1.000199150848986,-2.319552256062034e-17,0.010357093519487945,3.265577683360462e-16,1.0002931436799982,1.865020053989257e-15,0.008257521038058883,0.0,-0.7002312139878651,-1.8677900020981957e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,001,626,0,0.0,-0.9999796510040612,-5.090250830548143e-17,-0.999960846145106,-5.0648676345923463e-17,0.010322664900678936,3.2693891435801005e-16,0.9999796510040612,2.917838992654595e-15,0.008200634420287638,0.0,-0.7000117609620851,-3.1690521028700267e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,010,625,0,0.0,0.9996656101027557,-5.665573859282219e-18,0.9997287758415592,-1.976950863675177e-17,0.010214140548392219,3.215255041375122e-16,0.9996656101027557,-3.183082645139798e-16,0.008056123282006363,0.0,0.69979192416429,-7.907369434377148e-18,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,011,623,0,0.0,1.0000428840677498,-4.3416350411530316e-17,1.0000526981049074,-5.442655424073825e-17,0.010198050251563825,3.245666613153081e-16,1.0000428840677498,-2.4913640504576667e-15,0.00804844359529067,0.0,0.7000560257510929,-3.4335382214621765e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,100,626,0,0.0,-1.000125130099672,5.735360631441449e-17,-1.00010630034017,5.265207942418089e-17,0.010300836630339004,3.281107650887046e-16,1.000125130099672,-3.2889352554807928e-15,0.00818089388859184,0.0,-0.7001136001123113,4.409214806236349e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,101,622,0,0.0,-0.9996849230913982,1.0023266103027503e-17,-0.9996385783577552,2.3580954795874935e-17,0.010177697810059332,3.0848704318872783e-16,0.9996849230913982,-5.597698391419076e-16,0.00806103637993291,0.0,-0.6998054437585894,1.0957943474359258e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,110,624,0,0.0,1.0001671317135128,4.321013147730515e-17,1.0000061919503653,4.9544714803699065e-17,0.01016122023731124,3.3618993042126056e-16,1.0001671317135128,2.4804251249806343e-15,0.008053662299073073,0.0,0.700143002334285,2.6304918033938118e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
без искажений,111,634,0,0.0,1.0000674445201205,-1.0076005050440176e-17,0.999980779418755,-2.2358492137958885e-18,0.010336983321136445,3.3089869748917757e-16,1.0000674445201205,-5.646438653305923e-16,0.008248570840346733,0.0,0.7000732187064663,-1.0996370252882711e-17,0.700026005788434,-3.942638773738879e-18,0,0.9999345849172596
|
||||||
|
только SRO -3.5 ppm,000,618,0,0.0,-1.0007823562340121,-3.574668630819571e-17,-1.000878892829398,-4.3096068599418156e-17,0.012318977500386755,3.2273716564340147e-16,1.0007823562340121,2.0613001594081967e-15,0.00989708790253621,0.0,-0.7002980588855288,-3.1863576567390073e-17,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,001,626,0,0.0,-0.9756825166001841,-3.5137944174706555e-17,-0.9764796404233334,-3.399764234555552e-17,0.015474967835911041,3.3301062428152723e-16,0.9756825166001841,2.074517712909942e-15,0.02479755480588827,0.0,-0.6827344309254474,-3.12658141332338e-17,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,010,625,0,0.0,0.9991752242954434,-6.4629008792038566e-18,0.9990077802745452,-1.004275690703834e-17,0.012183624311424834,3.188338440579737e-16,0.9991752242954434,-3.629750966993994e-16,0.009808842813789232,0.0,0.6991734673397825,2.3163924670052718e-18,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,011,623,0,0.0,1.024346330590892,-2.2166208744888554e-17,1.0235396176905007,-3.032025209860568e-17,0.014902847080977328,3.4078402976628906e-16,1.024346330590892,-1.2355426929143958e-15,0.024724855270462344,0.0,0.7167869641894236,-8.499724167082658e-18,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,100,626,0,0.0,-1.0244438779762572,6.353925085997965e-17,-1.0233996653515027,6.721164976147591e-17,0.015214285979592818,3.4300871746429124e-16,1.0244438779762572,-3.5503879489943633e-15,0.024813236661930232,0.0,-0.7168552230313137,3.744986774399351e-17,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,101,622,0,0.0,-0.9991704855700663,3.781276373700251e-18,-0.9991312032539466,5.950964397953672e-18,0.01221593063466391,3.186349063739632e-16,0.9991704855700663,-2.0953093788571495e-16,0.009819473338403427,0.0,-0.6991701514138348,-4.19282840214353e-18,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,110,624,0,0.0,0.9758868931118758,3.370098110123651e-17,0.9765977242877031,4.857969605056626e-17,0.01525005133245707,3.241803988698192e-16,0.9758868931118758,1.9777270721475476e-15,0.024539569248432168,0.0,0.6828774435130773,3.0261697199855787e-17,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только SRO -3.5 ppm,111,634,0,0.0,1.0005460550201486,-7.442020366725188e-18,1.0003785050455694,-1.1930610215603022e-17,0.012193950170514516,3.3444527734491764e-16,1.0005460550201486,-3.931010026179579e-16,0.0097585801127184,0.0,0.7001327069682511,1.6406356047352882e-18,0.6997506046377366,6.844456406296741e-18,0,0.9999346349570075
|
||||||
|
только остаточная CFO +0.5 Гц,000,618,0,0.0,-1.0005405145730908,0.004549961910286652,-1.00491272276492,-0.004322898425968361,0.025524201284612764,0.2280583742146684,1.0264751200596467,-0.26129439402136373,0.20125941061500233,0.0,-0.5650484892946761,-0.3828705455373927,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,001,626,0,0.0,-0.9998959428731508,-0.0008962621558364577,-1.0041557696715198,8.636341190708949e-05,0.02547526333332098,0.22948062607379993,1.0261534184142616,0.05252364078134037,0.20211366611691822,0.0,-0.5625875851895938,-0.3856884185785349,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,010,625,0,0.0,0.9996889183875104,0.004700846876489959,1.004261223488352,0.010444191153138759,0.025396433412943842,0.2288982486402833,1.0258311542298981,0.26907954964012837,0.20141858594348247,0.0,0.5610054151536722,0.38775061638820946,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,011,623,0,0.0,1.0003136155716827,3.4486822409479976e-05,1.0041717059060316,-0.0024697565392285264,0.02505209930146019,0.22798813580706412,1.02621830655659,0.0028024989961719852,0.20126646057723502,0.0,0.563154707808065,0.3853641439636812,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,100,626,0,0.0,-1.0000339654342862,-0.0006265568535822356,-1.0033244935339916,0.0003252808581506445,0.02520603384419379,0.22957636782206733,1.0263027053107692,0.03464573073690392,0.20219190776611215,0.0,-0.56276918764136,-0.3855897463962108,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,101,622,0,0.0,-1.0000680279896892,-0.003539137840450598,-1.0051809482815732,-0.005368638038192208,0.025136907225291594,0.2273738046134359,1.0258509727043108,0.2021952278096826,0.2005775293136233,0.0,-0.5616663687148276,-0.3872426262422047,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,110,624,0,0.0,1.0003493297356336,-0.00023862510835228953,1.003998913544402,-0.0027415111063254626,0.024880920523000415,0.22842184999548698,1.0263458062858664,-0.015107834986988353,0.20164398697232905,0.0,0.563280023823765,0.3852241422373028,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только остаточная CFO +0.5 Гц,111,634,0,0.0,0.9993172683863958,-0.004973612686637713,1.0043640009783315,-0.013679792148858297,0.026371452807718986,0.2322349575295939,1.026243513361753,-0.2854746049298769,0.2047590780151857,0.0,0.564523012585757,0.38216081009474,0.5629914300776463,0.38522391595958455,0,0.9999280444571523
|
||||||
|
только дробный тайминг +0.45 отсчёта,000,618,0,0.0,-1.0003638012416773,-3.0252294566842336e-17,-1.0005356098392824,-3.7044751764603454e-17,0.010475350747601793,3.2440759102727786e-16,1.0003638012416773,1.7359202118856331e-15,0.008457735275899755,0.0,-0.7002418470555495,-1.889007563240263e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,001,626,0,0.0,-1.0066732143452937,-4.0565671076486225e-17,-1.00691435655856,-4.4394892301683e-17,0.010452756320897299,3.4228529340362064e-16,1.0066732143452937,2.3249870198486524e-15,0.010319843387043347,0.0,-0.7046583554098391,-2.609488810820273e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,010,625,0,0.0,0.9996027050274428,-9.712055303191803e-18,1.0000230291841714,-7.168164568802029e-18,0.010349486168542758,3.2499701805702617e-16,0.9996027050274428,-5.482731339619978e-16,0.008246199029850996,0.0,0.6997090894545838,-9.082718025071803e-18,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,011,623,0,0.0,0.9933400871648654,-3.09980102937199e-17,0.9931306357271391,-3.472607047820509e-17,0.010346435368622857,3.3191797815916734e-16,0.9933400871648654,-1.792013727894548e-15,0.01019642312258512,0.0,0.695325337169614,-2.3968301829757193e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,100,626,0,0.0,-0.9934302797691696,5.710805323666649e-17,-0.9933071060195908,5.649654133962659e-17,0.010440463684732759,3.3398785380709777e-16,0.9934302797691696,-3.290863708919959e-15,0.010229384089777475,0.0,-0.6953884708373359,4.22452035604784e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,101,622,0,0.0,-0.9996160803149469,1.0068447487737392e-17,-0.999591221030594,5.095173944048246e-18,0.010303765244567465,3.1909266230762487e-16,0.9996160803149469,-5.677845403307687e-16,0.008284727942094228,0.0,-0.6997184519845104,9.332218555871944e-18,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,110,624,0,0.0,1.0068601181800312,5.1274568470286146e-17,1.0071179752064987,4.41633107541207e-17,0.010284552131954717,3.165606839390655e-16,1.0068601181800312,2.921491693734847e-15,0.010265914506814007,0.0,0.7047891857000755,3.3590551978438037e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только дробный тайминг +0.45 отсчёта,111,634,0,0.0,1.000139444652914,-1.4804421122525754e-17,1.0001928569904543,-1.551872881456763e-17,0.010528991154430876,3.3383587290276977e-16,1.000139444652914,-8.482542163393518e-16,0.008496080555841655,0.0,0.7000848003172331,-1.2648535487033274e-17,0.6999871908463614,-2.2853116588788615e-18,0,0.9999310608776122
|
||||||
|
только gain 0.8 exp(j0.4),000,618,0,0.0,-1.0002931436799984,-3.0749782282223135e-17,-1.0001991508489865,-4.784243150873803e-17,0.01035709351948793,3.374807398016914e-16,1.0002931436799984,1.7713674781598607e-15,0.00825752103805889,0.0,-0.5601849711902923,-4.6682887991908416e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),001,626,0,0.0,-0.9999796510040615,-4.4847758642261754e-17,-0.9999608461451065,-3.823838122535474e-17,0.010322664900678938,3.452168453310068e-16,0.9999796510040615,2.587879187532213e-15,0.008200634420287619,0.0,-0.5600094087696681,-5.4568814526207665e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),010,625,0,0.0,0.999665610102756,-1.5328703374741225e-17,0.9997287758415596,-2.930001910058419e-17,0.010214140548392205,3.4254527550932965e-16,0.999665610102756,-8.776577063978714e-16,0.008056123282006349,0.0,0.5598335393314321,2.0859494169813997e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),011,623,0,0.0,1.0000428840677504,-2.7867207539056634e-17,1.0000526981049074,-4.428089958865185e-17,0.010198050251563857,3.332117265358971e-16,1.0000428840677504,-1.593680383785695e-15,0.008048443595290694,0.0,0.5600448206008745,1.384878310661252e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),100,626,0,0.0,-1.000125130099672,5.609609395039414e-17,-1.0001063003401705,5.694612309865554e-17,0.010300836630339,3.4519657615267763e-16,1.000125130099672,-3.2089743184576383e-15,0.008180893888591846,0.0,-0.5600908800898492,1.9575581223834506e-18,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),101,622,0,0.0,-0.9996849230913984,2.3329385177129972e-17,-0.9996385783577553,2.0259028300406906e-17,0.010177697810059335,3.1641855090325095e-16,0.9996849230913984,-1.3264384101346905e-15,0.008061036379932916,0.0,-0.5598443550068715,-1.6379514748914518e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),110,624,0,0.0,1.000167131713513,4.9211323157627446e-17,1.0000061919503656,7.343065997585499e-17,0.01016122023731122,3.50800124033128e-16,1.000167131713513,2.8223391809253912e-15,0.008053662299073058,0.0,0.560114401867428,5.701802344448213e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
только gain 0.8 exp(j0.4),111,634,0,0.0,1.000067444520121,-2.1521286820925234e-18,0.9999807794187555,3.710105026339808e-18,0.010336983321136441,3.349680700082323e-16,1.000067444520121,-1.2447380416433816e-16,0.008248570840346733,0.0,0.5600585749651731,2.825048565631281e-17,0.5600208046307471,2.9453735999436935e-17,0,0.9999345849172553
|
||||||
|
SRO+CFO+тайминг+gain,000,618,0,0.0,-1.0008739380208023,0.004498948845240244,-1.005080406028307,-0.004361719690771267,0.026024678539132717,0.22814068318270816,1.0268173236880707,-0.25884438081360245,0.20143911283968863,0.0,-0.45206512025923085,-0.3063209888858998,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,001,626,0,0.0,-0.9823019021809795,0.001204055473202981,-0.9878249499315466,4.156196054697222e-05,0.027395732431980575,0.22541011703430533,1.008091068292765,0.05489278772153692,0.19789849243314606,0.0,-0.4426873177416418,-0.30208300435230034,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,010,625,0,0.0,0.999362255013195,0.004654117666767775,1.002986936682864,0.010501764441009346,0.0259608260786354,0.22881066805317504,1.0254939126135476,0.2713706497876178,0.20140909844363705,0.0,0.44856457681225054,0.30997676707616456,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,011,623,0,0.0,1.017915216676135,0.0021017602527817316,1.0217547138909593,-0.00245080190836759,0.027329356258693597,0.23199593146838193,1.0442741764209607,0.005174664040996683,0.20800775846795144,0.0,0.4577050318370308,0.31454322851352845,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,100,626,0,0.0,-1.0176467683195116,-0.0027368196688400304,-1.0220645803845851,0.00028675669554682927,0.02735493603936188,0.23366851397382177,1.0443833063543895,0.03701711192526389,0.20903063165815075,0.0,-0.4573885058595173,-0.3147464836921453,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,101,622,0,0.0,-0.9997132505633392,-0.003477528412469562,-1.0044639688035528,-0.00542350542258045,0.025798700852509238,0.22726189467977656,1.025482843217309,0.2044860738237234,0.20054343328903368,0.0,-0.44908510579133737,-0.30955509976178675,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,110,624,0,0.0,0.9827607716190412,-0.002308901450231822,0.9870492042172159,-0.0026420834401516876,0.026584820479141544,0.2244138076193021,1.008300020364011,-0.012738449607494238,0.19734362767979766,0.0,0.4432343182823996,0.30172687552483723,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
SRO+CFO+тайминг+gain,111,634,0,0.0,0.9996435990296828,-0.0049247567236749635,1.0047359022406326,-0.013658464529557147,0.02684179097279431,0.2323116906510399,1.0265781789685229,-0.2830263105576786,0.2049269126760559,0.0,0.4516422982133428,0.3057502139069036,0.45028557339382663,0.308077559953349,0,0.9999251628507277
|
||||||
|
12
data/processed/lab043_diagnostics/input_manifest.json
Normal file
12
data/processed/lab043_diagnostics/input_manifest.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"metadata_file": "lab043_prbs11_s_20260819_134831.json",
|
||||||
|
"iq_file": "lab043_prbs11_s_20260819_134831.npy",
|
||||||
|
"verified_sha256": "d573d9bd0332a0473be1ffe4ed149dea0281c4dbcc4c4c9c199642d072441c5a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata_file": "lab043_prbs11_s_20260819_150001.json",
|
||||||
|
"iq_file": "lab043_prbs11_s_20260819_150001.npy",
|
||||||
|
"verified_sha256": "a8216afd7dd4cab7c3ba5190b5710a7a7e5409022ff2d8e595f2de9fb66fb98e"
|
||||||
|
}
|
||||||
|
]
|
||||||
241
data/processed/lab043_diagnostics/phase_sweep.csv
Normal file
241
data/processed/lab043_diagnostics/phase_sweep.csv
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
capture,phase,marker_start_symbol,marker_score,bit_errors,ber,errors_000,errors_001,errors_other,negative_mean_i,positive_mean_i,negative_p95_i,positive_p05_i,eye_opening_i_p05_p95,negative_std_i,positive_std_i
|
||||||
|
lab043_prbs11_s_20260819_134831,0,586,0.924068356732625,157,0.0314,68,10,79,-0.6659855894081477,1.3321491526148732,0.02197636699212176,0.5153775876666505,0.4934012206745288,0.44149976728803997,0.48611989882415996
|
||||||
|
lab043_prbs11_s_20260819_134831,1,586,0.9262820060960705,149,0.0298,68,11,70,-0.6675787901438206,1.3305648488916857,0.013431160824582315,0.5196217955495075,0.5061906347249252,0.4357475541277015,0.48112700759873595
|
||||||
|
lab043_prbs11_s_20260819_134831,2,586,0.9282879781464108,138,0.0276,67,11,60,-0.6690672324773898,1.3290847185615742,0.00014108579110438583,0.5207803237329575,0.5206392379418531,0.43055048660654,0.4766579101640469
|
||||||
|
lab043_prbs11_s_20260819_134831,3,586,0.9300999930009172,131,0.0262,66,12,53,-0.6704536467219613,1.3277060465584962,-0.01106213573751081,0.5197077007403111,0.5307698364778219,0.4259001559804359,0.47269968728744854
|
||||||
|
lab043_prbs11_s_20260819_134831,4,586,0.9317365070503667,125,0.025,65,12,48,-0.6717345798917904,1.326432266585467,-0.015315377723127056,0.5258536899544993,0.5411690676776264,0.42178857657272195,0.469238852656125
|
||||||
|
lab043_prbs11_s_20260819_134831,5,586,0.9332057315555816,123,0.0246,66,12,45,-0.6729162505234412,1.325257194832493,-0.029152140390238588,0.5296849180093909,0.5588370583996295,0.41820532028934493,0.46626504041157174
|
||||||
|
lab043_prbs11_s_20260819_134831,6,586,0.9345250635092867,119,0.0238,66,12,41,-0.6739969909846792,1.3241824896191439,-0.033574355942173346,0.5319286479373455,0.5655030038795189,0.4151412062825228,0.463766800199258
|
||||||
|
lab043_prbs11_s_20260819_134831,7,586,0.9357003336616172,115,0.023,65,14,36,-0.6749776845704568,1.323207272583108,-0.037353314517459706,0.5265870431201793,0.5639403576376391,0.41258696804320005,0.46173546836226703
|
||||||
|
lab043_prbs11_s_20260819_134831,8,586,0.9367402353717993,113,0.0226,65,14,34,-0.6758620135490878,1.3223278820191957,-0.037842149618524834,0.5291888031993269,0.5670309528178518,0.4105321757386238,0.4601594742611121
|
||||||
|
lab043_prbs11_s_20260819_134831,9,586,0.9376537191227973,110,0.022,65,15,30,-0.6766494157506379,1.3215448769579816,-0.03743961249028052,0.5318021840719668,0.5692417965622473,0.40896472824925595,0.4590233575126271
|
||||||
|
lab043_prbs11_s_20260819_134831,10,586,0.9384502410644282,107,0.0214,65,16,26,-0.677341811262274,1.3208563480347628,-0.037301566197318094,0.532061466340558,0.569363032537876,0.40787072253200674,0.4583189793636613
|
||||||
|
lab043_prbs11_s_20260819_134831,11,586,0.9391426846547335,107,0.0214,64,17,26,-0.6779379018155665,1.3202635862679672,-0.0386775782025146,0.5369355209215974,0.575613099124112,0.40724688774211454,0.4580375046444359
|
||||||
|
lab043_prbs11_s_20260819_134831,12,586,0.9397258213443209,112,0.0224,65,21,26,-0.6784389875676701,1.3197652987609885,-0.04064856701239005,0.531323197728947,0.571971764741337,0.4070801352524581,0.4581676638964428
|
||||||
|
lab043_prbs11_s_20260819_134831,13,586,0.9402067944573552,112,0.0224,65,22,25,-0.6788469905867284,1.3193595741792135,-0.036783207169693036,0.5327464083048169,0.56952961547451,0.4073557444063936,0.45869865551571565
|
||||||
|
lab043_prbs11_s_20260819_134831,14,586,0.9405964679420825,113,0.0226,65,23,25,-0.6791619835150654,1.3190463402859751,-0.03608819507699531,0.5277087370562249,0.5637969321332202,0.40806611659058806,0.45962004933566947
|
||||||
|
lab043_prbs11_s_20260819_134831,15,586,0.9408956225107673,111,0.0222,63,25,23,-0.6793810337222935,1.3188285133347917,-0.03549528662576219,0.5252491807356717,0.5607444673614339,0.4092038030467577,0.46092520510912455
|
||||||
|
lab043_prbs11_s_20260819_134831,16,586,0.9411076281687515,110,0.022,61,29,20,-0.67950746578176,1.318702787317939,-0.032252812033025005,0.5243189208677008,0.5565717329007258,0.410757389355189,0.46260119187367693
|
||||||
|
lab043_prbs11_s_20260819_134831,17,586,0.9412320107209128,115,0.023,62,32,21,-0.6795404267468858,1.3186700104188331,-0.03157895893808972,0.5237762185105839,0.5553551774486736,0.4127140648728039,0.4646388733075375
|
||||||
|
lab043_prbs11_s_20260819_134831,18,586,0.9412757814507751,117,0.0234,60,36,21,-0.6794757338502475,1.3187343420468016,-0.025614823610149693,0.5179247387965543,0.543539562406704,0.41506765641744686,0.4670386304128064
|
||||||
|
lab043_prbs11_s_20260819_134831,19,586,0.9412398992116264,113,0.0226,58,36,19,-0.6793181657338452,1.3188910302455215,-0.022137833134507123,0.510578536931114,0.5327163700656211,0.4178076759422869,0.4697875706909071
|
||||||
|
lab043_prbs11_s_20260819_134831,20,586,0.9411251741182902,118,0.0236,59,41,18,-0.6790663612863513,1.3191414285253793,-0.0216130554984655,0.5019142224580972,0.5235272779565627,0.4209281968087695,0.4728802868347639
|
||||||
|
lab043_prbs11_s_20260819_134831,21,586,0.9409315145529543,120,0.024,60,44,16,-0.6787199031825831,1.3194859518810607,-0.015929683893213566,0.4885202605775044,0.504449944470718,0.4244173310060206,0.4763104488794568
|
||||||
|
lab043_prbs11_s_20260819_134831,22,586,0.9406617037707291,130,0.026,62,51,17,-0.6782764561014185,1.3199269225924062,-0.016354104853254635,0.4822156559631635,0.49856976081641813,0.4282677724451274,0.4800718169861131
|
||||||
|
lab043_prbs11_s_20260819_134831,23,586,0.9403148986756253,135,0.027,63,55,17,-0.6777378301736409,1.320462540637062,-0.01262301143745062,0.4744610404502794,0.4870840518877301,0.43247548180508505,0.48416186899767083
|
||||||
|
lab043_prbs11_s_20260819_134831,24,586,0.9398849757013514,141,0.0282,63,58,20,-0.6771017996144919,1.3210950193701922,-0.005833199267161328,0.46803567614730995,0.47386887541447126,0.4370356927198379,0.4885712909655701
|
||||||
|
lab043_prbs11_s_20260819_134831,25,586,0.9393778126621425,146,0.0292,63,62,21,-0.6763648500132214,1.3218278535768004,0.003456825197673221,0.4644765739899177,0.4610197487922445,0.44194060503515714,0.4933005680073378
|
||||||
|
lab043_prbs11_s_20260819_134831,26,586,0.9387908148161194,151,0.0302,62,66,23,-0.675530514772735,1.3226575295857885,0.008019679423990251,0.45657705807380683,0.4485573786498166,0.4471869580679684,0.4983497256037323
|
||||||
|
lab043_prbs11_s_20260819_134831,27,586,0.9381215403366853,157,0.0314,62,72,23,-0.6745939465758469,1.3235888676451593,0.013340574037275916,0.4514373853652713,0.4380968113279954,0.45277225148973954,0.5037160135219635
|
||||||
|
lab043_prbs11_s_20260819_134831,28,586,0.9373635252911054,165,0.033,61,81,23,-0.6735543304567546,1.3246226781696488,0.02257720722841847,0.44645592409363916,0.42387871686522066,0.45869685707129143,0.5094001354811456
|
||||||
|
lab043_prbs11_s_20260819_134831,29,586,0.936524190160605,174,0.0348,61,88,25,-0.6724100408531668,1.3257605776438193,0.03268969195234952,0.447688578175528,0.4149988862231785,0.4649548708482804,0.5154003071853183
|
||||||
|
lab043_prbs11_s_20260819_134831,30,586,0.9355918903763845,181,0.0362,61,94,26,-0.6711605214115208,1.327003119314351,0.039616621174715094,0.442086418975391,0.40246979780067593,0.47154403847070653,0.5217154669786309
|
||||||
|
lab043_prbs11_s_20260819_134831,31,586,0.9345650504372153,194,0.0388,60,106,28,-0.6698043859971023,1.3283516815752792,0.04873288080784271,0.43784633870190903,0.3891134578940663,0.4784711527799905,0.5283499711359179
|
||||||
|
lab043_prbs11_s_20260819_134831,32,586,0.9334372177221079,213,0.0426,62,122,29,-0.66833631864754,1.329811550702705,0.05800173748918579,0.4308454800266391,0.3728437425374533,0.48573526525380833,0.5353073144721195
|
||||||
|
lab043_prbs11_s_20260819_134831,33,586,0.9322069563437837,224,0.0448,62,132,30,-0.6667558227123775,1.3313832205736105,0.07183704582068064,0.4200540116296282,0.34821696580894757,0.4933370047666099,0.5425895417234553
|
||||||
|
lab043_prbs11_s_20260819_134831,34,586,0.9308676778745424,229,0.0458,61,137,31,-0.6650624901094689,1.3330670969912617,0.08375347838224566,0.40546075477407545,0.3217072763918298,0.5012826302551984,0.5501992829879024
|
||||||
|
lab043_prbs11_s_20260819_134831,35,586,0.9294147941803909,244,0.0488,62,152,30,-0.6632520775741212,1.3348673995244176,0.10190967877819591,0.39073059605428945,0.28882091727609355,0.5095711832383397,0.5581422912475964
|
||||||
|
lab043_prbs11_s_20260819_134831,36,586,0.9278396478821677,257,0.0514,62,165,30,-0.6613194777589604,1.3367892069991676,0.11985635205964691,0.3788278732975236,0.2589715212378767,0.5182126298932007,0.5664278333246304
|
||||||
|
lab043_prbs11_s_20260819_134831,37,586,0.9261356027963862,273,0.0546,64,178,31,-0.6592656494139274,1.3388315660195764,0.1374325118235685,0.36301249548787495,0.22557998366430645,0.5272083294393253,0.5750614108765331
|
||||||
|
lab043_prbs11_s_20260819_134831,38,586,0.9242920971965133,297,0.0594,65,197,35,-0.6570843562930794,1.3410006780061239,0.14880389142562775,0.3480637258157819,0.19925983439015413,0.5365693950594468,0.5840485619048263
|
||||||
|
lab043_prbs11_s_20260819_134831,39,586,0.9223018373171441,322,0.0644,64,222,36,-0.6547732839066877,1.3432988445235858,0.16606967115149351,0.33663340020839533,0.1705637290569018,0.5463009156883587,0.5933985806688477
|
||||||
|
lab043_prbs11_s_20260819_134831,40,586,0.9201532944540215,339,0.0678,65,236,38,-0.6523314659509368,1.3457270264795822,0.18650168471123202,0.3266940848866488,0.1401924001754168,0.5564127909044201,0.6031221883620318
|
||||||
|
lab043_prbs11_s_20260819_134831,41,586,0.9178308054391655,369,0.0738,65,266,38,-0.6497500988219137,1.3482939783155041,0.2035465696098755,0.3160256768986581,0.11247910728878263,0.5669153566572448,0.6132288077392158
|
||||||
|
lab043_prbs11_s_20260819_134831,42,586,0.9153295666582568,396,0.0792,65,290,41,-0.647025535097874,1.3510033270845638,0.223987231110259,0.2999646655674145,0.07597743445715552,0.577819036655808,0.6237312564604816
|
||||||
|
lab043_prbs11_s_20260819_134831,43,586,0.9126318234289537,420,0.084,66,311,43,-0.644159537189783,1.3538533202177383,0.24104645218505208,0.2899788847326014,0.04893243254754934,0.5891328825106152,0.6346412087590747
|
||||||
|
lab043_prbs11_s_20260819_134831,44,586,0.9097222194150218,441,0.0882,66,331,44,-0.6411415234166019,1.3568544803041127,0.26513564174587706,0.27492581777459335,0.009790176028716291,0.6008753124576476,0.6459713688956571
|
||||||
|
lab043_prbs11_s_20260819_134831,45,586,0.9065806004094584,473,0.0946,68,357,48,-0.6379653373922171,1.3600129293502998,0.29121035979075666,0.26386841374609254,-0.02734194604466411,0.6130581569182658,0.6577368846012867
|
||||||
|
lab043_prbs11_s_20260819_134831,46,586,0.9031911415569012,495,0.099,66,377,52,-0.634630384904031,1.363329258250599,0.31668311605544147,0.24731231338610657,-0.0693708026693349,0.625696243445256,0.6699530002247139
|
||||||
|
lab043_prbs11_s_20260819_134831,47,586,0.8995374131645946,527,0.1054,66,400,61,-0.6311278268066707,1.3668122567893775,0.3428397833370038,0.23154986948692444,-0.11128991385007939,0.6388051313657893,0.6826366817310998
|
||||||
|
lab043_prbs11_s_20260819_134831,48,586,0.8955902981434892,552,0.1104,66,419,67,-0.6274474698300331,1.3704720613138126,0.3697232783241035,0.21511410024322755,-0.15460917808087596,0.6524035826895436,0.6958085568088207
|
||||||
|
lab043_prbs11_s_20260819_134831,49,586,0.891322087704631,579,0.1158,67,439,73,-0.6235924249179406,1.3743055782527218,0.400749845376256,0.19920841583837662,-0.2015414295378794,0.6665100890035865,0.7094851844524234
|
||||||
|
lab043_prbs11_s_20260819_134831,50,586,0.8867076363376143,600,0.12,66,456,78,-0.6195497505552633,1.378325676851108,0.42732126936756015,0.1819789447439618,-0.24534232462359834,0.6811452040759839,0.7236856925878135
|
||||||
|
lab043_prbs11_s_20260819_134831,51,586,0.881719142769753,625,0.125,65,468,92,-0.6153097718596897,1.3825419779632206,0.45794752658444177,0.1669315922139847,-0.29101593437045703,0.696330768686415,0.7384354853038256
|
||||||
|
lab043_prbs11_s_20260819_134831,52,586,0.8763223652482677,642,0.1284,64,482,96,-0.6108685371982946,1.3869584111546276,0.4906368049548605,0.1461684186673358,-0.34446838628752474,0.7120904154018045,0.7537595380275287
|
||||||
|
lab043_prbs11_s_20260819_134831,53,586,0.8704746972554525,670,0.134,66,500,104,-0.6062169024152849,1.3915840695168298,0.525744095863514,0.12892186411425946,-0.3968222317492546,0.7284475325311637,0.769671733449158
|
||||||
|
lab043_prbs11_s_20260819_134831,54,586,0.8641427345485114,686,0.1372,67,510,109,-0.6013434696876506,1.3964302872232497,0.562700896601655,0.11374915370102695,-0.44895174290062806,0.7454271004301627,0.7862103546525474
|
||||||
|
lab043_prbs11_s_20260819_134831,55,586,0.8572765618668114,706,0.1412,66,520,120,-0.5962397244734674,1.40150553126751,0.6068766875647564,0.08437798678887234,-0.5224987007758841,0.7630579668838491,0.8033987049483196
|
||||||
|
lab043_prbs11_s_20260819_134831,56,586,0.8498313583912235,732,0.1464,66,536,130,-0.5908925982655493,1.4068227971774974,0.6409859493646387,0.05890271495647785,-0.5820832344081609,0.7813744741639989,0.8212701356474056
|
||||||
|
lab043_prbs11_s_20260819_134831,57,586,0.8417564404146284,754,0.1508,66,552,136,-0.5852960729058512,1.4123880695036752,0.6809752105860043,0.03476761371093425,-0.64620759687507,0.8004025111153523,0.8398494115453475
|
||||||
|
lab043_prbs11_s_20260819_134831,58,586,0.8329858684074203,775,0.155,67,557,151,-0.5794334810494629,1.4182179225144356,0.7136668163278557,0.008780353876684476,-0.7048864624511711,0.8201776614132081,0.8591791205615152
|
||||||
|
lab043_prbs11_s_20260819_134831,59,586,0.8234585776646915,792,0.1584,68,561,163,-0.5732934134312082,1.4243237017614665,0.7548409680838847,-0.021568938316315397,-0.7764099064002,0.8407347762247983,0.8792864440997307
|
||||||
|
lab043_prbs11_s_20260819_134831,60,586,0.8131039255833545,811,0.1622,68,567,176,-0.5668633014985085,1.4307179056099797,0.7967125260128085,-0.051172663610445236,-0.8478851896232538,0.8621172682286867,0.9002172960821052
|
||||||
|
lab043_prbs11_s_20260819_134831,61,586,0.8018483842993291,827,0.1654,67,570,190,-0.5601248196928548,1.437418757281896,0.8395386361391474,-0.07797079235106036,-0.9175094284902077,0.8843633963438916,0.9220060340503344
|
||||||
|
lab043_prbs11_s_20260819_134831,62,586,0.7896092902158751,850,0.17,66,576,208,-0.553066734719211,1.4444374273414464,0.8872602283459761,-0.1133329387461816,-1.0005931670921577,0.9075132978603166,0.9446982087798524
|
||||||
|
lab043_prbs11_s_20260819_134831,63,586,0.7763032590187886,865,0.173,66,581,218,-0.5456677269396993,1.451795116369896,0.9350567347422475,-0.14902898947593413,-1.0840857242181816,0.9316171298625062,0.968350711856813
|
||||||
|
lab043_prbs11_s_20260819_134831,64,586,0.7618314567782936,895,0.179,66,586,243,-0.5379110294744874,1.4595084976147192,0.9890940632783062,-0.18543382871990735,-1.1745278919982136,0.9567265963199282,0.9930063980804443
|
||||||
|
lab043_prbs11_s_20260819_134831,65,586,0.7460976021827928,926,0.1852,65,593,268,-0.5297751578077421,1.4675989356143988,1.0459640950498237,-0.22967158639287796,-1.2756356814427017,0.9828921088718267,1.0187127660833912
|
||||||
|
lab043_prbs11_s_20260819_134831,66,586,0.7290153781645049,950,0.19,66,597,287,-0.5212406198426084,1.4760858136148287,1.1029437579297552,-0.266133120395618,-1.369076878325373,1.0101678921179758,1.0455296835842123
|
||||||
|
lab043_prbs11_s_20260819_134831,67,586,0.710461323169548,984,0.1968,65,599,320,-0.5122838088189564,1.484992606547404,1.1630707747921019,-0.3038538060469409,-1.4669245808390428,1.038619120840168,1.0735199645458262
|
||||||
|
lab043_prbs11_s_20260819_134831,68,586,0.6903395923304086,1008,0.2016,64,600,344,-0.5028781825932538,1.4943457083346703,1.2251148829423737,-0.33704909723940946,-1.5621639801817833,1.068311857276025,1.102753959176679
|
||||||
|
lab043_prbs11_s_20260819_134831,69,586,0.6685455540236415,1038,0.2076,63,600,375,-0.49300138999685317,1.5041673453282185,1.2848137905322061,-0.37650198068558777,-1.661315771217794,1.0993096803844238,1.1332953756268866
|
||||||
|
lab043_prbs11_s_20260819_134831,70,586,0.6449873260393597,1070,0.214,65,601,404,-0.482620678572517,1.5144900870836508,1.3545372228715682,-0.4213864371305915,-1.7759236600021597,1.1316951524537058,1.1652176787424533
|
||||||
|
lab043_prbs11_s_20260819_134831,71,586,0.61955659042444,1103,0.2206,65,604,434,-0.47170675180452304,1.5253430665142893,1.4224890529940577,-0.46611556974109564,-1.8886046227351534,1.1655454175360629,1.198607012301622
|
||||||
|
lab043_prbs11_s_20260819_134831,72,587,0.5954608661168048,1366,0.2732,222,1,1143,-1.4882440898321838,0.5144824427795643,1.115475074876603,-2.4578561143309803,-3.5733311892075834,1.652595224158021,1.6394984667937402
|
||||||
|
lab043_prbs11_s_20260819_134831,73,587,0.5709718112566252,1370,0.274,222,1,1147,-1.4886710879758849,0.5140578291488311,1.1240524274258572,-2.4600623807981563,-3.5841148082240135,1.653657328172379,1.6403870173298185
|
||||||
|
lab043_prbs11_s_20260819_134831,74,587,0.5446275541078681,1374,0.2748,219,1,1154,-1.4891849142983795,0.5135468722194412,1.1310218677319783,-2.462103167092029,-3.5931250348240074,1.6556985703278773,1.6422474956269457
|
||||||
|
lab043_prbs11_s_20260819_134831,75,587,0.5164085734545684,1374,0.2748,219,1,1154,-1.4897889472280719,0.5129462124293643,1.1374784850017052,-2.4772739774713615,-3.6147524624730667,1.65873752264181,1.6451054533683516
|
||||||
|
lab043_prbs11_s_20260819_134831,76,587,0.48630627290417194,1381,0.2762,219,1,1161,-1.4904810449524872,0.5122579796304141,1.1495834346413443,-2.4938258320080964,-3.6434092666494404,1.6627920051533485,1.6489743203022946
|
||||||
|
lab043_prbs11_s_20260819_134831,77,587,0.4543565461515319,1374,0.2748,217,1,1156,-1.4912557456510007,0.5114876051424236,1.161575521004454,-2.5107959163324423,-3.6723714373368965,1.6678553779471745,1.6538504617277194
|
||||||
|
lab043_prbs11_s_20260819_134831,78,587,0.42067304571618463,1384,0.2768,216,2,1166,-1.4921109152545389,0.5106372111170456,1.1648387165353824,-2.5226230513328187,-3.687461767868201,1.6739331412142666,1.659749228129709
|
||||||
|
lab043_prbs11_s_20260819_134831,79,587,0.3853436264563874,1402,0.2804,215,2,1185,-1.4930483743722471,0.5097049871120807,1.1745621306734675,-2.5302126735933013,-3.7047748042667688,1.6810366333122717,1.6666760725905139
|
||||||
|
lab043_prbs11_s_20260819_134831,80,587,0.3485344051319883,1406,0.2812,215,3,1188,-1.4940553113657125,0.5087036732210931,1.181238696032629,-2.5397457650077806,-3.72098446104041,1.6891650062395938,1.6746211214953113
|
||||||
|
lab043_prbs11_s_20260819_134831,81,587,0.31045914415176334,1422,0.2844,214,3,1205,-1.495137210113542,0.5076278161894447,1.1891782501805872,-2.5449063798040976,-3.734084629984685,1.6983345677190063,1.6836036376672632
|
||||||
|
lab043_prbs11_s_20260819_134831,82,587,0.27136197406778606,1438,0.2876,214,5,1219,-1.496291483709909,0.5064799884767431,1.2009326483837413,-2.55998523912394,-3.760917887507681,1.7085401075305717,1.6936295291022385
|
||||||
|
lab043_prbs11_s_20260819_134831,83,585,0.2527395916761685,1121,0.2242,70,7,1044,-0.49832793585463625,1.4988705448402035,1.3736296634717124,-0.3334044605643227,-1.7070341240360352,1.1498568488757268,1.1630400481057463
|
||||||
|
lab043_prbs11_s_20260819_134831,84,585,0.2985711939100713,1094,0.2188,70,7,1017,-0.5071736704878383,1.4900742080071077,1.306950074506932,-0.2821894755818229,-1.5891395500887548,1.1133218183388403,1.1271796155776306
|
||||||
|
lab043_prbs11_s_20260819_134831,85,585,0.3434385869149458,1060,0.212,70,7,983,-0.5156412864220489,1.481653878320635,1.238309500008264,-0.23431956040204197,-1.472629060410306,1.0781963694593713,1.0927430430681224
|
||||||
|
lab043_prbs11_s_20260819_134831,86,585,0.38698516659094745,1018,0.2036,71,7,940,-0.5237566007346964,1.4735838828753094,1.1770014757503542,-0.1940133996180635,-1.3710148753684177,1.0444097228616873,1.0596584402993738
|
||||||
|
lab043_prbs11_s_20260819_134831,87,585,0.42891254022572756,976,0.1952,72,7,897,-0.5315316853779258,1.4658522171331596,1.1158536131187755,-0.15382036403424967,-1.2696739771530252,1.0119128881113073,1.0278751358533167
|
||||||
|
lab043_prbs11_s_20260819_134831,88,585,0.4689855704108766,932,0.1864,72,6,854,-0.5389839331261742,1.4584415854473267,1.0576565070622677,-0.1095902554305312,-1.167246762492799,0.9806503187127675,0.9973358211599097
|
||||||
|
lab043_prbs11_s_20260819_134831,89,585,0.5070300136098886,899,0.1798,72,5,822,-0.5461271185540193,1.4513382901654697,1.0045603484971137,-0.06702916421708442,-1.0715895127141981,0.9505667174999127,0.9679876281126482
|
||||||
|
lab043_prbs11_s_20260819_134831,90,585,0.5429270343462076,865,0.173,71,5,789,-0.5529764715608292,1.4445271864375158,0.952859630023093,-0.03363830647057635,-0.9864979364936693,0.9216212008679424,0.939792193489485
|
||||||
|
lab043_prbs11_s_20260819_134831,91,585,0.5765869412729584,827,0.1654,71,5,751,-0.5595471664191328,1.4379931847295981,0.9034910289027511,-0.0051241857010318895,-0.908615214603783,0.8937655945449989,0.9127013034132604
|
||||||
|
lab043_prbs11_s_20260819_134831,92,585,0.6080018658836429,802,0.1604,71,5,726,-0.565847950876964,1.4317275861442875,0.8527865839941436,0.02742614804610433,-0.8253604359480393,0.8669638401674792,0.8866743288468447
|
||||||
|
lab043_prbs11_s_20260819_134831,93,585,0.6371972137239146,771,0.1542,72,5,694,-0.5718913239957532,1.4257179614194595,0.8055769557401598,0.059359446792131246,-0.7462175089480285,0.841175071703383,0.8616710556103849
|
||||||
|
lab043_prbs11_s_20260819_134831,94,585,0.6642050846943454,720,0.144,72,5,643,-0.577690492707118,1.4199511773758093,0.754519442293612,0.09148898351324294,-0.663030458780369,0.8163644044322313,0.8376635450795781
|
||||||
|
lab043_prbs11_s_20260819_134831,95,585,0.6891208826216834,688,0.1376,72,5,611,-0.5832531920360579,1.4144195421835288,0.7053548620828973,0.12306607813185709,-0.5822887839510402,0.7924936831680537,0.8146100496025348
|
||||||
|
lab043_prbs11_s_20260819_134831,96,585,0.7120259259176022,653,0.1306,72,5,576,-0.5885887840703432,1.409113746036152,0.6575101744869604,0.15823460360088815,-0.4992755708860722,0.7695354321724214,0.792484855883515
|
||||||
|
lab043_prbs11_s_20260819_134831,97,585,0.7330186397789855,611,0.1222,72,5,534,-0.5937108647462519,1.4040202689220558,0.613996298013993,0.19135171080536673,-0.4226445872086263,0.7474669348659341,0.7712588089510071
|
||||||
|
lab043_prbs11_s_20260819_134831,98,585,0.7522476655823649,589,0.1178,71,5,513,-0.5986212834466316,1.3991372717860189,0.5830232151853914,0.21322800623133015,-0.3697952089540612,0.7262562643096853,0.7509101876935861
|
||||||
|
lab043_prbs11_s_20260819_134831,99,585,0.7698198513523438,560,0.112,71,5,484,-0.6033326097469355,1.3944522552456682,0.5431868983285664,0.24208954971997185,-0.3010973486085945,0.7058744883690341,0.73140495570644
|
||||||
|
lab043_prbs11_s_20260819_134831,100,585,0.7858570785133816,536,0.1072,71,5,460,-0.6078495832608549,1.3899605061550409,0.507236529655775,0.27000713147359984,-0.2372293981821752,0.6863067964254232,0.712724678773947
|
||||||
|
lab043_prbs11_s_20260819_134831,101,585,0.8004778294427455,508,0.1016,70,5,433,-0.6121795102409284,1.3856547590623716,0.4666818227893659,0.2887793655390671,-0.1779024572502988,0.6675316057633957,0.6948456670415167
|
||||||
|
lab043_prbs11_s_20260819_134831,102,585,0.8138072478497561,480,0.096,70,5,405,-0.6163303747520613,1.3815270744886756,0.43434103163991616,0.3119829860037918,-0.12235804563612435,0.649527938907296,0.6777514675882365
|
||||||
|
lab043_prbs11_s_20260819_134831,103,585,0.825936438868285,459,0.0918,70,5,384,-0.6203088050360722,1.37757086120665,0.3927214845425293,0.3336555778701171,-0.05906590667241218,0.6322742335503748,0.6614207630231035
|
||||||
|
lab043_prbs11_s_20260819_134831,104,585,0.8369754762106737,432,0.0864,70,5,357,-0.6241199472811542,1.3737810017662875,0.36629452089459297,0.3448151414077251,-0.021479379486867844,0.615756453350285,0.6458306532270578
|
||||||
|
lab043_prbs11_s_20260819_134831,105,585,0.8470272757368669,402,0.0804,70,6,326,-0.6277684995729623,1.3701528243177519,0.333442582025133,0.3542206598841969,0.02077807785906388,0.5999585132136214,0.630969419513661
|
||||||
|
lab043_prbs11_s_20260819_134831,106,585,0.8561746296047691,384,0.0768,69,6,309,-0.6312611193271471,1.3666797086228246,0.2990540942333866,0.3724256144556353,0.07337152022224874,0.5848679922723099,0.6168204896807794
|
||||||
|
lab043_prbs11_s_20260819_134831,107,585,0.8645047630290654,349,0.0698,69,7,273,-0.6346008355336884,1.3633586426065076,0.26837572756922323,0.3910283744580488,0.12265264688882555,0.570468199391636,0.6033714744734193
|
||||||
|
lab043_prbs11_s_20260819_134831,108,585,0.8720816730958266,325,0.065,71,7,247,-0.6377937159608613,1.3601835923851502,0.2418574807638858,0.4035878472160463,0.1617303664521605,0.5567488890194826,0.5906071862392183
|
||||||
|
lab043_prbs11_s_20260819_134831,109,585,0.878975348097475,315,0.063,71,8,236,-0.640844731075646,1.357149615248669,0.21130031135525065,0.4272201999021476,0.21591988854689695,0.5436956243172907,0.5785075076913357
|
||||||
|
lab043_prbs11_s_20260819_134831,110,585,0.8852517061033369,297,0.0594,70,8,219,-0.6437568729782485,1.3542537358058342,0.18826605011066166,0.4407779277829532,0.25251187767229155,0.5312991939778278,0.5670615036523904
|
||||||
|
lab043_prbs11_s_20260819_134831,111,585,0.8909649854387707,275,0.055,69,8,198,-0.6465348997466879,1.3514912225494646,0.16706089578027344,0.44795246091882135,0.2808915651385479,0.519551686134255,0.5562594340369276
|
||||||
|
lab043_prbs11_s_20260819_134831,112,585,0.8961705981865468,265,0.053,70,8,187,-0.6491795112363157,1.3488613795324556,0.1511313549460599,0.4571982616136997,0.3060669066676398,0.5084438790546874,0.5460894042083458
|
||||||
|
lab043_prbs11_s_20260819_134831,113,585,0.9009122334341652,243,0.0486,70,8,165,-0.6516954005035124,1.3463595399061596,0.1357231250740756,0.463881016601406,0.32815789152733044,0.4979671411262529,0.5365411889740964
|
||||||
|
lab043_prbs11_s_20260819_134831,114,585,0.9052272030396968,230,0.046,70,8,152,-0.6540887508206481,1.3439795549278515,0.1156627375480785,0.4763779659763822,0.3607152284283037,0.48810532519443006,0.5276012041588062
|
||||||
|
lab043_prbs11_s_20260819_134831,115,585,0.9091507077424639,214,0.0428,70,8,136,-0.6563598119306858,1.3417211762492216,0.09530136969884168,0.4806262430272686,0.3853248733284269,0.47885623355066814,0.5192567324340971
|
||||||
|
lab043_prbs11_s_20260819_134831,116,585,0.9127254509326868,203,0.0406,70,8,125,-0.6585137572238061,1.339579259370184,0.07858830173998757,0.49406019172842885,0.4154718899884413,0.4702090731153832,0.5115020620239884
|
||||||
|
lab043_prbs11_s_20260819_134831,117,585,0.9159789295941559,190,0.038,71,8,111,-0.6605507260013056,1.3375536657673492,0.0655630904105539,0.5023098290012687,0.43674673859071483,0.46215733508278645,0.504320616517932
|
||||||
|
lab043_prbs11_s_20260819_134831,118,585,0.9189359906731527,173,0.0346,70,9,94,-0.6624724205189682,1.3356427026909496,0.047532757396522074,0.506334638995639,0.45880188159911695,0.45469447722708994,0.4977043770358277
|
||||||
|
lab043_prbs11_s_20260819_134831,119,585,0.9216289413767563,167,0.0334,69,9,89,-0.6642845875772625,1.3338406554327418,0.03405947465219247,0.5123100715774552,0.4782505969252627,0.44781136018939566,0.4916410975859823
|
||||||
|
lab043_prbs11_s_20260819_150001,0,566,0.8417098657962399,349,0.0698,35,0,314,-0.7439153794882191,1.2546545508320184,0.25431658178195643,0.27049012910009473,0.016173547318138304,0.6254484632423968,0.6234819346312261
|
||||||
|
lab043_prbs11_s_20260819_150001,1,566,0.8535170004870393,316,0.0632,34,0,282,-0.7465341473446708,1.252050407127936,0.2205672564249182,0.29895849701632554,0.07839124059140734,0.6079750482923494,0.6065043063107486
|
||||||
|
lab043_prbs11_s_20260819_150001,2,566,0.8642035402208976,285,0.057,35,0,250,-0.7490403700583727,1.2495581800735835,0.18941463870948091,0.3237550362285323,0.13434039751905139,0.5912431647847993,0.5902617438476941
|
||||||
|
lab043_prbs11_s_20260819_150001,3,566,0.8738675296079155,254,0.0508,35,0,219,-0.751439403025019,1.2471725441797479,0.15384049086087628,0.3457923915906471,0.19195190072977084,0.5752296767714061,0.5747334451697673
|
||||||
|
lab043_prbs11_s_20260819_150001,4,566,0.8826120011515349,233,0.0466,36,0,197,-0.7537365076353416,1.2448882674372117,0.12557351999688407,0.36993302493861413,0.24435950494173006,0.5599284069843365,0.5599088046200422
|
||||||
|
lab043_prbs11_s_20260819_150001,5,566,0.8905311363245768,207,0.0414,35,0,172,-0.7559308233336942,1.242706205595971,0.10004855252678625,0.389722156761372,0.28967360423458577,0.545321802573142,0.5457741379730258
|
||||||
|
lab043_prbs11_s_20260819_150001,6,566,0.8976849469112597,190,0.038,35,0,155,-0.7580274671808072,1.2406212701708208,0.07784377677452371,0.4091406079381435,0.3312968311636198,0.5314036676272855,0.5323203579380574
|
||||||
|
lab043_prbs11_s_20260819_150001,7,566,0.9041477012162931,166,0.0332,35,0,131,-0.7600279784130624,1.2386319305210347,0.04712413013313975,0.43151542165151313,0.38439129151837337,0.5181628218191525,0.5195355944094538
|
||||||
|
lab043_prbs11_s_20260819_150001,8,566,0.909997930914499,146,0.0292,35,0,111,-0.761935738366064,1.2367348241936194,0.023351916480462403,0.4486510510573269,0.42529913457686447,0.5055870303121734,0.5074113387877242
|
||||||
|
lab043_prbs11_s_20260819_150001,9,566,0.9152881378652608,126,0.0252,34,0,92,-0.763758177913763,1.234922561811324,0.0016712655791742779,0.4631321305082548,0.4614608649290805,0.49366953466042657,0.49593484369741736
|
||||||
|
lab043_prbs11_s_20260819_150001,10,566,0.9200727433534758,115,0.023,34,0,81,-0.7654893428543181,1.2332010643255618,-0.01451699159171784,0.4792643446056017,0.4937813361973195,0.48239876905779105,0.48509885409971004
|
||||||
|
lab043_prbs11_s_20260819_150001,11,566,0.9243996298480085,97,0.0194,34,0,63,-0.7671359826435864,1.2315636199718942,-0.025025537965609947,0.48990599920324307,0.514931537168853,0.4717716215992969,0.4748970960843038
|
||||||
|
lab043_prbs11_s_20260819_150001,12,566,0.9283108406024309,85,0.017,34,0,51,-0.7686992989460641,1.230009033796354,-0.045079690809859005,0.5002514395863755,0.5453311303962345,0.4617790488669972,0.46531949657426935
|
||||||
|
lab043_prbs11_s_20260819_150001,13,566,0.9318464547890782,78,0.0156,34,0,44,-0.7701827028970867,1.2285339137126308,-0.05980730327558621,0.5121656105010041,0.5719729137765903,0.4524141904187549,0.4563582523644184
|
||||||
|
lab043_prbs11_s_20260819_150001,14,566,0.9350372044926236,73,0.0146,34,0,39,-0.771585623914577,1.2271388271164583,-0.07101072758506645,0.5204197246686815,0.5914304522537479,0.4436733625330999,0.44800663970660404
|
||||||
|
lab043_prbs11_s_20260819_150001,15,566,0.9379180038148098,66,0.0132,34,0,32,-0.7729087099113112,1.2258231297132431,-0.09012031794945441,0.5312915969196479,0.6214119148691023,0.43555013679123905,0.44026004352497944
|
||||||
|
lab043_prbs11_s_20260819_150001,16,566,0.9405126829583762,52,0.0104,33,0,19,-0.7741587638208428,1.2245800565594886,-0.09309025247189073,0.5442500621483274,0.6373403146202181,0.42803842563689565,0.4331083381464462
|
||||||
|
lab043_prbs11_s_20260819_150001,17,566,0.942851707959703,48,0.0096,32,1,15,-0.7753312267978071,1.2234141410423087,-0.10212819033122356,0.5465290839255482,0.6486572742567718,0.42112431648107823,0.4265400063554966
|
||||||
|
lab043_prbs11_s_20260819_150001,18,566,0.9449571235041081,43,0.0086,32,1,10,-0.7764327432782724,1.2223187758305811,-0.1111497323314854,0.5541036182593458,0.6652533505908312,0.41480692303529265,0.4205525985222578
|
||||||
|
lab043_prbs11_s_20260819_150001,19,566,0.9468509232912231,41,0.0082,32,1,8,-0.7774615431907207,1.2212957211111013,-0.11702021334973679,0.5569028797811826,0.6739230931309194,0.40908000089051655,0.41513679682071275
|
||||||
|
lab043_prbs11_s_20260819_150001,20,566,0.948546535094071,38,0.0076,32,1,5,-0.7784194394063935,1.2203431741363622,-0.12929890338526115,0.5615605285849865,0.6908594319702477,0.4039316263972235,0.41028104714989594
|
||||||
|
lab043_prbs11_s_20260819_150001,21,566,0.9500618734017223,34,0.0068,32,1,1,-0.7793036461044882,1.219463905170127,-0.13779167904761155,0.5740715701339134,0.711863249181525,0.3993585179878287,0.4059813992131384
|
||||||
|
lab043_prbs11_s_20260819_150001,22,566,0.9514106916743266,32,0.0064,31,1,0,-0.7801262660430124,1.2186458790405945,-0.13861152238483265,0.5776106644492217,0.7162221868340544,0.3953518237493205,0.4022277574257924
|
||||||
|
lab043_prbs11_s_20260819_150001,23,566,0.9526081281105556,31,0.0062,30,1,0,-0.7808778682099851,1.2178984740935415,-0.1440613880254913,0.5808559029715669,0.7249172909970582,0.39189939115119543,0.39901080816809203
|
||||||
|
lab043_prbs11_s_20260819_150001,24,566,0.9536646985278557,31,0.0062,30,1,0,-0.7815593307696798,1.2172208170686831,-0.14861733700853194,0.5812320677490579,0.7298494047575899,0.3889959254410948,0.3963206692536148
|
||||||
|
lab043_prbs11_s_20260819_150001,25,566,0.95458920148356,29,0.0058,28,1,0,-0.7821773161236624,1.2166062827697277,-0.14975389028746344,0.5794252854037184,0.7291791756911818,0.386626213482415,0.39414442913630715
|
||||||
|
lab043_prbs11_s_20260819_150001,26,566,0.9553923010079891,29,0.0058,28,1,0,-0.7827286057937527,1.2160580717017058,-0.1542039363354876,0.5768920820989916,0.7310960184344791,0.3847837035256762,0.3924725051528404
|
||||||
|
lab043_prbs11_s_20260819_150001,27,566,0.9560854653083438,28,0.0056,27,1,0,-0.7832127802497072,1.2155766010520472,-0.1549672160226195,0.5739162841832407,0.7288835002058602,0.38345563055182,0.3912942796375709
|
||||||
|
lab043_prbs11_s_20260819_150001,28,566,0.9566721990787159,28,0.0056,27,1,0,-0.7836324102077048,1.2151593144603867,-0.15495033829807434,0.5683276072259524,0.7232779455240268,0.3826308221086911,0.390598507110402
|
||||||
|
lab043_prbs11_s_20260819_150001,29,566,0.9571583729318379,25,0.005,24,1,0,-0.78398907502942,1.2148046413847864,-0.15273054345508078,0.5679351867868732,0.7206657302419539,0.38229914812809707,0.39037099808567155
|
||||||
|
lab043_prbs11_s_20260819_150001,30,566,0.9575511614557676,26,0.0052,24,2,0,-0.7842803897592053,1.2145149534624253,-0.15347663136120857,0.5640667319159941,0.7175433632772027,0.38244617317358054,0.390603672111513
|
||||||
|
lab043_prbs11_s_20260819_150001,31,566,0.9578576886172656,26,0.0052,23,3,0,-0.784507657929072,1.2142889544406954,-0.15029576184784055,0.5617746976095612,0.7120704594574018,0.38306276919942556,0.39128392146984536
|
||||||
|
lab043_prbs11_s_20260819_150001,32,566,0.9580792311261221,25,0.005,22,3,0,-0.7846697079506403,1.214127809365398,-0.1480383685223169,0.5590103865816685,0.7070487551039853,0.38413417309950204,0.39239698380054905
|
||||||
|
lab043_prbs11_s_20260819_150001,33,566,0.958223344127079,25,0.005,22,3,0,-0.7847683796286135,1.2140296887059694,-0.1423187476789247,0.5553674840126356,0.6976862316915603,0.38564961580266244,0.39393595116095764
|
||||||
|
lab043_prbs11_s_20260819_150001,34,566,0.958287736928995,27,0.0054,23,4,0,-0.7848045304825814,1.2139937397315215,-0.1404910785978791,0.5518194085296737,0.6923104871275528,0.387595497176645,0.3958878386811557
|
||||||
|
lab043_prbs11_s_20260819_150001,35,566,0.9582806868206216,27,0.0054,22,5,0,-0.7847736725476696,1.2140244253445,-0.13822038981787882,0.5486491289249864,0.6868695187428653,0.3899598529677354,0.39824173759932097
|
||||||
|
lab043_prbs11_s_20260819_150001,36,566,0.9582012831543106,25,0.005,20,5,0,-0.7846797993516798,1.2141177743184135,-0.13154797891600561,0.5463319540670548,0.6778799329830605,0.39273443782438466,0.4009874774157728
|
||||||
|
lab043_prbs11_s_20260819_150001,37,566,0.9580492238140073,27,0.0054,20,7,0,-0.7845231195774928,1.2142735791357435,-0.12510151328191355,0.5447493248674221,0.6698508381493357,0.39590514793431686,0.4041123415338196
|
||||||
|
lab043_prbs11_s_20260819_150001,38,566,0.9578324874148139,27,0.0054,19,8,0,-0.7842965322928345,1.214498901074577,-0.12125803429269681,0.5403986788927823,0.661656713185479,0.39946484028741336,0.4076106171710976
|
||||||
|
lab043_prbs11_s_20260819_150001,39,566,0.9575469522030455,27,0.0054,19,8,0,-0.7840074180766032,1.2147864007718503,-0.11783094449829692,0.5387342618077324,0.6565652063060293,0.4034027941377667,0.4114746178460792
|
||||||
|
lab043_prbs11_s_20260819_150001,40,566,0.9571908913895233,29,0.0058,18,11,0,-0.7836530694346844,1.2151387706020473,-0.1077898149007571,0.5331912831795246,0.6409810980802817,0.4077083548555245,0.41569638952718135
|
||||||
|
lab043_prbs11_s_20260819_150001,41,566,0.9567753093131954,32,0.0064,19,13,0,-0.7832308856796534,1.2155585967294074,-0.10392345570960683,0.5317296681245018,0.6356531238341087,0.41237519335539286,0.4202656625389943
|
||||||
|
lab043_prbs11_s_20260819_150001,42,566,0.9562868164705285,34,0.0068,18,16,0,-0.7827422858508964,1.216044468038976,-0.10309576807434677,0.5314307063775014,0.6345264744518482,0.41739549305055945,0.4251789504612106
|
||||||
|
lab043_prbs11_s_20260819_150001,43,566,0.9557285535551558,34,0.0068,16,18,0,-0.7821843394239875,1.2165992986900673,-0.09940056303014612,0.5311655248378344,0.6305660878679805,0.4227649444402489,0.430431500098699
|
||||||
|
lab043_prbs11_s_20260819_150001,44,566,0.9551024894443848,39,0.0078,15,24,0,-0.7815594441487375,1.2172207043227743,-0.09410315492442063,0.5267703008939283,0.620873455818349,0.42847825734748884,0.4360202952182474
|
||||||
|
lab043_prbs11_s_20260819_150001,45,566,0.9544050863778095,44,0.0088,15,29,0,-0.7808638273056479,1.2179124365883607,-0.08729533702611139,0.5206745033526428,0.6079698403787541,0.4345323063449011,0.4419368162154012
|
||||||
|
lab043_prbs11_s_20260819_150001,46,566,0.9536340747856367,49,0.0098,15,34,0,-0.780096220427802,1.2186757568701598,-0.08512327895039921,0.5135397178324697,0.5986629967828688,0.440918893170941,0.44817843658505
|
||||||
|
lab043_prbs11_s_20260819_150001,47,566,0.9527883719797645,57,0.0114,15,42,0,-0.77925582093452,1.2195114632669486,-0.07687351461382276,0.5107387538112685,0.5876122684250913,0.44763737870702275,0.45475443575834257
|
||||||
|
lab043_prbs11_s_20260819_150001,48,566,0.9518664435010262,62,0.0124,14,48,0,-0.7783404283607672,1.2204217439555674,-0.06906867002931712,0.4994613285213756,0.5685299985506928,0.4546916423280267,0.4616546617897829
|
||||||
|
lab043_prbs11_s_20260819_150001,49,566,0.9508576924163983,72,0.0144,14,58,0,-0.7773511635914253,1.2214054843105613,-0.05629674040838482,0.4931608197836313,0.5494575601920161,0.4620785191923222,0.468878403074615
|
||||||
|
lab043_prbs11_s_20260819_150001,50,566,0.9497648596757319,78,0.0156,14,64,0,-0.7762850265894883,1.2224656676156391,-0.050689975121733066,0.48599406701553116,0.5366840421372643,0.4697954141188885,0.47643312851931596
|
||||||
|
lab043_prbs11_s_20260819_150001,51,566,0.9485792494521454,88,0.0176,14,74,0,-0.775140365164218,1.223603936835103,-0.04562944182554662,0.47328120406322627,0.5189106458887729,0.47784647975352407,0.48431759436615496
|
||||||
|
lab043_prbs11_s_20260819_150001,52,566,0.9472985194803859,97,0.0194,14,83,0,-0.7739147108046895,1.2248227466948167,-0.03604306763158382,0.4656197206811681,0.5016627883127519,0.4862355831864577,0.49253834484945747
|
||||||
|
lab043_prbs11_s_20260819_150001,53,566,0.9459214674097104,110,0.022,14,96,0,-0.7726045204213935,1.2261256204983921,-0.028934860414004268,0.4555293575257747,0.484464217939779,0.4949653251995523,0.5010965375959032
|
||||||
|
lab043_prbs11_s_20260819_150001,54,566,0.9444299072269519,118,0.0236,14,104,0,-0.7712117829787346,1.2275105803885182,-0.010771779220566966,0.44505172451720554,0.45582350373777253,0.5040404385165715,0.5099976127503403
|
||||||
|
lab043_prbs11_s_20260819_150001,55,566,0.9428237938254342,133,0.0266,14,119,0,-0.7697320033280102,1.2289820964113551,0.007944326875064455,0.4310884799767135,0.42314415310164905,0.5134690700893166,0.5192469264440223
|
||||||
|
lab043_prbs11_s_20260819_150001,56,566,0.9410954530809613,140,0.028,14,126,0,-0.7681625976571363,1.2305427379500435,0.028681582782509336,0.4148199649948024,0.3861383822122931,0.523257648218952,0.5288548179893505
|
||||||
|
lab043_prbs11_s_20260819_150001,57,566,0.9392327953708226,160,0.032,14,146,0,-0.766502124730572,1.2321939381917366,0.045324569668410475,0.4028496617967551,0.3575250921283446,0.533410421871228,0.5388275628478103
|
||||||
|
lab043_prbs11_s_20260819_150001,58,566,0.9372277780499362,182,0.0364,14,166,2,-0.7647461494962304,1.233940107421578,0.06308869882462921,0.38464188531489907,0.32155318649026987,0.5439384678161941,0.5491740094009836
|
||||||
|
lab043_prbs11_s_20260819_150001,59,566,0.9350687799899847,208,0.0416,14,190,4,-0.7628919510676594,1.2357839513316025,0.08100528965007356,0.36470302086761913,0.2836977312175456,0.5548534655775965,0.5599082999986138
|
||||||
|
lab043_prbs11_s_20260819_150001,60,566,0.9327443199859539,226,0.0452,14,206,6,-0.760937347240449,1.2377276399399924,0.1012577624595449,0.3451497346460263,0.24389197218648137,0.5661615012640613,0.5710361850383204
|
||||||
|
lab043_prbs11_s_20260819_150001,61,566,0.9302446752714513,257,0.0514,15,233,9,-0.7588775675796646,1.2397759170418416,0.12480081607671831,0.32533233181578325,0.20053151573906494,0.5778818486485496,0.5825750782437806
|
||||||
|
lab043_prbs11_s_20260819_150001,62,566,0.9275544297174029,282,0.0564,15,253,14,-0.7567108273876054,1.2419305573684498,0.14412176059716675,0.30766171772831596,0.16353995713114922,0.5900226205324292,0.5945308609311352
|
||||||
|
lab043_prbs11_s_20260819_150001,63,566,0.9246514106779686,318,0.0636,16,283,19,-0.7544299393021512,1.2441987081450885,0.1688674237970141,0.28574583861773284,0.11687841482071873,0.6025969006774378,0.60692399744975
|
||||||
|
lab043_prbs11_s_20260819_150001,64,566,0.9215215507346269,341,0.0682,16,304,21,-0.752032528617333,1.2465827308165094,0.1967427271666566,0.2635390065950153,0.06679627942835867,0.6156268962052861,0.6197749322911085
|
||||||
|
lab043_prbs11_s_20260819_150001,65,566,0.9181473473607321,377,0.0754,17,336,24,-0.749515726809513,1.2490854778874696,0.2247270301366536,0.24277603763329583,0.018049007496642233,0.6291284231597313,0.6330989394114357
|
||||||
|
lab043_prbs11_s_20260819_150001,66,566,0.914504137423558,411,0.0822,17,365,29,-0.746873576757757,1.25171287321217,0.2518446829877077,0.22339974417102576,-0.02844493881668192,0.6431138750356846,0.6469095205552707
|
||||||
|
lab043_prbs11_s_20260819_150001,67,566,0.9105699306000107,440,0.088,17,389,34,-0.744099924816224,1.2544710360722593,0.2766396532344156,0.20183391964058017,-0.07480573359383541,0.6576070005216411,0.6612273468777927
|
||||||
|
lab043_prbs11_s_20260819_150001,68,566,0.9063119364892922,471,0.0942,18,413,40,-0.741191843252119,1.2573628778510053,0.3036198433195562,0.1793478462235617,-0.12427199709599451,0.6726281734214363,0.6760740509626956
|
||||||
|
lab043_prbs11_s_20260819_150001,69,566,0.9017029953216349,502,0.1004,18,433,51,-0.7381372971009696,1.2604003663052592,0.33459628937394936,0.15257540746908455,-0.18202088190486482,0.6882046404020572,0.6914730782437374
|
||||||
|
lab043_prbs11_s_20260819_150001,70,566,0.8967163958644219,531,0.1062,20,453,58,-0.7349337631357405,1.2635860105714392,0.3686413900601503,0.12716565214137263,-0.24147573791877766,0.7043524011037164,0.7074492926787098
|
||||||
|
lab043_prbs11_s_20260819_150001,71,566,0.8913169925684403,565,0.113,21,474,70,-0.731580032150341,1.2669210131029909,0.4010611206373048,0.10120263276149781,-0.299858487875807,0.7211004009387844,0.7240321207946441
|
||||||
|
lab043_prbs11_s_20260819_150001,72,566,0.8854523924108935,588,0.1176,20,492,76,-0.7280571104010204,1.2704242615756909,0.4317658952216323,0.07413265408944023,-0.3576332411321921,0.7384796537019096,0.741248429744683
|
||||||
|
lab043_prbs11_s_20260819_150001,73,566,0.8790834822071036,630,0.126,20,517,93,-0.7243662003508955,1.2740945602414115,0.4687923249316298,0.04979677157776665,-0.4189955533538632,0.7565185664085023,0.7591229023776715
|
||||||
|
lab043_prbs11_s_20260819_150001,74,566,0.8721729331668495,662,0.1324,21,531,110,-0.7204965303856242,1.2779426205618836,0.5098678507744039,0.021595480260885765,-0.48827237051351813,0.7752441534798072,0.7776879950620835
|
||||||
|
lab043_prbs11_s_20260819_150001,75,566,0.8646588212026421,702,0.1404,22,548,132,-0.7164385414474577,1.2819779482135973,0.5468229478416348,-0.009571295502079283,-0.556394243343714,0.7946999032597145,0.7969801474058033
|
||||||
|
lab043_prbs11_s_20260819_150001,76,566,0.8564858434579065,720,0.144,24,554,142,-0.7121845138355763,1.2862082197877576,0.5836443933467396,-0.041152795033487996,-0.6247971883802276,0.814910388808187,0.8170345594445259
|
||||||
|
lab043_prbs11_s_20260819_150001,77,566,0.8475988930690542,743,0.1486,24,561,158,-0.7077194055223688,1.2906483933118205,0.6255258950275054,-0.07400983039163207,-0.6995357254191376,0.8359184510663351,0.8378914693353658
|
||||||
|
lab043_prbs11_s_20260819_150001,78,566,0.8379100323979151,777,0.1554,23,571,183,-0.7030360735313533,1.2953055718732884,0.6667225824196384,-0.10009962213681328,-0.7668222045564517,0.857765079571197,0.859586487534297
|
||||||
|
lab043_prbs11_s_20260819_150001,79,566,0.8273526129032499,800,0.16,23,578,199,-0.6981229130009546,1.3001912955279702,0.7103423737269061,-0.1305130501457721,-0.8408554238726782,0.8804887866585905,0.8821658890218503
|
||||||
|
lab043_prbs11_s_20260819_150001,80,566,0.8158434957605584,832,0.1664,23,590,219,-0.6929630426074409,1.305322351328141,0.7550658065264927,-0.16212806496925453,-0.9171938714957473,0.904149153274888,0.9056833864922944
|
||||||
|
lab043_prbs11_s_20260819_150001,81,566,0.8032890087238262,861,0.1722,23,601,237,-0.6875415561509107,1.3107135622320614,0.8041915297942587,-0.19768582073213492,-1.0018773505263936,0.9287892870352847,0.9301839300823902
|
||||||
|
lab043_prbs11_s_20260819_150001,82,566,0.7896071809168755,880,0.176,23,603,254,-0.6818473519597151,1.3163759679156075,0.8509976720113029,-0.2375403497109131,-1.088538021722216,0.9544618741170124,0.95571801309178
|
||||||
|
lab043_prbs11_s_20260819_150001,83,566,0.774684339745965,916,0.1832,24,609,283,-0.6758614631686461,1.3223284293261133,0.898336384524049,-0.27568731409566516,-1.1740236986197141,0.9812313518685594,0.9823510305970906
|
||||||
|
lab043_prbs11_s_20260819_150001,84,566,0.7584198926348125,951,0.1902,26,614,311,-0.6695631207346078,1.328591599524779,0.9541712148690765,-0.31322339197499677,-1.2673946068440733,1.009156394082203,1.0101509245413738
|
||||||
|
lab043_prbs11_s_20260819_150001,85,566,0.7406897684334062,990,0.198,26,618,346,-0.6629378194400956,1.3351799027267015,1.010133741444147,-0.3593032833320458,-1.3694370247761927,1.038300334223727,1.0391727420105303
|
||||||
|
lab043_prbs11_s_20260819_150001,86,566,0.7213913840122179,1013,0.2026,26,620,367,-0.655960555331209,1.3421182032546042,1.0617877063185208,-0.40018839692219793,-1.4619761032407188,1.0687472365820885,1.0694985114308453
|
||||||
|
lab043_prbs11_s_20260819_150001,87,566,0.7003926742172294,1045,0.209,26,621,398,-0.6486083218668584,1.349429379172685,1.1228940978237776,-0.4427343034084577,-1.5656284012322352,1.10056255582816,1.1012053241799082
|
||||||
|
lab043_prbs11_s_20260819_150001,88,566,0.6775888055923391,1068,0.2136,26,621,421,-0.6408572912356061,1.357137125229212,1.1821911516374,-0.49039965418410864,-1.6725908058215087,1.1338410228524813,1.1343731587114927
|
||||||
|
lab043_prbs11_s_20260819_150001,89,566,0.6528647867549533,1104,0.2208,26,623,455,-0.6326775677705234,1.365271170142834,1.2495833438721402,-0.540262928745818,-1.7898462726179583,1.168670080538643,1.1690963260685154
|
||||||
|
lab043_prbs11_s_20260819_150001,90,566,0.6261130839288158,1129,0.2258,26,623,480,-0.6240400096949823,1.373860492951898,1.3209104503495315,-0.5899757492779695,-1.9108861996275008,1.2051430321043437,1.205471606346128
|
||||||
|
lab043_prbs11_s_20260819_150001,91,566,0.5972726021460895,1161,0.2322,27,624,510,-0.6149043662600955,1.382945119630467,1.3890222635568863,-0.6498407127822906,-2.038862976339177,1.2433738453988161,1.24361230210792
|
||||||
|
lab043_prbs11_s_20260819_150001,92,566,0.5662508132473159,1192,0.2384,28,626,538,-0.6052401251765805,1.392555392076102,1.4685311451839953,-0.7029132012574931,-2.1714443464414885,1.283480827772402,1.283637182552647
|
||||||
|
lab043_prbs11_s_20260819_150001,93,566,0.5330246599990405,1218,0.2436,30,626,562,-0.5950032371136914,1.4027351136320565,1.548889170603502,-0.7617019655999068,-2.3105911362034086,1.3255899867524497,1.3256712978144956
|
||||||
|
lab043_prbs11_s_20260819_150001,94,567,0.5025494495824687,1345,0.269,274,0,1070,-1.321267142967587,0.6805269296297578,1.2787028653956487,-1.925443302309483,-3.2041461677051317,1.5924547649840202,1.596154983731797
|
||||||
|
lab043_prbs11_s_20260819_150001,95,567,0.47025505383773913,1345,0.269,273,0,1071,-1.3217891695288733,0.6800078182546943,1.2880275624270885,-1.9314698256008715,-3.21949738802796,1.5969898514810716,1.6006893561004114
|
||||||
|
lab043_prbs11_s_20260819_150001,96,567,0.43597367761848066,1358,0.2716,270,0,1087,-1.3223713604423375,0.6794288785070813,1.2918665950510302,-1.9332373711498165,-3.2251039662008467,1.6025706346360753,1.6062557299886904
|
||||||
|
lab043_prbs11_s_20260819_150001,97,567,0.39985966755633917,1372,0.2744,270,0,1101,-1.323013072999549,0.6787907495062326,1.2983998672302741,-1.9381998629561221,-3.2365997301863962,1.6092005646864826,1.612856422683389
|
||||||
|
lab043_prbs11_s_20260819_150001,98,567,0.36200944908395427,1386,0.2772,269,1,1115,-1.3237110545661201,0.6780966657226418,1.3049875499976797,-1.942998867882373,-3.247986417880053,1.6168896946614815,1.6205130395478473
|
||||||
|
lab043_prbs11_s_20260819_150001,99,567,0.3226504382602141,1406,0.2812,269,2,1134,-1.3244647360403263,0.6773471930799629,1.3115427129277317,-1.946354502421008,-3.2578972153487396,1.6256501925891491,1.6292301367967323
|
||||||
|
lab043_prbs11_s_20260819_150001,100,567,0.2820366883351844,1430,0.286,268,3,1158,-1.325272152910284,0.6765442851195297,1.3208467598984652,-1.95705687809974,-3.277903637998205,1.635484963599418,1.6390091354186278
|
||||||
|
lab043_prbs11_s_20260819_150001,101,565,0.2685923609492516,1060,0.212,35,0,1025,-0.6661000162900949,1.3320353647342618,1.1702326584406852,-0.4576350637979477,-1.627867722238633,1.1298947570686138,1.1171710614789336
|
||||||
|
lab043_prbs11_s_20260819_150001,102,565,0.31592782949142206,1033,0.2066,35,0,998,-0.6719342771544538,1.326233684504965,1.1071540943472618,-0.4077967992086726,-1.5149508935559344,1.0931359661200968,1.0810759187052386
|
||||||
|
lab043_prbs11_s_20260819_150001,103,565,0.3622848042869042,998,0.1996,35,0,963,-0.6775203816065186,1.320678774892282,1.0471869098717779,-0.3643410922593616,-1.4115280021311394,1.0577925411206943,1.0463800416139162
|
||||||
|
lab043_prbs11_s_20260819_150001,104,565,0.4073118639785343,957,0.1914,35,0,922,-0.6828711451280178,1.315357891980795,0.9891036081549907,-0.32025411253735964,-1.3093577206923503,1.023797216477992,1.01301640152485
|
||||||
|
lab043_prbs11_s_20260819_150001,105,565,0.4506567724580033,912,0.1824,35,0,877,-0.6880027544958235,1.310254939386483,0.9324634901449842,-0.2771000169076737,-1.2095635070526578,0.9910847781040989,0.9809224848731463
|
||||||
|
lab043_prbs11_s_20260819_150001,106,565,0.4920561419226367,870,0.174,35,0,835,-0.6929189752480125,1.305366172599403,0.8774709402580847,-0.23475500521003717,-1.1122259454681218,0.9596133573800516,0.9500572107619774
|
||||||
|
lab043_prbs11_s_20260819_150001,107,565,0.5313092401009925,812,0.1624,35,0,777,-0.6976311808903559,1.3006802816275789,0.823857859182045,-0.18915284188083611,-1.013010701062881,0.9293217299801961,0.9203611257479378
|
||||||
|
lab043_prbs11_s_20260819_150001,108,565,0.5682847153673783,778,0.1556,35,0,743,-0.7021493942259088,1.2961872996389345,0.771964311162175,-0.14474311900283604,-0.9167074301650111,0.9001681116715154,0.8917889218840903
|
||||||
|
lab043_prbs11_s_20260819_150001,109,565,0.6028558043459576,736,0.1472,35,0,701,-0.7064833964647679,1.2918775000452067,0.7212347870396306,-0.10526202747361407,-0.8264968145132447,0.8720990794150549,0.864298160345216
|
||||||
|
lab043_prbs11_s_20260819_150001,110,565,0.6350325412563236,694,0.1388,35,0,659,-0.7106392106637852,1.2877448934244842,0.6717152879271698,-0.06630821781928292,-0.7380235057464528,0.8450815161959315,0.8378462947204817
|
||||||
|
lab043_prbs11_s_20260819_150001,111,565,0.6648148975925997,655,0.131,35,0,620,-0.7146237435845483,1.28378261158505,0.6239786335995933,-0.02609615570631364,-0.6500747893059069,0.819076483814476,0.812401030062984
|
||||||
|
lab043_prbs11_s_20260819_150001,112,565,0.692283095057272,618,0.1236,36,0,582,-0.7184489799103261,1.2799787367704656,0.5784300488728558,0.0120878509546873,-0.5663421979181684,0.7940504163236839,0.7879193380287711
|
||||||
|
lab043_prbs11_s_20260819_150001,113,565,0.7175214202937549,583,0.1166,36,0,547,-0.7221174376673667,1.276330765016057,0.5312185503433392,0.04852161040924902,-0.4826969399340902,0.7699625416125242,0.7643743490684498
|
||||||
|
lab043_prbs11_s_20260819_150001,114,565,0.7406202028432197,539,0.1078,36,0,503,-0.7256365617910249,1.2728312929616965,0.48580110702325685,0.08328697365298139,-0.4025141333702755,0.7467889015257883,0.7417327348324911
|
||||||
|
lab043_prbs11_s_20260819_150001,115,565,0.7617206250622912,503,0.1006,35,0,468,-0.7290121252213998,1.2694745799054838,0.4414202479176482,0.11881573651500053,-0.3226045114026477,0.7245007490724401,0.719967571082296
|
||||||
|
lab043_prbs11_s_20260819_150001,116,565,0.7809375681833145,467,0.0934,35,0,432,-0.7322477981738659,1.2662569761278624,0.40255241277828047,0.15427957332033052,-0.24827283945794995,0.7030679592821116,0.6990550710523581
|
||||||
|
lab043_prbs11_s_20260819_150001,117,565,0.7984184582935019,441,0.0882,34,0,407,-0.7353543659838851,1.2631677565226058,0.3621592450864217,0.1836224632485949,-0.1785367818378268,0.682465996725849,0.678972771866944
|
||||||
|
lab043_prbs11_s_20260819_150001,118,565,0.8142817206577293,402,0.0804,35,0,367,-0.7383314828065166,1.2602072650033327,0.32046093273529164,0.21226903676134937,-0.10819189597394227,0.662675131913582,0.6596980421847636
|
||||||
|
lab043_prbs11_s_20260819_150001,119,565,0.8286673589169362,374,0.0748,35,0,339,-0.7411828412181719,1.2573718296143193,0.2820990784101022,0.24315676891329566,-0.03894230949680652,0.6436762008243364,0.6412080709418678
|
||||||
|
102
data/processed/lab043_diagnostics/report.txt
Normal file
102
data/processed/lab043_diagnostics/report.txt
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
Lab043: офлайн-диагностика асимметрии BPSK 000/001
|
||||||
|
|
||||||
|
Исходные данные
|
||||||
|
- lab043_prbs11_s_20260819_134831: SHA-256 d573d9bd0332a0473be1ffe4ed149dea0281c4dbcc4c4c9c199642d072441c5a; корреляция маркера 0.941276; диагностическая остаточная CFO +1.183884 Гц.
|
||||||
|
- lab043_prbs11_s_20260819_150001: SHA-256 a8216afd7dd4cab7c3ba5190b5710a7a7e5409022ff2d8e595f2de9fb66fb98e; корреляция маркера 0.958288; диагностическая остаточная CFO -0.098485 Гц.
|
||||||
|
|
||||||
|
Ошибки по тройкам после общей линейной фазовой коррекции по известной PRBS
|
||||||
|
- lab043_prbs11_s_20260819_134831: всего 34, в 000/001 34 (100.0%).
|
||||||
|
000: n=618, ошибок=26, BER=0.042071, mean=-0.38301+0.02765j.
|
||||||
|
001: n=626, ошибок=8, BER=0.012780, mean=-0.49129+0.01864j.
|
||||||
|
010: n=625, ошибок=0, BER=0.000000, mean=+1.62468+0.02154j.
|
||||||
|
011: n=623, ошибок=0, BER=0.000000, mean=+1.50789+0.02736j.
|
||||||
|
100: n=626, ошибок=0, BER=0.000000, mean=-0.86278-0.29993j.
|
||||||
|
101: n=622, ошибок=0, BER=0.000000, mean=-0.98532-0.29020j.
|
||||||
|
110: n=624, ошибок=0, BER=0.000000, mean=+1.12176-0.30358j.
|
||||||
|
111: n=634, ошибок=0, BER=0.000000, mean=+1.01780-0.28573j.
|
||||||
|
- lab043_prbs11_s_20260819_150001: всего 27, в 000/001 27 (100.0%).
|
||||||
|
000: n=618, ошибок=22, BER=0.035599, mean=-0.46423-0.10343j.
|
||||||
|
001: n=626, ошибок=5, BER=0.007987, mean=-0.60860-0.09103j.
|
||||||
|
010: n=625, ошибок=0, BER=0.000000, mean=+1.54394-0.08669j.
|
||||||
|
011: n=623, ошибок=0, BER=0.000000, mean=+1.38443-0.08533j.
|
||||||
|
100: n=626, ошибок=0, BER=0.000000, mean=-0.96145-0.29963j.
|
||||||
|
101: n=622, ошибок=0, BER=0.000000, mean=-1.10281-0.28653j.
|
||||||
|
110: n=624, ошибок=0, BER=0.000000, mean=+1.04731-0.30446j.
|
||||||
|
111: n=634, ошибок=0, BER=0.000000, mean=+0.88380-0.29881j.
|
||||||
|
|
||||||
|
Цифровой TX и идеальный канал
|
||||||
|
- идеальные символы: ошибок 0, размах средних амплитуд по тройкам 0.000000000.
|
||||||
|
- после TX RRC: ошибок 0, размах средних амплитуд по тройкам 0.309839549.
|
||||||
|
- после масштаба 0.70: ошибок 0, размах средних амплитуд по тройкам 0.309839549.
|
||||||
|
- после complex64 и масштаба 2^14: ошибок 0, размах средних амплитуд по тройкам 0.309839551.
|
||||||
|
- Идеальный канал, без искажений: ошибок 0, из них 000/001 0.
|
||||||
|
- Идеальный канал, только SRO -3.5 ppm: ошибок 0, из них 000/001 0.
|
||||||
|
- Идеальный канал, только остаточная CFO +0.5 Гц: ошибок 0, из них 000/001 0.
|
||||||
|
- Идеальный канал, только дробный тайминг +0.45 отсчёта: ошибок 0, из них 000/001 0.
|
||||||
|
- Идеальный канал, только gain 0.8 exp(j0.4): ошибок 0, из них 000/001 0.
|
||||||
|
- Идеальный канал, SRO+CFO+тайминг+gain: ошибок 0, из них 000/001 0.
|
||||||
|
|
||||||
|
RRC
|
||||||
|
{
|
||||||
|
"tx_tap_count": 1201,
|
||||||
|
"rx_tap_count": 1201,
|
||||||
|
"rolloff": 0.35,
|
||||||
|
"span_symbols": 10,
|
||||||
|
"samples_per_symbol": 120,
|
||||||
|
"symmetry_max_abs_error": 0.0,
|
||||||
|
"tap_energy": 1.0,
|
||||||
|
"tx_group_delay_samples": 600,
|
||||||
|
"rx_group_delay_samples": 600,
|
||||||
|
"total_group_delay_samples": 1200,
|
||||||
|
"total_group_delay_symbols": 10.0,
|
||||||
|
"sampling_index_rule": "find_radio_frame: phase 0..119, затем одинаковый индекс phase+n*120 для обоих знаков",
|
||||||
|
"one_sample_sign_dependent_shift": false
|
||||||
|
}
|
||||||
|
h[kT]: h[-5T]=-6.851591991e-03, h[-4T]=+1.485224371e-03, h[-3T]=-7.515407088e-04, h[-2T]=+1.943271982e-04, h[-1T]=+1.181546870e-04, h[+0T]=+1.000000000e+00, h[+1T]=+1.181546870e-04, h[+2T]=+1.943271982e-04, h[+3T]=-7.515407088e-04, h[+4T]=+1.485224371e-03, h[+5T]=-6.851591991e-03
|
||||||
|
|
||||||
|
Фаза выборки
|
||||||
|
- lab043_prbs11_s_20260819_134831: выбранная фаза 18, ошибок 117 (000=60, 001=36, прочие=21), глаз=+0.54354; минимум обзора на фазе 10: 107 ошибок, глаз=+0.56936. Фаза не изменялась.
|
||||||
|
- lab043_prbs11_s_20260819_150001: выбранная фаза 34, ошибок 27 (000=23, 001=4, прочие=0), глаз=+0.69231; минимум обзора на фазе 29: 25 ошибок, глаз=+0.72067. Фаза не изменялась.
|
||||||
|
|
||||||
|
DC, I/Q и расстояние до границы
|
||||||
|
- lab043_prbs11_s_20260819_134831: symbol DC=+0.31781-0.13594j; margin -1=0.68130, +1=1.31692; ellipse=1.721, corr(I,Q)=+0.495.
|
||||||
|
- lab043_prbs11_s_20260819_150001: symbol DC=+0.21442-0.19469j; margin -1=0.78498, +1=1.21382; ellipse=2.007, corr(I,Q)=+0.568.
|
||||||
|
|
||||||
|
Серии одинаковых символов
|
||||||
|
- lab043_prbs11_s_20260819_134831, бит 0: 1: A=0.9858, BER=0.0000; 2: A=0.7443, BER=0.0000; 3: A=0.5819, BER=0.0127; 4: A=0.4875, BER=0.0169; 5: A=0.4550, BER=0.0341; 6: A=0.4022, BER=0.0370; 7+: A=0.3730, BER=0.0764
|
||||||
|
- lab043_prbs11_s_20260819_134831, бит 1: 1: A=1.6247, BER=0.0000; 2: A=1.3734, BER=0.0000; 3: A=1.2430, BER=0.0000; 4: A=1.1186, BER=0.0000; 5: A=1.0757, BER=0.0000; 6: A=1.0384, BER=0.0000; 7+: A=1.0188, BER=0.0000
|
||||||
|
- lab043_prbs11_s_20260819_150001, бит 0: 1: A=1.1031, BER=0.0000; 2: A=0.8891, BER=0.0000; 3: A=0.7035, BER=0.0000; 4: A=0.5777, BER=0.0101; 5: A=0.4900, BER=0.0195; 6: A=0.4621, BER=0.0370; 7+: A=0.3488, BER=0.1019
|
||||||
|
- lab043_prbs11_s_20260819_150001, бит 1: 1: A=1.5439, BER=0.0000; 2: A=1.3163, BER=0.0000; 3: A=1.1365, BER=0.0000; 4: A=1.0012, BER=0.0000; 5: A=0.9210, BER=0.0000; 6: A=0.8581, BER=0.0000; 7+: A=0.8109, BER=0.0000
|
||||||
|
|
||||||
|
Низкие частоты
|
||||||
|
- чистый TX waveform: mean=+2.783e-04-1.588e-21j, P(|f|<500 Гц)=4.695284e-02, DC/median(2..10 кГц)=-5.79 дБ.
|
||||||
|
- lab043_prbs11_s_20260819_134831: RX после грубой CFO: mean=-3.587e-03-2.055e-03j, P(|f|<500 Гц)=2.128098e-02, DC/median(2..10 кГц)=-6.29 дБ.
|
||||||
|
- lab043_prbs11_s_20260819_150001: RX после грубой CFO: mean=-3.953e-03+1.590e-03j, P(|f|<500 Гц)=1.331852e-02, DC/median(2..10 кГц)=-8.34 дБ.
|
||||||
|
Передаточная характеристика на символьной скорости по известной PRBS
|
||||||
|
- lab043_prbs11_s_20260819_134831, 10..100 Гц: |H|=1.00207 (+0.02 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_134831, 100..500 Гц: |H|=0.96610 (-0.30 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_134831, 500..1000 Гц: |H|=0.91830 (-0.74 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_134831, 1000..5000 Гц: |H|=0.97907 (-0.18 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_134831, 5000..9000 Гц: |H|=1.18159 (+1.45 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_150001, 10..100 Гц: |H|=0.84774 (-1.43 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_150001, 100..500 Гц: |H|=0.81885 (-1.74 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_150001, 500..1000 Гц: |H|=0.64034 (-3.87 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_150001, 1000..5000 Гц: |H|=1.01586 (+0.14 дБ).
|
||||||
|
- lab043_prbs11_s_20260819_150001, 5000..9000 Гц: |H|=1.18464 (+1.47 дБ).
|
||||||
|
Диагностические модели символьного канала, обучение/проверка 50/50
|
||||||
|
- lab043_prbs11_s_20260819_134831, gain: RMSE=0.61054, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_134831, gain+DC: RMSE=0.50147, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_134831, FIR: RMSE=0.40648, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_134831, FIR+DC: RMSE=0.20954, предсказано ошибок 7/2492 (0.002809).
|
||||||
|
- lab043_prbs11_s_20260819_150001, gain: RMSE=0.56869, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_150001, gain+DC: RMSE=0.48895, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_150001, FIR: RMSE=0.36009, предсказано ошибок 0/2492 (0.000000).
|
||||||
|
- lab043_prbs11_s_20260819_150001, FIR+DC: RMSE=0.21257, предсказано ошибок 1/2492 (0.000401).
|
||||||
|
- lab043_prbs11_s_20260819_134831: FIR+DC: DC=+0.31661-0.13179j, |h0|=0.99895, сумма |h[k!=0]|=1.17350.
|
||||||
|
- lab043_prbs11_s_20260819_150001: FIR+DC: DC=+0.21123-0.19622j, |h0|=0.99755, сумма |h[k!=0]|=1.19183.
|
||||||
|
|
||||||
|
Интерпретация: таблицы являются измерениями; никакая коррекция DC, новый порог, эквалайзер или новая фаза автоматически не применялись.
|
||||||
|
Классификация: B. Ошибки 000/001 отсутствуют в полном цифровом TX-RRC -> RX-RRC тракте и появляются только в реальном IQ. Промежуточная зависимость амплитуды после одного TX-RRC полностью компенсируется согласованным RX-RRC в идеальном канале.
|
||||||
|
Наиболее вероятный механизм: совместное действие комплексного смещения середины кластеров и длинной памяти/ISI аппаратного тракта. FIR+DC-модель, обученная на первой половине и проверенная на второй, воспроизводит часть ошибок 000 без шума, но не весь измеренный BER; место внутри Pluto TX, кабеля/аттенюатора или RTL RX по этим данным не разделяется.
|
||||||
|
AC coupling отдельно не доказан: падение уровня длинных серий устойчиво, но оценённая низкочастотная АЧХ различается между двумя S и не образует однозначной монотонной высокочастотной характеристики.
|
||||||
|
Следующий диагностический шаг, пока не выполненный: сравнительный приём того же S другим приёмником либо loopback-разделение TX/RX с заранее фиксированными параметрами; после локализации отдельно проверить DC/АЧХ.
|
||||||
15
data/processed/lab043_diagnostics/rrc_audit.json
Normal file
15
data/processed/lab043_diagnostics/rrc_audit.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"tx_tap_count": 1201,
|
||||||
|
"rx_tap_count": 1201,
|
||||||
|
"rolloff": 0.35,
|
||||||
|
"span_symbols": 10,
|
||||||
|
"samples_per_symbol": 120,
|
||||||
|
"symmetry_max_abs_error": 0.0,
|
||||||
|
"tap_energy": 1.0,
|
||||||
|
"tx_group_delay_samples": 600,
|
||||||
|
"rx_group_delay_samples": 600,
|
||||||
|
"total_group_delay_samples": 1200,
|
||||||
|
"total_group_delay_symbols": 10.0,
|
||||||
|
"sampling_index_rule": "find_radio_frame: phase 0..119, затем одинаковый индекс phase+n*120 для обоих знаков",
|
||||||
|
"one_sample_sign_dependent_shift": false
|
||||||
|
}
|
||||||
12
data/processed/lab043_diagnostics/rrc_impulse_response.csv
Normal file
12
data/processed/lab043_diagnostics/rrc_impulse_response.csv
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
symbol_offset,sample_offset,h_normalized
|
||||||
|
-5,-600,-0.006851591990787818
|
||||||
|
-4,-480,0.0014852243708439643
|
||||||
|
-3,-360,-0.0007515407088124918
|
||||||
|
-2,-240,0.00019432719820258287
|
||||||
|
-1,-120,0.00011815468699953965
|
||||||
|
0,0,1.0
|
||||||
|
1,120,0.00011815468699953965
|
||||||
|
2,240,0.00019432719820258287
|
||||||
|
3,360,-0.0007515407088124918
|
||||||
|
4,480,0.0014852243708439643
|
||||||
|
5,600,-0.006851591990787818
|
||||||
|
73
data/processed/lab043_diagnostics/run_length_metrics.csv
Normal file
73
data/processed/lab043_diagnostics/run_length_metrics.csv
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
capture,bit,run_length,position,symbol_count,mean_i,mean_q,mean_amplitude,mean_signed_amplitude,mean_phase_error_deg,ber
|
||||||
|
lab043_prbs11_s_20260819_134831,0,1,single,623,-0.9857821657455609,-0.2902642009959631,1.0700427503250372,0.9857821657455609,14.801727171202234,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,2,first,315,-0.8424880653546357,-0.3127137567212283,0.9418657994085868,0.8424880653546357,18.417261446285792,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,2,last,315,-0.6461882928041996,-0.17139447420495169,0.7167473943757303,0.6461882928041996,14.794830864298815,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,3,first,158,-0.882306370843142,-0.28916668828632286,0.973149555801682,0.882306370843142,16.33931198629656,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,3,last,158,-0.3492240321328001,0.057379287291675365,0.40072110509646086,0.3492240321328001,-6.520976368528217,0.0379746835443038
|
||||||
|
lab043_prbs11_s_20260819_134831,0,3,middle,158,-0.5142377260197933,-0.14401977724709963,0.5907059677315208,0.5142377260197933,13.41558947498171,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,4,first,74,-0.8681869519253246,-0.2586254758947878,0.956311205223434,0.8681869519253246,14.328539173615859,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,4,last,74,-0.28305858758162084,0.26805526249921724,0.4099239931477214,0.28305858758162084,-42.86659221652123,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,4,middle,148,-0.39939338300128047,-0.03734529076885137,0.4588271089871034,0.39939338300128047,3.7409042801562378,0.033783783783783786
|
||||||
|
lab043_prbs11_s_20260819_134831,0,5,first,41,-0.9135417256105938,-0.2939747998048404,0.9999210129840694,0.9135417256105938,14.653322628302856,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,5,last,41,-0.30510111587274596,0.4229234429158172,0.5445408933903639,0.30510111587274596,-56.76960088975864,0.04878048780487805
|
||||||
|
lab043_prbs11_s_20260819_134831,0,5,middle,123,-0.35217660805637374,0.02944583444411268,0.454499837173404,0.35217660805637374,-13.184961796821467,0.04065040650406504
|
||||||
|
lab043_prbs11_s_20260819_134831,0,6,first,18,-0.887779527002307,-0.24575785543978,0.9537807208800194,0.887779527002307,11.871907726952344,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,6,last,18,-0.3067248634241106,0.47784545858497496,0.5779879336106305,0.3067248634241106,-57.00687683367144,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,6,middle,72,-0.3046959705110195,0.12883217311611908,0.44063343806980376,0.3046959705110195,-28.470653508668384,0.05555555555555555
|
||||||
|
lab043_prbs11_s_20260819_134831,0,7+,first,20,-0.8814991399013437,-0.3972899016812731,1.0127782355320558,0.8814991399013437,23.660468599173413,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,7+,last,20,-0.4922350130875081,0.5406233334931604,0.7469228959424001,0.4922350130875081,-48.093653513028514,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,0,7+,middle,117,-0.26568296607835235,0.27751684780162145,0.5085135965117819,0.26568296607835235,-45.13165326531156,0.10256410256410256
|
||||||
|
lab043_prbs11_s_20260819_134831,1,1,single,625,1.6246814910527565,0.021540864870758254,1.6592362427400138,1.6246814910527565,0.18194257569663422,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,2,first,313,1.4651935224517354,0.024510525512766227,1.4983324416844146,1.4651935224517354,0.417236057931388,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,2,last,313,1.2815513430080545,-0.12371400810134757,1.31932334145145,1.2815513430080545,-5.072518132084281,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,3,first,149,1.5588528736675464,0.021913572651993535,1.5946277676975151,1.5588528736675464,0.31644838639122885,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,3,last,149,0.9981815034652967,-0.2895061746626435,1.0577041982967457,0.9981815034652967,-15.912301681602749,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,3,middle,149,1.1720129617959687,-0.09130967883448256,1.2115117901079218,1.1720129617959687,-3.7933594981412506,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,4,first,82,1.5458958865581518,0.05902875919159914,1.5794796801436435,1.5458958865581518,1.6175355845057795,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,4,last,82,0.8835847577728094,-0.5578416198790078,1.058918110662329,0.8835847577728094,-32.797608429623544,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,4,middle,164,1.0225109228188605,-0.18103130808090823,1.0786125736379992,1.0225109228188605,-11.136408227843665,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,5,first,41,1.5704002752244177,0.002849185839505849,1.5942763755858251,1.5704002752244177,0.02071737447490966,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,5,last,41,0.8599842081274885,-0.697398946475133,1.1186316858583556,0.8599842081274885,-38.976071958325626,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,5,middle,123,0.982634383971298,-0.30232336867806897,1.0617197160088647,0.982634383971298,-18.81837795079926,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,6,first,18,1.55212416200691,0.025991126155437902,1.5858249348750895,1.55212416200691,0.2844874106828473,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,6,last,18,1.0883355189530914,-0.8137221339620337,1.369970248215814,1.0883355189530914,-37.18531591150748,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,6,middle,72,0.8975420383538609,-0.439309514136695,1.0585666107585348,0.8975420383538609,-26.706624685248492,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,7+,first,21,1.4694166646555065,0.0438076034442234,1.495818153253665,1.4694166646555065,0.9294249817155132,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,7+,last,21,1.0867985672903595,-0.885233809219734,1.4103358099926386,1.0867985672903595,-39.160112160969845,0.0
|
||||||
|
lab043_prbs11_s_20260819_134831,1,7+,middle,126,0.9323341129687039,-0.5479331057828538,1.1194144515071809,0.9323341129687039,-30.012822203600166,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,1,single,623,-1.1030631876442467,-0.2861020577882339,1.1650773302010677,1.1030631876442467,12.83074671663554,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,2,first,315,-0.9438306684637361,-0.30290467896809664,1.0192264897855752,0.9438306684637361,15.706636499280913,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,2,last,315,-0.8343812207234607,-0.21949290620454157,0.8996211841012238,0.8343812207234607,13.392275852320203,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,3,first,158,-0.9801436180086766,-0.29265827252392085,1.0499381278451252,0.9801436180086766,14.359839568634152,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,3,last,158,-0.4810387576529684,-0.07979229875331385,0.528607394001191,0.4810387576529684,8.708559121488143,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,3,middle,158,-0.6494318615630686,-0.2267518206305464,0.7272569010770391,0.6494318615630686,16.78465355635992,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,4,first,74,-0.951273564103175,-0.29611767886435725,1.0181457876048636,0.951273564103175,15.649578402390466,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,4,last,74,-0.3276292509285005,0.04048671315428493,0.37534513560086696,0.3276292509285005,-4.1654082139444775,0.013513513513513514
|
||||||
|
lab043_prbs11_s_20260819_150001,0,4,middle,148,-0.5160413085051206,-0.1724948748013655,0.5909819060423562,0.5160413085051206,14.99806210281587,0.013513513513513514
|
||||||
|
lab043_prbs11_s_20260819_150001,0,5,first,41,-0.968615319878473,-0.3083089234675125,1.038542938161848,0.968615319878473,16.447598165908122,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,5,last,41,-0.254015644856774,0.19547676549322335,0.3445906280679367,0.254015644856774,-35.989364114243536,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,5,middle,123,-0.40917042039516416,-0.09151761672201279,0.48029020650161963,0.40917042039516416,6.016051997727609,0.032520325203252036
|
||||||
|
lab043_prbs11_s_20260819_150001,0,6,first,18,-1.054071931279121,-0.3014826421075699,1.1223306809126927,1.054071931279121,16.559202493369735,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,6,last,18,-0.1964767498254503,0.3121613520798808,0.39326051470355733,0.1964767498254503,-58.854030063897085,0.1111111111111111
|
||||||
|
lab043_prbs11_s_20260819_150001,0,6,middle,72,-0.38045768497936,-0.01685802762084246,0.4630687400210571,0.38045768497936,-9.097631382178173,0.027777777777777776
|
||||||
|
lab043_prbs11_s_20260819_150001,0,7+,first,20,-1.030782900110509,-0.29681326450105644,1.1567757008936768,1.030782900110509,13.016420908040049,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,0,7+,last,20,-0.19775877228665736,0.4066703288523025,0.4695654428461916,0.19775877228665736,-65.86574671145465,0.1
|
||||||
|
lab043_prbs11_s_20260819_150001,0,7+,middle,117,-0.25801692584002206,0.08467032676227261,0.4130944817717871,0.25801692584002206,-28.80910874944147,0.11965811965811966
|
||||||
|
lab043_prbs11_s_20260819_150001,1,1,single,625,1.543937892189543,-0.0866919401911572,1.5765627581653052,1.543937892189543,-4.197559508608589,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,2,first,313,1.361786115921763,-0.08037829281320101,1.3962668544987367,1.361786115921763,-4.499258071458339,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,2,last,313,1.270744473611291,-0.15941431941910755,1.3133222129137216,1.270744473611291,-7.198651280005335,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,3,first,149,1.420701086437231,-0.08069079715052878,1.4555679094941192,1.420701086437231,-4.425965875615329,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,3,last,149,0.9143215528566313,-0.3093291346767263,0.9880459649748297,0.9143215528566313,-18.18464411245232,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,3,middle,149,1.0744085994719226,-0.15201002276221748,1.1240677574519422,1.0744085994719226,-8.34370851095225,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,4,first,82,1.3918047176779145,-0.08904540465613667,1.425272130524323,1.3918047176779145,-4.88602724735577,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,4,last,82,0.7875213220983199,-0.47287476298854797,0.9352841509128977,0.7875213220983199,-30.492329099374093,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,4,middle,164,0.9126815803354904,-0.23463367195779292,0.9864357488415159,0.9126815803354904,-15.559682234393858,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,5,first,41,1.3859855823571308,-0.0949080079579381,1.4173158678640236,1.3859855823571308,-5.194550123757227,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,5,last,41,0.7039054907082286,-0.596054863193749,0.9395363518554335,0.7039054907082286,-40.17907710629712,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,5,middle,123,0.8384428615261585,-0.3160958338842525,0.9429614055898407,0.8384428615261585,-22.708951504218277,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,6,first,18,1.381288694941642,-0.14096462974809634,1.4175256957656206,1.381288694941642,-7.0278376400009765,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,6,last,18,0.6725517345139995,-0.7065254272538648,0.9908845683950595,0.6725517345139995,-46.78411967919625,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,6,middle,72,0.7736538067078175,-0.37490704027314653,0.9051695274003921,0.7736538067078175,-28.23304732736698,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,7+,first,21,1.4521311301406687,-0.10451377197395277,1.4735631909026754,1.4521311301406687,-5.522381290059382,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,7+,last,21,0.6666411083852714,-0.8603178177571177,1.1030411950063679,0.6666411083852714,-52.88754280866333,0.0
|
||||||
|
lab043_prbs11_s_20260819_150001,1,7+,middle,126,0.7280475555396544,-0.49556558083947105,0.9433044420725241,0.7280475555396544,-36.041327810425955,0.0
|
||||||
|
4
data/processed/lab043_diagnostics/spectrum_metrics.csv
Normal file
4
data/processed/lab043_diagnostics/spectrum_metrics.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
source,mean_i,mean_q,mean_amplitude,dc_bin_to_2_10khz_median_db,power_fraction_abs_f_below_100_hz,power_fraction_abs_f_below_500_hz,power_fraction_abs_f_below_1000_hz,power_fraction_abs_f_below_5000_hz,power_fraction_abs_f_below_20000_hz
|
||||||
|
чистый TX waveform,0.0002782869136427176,-1.5879563804290438e-21,0.0588630600980395,-5.7877751031530575,0.005343323060338315,0.046952843076681544,0.09836002169740929,0.4978957206724244,0.9999895817349141
|
||||||
|
lab043_prbs11_s_20260819_134831: RX после грубой CFO,-0.0035866184049641804,-0.0020547927693326117,0.01810488205985558,-6.288525799773844,0.00309223994088002,0.02128098077879969,0.04279840801293315,0.2435579653253578,0.5894197180187851
|
||||||
|
lab043_prbs11_s_20260819_150001: RX после грубой CFO,-0.003953464860272102,0.0015903730102091952,0.019498397032834895,-8.342481966309766,0.0016061181880257529,0.01331852069411624,0.026415827000324466,0.20593062957796177,0.5104841300396246
|
||||||
|
@@ -0,0 +1,77 @@
|
|||||||
|
capture,model,term,lag_symbols,coefficient_i,coefficient_q,magnitude
|
||||||
|
lab043_prbs11_s_20260819_134831,gain,gain,0,1.000076898152648,-0.0025876863086384183,1.0000802459498206
|
||||||
|
lab043_prbs11_s_20260819_134831,gain+DC,gain,0,0.9980502284607532,-0.001713532962643461,0.9980516994253232
|
||||||
|
lab043_prbs11_s_20260819_134831,gain+DC,DC,,0.31565380451262254,-0.1361493836387165,0.3437644236515689
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-8,0.005088142049709876,0.002193127516113645,0.005540667633052954
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-7,0.008250747337673559,-0.00010273657343665143,0.008251386940002802
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-6,0.00021698735210965038,-0.0016766140662735453,0.0016905970064453177
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-5,-0.007805718933475608,-0.003652166929281369,0.008617863502502003
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-4,0.00018008620290619237,-0.0009846550370057607,0.0010009878033113023
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-3,-0.0012544616086486002,-0.0022538672986419602,0.002579455703721396
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-2,0.02772783038337061,-0.0009823298651181317,0.02774522571061323
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,-1,-0.05106409144999977,0.0050049066247871326,0.051308776305197326
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,0,1.0009908581405378,-0.003747165757517026,1.0009978717920156
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,1,-0.2501253779258194,-0.1577786617682146,0.2957309770583776
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,2,-0.15345632642043275,-0.19209445398806702,0.24586403431862092
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,3,-0.011209673614077015,-0.1680166432702729,0.16839016954188352
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,4,0.05438796195617884,-0.11262761701550482,0.1250721012869696
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,5,0.0704524188217869,-0.05119252826538461,0.08708741739219665
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,6,0.06749176660362004,-0.008556822484033881,0.0680320348828461
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,7,0.04562068583497904,0.01402124330933205,0.04772674554160744
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,tap,8,0.027936682659462142,0.024898426674665082,0.03742178361448271
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-8,0.002716787446301202,0.00318023458001113,0.004182681677139485
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-7,0.005905068022079525,0.0008736828194000068,0.0059693508871820344
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-6,-0.0021372593533339457,-0.0006966283864597209,0.002247925410736511
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-5,-0.010146468930157675,-0.0026777994292784754,0.010493876382638552
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-4,-0.001954784960822691,-9.598726745357295e-05,0.00195714020922666
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-3,-0.0033891688953710014,-0.001365267745016097,0.003653822904429227
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-2,0.02563805541154798,-0.00011243396946499353,0.025638301946172143
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,-1,-0.05311998118867498,0.005860697353311943,0.05344230697633011
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,0,0.9989459679181133,-0.0028959537200805765,0.998950165607777
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,1,-0.25216693291386993,-0.15692883806527905,0.2970098016424824
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,2,-0.1555249288499998,-0.19123337143732255,0.24649179670951013
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,3,-0.013561760337292937,-0.16703755671103424,0.16758719132272057
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,4,0.05204131643521074,-0.11165079542716785,0.12318359767367172
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,5,0.0678962612965066,-0.05012849459196749,0.08439649440646461
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,6,0.06491527875856577,-0.007484326051723186,0.0653453024535873
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,7,0.04304879842471665,0.015091824751082223,0.045617564820245114
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,tap,8,0.02532621180069811,0.025985068976529167,0.036285545522822156
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,DC,,0.31661026628081473,-0.13179312360078585,0.34294531363303454
|
||||||
|
lab043_prbs11_s_20260819_150001,gain,gain,0,0.998698652150514,-0.0020742102322665553,0.9987008061253085
|
||||||
|
lab043_prbs11_s_20260819_150001,gain+DC,gain,0,0.9973674020267097,-0.000782092951252052,0.9973677086686198
|
||||||
|
lab043_prbs11_s_20260819_150001,gain+DC,DC,,0.20734220678251997,-0.2012472665180131,0.28894853000909604
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-8,-0.0038344808885037744,-0.0019628856870946626,0.00430768660708991
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-7,0.0012385017770719237,-0.003639789216896658,0.003844730445069914
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-6,0.0023998700886108007,-0.0006957724557815977,0.0024986948097823324
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-5,-0.0009233996208636567,-0.0027768283867714615,0.0029263360622783815
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-4,0.009234526465185616,0.0006637967162348613,0.009258353261606393
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-3,-0.0061831798377780505,-0.0007957137093386642,0.0062341698094882285
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-2,0.027049804353416473,-0.003290927494980278,0.027249259060299715
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,-1,-0.07147738202589815,0.003953379177205796,0.0715866282778771
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,0,0.9989112753555566,-0.0028005479232093332,0.9989152011563017
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,1,-0.25722926274231,-0.10195801621504566,0.2766989893032858
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,2,-0.22017259736636305,-0.13190843406629513,0.2566628286465976
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,3,-0.0930284091519903,-0.1357719406157327,0.16458525076054706
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,4,-0.03876729891852838,-0.11817648198431167,0.12437276373718996
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,5,-0.01130815600869626,-0.09106010576263912,0.09175956219283109
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,6,0.025146655600306916,-0.06652125676965408,0.071115623389623
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,7,0.031132710714738852,-0.04451342716715576,0.05432026210000552
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,tap,8,0.02677074073353095,-0.021288542617737702,0.03420342974336298
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-8,-0.005416578965875615,-0.0004932630575657877,0.005438992198700536
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-7,-0.0003264665030823094,-0.00218607858295794,0.002210321231971087
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-6,0.0008291858978162321,0.000763247729913492,0.001126985514705229
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-5,-0.0024850792043536376,-0.0013261726475371307,0.0028167982787176207
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-4,0.00781020318653478,0.001986861165911015,0.008058963401552542
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-3,-0.007607393782508261,0.0005272491792477566,0.007625643045616729
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-2,0.02565556792824977,-0.001995810946489221,0.025733080403542136
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,-1,-0.07284901121968092,0.00522749570091397,0.07303632758421161
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,0,0.9975469847156482,-0.00153324823658316,0.9975481630304557
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,1,-0.2585913282118942,-0.1006927835056243,0.2775040750628756
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,2,-0.22155270809377556,-0.1306264389831378,0.25719422432298344
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,3,-0.09459765226614196,-0.1343142590568109,0.16428340147515216
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,4,-0.040332911822503086,-0.11672217255452778,0.12349416723850065
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,5,-0.013013549162631055,-0.08947595342270917,0.0904173584148035
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,6,0.023427698654697245,-0.06492450492311219,0.06902208634753461
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,7,0.029416823043976935,-0.04291952639276798,0.05203302051370994
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,tap,8,0.02502911132022019,-0.019670730147915552,0.03183385050590155
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,DC,,0.21123306182846485,-0.19621595665140998,0.2883055810317519
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
capture,model,training_symbols,validation_symbols,validation_rmse,predicted_bit_errors,predicted_ber,predicted_mean_i,predicted_mean_q
|
||||||
|
lab043_prbs11_s_20260819_134831,gain,2492,2492,0.610543736145253,0,0.0,-0.003210519737247668,8.307179160958007e-06
|
||||||
|
lab043_prbs11_s_20260819_134831,gain+DC,2492,2492,0.5014741666559047,0,0.0,0.3124497909381097,-0.1361438827303292
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR,2492,2492,0.4064837326783923,0,0.0,-0.0026407799641849634,0.0011360028841420013
|
||||||
|
lab043_prbs11_s_20260819_134831,FIR+DC,2492,2492,0.20953511049382884,7,0.0028089887640449437,0.3140884092399191,-0.1307066239235744
|
||||||
|
lab043_prbs11_s_20260819_150001,gain,2492,2492,0.5686850981096296,0,0.0,-0.003206095191494428,6.658780841947204e-06
|
||||||
|
lab043_prbs11_s_20260819_150001,gain+DC,2492,2492,0.48894584689725634,0,0.0,0.2041403852671855,-0.2012447557862274
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR,2492,2492,0.3600912162373556,0,0.0,-0.0019963832312459326,0.0011631487049894307
|
||||||
|
lab043_prbs11_s_20260819_150001,FIR+DC,2492,2492,0.21256610617464475,1,0.0004012841091492777,0.20931602047549436,-0.1951265092051798
|
||||||
|
@@ -0,0 +1,65 @@
|
|||||||
|
source,triplet,count,bit_errors,ber,mean_i,mean_q,median_i,median_q,std_i,std_q,mean_amplitude,mean_phase_error_deg,mean_distance_to_ideal,decision_cross_fraction,raw_mean_i,raw_mean_q,fitted_gain_i,fitted_gain_q
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",000,309,0,0.0,-1.0000768981526478,0.002587686308638419,-1.000076898152648,0.0025876863086384183,2.220446049250313e-16,8.673617379884035e-19,1.0000802459498206,-0.14825177302342232,0.002588828645892848,0.0,-1.0000768981526478,0.002587686308638419,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",001,312,0,0.0,-1.0000768981526478,0.002587686308638419,-1.000076898152648,0.0025876863086384183,2.220446049250313e-16,8.673617379884035e-19,1.0000802459498208,-0.14825177302342235,0.002588828645892848,0.0,-1.0000768981526478,0.002587686308638419,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",010,320,0,0.0,1.0000768981526478,-0.0025876863086384187,1.000076898152648,-0.0025876863086384183,2.220446049250313e-16,4.336808689942018e-19,1.0000802459498208,-0.14825177302342232,0.002588828645892848,0.0,1.0000768981526478,-0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",011,307,0,0.0,1.0000768981526478,-0.0025876863086384187,1.000076898152648,-0.0025876863086384183,2.220446049250313e-16,4.336808689942018e-19,1.0000802459498208,-0.14825177302342232,0.002588828645892848,0.0,1.0000768981526478,-0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",100,313,0,0.0,-1.0000768981526478,0.0025876863086384187,-1.000076898152648,0.0025876863086384183,2.220446049250313e-16,4.336808689942018e-19,1.0000802459498208,-0.14825177302342235,0.002588828645892848,0.0,-1.0000768981526478,0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",101,315,0,0.0,-1.000076898152648,0.0025876863086384187,-1.000076898152648,0.0025876863086384183,0.0,4.336808689942018e-19,1.0000802459498208,-0.14825177302342235,0.002588828645892848,0.0,-1.000076898152648,0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",110,308,0,0.0,1.000076898152648,-0.0025876863086384187,1.000076898152648,-0.0025876863086384183,0.0,4.336808689942018e-19,1.0000802459498208,-0.14825177302342232,0.002588828645892848,0.0,1.000076898152648,-0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain, проверочная половина",111,306,0,0.0,1.0000768981526478,-0.0025876863086384187,1.000076898152648,-0.0025876863086384183,2.220446049250313e-16,4.336808689942018e-19,1.0000802459498208,-0.14825177302342232,0.002588828645892848,0.0,1.0000768981526478,-0.0025876863086384187,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",000,309,0,0.0,-0.6823964239481307,-0.13443585067607303,-0.6823964239481306,-0.13443585067607305,1.1102230246251565e-16,2.7755575615628914e-17,0.6955126723246644,11.144864752908862,0.34488408120401126,0.0,-0.6823964239481307,-0.13443585067607303,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",001,312,0,0.0,-0.6823964239481306,-0.13443585067607303,-0.6823964239481306,-0.13443585067607305,0.0,2.7755575615628914e-17,0.6955126723246644,11.14486475290886,0.3448840812040112,0.0,-0.6823964239481306,-0.13443585067607303,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",010,320,0,0.0,1.313704032973376,-0.13786291660135994,1.3137040329733758,-0.13786291660135996,2.220446049250313e-16,2.7755575615628914e-17,1.3209180406158232,-5.990814121300027,0.34266077113902954,0.0,1.313704032973376,-0.13786291660135994,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",011,307,0,0.0,1.3137040329733758,-0.13786291660135996,1.3137040329733758,-0.13786291660135996,0.0,0.0,1.3209180406158232,-5.990814121300028,0.34266077113902954,0.0,1.3137040329733758,-0.13786291660135996,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",100,313,0,0.0,-0.6823964239481306,-0.13443585067607303,-0.6823964239481306,-0.13443585067607305,0.0,2.7755575615628914e-17,0.6955126723246644,11.144864752908859,0.3448840812040112,0.0,-0.6823964239481306,-0.13443585067607303,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",101,315,0,0.0,-0.6823964239481307,-0.13443585067607303,-0.6823964239481306,-0.13443585067607305,1.1102230246251565e-16,2.7755575615628914e-17,0.6955126723246644,11.14486475290886,0.3448840812040112,0.0,-0.6823964239481307,-0.13443585067607303,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",110,308,0,0.0,1.313704032973376,-0.13786291660135996,1.3137040329733758,-0.13786291660135996,2.220446049250313e-16,0.0,1.3209180406158232,-5.990814121300028,0.34266077113902954,0.0,1.313704032973376,-0.13786291660135996,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: gain+DC, проверочная половина",111,306,0,0.0,1.313704032973376,-0.13786291660135994,1.3137040329733758,-0.13786291660135996,2.220446049250313e-16,2.7755575615628914e-17,1.3209180406158232,-5.990814121300028,0.34266077113902954,0.0,1.313704032973376,-0.13786291660135994,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",000,309,0,0.0,-0.6959052312437318,0.15331107269225944,-0.6990093630386194,0.15918089308300562,0.20189181448009522,0.2780541085757557,0.7693007644568678,-13.65671147578478,0.4339815625407696,0.0,-0.6959052312437318,0.15331107269225944,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",001,312,0,0.0,-0.8058528221696036,0.1729192675974602,-0.8077464972367241,0.1750171073523559,0.19821143850994494,0.28327343165066554,0.8753009723070693,-13.019900843048168,0.38228688158698926,0.0,-0.8058528221696036,0.1729192675974602,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",010,320,0,0.0,1.2995205890475223,0.152430989972321,1.3008779110585262,0.15481940619322834,0.19642701499894422,0.28687379782622163,1.3375846780501275,5.870133367869796,0.43296329611107237,0.0,1.2995205890475223,0.152430989972321,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",011,307,0,0.0,1.1958025534179928,0.1562515217448702,1.1943933020068482,0.13903635064414496,0.19741159802653682,0.2809210470132544,1.2361296041231409,6.527944700578263,0.37514572720023953,0.0,1.1958025534179928,0.1562515217448702,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",100,313,0,0.0,-1.1942821421802072,-0.1505140009337925,-1.1926342229430742,-0.14768914590091894,0.20046331464452866,0.29039768912086905,1.2356002306079004,6.153938611190278,0.381008255008502,0.0,-1.1942821421802072,-0.1505140009337925,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",101,315,0,0.0,-1.3039066395993382,-0.14966668234353578,-1.2947624058430738,-0.14878821250584032,0.19674540344728236,0.2856811215452765,1.3412960234264184,5.754117431887854,0.4369845384462321,0.0,-1.3039066395993382,-0.14966668234353578,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",110,308,0,0.0,0.8034350111369687,-0.16882393321876418,0.7931704306195364,-0.17257626364778783,0.2010159778116291,0.28515881708652935,0.8732799380128532,-12.822950408394911,0.38514560683697635,0.0,0.8034350111369687,-0.16882393321876418,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR, проверочная половина",111,306,0,0.0,0.6982496298980488,-0.16058755911520972,0.6932137163619673,-0.1678417490616943,0.1974739737479717,0.2836014114847298,0.7756149804099978,-14.034022976032459,0.4365865890475238,0.0,0.6982496298980488,-0.16058755911520972,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",000,309,7,0.022653721682847898,-0.373361907916119,0.019048237259684454,-0.375062911937328,0.02673635505459082,0.20014860159729064,0.2760653890104564,0.47108963358424616,-6.861425073847069,0.6853621365096135,0.022653721682847898,-0.373361907916119,0.019048237259684454,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",001,312,0,0.0,-0.48696516180532956,0.04017814921604036,-0.4886871423367445,0.0444577677489765,0.19649428198329205,0.2811050663197481,0.5677582561636969,-7.4894433484319585,0.5853964946723793,0.0,-0.48696516180532956,0.04017814921604036,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",010,320,0,0.0,1.618371471161831,0.019705181013746378,1.6220114780926864,0.023944456608310558,0.1949837159985397,0.2846808797308616,1.6431726707365626,0.19804060232903004,0.6807183724206796,0.0,1.618371471161831,0.019705181013746378,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",011,307,0,0.0,1.5103733982441552,0.025307333736111895,1.5094296107097396,0.009835923807948066,0.19564504428657653,0.27866118219431757,1.5358779727416372,0.41368016067370933,0.5821463331648234,0.0,1.5103733982441552,0.025307333736111895,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",100,313,0,0.0,-0.8754204972373312,-0.2832442900591419,-0.8751630284378134,-0.280760851915945,0.19841221034169088,0.2893952818901169,0.9559619752524816,15.962566200579156,0.42968732433843515,0.0,-0.8754204972373312,-0.2832442900591419,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",101,315,0,0.0,-0.9892316514063746,-0.28065422137743334,-0.9818382568622401,-0.2757603775416038,0.19501905783536072,0.28460488159268144,1.0607361943775908,14.358614654856197,0.39732507639385783,0.0,-0.9892316514063746,-0.28065422137743334,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",110,308,0,0.0,1.1180959990534434,-0.2998056444562622,1.1165444649416947,-0.3002686314127111,0.19895336508396577,0.2841330851165556,1.1956808229546807,-15.439137103017439,0.43476753455331757,0.0,1.1180959990534434,-0.2998056444562622,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_134831: FIR+DC, проверочная половина",111,306,0,0.0,1.0088879691809087,-0.289894790763652,1.0099893568795157,-0.29316047691907,0.1955407745458894,0.28250782538856484,1.0913190363180871,-16.479503909256373,0.40273457084442965,0.0,1.0088879691809087,-0.289894790763652,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",000,309,0,0.0,-0.9986986521505139,0.0020742102322665558,-0.998698652150514,0.0020742102322665553,1.1102230246251565e-16,4.336808689942018e-19,0.9987008061253084,-0.11899817927704522,0.0024486433617415763,0.0,-0.9986986521505139,0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",001,312,0,0.0,-0.9986986521505139,0.0020742102322665558,-0.998698652150514,0.0020742102322665553,1.1102230246251565e-16,4.336808689942018e-19,0.9987008061253084,-0.11899817927704522,0.002448643361741576,0.0,-0.9986986521505139,0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",010,320,0,0.0,0.9986986521505139,-0.0020742102322665558,0.998698652150514,-0.0020742102322665553,1.1102230246251565e-16,4.336808689942018e-19,0.9987008061253084,-0.11899817927704522,0.002448643361741576,0.0,0.9986986521505139,-0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",011,307,0,0.0,0.998698652150514,-0.0020742102322665558,0.998698652150514,-0.0020742102322665553,0.0,4.336808689942018e-19,0.9987008061253083,-0.11899817927704519,0.002448643361741576,0.0,0.998698652150514,-0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",100,313,0,0.0,-0.998698652150514,0.0020742102322665558,-0.998698652150514,0.0020742102322665553,0.0,4.336808689942018e-19,0.9987008061253083,-0.11899817927704522,0.0024486433617415763,0.0,-0.998698652150514,0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",101,315,0,0.0,-0.9986986521505139,0.0020742102322665558,-0.998698652150514,0.0020742102322665553,1.1102230246251565e-16,4.336808689942018e-19,0.9987008061253084,-0.11899817927704522,0.002448643361741576,0.0,-0.9986986521505139,0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",110,308,0,0.0,0.998698652150514,-0.0020742102322665558,0.998698652150514,-0.0020742102322665553,0.0,4.336808689942018e-19,0.9987008061253083,-0.11899817927704519,0.0024486433617415763,0.0,0.998698652150514,-0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain, проверочная половина",111,306,0,0.0,0.9986986521505139,-0.0020742102322665558,0.998698652150514,-0.0020742102322665553,1.1102230246251565e-16,4.336808689942018e-19,0.9987008061253084,-0.11899817927704519,0.0024486433617415763,0.0,0.9986986521505139,-0.0020742102322665558,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",000,309,0,0.0,-0.7900251952441896,-0.20046517356676105,-0.7900251952441897,-0.20046517356676105,1.1102230246251565e-16,0.0,0.8150620190720285,14.238031306017975,0.29030278063668685,0.0,-0.7900251952441896,-0.20046517356676105,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",001,312,0,0.0,-0.7900251952441897,-0.20046517356676105,-0.7900251952441897,-0.20046517356676105,0.0,0.0,0.8150620190720285,14.238031306017977,0.29030278063668685,0.0,-0.7900251952441897,-0.20046517356676105,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",010,320,0,0.0,1.2047096088092297,-0.2020293594692652,1.2047096088092297,-0.20202935946926517,0.0,2.7755575615628914e-17,1.2215322769558112,-9.519897580765734,0.2876141269590029,0.0,1.2047096088092297,-0.2020293594692652,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",011,307,0,0.0,1.2047096088092297,-0.2020293594692652,1.2047096088092297,-0.20202935946926517,0.0,2.7755575615628914e-17,1.2215322769558112,-9.519897580765736,0.2876141269590029,0.0,1.2047096088092297,-0.2020293594692652,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",100,313,0,0.0,-0.7900251952441897,-0.20046517356676102,-0.7900251952441897,-0.20046517356676105,0.0,2.7755575615628914e-17,0.8150620190720285,14.238031306017977,0.29030278063668685,0.0,-0.7900251952441897,-0.20046517356676102,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",101,315,0,0.0,-0.7900251952441897,-0.20046517356676105,-0.7900251952441897,-0.20046517356676105,0.0,0.0,0.8150620190720285,14.238031306017977,0.29030278063668685,0.0,-0.7900251952441897,-0.20046517356676105,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",110,308,0,0.0,1.2047096088092297,-0.2020293594692652,1.2047096088092297,-0.20202935946926517,0.0,2.7755575615628914e-17,1.2215322769558112,-9.519897580765736,0.2876141269590029,0.0,1.2047096088092297,-0.2020293594692652,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: gain+DC, проверочная половина",111,306,0,0.0,1.2047096088092297,-0.2020293594692652,1.2047096088092297,-0.20202935946926517,0.0,2.7755575615628914e-17,1.2215322769558112,-9.519897580765734,0.2876141269590029,0.0,1.2047096088092297,-0.2020293594692652,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",000,309,0,0.0,-0.6710725187039128,0.09344369160270495,-0.6808189048478809,0.08688658919376054,0.24861776919736261,0.24939681573484215,0.7327560296334127,-11.775774154423525,0.4324949547472286,0.0,-0.6710725187039128,0.09344369160270495,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",001,312,0,0.0,-0.8113242081298582,0.11540812260778764,-0.8081534140039225,0.13040019024137117,0.2493341626463008,0.2544357540519286,0.8666832769699392,-11.05082625854985,0.3662322950142799,0.0,-0.8113242081298582,0.11540812260778764,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",010,320,0,0.0,1.3289266306259868,0.10067851591153154,1.3426949214924473,0.10605998994950924,0.2511199624976089,0.2577379117599549,1.3559798575297326,2.9266086491242937,0.43698270754103474,0.0,1.3289266306259868,0.10067851591153154,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",011,307,0,0.0,1.1802435067888202,0.101973530157473,1.1700774347034235,0.09039529156811495,0.24715773383921819,0.25665122898322723,1.2101773670615918,3.2484605533917965,0.3572543410093826,0.0,1.1802435067888202,0.101973530157473,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",100,313,0,0.0,-1.1764242418811381,-0.0968258216781235,-1.1518061648967206,-0.09777527946167801,0.2505627465167484,0.2565413362859851,1.2063782946665622,2.997651605811771,0.3596020850367703,0.0,-1.1764242418811381,-0.0968258216781235,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",101,315,0,0.0,-1.3287331580337447,-0.09387400797742058,-1.334534679715302,-0.08540971044219774,0.24509693947896344,0.25584163913880825,1.3549962424691067,2.7014633170148827,0.43355180307842056,0.0,-1.3287331580337447,-0.09387400797742058,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",110,308,0,0.0,0.8123717207465698,-0.11022990288189691,0.8062426350476075,-0.11104057150832841,0.24784188350971223,0.2540406668700511,0.8667943901674938,-10.621336714112806,0.362503437104132,0.0,0.8123717207465698,-0.11022990288189691,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR, проверочная половина",111,306,0,0.0,0.6674656833129947,-0.103092504726845,0.6609612642366145,-0.11257663061549493,0.24610220513947023,0.25250138487302465,0.7322257028036385,-12.652764288670907,0.4364994596630116,0.0,0.6674656833129947,-0.103092504726845,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",000,309,1,0.003236245954692557,-0.4558810956361874,-0.10644921614059683,-0.464859559487001,-0.1134187823244891,0.2503754783794727,0.2454171919344677,0.5277991871992165,5.199914308613728,0.6236679866091345,0.003236245954692557,-0.4558810956361874,-0.10644921614059683,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",001,312,0,0.0,-0.5985717359206436,-0.08221922560716155,-0.5991076898402583,-0.06700817968895466,0.25135697734444906,0.2501378233111643,0.6527672131207064,2.0372538608124713,0.5048785170357465,0.0,-0.5985717359206436,-0.08221922560716155,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",010,320,0,0.0,1.5416545654680465,-0.09692603936121179,1.5494244024258412,-0.088342869521054,0.2532693831736207,0.25352545001605287,1.5677893528661166,-4.6414289815651015,0.6232959268894408,0.0,1.5416545654680465,-0.09692603936121179,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",011,307,0,0.0,1.3901159265784606,-0.09297851601990005,1.3830271075774219,-0.10137091266408625,0.24928119012571637,0.2522506935226914,1.4184722871289466,-5.045995859433824,0.4983004675029795,0.0,1.3901159265784606,-0.09297851601990005,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",100,313,0,0.0,-0.9636891263962676,-0.29443704710319063,-0.9378749028311261,-0.2926532575514388,0.25132096355275274,0.25381930901456295,1.0294200554294395,14.793780098344119,0.4291587372140098,0.0,-0.9636891263962676,-0.29443704710319063,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",101,315,0,0.0,-1.1187912568514213,-0.2888905959354047,-1.1214625027188978,-0.2742072530579842,0.2460379440928326,0.25312916921017614,1.1752640737502726,12.772959574369287,0.4157688411867369,0.0,-1.1187912568514213,-0.2888905959354047,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",110,308,0,0.0,1.0223042813560053,-0.30523781431249886,1.0208525603382534,-0.3049588756084497,0.2485878198807318,0.25127291859371265,1.107172524312333,-18.19512513033301,0.4299588554499636,0.0,1.0223042813560053,-0.30523781431249886,1.0,0.0
|
||||||
|
"lab043_prbs11_s_20260819_150001: FIR+DC, проверочная половина",111,306,0,0.0,0.8747144510135012,-0.2956074210338545,0.8691220060249791,-0.3068578932042683,0.24697951882063934,0.2496747743040441,0.970047916342626,-20.588927935476164,0.4214355680933763,0.0,0.8747144510135012,-0.2956074210338545,1.0,0.0
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
capture,band_low_hz,band_high_hz,mean_transfer_magnitude,median_transfer_magnitude,mean_transfer_db
|
||||||
|
lab043_prbs11_s_20260819_134831,10,100,1.002069554851456,1.0049897256864089,0.017957349582434494
|
||||||
|
lab043_prbs11_s_20260819_134831,100,500,0.9661028865719044,0.989609261571821,-0.2995324056226316
|
||||||
|
lab043_prbs11_s_20260819_134831,500,1000,0.9182988982838727,0.945959496125638,-0.7403187344271658
|
||||||
|
lab043_prbs11_s_20260819_134831,1000,5000,0.9790711997415193,1.1012182577421776,-0.18371448813561786
|
||||||
|
lab043_prbs11_s_20260819_134831,5000,9000,1.181591435351549,1.1865979003577944,1.449346687495564
|
||||||
|
lab043_prbs11_s_20260819_150001,10,100,0.8477370942675726,0.8371031626924971,-1.4347762617504942
|
||||||
|
lab043_prbs11_s_20260819_150001,100,500,0.8188526554959003,0.8335873999651358,-1.7358847648402722
|
||||||
|
lab043_prbs11_s_20260819_150001,500,1000,0.6403369700347171,0.7224304126735926,-3.871828466762968
|
||||||
|
lab043_prbs11_s_20260819_150001,1000,5000,1.0158561997332687,1.0814306852225017,0.13664470851855184
|
||||||
|
lab043_prbs11_s_20260819_150001,5000,9000,1.184644227792827,1.1858019728540186,1.4717588532470873
|
||||||
|
33
data/processed/lab043_diagnostics/tx_stages_triplets.csv
Normal file
33
data/processed/lab043_diagnostics/tx_stages_triplets.csv
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
source,triplet,count,bit_errors,ber,mean_i,mean_q,median_i,median_q,std_i,std_q,mean_amplitude,mean_phase_error_deg,mean_distance_to_ideal,decision_cross_fraction,raw_mean_i,raw_mean_q,fitted_gain_i,fitted_gain_q
|
||||||
|
идеальные символы,000,618,0,0.0,-1.0,0.0,-1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,-1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,001,626,0,0.0,-1.0,0.0,-1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,-1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,010,625,0,0.0,1.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,011,623,0,0.0,1.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,100,626,0,0.0,-1.0,0.0,-1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,-1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,101,622,0,0.0,-1.0,0.0,-1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,-1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,110,624,0,0.0,1.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,1.0,0.0
|
||||||
|
идеальные символы,111,634,0,0.0,1.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,0.0,1.0,0.0
|
||||||
|
после TX RRC,000,618,0,0.0,-0.8447211351853866,-3.16637664624025e-17,-0.8458174838489158,-2.043476895199683e-17,0.08195783733693278,2.7724800523357534e-16,0.8447211351853866,2.1954275938784535e-15,0.1555852928589922,0.0,-0.08445216029186903,-3.5918389295957526e-18,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,001,626,0,0.0,-1.0004050270462215,5.689638487900804e-18,-1.0004890125643966,1.5852663216863385e-17,0.081268756901431,2.8173172396551604e-16,1.0004050270462215,-4.2381688289265534e-16,0.06554468539821465,0.0,-0.10001687205607476,6.406779338691513e-20,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,010,625,0,0.0,1.153590974720758,-3.664785498955269e-18,1.1551605412798769,-3.169233802432743e-18,0.08187034700843802,2.918987738801931e-16,1.153590974720758,-1.1741880644801756e-16,0.15394987495320192,0.0,0.11533184840579361,2.156607645445083e-19,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,011,623,0,0.0,0.9999766504304199,9.543270215936798e-18,1.0004890125643962,1.121968145257086e-17,0.08176939641698396,2.913164939367553e-16,0.9999766504304199,5.344798879995152e-16,0.06626105529395579,0.0,0.0999740445132135,1.4586471186719179e-18,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,100,626,0,0.0,-1.000209162092668,5.858564348969746e-18,-1.0004890125643962,9.042609602079001e-18,0.08157874188457086,2.9409492093087693e-16,1.000209162092668,-2.692785457920202e-16,0.06569607217373102,0.0,-0.09999729018726143,8.105521437455294e-20,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,101,622,0,0.0,-1.154560683753055,2.2676007987771794e-17,-1.155160541279877,2.2885397049242972e-17,0.08131379694938634,2.7413402469108926e-16,1.154560683753055,-1.0789996143200499e-15,0.1548792650197144,0.0,-0.11542879640344733,1.6845231449320436e-18,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,110,624,0,0.0,0.9998120280379368,-6.970963253964133e-18,1.0004890125643966,-1.4807615813401128e-17,0.08131500141429798,2.76893706766613e-16,0.9998120280379368,-3.7885745089968316e-16,0.06579158206105619,0.0,0.09995758616252412,-1.9246920569558615e-19,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после TX RRC,111,634,0,0.0,0.8478758083346417,3.2719991252106793e-18,0.8458174838489161,1.0253160945110266e-17,0.08055200459377172,2.958183391880481e-16,0.8478758083346417,2.793911358621806e-16,0.15252059362674364,0.0,0.08476755309000336,7.549245534916749e-19,0.09997637891862943,5.0455730063634775e-19
|
||||||
|
после масштаба 0.70,000,618,0,0.0,-0.8447211351853869,-3.16637664624025e-17,-0.845817483848916,-2.043476895199683e-17,0.08195783733693278,2.7724800523357544e-16,0.8447211351853869,2.1954275938784535e-15,0.15558529285899203,0.0,-0.05911651220430831,-2.514287250717027e-18,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,001,626,0,0.0,-1.0004050270462215,5.6896384879008164e-18,-1.0004890125643968,1.585266321686339e-17,0.08126875690143102,2.817317239655161e-16,1.0004050270462215,-4.238168828926557e-16,0.06554468539821467,0.0,-0.07001181043925234,4.4847455370840576e-20,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,010,625,0,0.0,1.1535909747207584,-3.6647854989552794e-18,1.155160541279877,-3.169233802432749e-18,0.08187034700843805,2.9189877388019315e-16,1.1535909747207584,-1.1741880644801798e-16,0.15394987495320214,0.0,0.0807322938840555,1.5096253518115591e-19,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,011,623,0,0.0,0.9999766504304202,9.543270215936798e-18,1.0004890125643966,1.1219681452570858e-17,0.08176939641698398,2.9131649393675533e-16,0.9999766504304202,5.344798879995148e-16,0.06626105529395582,0.0,0.06998183115924946,1.0210529830703427e-18,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,100,626,0,0.0,-1.000209162092668,5.858564348969753e-18,-1.0004890125643966,9.042609602079007e-18,0.08157874188457087,2.94094920930877e-16,1.000209162092668,-2.6927854579202056e-16,0.06569607217373108,0.0,-0.069998103131083,5.673865006218707e-20,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,101,622,0,0.0,-1.1545606837530553,2.2676007987771806e-17,-1.1551605412798773,2.288539704924298e-17,0.08131379694938637,2.741340246910893e-16,1.1545606837530553,-1.0789996143200503e-15,0.1548792650197147,0.0,-0.08080015748241312,1.17916620145243e-18,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,110,624,0,0.0,0.9998120280379368,-6.97096325396414e-18,1.0004890125643968,-1.4807615813401134e-17,0.081315001414298,2.7689370676661305e-16,0.9998120280379368,-3.788574508996836e-16,0.06579158206105622,0.0,0.06997031031376687,-1.3472844398691038e-19,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после масштаба 0.70,111,634,0,0.0,0.847875808334642,3.2719991252106723e-18,0.8458174838489162,1.0253160945110262e-17,0.08055200459377174,2.9581833918804815e-16,0.847875808334642,2.7939113586218023e-16,0.15252059362674344,0.0,0.059337287163002336,5.284471874441723e-19,0.06998346524304058,3.5319011044544367e-19
|
||||||
|
после complex64 и масштаба 2^14,000,618,0,0.0,-0.844721132164728,-3.166376645611102e-17,-0.8458174850382276,-2.043476819321968e-17,0.08195783531366697,2.77248005175605e-16,0.844721132164728,2.1954275974653788e-15,0.15558529653595318,0.0,-968.56494140625,-4.119408197260192e-14,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,001,626,0,0.0,-1.0004050290806876,5.689638700515076e-18,-1.0004890108573807,1.5852663367733532e-17,0.08126874885830437,2.817317238213439e-16,1.0004050290806876,-4.2381688127743276e-16,0.06554467131341328,0.0,-1147.073486328125,7.347805941336938e-16,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,010,625,0,0.0,1.1535909745425856,-3.664784928636354e-18,1.155160536676534,-3.169233843845358e-18,0.0818703482908584,2.918987737957422e-16,1.1535909745425856,-1.1741877813699304e-16,0.15394987537165816,0.0,1322.7178955078125,2.473370087300447e-15,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,011,623,0,0.0,0.9999766517391538,9.54327018742428e-18,1.0004890108573807,1.1219680713135247e-17,0.08176938762246996,2.9131649404141736e-16,0.9999766517391538,5.344798719659834e-16,0.06626104078643395,0.0,1146.5823974609375,1.6728931201458533e-14,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,100,626,0,0.0,-1.0002091641465911,5.858564725237296e-18,-1.0004890108573807,9.042609737912825e-18,0.08157873479071351,2.940949208401175e-16,1.0002091641465911,-2.692785710658976e-16,0.06569605903394975,0.0,-1146.8489990234375,9.296050012053201e-16,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,101,622,0,0.0,-1.1545606831392217,2.2676007803645295e-17,-1.155160536676534,2.2885397145632995e-17,0.08131379747849762,2.7413402489492663e-16,1.1545606831392217,-1.0789995911324584e-15,0.1548792650014609,0.0,-1323.829833984375,1.9319459497891406e-14,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,110,624,0,0.0,0.999812029920823,-6.970963557473678e-18,1.0004890108573807,-1.480761617308785e-17,0.08131499356745366,2.7689370656125954e-16,0.999812029920823,-3.788574570769471e-16,0.06579156845621685,0.0,1146.3936767578125,-2.207392636258414e-15,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
после complex64 и масштаба 2^14,111,634,0,0.0,0.8478758048905635,3.2719992899553873e-18,0.8458174850382276,1.025316095104262e-17,0.08055200208688879,2.9581833895628747e-16,0.8478758048905635,2.7939113076495106e-16,0.1525205978252917,0.0,972.1821899414062,8.658077713433708e-15,1146.6090955078125,5.7866669273070975e-15
|
||||||
|
4
data/processed/lab043_hackrf_compare/continuity.csv
Normal file
4
data/processed/lab043_hackrf_compare/continuity.csv
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
boundary_sample,low_phase_jump_rad,high_phase_jump_rad
|
||||||
|
2490368,-0.2270746402238407,0.936322989443652
|
||||||
|
2621440,-1.685691421437402,0.09155935561800127
|
||||||
|
2752512,-1.962337630395535,1.0596287040560621
|
||||||
|
32
data/processed/lab043_hackrf_compare/report.txt
Normal file
32
data/processed/lab043_hackrf_compare/report.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Lab043: единственный сравнительный S с HackRF
|
||||||
|
|
||||||
|
Результат: недействителен для BER и локализации асимметрии 000/001.
|
||||||
|
Классификация: D, данных недостаточно для локализации.
|
||||||
|
|
||||||
|
Raw: data\raw\lab043_hackrf\lab043_hackrf_prbs11_s_20260820_141720.npy
|
||||||
|
SHA-256: 02cd707262c042404cd8b9ac5176e2e24ee74fcf84e5f64223c2c22015958962
|
||||||
|
Waveform SHA-256: 981aeddde3ed63192c24bfbe8a11f58b2896b50a643dd5faf3f81eaa9c2bf0bc
|
||||||
|
|
||||||
|
HackRF: 000000000000000097c063dc323b97d3, firmware 2024.02.1 (API:1.08), libhackrf 2024.02.1 (0.9).
|
||||||
|
RX: 435 МГц, запрос 2 400 000 отсчётов/с, RF amp OFF, LNA 0 дБ, VGA 0 дБ.
|
||||||
|
Pluto+: фактически 435000000 Гц, 2399998 отсчётов/с, gain -30.0 дБ, RF bandwidth 200000 Гц.
|
||||||
|
|
||||||
|
Программная сборка: 32 рабочих callback после одного заранее отброшенного разогревочного; индексы последовательны, дубликатов полных блоков 0, пропусков очереди 0.
|
||||||
|
Средняя callback-скорость: 2399817.412 отсчётов/с.
|
||||||
|
USB-потери аппаратно не доказаны и не опровергнуты: внутреннего счётчика API нет.
|
||||||
|
|
||||||
|
Два тона найдены неизменным спектральным порогом 10 дБ: нижний +15.582 дБ, верхний +15.510 дБ.
|
||||||
|
Максимальный рост полной мощности: только 0.871 дБ, поэтому исходный широкополосный локатор не сработал.
|
||||||
|
Предварительная оценка CFO: +462.074 Гц (+1.062239 ppm).
|
||||||
|
Предварительная оценка SRO: +273.149 ppm.
|
||||||
|
Эти оценки нельзя считать итоговыми: RMSE фазовой модели 19.909 рад и в калибровке подтверждено 3 фазовых разрыва из 3 проверенных границ; максимум 1.962 рад при пределе 0,25 рад.
|
||||||
|
|
||||||
|
Маркер: N/A.
|
||||||
|
BER (доля ошибочных битов): N/A.
|
||||||
|
BER по четвертям: N/A.
|
||||||
|
EVM (величина вектора ошибки): N/A.
|
||||||
|
Тройки 000–111, серии и кластеры: N/A, чтобы не выдавать недостоверный захват за измерение.
|
||||||
|
|
||||||
|
Сравнение с RTL-SDR невозможно: два RTL-SDR S валидны, а HackRF S не прошёл контроль непрерывности. Главный текущий подозреваемый не 000/001-механизм, а достоверность приёма HackRF на минимальном усилении и/или непрерывность USB/драйвера. Усиления и пороги не менялись, повторный TX не выполнялся.
|
||||||
|
|
||||||
|
Следующий шаг, пока не выполненный: отдельно доказать непрерывность HackRF RX и достаточную фазовую точность на 2,4 Мвыб/с без изменения протокола; только затем отдельно решить, разрешать ли новый S или изменение усиления.
|
||||||
15
data/processed/lab043_hackrf_compare/run_lengths.csv
Normal file
15
data/processed/lab043_hackrf_compare/run_lengths.csv
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
bit,run_length,status,reason
|
||||||
|
0,1,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,2,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,3,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,4,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,5,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,6,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
0,7+,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,1,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,2,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,3,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,4,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,5,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,6,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
1,7+,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
2
data/processed/lab043_hackrf_compare/summary.csv
Normal file
2
data/processed/lab043_hackrf_compare/summary.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
receiver,capture,result_valid,invalid_reason,raw_iq_sha256,sample_count,marker_detected,marker_correlation,carrier_offset_hz_preliminary,carrier_offset_ppm_preliminary,sample_clock_error_ppm_preliminary,phase_fit_rmse_rad,mode_b_bit_errors,mode_b_ber,mode_b_evm_percent,peak_magnitude,clipped_component_fraction,callback_count,accepted_callback_count,program_continuity_confirmed,usb_continuity_proven,mean_callback_stream_sample_rate_hz,confirmed_phase_discontinuities,maximum_phase_jump_rad,classification
|
||||||
|
HackRF,lab043_hackrf_prbs11_s_20260820_141720,False,в той же записи подтверждён фазовый разрыв,02cd707262c042404cd8b9ac5176e2e24ee74fcf84e5f64223c2c22015958962,4139314,False,nan,462.0737655540943,1.062238541503665,273.14863907035306,19.90879367182428,N/A,N/A,N/A,0.0390625,0.0,33,32,True,False,2399817.411963232,3,1.962337630395535,D
|
||||||
|
9
data/processed/lab043_hackrf_compare/triplets.csv
Normal file
9
data/processed/lab043_hackrf_compare/triplets.csv
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
triplet,status,reason
|
||||||
|
000,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
001,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
010,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
011,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
100,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
101,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
110,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
111,N/A,захват недействителен из-за фазовых разрывов
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
received_symbol_index,expected_state_number,recognized_state_number,expected_next_position,actual_next_position,position_delta_symbols,minimum_confirmed_gap_symbols,type,estimated_raw_sample_index,nearest_callback_index,signed_distance_to_callback_samples,distance_category,distance_to_nearest_midpoint_samples,local_mean_amplitude,local_peak_amplitude,before_mean_amplitude,after_mean_amplitude,local_exact_zero_fraction,exact_lost_or_repeated_iq_samples
|
||||||
|
13
data/processed/lab043_hackrf_continuity/report.txt
Normal file
13
data/processed/lab043_hackrf_continuity/report.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Lab043: цифровой счётчик непрерывности HackRF
|
||||||
|
|
||||||
|
Классификация: D.
|
||||||
|
Причина: Недостаточно достоверно восстановленных полезных символов.
|
||||||
|
Передано символов: 110000, полезных: 100000.
|
||||||
|
Восстановлено полезных позиций: 0.
|
||||||
|
Обычных ошибок символов: N/A.
|
||||||
|
Подтверждённых скачков позиции: 0.
|
||||||
|
Пропусков: 0; повторов: 0; вставок: 0.
|
||||||
|
Непрерывность цифровой последовательности: НЕ ОПРЕДЕЛЕНО.
|
||||||
|
Непрерывность сырых I/Q-отсчётов: НЕ ОПРЕДЕЛЕНО.
|
||||||
|
|
||||||
|
I/Q означает синфазные и квадратурные комплексные отсчёты.
|
||||||
2
data/processed/lab043_hackrf_continuity/summary.csv
Normal file
2
data/processed/lab043_hackrf_continuity/summary.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
classification,reason,digital_sequence_continuity,raw_iq_continuity,raw_iq_reason,transmitted_symbol_count,useful_transmitted_symbol_count,recovered_transmitted_position_count,recovered_useful_position_count,ordinary_symbol_error_count,confirmed_position_jump_count,skip_event_count,repeat_event_count,insertion_event_count,ambiguous_event_count,anchor_count,stable_run_count,recovered_symbol_count,carrier_offset_hz,carrier_peak_above_noise_db,samples_per_symbol,sample_clock_error_ppm
|
||||||
|
D,Недостаточно достоверно восстановленных полезных символов,НЕ ОПРЕДЕЛЕНО,НЕ ОПРЕДЕЛЕНО,"Цифровая последовательность доказывает порядок символов, но сама по себе не доказывает сохранность каждого I/Q-отсчёта",110000,100000,0,0,N/A,0,0,0,0,0,0,0,0,-70.86010002260534,5.072038638260837,120.00238998532383,19.916544365283784
|
||||||
|
1
data/processed/lab043_hackrf_counter/discontinuities.csv
Normal file
1
data/processed/lab043_hackrf_counter/discontinuities.csv
Normal file
@@ -0,0 +1 @@
|
|||||||
|
received_symbol_index,expected_state_number,recognized_state_number,expected_next_position,actual_next_position,position_delta_symbols,minimum_confirmed_gap_symbols,type,estimated_raw_sample_index,nearest_callback_index,signed_distance_to_callback_samples,distance_category,distance_to_nearest_midpoint_samples,local_mean_amplitude,local_peak_amplitude,before_mean_amplitude,after_mean_amplitude,local_exact_zero_fraction,exact_lost_or_repeated_iq_samples,exact_iq_sample_count_status,exact_iq_sample_count_reason
|
||||||
|
13
data/processed/lab043_hackrf_counter/report.txt
Normal file
13
data/processed/lab043_hackrf_counter/report.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Lab043: цифровой счётчик непрерывности HackRF
|
||||||
|
|
||||||
|
Классификация: D.
|
||||||
|
Причина: Недостаточно достоверно восстановленных полезных символов.
|
||||||
|
Передано символов: 110000, полезных: 100000.
|
||||||
|
Восстановлено полезных позиций: 0.
|
||||||
|
Обычных ошибок символов: None.
|
||||||
|
Подтверждённых скачков позиции: 0.
|
||||||
|
Пропусков: 0; повторов: 0; вставок: 0.
|
||||||
|
Непрерывность цифровой последовательности: НЕ ОПРЕДЕЛЕНО.
|
||||||
|
Непрерывность сырых I/Q-отсчётов: НЕ ОПРЕДЕЛЕНО.
|
||||||
|
|
||||||
|
I/Q означает синфазные и квадратурные комплексные отсчёты.
|
||||||
2
data/processed/lab043_hackrf_counter/summary.csv
Normal file
2
data/processed/lab043_hackrf_counter/summary.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
classification,reason,digital_sequence_continuity,raw_iq_continuity,raw_iq_reason,transmitted_symbol_count,useful_transmitted_symbol_count,recovered_transmitted_position_count,recovered_useful_position_count,ordinary_symbol_error_count,ordinary_symbol_error_count_status,confirmed_position_jump_count,skip_event_count,repeat_event_count,insertion_event_count,ambiguous_event_count,anchor_count,stable_run_count,recovered_symbol_count,carrier_offset_hz,carrier_peak_above_noise_db,samples_per_symbol,sample_clock_error_ppm
|
||||||
|
D,Недостаточно достоверно восстановленных полезных символов,НЕ ОПРЕДЕЛЕНО,НЕ ОПРЕДЕЛЕНО,"Цифровая последовательность доказывает порядок символов, но сама по себе не доказывает сохранность каждого I/Q-отсчёта",110000,100000,0,0,,not_computed,0,0,0,0,0,0,0,0,-75.30663390057586,4.523106594908998,120.0023194133997,19.328444997634975
|
||||||
|
@@ -0,0 +1,205 @@
|
|||||||
|
{
|
||||||
|
"experiment": "Lab043 HackRF RX gain ladder with one continuous tone",
|
||||||
|
"started_utc": "2026-08-20T15:51:40.472441Z",
|
||||||
|
"physical_scheme": "Pluto+ TX -> SMA -> AT30S 30 dB -> HackRF RX; antennas removed",
|
||||||
|
"method": "one continuous cyclic Pluto tone; separate short HackRF RX sessions per gain point",
|
||||||
|
"fixed_gain_ladder": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
8,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
[
|
||||||
|
24,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
[
|
||||||
|
24,
|
||||||
|
24
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fixed_thresholds": {
|
||||||
|
"desirable_tone_over_noise_db": 35.0,
|
||||||
|
"near_limit_component": 0.9,
|
||||||
|
"preferred_max_component": 0.75,
|
||||||
|
"clipped_component": 0.9921875,
|
||||||
|
"near_limit_fraction_stop": 0.0001,
|
||||||
|
"nonlinear_harmonic_limit_dbc": -30.0
|
||||||
|
},
|
||||||
|
"pluto_preflight": {
|
||||||
|
"uri": "ip:192.168.2.1",
|
||||||
|
"context_opened": true,
|
||||||
|
"phy_name": "ad9361-phy",
|
||||||
|
"tx_device_name": "cf-ad9361-dds-core-lpc",
|
||||||
|
"first_tx_channel": "voltage0"
|
||||||
|
},
|
||||||
|
"hackrf_preflight": {
|
||||||
|
"model": "HackRF One",
|
||||||
|
"serial_number": "000000000000000097c063dc323b97d3",
|
||||||
|
"firmware_version": "2024.02.1 (API:1.08)",
|
||||||
|
"libhackrf_version": "2024.02.1 (0.9)",
|
||||||
|
"hardware_revision": "r9",
|
||||||
|
"hackrf_info_version": "2024.02.1",
|
||||||
|
"information_query": "hackrf_info version: 2024.02.1\nlibhackrf version: 2024.02.1 (0.9)\nFound HackRF\nIndex: 0\nSerial number: 000000000000000097c063dc323b97d3\nBoard ID Number: 4 (HackRF One)\nFirmware Version: 2024.02.1 (API:1.08)\nPart ID Number: 0xa000cb3c 0x00744f5a\nHardware Revision: r9\nHardware does not appear to have been manufactured by Great Scott Gadgets.\nHardware supported by installed firmware:\n HackRF One",
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"set_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000.0,
|
||||||
|
"set_sample_rate_hz": 2400000.0,
|
||||||
|
"sample_rate_readback_available": false,
|
||||||
|
"center_frequency_readback_available": false,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"device_opened_via_libhackrf": true,
|
||||||
|
"rx_started": true,
|
||||||
|
"probe_sample_count": 65536,
|
||||||
|
"probe_dtype": "complex64",
|
||||||
|
"probe_mean_i": -0.02207362651824951,
|
||||||
|
"probe_mean_q": 0.023364543914794922,
|
||||||
|
"probe_rms": 0.032287873327732086,
|
||||||
|
"probe_peak_magnitude": 0.03314562886953354,
|
||||||
|
"probe_clipped_component_fraction": 0.0,
|
||||||
|
"probe_stream": {
|
||||||
|
"callback_count_total": 2,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 1,
|
||||||
|
"received_bytes_including_warmup": 524288,
|
||||||
|
"accepted_bytes": 131072,
|
||||||
|
"accepted_sample_count": 65536,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 14833.3008998,
|
||||||
|
"stream_stopped_monotonic": 14833.4274047,
|
||||||
|
"stream_wall_seconds": 0.12650489999941783,
|
||||||
|
"accepted_interval_seconds": 0.05461333333333333,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2400000.0,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tx_parameters": {
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"actual_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000,
|
||||||
|
"actual_sample_rate_hz": 2399998,
|
||||||
|
"requested_gain_db": -30.0,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
"requested_rf_bandwidth_hz": 200000,
|
||||||
|
"actual_rf_bandwidth_hz": 200000
|
||||||
|
},
|
||||||
|
"rx_parameters": {
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"set_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000.0,
|
||||||
|
"set_sample_rate_hz": 2400000.0,
|
||||||
|
"sample_rate_readback_available": false,
|
||||||
|
"center_frequency_readback_available": false,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"antenna_bias_enabled": false
|
||||||
|
},
|
||||||
|
"actual_transmitted_tone_offset_hz": 49999.958333333336,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"completed_step_count": 1,
|
||||||
|
"stop_reason": "перегрузка/близость к пределу/гармоническая нелинейность",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"step_index": 0,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"gain_configuration": {
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"gain_readback_available": false,
|
||||||
|
"set_calls_succeeded": true
|
||||||
|
},
|
||||||
|
"capture_diagnostics": {
|
||||||
|
"callback_count_total": 20,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 19,
|
||||||
|
"received_bytes_including_warmup": 5242880,
|
||||||
|
"accepted_bytes": 4800000,
|
||||||
|
"accepted_sample_count": 2400000,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 14833.9455921,
|
||||||
|
"stream_stopped_monotonic": 14835.0408997,
|
||||||
|
"stream_wall_seconds": 1.095307599998705,
|
||||||
|
"accepted_interval_seconds": 1.015633833332328,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2452033.319753656,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"sample_count": 1800000,
|
||||||
|
"fft_samples": 262144,
|
||||||
|
"fft_segment_count": 6,
|
||||||
|
"fft_resolution_hz": 9.1552734375,
|
||||||
|
"tone_frequency_hz": 50553.32330951437,
|
||||||
|
"tone_peak_bin_hz": 50555.419921875,
|
||||||
|
"tone_power_dbfs": -81.28323863999425,
|
||||||
|
"noise_floor_dbfs_per_fft_bin": -102.8470903549844,
|
||||||
|
"tone_over_noise_db": 21.56385171499015,
|
||||||
|
"mean_amplitude": 0.03218085318803787,
|
||||||
|
"rms_amplitude": 0.03224262222647667,
|
||||||
|
"maximum_amplitude": 0.03314562886953354,
|
||||||
|
"maximum_component": 0.0234375,
|
||||||
|
"near_limit_component_fraction": 0.0,
|
||||||
|
"clipped_component_fraction": 0.0,
|
||||||
|
"dc_mean_i": -0.021994179114699364,
|
||||||
|
"dc_mean_q": 0.023369232192635536,
|
||||||
|
"second_harmonic_dbc": -17.033931670944185,
|
||||||
|
"third_harmonic_dbc": -16.93934642712324,
|
||||||
|
"harmonic_nonlinearity_detected": true,
|
||||||
|
"stop_gain_escalation": true,
|
||||||
|
"stop_reason": "перегрузка/близость к пределу/гармоническая нелинейность"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preferred_gain": null,
|
||||||
|
"digital_experiment_authorized": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
{
|
||||||
|
"experiment": "Lab043 HackRF RX gain ladder with one continuous tone",
|
||||||
|
"started_utc": "2026-08-20T16:14:24.031539Z",
|
||||||
|
"physical_scheme": "Pluto+ TX -> SMA -> AT30S 30 dB -> HackRF RX; antennas removed",
|
||||||
|
"method": "one continuous cyclic Pluto tone; separate short HackRF RX sessions per gain point",
|
||||||
|
"fixed_gain_ladder": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
8,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
[
|
||||||
|
24,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
[
|
||||||
|
24,
|
||||||
|
24
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fixed_thresholds": {
|
||||||
|
"desirable_tone_over_noise_db": 35.0,
|
||||||
|
"near_limit_component": 0.9,
|
||||||
|
"preferred_max_component": 0.75,
|
||||||
|
"clipped_component": 0.9921875,
|
||||||
|
"near_limit_fraction_stop": 0.0001,
|
||||||
|
"nonlinear_harmonic_limit_dbc": -30.0,
|
||||||
|
"harmonic_detection_margin_db": 10.0,
|
||||||
|
"harmonic_search_half_width_hz": 2000.0,
|
||||||
|
"harmonic_noise_outer_half_width_hz": 10000.0
|
||||||
|
},
|
||||||
|
"pluto_preflight": {
|
||||||
|
"uri": "ip:192.168.2.1",
|
||||||
|
"context_opened": true,
|
||||||
|
"phy_name": "ad9361-phy",
|
||||||
|
"tx_device_name": "cf-ad9361-dds-core-lpc",
|
||||||
|
"first_tx_channel": "voltage0"
|
||||||
|
},
|
||||||
|
"hackrf_preflight": {
|
||||||
|
"model": "HackRF One",
|
||||||
|
"serial_number": "000000000000000097c063dc323b97d3",
|
||||||
|
"firmware_version": "2024.02.1 (API:1.08)",
|
||||||
|
"libhackrf_version": "2024.02.1 (0.9)",
|
||||||
|
"hardware_revision": "r9",
|
||||||
|
"hackrf_info_version": "2024.02.1",
|
||||||
|
"information_query": "hackrf_info version: 2024.02.1\nlibhackrf version: 2024.02.1 (0.9)\nFound HackRF\nIndex: 0\nSerial number: 000000000000000097c063dc323b97d3\nBoard ID Number: 4 (HackRF One)\nFirmware Version: 2024.02.1 (API:1.08)\nPart ID Number: 0xa000cb3c 0x00744f5a\nHardware Revision: r9\nHardware does not appear to have been manufactured by Great Scott Gadgets.\nHardware supported by installed firmware:\n HackRF One",
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"set_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000.0,
|
||||||
|
"set_sample_rate_hz": 2400000.0,
|
||||||
|
"sample_rate_readback_available": false,
|
||||||
|
"center_frequency_readback_available": false,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"device_opened_via_libhackrf": true,
|
||||||
|
"rx_started": true,
|
||||||
|
"probe_sample_count": 65536,
|
||||||
|
"probe_dtype": "complex64",
|
||||||
|
"probe_mean_i": -0.02216637134552002,
|
||||||
|
"probe_mean_q": 0.023369193077087402,
|
||||||
|
"probe_rms": 0.032346732914447784,
|
||||||
|
"probe_peak_magnitude": 0.03314562886953354,
|
||||||
|
"probe_clipped_component_fraction": 0.0,
|
||||||
|
"probe_stream": {
|
||||||
|
"callback_count_total": 2,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 1,
|
||||||
|
"received_bytes_including_warmup": 524288,
|
||||||
|
"accepted_bytes": 131072,
|
||||||
|
"accepted_sample_count": 65536,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 16196.8526212,
|
||||||
|
"stream_stopped_monotonic": 16196.9628548,
|
||||||
|
"stream_wall_seconds": 0.11023360000035609,
|
||||||
|
"accepted_interval_seconds": 0.05461333333333333,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2400000.0,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tx_parameters": {
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"actual_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000,
|
||||||
|
"actual_sample_rate_hz": 2399998,
|
||||||
|
"requested_gain_db": -30.0,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
"requested_rf_bandwidth_hz": 200000,
|
||||||
|
"actual_rf_bandwidth_hz": 200000
|
||||||
|
},
|
||||||
|
"rx_parameters": {
|
||||||
|
"requested_center_frequency_hz": 435000000,
|
||||||
|
"set_center_frequency_hz": 435000000,
|
||||||
|
"requested_sample_rate_hz": 2400000.0,
|
||||||
|
"set_sample_rate_hz": 2400000.0,
|
||||||
|
"sample_rate_readback_available": false,
|
||||||
|
"center_frequency_readback_available": false,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"antenna_bias_enabled": false
|
||||||
|
},
|
||||||
|
"actual_transmitted_tone_offset_hz": 49999.958333333336,
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"completed_step_count": 3,
|
||||||
|
"stop_reason": "перегрузка/близость к пределу/гармоническая нелинейность",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"step_index": 0,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"gain_configuration": {
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"gain_readback_available": false,
|
||||||
|
"set_calls_succeeded": true
|
||||||
|
},
|
||||||
|
"capture_diagnostics": {
|
||||||
|
"callback_count_total": 20,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 19,
|
||||||
|
"received_bytes_including_warmup": 5242880,
|
||||||
|
"accepted_bytes": 4800000,
|
||||||
|
"accepted_sample_count": 2400000,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 16197.5058473,
|
||||||
|
"stream_stopped_monotonic": 16198.599203,
|
||||||
|
"stream_wall_seconds": 1.0933556999989378,
|
||||||
|
"accepted_interval_seconds": 1.0374631333339555,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2400439.996356343,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"sample_count": 1800000,
|
||||||
|
"fft_samples": 262144,
|
||||||
|
"fft_segment_count": 6,
|
||||||
|
"fft_resolution_hz": 9.1552734375,
|
||||||
|
"tone_frequency_hz": 50555.09081574355,
|
||||||
|
"tone_peak_bin_hz": 50555.419921875,
|
||||||
|
"tone_power_dbfs": -79.8521010939479,
|
||||||
|
"noise_floor_dbfs_per_fft_bin": -102.22903287394465,
|
||||||
|
"tone_over_noise_db": 22.376931779996752,
|
||||||
|
"mean_amplitude": 0.03206367790699005,
|
||||||
|
"rms_amplitude": 0.032130662351846695,
|
||||||
|
"maximum_amplitude": 0.03493856266140938,
|
||||||
|
"maximum_component": 0.03125,
|
||||||
|
"near_limit_component_fraction": 0.0,
|
||||||
|
"clipped_component_fraction": 0.0,
|
||||||
|
"dc_mean_i": -0.02178940176963806,
|
||||||
|
"dc_mean_q": 0.023389514535665512,
|
||||||
|
"second_harmonic": {
|
||||||
|
"order": 2,
|
||||||
|
"expected_frequency_hz": 101110.1816314871,
|
||||||
|
"peak_frequency_hz": 103042.6025390625,
|
||||||
|
"peak_power_dbfs": -97.16303551095399,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -102.3624373861,
|
||||||
|
"above_local_noise_db": 5.199401875146009,
|
||||||
|
"relative_to_fundamental_db": -17.310934417006095,
|
||||||
|
"credible": false,
|
||||||
|
"nonlinear": false
|
||||||
|
},
|
||||||
|
"third_harmonic": {
|
||||||
|
"order": 3,
|
||||||
|
"expected_frequency_hz": 151665.27244723076,
|
||||||
|
"peak_frequency_hz": 151263.427734375,
|
||||||
|
"peak_power_dbfs": -97.44245378672434,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -102.34809348021747,
|
||||||
|
"above_local_noise_db": 4.905639693493129,
|
||||||
|
"relative_to_fundamental_db": -17.59035269277645,
|
||||||
|
"credible": false,
|
||||||
|
"nonlinear": false
|
||||||
|
},
|
||||||
|
"second_harmonic_dbc": -17.310934417006095,
|
||||||
|
"third_harmonic_dbc": -17.59035269277645,
|
||||||
|
"harmonic_nonlinearity_detected": false,
|
||||||
|
"stop_gain_escalation": false,
|
||||||
|
"stop_reason": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_index": 1,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"gain_configuration": {
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"gain_readback_available": false,
|
||||||
|
"set_calls_succeeded": true
|
||||||
|
},
|
||||||
|
"capture_diagnostics": {
|
||||||
|
"callback_count_total": 15,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 14,
|
||||||
|
"received_bytes_including_warmup": 3932160,
|
||||||
|
"accepted_bytes": 3600000,
|
||||||
|
"accepted_sample_count": 1800000,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 16198.9768347,
|
||||||
|
"stream_stopped_monotonic": 16199.7983054,
|
||||||
|
"stream_wall_seconds": 0.8214706999988266,
|
||||||
|
"accepted_interval_seconds": 0.7651954333319796,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2398090.6315784073,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"sample_count": 1800000,
|
||||||
|
"fft_samples": 262144,
|
||||||
|
"fft_segment_count": 6,
|
||||||
|
"fft_resolution_hz": 9.1552734375,
|
||||||
|
"tone_frequency_hz": 50555.29344158161,
|
||||||
|
"tone_peak_bin_hz": 50555.419921875,
|
||||||
|
"tone_power_dbfs": -75.07841275653543,
|
||||||
|
"noise_floor_dbfs_per_fft_bin": -105.14911967255102,
|
||||||
|
"tone_over_noise_db": 30.070706916015595,
|
||||||
|
"mean_amplitude": 0.03427855297923088,
|
||||||
|
"rms_amplitude": 0.03433648869395256,
|
||||||
|
"maximum_amplitude": 0.04207159951329231,
|
||||||
|
"maximum_component": 0.0390625,
|
||||||
|
"near_limit_component_fraction": 0.0,
|
||||||
|
"clipped_component_fraction": 0.0,
|
||||||
|
"dc_mean_i": -0.015552565455436707,
|
||||||
|
"dc_mean_q": 0.030518028885126114,
|
||||||
|
"second_harmonic": {
|
||||||
|
"order": 2,
|
||||||
|
"expected_frequency_hz": 101110.58688316331,
|
||||||
|
"peak_frequency_hz": 101110.83984375,
|
||||||
|
"peak_power_dbfs": -96.46551235195447,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -105.04563379125153,
|
||||||
|
"above_local_noise_db": 8.58012143929706,
|
||||||
|
"relative_to_fundamental_db": -21.387099595419045,
|
||||||
|
"credible": false,
|
||||||
|
"nonlinear": false
|
||||||
|
},
|
||||||
|
"third_harmonic": {
|
||||||
|
"order": 3,
|
||||||
|
"expected_frequency_hz": 151665.88032474485,
|
||||||
|
"peak_frequency_hz": 150769.04296875,
|
||||||
|
"peak_power_dbfs": -100.56316044640394,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -105.10576449464062,
|
||||||
|
"above_local_noise_db": 4.542604048236683,
|
||||||
|
"relative_to_fundamental_db": -25.484747689868513,
|
||||||
|
"credible": false,
|
||||||
|
"nonlinear": false
|
||||||
|
},
|
||||||
|
"second_harmonic_dbc": -21.387099595419045,
|
||||||
|
"third_harmonic_dbc": -25.484747689868513,
|
||||||
|
"harmonic_nonlinearity_detected": false,
|
||||||
|
"stop_gain_escalation": false,
|
||||||
|
"stop_reason": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_index": 2,
|
||||||
|
"lna_gain_db": 16,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"gain_configuration": {
|
||||||
|
"rf_amp_enabled": false,
|
||||||
|
"antenna_bias_enabled": false,
|
||||||
|
"lna_gain_db": 16,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"gain_readback_available": false,
|
||||||
|
"set_calls_succeeded": true
|
||||||
|
},
|
||||||
|
"capture_diagnostics": {
|
||||||
|
"callback_count_total": 15,
|
||||||
|
"warmup_callback_count": 1,
|
||||||
|
"accepted_callback_count": 14,
|
||||||
|
"received_bytes_including_warmup": 3932160,
|
||||||
|
"accepted_bytes": 3600000,
|
||||||
|
"accepted_sample_count": 1800000,
|
||||||
|
"callback_indexes_sequential": true,
|
||||||
|
"program_queue_missing_callback_count": 0,
|
||||||
|
"duplicate_full_block_hash_count": 0,
|
||||||
|
"observed_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_valid_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"stream_started_monotonic": 16200.181376,
|
||||||
|
"stream_stopped_monotonic": 16201.0025195,
|
||||||
|
"stream_wall_seconds": 0.8211434999993799,
|
||||||
|
"accepted_interval_seconds": 0.7650824333337428,
|
||||||
|
"mean_callback_stream_sample_rate_hz": 2398444.8211733233,
|
||||||
|
"expected_callback_bytes": 262144,
|
||||||
|
"observed_callback_byte_sizes": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"observed_callback_buffer_lengths": [
|
||||||
|
262144
|
||||||
|
],
|
||||||
|
"usb_loss_counter_available": false,
|
||||||
|
"usb_loss_claim": "N/A: libhackrf callback API не предоставляет счётчик потерь"
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"sample_count": 1800000,
|
||||||
|
"fft_samples": 262144,
|
||||||
|
"fft_segment_count": 6,
|
||||||
|
"fft_resolution_hz": 9.1552734375,
|
||||||
|
"tone_frequency_hz": 50555.418595322284,
|
||||||
|
"tone_peak_bin_hz": 50555.419921875,
|
||||||
|
"tone_power_dbfs": -65.25476329876575,
|
||||||
|
"noise_floor_dbfs_per_fft_bin": -103.39135933360873,
|
||||||
|
"tone_over_noise_db": 38.13659603484298,
|
||||||
|
"mean_amplitude": 0.033912722021341324,
|
||||||
|
"rms_amplitude": 0.0339985117316246,
|
||||||
|
"maximum_amplitude": 0.04207159951329231,
|
||||||
|
"maximum_component": 0.0390625,
|
||||||
|
"near_limit_component_fraction": 0.0,
|
||||||
|
"clipped_component_fraction": 0.0,
|
||||||
|
"dc_mean_i": -0.015441679395735264,
|
||||||
|
"dc_mean_q": 0.030141202732920647,
|
||||||
|
"second_harmonic": {
|
||||||
|
"order": 2,
|
||||||
|
"expected_frequency_hz": 101110.83719064458,
|
||||||
|
"peak_frequency_hz": 101110.83984375,
|
||||||
|
"peak_power_dbfs": -83.20641938155373,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -103.4224986210237,
|
||||||
|
"above_local_noise_db": 20.216079239469977,
|
||||||
|
"relative_to_fundamental_db": -17.951656082787977,
|
||||||
|
"credible": true,
|
||||||
|
"nonlinear": true
|
||||||
|
},
|
||||||
|
"third_harmonic": {
|
||||||
|
"order": 3,
|
||||||
|
"expected_frequency_hz": 151666.25578596676,
|
||||||
|
"peak_frequency_hz": 153103.6376953125,
|
||||||
|
"peak_power_dbfs": -98.4311096772575,
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": -103.40473622499643,
|
||||||
|
"above_local_noise_db": 4.973626547738931,
|
||||||
|
"relative_to_fundamental_db": -33.17634637849174,
|
||||||
|
"credible": false,
|
||||||
|
"nonlinear": false
|
||||||
|
},
|
||||||
|
"second_harmonic_dbc": -17.951656082787977,
|
||||||
|
"third_harmonic_dbc": -33.17634637849174,
|
||||||
|
"harmonic_nonlinearity_detected": true,
|
||||||
|
"stop_gain_escalation": true,
|
||||||
|
"stop_reason": "перегрузка/близость к пределу/гармоническая нелинейность"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preferred_gain": {
|
||||||
|
"step_index": 1,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"tone_over_noise_db": 30.070706916015595,
|
||||||
|
"desirable_margin_reached": false
|
||||||
|
},
|
||||||
|
"digital_experiment_authorized": false
|
||||||
|
}
|
||||||
1034
experiments/lab043_bpsk_asymmetry_diagnostics.py
Normal file
1034
experiments/lab043_bpsk_asymmetry_diagnostics.py
Normal file
File diff suppressed because it is too large
Load Diff
618
experiments/lab043_hackrf_continuity.py
Normal file
618
experiments/lab043_hackrf_continuity.py
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
"""Однотонная проверка непрерывности HackRF RX для Lab043.
|
||||||
|
|
||||||
|
Разрешён ровно один непрерывный комплексный тон Pluto+ +50 кГц. Здесь нет
|
||||||
|
BPSK, PRBS, пакетов, JPEG и HackRF TX.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from dataclasses import asdict, dataclass
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_hardware as hackrf
|
||||||
|
from experiments import lab043_pluto_to_rtlsdr as lab043
|
||||||
|
from experiments import lab043_prbs11_hardware as rtl_hardware
|
||||||
|
|
||||||
|
|
||||||
|
TONE_OFFSET_HZ = 50_000.0
|
||||||
|
TONE_AMPLITUDE = 0.35
|
||||||
|
TONE_SECONDS = 5.0
|
||||||
|
RX_LEADING_SECONDS = 0.75
|
||||||
|
RX_TRAILING_SECONDS = 0.75
|
||||||
|
STABLE_EDGE_SECONDS = 0.25
|
||||||
|
CYCLIC_PERIOD_COUNT = 4096
|
||||||
|
COARSE_FFT_SAMPLES = 262_144
|
||||||
|
TONE_MARGIN_THRESHOLD_DB = 10.0
|
||||||
|
BOUNDARY_PHASE_THRESHOLD_RAD = 0.25
|
||||||
|
LOCAL_PHASE_RMS_LIMIT_RAD = 0.35
|
||||||
|
BOUNDARY_SIDE_SAMPLES = 65_536
|
||||||
|
LOCAL_PHASE_BLOCK_SAMPLES = 32_768
|
||||||
|
LOCAL_PHASE_HOP_SAMPLES = 8_192
|
||||||
|
GLOBAL_PHASE_BLOCK_SAMPLES = 262_144
|
||||||
|
GLOBAL_PHASE_HOP_SAMPLES = 65_536
|
||||||
|
TRANSITION_BLOCK_SAMPLES = 16_384
|
||||||
|
TRANSITION_HOP_SAMPLES = 512
|
||||||
|
RAW_DIRECTORY = Path("data/raw/lab043_hackrf")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class TonePhaseFit:
|
||||||
|
frequency_hz: float
|
||||||
|
phase_at_reference_rad: float
|
||||||
|
phase_fit_rms_rad: float
|
||||||
|
maximum_phase_error_rad: float
|
||||||
|
projection_count: int
|
||||||
|
|
||||||
|
|
||||||
|
def build_periodic_tone(actual_sample_rate_hz: float) -> tuple[np.ndarray, float]:
|
||||||
|
"""Построить циклически непрерывный тон около +50 кГц."""
|
||||||
|
|
||||||
|
samples_per_cycle = int(round(actual_sample_rate_hz / TONE_OFFSET_HZ))
|
||||||
|
sample_count = samples_per_cycle * CYCLIC_PERIOD_COUNT
|
||||||
|
indexes = np.arange(sample_count, dtype=np.float64)
|
||||||
|
tone = TONE_AMPLITUDE * np.exp(
|
||||||
|
1j * 2.0 * np.pi * CYCLIC_PERIOD_COUNT * indexes / sample_count
|
||||||
|
)
|
||||||
|
actual_tone_hz = CYCLIC_PERIOD_COUNT * actual_sample_rate_hz / sample_count
|
||||||
|
return tone.astype(np.complex64), float(actual_tone_hz)
|
||||||
|
|
||||||
|
|
||||||
|
def _phase_projections(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
coarse_frequency_hz: float,
|
||||||
|
global_start_sample: int,
|
||||||
|
reference_sample: int,
|
||||||
|
block_samples: int,
|
||||||
|
hop_samples: int,
|
||||||
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
|
received = np.asarray(samples, dtype=np.complex64)
|
||||||
|
if len(received) < block_samples + 2 * hop_samples:
|
||||||
|
raise ValueError("Участок слишком короток для фазовой модели")
|
||||||
|
window = np.hanning(block_samples).astype(np.float64)
|
||||||
|
starts = np.arange(0, len(received) - block_samples + 1, hop_samples)
|
||||||
|
projections = np.empty(len(starts), dtype=np.complex128)
|
||||||
|
centers = np.empty(len(starts), dtype=np.float64)
|
||||||
|
local_indexes = np.arange(block_samples, dtype=np.float64)
|
||||||
|
for row, start in enumerate(starts):
|
||||||
|
absolute_start = global_start_sample + int(start)
|
||||||
|
relative_indexes = absolute_start - reference_sample + local_indexes
|
||||||
|
oscillator = np.exp(
|
||||||
|
-1j * 2.0 * np.pi * coarse_frequency_hz * relative_indexes / sample_rate_hz
|
||||||
|
)
|
||||||
|
projections[row] = np.sum(received[start : start + block_samples] * oscillator * window)
|
||||||
|
centers[row] = (
|
||||||
|
absolute_start + (block_samples - 1) / 2.0 - reference_sample
|
||||||
|
) / sample_rate_hz
|
||||||
|
return centers, projections
|
||||||
|
|
||||||
|
|
||||||
|
def fit_tone_phase(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
coarse_frequency_hz: float,
|
||||||
|
global_start_sample: int,
|
||||||
|
reference_sample: int,
|
||||||
|
block_samples: int,
|
||||||
|
hop_samples: int,
|
||||||
|
) -> TonePhaseFit:
|
||||||
|
"""Оценить частоту и фазу тона, не пересекая неизвестную границу."""
|
||||||
|
|
||||||
|
times, projections = _phase_projections(
|
||||||
|
samples,
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse_frequency_hz,
|
||||||
|
global_start_sample,
|
||||||
|
reference_sample,
|
||||||
|
block_samples,
|
||||||
|
hop_samples,
|
||||||
|
)
|
||||||
|
phases = np.unwrap(np.angle(projections))
|
||||||
|
weights = np.abs(projections) ** 2
|
||||||
|
design = np.column_stack((np.ones(len(times)), times))
|
||||||
|
root_weights = np.sqrt(weights / max(float(np.max(weights)), 1e-30))
|
||||||
|
coefficients, *_ = np.linalg.lstsq(
|
||||||
|
design * root_weights[:, None], phases * root_weights, rcond=None
|
||||||
|
)
|
||||||
|
fitted = design @ coefficients
|
||||||
|
residuals = phases - fitted
|
||||||
|
weight_sum = max(float(np.sum(weights)), 1e-30)
|
||||||
|
rms = math.sqrt(float(np.sum(weights * residuals**2)) / weight_sum)
|
||||||
|
return TonePhaseFit(
|
||||||
|
frequency_hz=float(coarse_frequency_hz + coefficients[1] / (2.0 * np.pi)),
|
||||||
|
phase_at_reference_rad=float(np.angle(np.exp(1j * coefficients[0]))),
|
||||||
|
phase_fit_rms_rad=float(rms),
|
||||||
|
maximum_phase_error_rad=float(np.max(np.abs(residuals))),
|
||||||
|
projection_count=int(len(projections)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def estimate_coarse_tone(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
fft_samples: int = COARSE_FFT_SAMPLES,
|
||||||
|
) -> dict:
|
||||||
|
"""Найти единственный тон около |50 кГц| по усреднённому спектру."""
|
||||||
|
|
||||||
|
received = np.asarray(samples, dtype=np.complex64)
|
||||||
|
if len(received) < fft_samples:
|
||||||
|
raise ValueError("Недостаточно отсчётов для фиксированного спектрального окна")
|
||||||
|
window = np.hanning(fft_samples).astype(np.float64)
|
||||||
|
accumulated = np.zeros(fft_samples, dtype=np.float64)
|
||||||
|
segment_count = len(received) // fft_samples
|
||||||
|
for index in range(segment_count):
|
||||||
|
segment = received[index * fft_samples : (index + 1) * fft_samples]
|
||||||
|
spectrum = np.fft.fft(segment * window)
|
||||||
|
accumulated += np.abs(spectrum) ** 2
|
||||||
|
powers = accumulated / segment_count
|
||||||
|
frequencies = np.fft.fftfreq(fft_samples, d=1.0 / sample_rate_hz)
|
||||||
|
search = (np.abs(frequencies) >= 35_000.0) & (np.abs(frequencies) <= 65_000.0)
|
||||||
|
candidate_indexes = np.flatnonzero(search)
|
||||||
|
peak_index = int(candidate_indexes[np.argmax(powers[candidate_indexes])])
|
||||||
|
peak_frequency = float(frequencies[peak_index])
|
||||||
|
local_noise = search & (np.abs(frequencies - peak_frequency) >= 2_000.0)
|
||||||
|
noise_floor = float(np.median(powers[local_noise]))
|
||||||
|
margin_db = 10.0 * math.log10(float(powers[peak_index]) / max(noise_floor, 1e-30))
|
||||||
|
resolution_hz = sample_rate_hz / fft_samples
|
||||||
|
left = (peak_index - 1) % fft_samples
|
||||||
|
right = (peak_index + 1) % fft_samples
|
||||||
|
y0, y1, y2 = np.log(np.maximum(powers[[left, peak_index, right]], 1e-300))
|
||||||
|
denominator = y0 - 2.0 * y1 + y2
|
||||||
|
offset_bins = 0.0 if abs(denominator) < 1e-18 else 0.5 * (y0 - y2) / denominator
|
||||||
|
refined = peak_frequency + float(offset_bins) * resolution_hz
|
||||||
|
return {
|
||||||
|
"frequency_hz": float(refined),
|
||||||
|
"peak_bin_frequency_hz": peak_frequency,
|
||||||
|
"tone_above_noise_db": float(margin_db),
|
||||||
|
"noise_floor_power": noise_floor,
|
||||||
|
"fft_resolution_hz": float(resolution_hz),
|
||||||
|
"fft_segment_count": int(segment_count),
|
||||||
|
"credible": bool(margin_db >= TONE_MARGIN_THRESHOLD_DB),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _wrap_phase(value: float) -> float:
|
||||||
|
return float(np.angle(np.exp(1j * value)))
|
||||||
|
|
||||||
|
|
||||||
|
def _transition_offset(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
coarse_frequency_hz: float,
|
||||||
|
global_start_sample: int,
|
||||||
|
boundary_sample: int,
|
||||||
|
before_fit: TonePhaseFit,
|
||||||
|
jump_rad: float,
|
||||||
|
) -> dict:
|
||||||
|
times, projections = _phase_projections(
|
||||||
|
samples,
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse_frequency_hz,
|
||||||
|
global_start_sample,
|
||||||
|
boundary_sample,
|
||||||
|
TRANSITION_BLOCK_SAMPLES,
|
||||||
|
TRANSITION_HOP_SAMPLES,
|
||||||
|
)
|
||||||
|
before_model = before_fit.phase_at_reference_rad + 2.0 * np.pi * (
|
||||||
|
before_fit.frequency_hz - coarse_frequency_hz
|
||||||
|
) * times
|
||||||
|
residual = np.unwrap(np.angle(projections * np.exp(-1j * before_model)))
|
||||||
|
kernel = np.ones(9, dtype=np.float64) / 9.0
|
||||||
|
smoothed = np.convolve(residual, kernel, mode="same")
|
||||||
|
guard = 4
|
||||||
|
usable = slice(guard, len(times) - guard)
|
||||||
|
target = jump_rad / 2.0
|
||||||
|
local_index = int(np.argmin(np.abs(smoothed[usable] - target))) + guard
|
||||||
|
return {
|
||||||
|
"transition_offset_samples": float(times[local_index] * sample_rate_hz),
|
||||||
|
"transition_resolution_samples": TRANSITION_HOP_SAMPLES,
|
||||||
|
"transition_window_half_width_samples": TRANSITION_BLOCK_SAMPLES // 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_callback_boundaries(
|
||||||
|
samples: np.ndarray,
|
||||||
|
boundaries: tuple[hackrf.HackrfBoundary, ...],
|
||||||
|
sample_rate_hz: float,
|
||||||
|
coarse_frequency_hz: float,
|
||||||
|
stable_start_sample: int,
|
||||||
|
stable_end_sample: int,
|
||||||
|
side_samples: int = BOUNDARY_SIDE_SAMPLES,
|
||||||
|
block_samples: int = LOCAL_PHASE_BLOCK_SAMPLES,
|
||||||
|
hop_samples: int = LOCAL_PHASE_HOP_SAMPLES,
|
||||||
|
) -> tuple[list[dict], dict]:
|
||||||
|
rows: list[dict] = []
|
||||||
|
for boundary in boundaries:
|
||||||
|
sample = int(boundary.accepted_end_sample)
|
||||||
|
if sample - side_samples < stable_start_sample or sample + side_samples > stable_end_sample:
|
||||||
|
continue
|
||||||
|
before = fit_tone_phase(
|
||||||
|
samples[sample - side_samples : sample],
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse_frequency_hz,
|
||||||
|
sample - side_samples,
|
||||||
|
sample,
|
||||||
|
block_samples,
|
||||||
|
hop_samples,
|
||||||
|
)
|
||||||
|
after = fit_tone_phase(
|
||||||
|
samples[sample : sample + side_samples],
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse_frequency_hz,
|
||||||
|
sample,
|
||||||
|
sample,
|
||||||
|
block_samples,
|
||||||
|
hop_samples,
|
||||||
|
)
|
||||||
|
jump = _wrap_phase(after.phase_at_reference_rad - before.phase_at_reference_rad)
|
||||||
|
credible = bool(
|
||||||
|
before.phase_fit_rms_rad <= LOCAL_PHASE_RMS_LIMIT_RAD
|
||||||
|
and after.phase_fit_rms_rad <= LOCAL_PHASE_RMS_LIMIT_RAD
|
||||||
|
)
|
||||||
|
confirmed = bool(credible and abs(jump) > BOUNDARY_PHASE_THRESHOLD_RAD)
|
||||||
|
mean_frequency = 0.5 * (before.frequency_hz + after.frequency_hz)
|
||||||
|
phase_per_sample = 2.0 * np.pi * mean_frequency / sample_rate_hz
|
||||||
|
period_samples = sample_rate_hz / abs(mean_frequency)
|
||||||
|
equivalent_shift = jump / phase_per_sample
|
||||||
|
row = {
|
||||||
|
"callback_index": boundary.callback_index,
|
||||||
|
"boundary_sample": sample,
|
||||||
|
"buffer_length_bytes": boundary.buffer_length,
|
||||||
|
"valid_length_bytes": boundary.valid_bytes,
|
||||||
|
"complex_samples_in_callback": boundary.valid_bytes // 2,
|
||||||
|
"callback_duration_seconds": boundary.valid_bytes / (2.0 * sample_rate_hz),
|
||||||
|
"frequency_before_hz": before.frequency_hz,
|
||||||
|
"frequency_after_hz": after.frequency_hz,
|
||||||
|
"phase_before_at_boundary_rad": before.phase_at_reference_rad,
|
||||||
|
"phase_after_at_boundary_rad": after.phase_at_reference_rad,
|
||||||
|
"expected_phase_per_sample_rad": float(phase_per_sample),
|
||||||
|
"additional_phase_jump_rad": jump,
|
||||||
|
"before_phase_fit_rms_rad": before.phase_fit_rms_rad,
|
||||||
|
"after_phase_fit_rms_rad": after.phase_fit_rms_rad,
|
||||||
|
"credible": credible,
|
||||||
|
"confirmed_jump": confirmed,
|
||||||
|
"equivalent_sample_shift_principal": float(equivalent_shift),
|
||||||
|
"tone_period_samples": float(period_samples),
|
||||||
|
"equivalent_sample_shift_ambiguity": "principal + k * tone_period_samples",
|
||||||
|
}
|
||||||
|
if confirmed:
|
||||||
|
transition_radius = 2 * TRANSITION_BLOCK_SAMPLES
|
||||||
|
local_start = sample - transition_radius
|
||||||
|
local_end = sample + transition_radius
|
||||||
|
transition = _transition_offset(
|
||||||
|
samples[local_start:local_end],
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse_frequency_hz,
|
||||||
|
local_start,
|
||||||
|
sample,
|
||||||
|
before,
|
||||||
|
jump,
|
||||||
|
)
|
||||||
|
row.update(transition)
|
||||||
|
uncertainty = transition["transition_window_half_width_samples"]
|
||||||
|
offset = transition["transition_offset_samples"]
|
||||||
|
row["relation_to_callback_boundary"] = (
|
||||||
|
"consistent_with_exact_boundary"
|
||||||
|
if abs(offset) <= uncertainty
|
||||||
|
else "delayed_after_boundary"
|
||||||
|
if offset > uncertainty
|
||||||
|
else "before_boundary"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
row.update(
|
||||||
|
{
|
||||||
|
"transition_offset_samples": None,
|
||||||
|
"transition_resolution_samples": None,
|
||||||
|
"transition_window_half_width_samples": None,
|
||||||
|
"relation_to_callback_boundary": "no_confirmed_jump",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
rows.append(row)
|
||||||
|
credible_count = sum(bool(row["credible"]) for row in rows)
|
||||||
|
confirmed_count = sum(bool(row["confirmed_jump"]) for row in rows)
|
||||||
|
return rows, {
|
||||||
|
"checked_boundary_count": len(rows),
|
||||||
|
"credible_boundary_count": credible_count,
|
||||||
|
"confirmed_jump_count": confirmed_count,
|
||||||
|
"maximum_absolute_jump_rad": float(
|
||||||
|
max((abs(row["additional_phase_jump_rad"]) for row in rows), default=float("nan"))
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_continuity_tone(
|
||||||
|
samples: np.ndarray,
|
||||||
|
boundaries: tuple[hackrf.HackrfBoundary, ...],
|
||||||
|
sample_rate_hz: float,
|
||||||
|
stable_start_sample: int,
|
||||||
|
stable_end_sample: int,
|
||||||
|
) -> dict:
|
||||||
|
stable = np.asarray(samples[stable_start_sample:stable_end_sample], dtype=np.complex64)
|
||||||
|
coarse = estimate_coarse_tone(stable, sample_rate_hz)
|
||||||
|
if not coarse["credible"]:
|
||||||
|
return {
|
||||||
|
"classification": "D",
|
||||||
|
"reason": "Тон не прошёл заранее заданный спектральный порог 10 дБ",
|
||||||
|
"coarse_tone": coarse,
|
||||||
|
"boundaries": [],
|
||||||
|
}
|
||||||
|
whole = fit_tone_phase(
|
||||||
|
stable,
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse["frequency_hz"],
|
||||||
|
stable_start_sample,
|
||||||
|
stable_start_sample,
|
||||||
|
GLOBAL_PHASE_BLOCK_SAMPLES,
|
||||||
|
GLOBAL_PHASE_HOP_SAMPLES,
|
||||||
|
)
|
||||||
|
rows, boundary_summary = analyze_callback_boundaries(
|
||||||
|
samples,
|
||||||
|
boundaries,
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse["frequency_hz"],
|
||||||
|
stable_start_sample,
|
||||||
|
stable_end_sample,
|
||||||
|
)
|
||||||
|
thirds = []
|
||||||
|
edges = np.linspace(stable_start_sample, stable_end_sample, 4, dtype=int)
|
||||||
|
for index in range(3):
|
||||||
|
start, end = int(edges[index]), int(edges[index + 1])
|
||||||
|
fit = fit_tone_phase(
|
||||||
|
samples[start:end],
|
||||||
|
sample_rate_hz,
|
||||||
|
coarse["frequency_hz"],
|
||||||
|
start,
|
||||||
|
start,
|
||||||
|
GLOBAL_PHASE_BLOCK_SAMPLES,
|
||||||
|
GLOBAL_PHASE_HOP_SAMPLES,
|
||||||
|
)
|
||||||
|
thirds.append(
|
||||||
|
{
|
||||||
|
"section": index + 1,
|
||||||
|
"start_sample": start,
|
||||||
|
"end_sample": end,
|
||||||
|
**asdict(fit),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
centers = np.asarray(
|
||||||
|
[0.5 * (row["start_sample"] + row["end_sample"]) / sample_rate_hz for row in thirds]
|
||||||
|
)
|
||||||
|
frequencies = np.asarray([row["frequency_hz"] for row in thirds])
|
||||||
|
drift_hz_per_second = float(np.polyfit(centers, frequencies, 1)[0])
|
||||||
|
required_credible = max(10, math.ceil(0.8 * len(rows)))
|
||||||
|
if len(rows) == 0 or boundary_summary["credible_boundary_count"] < required_credible:
|
||||||
|
classification = "D"
|
||||||
|
reason = "Локальная фазовая точность недостаточна для решения о непрерывности"
|
||||||
|
elif boundary_summary["confirmed_jump_count"]:
|
||||||
|
classification = "B"
|
||||||
|
reason = "Подтверждены реальные фазовые скачки в непрерывном HackRF RX"
|
||||||
|
else:
|
||||||
|
classification = "A"
|
||||||
|
reason = "Однотонный контроль непрерывен; прежняя двухтональная проверка была недостоверна"
|
||||||
|
return {
|
||||||
|
"classification": classification,
|
||||||
|
"reason": reason,
|
||||||
|
"coarse_tone": coarse,
|
||||||
|
"stable_start_sample": int(stable_start_sample),
|
||||||
|
"stable_end_sample": int(stable_end_sample),
|
||||||
|
"stable_sample_count": int(len(stable)),
|
||||||
|
"stable_duration_seconds": float(len(stable) / sample_rate_hz),
|
||||||
|
"whole_tone_phase_fit": asdict(whole),
|
||||||
|
"frequency_by_thirds": thirds,
|
||||||
|
"frequency_drift_hz_per_second": drift_hz_per_second,
|
||||||
|
"frequency_span_hz": float(np.ptp(frequencies)),
|
||||||
|
"boundary_summary": boundary_summary,
|
||||||
|
"boundaries": rows,
|
||||||
|
"phase_jump_threshold_rad": BOUNDARY_PHASE_THRESHOLD_RAD,
|
||||||
|
"local_phase_rms_limit_rad": LOCAL_PHASE_RMS_LIMIT_RAD,
|
||||||
|
"software_callback_bug_found": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _monotonic_to_sample(
|
||||||
|
monotonic_value: float,
|
||||||
|
capture: hackrf.HackrfCapture,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
) -> int:
|
||||||
|
relative = monotonic_value - capture.diagnostics["stream_started_monotonic"]
|
||||||
|
boundary = min(
|
||||||
|
capture.boundaries,
|
||||||
|
key=lambda row: abs(row.monotonic_seconds - relative),
|
||||||
|
)
|
||||||
|
estimate = boundary.accepted_end_sample + round(
|
||||||
|
(relative - boundary.monotonic_seconds) * sample_rate_hz
|
||||||
|
)
|
||||||
|
return int(np.clip(estimate, 0, len(capture.samples)))
|
||||||
|
|
||||||
|
|
||||||
|
def run_one_continuity_tone(raw_directory: Path = RAW_DIRECTORY) -> dict:
|
||||||
|
"""Выполнить ровно один однотоновый опыт и остановиться."""
|
||||||
|
|
||||||
|
pluto_preflight = rtl_hardware.preflight_pluto()
|
||||||
|
hackrf_preflight = hackrf.preflight_hackrf()
|
||||||
|
pluto, tx_parameters = rtl_hardware.configure_pluto()
|
||||||
|
actual_tx_rate = float(tx_parameters["actual_sample_rate_hz"])
|
||||||
|
waveform, actual_tx_tone_hz = build_periodic_tone(actual_tx_rate)
|
||||||
|
device_waveform = lab043.to_pluto_tx_samples(waveform)
|
||||||
|
waveform_sha256 = hashlib.sha256(waveform.tobytes()).hexdigest()
|
||||||
|
target_samples = math.ceil(
|
||||||
|
(RX_LEADING_SECONDS + TONE_SECONDS + RX_TRAILING_SECONDS)
|
||||||
|
* hackrf.HACKRF_SAMPLE_RATE_HZ
|
||||||
|
) + hackrf.HACKRF_EXPECTED_CALLBACK_BYTES // 2
|
||||||
|
capture_started = datetime.now(timezone.utc)
|
||||||
|
capture_holder: list[hackrf.HackrfCapture] = []
|
||||||
|
errors: list[str] = []
|
||||||
|
tx_times: dict[str, float] = {}
|
||||||
|
|
||||||
|
with hackrf.HackrfRxDevice() as receiver:
|
||||||
|
rx_parameters = receiver.configure_rx()
|
||||||
|
|
||||||
|
def receive() -> None:
|
||||||
|
try:
|
||||||
|
capture_holder.append(receiver.capture(target_samples))
|
||||||
|
except Exception as error: # pragma: no cover - аппаратный путь
|
||||||
|
errors.append(f"RX {type(error).__name__}: {error}")
|
||||||
|
|
||||||
|
rx_thread = threading.Thread(target=receive, daemon=True)
|
||||||
|
rx_thread.start()
|
||||||
|
deadline = time.perf_counter() + 5.0
|
||||||
|
while time.perf_counter() < deadline:
|
||||||
|
if receiver.library.hackrf_is_streaming(receiver.device) == 1:
|
||||||
|
break
|
||||||
|
if errors:
|
||||||
|
break
|
||||||
|
time.sleep(0.01)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("HackRF RX не подтвердил непрерывный поток; TX не включён")
|
||||||
|
time.sleep(RX_LEADING_SECONDS)
|
||||||
|
pluto.tx_cyclic_buffer = True
|
||||||
|
pluto.tx_destroy_buffer()
|
||||||
|
try:
|
||||||
|
tx_times["tx_call_started_monotonic"] = time.perf_counter()
|
||||||
|
pluto.tx(device_waveform)
|
||||||
|
tx_times["tx_confirmed_monotonic"] = time.perf_counter()
|
||||||
|
time.sleep(TONE_SECONDS)
|
||||||
|
tx_times["tx_stop_started_monotonic"] = time.perf_counter()
|
||||||
|
finally:
|
||||||
|
pluto.tx_destroy_buffer()
|
||||||
|
tx_times["tx_destroyed_monotonic"] = time.perf_counter()
|
||||||
|
rx_thread.join(timeout=hackrf.HACKRF_STREAM_TIMEOUT_SECONDS + 5.0)
|
||||||
|
if rx_thread.is_alive():
|
||||||
|
raise RuntimeError("Непрерывный поток HackRF не завершился")
|
||||||
|
if errors:
|
||||||
|
raise RuntimeError("; ".join(errors))
|
||||||
|
if len(capture_holder) != 1:
|
||||||
|
raise RuntimeError("HackRF не вернул единственный непрерывный массив")
|
||||||
|
capture = capture_holder[0]
|
||||||
|
stable_start = _monotonic_to_sample(
|
||||||
|
tx_times["tx_confirmed_monotonic"] + STABLE_EDGE_SECONDS,
|
||||||
|
capture,
|
||||||
|
hackrf.HACKRF_SAMPLE_RATE_HZ,
|
||||||
|
)
|
||||||
|
stable_end = _monotonic_to_sample(
|
||||||
|
tx_times["tx_stop_started_monotonic"] - STABLE_EDGE_SECONDS,
|
||||||
|
capture,
|
||||||
|
hackrf.HACKRF_SAMPLE_RATE_HZ,
|
||||||
|
)
|
||||||
|
overload = {
|
||||||
|
"peak_magnitude": float(np.max(np.abs(capture.samples))),
|
||||||
|
"clipped_component_fraction": float(
|
||||||
|
np.mean(
|
||||||
|
(np.abs(capture.samples.real * 128.0) >= 127)
|
||||||
|
| (np.abs(capture.samples.imag * 128.0) >= 127)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
boundary_rows = [asdict(row) for row in capture.boundaries]
|
||||||
|
metadata = {
|
||||||
|
"experiment": "Lab043 HackRF single-tone continuity",
|
||||||
|
"capture_status": "captured",
|
||||||
|
"processing_status": "pending",
|
||||||
|
"processing_error": None,
|
||||||
|
"capture_started_utc": capture_started.isoformat().replace("+00:00", "Z"),
|
||||||
|
"tx_parameters": tx_parameters,
|
||||||
|
"rx_parameters": rx_parameters | {
|
||||||
|
"serial_number": hackrf_preflight["serial_number"],
|
||||||
|
"firmware_version": hackrf_preflight["firmware_version"],
|
||||||
|
"libhackrf_version": hackrf_preflight["libhackrf_version"],
|
||||||
|
},
|
||||||
|
"pluto_preflight": pluto_preflight,
|
||||||
|
"hackrf_preflight": hackrf_preflight,
|
||||||
|
"physical_scheme": "Pluto+ TX -> SMA -> AT30S 30 dB -> HackRF ANTENNA; antennas removed",
|
||||||
|
"waveform_sha256": waveform_sha256,
|
||||||
|
"waveform": {
|
||||||
|
"kind": "single_complex_tone",
|
||||||
|
"requested_offset_hz": TONE_OFFSET_HZ,
|
||||||
|
"actual_periodic_offset_hz": actual_tx_tone_hz,
|
||||||
|
"amplitude": TONE_AMPLITUDE,
|
||||||
|
"cyclic_buffer_sample_count": len(waveform),
|
||||||
|
"cyclic_period_count": CYCLIC_PERIOD_COUNT,
|
||||||
|
},
|
||||||
|
"tx_waveform_duration_seconds": TONE_SECONDS,
|
||||||
|
"tx_timing": tx_times,
|
||||||
|
"callback_count": capture.diagnostics["callback_count_total"],
|
||||||
|
"callback_boundaries": boundary_rows,
|
||||||
|
"continuous_rx": capture.diagnostics | {"boundaries": boundary_rows},
|
||||||
|
"expected_intervals": {
|
||||||
|
"rx_leading_seconds": RX_LEADING_SECONDS,
|
||||||
|
"tone_seconds": TONE_SECONDS,
|
||||||
|
"rx_trailing_seconds": RX_TRAILING_SECONDS,
|
||||||
|
"stable_edge_seconds": STABLE_EDGE_SECONDS,
|
||||||
|
"stable_start_sample": stable_start,
|
||||||
|
"stable_end_sample": stable_end,
|
||||||
|
},
|
||||||
|
"overload": overload,
|
||||||
|
}
|
||||||
|
stamp = capture_started.strftime("%Y%m%d_%H%M%S")
|
||||||
|
base = raw_directory / f"lab043_hackrf_continuity_tone_{stamp}"
|
||||||
|
iq_path, metadata_path, document = lab043.save_raw_iq_before_processing(
|
||||||
|
base,
|
||||||
|
capture.samples,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
restored = np.load(iq_path, allow_pickle=False)
|
||||||
|
if hashlib.sha256(iq_path.read_bytes()).hexdigest() != document["iq_sha256"]:
|
||||||
|
raise RuntimeError("SHA-256 raw изменился перед анализом")
|
||||||
|
try:
|
||||||
|
analysis = analyze_continuity_tone(
|
||||||
|
restored,
|
||||||
|
capture.boundaries,
|
||||||
|
hackrf.HACKRF_SAMPLE_RATE_HZ,
|
||||||
|
stable_start,
|
||||||
|
stable_end,
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
message = f"{type(error).__name__}: {error}"
|
||||||
|
lab043.update_processing_metadata(
|
||||||
|
metadata_path,
|
||||||
|
processing_status="processing_failed",
|
||||||
|
processing_error=message,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"iq_path": str(iq_path),
|
||||||
|
"metadata_path": str(metadata_path),
|
||||||
|
"iq_sha256": document["iq_sha256"],
|
||||||
|
"processing_status": "processing_failed",
|
||||||
|
"processing_error": message,
|
||||||
|
}
|
||||||
|
lab043.update_processing_metadata(
|
||||||
|
metadata_path,
|
||||||
|
processing_status="success",
|
||||||
|
processing_error=None,
|
||||||
|
analysis=analysis,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"iq_path": str(iq_path),
|
||||||
|
"metadata_path": str(metadata_path),
|
||||||
|
"iq_sha256": document["iq_sha256"],
|
||||||
|
"processing_status": "success",
|
||||||
|
"tx_parameters": tx_parameters,
|
||||||
|
"rx_parameters": metadata["rx_parameters"],
|
||||||
|
"overload": overload,
|
||||||
|
"continuous_rx": capture.diagnostics,
|
||||||
|
"analysis": analysis,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--run-one-continuity-tone", action="store_true", required=True)
|
||||||
|
arguments = parser.parse_args()
|
||||||
|
if not arguments.run_one_continuity_tone: # pragma: no cover
|
||||||
|
return 2
|
||||||
|
result = run_one_continuity_tone()
|
||||||
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||||
|
return 0 if result["processing_status"] == "success" else 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
1397
experiments/lab043_hackrf_counter.py
Normal file
1397
experiments/lab043_hackrf_counter.py
Normal file
File diff suppressed because it is too large
Load Diff
402
experiments/lab043_hackrf_gain_ladder.py
Normal file
402
experiments/lab043_hackrf_gain_ladder.py
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
"""Безопасный однотоновый поиск рабочего RX-усиления HackRF для Lab043.
|
||||||
|
|
||||||
|
Разрешён один непрерывный циклический тон Pluto+ и заранее фиксированная
|
||||||
|
лестница усилений HackRF. RF amp и antenna bias всегда выключены. Здесь нет
|
||||||
|
BPSK, PRBS, пакетов, счётчика или JPEG.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_continuity as continuity
|
||||||
|
from experiments import lab043_hackrf_hardware as hackrf
|
||||||
|
from experiments import lab043_pluto_to_rtlsdr as lab043
|
||||||
|
from experiments import lab043_prbs11_hardware as pluto_hardware
|
||||||
|
|
||||||
|
|
||||||
|
GAIN_LADDER = ((0, 0), (8, 8), (16, 8), (16, 16), (24, 16), (24, 24))
|
||||||
|
SETTLE_SECONDS = 0.25
|
||||||
|
MEASUREMENT_SECONDS = 0.75
|
||||||
|
FIRST_CAPTURE_SECONDS = SETTLE_SECONDS + MEASUREMENT_SECONDS
|
||||||
|
FFT_SAMPLES = 262_144
|
||||||
|
SEARCH_LOW_HZ = 35_000.0
|
||||||
|
SEARCH_HIGH_HZ = 65_000.0
|
||||||
|
NOISE_EXCLUSION_HZ = 2_000.0
|
||||||
|
DESIRABLE_TONE_OVER_NOISE_DB = 35.0
|
||||||
|
NEAR_LIMIT_COMPONENT = 0.90
|
||||||
|
PREFERRED_MAX_COMPONENT = 0.75
|
||||||
|
CLIPPED_COMPONENT = 127.0 / 128.0
|
||||||
|
NEAR_LIMIT_FRACTION_STOP = 1e-4
|
||||||
|
NONLINEAR_HARMONIC_LIMIT_DBC = -30.0
|
||||||
|
HARMONIC_DETECTION_MARGIN_DB = 10.0
|
||||||
|
HARMONIC_SEARCH_HALF_WIDTH_HZ = 2_000.0
|
||||||
|
HARMONIC_NOISE_OUTER_HALF_WIDTH_HZ = 10_000.0
|
||||||
|
OUTPUT_DIRECTORY = Path("data/processed/lab043_hackrf_gain_ladder")
|
||||||
|
|
||||||
|
|
||||||
|
def _db(power: float) -> float:
|
||||||
|
return 10.0 * math.log10(max(float(power), 1e-300))
|
||||||
|
|
||||||
|
|
||||||
|
def alias_frequency_to_nyquist(frequency_hz: float, sample_rate_hz: float) -> float:
|
||||||
|
"""Свернуть частоту в полуоткрытую полосу [-Fs/2, Fs/2)."""
|
||||||
|
|
||||||
|
if not np.isfinite(sample_rate_hz) or sample_rate_hz <= 0.0:
|
||||||
|
raise ValueError("Частота дискретизации должна быть положительной")
|
||||||
|
return float(
|
||||||
|
(float(frequency_hz) + sample_rate_hz / 2.0) % sample_rate_hz
|
||||||
|
- sample_rate_hz / 2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _cyclic_frequency_distance(
|
||||||
|
frequencies_hz: np.ndarray,
|
||||||
|
target_hz: float,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
) -> np.ndarray:
|
||||||
|
return np.abs(
|
||||||
|
(frequencies_hz - target_hz + sample_rate_hz / 2.0) % sample_rate_hz
|
||||||
|
- sample_rate_hz / 2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_harmonic(
|
||||||
|
powers: np.ndarray,
|
||||||
|
frequencies: np.ndarray,
|
||||||
|
fundamental_frequency_hz: float,
|
||||||
|
fundamental_power: float,
|
||||||
|
order: int,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
) -> dict:
|
||||||
|
"""Оценить гармонику отдельно относительно тона и локального фона."""
|
||||||
|
|
||||||
|
if order not in (2, 3):
|
||||||
|
raise ValueError("Поддерживаются только вторая и третья гармоники")
|
||||||
|
expected_hz = alias_frequency_to_nyquist(
|
||||||
|
order * fundamental_frequency_hz,
|
||||||
|
sample_rate_hz,
|
||||||
|
)
|
||||||
|
distances = _cyclic_frequency_distance(frequencies, expected_hz, sample_rate_hz)
|
||||||
|
peak_mask = distances <= HARMONIC_SEARCH_HALF_WIDTH_HZ
|
||||||
|
noise_mask = (
|
||||||
|
(distances > HARMONIC_SEARCH_HALF_WIDTH_HZ)
|
||||||
|
& (distances <= HARMONIC_NOISE_OUTER_HALF_WIDTH_HZ)
|
||||||
|
)
|
||||||
|
if not np.any(peak_mask) or not np.any(noise_mask):
|
||||||
|
raise ValueError("Недостаточно спектральных отсчётов около гармоники")
|
||||||
|
local_indexes = np.flatnonzero(peak_mask)
|
||||||
|
peak_index = int(local_indexes[np.argmax(powers[local_indexes])])
|
||||||
|
peak_power = float(powers[peak_index])
|
||||||
|
local_noise_power = float(np.median(powers[noise_mask]))
|
||||||
|
above_local_noise_db = _db(peak_power) - _db(local_noise_power)
|
||||||
|
relative_to_fundamental_db = _db(peak_power) - _db(fundamental_power)
|
||||||
|
credible = bool(above_local_noise_db >= HARMONIC_DETECTION_MARGIN_DB)
|
||||||
|
nonlinear = bool(
|
||||||
|
credible and relative_to_fundamental_db >= NONLINEAR_HARMONIC_LIMIT_DBC
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"order": order,
|
||||||
|
"expected_frequency_hz": expected_hz,
|
||||||
|
"peak_frequency_hz": float(frequencies[peak_index]),
|
||||||
|
"peak_power_dbfs": _db(peak_power),
|
||||||
|
"local_noise_floor_dbfs_per_fft_bin": _db(local_noise_power),
|
||||||
|
"above_local_noise_db": float(above_local_noise_db),
|
||||||
|
"relative_to_fundamental_db": float(relative_to_fundamental_db),
|
||||||
|
"credible": credible,
|
||||||
|
"nonlinear": nonlinear,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def measure_tone_segment(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
fft_samples: int = FFT_SAMPLES,
|
||||||
|
) -> dict:
|
||||||
|
"""Измерить тон и перегрузку по неизменяемой спектральной методике."""
|
||||||
|
|
||||||
|
received = np.asarray(samples, dtype=np.complex64)
|
||||||
|
if received.ndim != 1 or len(received) < fft_samples:
|
||||||
|
raise ValueError("Участок короче одного фиксированного БПФ-окна")
|
||||||
|
if not np.all(np.isfinite(received)):
|
||||||
|
raise ValueError("Участок содержит нечисловые отсчёты")
|
||||||
|
|
||||||
|
segment_count = len(received) // fft_samples
|
||||||
|
window = np.hanning(fft_samples).astype(np.float64)
|
||||||
|
coherent_scale = float(np.sum(window))
|
||||||
|
powers = np.zeros(fft_samples, dtype=np.float64)
|
||||||
|
for index in range(segment_count):
|
||||||
|
segment = received[index * fft_samples : (index + 1) * fft_samples]
|
||||||
|
spectrum = np.fft.fft(segment * window)
|
||||||
|
powers += np.abs(spectrum / coherent_scale) ** 2
|
||||||
|
powers /= segment_count
|
||||||
|
frequencies = np.fft.fftfreq(fft_samples, d=1.0 / sample_rate_hz)
|
||||||
|
|
||||||
|
search = (frequencies >= SEARCH_LOW_HZ) & (frequencies <= SEARCH_HIGH_HZ)
|
||||||
|
candidates = np.flatnonzero(search)
|
||||||
|
peak_index = int(candidates[np.argmax(powers[candidates])])
|
||||||
|
peak_bin_hz = float(frequencies[peak_index])
|
||||||
|
resolution_hz = float(sample_rate_hz / fft_samples)
|
||||||
|
left = (peak_index - 1) % fft_samples
|
||||||
|
right = (peak_index + 1) % fft_samples
|
||||||
|
y0, y1, y2 = np.log(np.maximum(powers[[left, peak_index, right]], 1e-300))
|
||||||
|
denominator = y0 - 2.0 * y1 + y2
|
||||||
|
bin_offset = 0.0 if abs(denominator) < 1e-18 else 0.5 * (y0 - y2) / denominator
|
||||||
|
tone_frequency_hz = peak_bin_hz + float(np.clip(bin_offset, -0.5, 0.5)) * resolution_hz
|
||||||
|
|
||||||
|
noise_mask = search & (np.abs(frequencies - tone_frequency_hz) >= NOISE_EXCLUSION_HZ)
|
||||||
|
noise_power = float(np.median(powers[noise_mask]))
|
||||||
|
tone_power = float(powers[peak_index])
|
||||||
|
tone_over_noise_db = _db(tone_power) - _db(noise_power)
|
||||||
|
|
||||||
|
second = analyze_harmonic(
|
||||||
|
powers,
|
||||||
|
frequencies,
|
||||||
|
tone_frequency_hz,
|
||||||
|
tone_power,
|
||||||
|
2,
|
||||||
|
sample_rate_hz,
|
||||||
|
)
|
||||||
|
third = analyze_harmonic(
|
||||||
|
powers,
|
||||||
|
frequencies,
|
||||||
|
tone_frequency_hz,
|
||||||
|
tone_power,
|
||||||
|
3,
|
||||||
|
sample_rate_hz,
|
||||||
|
)
|
||||||
|
|
||||||
|
component_peak = np.maximum(np.abs(received.real), np.abs(received.imag))
|
||||||
|
near_fraction = float(np.mean(component_peak >= NEAR_LIMIT_COMPONENT))
|
||||||
|
clipped_fraction = float(np.mean(component_peak >= CLIPPED_COMPONENT))
|
||||||
|
max_component = float(np.max(component_peak))
|
||||||
|
harmonic_nonlinearity = bool(second["nonlinear"] or third["nonlinear"])
|
||||||
|
stop = bool(
|
||||||
|
clipped_fraction > 0.0
|
||||||
|
or near_fraction >= NEAR_LIMIT_FRACTION_STOP
|
||||||
|
or max_component >= NEAR_LIMIT_COMPONENT
|
||||||
|
or harmonic_nonlinearity
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"sample_count": int(len(received)),
|
||||||
|
"fft_samples": int(fft_samples),
|
||||||
|
"fft_segment_count": int(segment_count),
|
||||||
|
"fft_resolution_hz": resolution_hz,
|
||||||
|
"tone_frequency_hz": float(tone_frequency_hz),
|
||||||
|
"tone_peak_bin_hz": peak_bin_hz,
|
||||||
|
"tone_power_dbfs": _db(tone_power),
|
||||||
|
"noise_floor_dbfs_per_fft_bin": _db(noise_power),
|
||||||
|
"tone_over_noise_db": float(tone_over_noise_db),
|
||||||
|
"mean_amplitude": float(np.mean(np.abs(received))),
|
||||||
|
"rms_amplitude": float(np.sqrt(np.mean(np.abs(received) ** 2))),
|
||||||
|
"maximum_amplitude": float(np.max(np.abs(received))),
|
||||||
|
"maximum_component": max_component,
|
||||||
|
"near_limit_component_fraction": near_fraction,
|
||||||
|
"clipped_component_fraction": clipped_fraction,
|
||||||
|
"dc_mean_i": float(np.mean(received.real)),
|
||||||
|
"dc_mean_q": float(np.mean(received.imag)),
|
||||||
|
"second_harmonic": second,
|
||||||
|
"third_harmonic": third,
|
||||||
|
"second_harmonic_dbc": second["relative_to_fundamental_db"],
|
||||||
|
"third_harmonic_dbc": third["relative_to_fundamental_db"],
|
||||||
|
"harmonic_nonlinearity_detected": harmonic_nonlinearity,
|
||||||
|
"stop_gain_escalation": stop,
|
||||||
|
"stop_reason": (
|
||||||
|
"перегрузка/близость к пределу/гармоническая нелинейность"
|
||||||
|
if stop
|
||||||
|
else ""
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def choose_preferred_gain(rows: list[dict]) -> dict | None:
|
||||||
|
"""Выбрать минимальное безопасное усиление без погони за лишними децибелами."""
|
||||||
|
|
||||||
|
safe = [
|
||||||
|
row
|
||||||
|
for row in rows
|
||||||
|
if not row["metrics"]["stop_gain_escalation"]
|
||||||
|
and row["metrics"]["maximum_component"] <= PREFERRED_MAX_COMPONENT
|
||||||
|
]
|
||||||
|
if not safe:
|
||||||
|
return None
|
||||||
|
desirable = [
|
||||||
|
row
|
||||||
|
for row in safe
|
||||||
|
if row["metrics"]["tone_over_noise_db"] >= DESIRABLE_TONE_OVER_NOISE_DB
|
||||||
|
]
|
||||||
|
if desirable:
|
||||||
|
candidates = desirable
|
||||||
|
else:
|
||||||
|
best_margin = max(row["metrics"]["tone_over_noise_db"] for row in safe)
|
||||||
|
candidates = [
|
||||||
|
row
|
||||||
|
for row in safe
|
||||||
|
if row["metrics"]["tone_over_noise_db"] >= best_margin - 2.0
|
||||||
|
]
|
||||||
|
return min(
|
||||||
|
candidates,
|
||||||
|
key=lambda row: (row["lna_gain_db"] + row["vga_gain_db"], row["step_index"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _capture(receiver: hackrf.HackrfRxDevice, seconds: float) -> hackrf.HackrfCapture:
|
||||||
|
count = math.ceil(seconds * hackrf.HACKRF_SAMPLE_RATE_HZ)
|
||||||
|
return receiver.capture(count)
|
||||||
|
|
||||||
|
|
||||||
|
def run_gain_ladder(output_directory: Path = OUTPUT_DIRECTORY) -> dict:
|
||||||
|
"""Выполнить один аппаратный сеанс с одним непрерывным тоном."""
|
||||||
|
|
||||||
|
for lna, vga in GAIN_LADDER:
|
||||||
|
hackrf.validate_hackrf_rx_gains(lna, vga)
|
||||||
|
pluto_preflight = pluto_hardware.preflight_pluto()
|
||||||
|
hackrf_preflight = hackrf.preflight_hackrf()
|
||||||
|
pluto, tx_parameters = pluto_hardware.configure_pluto()
|
||||||
|
actual_tx_rate = float(tx_parameters["actual_sample_rate_hz"])
|
||||||
|
waveform, actual_tone_hz = continuity.build_periodic_tone(actual_tx_rate)
|
||||||
|
device_waveform = lab043.to_pluto_tx_samples(waveform)
|
||||||
|
rows: list[dict] = []
|
||||||
|
tx_started = False
|
||||||
|
stop_reason = "лестница завершена"
|
||||||
|
started = datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with hackrf.HackrfRxDevice() as receiver:
|
||||||
|
rx_parameters = receiver.configure_rx()
|
||||||
|
first_holder: list[hackrf.HackrfCapture] = []
|
||||||
|
first_errors: list[str] = []
|
||||||
|
|
||||||
|
def first_receive() -> None:
|
||||||
|
try:
|
||||||
|
first_holder.append(_capture(receiver, FIRST_CAPTURE_SECONDS))
|
||||||
|
except Exception as error: # pragma: no cover - аппаратный путь
|
||||||
|
first_errors.append(f"{type(error).__name__}: {error}")
|
||||||
|
|
||||||
|
first_gain = receiver.set_rx_gains(*GAIN_LADDER[0])
|
||||||
|
rx_thread = threading.Thread(target=first_receive, daemon=True)
|
||||||
|
rx_thread.start()
|
||||||
|
deadline = time.perf_counter() + 5.0
|
||||||
|
while time.perf_counter() < deadline:
|
||||||
|
if receiver.library.hackrf_is_streaming(receiver.device) == 1:
|
||||||
|
break
|
||||||
|
if first_errors:
|
||||||
|
break
|
||||||
|
time.sleep(0.01)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("HackRF RX не подтвердил поток; TX не включён")
|
||||||
|
time.sleep(SETTLE_SECONDS)
|
||||||
|
pluto.tx_cyclic_buffer = True
|
||||||
|
pluto.tx_destroy_buffer()
|
||||||
|
pluto.tx(device_waveform)
|
||||||
|
tx_started = True
|
||||||
|
rx_thread.join(timeout=hackrf.HACKRF_STREAM_TIMEOUT_SECONDS + 5.0)
|
||||||
|
if rx_thread.is_alive():
|
||||||
|
raise RuntimeError("Первый короткий RX-сеанс не завершился")
|
||||||
|
if first_errors:
|
||||||
|
raise RuntimeError("; ".join(first_errors))
|
||||||
|
if len(first_holder) != 1:
|
||||||
|
raise RuntimeError("Первый RX-сеанс не вернул единственный массив")
|
||||||
|
|
||||||
|
first_capture = first_holder[0]
|
||||||
|
measurement_count = math.floor(MEASUREMENT_SECONDS * hackrf.HACKRF_SAMPLE_RATE_HZ)
|
||||||
|
metrics = measure_tone_segment(first_capture.samples[-measurement_count:], hackrf.HACKRF_SAMPLE_RATE_HZ)
|
||||||
|
rows.append({
|
||||||
|
"step_index": 0,
|
||||||
|
"lna_gain_db": GAIN_LADDER[0][0],
|
||||||
|
"vga_gain_db": GAIN_LADDER[0][1],
|
||||||
|
"gain_configuration": first_gain,
|
||||||
|
"capture_diagnostics": first_capture.diagnostics,
|
||||||
|
"metrics": metrics,
|
||||||
|
})
|
||||||
|
|
||||||
|
if metrics["stop_gain_escalation"]:
|
||||||
|
stop_reason = metrics["stop_reason"]
|
||||||
|
else:
|
||||||
|
for step_index, (lna_gain, vga_gain) in enumerate(GAIN_LADDER[1:], start=1):
|
||||||
|
gain_configuration = receiver.set_rx_gains(lna_gain, vga_gain)
|
||||||
|
time.sleep(SETTLE_SECONDS)
|
||||||
|
capture = _capture(receiver, MEASUREMENT_SECONDS)
|
||||||
|
metrics = measure_tone_segment(capture.samples, hackrf.HACKRF_SAMPLE_RATE_HZ)
|
||||||
|
rows.append({
|
||||||
|
"step_index": step_index,
|
||||||
|
"lna_gain_db": lna_gain,
|
||||||
|
"vga_gain_db": vga_gain,
|
||||||
|
"gain_configuration": gain_configuration,
|
||||||
|
"capture_diagnostics": capture.diagnostics,
|
||||||
|
"metrics": metrics,
|
||||||
|
})
|
||||||
|
if metrics["stop_gain_escalation"]:
|
||||||
|
stop_reason = metrics["stop_reason"]
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
if tx_started:
|
||||||
|
pluto.tx_destroy_buffer()
|
||||||
|
|
||||||
|
preferred = choose_preferred_gain(rows)
|
||||||
|
preferred_summary = None if preferred is None else {
|
||||||
|
"step_index": preferred["step_index"],
|
||||||
|
"lna_gain_db": preferred["lna_gain_db"],
|
||||||
|
"vga_gain_db": preferred["vga_gain_db"],
|
||||||
|
"tone_over_noise_db": preferred["metrics"]["tone_over_noise_db"],
|
||||||
|
"desirable_margin_reached": bool(
|
||||||
|
preferred["metrics"]["tone_over_noise_db"] >= DESIRABLE_TONE_OVER_NOISE_DB
|
||||||
|
),
|
||||||
|
}
|
||||||
|
result = {
|
||||||
|
"experiment": "Lab043 HackRF RX gain ladder with one continuous tone",
|
||||||
|
"started_utc": started.isoformat().replace("+00:00", "Z"),
|
||||||
|
"physical_scheme": "Pluto+ TX -> SMA -> AT30S 30 dB -> HackRF RX; antennas removed",
|
||||||
|
"method": "one continuous cyclic Pluto tone; separate short HackRF RX sessions per gain point",
|
||||||
|
"fixed_gain_ladder": [list(point) for point in GAIN_LADDER],
|
||||||
|
"fixed_thresholds": {
|
||||||
|
"desirable_tone_over_noise_db": DESIRABLE_TONE_OVER_NOISE_DB,
|
||||||
|
"near_limit_component": NEAR_LIMIT_COMPONENT,
|
||||||
|
"preferred_max_component": PREFERRED_MAX_COMPONENT,
|
||||||
|
"clipped_component": CLIPPED_COMPONENT,
|
||||||
|
"near_limit_fraction_stop": NEAR_LIMIT_FRACTION_STOP,
|
||||||
|
"nonlinear_harmonic_limit_dbc": NONLINEAR_HARMONIC_LIMIT_DBC,
|
||||||
|
"harmonic_detection_margin_db": HARMONIC_DETECTION_MARGIN_DB,
|
||||||
|
"harmonic_search_half_width_hz": HARMONIC_SEARCH_HALF_WIDTH_HZ,
|
||||||
|
"harmonic_noise_outer_half_width_hz": HARMONIC_NOISE_OUTER_HALF_WIDTH_HZ,
|
||||||
|
},
|
||||||
|
"pluto_preflight": pluto_preflight,
|
||||||
|
"hackrf_preflight": hackrf_preflight,
|
||||||
|
"tx_parameters": tx_parameters,
|
||||||
|
"rx_parameters": rx_parameters,
|
||||||
|
"actual_transmitted_tone_offset_hz": actual_tone_hz,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"completed_step_count": len(rows),
|
||||||
|
"stop_reason": stop_reason,
|
||||||
|
"rows": rows,
|
||||||
|
"preferred_gain": preferred_summary,
|
||||||
|
"digital_experiment_authorized": False,
|
||||||
|
}
|
||||||
|
output_directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
stamp = started.strftime("%Y%m%d_%H%M%S")
|
||||||
|
output_path = output_directory / f"lab043_hackrf_gain_ladder_{stamp}.json"
|
||||||
|
output_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||||
|
result["result_path"] = str(output_path)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--output-directory", type=Path, default=OUTPUT_DIRECTORY)
|
||||||
|
arguments = parser.parse_args()
|
||||||
|
result = run_gain_ladder(arguments.output_directory)
|
||||||
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
1173
experiments/lab043_hackrf_hardware.py
Normal file
1173
experiments/lab043_hackrf_hardware.py
Normal file
File diff suppressed because it is too large
Load Diff
1141
experiments/lab043_hackrf_zero_if_compare.py
Normal file
1141
experiments/lab043_hackrf_zero_if_compare.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -650,6 +650,60 @@ def locate_calibration_tone_start(
|
|||||||
raise RuntimeError("Начало двухтоновой калибровки не найдено по фиксированному порогу 10 дБ")
|
raise RuntimeError("Начало двухтоновой калибровки не найдено по фиксированному порогу 10 дБ")
|
||||||
|
|
||||||
|
|
||||||
|
def locate_calibration_tone_start_spectral(
|
||||||
|
samples: np.ndarray,
|
||||||
|
sample_rate_hz: float,
|
||||||
|
block_samples: int = CALIBRATION_NFFT,
|
||||||
|
hop_samples: int = CALIBRATION_NFFT // 4,
|
||||||
|
required_consecutive_blocks: int = 3,
|
||||||
|
) -> int:
|
||||||
|
"""Найти начало по двум известным тонам с тем же порогом 10 дБ.
|
||||||
|
|
||||||
|
Резервный метод нужен, когда узкие тоны надёжны спектрально, но не дают
|
||||||
|
десятикратного роста полной широкополосной мощности. Дополнительно
|
||||||
|
применяется существующее ограничение геометрии тонов: ошибка такта не
|
||||||
|
должна превышать 1000 ppm.
|
||||||
|
"""
|
||||||
|
|
||||||
|
received = np.asarray(samples, dtype=np.complex128)
|
||||||
|
if received.ndim != 1 or len(received) < block_samples:
|
||||||
|
raise ValueError("Захват слишком короток для спектрального поиска калибровки")
|
||||||
|
if (
|
||||||
|
sample_rate_hz <= 0.0
|
||||||
|
or block_samples < 1024
|
||||||
|
or hop_samples <= 0
|
||||||
|
or required_consecutive_blocks <= 0
|
||||||
|
):
|
||||||
|
raise ValueError("Параметры спектрального поиска должны быть положительными")
|
||||||
|
window = np.hanning(block_samples)
|
||||||
|
frequencies = np.fft.fftshift(
|
||||||
|
np.fft.fftfreq(block_samples, d=1.0 / sample_rate_hz)
|
||||||
|
)
|
||||||
|
starts = np.arange(
|
||||||
|
0,
|
||||||
|
len(received) - block_samples + 1,
|
||||||
|
hop_samples,
|
||||||
|
dtype=np.int64,
|
||||||
|
)
|
||||||
|
active = np.zeros(len(starts), dtype=bool)
|
||||||
|
for index, start in enumerate(starts):
|
||||||
|
block = received[start : start + block_samples]
|
||||||
|
centered = block - np.mean(block)
|
||||||
|
spectrum = np.fft.fftshift(np.fft.fft(centered * window))
|
||||||
|
estimate = estimate_calibration_from_spectrum(
|
||||||
|
frequencies,
|
||||||
|
np.abs(spectrum) ** 2,
|
||||||
|
)
|
||||||
|
active[index] = bool(estimate.valid)
|
||||||
|
for index in range(len(active) - required_consecutive_blocks + 1):
|
||||||
|
if bool(np.all(active[index : index + required_consecutive_blocks])):
|
||||||
|
return int(starts[index])
|
||||||
|
raise RuntimeError(
|
||||||
|
"Начало двухтоновой калибровки не найдено спектрально: "
|
||||||
|
"два тона не прошли неизменный порог 10 дБ и проверку геометрии"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def split_calibration_and_bpsk(
|
def split_calibration_and_bpsk(
|
||||||
samples: np.ndarray,
|
samples: np.ndarray,
|
||||||
plan: PrbsTransmissionPlan,
|
plan: PrbsTransmissionPlan,
|
||||||
@@ -659,7 +713,15 @@ def split_calibration_and_bpsk(
|
|||||||
"""Выделить тоны и BPSK по одной временной шкале одного захвата."""
|
"""Выделить тоны и BPSK по одной временной шкале одного захвата."""
|
||||||
|
|
||||||
received = np.asarray(samples, dtype=np.complex128)
|
received = np.asarray(samples, dtype=np.complex128)
|
||||||
|
try:
|
||||||
tone_start = locate_calibration_tone_start(received, actual_rx_sample_rate_hz)
|
tone_start = locate_calibration_tone_start(received, actual_rx_sample_rate_hz)
|
||||||
|
tone_start_locator = "broadband_power_10db"
|
||||||
|
except RuntimeError:
|
||||||
|
tone_start = locate_calibration_tone_start_spectral(
|
||||||
|
received,
|
||||||
|
actual_rx_sample_rate_hz,
|
||||||
|
)
|
||||||
|
tone_start_locator = "two_tone_spectral_10db"
|
||||||
tone_duration_rx = round(
|
tone_duration_rx = round(
|
||||||
plan.calibration_sample_count / actual_tx_sample_rate_hz * actual_rx_sample_rate_hz
|
plan.calibration_sample_count / actual_tx_sample_rate_hz * actual_rx_sample_rate_hz
|
||||||
)
|
)
|
||||||
@@ -684,6 +746,7 @@ def split_calibration_and_bpsk(
|
|||||||
received[bpsk_start:bpsk_end],
|
received[bpsk_start:bpsk_end],
|
||||||
{
|
{
|
||||||
"tone_start_sample": int(tone_start),
|
"tone_start_sample": int(tone_start),
|
||||||
|
"tone_start_locator": tone_start_locator,
|
||||||
"calibration_start_sample": int(calibration_start),
|
"calibration_start_sample": int(calibration_start),
|
||||||
"calibration_end_sample": int(calibration_end),
|
"calibration_end_sample": int(calibration_end),
|
||||||
"bpsk_nominal_start_sample": int(bpsk_nominal_start),
|
"bpsk_nominal_start_sample": int(bpsk_nominal_start),
|
||||||
|
|||||||
@@ -41,12 +41,31 @@ class CapturedPrbsAnalysis:
|
|||||||
modes: dict[str, lab043.PrbsModeMetrics]
|
modes: dict[str, lab043.PrbsModeMetrics]
|
||||||
|
|
||||||
|
|
||||||
def preflight_pluto() -> dict:
|
def discover_pluto_usb_uri() -> str:
|
||||||
|
"""Найти единственный Pluto+ через прямой USB-IIO без изменения сети."""
|
||||||
|
|
||||||
|
import iio
|
||||||
|
|
||||||
|
contexts = iio.scan_contexts()
|
||||||
|
candidates = sorted(
|
||||||
|
uri
|
||||||
|
for uri, description in contexts.items()
|
||||||
|
if uri.startswith("usb:") and "PlutoSDR" in description
|
||||||
|
)
|
||||||
|
if len(candidates) != 1:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Ожидался ровно один USB-IIO контекст PlutoSDR, "
|
||||||
|
f"получено {len(candidates)}: {candidates}"
|
||||||
|
)
|
||||||
|
return candidates[0]
|
||||||
|
|
||||||
|
|
||||||
|
def preflight_pluto(uri: str = PLUTO_URI) -> dict:
|
||||||
"""Подтвердить IIO-контекст, PHY и первый TX-канал без передачи."""
|
"""Подтвердить IIO-контекст, PHY и первый TX-канал без передачи."""
|
||||||
|
|
||||||
import iio
|
import iio
|
||||||
|
|
||||||
context = iio.Context(PLUTO_URI)
|
context = iio.Context(uri)
|
||||||
phy = context.find_device("ad9361-phy")
|
phy = context.find_device("ad9361-phy")
|
||||||
tx_device = context.find_device("cf-ad9361-dds-core-lpc")
|
tx_device = context.find_device("cf-ad9361-dds-core-lpc")
|
||||||
tx_channel = tx_device.find_channel("voltage0", True) if tx_device is not None else None
|
tx_channel = tx_device.find_channel("voltage0", True) if tx_device is not None else None
|
||||||
@@ -55,7 +74,7 @@ def preflight_pluto() -> dict:
|
|||||||
if tx_device is None or tx_channel is None:
|
if tx_device is None or tx_channel is None:
|
||||||
raise RuntimeError("IIO-контекст открыт, но первый TX-канал недоступен")
|
raise RuntimeError("IIO-контекст открыт, но первый TX-канал недоступен")
|
||||||
return {
|
return {
|
||||||
"uri": PLUTO_URI,
|
"uri": uri,
|
||||||
"context_opened": True,
|
"context_opened": True,
|
||||||
"phy_name": str(phy.name),
|
"phy_name": str(phy.name),
|
||||||
"tx_device_name": str(tx_device.name),
|
"tx_device_name": str(tx_device.name),
|
||||||
@@ -100,16 +119,17 @@ def preflight_rtlsdr() -> dict:
|
|||||||
sdr.close()
|
sdr.close()
|
||||||
|
|
||||||
|
|
||||||
def configure_pluto() -> tuple[object, dict]:
|
def configure_pluto(uri: str = PLUTO_URI) -> tuple[object, dict]:
|
||||||
import adi
|
import adi
|
||||||
|
|
||||||
device = adi.Pluto(uri=PLUTO_URI)
|
device = adi.Pluto(uri=uri)
|
||||||
device.sample_rate = int(lab043.SAMPLE_RATE_HZ)
|
device.sample_rate = int(lab043.SAMPLE_RATE_HZ)
|
||||||
device.tx_lo = int(lab043.CARRIER_HZ)
|
device.tx_lo = int(lab043.CARRIER_HZ)
|
||||||
device.tx_rf_bandwidth = int(RF_BANDWIDTH_HZ)
|
device.tx_rf_bandwidth = int(RF_BANDWIDTH_HZ)
|
||||||
device.tx_hardwaregain_chan0 = float(TX_GAIN_DB)
|
device.tx_hardwaregain_chan0 = float(TX_GAIN_DB)
|
||||||
device.tx_cyclic_buffer = False
|
device.tx_cyclic_buffer = False
|
||||||
return device, {
|
return device, {
|
||||||
|
"uri": uri,
|
||||||
"requested_center_frequency_hz": int(lab043.CARRIER_HZ),
|
"requested_center_frequency_hz": int(lab043.CARRIER_HZ),
|
||||||
"actual_center_frequency_hz": int(device.tx_lo),
|
"actual_center_frequency_hz": int(device.tx_lo),
|
||||||
"requested_sample_rate_hz": int(lab043.SAMPLE_RATE_HZ),
|
"requested_sample_rate_hz": int(lab043.SAMPLE_RATE_HZ),
|
||||||
|
|||||||
78
tests/test_lab043_bpsk_asymmetry_diagnostics.py
Normal file
78
tests/test_lab043_bpsk_asymmetry_diagnostics.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from experiments import lab043_bpsk_asymmetry_diagnostics as diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
def test_known_sequence_phase_fit_removes_known_linear_phase() -> None:
|
||||||
|
bits = np.tile(np.array([0, 0, 1, 1, 0, 1, 0, 1], dtype=np.uint8), 128)
|
||||||
|
expected = 2.0 * bits.astype(np.float64) - 1.0
|
||||||
|
indexes = np.arange(len(expected), dtype=np.float64)
|
||||||
|
frequency_hz = 0.75
|
||||||
|
received = expected * np.exp(
|
||||||
|
1j * (0.37 + 2.0 * np.pi * frequency_hz * indexes / 20_000.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
corrected, estimated_hz, fit_rmse = diagnostics._known_sequence_phase_fit(
|
||||||
|
received, expected, 20_000.0
|
||||||
|
)
|
||||||
|
normalized, _ = diagnostics._normalize_symbols(corrected, expected)
|
||||||
|
|
||||||
|
assert abs(estimated_hz - frequency_hz) < 1e-9
|
||||||
|
assert fit_rmse < 1e-12
|
||||||
|
assert np.max(np.abs(normalized - expected)) < 1e-12
|
||||||
|
|
||||||
|
|
||||||
|
def test_triplet_rows_count_and_classify_only_actual_decision_crossings() -> None:
|
||||||
|
bits = np.tile(np.array([0, 0, 0, 1, 1, 1, 0, 1], dtype=np.uint8), 20)
|
||||||
|
values = 2.0 * bits.astype(np.float64) - 1.0
|
||||||
|
target = np.flatnonzero(
|
||||||
|
(bits[:-2] == 0) & (bits[1:-1] == 0) & (bits[2:] == 0)
|
||||||
|
)[0] + 1
|
||||||
|
values[target] = 0.1
|
||||||
|
|
||||||
|
rows = diagnostics.triplet_rows("synthetic", bits, values.astype(np.complex128))
|
||||||
|
by_triplet = {row["triplet"]: row for row in rows}
|
||||||
|
|
||||||
|
assert sum(row["count"] for row in rows) == len(bits) - 2
|
||||||
|
assert by_triplet["000"]["bit_errors"] == 1
|
||||||
|
assert sum(row["bit_errors"] for row in rows) == 1
|
||||||
|
assert by_triplet["000"]["decision_cross_fraction"] == by_triplet["000"]["ber"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_rrc_audit_has_symmetric_unit_energy_pair() -> None:
|
||||||
|
impulse_rows, audit = diagnostics.rrc_rows()
|
||||||
|
|
||||||
|
assert audit["tx_tap_count"] == 1201
|
||||||
|
assert audit["rx_tap_count"] == 1201
|
||||||
|
assert audit["symmetry_max_abs_error"] == 0.0
|
||||||
|
assert abs(audit["tap_energy"] - 1.0) < 1e-12
|
||||||
|
by_offset = {row["symbol_offset"]: row["h_normalized"] for row in impulse_rows}
|
||||||
|
assert by_offset[0] == 1.0
|
||||||
|
for offset in range(1, 6):
|
||||||
|
assert abs(by_offset[offset] - by_offset[-offset]) < 1e-15
|
||||||
|
|
||||||
|
|
||||||
|
def test_fractional_delay_preserves_order_and_length() -> None:
|
||||||
|
source = np.array([0.0, 1.0, 2.0, 3.0], dtype=np.complex128)
|
||||||
|
|
||||||
|
shifted = diagnostics._fractional_delay(source, 0.5)
|
||||||
|
|
||||||
|
assert len(shifted) == len(source)
|
||||||
|
assert np.allclose(shifted, [0.0, 0.5, 1.5, 2.5])
|
||||||
|
|
||||||
|
|
||||||
|
def test_triplet_metrics_keep_complex_dc_visible() -> None:
|
||||||
|
bits = np.tile(np.array([0, 0, 1, 1, 0, 1, 0, 1], dtype=np.uint8), 20)
|
||||||
|
expected = 2.0 * bits.astype(np.float64) - 1.0
|
||||||
|
offset = 0.2 - 0.1j
|
||||||
|
|
||||||
|
rows = diagnostics.triplet_rows(
|
||||||
|
"affine", bits, expected.astype(np.complex128) + offset
|
||||||
|
)
|
||||||
|
|
||||||
|
negative = [row for row in rows if row["triplet"][1] == "0" and row["count"]]
|
||||||
|
positive = [row for row in rows if row["triplet"][1] == "1" and row["count"]]
|
||||||
|
present = [row for row in rows if row["count"]]
|
||||||
|
assert all(abs(row["mean_i"] + 0.8) < 1e-12 for row in negative)
|
||||||
|
assert all(abs(row["mean_i"] - 1.2) < 1e-12 for row in positive)
|
||||||
|
assert all(abs(row["mean_q"] + 0.1) < 1e-12 for row in present)
|
||||||
@@ -764,6 +764,39 @@ def test_symbol_sample_phase_is_selected_separately(initial_sample_phase: int) -
|
|||||||
assert found["score"] > 0.99
|
assert found["score"] > 0.99
|
||||||
|
|
||||||
|
|
||||||
|
def test_spectral_tone_start_fallback_finds_narrow_tones_without_broadband_jump() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
rng = np.random.default_rng(43)
|
||||||
|
samples = (
|
||||||
|
rng.normal(0.0, 0.08, 240_000)
|
||||||
|
+ 1j * rng.normal(0.0, 0.08, 240_000)
|
||||||
|
)
|
||||||
|
tone_start = 96_000
|
||||||
|
tone_count = 60_000
|
||||||
|
indexes = np.arange(tone_count, dtype=np.float64)
|
||||||
|
samples[tone_start : tone_start + tone_count] += 0.025 * (
|
||||||
|
np.exp(-1j * 2.0 * np.pi * 50_000.0 * indexes / sample_rate)
|
||||||
|
+ np.exp(1j * 2.0 * np.pi * 50_000.0 * indexes / sample_rate)
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match="10"):
|
||||||
|
lab043.locate_calibration_tone_start(
|
||||||
|
samples,
|
||||||
|
sample_rate,
|
||||||
|
block_samples=2048,
|
||||||
|
hop_samples=1024,
|
||||||
|
)
|
||||||
|
found = lab043.locate_calibration_tone_start_spectral(
|
||||||
|
samples,
|
||||||
|
sample_rate,
|
||||||
|
block_samples=8192,
|
||||||
|
hop_samples=2048,
|
||||||
|
required_consecutive_blocks=3,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert tone_start - 8192 <= found <= tone_start + 2048
|
||||||
|
|
||||||
|
|
||||||
def test_one_control_packet_passes_crc() -> None:
|
def test_one_control_packet_passes_crc() -> None:
|
||||||
assert lab043.control_packet_crc_roundtrip(b"known payload")
|
assert lab043.control_packet_crc_roundtrip(b"known payload")
|
||||||
|
|
||||||
|
|||||||
538
tests/test_lab043_hackrf_counter.py
Normal file
538
tests/test_lab043_hackrf_counter.py
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_counter as counter
|
||||||
|
from experiments import lab043_hackrf_hardware as hackrf
|
||||||
|
from experiments import lab043_pluto_to_rtlsdr as lab043
|
||||||
|
from experiments import lab043_prbs11_hardware as pluto_hardware
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeHackrfReceiver:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.gain_calls: list[tuple[int, int]] = []
|
||||||
|
|
||||||
|
def configure_rx(self) -> dict:
|
||||||
|
return {
|
||||||
|
"set_center_frequency_hz": 435_000_000,
|
||||||
|
"set_sample_rate_hz": 2_400_000.0,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_rx_gains(self, lna_gain_db: int, vga_gain_db: int) -> dict:
|
||||||
|
self.gain_calls.append((lna_gain_db, vga_gain_db))
|
||||||
|
return {
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"lna_gain_db": lna_gain_db,
|
||||||
|
"vga_gain_db": vga_gain_db,
|
||||||
|
"gain_readback_available": False,
|
||||||
|
"set_calls_succeeded": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeHackrfModule:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.preflight_calls: list[tuple[int, int]] = []
|
||||||
|
|
||||||
|
def preflight_hackrf(self, lna_gain_db: int, vga_gain_db: int) -> dict:
|
||||||
|
self.preflight_calls.append((lna_gain_db, vga_gain_db))
|
||||||
|
return _FakeHackrfReceiver().configure_rx()
|
||||||
|
|
||||||
|
|
||||||
|
class _FakePlutoModule:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.preflight_uris: list[str] = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def discover_pluto_usb_uri() -> str:
|
||||||
|
return "usb:1.2.3"
|
||||||
|
|
||||||
|
def preflight_pluto(self, uri: str) -> dict:
|
||||||
|
self.preflight_uris.append(uri)
|
||||||
|
return {"uri": uri, "context_opened": True}
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_uses_dedicated_output_directory() -> None:
|
||||||
|
assert counter.PROCESSED_DIRECTORY == Path(
|
||||||
|
"data/processed/lab043_hackrf_counter"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"script_name",
|
||||||
|
["lab043_hackrf_hardware.py", "lab043_hackrf_counter.py"],
|
||||||
|
)
|
||||||
|
def test_hackrf_scripts_support_direct_help_invocation(script_name: str) -> None:
|
||||||
|
project_root = Path(__file__).resolve().parents[1]
|
||||||
|
completed = subprocess.run(
|
||||||
|
[sys.executable, str(project_root / "experiments" / script_name), "--help"],
|
||||||
|
cwd=project_root,
|
||||||
|
check=False,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert completed.returncode == 0, completed.stdout + completed.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_receiver_is_forced_to_working_point_8_8() -> None:
|
||||||
|
receiver = _FakeHackrfReceiver()
|
||||||
|
|
||||||
|
parameters = counter.configure_counter_receiver(receiver)
|
||||||
|
|
||||||
|
assert receiver.gain_calls == [(8, 8)]
|
||||||
|
assert parameters["lna_gain_db"] == 8
|
||||||
|
assert parameters["vga_gain_db"] == 8
|
||||||
|
assert parameters["rf_amp_enabled"] is False
|
||||||
|
assert parameters["antenna_bias_enabled"] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_and_hackrf_module_share_working_point_8_8() -> None:
|
||||||
|
assert (counter.HACKRF_LNA_GAIN_DB, counter.HACKRF_VGA_GAIN_DB) == (8, 8)
|
||||||
|
assert (hackrf.HACKRF_LNA_GAIN_DB, hackrf.HACKRF_VGA_GAIN_DB) == (8, 8)
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_preflight_explicitly_requests_working_point_8_8() -> None:
|
||||||
|
module = _FakeHackrfModule()
|
||||||
|
|
||||||
|
parameters = counter.preflight_counter_receiver(module)
|
||||||
|
|
||||||
|
assert module.preflight_calls == [(8, 8)]
|
||||||
|
assert parameters["lna_gain_db"] == 8
|
||||||
|
assert parameters["vga_gain_db"] == 8
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_hardware_preflight_uses_discovered_usb_pluto() -> None:
|
||||||
|
hackrf_module = _FakeHackrfModule()
|
||||||
|
pluto_module = _FakePlutoModule()
|
||||||
|
|
||||||
|
result = counter.preflight_counter_hardware(hackrf_module, pluto_module)
|
||||||
|
|
||||||
|
assert pluto_module.preflight_uris == ["usb:1.2.3"]
|
||||||
|
assert result["pluto"]["uri"] == "usb:1.2.3"
|
||||||
|
assert hackrf_module.preflight_calls == [(8, 8)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_pluto_working_point_is_checked_before_tx() -> None:
|
||||||
|
counter.validate_pluto_working_point(
|
||||||
|
{
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
counter.validate_pluto_working_point(
|
||||||
|
{
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_399_998,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match=r"Рабочая точка Pluto\+ не подтверждена"):
|
||||||
|
counter.validate_pluto_working_point(
|
||||||
|
{
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -20.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match=r"Рабочая точка Pluto\+ не подтверждена"):
|
||||||
|
counter.validate_pluto_working_point(
|
||||||
|
{
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_399_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("field", "bad_value"),
|
||||||
|
[
|
||||||
|
("set_center_frequency_hz", 434_999_999),
|
||||||
|
("set_sample_rate_hz", 2_399_999.0),
|
||||||
|
("lna_gain_db", 0),
|
||||||
|
("vga_gain_db", 0),
|
||||||
|
("rf_amp_enabled", True),
|
||||||
|
("antenna_bias_enabled", True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_counter_rejects_any_other_hackrf_working_point(
|
||||||
|
field: str,
|
||||||
|
bad_value: object,
|
||||||
|
) -> None:
|
||||||
|
parameters = _FakeHackrfReceiver().configure_rx()
|
||||||
|
parameters[field] = bad_value
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match="Рабочая точка HackRF не подтверждена"):
|
||||||
|
counter.validate_counter_working_point(parameters)
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_rows_use_null_and_explicit_status_for_unknown_iq_count() -> None:
|
||||||
|
events = [
|
||||||
|
{
|
||||||
|
"received_symbol_index": 0,
|
||||||
|
"type": "пропуск",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
boundaries = (
|
||||||
|
SimpleNamespace(callback_index=1, accepted_end_sample=100),
|
||||||
|
)
|
||||||
|
|
||||||
|
rows, _ = counter._event_hardware_rows(
|
||||||
|
events,
|
||||||
|
np.asarray([100.0]),
|
||||||
|
boundaries,
|
||||||
|
np.zeros(200, dtype=np.complex64),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert rows[0]["exact_lost_or_repeated_iq_samples"] is None
|
||||||
|
assert rows[0]["exact_iq_sample_count_status"] == "not_computed"
|
||||||
|
assert rows[0]["exact_iq_sample_count_reason"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardware_orchestration_saves_raw_before_analysis_and_transmits_once(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
events: list[str] = []
|
||||||
|
transmitted: list[np.ndarray] = []
|
||||||
|
configured_gains: list[tuple[int, int]] = []
|
||||||
|
|
||||||
|
class FakeLibrary:
|
||||||
|
@staticmethod
|
||||||
|
def hackrf_is_streaming(_device: object) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
class FakeDevice:
|
||||||
|
library = FakeLibrary()
|
||||||
|
device = object()
|
||||||
|
|
||||||
|
def __enter__(self) -> "FakeDevice":
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_arguments: object) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def configure_rx(self) -> dict:
|
||||||
|
events.append("configure_hackrf")
|
||||||
|
return _FakeHackrfReceiver().configure_rx()
|
||||||
|
|
||||||
|
def set_rx_gains(self, lna_gain_db: int, vga_gain_db: int) -> dict:
|
||||||
|
configured_gains.append((lna_gain_db, vga_gain_db))
|
||||||
|
return {
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"lna_gain_db": lna_gain_db,
|
||||||
|
"vga_gain_db": vga_gain_db,
|
||||||
|
"gain_readback_available": False,
|
||||||
|
"set_calls_succeeded": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
def capture(self, target_sample_count: int) -> SimpleNamespace:
|
||||||
|
events.append("capture")
|
||||||
|
assert target_sample_count == 4
|
||||||
|
return SimpleNamespace(
|
||||||
|
samples=np.zeros(target_sample_count, dtype=np.complex64),
|
||||||
|
boundaries=(),
|
||||||
|
diagnostics={"callback_count_total": 1},
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(counter, "RX_LEADING_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(counter, "RX_TRAILING_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(counter, "FIXED_TX_UPLOAD_MARGIN_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(hackrf, "HACKRF_EXPECTED_CALLBACK_BYTES", 0)
|
||||||
|
monkeypatch.setattr(hackrf, "HackrfRxDevice", FakeDevice)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
hackrf,
|
||||||
|
"preflight_hackrf",
|
||||||
|
lambda lna, vga: {
|
||||||
|
**_FakeHackrfReceiver().configure_rx(),
|
||||||
|
"lna_gain_db": lna,
|
||||||
|
"vga_gain_db": vga,
|
||||||
|
"serial_number": "test-serial",
|
||||||
|
"firmware_version": "test-firmware",
|
||||||
|
"libhackrf_version": "test-library",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"discover_pluto_usb_uri",
|
||||||
|
lambda: "usb:1.2.3",
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"preflight_pluto",
|
||||||
|
lambda uri: {"context_opened": True, "uri": uri},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"configure_pluto",
|
||||||
|
lambda uri: (
|
||||||
|
object(),
|
||||||
|
{
|
||||||
|
"uri": uri,
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def fake_transmit(
|
||||||
|
_device: object,
|
||||||
|
samples: np.ndarray,
|
||||||
|
_sample_rate_hz: float,
|
||||||
|
) -> float:
|
||||||
|
events.append("transmit")
|
||||||
|
transmitted.append(np.asarray(samples).copy())
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"transmit_noncyclic_buffer_once",
|
||||||
|
fake_transmit,
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
counter,
|
||||||
|
"build_counter_waveform",
|
||||||
|
lambda _sample_rate_hz: (
|
||||||
|
np.asarray([0.25 + 0.25j] * 4, dtype=np.complex64),
|
||||||
|
{"total_duration_seconds": 4 / counter.NOMINAL_SAMPLE_RATE},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
real_save_raw = lab043.save_raw_iq_before_processing
|
||||||
|
|
||||||
|
def save_raw(*arguments: object, **keyword_arguments: object):
|
||||||
|
events.append("save_raw")
|
||||||
|
return real_save_raw(*arguments, **keyword_arguments)
|
||||||
|
|
||||||
|
monkeypatch.setattr(lab043, "save_raw_iq_before_processing", save_raw)
|
||||||
|
|
||||||
|
def fake_analyze(*_arguments: object) -> tuple[dict, dict]:
|
||||||
|
events.append("analyze")
|
||||||
|
return {"classification": "A"}, {}
|
||||||
|
|
||||||
|
monkeypatch.setattr(counter, "analyze_hardware_counter", fake_analyze)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
counter,
|
||||||
|
"save_counter_artifacts",
|
||||||
|
lambda *_arguments, **_keyword_arguments: events.append("save_processed"),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = counter.run_one_hardware_counter(
|
||||||
|
raw_directory=tmp_path / "raw",
|
||||||
|
processed_directory=tmp_path / "processed",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["processing_status"] == "success"
|
||||||
|
assert configured_gains == [(8, 8)]
|
||||||
|
assert len(transmitted) == 1
|
||||||
|
assert events.count("transmit") == 1
|
||||||
|
assert events.index("save_raw") < events.index("analyze")
|
||||||
|
assert result["waveform"]["purpose"] == (
|
||||||
|
"цифровой счётчик времени, не измерение BER"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _reference(count: int = 20_000, start: int = 12_345) -> np.ndarray:
|
||||||
|
return counter.counter_symbol_ids(start, count)
|
||||||
|
|
||||||
|
|
||||||
|
def test_prbs20_period_and_unique_state_map() -> None:
|
||||||
|
bits = counter.prbs20_period_bits()
|
||||||
|
positions = counter.bit_state_to_position()
|
||||||
|
|
||||||
|
assert len(bits) == (1 << 20) - 1
|
||||||
|
assert positions[0] == -1
|
||||||
|
assert np.count_nonzero(positions >= 0) == (1 << 20) - 1
|
||||||
|
assert len(np.unique(positions[positions >= 0])) == (1 << 20) - 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_qpsk_alphabet_has_four_separated_unit_states() -> None:
|
||||||
|
states = counter.QPSK_STATES
|
||||||
|
|
||||||
|
assert len(states) == 4
|
||||||
|
assert np.allclose(np.abs(states), 1.0)
|
||||||
|
distances = np.abs(states[:, None] - states[None, :])
|
||||||
|
assert np.min(distances[distances > 0]) == pytest.approx(np.sqrt(2.0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardware_waveform_parameters_are_fixed_before_tx() -> None:
|
||||||
|
waveform, parameters = counter.build_counter_waveform(2_399_998.0)
|
||||||
|
|
||||||
|
assert counter.SYMBOL_RATE == 20_000.0
|
||||||
|
assert parameters["samples_per_symbol"] == 120
|
||||||
|
assert parameters["useful_symbol_count"] == 100_000
|
||||||
|
assert parameters["transmitted_symbol_count"] == 110_000
|
||||||
|
assert parameters["margin_symbol_count_each_side"] == 5_000
|
||||||
|
assert len(waveform) == 13_200_000
|
||||||
|
assert parameters["useful_duration_seconds"] == pytest.approx(5.00000416667)
|
||||||
|
|
||||||
|
|
||||||
|
def test_zero_cfo_exclusion_is_reproduced_and_diagnostic_override_recovers() -> None:
|
||||||
|
waveform, parameters = counter.build_counter_waveform(2_399_998.0)
|
||||||
|
|
||||||
|
default = counter.recover_counter_from_iq(waveform, 2_399_998.0)
|
||||||
|
diagnostic = counter.recover_counter_from_iq(
|
||||||
|
waveform,
|
||||||
|
2_399_998.0,
|
||||||
|
minimum_fourth_power_hz=0.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert default["carrier"]["carrier_offset_hz"] == pytest.approx(44.99, abs=0.1)
|
||||||
|
assert (
|
||||||
|
default["counter_analysis"]["recovered_symbol_count"]
|
||||||
|
< parameters["transmitted_symbol_count"]
|
||||||
|
)
|
||||||
|
assert diagnostic["carrier"]["carrier_offset_hz"] == pytest.approx(0.0, abs=0.1)
|
||||||
|
assert (
|
||||||
|
diagnostic["counter_analysis"]["recovered_symbol_count"]
|
||||||
|
== parameters["transmitted_symbol_count"]
|
||||||
|
)
|
||||||
|
assert diagnostic["counter_analysis"]["stable_run_count"] == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_ideal_counter_is_continuous() -> None:
|
||||||
|
result = counter.analyze_counter_symbols(_reference())
|
||||||
|
|
||||||
|
assert result["classification"] == "A"
|
||||||
|
assert result["events"] == []
|
||||||
|
assert result["ordinary_symbol_error_count"] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("deleted", [1, 2, 10])
|
||||||
|
def test_counter_detects_deleted_symbols(deleted: int) -> None:
|
||||||
|
reference = _reference()
|
||||||
|
received = np.delete(reference, np.s_[8_000 : 8_000 + deleted])
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "B"
|
||||||
|
assert any(
|
||||||
|
event["type"] == "пропуск"
|
||||||
|
and event["minimum_confirmed_gap_symbols"] == deleted
|
||||||
|
for event in result["events"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("repeated", [1, 4])
|
||||||
|
def test_counter_detects_repeated_symbols(repeated: int) -> None:
|
||||||
|
reference = _reference()
|
||||||
|
at = 8_000
|
||||||
|
received = np.insert(reference, at, reference[at - repeated : at])
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "B"
|
||||||
|
assert any(
|
||||||
|
event["type"] == "повтор"
|
||||||
|
and event["minimum_confirmed_gap_symbols"] == repeated
|
||||||
|
for event in result["events"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_detects_foreign_insertion() -> None:
|
||||||
|
reference = _reference()
|
||||||
|
received = np.insert(reference, 8_000, np.asarray([0, 0, 0], dtype=np.uint8))
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "B"
|
||||||
|
assert any(event["type"] == "вставка" for event in result["events"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_counter_detects_reordered_neighboring_blocks() -> None:
|
||||||
|
reference = _reference()
|
||||||
|
first = reference[7_000:7_200]
|
||||||
|
second = reference[7_200:7_450]
|
||||||
|
received = np.concatenate((reference[:7_000], second, first, reference[7_450:]))
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "B"
|
||||||
|
assert len(result["events"]) >= 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_partial_capture_from_middle_locates_position_without_false_jump() -> None:
|
||||||
|
received = counter.counter_symbol_ids(456_789, 12_000)
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "A"
|
||||||
|
assert result["runs"][0]["first_sequence_position"] == 456_789
|
||||||
|
|
||||||
|
|
||||||
|
def test_capture_ending_early_is_not_a_discontinuity() -> None:
|
||||||
|
reference = _reference()
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(reference[:9_321])
|
||||||
|
|
||||||
|
assert result["classification"] == "A"
|
||||||
|
assert result["events"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_single_symbol_error_is_not_a_large_position_jump() -> None:
|
||||||
|
received = _reference()
|
||||||
|
received[8_000] = (received[8_000] + 1) % 4
|
||||||
|
|
||||||
|
result = counter.analyze_counter_symbols(received)
|
||||||
|
|
||||||
|
assert result["classification"] == "A"
|
||||||
|
assert result["events"] == []
|
||||||
|
assert result["ordinary_symbol_error_count"] == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("carrier_offset_hz", "clock_error_ppm", "noise"),
|
||||||
|
[
|
||||||
|
(1_000.0, 0.0, 0.0),
|
||||||
|
(1_000.0, 35.0, 0.0),
|
||||||
|
(1_000.0, 0.0, 0.12),
|
||||||
|
(-750.0, -30.0, 0.10),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_iq_recovery_handles_frequency_clock_error_and_noise(
|
||||||
|
carrier_offset_hz: float,
|
||||||
|
clock_error_ppm: float,
|
||||||
|
noise: float,
|
||||||
|
) -> None:
|
||||||
|
sample_rate = 120_000.0
|
||||||
|
samples_per_symbol = 12
|
||||||
|
received = counter.synthesize_counter_iq(
|
||||||
|
start_position=345_678,
|
||||||
|
symbol_count=10_000,
|
||||||
|
samples_per_symbol=samples_per_symbol,
|
||||||
|
sample_rate_hz=sample_rate,
|
||||||
|
carrier_offset_hz=carrier_offset_hz,
|
||||||
|
sample_clock_error_ppm=clock_error_ppm,
|
||||||
|
noise_standard_deviation=noise,
|
||||||
|
)
|
||||||
|
|
||||||
|
recovered = counter.recover_counter_from_iq(
|
||||||
|
received,
|
||||||
|
sample_rate,
|
||||||
|
nominal_samples_per_symbol=samples_per_symbol,
|
||||||
|
fft_samples=65_536,
|
||||||
|
minimum_fourth_power_hz=200.0,
|
||||||
|
maximum_fourth_power_hz=10_000.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert recovered["counter_analysis"]["classification"] == "A"
|
||||||
|
assert recovered["counter_analysis"]["anchor_count"] > 8_000
|
||||||
|
assert recovered["counter_analysis"]["events"] == []
|
||||||
|
assert recovered["carrier"]["carrier_offset_hz"] == pytest.approx(
|
||||||
|
carrier_offset_hz, abs=2.0
|
||||||
|
)
|
||||||
191
tests/test_lab043_hackrf_gain_ladder.py
Normal file
191
tests/test_lab043_hackrf_gain_ladder.py
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_gain_ladder as ladder
|
||||||
|
|
||||||
|
|
||||||
|
def _tone(
|
||||||
|
sample_rate: float,
|
||||||
|
seconds: float,
|
||||||
|
amplitude: float,
|
||||||
|
noise: float = 0.0,
|
||||||
|
second: float = 0.0,
|
||||||
|
third: float = 0.0,
|
||||||
|
frequency: float = 50_123.0,
|
||||||
|
) -> np.ndarray:
|
||||||
|
rng = np.random.default_rng(43043)
|
||||||
|
count = round(sample_rate * seconds)
|
||||||
|
indexes = np.arange(count, dtype=np.float64)
|
||||||
|
result = amplitude * np.exp(1j * 2.0 * np.pi * frequency * indexes / sample_rate)
|
||||||
|
result += second * np.exp(1j * 2.0 * np.pi * 2.0 * frequency * indexes / sample_rate)
|
||||||
|
result += third * np.exp(1j * 2.0 * np.pi * 3.0 * frequency * indexes / sample_rate)
|
||||||
|
if noise:
|
||||||
|
result += noise * (rng.normal(size=count) + 1j * rng.normal(size=count))
|
||||||
|
return result.astype(np.complex64)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fixed_gain_ladder_is_valid_and_monotonic() -> None:
|
||||||
|
assert ladder.GAIN_LADDER == (
|
||||||
|
(0, 0), (8, 8), (16, 8), (16, 16), (24, 16), (24, 24)
|
||||||
|
)
|
||||||
|
assert [sum(point) for point in ladder.GAIN_LADDER] == sorted(
|
||||||
|
sum(point) for point in ladder.GAIN_LADDER
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_measure_tone_finds_frequency_margin_and_no_overload() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
samples = _tone(sample_rate, 3.0, amplitude=0.20, noise=0.002)
|
||||||
|
|
||||||
|
metrics = ladder.measure_tone_segment(samples, sample_rate, fft_samples=65_536)
|
||||||
|
|
||||||
|
assert metrics["tone_frequency_hz"] == pytest.approx(50_123.0, abs=2.0)
|
||||||
|
assert metrics["tone_over_noise_db"] > 35.0
|
||||||
|
assert metrics["rms_amplitude"] == pytest.approx(0.20, abs=0.01)
|
||||||
|
assert metrics["clipped_component_fraction"] == 0.0
|
||||||
|
assert not metrics["second_harmonic"]["credible"]
|
||||||
|
assert not metrics["third_harmonic"]["credible"]
|
||||||
|
assert not metrics["stop_gain_escalation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_strong_tone_without_harmonics_is_not_nonlinear() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
samples = _tone(sample_rate, 3.0, amplitude=0.55, noise=0.002)
|
||||||
|
|
||||||
|
metrics = ladder.measure_tone_segment(samples, sample_rate, fft_samples=65_536)
|
||||||
|
|
||||||
|
assert not metrics["second_harmonic"]["credible"]
|
||||||
|
assert not metrics["third_harmonic"]["credible"]
|
||||||
|
assert not metrics["harmonic_nonlinearity_detected"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_credible_second_harmonic_is_detected() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
samples = _tone(sample_rate, 3.0, amplitude=0.30, noise=0.001, second=0.03)
|
||||||
|
|
||||||
|
metrics = ladder.measure_tone_segment(samples, sample_rate, fft_samples=65_536)
|
||||||
|
|
||||||
|
assert metrics["second_harmonic"]["credible"]
|
||||||
|
assert metrics["second_harmonic"]["nonlinear"]
|
||||||
|
assert metrics["second_harmonic"]["relative_to_fundamental_db"] == pytest.approx(-20.0, abs=1.0)
|
||||||
|
assert metrics["stop_gain_escalation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_credible_third_harmonic_is_detected() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
samples = _tone(sample_rate, 3.0, amplitude=0.30, noise=0.001, third=0.015)
|
||||||
|
|
||||||
|
metrics = ladder.measure_tone_segment(samples, sample_rate, fft_samples=65_536)
|
||||||
|
|
||||||
|
assert metrics["third_harmonic"]["credible"]
|
||||||
|
assert metrics["third_harmonic"]["nonlinear"]
|
||||||
|
assert metrics["third_harmonic"]["relative_to_fundamental_db"] == pytest.approx(-26.0, abs=1.0)
|
||||||
|
assert metrics["stop_gain_escalation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_peak_high_relative_to_weak_tone_but_below_local_margin_is_not_credible() -> None:
|
||||||
|
sample_rate = 1_000_000.0
|
||||||
|
fft_samples = 10_000
|
||||||
|
frequencies = np.fft.fftfreq(fft_samples, d=1.0 / sample_rate)
|
||||||
|
powers = np.full(fft_samples, 1e-5, dtype=np.float64)
|
||||||
|
expected = 100_000.0
|
||||||
|
peak_index = int(np.argmin(np.abs(frequencies - expected)))
|
||||||
|
powers[peak_index] = 3e-5
|
||||||
|
|
||||||
|
result = ladder.analyze_harmonic(
|
||||||
|
powers,
|
||||||
|
frequencies,
|
||||||
|
fundamental_frequency_hz=50_000.0,
|
||||||
|
fundamental_power=1e-6,
|
||||||
|
order=2,
|
||||||
|
sample_rate_hz=sample_rate,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["relative_to_fundamental_db"] > 10.0
|
||||||
|
assert result["above_local_noise_db"] < ladder.HARMONIC_DETECTION_MARGIN_DB
|
||||||
|
assert not result["credible"]
|
||||||
|
assert not result["nonlinear"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_measure_tone_stops_on_near_limit_samples() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
samples = _tone(sample_rate, 2.0, amplitude=0.95)
|
||||||
|
|
||||||
|
metrics = ladder.measure_tone_segment(samples, sample_rate, fft_samples=65_536)
|
||||||
|
|
||||||
|
assert metrics["near_limit_component_fraction"] > 0.0
|
||||||
|
assert metrics["stop_gain_escalation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_harmonic_frequency_aliases_into_nyquist_band() -> None:
|
||||||
|
assert ladder.alias_frequency_to_nyquist(900_000.0, 1_000_000.0) == pytest.approx(-100_000.0)
|
||||||
|
assert ladder.alias_frequency_to_nyquist(1_350_000.0, 1_000_000.0) == pytest.approx(350_000.0)
|
||||||
|
|
||||||
|
sample_rate = 1_000_000.0
|
||||||
|
fft_samples = 100_000
|
||||||
|
frequencies = np.fft.fftfreq(fft_samples, d=1.0 / sample_rate)
|
||||||
|
powers = np.full(fft_samples, 1e-10, dtype=np.float64)
|
||||||
|
powers[int(np.argmin(np.abs(frequencies + 100_000.0)))] = 1e-3
|
||||||
|
powers[int(np.argmin(np.abs(frequencies - 350_000.0)))] = 2.5e-4
|
||||||
|
second = ladder.analyze_harmonic(
|
||||||
|
powers, frequencies, 450_000.0, 0.1, 2, sample_rate
|
||||||
|
)
|
||||||
|
third = ladder.analyze_harmonic(
|
||||||
|
powers, frequencies, 450_000.0, 0.1, 3, sample_rate
|
||||||
|
)
|
||||||
|
assert second["expected_frequency_hz"] == pytest.approx(-100_000.0)
|
||||||
|
assert third["expected_frequency_hz"] == pytest.approx(350_000.0)
|
||||||
|
assert second["credible"]
|
||||||
|
assert third["credible"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_choose_preferred_gain_uses_lowest_gain_reaching_desirable_margin() -> None:
|
||||||
|
def row(index: int, lna: int, vga: int, margin: float) -> dict:
|
||||||
|
return {
|
||||||
|
"step_index": index,
|
||||||
|
"lna_gain_db": lna,
|
||||||
|
"vga_gain_db": vga,
|
||||||
|
"metrics": {
|
||||||
|
"tone_over_noise_db": margin,
|
||||||
|
"maximum_component": 0.4,
|
||||||
|
"stop_gain_escalation": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rows = [row(0, 0, 0, 20.0), row(1, 8, 8, 38.5), row(2, 16, 8, 40.0)]
|
||||||
|
|
||||||
|
selected = ladder.choose_preferred_gain(rows)
|
||||||
|
|
||||||
|
assert selected is rows[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_choose_preferred_gain_rejects_unsafe_rows() -> None:
|
||||||
|
row = {
|
||||||
|
"step_index": 0,
|
||||||
|
"lna_gain_db": 0,
|
||||||
|
"vga_gain_db": 0,
|
||||||
|
"metrics": {
|
||||||
|
"tone_over_noise_db": 60.0,
|
||||||
|
"maximum_component": 0.95,
|
||||||
|
"stop_gain_escalation": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert ladder.choose_preferred_gain([row]) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_choose_preferred_gain_uses_near_best_when_target_not_reached() -> None:
|
||||||
|
def row(index: int, lna: int, vga: int, margin: float) -> dict:
|
||||||
|
return {
|
||||||
|
"step_index": index,
|
||||||
|
"lna_gain_db": lna,
|
||||||
|
"vga_gain_db": vga,
|
||||||
|
"metrics": {
|
||||||
|
"tone_over_noise_db": margin,
|
||||||
|
"maximum_component": 0.4,
|
||||||
|
"stop_gain_escalation": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rows = [row(0, 0, 0, 20.0), row(1, 8, 8, 31.5), row(2, 16, 8, 33.0)]
|
||||||
|
assert ladder.choose_preferred_gain(rows) is rows[1]
|
||||||
203
tests/test_lab043_hackrf_hardware.py
Normal file
203
tests/test_lab043_hackrf_hardware.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import ctypes
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_hardware as hackrf
|
||||||
|
from experiments import lab043_hackrf_continuity as continuity
|
||||||
|
|
||||||
|
|
||||||
|
def _block(first: int, complex_samples: int) -> bytes:
|
||||||
|
values = (np.arange(2 * complex_samples, dtype=np.int16) + first) % 255 - 127
|
||||||
|
return values.astype(np.int8).tobytes()
|
||||||
|
|
||||||
|
|
||||||
|
def test_signed_iq_bytes_to_complex64_preserves_iq_order() -> None:
|
||||||
|
raw = np.asarray([-128, 127, -64, 32], dtype=np.int8).tobytes()
|
||||||
|
|
||||||
|
result = hackrf.signed_iq_bytes_to_complex64(raw)
|
||||||
|
|
||||||
|
assert result.dtype == np.complex64
|
||||||
|
assert np.allclose(result, [-1.0 + 127j / 128.0, -0.5 + 0.25j])
|
||||||
|
|
||||||
|
|
||||||
|
def test_signed_iq_bytes_rejects_incomplete_complex_sample() -> None:
|
||||||
|
with pytest.raises(ValueError, match="чётное"):
|
||||||
|
hackrf.signed_iq_bytes_to_complex64(b"\x01")
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_copy_uses_only_valid_length_and_survives_source_reuse() -> None:
|
||||||
|
source = (ctypes.c_uint8 * 8)(1, 2, 3, 4, 90, 91, 92, 93)
|
||||||
|
|
||||||
|
copied = hackrf.copy_valid_callback_bytes(source, buffer_length=8, valid_length=4)
|
||||||
|
for index in range(8):
|
||||||
|
source[index] = 0
|
||||||
|
|
||||||
|
assert copied == b"\x01\x02\x03\x04"
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_copy_rejects_odd_valid_length() -> None:
|
||||||
|
source = (ctypes.c_uint8 * 4)(1, 2, 3, 4)
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="чётным"):
|
||||||
|
hackrf.copy_valid_callback_bytes(source, buffer_length=4, valid_length=3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_assembler_discards_fixed_warmup_and_keeps_order() -> None:
|
||||||
|
blocks = [_block(0, 4), _block(20, 4), _block(40, 4), _block(60, 4)]
|
||||||
|
|
||||||
|
samples, boundaries, diagnostics = hackrf.assemble_callback_blocks(
|
||||||
|
blocks, target_sample_count=9, warmup_callback_count=1
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = hackrf.signed_iq_bytes_to_complex64(
|
||||||
|
blocks[1] + blocks[2] + blocks[3][:2]
|
||||||
|
)
|
||||||
|
assert np.array_equal(samples, expected)
|
||||||
|
assert [row.callback_index for row in boundaries] == [1, 2, 3]
|
||||||
|
assert [row.accepted_end_sample for row in boundaries] == [4, 8, 9]
|
||||||
|
assert [row.accepted_bytes for row in boundaries] == [8, 8, 2]
|
||||||
|
assert [row.buffer_length for row in boundaries] == [8, 8, 8]
|
||||||
|
assert diagnostics["callback_indexes_sequential"]
|
||||||
|
assert diagnostics["program_queue_missing_callback_count"] == 0
|
||||||
|
assert diagnostics["accepted_sample_count"] == 9
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_assembler_keeps_distinct_blocks_without_duplication() -> None:
|
||||||
|
blocks = [b"\x01\x02\x03\x04", b"\x05\x06\x07\x08"]
|
||||||
|
|
||||||
|
samples, boundaries, diagnostics = hackrf.assemble_callback_blocks(
|
||||||
|
blocks,
|
||||||
|
target_sample_count=4,
|
||||||
|
warmup_callback_count=0,
|
||||||
|
buffer_lengths=[16, 16],
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = hackrf.signed_iq_bytes_to_complex64(blocks[0] + blocks[1])
|
||||||
|
assert np.array_equal(samples, expected)
|
||||||
|
assert [row.callback_index for row in boundaries] == [0, 1]
|
||||||
|
assert [row.valid_bytes for row in boundaries] == [4, 4]
|
||||||
|
assert [row.buffer_length for row in boundaries] == [16, 16]
|
||||||
|
assert diagnostics["accepted_bytes"] == sum(map(len, blocks))
|
||||||
|
|
||||||
|
|
||||||
|
def test_capture_contract_keeps_original_int8_bytes_separate_from_complex64() -> None:
|
||||||
|
raw = np.asarray([-128, 127, -64, 32], dtype=np.int8).tobytes()
|
||||||
|
capture = hackrf.HackrfCapture(
|
||||||
|
samples=hackrf.signed_iq_bytes_to_complex64(raw),
|
||||||
|
boundaries=(),
|
||||||
|
diagnostics={},
|
||||||
|
raw_bytes=raw,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert capture.raw_bytes == raw
|
||||||
|
assert capture.samples.dtype == np.complex64
|
||||||
|
assert np.array_equal(
|
||||||
|
capture.samples,
|
||||||
|
hackrf.signed_iq_bytes_to_complex64(capture.raw_bytes),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("timeout_seconds", [0.0, -1.0, float("nan")])
|
||||||
|
def test_capture_rejects_invalid_timeout_before_hardware_access(
|
||||||
|
timeout_seconds: float,
|
||||||
|
) -> None:
|
||||||
|
receiver = hackrf.HackrfRxDevice()
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="Тайм-аут"):
|
||||||
|
receiver.capture(1, timeout_seconds=timeout_seconds)
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_assembler_rejects_short_stream() -> None:
|
||||||
|
with pytest.raises(RuntimeError, match="короче"):
|
||||||
|
hackrf.assemble_callback_blocks(
|
||||||
|
[_block(0, 4), _block(20, 4)],
|
||||||
|
target_sample_count=9,
|
||||||
|
warmup_callback_count=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_assembler_rejects_odd_callback() -> None:
|
||||||
|
with pytest.raises(ValueError, match="нечётное"):
|
||||||
|
hackrf.assemble_callback_blocks(
|
||||||
|
[b"\x00\x01", b"\x02"],
|
||||||
|
target_sample_count=1,
|
||||||
|
warmup_callback_count=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hackrf_configuration_is_fixed_and_rx_only() -> None:
|
||||||
|
assert hackrf.HACKRF_CENTER_HZ == 435_000_000
|
||||||
|
assert hackrf.HACKRF_SAMPLE_RATE_HZ == 2_400_000.0
|
||||||
|
assert hackrf.HACKRF_RF_AMP == 0
|
||||||
|
assert hackrf.HACKRF_ANTENNA_BIAS == 0
|
||||||
|
assert hackrf.HACKRF_LNA_GAIN_DB == 8
|
||||||
|
assert hackrf.HACKRF_VGA_GAIN_DB == 8
|
||||||
|
assert not hasattr(hackrf.HackrfRxDevice, "transmit")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("lna", "vga"),
|
||||||
|
[(0, 0), (8, 8), (16, 8), (16, 16), (24, 16), (24, 24), (40, 62)],
|
||||||
|
)
|
||||||
|
def test_hackrf_rx_gain_steps_accept_official_values(lna: int, vga: int) -> None:
|
||||||
|
assert hackrf.validate_hackrf_rx_gains(lna, vga) == (lna, vga)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("lna", [-8, 4, 48])
|
||||||
|
def test_hackrf_rx_gain_steps_reject_invalid_lna(lna: int) -> None:
|
||||||
|
with pytest.raises(ValueError, match="LNA"):
|
||||||
|
hackrf.validate_hackrf_rx_gains(lna, 0)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("vga", [-2, 1, 64])
|
||||||
|
def test_hackrf_rx_gain_steps_reject_invalid_vga(vga: int) -> None:
|
||||||
|
with pytest.raises(ValueError, match="VGA"):
|
||||||
|
hackrf.validate_hackrf_rx_gains(0, vga)
|
||||||
|
|
||||||
|
|
||||||
|
def test_periodic_continuity_tone_has_identical_wrap_phase() -> None:
|
||||||
|
tone, frequency = continuity.build_periodic_tone(2_400_000.0)
|
||||||
|
|
||||||
|
phase_step = np.exp(1j * 2.0 * np.pi * frequency / 2_400_000.0)
|
||||||
|
assert len(tone) == 48 * continuity.CYCLIC_PERIOD_COUNT
|
||||||
|
assert np.allclose(tone[0], tone[-1] * phase_step, atol=2e-6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_boundary_analysis_finds_known_phase_step_at_callback_boundary() -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
frequency = 5_000.0
|
||||||
|
sample_count = 240_000
|
||||||
|
boundary_sample = sample_count // 2
|
||||||
|
indexes = np.arange(sample_count, dtype=np.float64)
|
||||||
|
samples = np.exp(1j * 2.0 * np.pi * frequency * indexes / sample_rate)
|
||||||
|
samples[boundary_sample:] *= np.exp(0.8j)
|
||||||
|
boundary = hackrf.HackrfBoundary(
|
||||||
|
callback_index=1,
|
||||||
|
valid_bytes=2 * boundary_sample,
|
||||||
|
accepted_bytes=2 * boundary_sample,
|
||||||
|
accepted_start_sample=0,
|
||||||
|
accepted_end_sample=boundary_sample,
|
||||||
|
monotonic_seconds=0.5,
|
||||||
|
block_sha256="synthetic",
|
||||||
|
buffer_length=2 * boundary_sample,
|
||||||
|
)
|
||||||
|
|
||||||
|
rows, summary = continuity.analyze_callback_boundaries(
|
||||||
|
samples.astype(np.complex64),
|
||||||
|
(boundary,),
|
||||||
|
sample_rate,
|
||||||
|
frequency,
|
||||||
|
stable_start_sample=0,
|
||||||
|
stable_end_sample=sample_count,
|
||||||
|
side_samples=32_768,
|
||||||
|
block_samples=8_192,
|
||||||
|
hop_samples=2_048,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert summary["confirmed_jump_count"] == 1
|
||||||
|
assert rows[0]["additional_phase_jump_rad"] == pytest.approx(0.8, abs=0.01)
|
||||||
|
assert rows[0]["equivalent_sample_shift_principal"] == pytest.approx(
|
||||||
|
0.8 / (2.0 * np.pi * frequency / sample_rate), abs=0.05
|
||||||
|
)
|
||||||
|
assert rows[0]["relation_to_callback_boundary"] == "consistent_with_exact_boundary"
|
||||||
428
tests/test_lab043_hackrf_zero_if_compare.py
Normal file
428
tests/test_lab043_hackrf_zero_if_compare.py
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
import ast
|
||||||
|
import inspect
|
||||||
|
from pathlib import Path
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from experiments import lab043_hackrf_counter as counter
|
||||||
|
from experiments import lab043_hackrf_hardware as hackrf
|
||||||
|
from experiments import lab043_hackrf_zero_if_compare as comparison
|
||||||
|
from experiments import lab043_prbs11_hardware as pluto_hardware
|
||||||
|
|
||||||
|
|
||||||
|
def test_comparison_uses_dedicated_output_directory() -> None:
|
||||||
|
assert comparison.PROCESSED_DIRECTORY == Path(
|
||||||
|
"data/processed/lab043_hackrf_zero_if_compare"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_composite_waveform_has_seven_fixed_sections_and_identical_counters(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
base_counter = np.asarray(
|
||||||
|
[0.35 + 0.0j, 0.0 + 0.35j, -0.35 + 0.0j, 0.0 - 0.35j],
|
||||||
|
dtype=np.complex64,
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
counter,
|
||||||
|
"build_counter_waveform",
|
||||||
|
lambda _sample_rate: (base_counter.copy(), {"samples_per_symbol": 120}),
|
||||||
|
)
|
||||||
|
|
||||||
|
waveform, metadata = comparison.build_composite_waveform(sample_rate)
|
||||||
|
|
||||||
|
names = [row["name"] for row in metadata["sections"]]
|
||||||
|
assert names == [
|
||||||
|
"leading_zero",
|
||||||
|
"tone_plus_50khz",
|
||||||
|
"guard_before_shifted_counter",
|
||||||
|
"counter_plus_50khz",
|
||||||
|
"guard_after_shifted_counter",
|
||||||
|
"counter_zero_if",
|
||||||
|
"trailing_zero",
|
||||||
|
]
|
||||||
|
sections = {row["name"]: row for row in metadata["sections"]}
|
||||||
|
shifted_row = sections["counter_plus_50khz"]
|
||||||
|
centered_row = sections["counter_zero_if"]
|
||||||
|
shifted = waveform[
|
||||||
|
shifted_row["start_sample"] : shifted_row["end_sample_exclusive"]
|
||||||
|
]
|
||||||
|
centered = waveform[
|
||||||
|
centered_row["start_sample"] : centered_row["end_sample_exclusive"]
|
||||||
|
]
|
||||||
|
indexes = np.arange(len(shifted), dtype=np.float64)
|
||||||
|
restored = shifted * np.exp(
|
||||||
|
-2j * np.pi * comparison.TONE_OFFSET_HZ * indexes / sample_rate
|
||||||
|
)
|
||||||
|
assert np.allclose(restored, centered, atol=2e-7)
|
||||||
|
assert metadata["digital_sequences_bit_identical"] is True
|
||||||
|
assert (
|
||||||
|
metadata["counter_symbol_ids_sha256_shifted"]
|
||||||
|
== metadata["counter_symbol_ids_sha256_centered"]
|
||||||
|
)
|
||||||
|
assert metadata["counter_amplitude"] == metadata["tone_amplitude"] == 0.35
|
||||||
|
for name in (
|
||||||
|
"leading_zero",
|
||||||
|
"guard_before_shifted_counter",
|
||||||
|
"guard_after_shifted_counter",
|
||||||
|
"trailing_zero",
|
||||||
|
):
|
||||||
|
row = sections[name]
|
||||||
|
assert np.count_nonzero(waveform[row["start_sample"] : row["end_sample_exclusive"]]) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_pluto_scaling_is_in_place_and_does_not_clip() -> None:
|
||||||
|
waveform = np.asarray([0.35 + 0.0j, 0.0 - 0.35j], dtype=np.complex64)
|
||||||
|
identity = id(waveform)
|
||||||
|
|
||||||
|
result = comparison.scale_pluto_samples_in_place(waveform)
|
||||||
|
|
||||||
|
assert id(result) == identity
|
||||||
|
assert result.dtype == np.complex64
|
||||||
|
assert np.max(np.abs(result)) == pytest.approx(0.35 * 2**14, rel=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pluto_validation_includes_rf_bandwidth() -> None:
|
||||||
|
parameters = {
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
"actual_rf_bandwidth_hz": 200_000,
|
||||||
|
}
|
||||||
|
comparison.validate_pluto_working_point(parameters)
|
||||||
|
|
||||||
|
parameters["actual_rf_bandwidth_hz"] = 100_000
|
||||||
|
with pytest.raises(RuntimeError, match="RF bandwidth"):
|
||||||
|
comparison.validate_pluto_working_point(parameters)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dual_raw_is_hashed_reread_and_exactly_converted(tmp_path: Path) -> None:
|
||||||
|
raw = np.asarray([-128, 127, -64, 32, 0, -1], dtype=np.int8).tobytes()
|
||||||
|
samples = hackrf.signed_iq_bytes_to_complex64(raw)
|
||||||
|
|
||||||
|
int8_path, iq_path, metadata_path, document = comparison.save_dual_raw_before_processing(
|
||||||
|
tmp_path / "capture",
|
||||||
|
raw,
|
||||||
|
samples,
|
||||||
|
{"capture_status": "captured", "processing_status": "pending"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert int8_path.read_bytes() == raw
|
||||||
|
assert np.array_equal(np.load(iq_path, allow_pickle=False), samples)
|
||||||
|
assert document["raw_verified"] is True
|
||||||
|
assert document["int8_to_complex64"]["verified"] is True
|
||||||
|
assert document["int8_to_complex64"]["byte_order"] == "interleaved I then Q"
|
||||||
|
assert document["int8_sha256"] == comparison._hash_file(int8_path)
|
||||||
|
assert document["iq_sha256"] == comparison._hash_file(iq_path)
|
||||||
|
assert metadata_path.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_background_metrics_keep_dc_and_signed_code_distributions() -> None:
|
||||||
|
codes = np.asarray([[-2, 4], [-2, 4], [-1, 3], [-2, 4]], dtype=np.int8)
|
||||||
|
samples = hackrf.signed_iq_bytes_to_complex64(codes.tobytes())
|
||||||
|
|
||||||
|
metrics = comparison.background_metrics(samples, codes, 2_400_000.0)
|
||||||
|
|
||||||
|
assert metrics["i_code_distribution"] == {"-2": 3, "-1": 1}
|
||||||
|
assert metrics["q_code_distribution"] == {"3": 1, "4": 3}
|
||||||
|
assert metrics["mean_i"] == pytest.approx(-1.75 / 128.0)
|
||||||
|
assert metrics["mean_q"] == pytest.approx(3.75 / 128.0)
|
||||||
|
assert metrics["dc_correction_applied"] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_known_counter_analysis_recovers_shifted_synthetic_without_dc_correction(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
sample_rate = 240_000.0
|
||||||
|
symbol_count = 1_000
|
||||||
|
samples_per_symbol = 120
|
||||||
|
carrier_hz = 50_200.0
|
||||||
|
expected_start = 80_037
|
||||||
|
monkeypatch.setattr(counter, "TRANSMITTED_SYMBOL_COUNT", symbol_count)
|
||||||
|
monkeypatch.setattr(comparison, "MATCH_REFERENCE_START_SYMBOL", 100)
|
||||||
|
monkeypatch.setattr(comparison, "MATCH_REFERENCE_SYMBOL_COUNT", 300)
|
||||||
|
symbols = counter.counter_qpsk_symbols(0, symbol_count)
|
||||||
|
base = np.repeat(symbols, samples_per_symbol)
|
||||||
|
indexes = np.arange(len(base), dtype=np.float64)
|
||||||
|
signal = (0.02 * base * np.exp(2j * np.pi * carrier_hz * indexes / sample_rate)).astype(
|
||||||
|
np.complex64
|
||||||
|
)
|
||||||
|
raw = np.full(320_000, 0.01 + 0.02j, dtype=np.complex64)
|
||||||
|
raw[expected_start : expected_start + len(signal)] += signal
|
||||||
|
|
||||||
|
result = comparison.analyze_counter_section(
|
||||||
|
raw,
|
||||||
|
expected_start + 40,
|
||||||
|
carrier_hz,
|
||||||
|
sample_rate,
|
||||||
|
background_power=0.01**2 + 0.02**2,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["start_sample"] == expected_start
|
||||||
|
assert result["measured_carrier_hz"] == pytest.approx(carrier_hz, abs=0.1)
|
||||||
|
assert result["symbol_error_rate"] == 0.0
|
||||||
|
assert result["dc_correction_applied"] is False
|
||||||
|
assert result["new_filter_applied"] is False
|
||||||
|
assert result["equalizer_applied"] is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardware_runner_contains_one_tx_call_and_no_forbidden_experiment_calls() -> None:
|
||||||
|
tree = ast.parse(inspect.getsource(comparison.run_one_zero_if_comparison))
|
||||||
|
calls = [node for node in ast.walk(tree) if isinstance(node, ast.Call)]
|
||||||
|
attributes = [node.func.attr for node in calls if isinstance(node.func, ast.Attribute)]
|
||||||
|
|
||||||
|
assert attributes.count("transmit_noncyclic_buffer_once") == 1
|
||||||
|
forbidden = {
|
||||||
|
"run_one_hackrf_s",
|
||||||
|
"run_one_hardware_counter",
|
||||||
|
"run_one_hardware_prbs11",
|
||||||
|
"run_packet",
|
||||||
|
"run_jpeg",
|
||||||
|
}
|
||||||
|
assert forbidden.isdisjoint(attributes)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardware_orchestration_transmits_once_and_saves_both_raw_before_analysis(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
events: list[str] = []
|
||||||
|
transmitted: list[np.ndarray] = []
|
||||||
|
|
||||||
|
class FakeLibrary:
|
||||||
|
@staticmethod
|
||||||
|
def hackrf_is_streaming(_device: object) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
class FakeReceiver:
|
||||||
|
library = FakeLibrary()
|
||||||
|
device = object()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_arguments: object) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def configure_rx(self) -> dict:
|
||||||
|
return {
|
||||||
|
"set_center_frequency_hz": 435_000_000,
|
||||||
|
"set_sample_rate_hz": 2_400_000.0,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_rx_gains(self, lna_gain_db: int, vga_gain_db: int) -> dict:
|
||||||
|
assert (lna_gain_db, vga_gain_db) == (8, 8)
|
||||||
|
return {
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"lna_gain_db": lna_gain_db,
|
||||||
|
"vga_gain_db": vga_gain_db,
|
||||||
|
}
|
||||||
|
|
||||||
|
def capture(self, target_sample_count: int, timeout_seconds: float):
|
||||||
|
events.append("capture")
|
||||||
|
assert timeout_seconds == comparison.RX_TIMEOUT_SECONDS
|
||||||
|
raw = bytes(2 * target_sample_count)
|
||||||
|
return SimpleNamespace(
|
||||||
|
samples=hackrf.signed_iq_bytes_to_complex64(raw),
|
||||||
|
raw_bytes=raw,
|
||||||
|
boundaries=(),
|
||||||
|
diagnostics={
|
||||||
|
"callback_count_total": 1,
|
||||||
|
"stream_started_monotonic": 0.0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(comparison, "RX_LEADING_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(comparison, "RX_TRAILING_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(comparison, "TX_UPLOAD_MARGIN_SECONDS", 0.0)
|
||||||
|
monkeypatch.setattr(hackrf, "HACKRF_EXPECTED_CALLBACK_BYTES", 0)
|
||||||
|
monkeypatch.setattr(hackrf, "HackrfRxDevice", FakeReceiver)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
hackrf,
|
||||||
|
"preflight_hackrf",
|
||||||
|
lambda lna, vga: {
|
||||||
|
"set_center_frequency_hz": 435_000_000,
|
||||||
|
"set_sample_rate_hz": 2_400_000.0,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"lna_gain_db": lna,
|
||||||
|
"vga_gain_db": vga,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"serial_number": "serial",
|
||||||
|
"firmware_version": "firmware",
|
||||||
|
"libhackrf_version": "library",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(pluto_hardware, "discover_pluto_usb_uri", lambda: "usb:1.2.3")
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"preflight_pluto",
|
||||||
|
lambda uri: {"uri": uri, "context_opened": True},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"configure_pluto",
|
||||||
|
lambda uri: (
|
||||||
|
object(),
|
||||||
|
{
|
||||||
|
"uri": uri,
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
"actual_rf_bandwidth_hz": 200_000,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
comparison,
|
||||||
|
"build_composite_waveform",
|
||||||
|
lambda _sample_rate: (
|
||||||
|
np.asarray([0.1 + 0.1j] * 4, dtype=np.complex64),
|
||||||
|
{"total_duration_seconds": 4 / 2_400_000.0, "sections": [], "total_sample_count": 4},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def fake_transmit(_device: object, samples: np.ndarray, _sample_rate: float) -> float:
|
||||||
|
events.append("transmit")
|
||||||
|
transmitted.append(np.asarray(samples).copy())
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
monkeypatch.setattr(pluto_hardware, "transmit_noncyclic_buffer_once", fake_transmit)
|
||||||
|
real_save = comparison.save_dual_raw_before_processing
|
||||||
|
|
||||||
|
def save_raw(*arguments: object, **keyword_arguments: object):
|
||||||
|
events.append("save_raw")
|
||||||
|
return real_save(*arguments, **keyword_arguments)
|
||||||
|
|
||||||
|
monkeypatch.setattr(comparison, "save_dual_raw_before_processing", save_raw)
|
||||||
|
|
||||||
|
def analyze(*_arguments: object) -> dict:
|
||||||
|
events.append("analyze")
|
||||||
|
return {
|
||||||
|
"counter_plus_50khz": {},
|
||||||
|
"counter_zero_if": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
monkeypatch.setattr(comparison, "analyze_saved_capture", analyze)
|
||||||
|
monkeypatch.setattr(comparison, "save_processed_artifacts", lambda *_arguments: ())
|
||||||
|
|
||||||
|
result = comparison.run_one_zero_if_comparison(tmp_path, tmp_path / "processed")
|
||||||
|
|
||||||
|
assert result["processing_status"] == "success"
|
||||||
|
assert events.count("transmit") == 1
|
||||||
|
assert len(transmitted) == 1
|
||||||
|
assert events.index("save_raw") < events.index("analyze")
|
||||||
|
assert Path(result["int8_path"]).suffix == ".int8"
|
||||||
|
assert Path(result["iq_path"]).suffix == ".npy"
|
||||||
|
|
||||||
|
|
||||||
|
def test_rx_failure_before_stream_confirmation_prevents_tx(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
transmit_calls = 0
|
||||||
|
|
||||||
|
class FailedLibrary:
|
||||||
|
@staticmethod
|
||||||
|
def hackrf_is_streaming(_device: object) -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
class FailedReceiver:
|
||||||
|
library = FailedLibrary()
|
||||||
|
device = object()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_arguments: object) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def configure_rx(self) -> dict:
|
||||||
|
return {
|
||||||
|
"set_center_frequency_hz": 435_000_000,
|
||||||
|
"set_sample_rate_hz": 2_400_000.0,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"lna_gain_db": 8,
|
||||||
|
"vga_gain_db": 8,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_rx_gains(self, lna_gain_db: int, vga_gain_db: int) -> dict:
|
||||||
|
return {
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"lna_gain_db": lna_gain_db,
|
||||||
|
"vga_gain_db": vga_gain_db,
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def capture(_target_sample_count: int, timeout_seconds: float):
|
||||||
|
raise RuntimeError(f"synthetic RX failure before streaming ({timeout_seconds})")
|
||||||
|
|
||||||
|
monkeypatch.setattr(hackrf, "HackrfRxDevice", FailedReceiver)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
hackrf,
|
||||||
|
"preflight_hackrf",
|
||||||
|
lambda lna, vga: {
|
||||||
|
"set_center_frequency_hz": 435_000_000,
|
||||||
|
"set_sample_rate_hz": 2_400_000.0,
|
||||||
|
"rf_amp_enabled": False,
|
||||||
|
"lna_gain_db": lna,
|
||||||
|
"vga_gain_db": vga,
|
||||||
|
"antenna_bias_enabled": False,
|
||||||
|
"serial_number": "serial",
|
||||||
|
"firmware_version": "firmware",
|
||||||
|
"libhackrf_version": "library",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(pluto_hardware, "discover_pluto_usb_uri", lambda: "usb:1.2.3")
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"preflight_pluto",
|
||||||
|
lambda uri: {"uri": uri, "context_opened": True},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"configure_pluto",
|
||||||
|
lambda uri: (
|
||||||
|
object(),
|
||||||
|
{
|
||||||
|
"uri": uri,
|
||||||
|
"actual_center_frequency_hz": 435_000_000,
|
||||||
|
"actual_sample_rate_hz": 2_400_000,
|
||||||
|
"actual_gain_db": -30.0,
|
||||||
|
"actual_rf_bandwidth_hz": 200_000,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
comparison,
|
||||||
|
"build_composite_waveform",
|
||||||
|
lambda _sample_rate: (
|
||||||
|
np.asarray([0.1 + 0.1j], dtype=np.complex64),
|
||||||
|
{"total_duration_seconds": 1 / 2_400_000.0},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def forbidden_transmit(*_arguments: object) -> float:
|
||||||
|
nonlocal transmit_calls
|
||||||
|
transmit_calls += 1
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
pluto_hardware,
|
||||||
|
"transmit_noncyclic_buffer_once",
|
||||||
|
forbidden_transmit,
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match="до TX; Pluto TX не включён"):
|
||||||
|
comparison.run_one_zero_if_comparison(tmp_path, tmp_path / "processed")
|
||||||
|
|
||||||
|
assert transmit_calls == 0
|
||||||
Reference in New Issue
Block a user