May 2025
This commit is contained in:
@@ -16,11 +16,12 @@
|
||||
"rotate": 0,
|
||||
"roi": null,
|
||||
"image_background": null,
|
||||
"source_type": "epics",
|
||||
"source_type": "bsread",
|
||||
"name": "S10DI01-DSCR020",
|
||||
"source": "S10DI01-DSCR020",
|
||||
"group": [
|
||||
"Electrons"
|
||||
],
|
||||
"alias": []
|
||||
"alias": [],
|
||||
"forwarder_port": 9016
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
533,
|
||||
592,
|
||||
535,
|
||||
594
|
||||
642,
|
||||
497,
|
||||
644,
|
||||
499
|
||||
],
|
||||
"reference_marker_width": 10.256410256410257,
|
||||
"reference_marker_height": 10.256410256410257,
|
||||
"reference_marker_width": 16.256,
|
||||
"reference_marker_height": 16.256,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
"mirror_x": false,
|
||||
"mirror_y": false,
|
||||
"mirror_y": true,
|
||||
"rotate": 0,
|
||||
"roi": null,
|
||||
"image_background": null,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
"mirror_x": false,
|
||||
"mirror_x": true,
|
||||
"mirror_y": true,
|
||||
"rotate": 3,
|
||||
"roi": null,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
1068,
|
||||
1017,
|
||||
1070,
|
||||
1019
|
||||
1492,
|
||||
705,
|
||||
1494,
|
||||
707
|
||||
],
|
||||
"reference_marker_width": 19.333333333333332,
|
||||
"reference_marker_height": 22.4,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
485,
|
||||
261,
|
||||
1075,
|
||||
971
|
||||
600,
|
||||
343,
|
||||
999,
|
||||
745
|
||||
],
|
||||
"reference_marker_width": 1200.0,
|
||||
"reference_marker_height": 1000.0,
|
||||
"reference_marker_width": 200.0,
|
||||
"reference_marker_height": 200.0,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
"mirror_x": false,
|
||||
"mirror_y": false,
|
||||
"rotate": 0,
|
||||
"roi": null,
|
||||
"image_background": null,
|
||||
"source_type": "bsread",
|
||||
"name": "SATES21-CAMS154-M1",
|
||||
"prefix": "SATES21-CAMS154-M1",
|
||||
@@ -27,5 +29,6 @@
|
||||
"Photonics",
|
||||
"Maloja"
|
||||
],
|
||||
"alias": []
|
||||
"alias": [],
|
||||
"no_client_timeout": 0
|
||||
}
|
||||
28
configuration/camera_config/SATES30-CAMS182-GIGE6.json
Normal file
28
configuration/camera_config/SATES30-CAMS182-GIGE6.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
100,
|
||||
100,
|
||||
113,
|
||||
113
|
||||
],
|
||||
"reference_marker_width": 500.0,
|
||||
"reference_marker_height": 500.0,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
"mirror_x": true,
|
||||
"mirror_y": false,
|
||||
"rotate": 0,
|
||||
"roi": null,
|
||||
"image_background": null,
|
||||
"source_type": "bsread",
|
||||
"protocol": "tcp",
|
||||
"source": "SATES30-CAMS182-GIGE6",
|
||||
"name": "SATES30-CAMS182-GIGE6",
|
||||
"prefix": "SATES30-CAMS182-GIGE6",
|
||||
"group": [
|
||||
"Photonics",
|
||||
"Furka"
|
||||
]
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
42,
|
||||
37,
|
||||
50,
|
||||
44
|
||||
98,
|
||||
85,
|
||||
109,
|
||||
96
|
||||
],
|
||||
"reference_marker_width": 8.0,
|
||||
"reference_marker_height": 7.0,
|
||||
"reference_marker_width": 58.0,
|
||||
"reference_marker_height": 58.4,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
540,
|
||||
373,
|
||||
554,
|
||||
382
|
||||
662,
|
||||
449,
|
||||
759,
|
||||
548
|
||||
],
|
||||
"reference_marker_width": 104.0,
|
||||
"reference_marker_height": 108.0,
|
||||
"reference_marker_width": 514.0,
|
||||
"reference_marker_height": 525.0,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"camera_calibration": {
|
||||
"reference_marker": [
|
||||
364,
|
||||
250,
|
||||
468,
|
||||
358
|
||||
72,
|
||||
49,
|
||||
83,
|
||||
59
|
||||
],
|
||||
"reference_marker_width": 104.0,
|
||||
"reference_marker_height": 108.0,
|
||||
"reference_marker_width": 58.0,
|
||||
"reference_marker_height": 53.0,
|
||||
"angle_horizontal": 0.0,
|
||||
"angle_vertical": 0.0
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"#SATES21-ADTEST1-CAM5": "SATES21-ADTEST1-CAM5",
|
||||
"#SINBC02-DSRM310": "SINBC02-DSRM310",
|
||||
"S10BD01-DSCR030": "S10BD01-DSCR030",
|
||||
"S10DI01-DSCR020": "S10DI01-DSCR020",
|
||||
"SARCL01-DSCR170": "SARCL01-DSCR170",
|
||||
"SARES11-SPEC125-M1": "SARES11-SPEC125-M1",
|
||||
"SARES11-SPEC125-M2": "SARES11-SPEC125-M2",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"SATBD01-DSCR120",
|
||||
"SARBD01-DSCR110",
|
||||
"S10BD01-DSCR030",
|
||||
"S10DI01-DSCR020",
|
||||
"SATBD02-DSCR050",
|
||||
"SARCL01-DSCR170",
|
||||
"SARCL02-DSCR280"
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"camera_name": "S10BC02-DSRM310",
|
||||
"name": "S10BC02-DSRM310_sp"
|
||||
"name": "S10BC02-DSRM310_sp",
|
||||
"max_frame_rate": 10.1
|
||||
}
|
||||
@@ -6,5 +6,6 @@
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"camera_name": "S10DI01-DSCR020",
|
||||
"name": "S10DI01-DSCR020_sp"
|
||||
"name": "S10DI01-DSCR020_sp",
|
||||
"max_frame_rate": 10.1
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"image_background_enable": false,
|
||||
"image_background": null,
|
||||
"image_background_enable": true,
|
||||
"image_background": "SARBD02-DSCR050_20250305_182528_541069",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": [
|
||||
1213,
|
||||
329,
|
||||
576,
|
||||
812
|
||||
1171,
|
||||
448,
|
||||
461,
|
||||
1364
|
||||
],
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"camera_calibration": null,
|
||||
"image_background_enable": false,
|
||||
"image_background": null,
|
||||
"image_background": "SARBD02-DSCR051_20250306_161408_842429",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"pipeline_type": "processing",
|
||||
"camera_name": "SARBD02-DSCR051",
|
||||
"name": "SARBD02-DSCR051_sp",
|
||||
"max_frame_rate": 5.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"image_background_enable": "passive",
|
||||
"image_background": "SARES11-SPEC125-M1_20250315_152506_682314",
|
||||
"image_background": "SARES11-SPEC125-M1_20250501_183259_735224",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
"mode": "PUSH",
|
||||
"allow_type_changes": false,
|
||||
"roi_signal": [
|
||||
1000,
|
||||
1200,
|
||||
1400,
|
||||
848,
|
||||
1448
|
||||
1100,
|
||||
1700
|
||||
],
|
||||
"roi_background": [
|
||||
0,
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
"down": "SARES21-PBPS141:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SARES21-PBPS141:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SARES21-PBPS141:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 4.0268387189885095e-05,
|
||||
"down_calib": 3.837274982195044e-05,
|
||||
"left_calib": 0.00010659908000729991,
|
||||
"right_calib": 5.903547370772529e-05,
|
||||
"up_calib": 9.086696828684651e-06,
|
||||
"down_calib": 8.479198152755808e-06,
|
||||
"left_calib": 2.402225113860666e-05,
|
||||
"right_calib": 1.253692752001019e-05,
|
||||
"horiz_calib": -5.93887,
|
||||
"vert_calib": -9.0057,
|
||||
"uJ_calib": 941.943984588351,
|
||||
@@ -94,5 +94,5 @@
|
||||
0.11052246554408188,
|
||||
0.11072063526778356
|
||||
],
|
||||
"calib_datetime": "2025-04-04 15:05:51"
|
||||
"calib_datetime": "2025-05-06 11:19:16"
|
||||
}
|
||||
@@ -26,12 +26,12 @@
|
||||
"down": "SARFE10-PBPS053:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SARFE10-PBPS053:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SARFE10-PBPS053:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 8.252737102787511e-05,
|
||||
"down_calib": 9.932451384623452e-05,
|
||||
"left_calib": 0.0002898544003376224,
|
||||
"right_calib": 0.0001714541229915864,
|
||||
"horiz_calib": -3.6052981040446994,
|
||||
"vert_calib": -5.712227095363798,
|
||||
"up_calib": 5.3603874230730805e-05,
|
||||
"down_calib": 6.429273872665403e-05,
|
||||
"left_calib": 0.0001873753953620842,
|
||||
"right_calib": 0.00011135083709105292,
|
||||
"horiz_calib": -3.5966302878741434,
|
||||
"vert_calib": -5.704870102644,
|
||||
"uJ_calib": 834.5191797495979,
|
||||
"threshold": 0,
|
||||
"queue_length": 5000,
|
||||
@@ -69,9 +69,9 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.08353620653149268,
|
||||
0.0003093021467825846,
|
||||
-0.08288553799134554
|
||||
0.08373324791431114,
|
||||
0.0002666207178174507,
|
||||
-0.08308957010589782
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -79,20 +79,20 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.05297838244709519,
|
||||
0.00013686051846039786,
|
||||
-0.052059458308041553
|
||||
0.05334340044159048,
|
||||
6.423190047678002e-05,
|
||||
-0.051829896970023125
|
||||
],
|
||||
"calib_time": "2022-11-28 16:19:37",
|
||||
"calib_datetime": "2025-04-03 16:25:15",
|
||||
"calib_datetime": "2025-05-12 19:38:08",
|
||||
"calib_x_norm_std": [
|
||||
0.039097499054084266,
|
||||
0.04318884492921968,
|
||||
0.041594738954934915
|
||||
0.03694393985351428,
|
||||
0.036381119656154114,
|
||||
0.037504981101666966
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.047561029795043466,
|
||||
0.04584223560113521,
|
||||
0.04414664834114283
|
||||
0.032515850998287014,
|
||||
0.031406268858134787,
|
||||
0.03357316145483791
|
||||
]
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"pipeline_type": "processing",
|
||||
"camera_name": "SARFE10-PSSS059",
|
||||
"name": "SARFE10-PSSS059_psss",
|
||||
"function": "swissfel_spectral_processing.py",
|
||||
"function": "swissfel_spectral_processing_fast.py",
|
||||
"mode": "PUSH",
|
||||
"allow_type_changes": false,
|
||||
"no_client_timeout": 0,
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
"down": "SAROP11-PBPS110:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SAROP11-PBPS110:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SAROP11-PBPS110:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 4.098127129673725e-06,
|
||||
"down_calib": 4.259138962245459e-06,
|
||||
"left_calib": 2.183005012581182e-06,
|
||||
"right_calib": 2.4378049645254522e-06,
|
||||
"horiz_calib": -4.665452678775223,
|
||||
"vert_calib": -4.471600564729387,
|
||||
"up_calib": 1.778951980962652e-05,
|
||||
"down_calib": 1.647636031137421e-05,
|
||||
"left_calib": 1.343967521143297e-05,
|
||||
"right_calib": 1.4712267477026206e-05,
|
||||
"horiz_calib": -4.084489404678124,
|
||||
"vert_calib": -4.152037498266164,
|
||||
"uJ_calib": 605.4608924473305,
|
||||
"threshold": 0,
|
||||
"queue_length": 1000,
|
||||
@@ -69,9 +69,9 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.06458675818610864,
|
||||
0.00033689669329196073,
|
||||
-0.06401812569356503
|
||||
0.07355089424549768,
|
||||
0.0005918260320667978,
|
||||
-0.07334629180492924
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -79,19 +79,19 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.06705606264028884,
|
||||
-0.00046031410996389923,
|
||||
-0.0671240796408925
|
||||
0.07059159363843578,
|
||||
-0.0010492828771324209,
|
||||
-0.07391577178168675
|
||||
],
|
||||
"calib_datetime": "2025-03-13 13:56:21",
|
||||
"calib_datetime": "2025-05-08 19:40:32",
|
||||
"calib_x_norm_std": [
|
||||
0.09075244320195952,
|
||||
0.0877275386080403,
|
||||
0.0905045199152049
|
||||
0.03951572779577543,
|
||||
0.036895048152752644,
|
||||
0.04082834764914548
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.09006310930261463,
|
||||
0.09317196133148388,
|
||||
0.09861810436291076
|
||||
0.042522854070151855,
|
||||
0.04157478982211735,
|
||||
0.03874863852211236
|
||||
]
|
||||
}
|
||||
@@ -27,12 +27,12 @@
|
||||
"down": "SAROP11-PBPS122:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SAROP11-PBPS122:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SAROP11-PBPS122:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 1.893276460318213e-05,
|
||||
"down_calib": 2.3306024887105614e-05,
|
||||
"left_calib": 8.257188295270447e-06,
|
||||
"right_calib": 8.277311386229812e-06,
|
||||
"horiz_calib": -5.297540191258623,
|
||||
"vert_calib": -6.29549683664401,
|
||||
"up_calib": 3.136666045188568e-05,
|
||||
"down_calib": 4.287710153537755e-05,
|
||||
"left_calib": 1.9240676699217273e-05,
|
||||
"right_calib": 1.9033978392323185e-05,
|
||||
"horiz_calib": -4.800851116441316,
|
||||
"vert_calib": -4.325389727023896,
|
||||
"uJ_calib": 605.9512700123181,
|
||||
"threshold": 0,
|
||||
"queue_length": 1000,
|
||||
@@ -70,14 +70,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.056699918319259426,
|
||||
-6.414005929787459e-05,
|
||||
-0.05656019455162533
|
||||
0.06260165947402832,
|
||||
0.0005469889807531498,
|
||||
-0.06237617996473284
|
||||
],
|
||||
"calib_x_norm_std": [
|
||||
0.09941735065928761,
|
||||
0.09644142804120188,
|
||||
0.09652404146483615
|
||||
0.037489193261730905,
|
||||
0.04049565430616364,
|
||||
0.036369883937793064
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -85,14 +85,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.04720895487460161,
|
||||
7.316327567623546e-05,
|
||||
-0.04809726408934068
|
||||
0.0680948696951371,
|
||||
-0.001074835754827735,
|
||||
-0.07062095428052871
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.09985294158981244,
|
||||
0.10707615783473319,
|
||||
0.09659571295757036
|
||||
0.036781724002055614,
|
||||
0.03612254480714764,
|
||||
0.039495450086968996
|
||||
],
|
||||
"calib_datetime": "2025-03-13 14:11:39"
|
||||
"calib_datetime": "2025-05-08 19:20:54"
|
||||
}
|
||||
@@ -29,9 +29,9 @@
|
||||
"reload": true,
|
||||
"dark_buffer_length": 3,
|
||||
"calibration": [
|
||||
-7.09793884e-19,
|
||||
-2.19408437e-16,
|
||||
1.2869905e-12
|
||||
-9.73024084e-19,
|
||||
3.28988958e-16,
|
||||
1.0206364e-12
|
||||
],
|
||||
"roi": [
|
||||
600,
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
"check_timestamp": true,
|
||||
"stream_timeout": 20,
|
||||
"queue_length": 5000,
|
||||
"down_calib": 3.4441678486821112e-06,
|
||||
"down_calib": 1.3438944081736304e-05,
|
||||
"xpos_odd_w_pvname": "SAROP21-PBPS103:XPOS-ODD-HIST-W",
|
||||
"ypos_all_y_pvname": "SAROP21-PBPS103:YPOS-ALL-HIST-Y",
|
||||
"ypos_all_w_pvname": "SAROP21-PBPS103:YPOS-ALL-HIST-W",
|
||||
"name": "SAROP21-PBPS103_proc",
|
||||
"vert_calib": -7.857205929014205,
|
||||
"vert_calib": -3.9358348895956135,
|
||||
"bsread_address": "",
|
||||
"right": "SAROP21-PBPS103:Lnk9Ch0-PP_VAL_PD3",
|
||||
"ypos_dif_w_pvname": "SAROP21-PBPS103:YPOS-DIF-HIST-W",
|
||||
"ypos_odd_x_pvname": "SAROP21-PBPS103:YPOS-ODD-HIST-X",
|
||||
"function": "pbps_full",
|
||||
"port": "9009",
|
||||
"left_calib": 7.724151636342986e-06,
|
||||
"left_calib": 8.747777364727171e-06,
|
||||
"down": "SAROP21-PBPS103:Lnk9Ch0-PP_VAL_PD2",
|
||||
"ypos_odd_w_pvname": "SAROP21-PBPS103:YPOS-ODD-HIST-W",
|
||||
"xpos_odd_y_pvname": "SAROP21-PBPS103:XPOS-ODD-HIST-Y",
|
||||
@@ -32,7 +32,7 @@
|
||||
"ypos_evn_x_pvname": "SAROP21-PBPS103:YPOS-EVN-HIST-X",
|
||||
"uJ_calib": 605.9512700123181,
|
||||
"xpos_evn_m_pvname": "SAROP21-PBPS103:XPOS-EVN-HIST-M",
|
||||
"horiz_calib": -5.034588377303698,
|
||||
"horiz_calib": -4.106805000082229,
|
||||
"ypos_all_m_pvname": "SAROP21-PBPS103:YPOS-ALL-HIST-M",
|
||||
"ypos_dif_m_pvname": "SAROP21-PBPS103:YPOS-DIF-HIST-M",
|
||||
"bsread_channels": [
|
||||
@@ -45,7 +45,7 @@
|
||||
"ypos_evn_w_pvname": "SAROP21-PBPS103:YPOS-EVN-HIST-W",
|
||||
"pipeline_type": "stream",
|
||||
"ypos_all_x_pvname": "SAROP21-PBPS103:YPOS-ALL-HIST-X",
|
||||
"right_calib": 8.358613122862118e-06,
|
||||
"right_calib": 9.684568190671639e-06,
|
||||
"xpos_all_m_pvname": "SAROP21-PBPS103:XPOS-ALL-HIST-M",
|
||||
"xpos_odd_m_pvname": "SAROP21-PBPS103:XPOS-ODD-HIST-M",
|
||||
"left": "SAROP21-PBPS103:Lnk9Ch0-PP_VAL_PD0",
|
||||
@@ -58,7 +58,7 @@
|
||||
"ypos_evn_y_pvname": "SAROP21-PBPS103:YPOS-EVN-HIST-Y",
|
||||
"xpos_odd_x_pvname": "SAROP21-PBPS103:XPOS-ODD-HIST-X",
|
||||
"threshold": 0,
|
||||
"up_calib": 3.381429158599253e-06,
|
||||
"up_calib": 1.2578887233395516e-05,
|
||||
"ypos_odd_m_pvname": "SAROP21-PBPS103:YPOS-ODD-HIST-M",
|
||||
"xpos_all_x_pvname": "SAROP21-PBPS103:XPOS-ALL-HIST-X",
|
||||
"up": "SAROP21-PBPS103:Lnk9Ch0-PP_VAL_PD1",
|
||||
@@ -69,9 +69,9 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.06233292421608874,
|
||||
0.002018002684269913,
|
||||
-0.05684265778478445
|
||||
0.07264113800909158,
|
||||
-0.00027682928694833323,
|
||||
-0.07345783673842782
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -79,19 +79,19 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.03833798078739985,
|
||||
0.0010236985633388389,
|
||||
-0.03802504258511831
|
||||
0.07681455660145628,
|
||||
-0.0005021565266583652,
|
||||
-0.07563086268838766
|
||||
],
|
||||
"calib_x_norm_std": [
|
||||
0.6418256445167525,
|
||||
0.6759359880444116,
|
||||
0.6554307724365318
|
||||
0.3239146627568919,
|
||||
0.3360879764341496,
|
||||
0.31769366304131247
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.6584007080383298,
|
||||
0.6436547013306737,
|
||||
0.6454721642147889
|
||||
0.3375259185485036,
|
||||
0.3494180218450826,
|
||||
0.34646009364333663
|
||||
],
|
||||
"calib_datetime": "2025-04-04 10:40:33"
|
||||
"calib_datetime": "2025-05-12 18:46:13"
|
||||
}
|
||||
@@ -27,12 +27,12 @@
|
||||
"down": "SAROP21-PBPS133:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SAROP21-PBPS133:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SAROP21-PBPS133:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 5.349312228228193e-05,
|
||||
"down_calib": 5.145953654306361e-05,
|
||||
"left_calib": 3.964746111932078e-05,
|
||||
"right_calib": 3.9392026612622904e-05,
|
||||
"horiz_calib": -4.027132099327991,
|
||||
"vert_calib": -4.3256874948249155,
|
||||
"up_calib": 1.1994417318403323e-05,
|
||||
"down_calib": 1.1777156969811e-05,
|
||||
"left_calib": 8.546152470880694e-06,
|
||||
"right_calib": 8.292371780859814e-06,
|
||||
"horiz_calib": -4.030808070907288,
|
||||
"vert_calib": -3.9995027435812665,
|
||||
"uJ_calib": 605.4608924473305,
|
||||
"threshold": 0,
|
||||
"queue_length": 3000,
|
||||
@@ -70,14 +70,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.07523729980148029,
|
||||
0.00020716758487356637,
|
||||
-0.07375210139052979
|
||||
0.07558987766893042,
|
||||
0.00010780904235330975,
|
||||
-0.07326364982362192
|
||||
],
|
||||
"calib_x_norm_std": [
|
||||
0.3755149062751643,
|
||||
0.3786561572290592,
|
||||
0.3748798320928806
|
||||
0.37640119241355796,
|
||||
0.3766165188476263,
|
||||
0.38834395117940335
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -85,14 +85,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.0699176899290634,
|
||||
-0.00030959523730942853,
|
||||
-0.06878858525096673
|
||||
0.07489741542673554,
|
||||
0.0007133487847056664,
|
||||
-0.07512123400735467
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.37846861570249735,
|
||||
0.38072721857616276,
|
||||
0.3832545225535354
|
||||
0.4039920352608262,
|
||||
0.4026890943163395,
|
||||
0.3902031448932646
|
||||
],
|
||||
"calib_datetime": "2025-04-04 10:39:32"
|
||||
"calib_datetime": "2025-05-10 10:06:36"
|
||||
}
|
||||
@@ -26,12 +26,12 @@
|
||||
"down": "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SAROP31-PBPS113:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 5.059538606264929e-07,
|
||||
"down_calib": 5.64927448333758e-07,
|
||||
"left_calib": 1.125846743706708e-06,
|
||||
"right_calib": 1.3457517438143435e-06,
|
||||
"horiz_calib": -4.719752799047021,
|
||||
"vert_calib": -7.115673207163331,
|
||||
"up_calib": 3.861793515770638e-05,
|
||||
"down_calib": 4.4900118787754264e-05,
|
||||
"left_calib": 9.126519109105711e-05,
|
||||
"right_calib": 0.00011276977914264295,
|
||||
"horiz_calib": -3.8084771908604007,
|
||||
"vert_calib": -6.247648389472207,
|
||||
"uJ_calib": 941.943984588351,
|
||||
"threshold": 0,
|
||||
"queue_length": 300,
|
||||
@@ -70,14 +70,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.06422228966212074,
|
||||
-0.0003177089811439902,
|
||||
-0.06290301234970237
|
||||
0.0786096188018742,
|
||||
0.00035821990918893194,
|
||||
-0.0789336642299587
|
||||
],
|
||||
"calib_x_norm_std": [
|
||||
0.05497993675328227,
|
||||
0.05722297512373116,
|
||||
0.05244845040249846
|
||||
0.040490407392167534,
|
||||
0.04028139405139821,
|
||||
0.03862030068928889
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -85,14 +85,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.04291975949563341,
|
||||
-0.0002750343024646076,
|
||||
-0.04140114487023621
|
||||
0.04775193765978428,
|
||||
-0.00032249451531026196,
|
||||
-0.04828419667374328
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.05799243003721293,
|
||||
0.05228267176725063,
|
||||
0.057094675167291845
|
||||
0.0376808182312105,
|
||||
0.0399368891843527,
|
||||
0.037962528852795725
|
||||
],
|
||||
"calib_datetime": "2025-04-03 19:26:20"
|
||||
"calib_datetime": "2025-05-12 19:40:38"
|
||||
}
|
||||
@@ -27,12 +27,12 @@
|
||||
"down": "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD2",
|
||||
"right": "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD3",
|
||||
"left": "SAROP31-PBPS149:Lnk9Ch0-PP_VAL_PD0",
|
||||
"up_calib": 5.520345954869785e-07,
|
||||
"down_calib": 5.619057169946393e-07,
|
||||
"left_calib": 1.0781825161854172e-06,
|
||||
"right_calib": 1.7591006509263466e-06,
|
||||
"horiz_calib": -2.951379555975132,
|
||||
"vert_calib": -5.5751155038433415,
|
||||
"up_calib": 8.923922065175471e-06,
|
||||
"down_calib": 9.805425067137745e-06,
|
||||
"left_calib": 5.870948933687726e-06,
|
||||
"right_calib": 8.378280574406873e-06,
|
||||
"horiz_calib": -3.775717899566187,
|
||||
"vert_calib": -3.8593992845314324,
|
||||
"uJ_calib": 605.9512700123181,
|
||||
"threshold": 0.0,
|
||||
"queue_length": 300,
|
||||
@@ -71,14 +71,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_x_norm": [
|
||||
0.11031392780555577,
|
||||
0.000928620923623025,
|
||||
-0.09298083270238598
|
||||
0.08010117214752004,
|
||||
0.00011095255532506727,
|
||||
-0.07880900492607362
|
||||
],
|
||||
"calib_x_norm_std": [
|
||||
0.06272526898974226,
|
||||
0.06648517579759342,
|
||||
0.05664085326165932
|
||||
0.03546822052236209,
|
||||
0.03566075428198375,
|
||||
0.038689695811515164
|
||||
],
|
||||
"calib_y_range": [
|
||||
-0.3,
|
||||
@@ -86,14 +86,14 @@
|
||||
0.3
|
||||
],
|
||||
"calib_y_norm": [
|
||||
0.053727058023198666,
|
||||
-3.663064961326165e-05,
|
||||
-0.053894030649560734
|
||||
0.07814310330557633,
|
||||
-0.0003988992296753892,
|
||||
-0.07732150550150274
|
||||
],
|
||||
"calib_y_norm_std": [
|
||||
0.061694021446861605,
|
||||
0.06711504500830567,
|
||||
0.06812822215629918
|
||||
0.07331681331314215,
|
||||
0.03660437215717908,
|
||||
0.036695466427208896
|
||||
],
|
||||
"calib_datetime": "2025-04-03 19:27:23"
|
||||
"calib_datetime": "2025-05-12 19:42:03"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"image_background_enable": "passive",
|
||||
"image_background": "SATES21-CAMS-PATT1_20250401_153642_380292",
|
||||
"image_background": "SATES21-CAMS-PATT1_20250511_094953_959660",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
@@ -20,16 +20,16 @@
|
||||
"project_axis": 0,
|
||||
"reload": true,
|
||||
"roi_background": [
|
||||
106,
|
||||
935,
|
||||
0,
|
||||
2435
|
||||
9,
|
||||
444,
|
||||
10,
|
||||
2501
|
||||
],
|
||||
"roi_signal": [
|
||||
106,
|
||||
935,
|
||||
0,
|
||||
2435
|
||||
9,
|
||||
444,
|
||||
10,
|
||||
2501
|
||||
],
|
||||
"enforce_pid": true,
|
||||
"enforce_timestamp": true,
|
||||
|
||||
15
configuration/pipeline_config/SATES21-CAMS154-M1_proc.json
Normal file
15
configuration/pipeline_config/SATES21-CAMS154-M1_proc.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"image_background_enable": true,
|
||||
"image_background": "SATES21-CAMS154-M1_20250430_112650_821925",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"mode": "PUSH",
|
||||
"pipeline_type": "processing",
|
||||
"function": "maloja_spectrometers.py",
|
||||
"camera_name": "SATES21-CAMS154-M1",
|
||||
"name": "SATES21-CAMS154-M1_proc",
|
||||
"reload": true,
|
||||
"block": false
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"image_background_enable": "passive",
|
||||
"image_background": "SATES21-CAMS154-M1_20250218_150832_735370",
|
||||
"image_background": "SATES21-CAMS154-M1_20250430_112650_821925",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"pipeline_type": "processing",
|
||||
"function": "spectrometer.py",
|
||||
"function": "maloja_spectrometer.py",
|
||||
"camera_name": "SATES21-CAMS154-M1",
|
||||
"name": "SATES21-CAMS154-M1_spec_db",
|
||||
"mode": "PUSH",
|
||||
@@ -20,15 +20,15 @@
|
||||
"threshold": 10,
|
||||
"project_axis": 0,
|
||||
"roi_signal": [
|
||||
2,
|
||||
594,
|
||||
5,
|
||||
1412
|
||||
1,
|
||||
847,
|
||||
1,
|
||||
1635
|
||||
],
|
||||
"roi_background": [
|
||||
2,
|
||||
594,
|
||||
5,
|
||||
1412
|
||||
1,
|
||||
847,
|
||||
1,
|
||||
1635
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "SATES30-CAMS182-GIGE6_profiles",
|
||||
"image_background_enable": false,
|
||||
"image_background": null,
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"pipeline_type": "processing",
|
||||
"camera_name": "SATES30-CAMS182-GIGE6",
|
||||
"function": "profiles",
|
||||
"mode": "PUSH",
|
||||
"allow_type_changes": false,
|
||||
"block": false
|
||||
}
|
||||
12
configuration/pipeline_config/SATES30-CAMS182-GIGE6_sp.json
Normal file
12
configuration/pipeline_config/SATES30-CAMS182-GIGE6_sp.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"image_background_enable": false,
|
||||
"image_background": null,
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"pipeline_type": "processing",
|
||||
"camera_name": "SATES30-CAMS182-GIGE6",
|
||||
"name": "SATES30-CAMS182-GIGE6_sp",
|
||||
"max_frame_rate": 5.1
|
||||
}
|
||||
11
configuration/pipeline_config/SATES30-CAMS182-GIGE_sp.json
Normal file
11
configuration/pipeline_config/SATES30-CAMS182-GIGE_sp.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"image_background_enable": false,
|
||||
"image_background": null,
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
"image_slices": null,
|
||||
"pipeline_type": "processing",
|
||||
"camera_name": "SATES30-CAMS182-GIGE",
|
||||
"name": "SATES30-CAMS182-GIGE_sp"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"image_background_enable": false,
|
||||
"image_background": "SATES31-CAMS187-RIXS1_20250222_100737_996974",
|
||||
"image_background_enable": true,
|
||||
"image_background": "SATES31-CAMS187-RIXS1_20250513_091423_890325",
|
||||
"image_threshold": null,
|
||||
"image_region_of_interest": null,
|
||||
"image_good_region": null,
|
||||
@@ -9,5 +9,6 @@
|
||||
"camera_name": "SATES31-CAMS187-RIXS1",
|
||||
"name": "SATES31-CAMS187-RIXS1_sp",
|
||||
"max_frame_rate": 5.1,
|
||||
"reload": true
|
||||
"reload": true,
|
||||
"_function": "Bernina_mid_IR_CEP_analysis.py"
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"#Bernina_tt_kb_restart_cam": "Bernina_tt_kb_restart_cam",
|
||||
"#S10BC02-DSRM310_profiles": "S10BC02-DSRM310_profiles",
|
||||
"#SARES11-SPEC125-M1_psen_db": "SARES11-SPEC125-M1_psen_db",
|
||||
"#SARES11-SPEC125-M1_test": "SARES11-SPEC125-M1_test",
|
||||
"#SARES11-SPEC125-M3_sp": "SARES11-SPEC125-M3_sp",
|
||||
"#SARES11-SPEC125-M3_spec_db": "SARES11-SPEC125-M3_spec_db",
|
||||
"#SARES11-XMI125-C4P1_db": "SARES11-XMI125-C4P1_db",
|
||||
"#SARES11-XMI125-C4P1_xy_db": "SARES11-XMI125-C4P1_xy_db",
|
||||
"#SARES12-CAMS128-M1_psen_db": "SARES12-CAMS128-M1_psen_db",
|
||||
@@ -65,8 +65,8 @@
|
||||
"SARBD02-DSCR051_sp": "SARBD02-DSCR051_sp",
|
||||
"SARBD02-DSCR05x_merge": "SARBD02-DSCR05x_merge",
|
||||
"SARCL01-DSCR170_profiles": "SARCL01-DSCR170_profiles",
|
||||
"SARES11-SPEC125-M1_psen_db": "SARES11-SPEC125-M1_psen_db",
|
||||
"SARES11-SPEC125-M2_db": "SARES11-SPEC125-M2_db",
|
||||
"SARES11-SPEC125-M3_spec_db": "SARES11-SPEC125-M3_spec_db",
|
||||
"SARES20-CAMS142-M3_proc": "SARES20-CAMS142-M3_proc",
|
||||
"SARES20-CAMS142-M4_psen_db": "SARES20-CAMS142-M4_psen_db",
|
||||
"SARES20-CAMS142-M5_psen_db": "SARES20-CAMS142-M5_psen_db",
|
||||
@@ -99,6 +99,7 @@
|
||||
"SATBD02-DSCR050_sp1": "SATBD02-DSCR050_sp_rep",
|
||||
"SATES21-CAMS-PATT1_spec_db": "SATES21-CAMS-PATT1_spec_db",
|
||||
"SATES21-CAMS154-GIGE9_proc": "SATES21-CAMS154-GIGE9_proc",
|
||||
"SATES21-CAMS154-M1_proc": "SATES21-CAMS154-M1_proc",
|
||||
"SATES21-CAMS154-M1_spec_db": "SATES21-CAMS154-M1_spec_db",
|
||||
"SATES21-CAMS154-M2_proc": "SATES21-CAMS154-M2_proc",
|
||||
"SATES22-ADTEST1-CAM10_proc": "SATES22-ADTEST1-CAM10_proc",
|
||||
@@ -115,6 +116,7 @@
|
||||
"SATES22-ADTEST1-CAM9_proc": "SATES22-ADTEST1-CAM9_proc",
|
||||
"SATES24-CAMS161-M1_spec_db": "SATES24-CAMS161-M1_spec_db",
|
||||
"SATES30-CAMS182-GIGE1_profiles": "SATES30-CAMS182-GIGE1_profiles",
|
||||
"SATES30-CAMS182-GIGE6_profiles": "SATES30-CAMS182-GIGE6_profiles",
|
||||
"SATES30-RIXS-CAM01_fit": "SATES30-RIXS-CAM01_fit",
|
||||
"SATES30-RIXS-CAM01_proc": "SATES30-RIXS-CAM01_proc",
|
||||
"SATES30-RIXS-CAM01_repeater": "SATES30-RIXS-CAM01_repeater",
|
||||
|
||||
@@ -96,7 +96,8 @@
|
||||
"SLG-LCAM-C071",
|
||||
"SARBD01-DSCR050",
|
||||
"SARBD02-DSCR050",
|
||||
"SARBD02-DSCR051"
|
||||
"SARBD02-DSCR051",
|
||||
"S10DI01-DSCR020"
|
||||
],
|
||||
"enabled": true,
|
||||
"expanding": false,
|
||||
@@ -136,7 +137,7 @@
|
||||
"instances": [
|
||||
"SARFE10-PSSS059_psss:8889",
|
||||
"SARFE10-PSSS059_sp",
|
||||
"SARFE10-PSSS059_psss_avg:9005",
|
||||
"#SARFE10-PSSS059_psss_avg:9005",
|
||||
"SARFE10-PSSS059_store:8890",
|
||||
"SARFE10-PSSS059-LB_psss:9004"
|
||||
]
|
||||
@@ -178,7 +179,8 @@
|
||||
"#SATES21-CAMS154-GIGE8_proc:9058",
|
||||
"#SATES21-CAMS154-GIGE9_proc",
|
||||
"SATES21-CAMS154-GIGE10_sp",
|
||||
"SATES21-CAMS154-GIGE11_sp"
|
||||
"SATES21-CAMS154-GIGE11_sp",
|
||||
"SATES21-CAMS154-M1_proc"
|
||||
]
|
||||
},
|
||||
"http://sf-daqsync-13.psi.ch:8881": {
|
||||
@@ -198,7 +200,7 @@
|
||||
"expanding": false,
|
||||
"instances": [
|
||||
"#SAROP11-PBPS122_proc:9010",
|
||||
"#SARES11-SPEC125-M1_psen_db:9001",
|
||||
"SARES11-SPEC125-M1_psen_db:9001",
|
||||
"#SARES11-SPEC125-M1_test:9009",
|
||||
"#SARES11-SPEC125-M2_psen_db:9011",
|
||||
"#SARES12-CAMS128-M1_psen_db:9003",
|
||||
@@ -277,6 +279,7 @@
|
||||
"SATES30-CAMS182-GIGE3",
|
||||
"SATES30-CAMS182-GIGE4",
|
||||
"SATES30-CAMS182-GIGE5",
|
||||
"SATES30-CAMS182-GIGE6",
|
||||
"SATES30-RIXS-CAM01",
|
||||
"furka_jungfrau"
|
||||
],
|
||||
@@ -295,6 +298,7 @@
|
||||
"SATES30-CAMS182-GIGE2_sp",
|
||||
"SATES30-CAMS182-GIGE1_profiles:9002",
|
||||
"SATES30-CAMS182-GIGE2_profiles:9004",
|
||||
"SATES30-CAMS182-GIGE6_profiles:9008",
|
||||
"test_furka_proc:9020"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ def edge(filter_name, backgrounds, signals, peakback):
|
||||
sig_deriv -= peakback
|
||||
sig_deriv *= signal.tukey(2048) # just added Nov 20 2024
|
||||
#peak_pos = 1024 - (np.argmax(sig_deriv[500:1500], axis=-1) + 500)
|
||||
peak_pos = 800 - (np.argmax(sig_deriv[400:1600], axis=-1) + 400) # I am grossed out
|
||||
peak_pos = 1024 - (np.argmax(sig_deriv[400:1600], axis=-1) + 400) # I am grossed out
|
||||
peak_amp = np.amax(sig_deriv[400:1600], axis=-1)
|
||||
|
||||
return peak_pos, peak_amp, sig_deriv, sig_uninterp
|
||||
|
||||
@@ -25,6 +25,12 @@ base_pv_names = []
|
||||
all_pv_names = []
|
||||
global_ravg_length = 100
|
||||
ravg_buffers = {}
|
||||
# Configuration for rolling-average of statistics
|
||||
|
||||
# Configuration for N-shot average spectrum
|
||||
global_avg_length = 100
|
||||
avg_buffer = None
|
||||
avg_pv_names = []
|
||||
|
||||
@numba.njit(parallel=False)
|
||||
def get_spectrum(image, background):
|
||||
@@ -55,51 +61,66 @@ def update_PVs(buffer, *pv_names):
|
||||
|
||||
|
||||
def initialize(params):
|
||||
"""Initialize PV names, running-average settings, and launch update thread."""
|
||||
"""Initialize PV names, running-average settings, N-shot average, and launch update thread."""
|
||||
global channel_pv_names, base_pv_names, all_pv_names, global_ravg_length
|
||||
global global_avg_length, avg_buffer, avg_pv_names
|
||||
|
||||
camera = params["camera_name"]
|
||||
e_int = params["e_int_name"]
|
||||
e_axis = params["e_axis_name"]
|
||||
|
||||
# Fit/result PV names
|
||||
center_pv = f"{camera}:FIT-COM"
|
||||
fwhm_pv = f"{camera}:FIT-FWHM"
|
||||
fit_rms_pv = f"{camera}:FIT-RMS"
|
||||
fit_res_pv = f"{camera}:FIT-RES"
|
||||
center_pv = f"{camera}:FIT-COM"
|
||||
fwhm_pv = f"{camera}:FIT-FWHM"
|
||||
fit_rms_pv = f"{camera}:FIT-RMS"
|
||||
fit_res_pv = f"{camera}:FIT-RES"
|
||||
fit_spec_pv = f"{camera}:FIT-SPECTRUM_Y"
|
||||
|
||||
# ROI PVs for dynamic read
|
||||
ymin_pv = f"{camera}:SPC_ROI_YMIN"
|
||||
ymax_pv = f"{camera}:SPC_ROI_YMAX"
|
||||
axis_pv = e_axis
|
||||
ymin_pv = f"{camera}:SPC_ROI_YMIN"
|
||||
ymax_pv = f"{camera}:SPC_ROI_YMAX"
|
||||
axis_pv = e_axis
|
||||
channel_pv_names = [ymin_pv, ymax_pv, axis_pv]
|
||||
|
||||
# Spectrum statistical PV names
|
||||
com_pv = f"{camera}:SPECT-COM"
|
||||
std_pv = f"{camera}:SPECT-RMS"
|
||||
skew_pv = f"{camera}:SPECT-SKEW"
|
||||
iqr_pv = f"{camera}:SPECT-IQR"
|
||||
res_pv = f"{camera}:SPECT-RES" # will use IQR-based calc
|
||||
com_pv = f"{camera}:SPECT-COM"
|
||||
std_pv = f"{camera}:SPECT-RMS"
|
||||
skew_pv = f"{camera}:SPECT-SKEW"
|
||||
iqr_pv = f"{camera}:SPECT-IQR"
|
||||
res_pv = f"{camera}:SPECT-RES"
|
||||
|
||||
# Base PVs for update thread (order matters)
|
||||
base_pv_names = [
|
||||
e_int, center_pv, fwhm_pv, fit_rms_pv,
|
||||
fit_res_pv, com_pv, std_pv, skew_pv, iqr_pv, res_pv
|
||||
fit_res_pv, fit_spec_pv, com_pv, std_pv, skew_pv, iqr_pv, res_pv
|
||||
]
|
||||
|
||||
# Running-average configuration
|
||||
global_ravg_length = params.get('RAVG_length', global_ravg_length)
|
||||
# Build list of running-average PVs (exclude e_int, e_axis, processing_parameters)
|
||||
exclude = {
|
||||
e_int,
|
||||
e_axis,
|
||||
f"{camera}:processing_parameters"
|
||||
}
|
||||
exclude = {e_int, e_axis, f"{camera}:processing_parameters"}
|
||||
ravg_base = [pv for pv in base_pv_names if pv not in exclude]
|
||||
ravg_pv_names = [pv + '-RAVG' for pv in ravg_base]
|
||||
|
||||
# All PVs (original + running average)
|
||||
all_pv_names = base_pv_names + ravg_pv_names
|
||||
# N-shot average configuration
|
||||
global_avg_length = params.get('avg_nshots', global_avg_length)
|
||||
avg_buffer = deque(maxlen=global_avg_length)
|
||||
# Define PVs for N-shot average statistics and spectra
|
||||
avg_pv_names = [
|
||||
f"{camera}:AVG-FIT-COM",
|
||||
f"{camera}:AVG-FIT-FWHM",
|
||||
f"{camera}:AVG-FIT-RMS",
|
||||
f"{camera}:AVG-FIT-RES",
|
||||
f"{camera}:AVG-SPECT-COM",
|
||||
f"{camera}:AVG-SPECT-RMS",
|
||||
f"{camera}:AVG-SPECT-SKEW",
|
||||
f"{camera}:AVG-SPECT-IQR",
|
||||
f"{camera}:AVG-SPECT-RES",
|
||||
f"{camera}:AVG-SPECTRUM_Y",
|
||||
f"{camera}:AVG-FIT-SPECTRUM_Y"
|
||||
]
|
||||
|
||||
# All PVs (original + running average + N-shot average)
|
||||
all_pv_names = base_pv_names + ravg_pv_names + avg_pv_names
|
||||
|
||||
# Start background thread for PV updates
|
||||
thread = Thread(target=update_PVs, args=(buffer, *all_pv_names), daemon=True)
|
||||
@@ -109,15 +130,18 @@ def initialize(params):
|
||||
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata=None, background=None):
|
||||
"""
|
||||
Main entrypoint: subtract background, crop ROI, smooth, fit Gaussian,
|
||||
compute metrics, queue PV updates (with running averages for skew and IQR).
|
||||
Returns a dict of processed PV values (original channels only).
|
||||
compute metrics, N-shot average, queue PV updates (with running averages).
|
||||
Returns a dict of processed PV values (original and average channels).
|
||||
"""
|
||||
global initialized, sent_pid, channel_pv_names, global_ravg_length, ravg_buffers
|
||||
global initialized, sent_pid, channel_pv_names
|
||||
global global_ravg_length, ravg_buffers, avg_buffer
|
||||
try:
|
||||
if not initialized:
|
||||
initialize(parameters)
|
||||
initialized = True
|
||||
|
||||
camera = parameters["camera_name"]
|
||||
|
||||
# Dynamic ROI and axis PV read
|
||||
ymin_pv, ymax_pv, axis_pv = create_thread_pvs(channel_pv_names)
|
||||
if ymin_pv and ymin_pv.connected:
|
||||
@@ -128,11 +152,7 @@ def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata
|
||||
if not (axis_pv and axis_pv.connected):
|
||||
_logger.warning("Energy axis not connected")
|
||||
return None
|
||||
axis = axis_pv.value
|
||||
if len(axis) < image.shape[1]:
|
||||
_logger.warning("Energy axis length %d < image width %d", len(axis), image.shape[1])
|
||||
return None
|
||||
axis = axis[:image.shape[1]]
|
||||
axis = axis_pv.value[:image.shape[1]]
|
||||
|
||||
# Preprocess image
|
||||
proc_img = image.astype(np.float32) - np.float32(parameters.get("pixel_bkg", 0))
|
||||
@@ -140,51 +160,36 @@ def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata
|
||||
|
||||
# Background image
|
||||
bg_img = parameters.pop('background_data', None)
|
||||
if not (isinstance(bg_img, np.ndarray) and bg_img.shape == proc_img.shape):
|
||||
bg_img = None
|
||||
else:
|
||||
bg_img = bg_img.astype(np.float32)
|
||||
bg_img = bg_img.astype(np.float32) if isinstance(bg_img, np.ndarray) and bg_img.shape == proc_img.shape else None
|
||||
|
||||
# Crop ROI
|
||||
ymin, ymax = int(global_roi[0]), int(global_roi[1])
|
||||
ymin, ymax = map(int, global_roi)
|
||||
if 0 <= ymin < ymax <= nrows:
|
||||
proc_img = proc_img[ymin:ymax, :]
|
||||
if bg_img is not None:
|
||||
bg_img = bg_img[ymin:ymax, :]
|
||||
|
||||
# Extract spectrum
|
||||
# Extract spectrum and fitted spectrum
|
||||
spectrum = get_spectrum(proc_img, bg_img) if bg_img is not None else np.sum(proc_img, axis=0)
|
||||
|
||||
# Smooth
|
||||
smoothed = scipy.signal.savgol_filter(spectrum, 51, 3)
|
||||
|
||||
# Noise check and fit Gaussian
|
||||
minimum, maximum = smoothed.min(), smoothed.max()
|
||||
amplitude = maximum - minimum
|
||||
skip = amplitude <= nrows * 1.5
|
||||
offset, amp_fit, center, sigma = functions.gauss_fit_psss(
|
||||
smoothed[::2], axis[::2], offset=minimum,
|
||||
amplitude=amplitude, skip=skip, maxfev=10
|
||||
smoothed[::2], axis[::2], offset=minimum, amplitude=amplitude, skip=skip, maxfev=10
|
||||
)
|
||||
# Reconstruct fitted curve
|
||||
fit_spectrum = offset + amp_fit * np.exp(-((axis - center)**2) / (2 * sigma**2))
|
||||
|
||||
# Compute normalized spectrum weights
|
||||
# Moments
|
||||
sm_norm = smoothed / np.sum(smoothed)
|
||||
|
||||
# Statistical moments
|
||||
spect_com = np.sum(axis * sm_norm)
|
||||
spect_std = np.sqrt(np.sum((axis - spect_com)**2 * sm_norm))
|
||||
spect_com = np.sum(axis * sm_norm)
|
||||
spect_std = np.sqrt(np.sum((axis - spect_com)**2 * sm_norm))
|
||||
spect_skew = np.sum((axis - spect_com)**3 * sm_norm) / (spect_std**3)
|
||||
cum = np.cumsum(sm_norm); e25 = np.interp(0.25, cum, axis); e75 = np.interp(0.75, cum, axis)
|
||||
spect_iqr = e75 - e25; spect_sum = np.sum(spectrum)
|
||||
|
||||
# Interquartile width (IQR)
|
||||
cum = np.cumsum(sm_norm)
|
||||
e25 = np.interp(0.25, cum, axis)
|
||||
e75 = np.interp(0.75, cum, axis)
|
||||
spect_iqr = e75 - e25
|
||||
|
||||
spect_sum = np.sum(spectrum)
|
||||
|
||||
camera = parameters["camera_name"]
|
||||
# Original result dict
|
||||
# Original result
|
||||
result = {
|
||||
parameters["e_int_name"]: spectrum,
|
||||
parameters["e_axis_name"]: axis,
|
||||
@@ -193,31 +198,59 @@ def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata
|
||||
f"{camera}:FIT-FWHM": np.float64(2.355 * sigma),
|
||||
f"{camera}:FIT-RMS": np.float64(sigma),
|
||||
f"{camera}:FIT-RES": np.float64(2.355 * sigma / center * 1000),
|
||||
f"{camera}:FIT-SPECTRUM_Y": fit_spectrum,
|
||||
f"{camera}:SPECT-COM": spect_com,
|
||||
f"{camera}:SPECT-RMS": spect_std,
|
||||
f"{camera}:SPECT-SKEW": spect_skew,
|
||||
f"{camera}:SPECT-IQR": spect_iqr,
|
||||
# Use IQR for relative spread instead of std
|
||||
f"{camera}:SPECT-RES": np.float64(spect_iqr / spect_com * 1000),
|
||||
f"{camera}:processing_parameters": json.dumps({"roi": global_roi})
|
||||
}
|
||||
|
||||
# Prepare full values for PV update (including running averages)
|
||||
exclude = {
|
||||
parameters["e_int_name"],
|
||||
parameters["e_axis_name"],
|
||||
f"{camera}:processing_parameters"
|
||||
}
|
||||
# Rolling averages
|
||||
exclude = {parameters["e_int_name"], parameters["e_axis_name"], f"{camera}:processing_parameters"}
|
||||
ravg_results = {}
|
||||
for base_pv in (pv for pv in base_pv_names if pv not in exclude):
|
||||
buf = ravg_buffers.setdefault(base_pv, deque(maxlen=global_ravg_length))
|
||||
buf.append(result.get(base_pv))
|
||||
buf.append(result[base_pv])
|
||||
ravg_results[f"{base_pv}-RAVG"] = np.mean(buf)
|
||||
|
||||
# Merge for PV write
|
||||
full_results = {**result, **ravg_results}
|
||||
# N-shot average and average fitted spectrum
|
||||
avg_buffer.append(spectrum)
|
||||
avg_spectrum = np.mean(np.stack(avg_buffer), axis=0)
|
||||
fit_avg = offset + amp_fit * np.exp(-((axis - center)**2) / (2 * sigma**2)) # using avg fit params below
|
||||
sm_avg = scipy.signal.savgol_filter(avg_spectrum, 51, 3)
|
||||
min_a, max_a = sm_avg.min(), sm_avg.max()
|
||||
amp_a = max_a - min_a; skip_a = amp_a <= nrows * 1.5
|
||||
offs_a, amp_fit_a, center_a, sigma_a = functions.gauss_fit_psss(
|
||||
sm_avg[::2], axis[::2], offset=min_a, amplitude=amp_a, skip=skip_a, maxfev=10
|
||||
)
|
||||
fit_avg_spectrum = offs_a + amp_fit_a * np.exp(-((axis - center_a)**2) / (2 * sigma_a**2))
|
||||
# Average moments
|
||||
sm_norm_a = sm_avg / np.sum(sm_avg)
|
||||
spect_com_a = np.sum(axis * sm_norm_a)
|
||||
spect_std_a = np.sqrt(np.sum((axis - spect_com_a)**2 * sm_norm_a))
|
||||
spect_skew_a = np.sum((axis - spect_com_a)**3 * sm_norm_a) / (spect_std_a**3)
|
||||
cum_a = np.cumsum(sm_norm_a); e25_a = np.interp(0.25, cum_a, axis); e75_a = np.interp(0.75, cum_a, axis)
|
||||
spect_iqr_a = e75_a - e25_a
|
||||
spect_res_a = spect_iqr_a / spect_com_a * 1000
|
||||
|
||||
# Queue PV update if new pulse
|
||||
avg_results = {
|
||||
f"{camera}:AVG-FIT-COM": np.float64(center_a),
|
||||
f"{camera}:AVG-FIT-FWHM": np.float64(2.355 * sigma_a),
|
||||
f"{camera}:AVG-FIT-RMS": np.float64(sigma_a),
|
||||
f"{camera}:AVG-FIT-RES": np.float64(2.355 * sigma_a / center_a * 1000),
|
||||
f"{camera}:AVG-SPECT-COM": spect_com_a,
|
||||
f"{camera}:AVG-SPECT-RMS": spect_std_a,
|
||||
f"{camera}:AVG-SPECT-SKEW": spect_skew_a,
|
||||
f"{camera}:AVG-SPECT-IQR": spect_iqr_a,
|
||||
f"{camera}:AVG-SPECT-RES": np.float64(spect_res_a),
|
||||
f"{camera}:AVG-SPECTRUM_Y": avg_spectrum,
|
||||
f"{camera}:AVG-FIT-SPECTRUM_Y": fit_avg_spectrum
|
||||
}
|
||||
|
||||
# Merge and queue
|
||||
full_results = {**result, **ravg_results, **avg_results}
|
||||
if epics_lock.acquire(False):
|
||||
try:
|
||||
if pulse_id > sent_pid:
|
||||
|
||||
234
configuration/user_scripts/swissfel_spectral_processing_bkg.py
Normal file
234
configuration/user_scripts/swissfel_spectral_processing_bkg.py
Normal file
@@ -0,0 +1,234 @@
|
||||
from logging import getLogger
|
||||
from cam_server.pipeline.data_processing import functions
|
||||
from cam_server.utils import create_thread_pvs, epics_lock
|
||||
from collections import deque
|
||||
import json
|
||||
import numpy as np
|
||||
import scipy.signal
|
||||
import numba
|
||||
import time
|
||||
import sys
|
||||
from threading import Thread
|
||||
|
||||
# Configure Numba to use multiple threads
|
||||
numba.set_num_threads(4)
|
||||
|
||||
_logger = getLogger(__name__)
|
||||
|
||||
# Shared state globals
|
||||
global_roi = [0, 0]
|
||||
initialized = False
|
||||
sent_pid = -1
|
||||
buffer = deque(maxlen=5)
|
||||
channel_pv_names = None
|
||||
base_pv_names = []
|
||||
all_pv_names = []
|
||||
global_ravg_length = 100
|
||||
ravg_buffers = {}
|
||||
|
||||
@numba.njit(parallel=False)
|
||||
def get_spectrum(image, background):
|
||||
"""Compute background-subtracted spectrum via row-wise summation."""
|
||||
y, x = image.shape
|
||||
profile = np.zeros(x, dtype=np.float64)
|
||||
for i in numba.prange(y):
|
||||
for j in range(x):
|
||||
profile[j] += image[i, j] - background[i, j]
|
||||
return profile
|
||||
|
||||
|
||||
def update_PVs(buffer, *pv_names):
|
||||
"""Continuously read from buffer and write to EPICS PVs."""
|
||||
pvs = create_thread_pvs(list(pv_names))
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
try:
|
||||
rec = buffer.popleft()
|
||||
except IndexError:
|
||||
continue
|
||||
try:
|
||||
for pv, val in zip(pvs, rec):
|
||||
if pv and pv.connected and (val is not None):
|
||||
pv.put(val)
|
||||
except Exception:
|
||||
_logger.exception("Error updating channels")
|
||||
|
||||
|
||||
def initialize(params):
|
||||
"""Initialize PV names, running-average settings, and launch update thread."""
|
||||
global channel_pv_names, base_pv_names, all_pv_names, global_ravg_length
|
||||
|
||||
camera = params["camera_name"]
|
||||
e_int = params["e_int_name"]
|
||||
e_axis = params["e_axis_name"]
|
||||
|
||||
# Fit/result PV names
|
||||
center_pv = f"{camera}:FIT-COM"
|
||||
fwhm_pv = f"{camera}:FIT-FWHM"
|
||||
fit_rms_pv = f"{camera}:FIT-RMS"
|
||||
fit_res_pv = f"{camera}:FIT-RES"
|
||||
|
||||
# ROI PVs for dynamic read
|
||||
ymin_pv = f"{camera}:SPC_ROI_YMIN"
|
||||
ymax_pv = f"{camera}:SPC_ROI_YMAX"
|
||||
axis_pv = e_axis
|
||||
channel_pv_names = [ymin_pv, ymax_pv, axis_pv]
|
||||
|
||||
# Spectrum statistical PV names
|
||||
com_pv = f"{camera}:SPECT-COM"
|
||||
std_pv = f"{camera}:SPECT-RMS"
|
||||
skew_pv = f"{camera}:SPECT-SKEW"
|
||||
iqr_pv = f"{camera}:SPECT-IQR"
|
||||
res_pv = f"{camera}:SPECT-RES" # will use IQR-based calc
|
||||
|
||||
# Base PVs for update thread (order matters)
|
||||
base_pv_names = [
|
||||
e_int, center_pv, fwhm_pv, fit_rms_pv,
|
||||
fit_res_pv, com_pv, std_pv, skew_pv, iqr_pv, res_pv
|
||||
]
|
||||
|
||||
# Running-average configuration
|
||||
global_ravg_length = params.get('RAVG_length', global_ravg_length)
|
||||
# Build list of running-average PVs (exclude e_int, e_axis, processing_parameters)
|
||||
exclude = {
|
||||
e_int,
|
||||
e_axis,
|
||||
f"{camera}:processing_parameters"
|
||||
}
|
||||
ravg_base = [pv for pv in base_pv_names if pv not in exclude]
|
||||
ravg_pv_names = [pv + '-RAVG' for pv in ravg_base]
|
||||
|
||||
# All PVs (original + running average)
|
||||
all_pv_names = base_pv_names + ravg_pv_names
|
||||
|
||||
# Start background thread for PV updates
|
||||
thread = Thread(target=update_PVs, args=(buffer, *all_pv_names), daemon=True)
|
||||
thread.start()
|
||||
|
||||
|
||||
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata=None, background=None):
|
||||
"""
|
||||
Main entrypoint: subtract background, crop ROI, smooth, fit Gaussian,
|
||||
compute metrics, queue PV updates (with running averages for skew and IQR).
|
||||
Returns a dict of processed PV values (original channels only).
|
||||
"""
|
||||
global initialized, sent_pid, channel_pv_names, global_ravg_length, ravg_buffers
|
||||
try:
|
||||
if not initialized:
|
||||
initialize(parameters)
|
||||
initialized = True
|
||||
|
||||
# Dynamic ROI and axis PV read
|
||||
ymin_pv, ymax_pv, axis_pv = create_thread_pvs(channel_pv_names)
|
||||
if ymin_pv and ymin_pv.connected:
|
||||
global_roi[0] = ymin_pv.value
|
||||
if ymax_pv and ymax_pv.connected:
|
||||
global_roi[1] = ymax_pv.value
|
||||
|
||||
if not (axis_pv and axis_pv.connected):
|
||||
_logger.warning("Energy axis not connected")
|
||||
return None
|
||||
axis = axis_pv.value
|
||||
if len(axis) < image.shape[1]:
|
||||
_logger.warning("Energy axis length %d < image width %d", len(axis), image.shape[1])
|
||||
return None
|
||||
axis = axis[:image.shape[1]]
|
||||
|
||||
# Preprocess image
|
||||
proc_img = image.astype(np.float32) - np.float32(parameters.get("pixel_bkg", 0))
|
||||
nrows, _ = proc_img.shape
|
||||
|
||||
# Background image
|
||||
bg_img = parameters.pop('background_data', None)
|
||||
if not (isinstance(bg_img, np.ndarray) and bg_img.shape == proc_img.shape):
|
||||
bg_img = None
|
||||
else:
|
||||
bg_img = bg_img.astype(np.float32)
|
||||
|
||||
# Crop ROI
|
||||
ymin, ymax = int(global_roi[0]), int(global_roi[1])
|
||||
if 0 <= ymin < ymax <= nrows:
|
||||
proc_img = proc_img[ymin:ymax, :]
|
||||
if bg_img is not None:
|
||||
bg_img = bg_img[ymin:ymax, :]
|
||||
|
||||
# Extract spectrum
|
||||
spectrum = get_spectrum(proc_img, bg_img) if bg_img is not None else np.sum(proc_img, axis=0)
|
||||
|
||||
# Smooth
|
||||
smoothed = scipy.signal.savgol_filter(spectrum, 51, 3)
|
||||
|
||||
# Noise check and fit Gaussian
|
||||
minimum, maximum = smoothed.min(), smoothed.max()
|
||||
amplitude = maximum - minimum
|
||||
skip = amplitude <= nrows * 1.5
|
||||
offset, amp_fit, center, sigma = functions.gauss_fit_psss(
|
||||
smoothed[::2], axis[::2], offset=minimum,
|
||||
amplitude=amplitude, skip=skip, maxfev=10
|
||||
)
|
||||
|
||||
# Compute normalized spectrum weights
|
||||
sm_norm = smoothed / np.sum(smoothed)
|
||||
|
||||
# Statistical moments
|
||||
spect_com = np.sum(axis * sm_norm)
|
||||
spect_std = np.sqrt(np.sum((axis - spect_com)**2 * sm_norm))
|
||||
spect_skew = np.sum((axis - spect_com)**3 * sm_norm) / (spect_std**3)
|
||||
|
||||
# Interquartile width (IQR)
|
||||
cum = np.cumsum(sm_norm)
|
||||
e25 = np.interp(0.25, cum, axis)
|
||||
e75 = np.interp(0.75, cum, axis)
|
||||
spect_iqr = e75 - e25
|
||||
|
||||
spect_sum = np.sum(spectrum)
|
||||
|
||||
camera = parameters["camera_name"]
|
||||
# Original result dict
|
||||
result = {
|
||||
parameters["e_int_name"]: spectrum,
|
||||
parameters["e_axis_name"]: axis,
|
||||
f"{camera}:SPECTRUM_Y_SUM": spect_sum,
|
||||
f"{camera}:FIT-COM": np.float64(center),
|
||||
f"{camera}:FIT-FWHM": np.float64(2.355 * sigma),
|
||||
f"{camera}:FIT-RMS": np.float64(sigma),
|
||||
f"{camera}:FIT-RES": np.float64(2.355 * sigma / center * 1000),
|
||||
f"{camera}:SPECT-COM": spect_com,
|
||||
f"{camera}:SPECT-RMS": spect_std,
|
||||
f"{camera}:SPECT-SKEW": spect_skew,
|
||||
f"{camera}:SPECT-IQR": spect_iqr,
|
||||
# Use IQR for relative spread instead of std
|
||||
f"{camera}:SPECT-RES": np.float64(spect_iqr / spect_com * 1000),
|
||||
f"{camera}:processing_parameters": json.dumps({"roi": global_roi})
|
||||
}
|
||||
|
||||
# Prepare full values for PV update (including running averages)
|
||||
exclude = {
|
||||
parameters["e_int_name"],
|
||||
parameters["e_axis_name"],
|
||||
f"{camera}:processing_parameters"
|
||||
}
|
||||
ravg_results = {}
|
||||
for base_pv in (pv for pv in base_pv_names if pv not in exclude):
|
||||
buf = ravg_buffers.setdefault(base_pv, deque(maxlen=global_ravg_length))
|
||||
buf.append(result.get(base_pv))
|
||||
ravg_results[f"{base_pv}-RAVG"] = np.mean(buf)
|
||||
|
||||
# Merge for PV write
|
||||
full_results = {**result, **ravg_results}
|
||||
|
||||
# Queue PV update if new pulse
|
||||
if epics_lock.acquire(False):
|
||||
try:
|
||||
if pulse_id > sent_pid:
|
||||
sent_pid = pulse_id
|
||||
entry = tuple(full_results.get(pv) for pv in all_pv_names)
|
||||
buffer.append(entry)
|
||||
finally:
|
||||
epics_lock.release()
|
||||
|
||||
return full_results
|
||||
|
||||
except Exception as ex:
|
||||
_logger.warning("Processing error: %s", ex)
|
||||
return {}
|
||||
283
configuration/user_scripts/swissfel_spectral_processing_fast.py
Normal file
283
configuration/user_scripts/swissfel_spectral_processing_fast.py
Normal file
@@ -0,0 +1,283 @@
|
||||
from logging import getLogger
|
||||
from cam_server.pipeline.data_processing import functions
|
||||
from cam_server.utils import epics_lock, create_thread_pvs
|
||||
from collections import deque
|
||||
import threading
|
||||
import json
|
||||
import numpy as np
|
||||
import scipy.signal
|
||||
import numba
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
# Configure Numba to use multiple threads and parallelize
|
||||
numba.set_num_threads(4)
|
||||
|
||||
_logger = getLogger(__name__)
|
||||
|
||||
# Shared state globals
|
||||
global_roi = [0, 0]
|
||||
last_roi = None
|
||||
params_json = None
|
||||
initialized = False
|
||||
sent_pid = -1
|
||||
buffer = deque(maxlen=5)
|
||||
channel_pv_names = []
|
||||
base_pv_names = []
|
||||
all_pv_names = []
|
||||
global_ravg_length = 100
|
||||
# Running-average state
|
||||
global ravg_buffers, ravg_sum_map, ravg_lock
|
||||
ravg_buffers = {}
|
||||
ravg_sum_map = {}
|
||||
ravg_lock = threading.Lock()
|
||||
# N-shot average state
|
||||
global global_avg_n, avg_buffer, avg_sum
|
||||
global_avg_n = 100
|
||||
avg_buffer = deque()
|
||||
avg_sum = None
|
||||
# Cached PV handles
|
||||
pv_handles = None
|
||||
|
||||
# Update thread function
|
||||
def update_PVs():
|
||||
"""Continuously pop and write to EPICS PVs using cached handles."""
|
||||
global pv_handles, buffer
|
||||
while True:
|
||||
try:
|
||||
entry = buffer.popleft()
|
||||
except IndexError:
|
||||
time.sleep(0.001)
|
||||
continue
|
||||
for pv, val in zip(pv_handles, entry):
|
||||
if pv and pv.connected and val is not None:
|
||||
pv.put(val)
|
||||
|
||||
|
||||
def initialize(params):
|
||||
"""Initialize PV names, caches, and start update thread."""
|
||||
global channel_pv_names, base_pv_names, all_pv_names
|
||||
global global_ravg_length, global_avg_n, avg_buffer, avg_sum, pv_handles
|
||||
|
||||
camera = params["camera_name"]
|
||||
e_int = params["e_int_name"]
|
||||
e_axis = params["e_axis_name"]
|
||||
|
||||
# Fit/result PV names
|
||||
center_pv = f"{camera}:FIT-COM"
|
||||
fwhm_pv = f"{camera}:FIT-FWHM"
|
||||
fit_rms_pv = f"{camera}:FIT-RMS"
|
||||
fit_res_pv = f"{camera}:FIT-RES"
|
||||
fit_spec_pv = f"{camera}:FIT-SPECTRUM_Y"
|
||||
|
||||
# ROI PVs
|
||||
ymin_pv = f"{camera}:SPC_ROI_YMIN"
|
||||
ymax_pv = f"{camera}:SPC_ROI_YMAX"
|
||||
channel_pv_names = [ymin_pv, ymax_pv, e_axis]
|
||||
|
||||
# Stats PVs
|
||||
com_pv = f"{camera}:SPECT-COM"
|
||||
std_pv = f"{camera}:SPECT-RMS"
|
||||
skew_pv = f"{camera}:SPECT-SKEW"
|
||||
iqr_pv = f"{camera}:SPECT-IQR"
|
||||
res_pv = f"{camera}:SPECT-RES"
|
||||
|
||||
# Base PV list
|
||||
base_pv_names = [
|
||||
e_int, center_pv, fwhm_pv, fit_rms_pv,
|
||||
fit_res_pv, fit_spec_pv, com_pv, std_pv, skew_pv, iqr_pv, res_pv
|
||||
]
|
||||
|
||||
# Running-average PV names
|
||||
global_ravg_length = params.get('RAVG_length', global_ravg_length)
|
||||
exclude = {e_int, e_axis, f"{camera}:processing_parameters"}
|
||||
ravg_base = [pv for pv in base_pv_names if pv not in exclude]
|
||||
ravg_pv_names = [pv + '-RAVG' for pv in ravg_base]
|
||||
|
||||
# N-shot average settings
|
||||
global_avg_n = params.get('avg_nshots', global_avg_n)
|
||||
avg_buffer = deque(maxlen=global_avg_n)
|
||||
avg_sum = None
|
||||
avg_pv_names = [
|
||||
f"{camera}:AVG-FIT-COM",
|
||||
f"{camera}:AVG-FIT-FWHM",
|
||||
f"{camera}:AVG-FIT-RMS",
|
||||
f"{camera}:AVG-FIT-RES",
|
||||
f"{camera}:AVG-SPECT-COM",
|
||||
f"{camera}:AVG-SPECT-RMS",
|
||||
f"{camera}:AVG-SPECT-SKEW",
|
||||
f"{camera}:AVG-SPECT-IQR",
|
||||
f"{camera}:AVG-SPECT-RES",
|
||||
f"{camera}:AVG-SPECTRUM_Y",
|
||||
f"{camera}:AVG-FIT-SPECTRUM_Y"
|
||||
]
|
||||
|
||||
# All PVs
|
||||
all_pv_names = base_pv_names + ravg_pv_names + avg_pv_names + [f"{camera}:processing_parameters"]
|
||||
|
||||
# Cache PV handles
|
||||
pv_handles = create_thread_pvs(all_pv_names)
|
||||
|
||||
# Start update thread
|
||||
thread = Thread(target=update_PVs, daemon=True)
|
||||
thread.start()
|
||||
|
||||
|
||||
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata=None, background=None):
|
||||
"""
|
||||
Fast processing: vectorized spectrum, incremental averages, cached PVs.
|
||||
"""
|
||||
global initialized, sent_pid, buffer
|
||||
global global_roi, last_roi, params_json
|
||||
global ravg_buffers, ravg_sum_map, ravg_lock
|
||||
global avg_buffer, avg_sum, global_avg_n, all_pv_names
|
||||
|
||||
if not initialized:
|
||||
initialize(parameters)
|
||||
initialized = True
|
||||
|
||||
camera = parameters["camera_name"]
|
||||
|
||||
# Read ROI once and detect change
|
||||
ymin, ymax = global_roi
|
||||
new_ymin = parameters.get('roi_ymin', ymin)
|
||||
new_ymax = parameters.get('roi_ymax', ymax)
|
||||
if (new_ymin, new_ymax) != (ymin, ymax):
|
||||
global_roi[:] = [new_ymin, new_ymax]
|
||||
roi_changed = True
|
||||
else:
|
||||
roi_changed = False
|
||||
|
||||
# Preprocess image
|
||||
img = image.astype(np.float32)
|
||||
pixel_bkg = parameters.get("pixel_bkg", 0)
|
||||
proc_img = img - pixel_bkg
|
||||
nrows, _ = proc_img.shape
|
||||
|
||||
# Background subtraction
|
||||
bg = parameters.pop('background_data', None)
|
||||
if isinstance(bg, np.ndarray) and bg.shape == proc_img.shape:
|
||||
proc_img -= bg.astype(np.float32)
|
||||
|
||||
# Crop ROI
|
||||
ymin_i, ymax_i = int(global_roi[0]), int(global_roi[1])
|
||||
if 0 <= ymin_i < ymax_i <= nrows:
|
||||
proc_img = proc_img[ymin_i:ymax_i, :]
|
||||
|
||||
# Spectrum via vector sum
|
||||
spectrum = np.sum(proc_img, axis=0)
|
||||
# Smooth
|
||||
smoothed = scipy.signal.savgol_filter(spectrum, 51, 3)
|
||||
# Fit Gaussian
|
||||
minimum, maximum = smoothed.min(), smoothed.max()
|
||||
amplitude = maximum - minimum
|
||||
skip = amplitude <= nrows * 1.5
|
||||
offset, amp_fit, center, sigma = functions.gauss_fit_psss(
|
||||
smoothed[::2], x_axis[:len(smoothed)][::2], offset=minimum,
|
||||
amplitude=amplitude, skip=skip, maxfev=10
|
||||
)
|
||||
fit_spectrum = offset + amp_fit * np.exp(-((x_axis[:len(smoothed)] - center)**2) / (2 * sigma**2))
|
||||
|
||||
# Compute stats
|
||||
sm_norm = smoothed / np.sum(smoothed)
|
||||
spect_com = np.dot(x_axis[:len(sm_norm)], sm_norm)
|
||||
spect_std = np.sqrt(np.dot((x_axis[:len(sm_norm)] - spect_com)**2, sm_norm))
|
||||
spect_skew = np.dot((x_axis[:len(sm_norm)] - spect_com)**3, sm_norm) / (spect_std**3)
|
||||
cum = np.cumsum(sm_norm)
|
||||
e25 = np.interp(0.25, cum, x_axis[:len(cum)])
|
||||
e75 = np.interp(0.75, cum, x_axis[:len(cum)])
|
||||
spect_iqr = e75 - e25
|
||||
spect_sum = spectrum.sum()
|
||||
|
||||
# Original result
|
||||
result = {
|
||||
parameters["e_int_name"]: spectrum,
|
||||
parameters["e_axis_name"]: x_axis[:len(spectrum)],
|
||||
f"{camera}:SPECTRUM_Y_SUM": spect_sum,
|
||||
f"{camera}:FIT-COM": np.float64(center),
|
||||
f"{camera}:FIT-FWHM": np.float64(2.355 * sigma),
|
||||
f"{camera}:FIT-RMS": np.float64(sigma),
|
||||
f"{camera}:FIT-RES": np.float64(2.355 * sigma / center * 1000),
|
||||
f"{camera}:FIT-SPECTRUM_Y": fit_spectrum,
|
||||
f"{camera}:SPECT-COM": spect_com,
|
||||
f"{camera}:SPECT-RMS": spect_std,
|
||||
f"{camera}:SPECT-SKEW": spect_skew,
|
||||
f"{camera}:SPECT-IQR": spect_iqr,
|
||||
f"{camera}:SPECT-RES": np.float64(spect_iqr / spect_com * 1000)
|
||||
}
|
||||
# Update JSON PV only on ROI change
|
||||
if roi_changed:
|
||||
params_json = json.dumps({"roi": global_roi})
|
||||
result[f"{camera}:processing_parameters"] = params_json
|
||||
|
||||
# Running averages (thread-safe, incremental sum)
|
||||
ravg_results = {}
|
||||
exclude = {parameters["e_int_name"], parameters["e_axis_name"], f"{camera}:processing_parameters"}
|
||||
with ravg_lock:
|
||||
for pv in base_pv_names:
|
||||
if pv not in exclude:
|
||||
buf = ravg_buffers.setdefault(pv, deque(maxlen=global_ravg_length))
|
||||
sum_val = ravg_sum_map.get(pv, 0.0)
|
||||
if len(buf) == buf.maxlen:
|
||||
old = buf.popleft()
|
||||
sum_val -= old
|
||||
buf.append(result[pv])
|
||||
sum_val += result[pv]
|
||||
ravg_sum_map[pv] = sum_val
|
||||
ravg_results[pv + "-RAVG"] = sum_val / len(buf)
|
||||
|
||||
# N-shot average (incremental, no full-stack)
|
||||
global avg_sum
|
||||
if avg_sum is None:
|
||||
avg_sum = np.zeros_like(spectrum)
|
||||
if len(avg_buffer) == global_avg_n:
|
||||
old = avg_buffer.popleft()
|
||||
avg_sum -= old
|
||||
avg_buffer.append(spectrum)
|
||||
avg_sum += spectrum
|
||||
avg_spectrum = avg_sum / len(avg_buffer)
|
||||
# Fit and stats on avg_spectrum
|
||||
sm_avg = scipy.signal.savgol_filter(avg_spectrum, 51, 3)
|
||||
min_a, max_a = sm_avg.min(), sm_avg.max()
|
||||
amp_a = max_a - min_a
|
||||
skip_a = amp_a <= nrows * 1.5
|
||||
offs_a, amp_fit_a, center_a, sigma_a = functions.gauss_fit_psss(
|
||||
sm_avg[::2], x_axis[:len(sm_avg)][::2], offset=min_a,
|
||||
amplitude=amp_a, skip=skip_a, maxfev=10
|
||||
)
|
||||
fit_avg_spectrum = offs_a + amp_fit_a * np.exp(-((x_axis[:len(sm_avg)] - center_a)**2) / (2 * sigma_a**2))
|
||||
sm_norm_a = sm_avg / np.sum(sm_avg)
|
||||
spect_com_a = np.dot(x_axis[:len(sm_norm_a)], sm_norm_a)
|
||||
spect_std_a = np.sqrt(np.dot((x_axis[:len(sm_norm_a)] - spect_com_a)**2, sm_norm_a))
|
||||
spect_skew_a = np.dot((x_axis[:len(sm_norm_a)] - spect_com_a)**3, sm_norm_a) / (spect_std_a**3)
|
||||
cum_a = np.cumsum(sm_norm_a)
|
||||
e25_a = np.interp(0.25, cum_a, x_axis[:len(cum_a)])
|
||||
e75_a = np.interp(0.75, cum_a, x_axis[:len(cum_a)])
|
||||
spect_iqr_a = e75_a - e25_a
|
||||
spect_res_a = spect_iqr_a / spect_com_a * 1000
|
||||
|
||||
avg_results = {
|
||||
f"{camera}:AVG-FIT-COM": np.float64(center_a),
|
||||
f"{camera}:AVG-FIT-FWHM": np.float64(2.355 * sigma_a),
|
||||
f"{camera}:AVG-FIT-RMS": np.float64(sigma_a),
|
||||
f"{camera}:AVG-FIT-RES": np.float64(2.355 * sigma_a / center_a * 1000),
|
||||
f"{camera}:AVG-SPECT-COM": spect_com_a,
|
||||
f"{camera}:AVG-SPECT-RMS": spect_std_a,
|
||||
f"{camera}:AVG-SPECT-SKEW": spect_skew_a,
|
||||
f"{camera}:AVG-SPECT-IQR": spect_iqr_a,
|
||||
f"{camera}:AVG-SPECT-RES": np.float64(spect_res_a),
|
||||
f"{camera}:AVG-SPECTRUM_Y": avg_spectrum,
|
||||
f"{camera}:AVG-FIT-SPECTRUM_Y": fit_avg_spectrum
|
||||
}
|
||||
|
||||
# Merge and queue for PV update
|
||||
full = {**result, **ravg_results, **avg_results}
|
||||
if epics_lock.acquire(False):
|
||||
try:
|
||||
if pulse_id > sent_pid:
|
||||
sent_pid = pulse_id
|
||||
buffer.append(tuple(full[pv] for pv in all_pv_names))
|
||||
finally:
|
||||
epics_lock.release()
|
||||
|
||||
return full
|
||||
Reference in New Issue
Block a user