API reference¶
Camera¶
getframes.camera.Camera
¶
A camera that generates realistic synthetic frames.
A :class:Camera wraps a :class:~getframes.config.CameraConfig and exposes
high-level frame-generation methods. Construct one directly from a config, or
load a built-in preset:
import getframes as gf cam = gf.Camera.from_preset("andor_ikon_m934") frame = cam.dark_frame(exposure=30.0, temperature=-60.0, seed=0) frame.shape (1024, 1024)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CameraConfig
|
The detector configuration. |
required |
default_temperature_c
|
float | None
|
Temperature (deg C) used when a frame method is called without an explicit temperature. Defaults to the config's dark-current reference temperature. |
None
|
seed
|
int | None
|
Optional seed for this camera's internal random generator, giving reproducible output across calls when no per-call seed is supplied. |
None
|
precision
|
str
|
Working floating-point precision of the signal chain: |
'float64'
|
device
|
str
|
Execution device for detector arrays and random sampling: |
'cpu'
|
Source code in src/getframes/camera.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | |
resolution
property
¶
Unbinned output shape, accounting for the configured detector ROI.
sensor_resolution
property
¶
Full physical detector shape before applying an ROI.
roi
property
¶
Configured (left, top, width, height) detector ROI, if any.
device
property
¶
Execution device ("cpu" or "gpu").
from_preset(name, **kwargs)
classmethod
¶
Create a camera from a built-in preset (see :func:getframes.available_presets).
Source code in src/getframes/camera.py
111 112 113 114 | |
from_dict(data, **kwargs)
classmethod
¶
Create a camera from a plain configuration dictionary.
Source code in src/getframes/camera.py
116 117 118 119 | |
with_config(**changes)
¶
Return a new camera with configuration fields overridden.
Source code in src/getframes/camera.py
152 153 154 155 156 157 158 159 | |
dark_frame(exposure, temperature=None, *, seed=None)
¶
Generate a single dark frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exposure
|
float
|
Integration time in seconds. |
required |
temperature
|
float | None
|
Sensor temperature in degrees Celsius. Defaults to the camera's
:attr: |
None
|
seed
|
int | None
|
If given, use a fresh generator seeded with this value, producing a fully reproducible frame independent of prior calls. If omitted, the camera's internal generator advances. |
None
|
Returns:
| Type | Description |
|---|---|
Frame
|
The simulated frame (ADU) with descriptive metadata. |
Source code in src/getframes/camera.py
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
dark_series(exposure, n_frames, temperature=None, *, seed=None)
¶
Yield n_frames independent dark frames (e.g. for building a master dark).
When seed is given the series is reproducible; each frame uses a distinct
derived seed so the frames are independent but the whole series is repeatable.
Source code in src/getframes/camera.py
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | |
nondestructive_series(photon_rate, read_interval, n_frames, reads_per_reset, temperature=None, *, background=0.0, quantum_efficiency=None, seed=None, include_truth=True)
¶
Yield correlated nondestructive reads separated by global resets.
Newly collected photo- and dark electrons are sampled once per
read_interval and accumulated in the pixel well. For an EMCCD/eAPD,
each new increment passes through the stochastic gain stage once when it
is collected; already accumulated charge is not re-multiplied on later
reads. Reset noise is drawn once at the start of a ramp and is therefore
common to every read in that ramp, while amplifier read noise is fresh on
every read. This gives correlated double sampling and up-the-ramp fitting
the correct temporal covariance.
A reset occurs immediately before reads 0, reads_per_reset, .... The
first returned frame therefore contains one read interval of accumulated
charge. Detector transport terms that are linear in charge (IPC) act on
each collected increment; CCD-only transfer/blooming models are outside
this hybrid-array readout path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
photon_rate
|
PhotonRate
|
Incident photons/s/pixel, scalar or a map matching the active camera resolution. |
required |
read_interval
|
float
|
Time between consecutive reads in seconds. |
required |
n_frames
|
int
|
Total number of raw reads to return, across all ramps. |
required |
reads_per_reset
|
int
|
Number of nondestructive reads between global resets. |
required |
temperature
|
float | None
|
Detector temperature in degrees Celsius. |
None
|
background
|
PhotonRate
|
Additive incident background in photons/s/pixel. |
0.0
|
quantum_efficiency
|
float | None
|
Optional scalar QE override. |
None
|
seed
|
int | None
|
Seed for the complete correlated sequence. |
None
|
include_truth
|
bool
|
Attach the cumulative noise-free input-electron expectation. |
True
|
Yields:
| Type | Description |
|---|---|
Frame
|
Raw digitised reads with ramp/read metadata. |
Source code in src/getframes/camera.py
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | |
dark_nondestructive_series(read_interval, n_frames, reads_per_reset, temperature=None, *, seed=None, include_truth=True)
¶
Yield global-reset nondestructive dark reads.
This is :meth:nondestructive_series with zero incident photon rate.
Source code in src/getframes/camera.py
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | |
correlated_double_sample(photon_rate, exposure, temperature=None, *, background=0.0, quantum_efficiency=None, pedestal_interval_s=0.0, seed=None, include_truth=True)
¶
Read the sensor in correlated double sampling and return the difference.
CDS is the standard low-noise operating mode of a nondestructive-readout
hybrid array such as the SAPHIRA in a C-RED One. The pixel is globally
reset, read once to record the reset pedestal, integrated for
exposure, and read again; the reported value is the difference of
the two reads. This is one ramp of :meth:nondestructive_series with
two reads, differenced, and it uses that same reset-correlated core.
What the differencing does and does not remove follows from which terms are common to the two reads:
- Removed. kTC/reset noise (
reset_noise_e), drawn once per ramp, and the fixed bias structure — pedestal, per-channel and per-pixel offsets, and edge structure — which is a property of the silicon and identical in both reads. - Amplified. Amplifier read noise is redrawn per read, so the
difference carries
sqrt(2) * read_noise_e. The eAPD input-referred noise likewise adds in quadrature across the two reads. - Partly removed. Readout common mode is an AR(1) sequence with
correlation
readout_common_mode_correlation, so the difference retains thesqrt(2 * (1 - rho))fraction of it rather than all or none. Reset settling is read-index dependent and therefore leaves the residual between its value at the pedestal and signal reads, which is the physical CDS pedestal artifact rather than a modelling shortcut. - Not removed. The interval-proportional bias rate
(
ndr_bias_offset_adu_per_sandndr_bias_gain_coefficient_adu_per_s) scales with collected integration time, not with the read operation, so it survives differencing in full. A CDS frame therefore still sits on a small exposure-dependent pedestal — for the C-RED One preset at 1750 Hz, about+50 ADUof bias rate against-8 ADUof settling residual. Subtract it with a dark CDS frame at the same exposure and gain, exactly as on the real camera.
Charge is collected only between the two reads, so the well holds one
exposure worth of signal and full-well clipping happens at the
intended level.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
photon_rate
|
PhotonRate
|
Incident photons/s/pixel, scalar or a map matching the active camera resolution. |
required |
exposure
|
float
|
Integration time between the pedestal and signal reads, in
seconds. This is the charge the difference measures, so it is
independent of |
required |
temperature
|
float | None
|
Detector temperature in degrees Celsius. Defaults to
:attr: |
None
|
background
|
PhotonRate
|
Additive incident background in photons/s/pixel. |
0.0
|
quantum_efficiency
|
float | None
|
Optional scalar QE override. |
None
|
pedestal_interval_s
|
float
|
Reset-to-pedestal-read time in seconds. |
0.0
|
seed
|
int | None
|
Seed for the complete two-read sequence. |
None
|
include_truth
|
bool
|
Attach the noise-free electron expectation of the difference, i.e.
the charge collected during |
True
|
Returns:
| Type | Description |
|---|---|
Frame
|
Signed difference frame in ADU ( |
Source code in src/getframes/camera.py
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 | |
expose(photon_rate, exposure, temperature=None, *, background=0.0, quantum_efficiency=None, extra_electrons=0.0, binning=1, binning_mode='digital', seed=None, include_truth=True, workspace=None, out=None)
¶
Expose the sensor to an incident photon rate and return a frame.
This is the general signal path; :meth:dark_frame, :meth:flat_frame,
and :meth:bias_frame are convenience wrappers around it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
photon_rate
|
PhotonRate
|
Incident photon rate in photons/s/pixel, as a scalar (uniform
illumination) or a 2-D array matching :attr: |
required |
exposure
|
float
|
Integration time in seconds. |
required |
temperature
|
float | None
|
Sensor temperature in degrees Celsius. Defaults to
:attr: |
None
|
background
|
PhotonRate
|
Additive background (sky/thermal) photon rate in photons/s/pixel. |
0.0
|
quantum_efficiency
|
float | None
|
Overrides the config's scalar QE for this exposure. Spectral mode uses
this with an already-photoelectron map and |
None
|
extra_electrons
|
PhotonRate
|
Additive noise-free signal in electrons (scalar or array) injected
before shot noise. Used by :meth: |
0.0
|
binning
|
int
|
Combine |
1
|
binning_mode
|
str
|
|
'digital'
|
seed
|
int | None
|
If given, use a fresh generator seeded with this value for a fully reproducible frame. |
None
|
include_truth
|
bool
|
If |
True
|
workspace
|
DetectorWorkspace | None
|
Optional reusable :class: |
None
|
out
|
Any | None
|
Optional C-contiguous, writable backend-native |
None
|
Source code in src/getframes/camera.py
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | |
expose_spectral(photon_rate_cube, wavelengths_nm, exposure, temperature=None, *, background=0.0, seed=None, binning=1, binning_mode='digital', include_truth=True, workspace=None, out=None)
¶
Expose a wavelength-resolved photon-rate cube.
photon_rate_cube is incident photons/s/native pixel with shape
(n_wavelength, height, width). The configured :class:~getframes.spectral.QE
is evaluated at each node and applied before the ordinary detector signal
chain. The detector stochastic model is therefore executed exactly once;
FrameTruth.mean_photoelectrons contains the QE-weighted result while
FrameTruth.photon_rate retains the integrated incident photon map.
This method is separate from :meth:expose so scalar callers remain
unchanged and callers cannot accidentally apply QE twice. A configured
qe_curve is required. workspace and out have the same
reusable-scratch and caller-owned-lifetime contracts as :meth:expose.
Source code in src/getframes/camera.py
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | |
correlated_double_sample_spectral(photon_rate_cube, wavelengths_nm, exposure, temperature=None, *, background=0.0, pedestal_interval_s=0.0, seed=None, include_truth=True)
¶
Read a wavelength-resolved photon-rate cube in correlated double sampling.
This is :meth:correlated_double_sample for the spectral path, and
stands in the same relation to it as :meth:expose_spectral does to
:meth:expose: the configured :class:~getframes.spectral.QE is
evaluated at each wavelength node and folded in before the detector
signal chain runs once, so callers cannot apply QE twice.
photon_rate_cube is incident photons/s/native pixel with shape
(n_wavelength, height, width). A configured qe_curve is required.
The return is the signed int32 ADU difference described in
:meth:correlated_double_sample.
Source code in src/getframes/camera.py
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 | |
flat_frame(photon_rate, exposure, temperature=None, *, background=0.0, seed=None, include_truth=True)
¶
A uniformly (or per-pixel) illuminated flat-field frame.
Equivalent to :meth:expose; provided as a named entry point for
flat-field/photon-transfer workflows. Pass a scalar photon_rate for a
uniform flat.
Source code in src/getframes/camera.py
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 | |
bias_frame(temperature=None, *, seed=None)
¶
A zero-exposure bias frame (bias pedestal + read noise only).
Source code in src/getframes/camera.py
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | |
observe(scene, exposure, temperature=None, *, seed=None, include_truth=True)
¶
Observe a :class:~getframes.scene.Scene and return a science frame.
Renders the scene to an incident photon-rate map, then exposes the sensor
to it (adding the scene's sky as a uniform background). The scene's
shape must match this camera's :attr:resolution.
Spectral mode activates automatically when this camera's config has a
:attr:~getframes.config.CameraConfig.qe_curve and the scene's band
carries a spectral response: each source then gets a colour-dependent
effective QE from its SED, instead of the scalar quantum_efficiency.
Source code in src/getframes/camera.py
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 | |
expose_series(photon_rate, exposure, n_frames, temperature=None, *, background=0.0, quantum_efficiency=None, binning=1, binning_mode='digital', seed=None, include_truth=True)
¶
Yield n_frames independent illuminated frames (the :meth:expose series).
The light-frame analogue of :meth:dark_series. When seed is given the
series is reproducible; each frame uses a distinct derived seed so the
frames are independent but the whole series repeats. quantum_efficiency
has the same meaning as in :meth:expose; pass 1.0 when
photon_rate and background are already expressed as electron rates.
binning and binning_mode are passed through to :meth:expose, so a
calibration series bins exactly as its science frames do.
Source code in src/getframes/camera.py
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | |
observe_series(scene, exposure, n_frames, temperature=None, *, cadence=None, pointing=None, jitter_arcsec=0.0, seed=None, include_truth=True)
¶
Observe scene over time, returning a reproducible :class:Observation.
Produces a time-ordered stack of science frames. Frame i is exposed at
timestamp t_i = i * cadence (the start of its exposure); sources
carrying a :class:~getframes.scene.sources.LightCurve vary accordingly,
and a :class:~getframes.observation.Pointing model shifts the field per
frame. If the detector has a non-zero
:attr:~getframes.config.CameraConfig.persistence_fraction, latent charge
is carried across frames.
The returned :class:Observation is iterable over its frames (so
for f in cam.observe_series(...) still works) and carries the per-frame
timestamps, realised pointing offsets, and the ground-truth light curve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
Scene
|
As in :meth: |
required |
exposure
|
Scene
|
As in :meth: |
required |
temperature
|
Scene
|
As in :meth: |
required |
n_frames
|
int
|
Number of frames in the series. |
required |
cadence
|
float | None
|
Seconds between successive frame start times. Defaults to |
None
|
pointing
|
Pointing | None
|
A :class: |
None
|
jitter_arcsec
|
float
|
Convenience for the common case: the RMS of a per-frame Gaussian
pointing jitter (ignored if |
0.0
|
seed
|
int | None
|
When given, the series is reproducible; each frame draws a distinct derived seed (independent frames) and the pointing jitter uses its own derived stream, so the whole observation repeats exactly. |
None
|
include_truth
|
bool
|
Whether to attach per-frame :class: |
True
|
Source code in src/getframes/camera.py
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | |
master_bias(n_frames, temperature=None, *, seed=None, method='median')
¶
Combine n_frames bias frames into a master bias (see :func:getframes.combine).
Source code in src/getframes/camera.py
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | |
master_dark(exposure, n_frames, temperature=None, *, seed=None, method='median')
¶
Combine n_frames dark frames into a master dark.
The result still contains the bias pedestal, so it is subtracted directly
from an exposure-matched science frame (calibrate(sci, dark=master)).
Source code in src/getframes/camera.py
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 | |
master_flat(photon_rate, exposure, n_frames, temperature=None, *, background=0.0, bias=None, seed=None, method='median')
¶
Combine n_frames flat frames into a master flat.
If bias is given it is subtracted, yielding a pedestal-free flat whose
pixel-to-pixel structure is the detector's response — the form
:func:getframes.calibrate expects to normalise and divide by.
Source code in src/getframes/camera.py
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 | |
CameraConfig¶
getframes.config.CameraConfig
dataclass
¶
Physical and electronic parameters of a camera/detector.
All electron quantities are in electrons (e-); all digital quantities are
in analog-to-digital units (ADU, sometimes called counts or DN).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable identifier (e.g. |
required |
sensor_type
|
SensorType
|
One of :class: |
required |
resolution
|
tuple[int, int]
|
Sensor size as |
required |
roi
|
tuple[int, int, int, int] | None
|
Optional detector region of interest as |
None
|
pixel_size_um
|
float
|
Physical pixel pitch in microns. Informational; not used for dark frames. |
required |
quantum_efficiency
|
float
|
Band-averaged quantum efficiency in |
required |
qe_curve
|
QE | None
|
Optional wavelength-resolved quantum efficiency
(:class: |
None
|
supported_binnings
|
tuple[int, ...]
|
Integer pixel-binning factors this sensor supports (must include |
(1,)
|
binning_method
|
str
|
How this sensor combines binned pixels: |
'digital'
|
full_well_e
|
float
|
Image-area (input) full-well capacity in electrons. Collected charge saturates here before any EM/avalanche multiplication stage. |
required |
output_full_well_e
|
float | None
|
Optional post-multiplication output-register capacity in electrons. This
limits amplified charge before conversion to ADU. |
None
|
bit_depth
|
int
|
ADC resolution in bits. The output saturates at |
required |
gain_e_per_adu
|
float
|
Camera conversion gain in electrons per ADU. Electrons reaching the ADC are divided by this to produce counts. |
required |
bias_offset_adu
|
float
|
Electronic offset (pedestal) added to every pixel, in ADU. |
required |
read_noise_e
|
float
|
RMS read noise in electrons. When |
required |
avalanche_input_noise_e
|
float
|
RMS per-read noise in input-referred electrons that scales with the mean
avalanche gain. This empirical term captures gain-dependent tunnelling or
multiplication-region noise that is not part of the output-amplifier
|
0.0
|
avalanche_input_noise_gain_exponent
|
float
|
Optional sublinear gain scaling of the avalanche-noise output RMS. The
ordinary input-referred result is multiplied by |
1.0
|
avalanche_input_noise_reference_gain
|
float
|
Optional sublinear gain scaling of the avalanche-noise output RMS. The
ordinary input-referred result is multiplied by |
1.0
|
read_noise_nonuniformity
|
float
|
Fractional pixel-to-pixel spread of the read-noise RMS (e.g. The resulting per-pixel RMS is a fixed property of the sensor (drawn from
|
0.0
|
read_noise_rts_fraction
|
float
|
Fraction of pixels belonging to a second, noisier read-noise population,
in |
0.0
|
read_noise_rts_factor
|
float
|
Multiplier applied to the read-noise RMS of the RTS population selected by
|
2.5
|
readout_channel_count
|
int
|
Number of interleaved video-output channels. Channel |
1
|
readout_channel_axis
|
int
|
Detector axis carrying the interleaved channel assignment: |
1
|
read_noise_channel_nonuniformity
|
float
|
Log-normal fractional spread of read-noise RMS between interleaved output
channels. The factors have unit mean and are fixed by
|
0.0
|
read_noise_edge_factor
|
float
|
Multiplicative rise in read-noise RMS at the detector boundary and its
exponential falloff scale in pixels. A factor of |
1.0
|
read_noise_edge_scale_px
|
float
|
Multiplicative rise in read-noise RMS at the detector boundary and its
exponential falloff scale in pixels. A factor of |
1.0
|
readout_common_mode_noise_adu
|
float
|
Frame-wide electronic offset noise RMS in ADU. Unlike the fixed bias map,
this scalar is redrawn for each ordinary frame and therefore survives a
master bias. |
0.0
|
readout_common_mode_correlation
|
float
|
Lag-one correlation coefficient of common-mode noise in
:meth: |
0.0
|
ndr_bias_offset_adu_per_s
|
float
|
Read-interval-dependent pedestal coefficients for nondestructive sequences.
The added pedestal is |
0.0
|
ndr_bias_gain_coefficient_adu_per_s
|
float
|
Read-interval-dependent pedestal coefficients for nondestructive sequences.
The added pedestal is |
0.0
|
ndr_common_mode_gain_noise_adu_per_s
|
float
|
Additional frame-wide common-mode RMS in an NDR sequence, equal to this
coefficient times |
0.0
|
ndr_avalanche_input_noise_reference_interval_s
|
float
|
|
1.0
|
ndr_avalanche_input_noise_interval_exponent
|
float
|
Optional read-rate scaling of |
0.0
|
ndr_reset_settling_input_e
|
float
|
|
0.0
|
ndr_reset_settling_scale_reads
|
float
|
|
0.0
|
ndr_reset_settling_reference_interval_s
|
float
|
Input-referred amplitude and exponential read-index scale of the negative
pedestal transient immediately following a global reset. The first read
is lowered by |
1.0
|
ndr_reset_settling_interval_exponent
|
float
|
Input-referred amplitude and exponential read-index scale of the negative
pedestal transient immediately following a global reset. The first read
is lowered by |
1.0
|
detector_glow_edge_scale_px
|
float
|
Exponential falloff scale, in pixels, of the |
0.0
|
nonlinearity
|
float
|
Fractional signal compression at full well, in |
0.0
|
nonlinearity_coeffs
|
tuple[float, ...] | None
|
Optional polynomial generalisation of |
None
|
cti
|
float
|
Charge-transfer inefficiency (CTI) of a CCD, the fraction of charge left
behind per pixel-to-pixel transfer during readout, in |
0.0
|
blooming
|
bool
|
When |
False
|
ipc_coupling
|
float
|
Inter-pixel capacitance (IPC): the fraction of each pixel's signal that
couples capacitively into each of its four nearest neighbours at readout,
in |
0.0
|
charge_diffusion_fwhm_px
|
float
|
Lateral charge-diffusion FWHM in native pixels. Photo-electrons random
walk in the silicon before reaching a potential well, so the collected
charge is the incident irradiance convolved with this Gaussian and only
then integrated over each pixel's area. It is applied only by
:func: |
0.0
|
reset_noise_e
|
float
|
kTC / reset noise RMS in electrons. Ordinary exposures draw an independent
per-pixel Gaussian; nondestructive reads share one draw per reset ramp.
|
0.0
|
read_noise_correlated_fraction
|
float
|
Fraction of the read-noise variance that is common to every read of a
nondestructive ramp, and therefore cancels when two reads are
differenced. Read noise measured from a single read is not all white. Reference-level
drift, bias settling, and 1/f components persist across the microseconds
between two reads of a correlated-double-sampling pair, and differencing
removes them --- which is the entire reason CDS is used. A detector
whose single-read noise is R and whose correlated fraction is Fitting this from single-read data alone is impossible: only a
differenced measurement separates the correlated part. Take it from a
CDS measurement, or leave it at |
0.0
|
amplifier_layout
|
tuple[int, int]
|
Multi-amplifier readout as |
(1, 1)
|
amplifier_boundaries_y_px
|
tuple[int, ...]
|
Optional exact internal amplifier split coordinates on the full detector.
Empty tuples divide |
()
|
amplifier_boundaries_x_px
|
tuple[int, ...]
|
Optional exact internal amplifier split coordinates on the full detector.
Empty tuples divide |
()
|
amplifier_gain_factors
|
tuple[float, ...] | None
|
Optional exact row-major multiplicative conversion-gain factors, one per
amplifier. These override stochastic |
None
|
amplifier_offsets_adu
|
tuple[float, ...] | None
|
Optional exact row-major additive bias offsets in ADU, one per amplifier.
These override stochastic |
None
|
amp_gain_nonuniformity
|
float
|
Fractional RMS spread of per-amplifier gain about |
0.0
|
amp_offset_spread_adu
|
float
|
RMS spread of per-amplifier bias offset in ADU, about |
0.0
|
cosmic_ray_track_length_px
|
float
|
Mean length in pixels of cosmic-ray tracks. |
0.0
|
bad_column_fraction
|
float
|
Fraction of columns that are defective (dead): a fixed, deterministic set of
whole columns forced to zero signal in every frame — the bad columns a flat
cannot rescue. |
0.0
|
dead_pixel_fraction
|
float
|
Fraction of individual pixels that are dead (zero response), a fixed map.
|
0.0
|
bias_structure_amplitude_adu
|
float
|
Peak amplitude in ADU of a fixed, structured bias pattern (a smooth gradient
plus per-column offsets) added on top of the flat |
0.0
|
bias_channel_spread_adu
|
float
|
RMS fixed offset in ADU between the interleaved readout channels. Requires
|
0.0
|
bias_pixel_spread_adu
|
float
|
RMS fixed pixel-scale bias texture in ADU, drawn once from
|
0.0
|
bias_edge_amplitude_adu
|
float
|
Additive fixed pedestal at the detector boundary and its exponential
falloff scale in pixels. |
0.0
|
bias_edge_scale_px
|
float
|
Additive fixed pedestal at the detector boundary and its exponential
falloff scale in pixels. |
0.0
|
bias_edge_axis
|
float
|
Additive fixed pedestal at the detector boundary and its exponential
falloff scale in pixels. |
0.0
|
bias_edge_secondary_amplitude_adu
|
float
|
|
0.0
|
bias_edge_secondary_scale_px
|
float
|
|
0.0
|
bias_edge_secondary_axis
|
int | None
|
Optional second exponential edge pedestal. This represents detectors with a broad halo on one axis and a weaker, narrower halo on the other. |
None
|
cosmic_ray_rate_per_cm2_s
|
float
|
Cosmic-ray hit rate in events per cm^2 per second (sea level is ~5). The number of hits scales with sensor area and exposure; each deposits a burst of charge in a random pixel. |
0.0
|
prnu
|
float
|
Photo-response non-uniformity: fractional pixel-to-pixel variation in
sensitivity (e.g. |
0.0
|
dark_current_e_per_s
|
float
|
Dark current in electrons per pixel per second, specified at
|
required |
detector_glow_e_per_s
|
float
|
Detector self-emission ("glow") in electrons per pixel per second, added to
the dark signal (it scales with exposure and so is removed by an
exposure-matched master dark). A uniform model of amplifier/array glow,
relevant for IR arrays alongside the thermal background. |
0.0
|
dark_current_ref_temp_c
|
float
|
Temperature (deg C) at which |
20.0
|
dark_current_doubling_temp_c
|
float
|
Temperature increase (deg C) that doubles the dark current. Typical CCD/CMOS silicon values are 5-8 C. |
6.3
|
em_gain
|
float
|
Mean gain of the stochastic multiplication stage: the EM register of an
EMCCD or the avalanche gain of an eAPD. |
1.0
|
avalanche_gain_nonuniformity
|
float
|
Fixed pixel-to-pixel avalanche-gain variation per natural logarithm of
physical gain. The resulting log-normal multiplier has fractional width
|
0.0
|
excess_noise_factor
|
float | None
|
Excess noise factor |
None
|
clock_induced_charge_e
|
float
|
Clock-induced charge (spurious charge) in electrons per pixel per frame. Relevant mainly for EMCCD. |
0.0
|
persistence_fraction
|
float
|
Fraction of a frame's collected charge captured into traps as a latent
image (image persistence), in |
0.0
|
persistence_decay
|
float
|
Fraction of the trapped charge released each subsequent frame, in
|
0.5
|
dark_current_nonuniformity
|
float
|
Fractional pixel-to-pixel dark-signal non-uniformity (DSNU), e.g. |
0.0
|
hot_pixel_fraction
|
float
|
Fraction of pixels that are "hot" (anomalously high dark current). |
0.0
|
hot_pixel_factor
|
float
|
Multiplicative dark-current factor applied to hot pixels. |
100.0
|
fixed_pattern_seed
|
int
|
Seed for the sensor's fixed-pattern noise (PRNU, DSNU, hot-pixel,
read-noise scale, channel-offset, and bias-structure maps). These patterns
are a property of the physical sensor, so they are the
same in every frame this camera produces --- which is exactly what lets a
master flat or dark capture and remove them. Two configs with the same seed
and shape share a pattern; change it to mint a different sensor. Independent
of the per-frame |
0
|
manufacturer
|
str | None
|
Optional provenance metadata. |
None
|
model
|
str | None
|
Optional provenance metadata. |
None
|
notes
|
str | None
|
Optional provenance metadata. |
None
|
Source code in src/getframes/config.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | |
max_adu
property
¶
The saturation value of the ADC output.
output_resolution
property
¶
Unbinned camera output shape, accounting for an optional ROI.
roi_slices
property
¶
Full-detector array slices selecting the configured ROI.
active_amplifier_boundaries_y_px
property
¶
Amplifier row splits translated into coordinates of the active ROI.
active_amplifier_boundaries_x_px
property
¶
Amplifier column splits translated into coordinates of the active ROI.
has_gain_stage
property
¶
Whether a stochastic multiplication stage (EM/avalanche) is active.
gain_excess_noise_factor
property
¶
The effective excess noise factor F of the gain stage.
Returns :attr:excess_noise_factor if set, else a sensible default for the
sensor type: sqrt(2) for EMCCD (the high-gain limit) and 1.0
(noiseless) otherwise.
dark_current_at(temperature_c)
¶
Dark current (e-/pixel/s) scaled to temperature_c.
Uses the standard doubling-temperature model::
D(T) = D_ref * 2 ** ((T - T_ref) / T_double)
Source code in src/getframes/config.py
781 782 783 784 785 786 787 788 789 790 | |
replace(**changes)
¶
Return a copy with the given fields overridden (like dataclasses.replace).
Source code in src/getframes/config.py
792 793 794 795 796 | |
to_dict()
¶
Serialise to a plain dict (sensor_type rendered as its string value).
Source code in src/getframes/config.py
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | |
from_dict(data)
classmethod
¶
Build a config from a dict, ignoring unknown keys (stashed in extra).
A qe_curve may be given as a :class:~getframes.spectral.QE or as a
mapping {"wavelength_nm": [...], "qe": [...]} (the form used in preset
TOML files).
Source code in src/getframes/config.py
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | |
SensorType¶
getframes.config.SensorType
¶
Bases: str, Enum
The detector architecture, which selects the noise model used.
Source code in src/getframes/config.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
coerce(value)
classmethod
¶
Accept either a :class:SensorType or a case-insensitive string.
Source code in src/getframes/config.py
28 29 30 31 32 33 34 35 36 37 | |
Frame¶
getframes.frame.Frame
dataclass
¶
A single simulated image plus the metadata describing how it was made.
The pixel values live in :attr:data as a 2-D NumPy or CuPy array in ADU.
np.asarray(frame) remains an explicit request for host NumPy storage and
therefore copies a GPU frame; use frame.data to keep processing on device.
Attributes:
| Name | Type | Description |
|---|---|---|
data |
Any
|
2-D array of pixel values in ADU, shaped |
metadata |
dict[str, Any]
|
Free-form dictionary describing the simulation (camera name, exposure, temperature, frame type, etc.). Suitable for writing to a FITS header. |
truth |
FrameTruth | None
|
Optional :class: |
Source code in src/getframes/frame.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
device
property
¶
Storage device for :attr:data ("cpu" or "gpu").
binned(factor, *, method='sum')
¶
Digitally bin the frame into factor x factor super-pixels after readout.
Models post-read (digital) binning: a read-out image is combined into
coarser pixels in software, rather than charge being summed on-chip before
the amplifier. With method="sum" the ADU of each factor x factor
block are added (the charge-combining convention, which also sums the bias
pedestal and read noise in quadrature); method="mean" averages them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factor
|
int
|
Positive integer block size. Both image dimensions must be divisible by it. |
required |
method
|
str
|
|
'sum'
|
Returns:
| Name | Type | Description |
|---|---|---|
Frame |
Frame
|
A new frame of shape |
Source code in src/getframes/frame.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | |
stats()
¶
Common host summary statistics (copies GPU data to NumPy).
Source code in src/getframes/frame.py
137 138 139 140 141 142 143 144 145 146 | |
to_fits(path, overwrite=False)
¶
Write the frame to a FITS file (requires astropy).
Metadata keys are written to the FITS header where they fit the 8-character keyword and value-type constraints.
Source code in src/getframes/frame.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
getframes.frame.FrameTruth
dataclass
¶
Noise-free ground truth a :class:Frame was generated from.
Useful for validating analysis pipelines against exactly what went in. All arrays are in electrons unless noted, shaped like the frame.
Attributes:
| Name | Type | Description |
|---|---|---|
mean_electrons |
Any
|
Noise-free total signal (photo + dark) per pixel, in electrons. This is the expectation value before shot noise, gain, and read noise. |
mean_photoelectrons |
Any
|
Noise-free photo signal per pixel, in electrons (i.e. excluding dark). |
photon_rate |
Any
|
The incident photon rate the frame was exposed to, in photons/s/pixel, as provided by the caller (a scalar for uniform illumination, else an array). |
spectral_photon_rate |
Any | None
|
Optional wavelength-resolved incident photon-rate cube with shape
|
wavelengths_nm |
Any | None
|
Wavelength nodes corresponding to |
Source code in src/getframes/frame.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | |
Array backends¶
getframes.backend.ArrayBackend
dataclass
¶
Array namespace and RNG factory for one detector execution device.
Source code in src/getframes/backend.py
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
is_cpu
property
¶
Whether arrays live in host NumPy storage.
asarray(value, *, dtype=None)
¶
Convert value to an array on this backend.
Source code in src/getframes/backend.py
79 80 81 | |
default_rng(seed=None, *, float_dtype=np.float64)
¶
Create a backend-native random generator.
Source code in src/getframes/backend.py
83 84 85 86 87 88 89 90 91 | |
convolve(array, kernel)
¶
Convolve with constant-zero boundary conditions on this backend.
Source code in src/getframes/backend.py
93 94 95 96 97 98 99 100 101 | |
scalar(value)
¶
Transfer one scalar to the host for validation or metadata.
Source code in src/getframes/backend.py
103 104 105 106 | |
to_numpy(value)
¶
Copy an array to host NumPy storage at an explicit boundary.
Source code in src/getframes/backend.py
108 109 110 111 112 | |
getframes.backend.get_backend(device='cpu')
¶
Return the backend for device ("cpu" or "gpu").
CuPy is an optional dependency and is imported lazily only for "gpu".
"cuda" and "cupy" are accepted aliases.
Source code in src/getframes/backend.py
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
getframes.backend.get_array_module(value)
¶
Return NumPy or CuPy for an existing array without copying it.
Source code in src/getframes/backend.py
136 137 138 139 140 141 | |
getframes.backend.to_numpy(value)
¶
Return value in host NumPy storage, copying device arrays explicitly.
Source code in src/getframes/backend.py
144 145 146 147 | |
Reusable detector execution¶
getframes.noise.DetectorWorkspace
¶
Reusable private scratch storage for repeated detector simulations.
A workspace is lazy: its arrays are allocated only when a compatible call to
:func:simulate_frame or :meth:getframes.Camera.expose needs them. It may
be reused sequentially, but not concurrently. Returned frame and truth
arrays never alias workspace storage; only an explicit caller-owned out
array is returned without a copy.
One workspace binds to the detector shape, working dtype, backend, and CUDA device of its first use. Construct a separate workspace for a different camera geometry or execution device.
Source code in src/getframes/noise.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
Charge diffusion¶
getframes.noise.charge_diffusion_kernel(fwhm_px, *, oversampling)
¶
Return a flux-normalized lateral charge-diffusion kernel.
The detector diffusion profile is represented by a circular Gaussian whose
full width at half maximum is fwhm_px native pixels. Each returned tap is
the Gaussian probability integrated over one focal-plane sample cell, rather
than a point sample, and the finite four-sigma support is renormalized to unit
sum. The kernel is intended for an oversampled focal-plane irradiance before
native detector pixels collect charge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fwhm_px
|
float
|
Lateral diffusion FWHM in native detector pixels. Zero returns an identity
|
required |
oversampling
|
int
|
Focal-plane samples per native detector pixel. A nonzero width must span at least one sample at FWHM so the configured detector property cannot silently collapse to a numerical no-op. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Odd, square, symmetric |
Source code in src/getframes/noise.py
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | |
getframes.noise.apply_charge_diffusion(values, fwhm_px, *, oversampling, backend=None)
¶
Diffuse an oversampled irradiance map before pixel-area integration.
values is a two-dimensional irradiance or photon-rate map, or a batch of
such maps, sampled at oversampling cells per native detector pixel. The
returned map has the same shape and dtype. A zero width leaves values
untouched. Charge that diffuses off the supplied map is lost at its edge.
Use this before summing focal-plane samples into native pixels. It accepts CPU NumPy and optional GPU CuPy arrays; the public kernel itself remains a portable NumPy array for callers that use another convolution implementation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Any
|
Two-dimensional irradiance or photon-rate map, or a leading batch of maps, on the oversampled focal-plane grid. |
required |
fwhm_px
|
float
|
Gaussian lateral charge-diffusion FWHM in native detector pixels. |
required |
oversampling
|
int
|
Number of focal-plane grid samples per native detector pixel. |
required |
backend
|
ArrayBackend | None
|
Array backend containing |
None
|
Returns:
| Type | Description |
|---|---|
array
|
Diffused array on the same backend, with the input shape and dtype. |
Source code in src/getframes/noise.py
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | |
Calibration¶
getframes.calibrate
¶
Calibration: combine frames into masters and reduce raw frames against them.
These helpers close the loop the library is built for: generate raw frames (each
optionally carrying :class:~getframes.frame.FrameTruth), then reduce them with
master calibration frames and compare the result to the ground truth.
The reduction follows the standard, exposure-matched CCD equation::
reduced = (raw - dark) / normalised(flat)
where dark is an exposure-matched master dark (which still contains the bias
pedestal, so subtracting it removes bias and dark current together) and flat is
a pedestal-free master flat (see :meth:getframes.Camera.master_flat). Pass
bias instead of dark to subtract only the bias pedestal.
combine(frames, *, method='median', sigma=3.0)
¶
Combine a stack of frames pixel-wise into a single master frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
Iterable[FrameLike]
|
An iterable of :class: |
required |
method
|
str
|
|
'median'
|
sigma
|
float
|
Clipping threshold for |
3.0
|
Returns:
| Type | Description |
|---|---|
Frame
|
The master frame (ADU, |
Source code in src/getframes/calibrate.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
calibrate(raw, *, bias=None, dark=None, flat=None, dark_scale=1.0)
¶
Reduce a raw frame with master calibration frames.
Performs, in order: subtract the additive pedestal (an exposure-matched master
dark if given, else a bias), then divide by the normalised flat::
out = raw - dark_scale * dark # or raw - bias if no dark
out = out / (flat / mean(flat))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw
|
FrameLike
|
The frame to reduce (a :class: |
required |
bias
|
FrameLike | None
|
Master bias. Subtracted only when |
None
|
dark
|
FrameLike | None
|
Exposure-matched master dark (including bias). Subtracted from |
None
|
flat
|
FrameLike | None
|
Pedestal-free master flat. Divided out after normalising it to unit mean, so only its relative pixel-to-pixel response remains. |
None
|
dark_scale
|
float
|
Multiplier applied to |
1.0
|
Returns:
| Type | Description |
|---|---|
Frame
|
The reduced frame ( |
Source code in src/getframes/calibrate.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
Presets¶
getframes.presets
¶
Built-in library of camera/detector presets.
Presets are stored as TOML files in :mod:getframes.presets.data. They are loaded
lazily and cached. Add a new camera by dropping a <name>.toml file into that
directory (see the existing files for the schema) — no code changes required.
available_presets()
¶
Return the sorted list of available preset names.
from getframes import available_presets "andor_ikon_m934" in available_presets() True
Source code in src/getframes/presets/__init__.py
38 39 40 41 42 43 44 45 | |
preset_info()
¶
Return lightweight descriptors (name, manufacturer, model, sensor_type) for each preset.
Source code in src/getframes/presets/__init__.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | |
load_preset(name)
¶
Load a preset by name and return a :class:~getframes.config.CameraConfig.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
A preset slug, e.g. |
required |
Source code in src/getframes/presets/__init__.py
75 76 77 78 79 80 81 82 83 84 85 86 87 | |
Scene & optics¶
getframes.scene.scene.Scene
dataclass
¶
A focal-plane scene that renders to an incident photon-rate map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
tuple[int, int]
|
Output size as |
required |
optics
|
Telescope
|
The :class: |
required |
psf
|
PSF
|
The :class: |
required |
sources
|
Sequence[Source]
|
The sources in the field (point, extended, catalog, or uniform). |
tuple()
|
sky
|
Sky | None
|
Optional uniform sky background. |
None
|
thermal
|
Thermal | None
|
Optional :class: |
None
|
wcs
|
WCSInfo | None
|
Optional :class: |
None
|
Source code in src/getframes/scene/scene.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
is_spectral_capable
property
¶
Whether this scene's band carries a spectral response for spectral mode.
add(*sources)
¶
Append one or more sources to the scene.
Source code in src/getframes/scene/scene.py
68 69 70 | |
photon_rate_map(time_s=None, offset_xy=(0.0, 0.0), dtype=np.float64)
¶
Render the sources through the PSF into a photons/s/pixel map.
This is the incident rate at the detector before quantum efficiency; the camera applies QE, dark current, and noise when it exposes the scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_s
|
float | None
|
Optional observation time in seconds. When set, sources carrying a
:class: |
None
|
offset_xy
|
tuple[float, float]
|
A whole-field pointing offset |
(0.0, 0.0)
|
dtype
|
DTypeLike
|
Output (and working) floating-point dtype. |
float64
|
Source code in src/getframes/scene/scene.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
sky_photon_rate()
¶
Uniform sky background in photons/s/pixel (0 if no sky is set).
Source code in src/getframes/scene/scene.py
141 142 143 144 145 | |
thermal_photon_rate()
¶
Uniform thermal (graybody) background in photons/s/pixel (0 if unset).
Source code in src/getframes/scene/scene.py
147 148 149 150 151 | |
photoelectron_rate_map(qe_curve, time_s=None, offset_xy=(0.0, 0.0), dtype=np.float64)
¶
Render sources to a photoelectron-rate map (e-/s/pixel) in spectral mode.
Like :meth:photon_rate_map, but each source's incident photon rate is
multiplied by the colour-dependent effective QE for its SED (folding the
detector qe_curve with the band's spectral response). The result is
already in photoelectrons, so the camera applies a unit QE downstream.
time_s and offset_xy behave as in :meth:photon_rate_map.
Requires a band with a spectral response (see :attr:is_spectral_capable).
Source code in src/getframes/scene/scene.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
sky_electron_rate(qe_curve)
¶
Uniform sky background in photoelectrons/s/pixel for spectral mode.
Source code in src/getframes/scene/scene.py
181 182 183 184 185 186 187 188 | |
thermal_electron_rate(qe_curve)
¶
Uniform thermal background in photoelectrons/s/pixel for spectral mode.
Source code in src/getframes/scene/scene.py
190 191 192 193 194 195 196 197 | |
background_photon_rate()
¶
Total uniform background (sky + thermal) in photons/s/pixel.
Source code in src/getframes/scene/scene.py
199 200 201 | |
background_electron_rate(qe_curve)
¶
Total uniform background (sky + thermal) in photoelectrons/s/pixel (spectral).
Source code in src/getframes/scene/scene.py
203 204 205 | |
getframes.scene.sources.PointSource
dataclass
¶
Bases: Source
An unresolved point source (e.g. a star) at pixel position (x, y).
Specify the brightness in exactly one of two ways:
magnitude--- converted to a photon rate by the telescope's bandpass, orphoton_rate--- photons/s already arriving at the detector (post-optics, pre-quantum-efficiency), handy when you know the flux directly (e.g. an AO sub-aperture).
x is the column and y the row, in pixels; sub-pixel positions are fine.
sed is an optional spectral energy distribution
(:class:~getframes.spectral.SED). It is used only in spectral mode, to give
the source a colour-dependent effective QE; it has no effect on the integrated
photon rate (the magnitude sets that). Defaults to a flat photon spectrum.
brightness is an optional :class:LightCurve. When set, the source's
photon rate is multiplied by brightness(t) at each timestamp sampled by
:meth:getframes.Camera.observe_series, making the source variable in time.
A static :meth:getframes.Camera.observe (no time) ignores it.
name is an optional label used to key the source in an observation's
per-frame truth light curve.
flux_sed is an alternative to magnitude/photon_rate: an absolute
:class:~getframes.spectral.SED (SED.from_flux_density) whose integral over
the band sets the photon rate directly (true spectral flux integration). When
given it also serves as the colour SED for spectral mode.
Source code in src/getframes/scene/sources.py
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | |
getframes.scene.sources.ExtendedSource
dataclass
¶
Bases: Source
A resolved source rendered from an analytic Sersic profile or a pixel array.
Place it by pixel (x, y) or, with a scene :class:~getframes.scene.wcs.WCSInfo,
by sky (ra_deg, dec_deg). Total brightness is set by magnitude or an
explicit photon_rate (exactly one), as for :class:PointSource; the profile
distributes that total flux over pixels and is normalised to conserve it.
Construct via :meth:sersic (a Sersic surface-brightness profile, optionally
elliptical) or :meth:from_array (an arbitrary normalised image, e.g. a galaxy
cutout). The profile is rendered directly to the focal plane and is not
additionally convolved with the scene PSF --- supply a pre-convolved array, or
rely on the profile being broad compared with the PSF.
Source code in src/getframes/scene/sources.py
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | |
position_angle
property
¶
Position angle of the major axis, in degrees (alias of the field).
sersic(*, x=None, y=None, ra=None, dec=None, magnitude=None, photon_rate=None, n=1.0, r_eff_arcsec, ellipticity=0.0, position_angle_deg=0.0, sed=None, brightness=None, name=None, flux_sed=None)
classmethod
¶
A Sersic profile I(r) ~ exp(-b_n[(r/r_eff)^(1/n) - 1]).
n=1 is an exponential disk, n=4 a de Vaucouleurs bulge. ellipticity
(1 - b/a) and position_angle_deg (of the major axis, measured
counter-clockwise from the +x axis) shape an elliptical isophote.
Source code in src/getframes/scene/sources.py
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | |
from_array(image, *, x=None, y=None, ra=None, dec=None, magnitude=None, photon_rate=None, sed=None, brightness=None, name=None, flux_sed=None)
classmethod
¶
An arbitrary 2D image (e.g. a galaxy cutout) used as the profile.
The array is normalised to unit sum and pasted centred on the source position at detector-pixel resolution, then scaled to the total flux.
Source code in src/getframes/scene/sources.py
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | |
getframes.scene.sources.UniformIllumination
dataclass
¶
Bases: Source
A spatially flat illumination of photon_rate photons/s/pixel.
A clean, PSF-free flat field --- the natural input for a photon-transfer curve
(PTC) or for building synthetic flats. brightness and sed behave as for
other sources (time variability and spectral effective QE).
Source code in src/getframes/scene/sources.py
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | |
getframes.scene.sources.Catalog
dataclass
¶
Bases: Source
Many point sources sharing a PSF, SED, and optional light curve.
Build one from a table with :meth:from_table. Entries may be placed by pixel
(x, y) or by sky (ra, dec); sky coordinates are projected to pixels
through the scene's :class:~getframes.scene.wcs.WCSInfo, so a Gaia/2MASS-style
catalogue drops straight into a WCS-tagged scene. The whole catalogue is keyed
by a single :attr:name in observation truth (its summed flux).
Source code in src/getframes/scene/sources.py
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | |
from_table(table, *, magnitude=None, photon_rate=None, x=None, y=None, ra=None, dec=None, sed=None, brightness=None, name=None)
classmethod
¶
Build a catalogue from column names of table.
table is anything column-indexable by name (an astropy Table, a
pandas DataFrame, or a dict of arrays). Give the brightness column as
magnitude or photon_rate, and the position columns as either
(x, y) pixels or (ra, dec) degrees.
Source code in src/getframes/scene/sources.py
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | |
getframes.scene.sources.Sky
dataclass
¶
A uniform sky background of a given surface brightness.
The :class:~getframes.scene.scene.Scene treats the sky specially: it is added
by the camera as a uniform background rather than deposited into the rendered
source map, and is therefore not affected by vignetting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
surface_brightness_mag_arcsec2
|
float
|
Sky brightness in magnitudes per square arcsecond (fainter = larger). |
required |
sed
|
SED | None
|
Optional spectral energy distribution for the sky, used only in spectral mode for the sky's effective QE. Defaults to a flat photon spectrum. |
None
|
Source code in src/getframes/scene/sources.py
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | |
getframes.scene.thermal.Thermal
dataclass
¶
A graybody thermal background from warm optics/enclosure.
Models the thermal emission seen by the detector as a graybody of emissivity
:attr:emissivity at temperature :attr:temperature_k, integrated over the
telescope band into a per-pixel photon rate. Attach it to a
:class:~getframes.scene.scene.Scene (scene.thermal = Thermal(...)) and it
is added as a uniform background by :meth:getframes.Camera.observe, like the
sky but dominant in the thermal infrared.
Computing the rate requires the telescope band to carry a spectral
response (the graybody is integrated over it).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
temperature_k
|
float
|
Graybody temperature in kelvin (e.g. ~273--293 K for a warm enclosure). |
required |
emissivity
|
float
|
Effective emissivity in |
1.0
|
Source code in src/getframes/scene/thermal.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
photon_rate(optics)
¶
Thermal background in photons/s/pixel reaching the detector through optics.
emissivity * Omega_pixel * A_collect * int L_ph(lambda, T) T_band(lambda)
dlambda, with Omega_pixel the per-pixel solid angle and A_collect
the collecting area. Requires a band with a spectral response.
Source code in src/getframes/scene/thermal.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
photon_sed(wavelength_min_nm=300.0, wavelength_max_nm=3000.0, n_samples=256)
¶
A relative SED of the graybody photon spectrum (for spectral effective QE).
Source code in src/getframes/scene/thermal.py
102 103 104 105 106 107 108 109 110 111 | |
getframes.scene.optics.Telescope
dataclass
¶
An optical system that turns source magnitudes into photon rates at the focal plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
aperture_diameter_m
|
float
|
Primary aperture diameter in metres. |
required |
plate_scale_arcsec_per_pixel
|
float
|
Angular size of one detector pixel, in arcseconds. |
required |
throughput
|
float
|
End-to-end fraction of photons transmitted (optics x filter x atmosphere),
in |
1.0
|
central_obstruction
|
float
|
Diameter of the central obstruction as a fraction of the aperture diameter
(e.g. the secondary mirror); |
0.0
|
band
|
Bandpass | None
|
The :class: |
None
|
vignetting
|
Vignetting | None
|
Optional :class: |
None
|
distortion
|
RadialDistortion | None
|
Optional :class: |
None
|
Source code in src/getframes/scene/optics.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
collecting_area_m2
property
¶
Unobstructed collecting area in square metres.
pixel_solid_angle_arcsec2
property
¶
Solid angle subtended by one pixel, in square arcseconds.
illumination_map(shape)
¶
Relative illumination map for shape (None if no vignetting set).
Source code in src/getframes/scene/optics.py
121 122 123 124 125 | |
unit(plate_scale_arcsec_per_pixel=1.0)
classmethod
¶
A trivial 1 m, unit-throughput telescope.
Handy when you supply source photon rates directly (already at the detector) and only need a plate scale --- e.g. AO sub-aperture simulations.
Source code in src/getframes/scene/optics.py
127 128 129 130 131 132 133 134 135 136 137 138 | |
photon_rate_from_magnitude(magnitude)
¶
Photons/s reaching the detector from a point source of this magnitude.
Source code in src/getframes/scene/optics.py
151 152 153 154 155 156 157 158 | |
photon_rate_from_sed(sed)
¶
Photons/s at the detector from a source described by an absolute SED.
Integrates the SED over the band's spectral response
(:meth:~getframes.scene.photometry.Bandpass.photon_flux_from_sed) and
scales by collecting area and throughput --- the spectral-flux-integration
counterpart of :meth:photon_rate_from_magnitude. Requires a band with a
spectral response and an absolute SED
(:meth:getframes.spectral.SED.from_flux_density).
Source code in src/getframes/scene/optics.py
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
surface_brightness_photon_rate(surface_brightness_mag_arcsec2)
¶
Photons/s/pixel from a uniform sky of the given surface brightness.
Source code in src/getframes/scene/optics.py
177 178 179 180 | |
getframes.scene.optics.Vignetting
dataclass
¶
A radial illumination falloff toward the edges of the field.
Relative illumination is 1 - strength * (r / r_corner)^power, where r is
the distance from the optical centre and r_corner is the distance to the
farthest corner. strength is the fractional light loss at that corner;
power=2 gives a gentle quadratic roll-off (power=4 approximates the cos^4
law). The map is clipped to [0, 1].
Source code in src/getframes/scene/optics.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
illumination_map(shape)
¶
Relative illumination in [0, 1] for a frame of (height, width).
Source code in src/getframes/scene/optics.py
40 41 42 43 44 45 46 47 48 49 50 51 | |
getframes.scene.optics.RadialDistortion
dataclass
¶
A simple radial (barrel/pincushion) distortion about the field centre.
A source at pixel distance r from the centre is displaced to
r * (1 + k1 r^2 + k2 r^4). k1 < 0 gives barrel distortion, k1 > 0
pincushion; both coefficients carry inverse-pixel-power units (k1 is small,
e.g. 1e-7 per pixel^2 for a 2k detector).
Source code in src/getframes/scene/optics.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
apply(x, y, cx, cy)
¶
Map pixel (x, y) to its distorted position about centre (cx, cy).
Source code in src/getframes/scene/optics.py
67 68 69 70 71 72 | |
getframes.scene.photometry.Bandpass
dataclass
¶
A photometric band, summarised by its photon zero point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label, e.g. |
required |
photon_zeropoint
|
float
|
Photons per second per square metre, above the atmosphere, from a magnitude-0 source integrated over the band. |
required |
response
|
SpectralBandpass | None
|
Optional spectral transmission curve for the band. Enables spectral mode
(colour-dependent effective QE); |
None
|
Source code in src/getframes/scene/photometry.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
johnson(band, *, spectral=True)
classmethod
¶
Return a Vega-system band (U B V R I, or 2MASS J H Ks).
By default the band also carries a tophat spectral response so spectral
mode works out of the box; pass spectral=False for the bare zero point.
U through I carry representative textbook band-integrated photon
zero points. J, H, and Ks are derived from the 2MASS absolute
calibration instead, so near-infrared work does not have to leave the
Vega system to reach a defensible zero point. Use :meth:ab for the AB
system, which is a different magnitude for the same star.
Source code in src/getframes/scene/photometry.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | |
ab(band)
classmethod
¶
Return an AB-system band for a common survey filter.
The AB system references every band to a flat :math:f_\nu = 3631
Jy source, so the zero point is computed from the band's transmission
shape (see :func:_ab_photon_zeropoint) rather than tabulated. Supported
band names (case-insensitive): SDSS u g r i z, Gaia
gaia_g gaia_bp gaia_rp (also G BP RP), and 2MASS J H Ks. Each
carries a tophat spectral response, so spectral mode works out of the box;
supply a measured curve via :meth:SpectralBandpass.from_file for rigour.
Gaia bands are gaia_g, gaia_bp, gaia_rp (bp/rp also
accepted); g is SDSS g. Use :meth:johnson for the Vega system instead.
Source code in src/getframes/scene/photometry.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
photon_flux(magnitude)
¶
Photons/s/m^2 above the atmosphere for a source of the given magnitude.
Source code in src/getframes/scene/photometry.py
192 193 194 | |
photon_flux_from_sed(sed)
¶
Photons/s/m^2 above the atmosphere from an absolute SED through this band.
Integrates int S(lambda) T(lambda) dlambda over the band's spectral
response, where S is the absolute photon flux density
(photons/s/m^2/nm) of an SED built with
:meth:getframes.spectral.SED.from_flux_density. This is the "true spectral
flux integration" path: the spectrum itself sets the rate, rather than a
magnitude. Requires a spectral :attr:response.
Source code in src/getframes/scene/photometry.py
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
effective_qe(qe, sed=None)
¶
Photon-weighted effective QE for a source of SED sed seen through this band.
Requires a spectral :attr:response. sed defaults to a flat photon
spectrum (the bandpass-weighted mean QE). See
:func:getframes.spectral.effective_qe.
Source code in src/getframes/scene/photometry.py
217 218 219 220 221 222 223 224 225 226 227 228 229 | |
getframes.scene.photometry.Extinction
dataclass
¶
Interstellar extinction (reddening) by intervening dust.
A Cardelli, Clayton & Mathis (1989) extinction curve, parameterised by the
visual extinction a_v (magnitudes of attenuation in V) and the total-to-
selective ratio r_v (3.1 for the diffuse Galactic ISM). It dims and reddens a
source: redder dust passes more light, so a blue source is attenuated more.
Use :meth:transmission for the wavelength-dependent throughput
10**(-0.4 A(lambda)), :meth:redden to apply it to an
:class:~getframes.spectral.SED, or :meth:band_attenuation_mag for the
band-integrated magnitude shift to add to a source magnitude.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a_v
|
float
|
Visual extinction |
required |
r_v
|
float
|
Total-to-selective extinction ratio |
3.1
|
Source code in src/getframes/scene/photometry.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
attenuation_mag(wavelength_nm)
¶
Extinction A(lambda) in magnitudes at each wavelength (nm).
Wavelengths outside the CCM89 range (~303--3333 nm) are clamped to the nearest valid value.
Source code in src/getframes/scene/photometry.py
305 306 307 308 309 310 311 312 313 314 | |
transmission(wavelength_nm)
¶
Fractional transmission 10**(-0.4 A(lambda)) at each wavelength (nm).
Source code in src/getframes/scene/photometry.py
316 317 318 | |
transmission_curve(wavelength_nm)
¶
The transmission as a :class:~getframes.spectral.Spectrum (for :func:product).
Source code in src/getframes/scene/photometry.py
320 321 322 323 | |
redden(sed)
¶
Apply extinction to sed, returning a reddened copy (units preserved).
Source code in src/getframes/scene/photometry.py
325 326 327 328 | |
band_attenuation_mag(band, sed=None)
¶
Band-integrated extinction in magnitudes through band for a source sed.
The photon-weighted mean attenuation,
-2.5 log10(int S T 10^{-0.4 A} dl / int S T dl), evaluated on the band's
response grid. sed defaults to a flat photon spectrum. Add the result to
a source magnitude to dim it by the dust column. Requires a spectral
:attr:~Bandpass.response.
Source code in src/getframes/scene/photometry.py
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
getframes.scene.wcs.WCSInfo
dataclass
¶
A tangent-plane (TAN) world coordinate system for a detector frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
crval_ra_deg
|
float
|
Sky coordinates (degrees) of the reference point. |
required |
crval_dec_deg
|
float
|
Sky coordinates (degrees) of the reference point. |
required |
crpix_x
|
float
|
Pixel coordinates of the reference point, in 0-based array convention
( |
required |
crpix_y
|
float
|
Pixel coordinates of the reference point, in 0-based array convention
( |
required |
plate_scale_arcsec_per_pixel
|
float
|
Angular pixel size, matching the telescope's plate scale. |
required |
rotation_deg
|
float
|
Position angle of the y-axis east of north, in degrees ( |
0.0
|
Source code in src/getframes/scene/wcs.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
header_cards()
¶
FITS WCS header cards for a TAN projection (8-char keywords, no astropy).
RA increases to the left (east), so CD1_1 carries the sign flip. The
rotation is folded into the CD matrix.
Source code in src/getframes/scene/wcs.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
to_astropy()
¶
Build an :class:astropy.wcs.WCS (requires astropy).
Source code in src/getframes/scene/wcs.py
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | |
pixel_to_world(x, y)
¶
Convert a 0-based pixel (x, y) to (ra_deg, dec_deg) (needs astropy).
Source code in src/getframes/scene/wcs.py
99 100 101 102 | |
world_to_pixel(ra_deg, dec_deg)
¶
Convert (ra_deg, dec_deg) to a 0-based pixel (x, y) (needs astropy).
Source code in src/getframes/scene/wcs.py
104 105 106 107 | |
getframes.scene.psf
¶
Point-spread functions: how a point source's flux is spread over pixels.
Each PSF knows how to add a source of a given total flux at a sub-pixel position into an image, conserving flux. Models are evaluated on a small stamp around the source for efficiency. The Gaussian uses the exact per-pixel integral (via the error function) so it is flux-conserving to machine precision; the Moffat is sampled on a stamp and normalised.
PSF
¶
Base class for point-spread functions.
Source code in src/getframes/scene/psf.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
add_source(image, x, y, flux, plate_scale_arcsec_per_pixel)
¶
Add flux photons/s of a point source at sub-pixel (x, y) into image.
Source code in src/getframes/scene/psf.py
43 44 45 46 47 48 49 50 51 52 | |
add_sources(image, xs, ys, fluxes, plate_scale_arcsec_per_pixel)
¶
Add many point sources at once (vectorised where the PSF supports it).
xs, ys, fluxes are equal-length 1-D arrays of sub-pixel column,
row, and total flux. The generic implementation loops over
:meth:add_source; subclasses (e.g. :class:GaussianPSF) override it with a
batched, chunked evaluation so a large :class:~getframes.scene.sources.Catalog
does not pay a Python-level per-source loop.
Source code in src/getframes/scene/psf.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
GaussianPSF
dataclass
¶
Bases: PSF
A circular Gaussian PSF specified by its full width at half maximum.
Source code in src/getframes/scene/psf.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
add_sources(image, xs, ys, fluxes, plate_scale_arcsec_per_pixel)
¶
Vectorised, chunked deposition of many Gaussian point sources.
Builds every source's exact per-pixel error-function integral on a common
stamp in one batched NumPy expression and scatter-adds it into image,
replacing the Python per-source loop. Identical pixel values to repeated
:meth:add_source calls (flux off the frame is clipped the same way). Work
is chunked over sources to keep the intermediate (chunk, stamp, stamp)
buffer bounded for very large catalogues.
Source code in src/getframes/scene/psf.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
MoffatPSF
dataclass
¶
Bases: PSF
A Moffat PSF, a better match to seeing-limited stars than a Gaussian.
The beta parameter controls the wings: smaller beta gives broader wings
(beta -> infinity approaches a Gaussian). beta ~ 3 is typical for
atmospheric seeing.
Source code in src/getframes/scene/psf.py
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | |
EllipticalGaussianPSF
dataclass
¶
Bases: PSF
An elliptical Gaussian PSF with independent major/minor widths and an angle.
position_angle_deg is the angle of the major axis, measured counter-clockwise
from the +x axis. The profile is sampled on a stamp and normalised (not the exact
error-function integral the circular :class:GaussianPSF uses), so flux is
conserved to the sampling accuracy.
Source code in src/getframes/scene/psf.py
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | |
AiryPSF
dataclass
¶
Bases: PSF
The diffraction-limited Airy pattern of a circular aperture.
Models a space- or AO-corrected diffraction-limited core: the intensity is
[2 J1(x)/x]^2 with x = pi * D * theta / lambda, optionally including a
central obstruction of fractional diameter obstruction. The first dark ring
sits at theta = 1.22 lambda / D. Sampled on a stamp and normalised.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
aperture_diameter_m
|
float
|
Aperture diameter in metres (sets the angular scale of the pattern). |
required |
wavelength_m
|
float
|
Observing wavelength in metres. |
required |
obstruction
|
float
|
Central-obstruction diameter as a fraction of the aperture, in |
0.0
|
Source code in src/getframes/scene/psf.py
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
ArrayPSF
dataclass
¶
Bases: PSF
A user-supplied PSF kernel, e.g. straight from an AO/optics simulation.
The kernel is a 2D array sampled at detector-pixel resolution; it is
normalised to unit sum on construction. Sub-pixel source positions are handled by
a first-order (bilinear) shift of the kernel before it is pasted, so the centroid
lands at the requested location. Flux falling off the frame is clipped.
Source code in src/getframes/scene/psf.py
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | |
Time series¶
getframes.scene.sources.LightCurve
dataclass
¶
A time-varying brightness multiplier for a source.
A light curve maps a time t (seconds, measured from the start of an
observation) to a dimensionless factor that multiplies the source's baseline
brightness. A constant 1.0 leaves the source unchanged; 0.99 during a
transit dims it by 1%.
Time variability is owned by the source (see :attr:PointSource.brightness):
:meth:getframes.Camera.observe_series samples the curve at each frame's
timestamp, so the injected signal is reproducible and recorded in the
observation's per-frame truth.
Construct one with a factory (:meth:box, :meth:sinusoidal,
:meth:constant) or wrap any callable with :meth:from_function. The instance
itself is callable: lc(t) returns the multiplier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[[float], float]
|
Callable mapping time in seconds to a non-negative brightness multiplier. |
required |
Source code in src/getframes/scene/sources.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |
constant(level=1.0)
classmethod
¶
A flat light curve at level (default 1.0, i.e. no variation).
Source code in src/getframes/scene/sources.py
119 120 121 122 | |
box(depth, t0, t1, baseline=1.0)
classmethod
¶
A box-shaped dip of fractional depth between times t0 and t1.
Outside [t0, t1) the multiplier is baseline; inside it is
baseline * (1 - depth). A simple model of a flat-bottomed transit
(depth=0.01 for a 1% transit).
Source code in src/getframes/scene/sources.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
sinusoidal(amplitude, period_s, *, phase=0.0, baseline=1.0)
classmethod
¶
A sinusoid: baseline + amplitude * sin(2*pi*t/period + phase).
Models a pulsating or rotating variable. amplitude is in the same units
as baseline (i.e. a fraction of the unit baseline); keep
amplitude <= baseline to stay non-negative.
Source code in src/getframes/scene/sources.py
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
from_function(func)
classmethod
¶
Wrap an arbitrary t -> multiplier callable as a light curve.
Source code in src/getframes/scene/sources.py
166 167 168 169 | |
getframes.observation.Observation
dataclass
¶
A reproducible stack of frames of one scene over time.
Returned by :meth:getframes.Camera.observe_series. It is iterable and
indexable over its :attr:frames, so existing for frame in obs: style code
keeps working, while :attr:truth, :attr:times_s, and :attr:offsets_pixels
expose the time and pointing information.
Attributes:
| Name | Type | Description |
|---|---|---|
frames |
list[Frame]
|
The realised science :class: |
times_s |
NDArray[float64]
|
Frame timestamps in seconds, shape |
offsets_pixels |
NDArray[float64]
|
The realised pointing offset |
truth |
ObservationTruth | None
|
The :class: |
Source code in src/getframes/observation.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | |
getframes.observation.ObservationTruth
dataclass
¶
The noise-free ground truth of an :class:Observation.
Attributes:
| Name | Type | Description |
|---|---|---|
times_s |
NDArray[float64]
|
The frame timestamps, in seconds from the start of the observation,
shape |
light_curve |
dict[str, NDArray[float64]]
|
Per-source injected signal: a mapping from source name to an array of the
noise-free incident photons collected from that source in each frame
(photon rate x exposure, post-optics, pre-quantum-efficiency), shape
|
Source code in src/getframes/observation.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
getframes.observation.Pointing
dataclass
¶
A per-frame pointing model: jitter, slow drift, and a programmed dither.
The three components combine additively into a whole-field offset applied to every source in the scene at each frame. Offsets are specified in arcseconds (converted to pixels with the scene's plate scale) so the model is independent of the detector sampling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jitter_arcsec
|
float
|
RMS of a per-frame Gaussian offset drawn independently for each axis and
each frame. Models random tracking jitter and atmospheric tip-tilt / image
motion (e.g. for AO sub-apertures). |
0.0
|
drift_arcsec_per_s
|
tuple[float, float]
|
A constant |
(0.0, 0.0)
|
dither_arcsec
|
Sequence[tuple[float, float]] | None
|
An optional sequence of programmed |
None
|
Source code in src/getframes/observation.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | |
is_static
property
¶
Whether this model never moves the field (a no-op pointing).
offset_pixels(frame_index, time_s, plate_scale_arcsec_per_pixel, rng)
¶
The realised (dx, dy) offset in pixels for one frame.
Combines drift (deterministic in time_s), the cycled dither entry, and a
fresh Gaussian jitter draw, then converts arcseconds to pixels.
Source code in src/getframes/observation.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | |
Spectral mode¶
getframes.spectral
¶
Wavelength-resolved primitives for the opt-in spectral mode.
The band-integrated model (a scalar quantum efficiency and a single photon zero point per band) is accurate enough for exposure planning, but it cannot capture how a detector's response colour interacts with a source's spectral energy distribution (SED). Spectral mode adds that, additively, through three tabulated curves on a shared wavelength axis (nanometres):
- :class:
SED--- a source's spectral photon flux density (shape only; the absolute level is still set by the source magnitude), - :class:
SpectralBandpass--- a filter/optics transmission response in[0, 1], - :class:
QE--- a detector quantum-efficiency curve in[0, 1].
The single physical quantity spectral mode computes is the effective quantum efficiency a source sees,
.. math::
\mathrm{QE}_\mathrm{eff} =
\frac{\int S(\lambda)\,T(\lambda)\,\mathrm{QE}(\lambda)\,d\lambda}
{\int S(\lambda)\,T(\lambda)\,d\lambda},
a photon-weighted average of :math:\mathrm{QE}(\lambda) over the band. It is a
ratio, so it is invariant to the absolute normalisation of both the SED and the
bandpass --- which is why spectral mode needs no absolute reference spectrum and
leaves the magnitude-to-photon-rate conversion (governed by the band zero point)
untouched. Only the photon-to-electron conversion is refined.
Everything here is pure NumPy and free of randomness.
Spectrum
dataclass
¶
A tabulated, non-negative curve value(wavelength_nm).
Values are linearly interpolated within the sampled range and treated as zero
outside it. The wavelength axis is in nanometres and must be strictly
increasing. This base class carries the shared sampling/integration machinery;
:class:SED, :class:SpectralBandpass, and :class:QE add units and
constructors.
Source code in src/getframes/spectral.py
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
__call__(wavelength_nm)
¶
Interpolate the curve at wavelength_nm (zero outside the sampled range).
Source code in src/getframes/spectral.py
112 113 114 115 | |
from_file(path, *, wavelength_to_nm=1.0, delimiter=None, skiprows=0, usecols=(0, 1))
classmethod
¶
Load a two-column (wavelength, value) curve from a text file.
Reads path with :func:numpy.loadtxt. The first column is scaled by
wavelength_to_nm to nanometres (e.g. 0.1 for angstroms, 1000 for
microns); the second is taken verbatim. Handy for measured filter, QE, or
atmospheric-transmission curves --- combine several with :func:product or
:meth:SpectralBandpass.from_product.
Source code in src/getframes/spectral.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | |
integrate()
¶
Trapezoidal integral of the curve over wavelength (nm).
Source code in src/getframes/spectral.py
140 141 142 | |
SED
dataclass
¶
Bases: Spectrum
A source's spectral photon flux density.
Two flavours, distinguished by :attr:is_absolute:
- Relative (the default; :meth:
from_arraysand the parametric shapes). Only the shape matters: spectral mode uses it to colour-weight the quantum efficiency, a calculation invariant to overall scale (the source magnitude still sets the absolute photon rate). - Absolute (:meth:
from_flux_density): values are a true photon flux density inphotons/s/m^2/nmabove the atmosphere. Such an SED can set the integrated photon rate directly --- pass it to a source asflux_sedand the telescope integrates it over the band (see :meth:getframes.scene.photometry.Bandpass.photon_flux_from_sed), instead of deriving the rate from a magnitude.
Source code in src/getframes/spectral.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | |
from_arrays(wavelength_nm, photon_flux)
classmethod
¶
A relative SED sampled at wavelength_nm with photon flux density (shape only).
Source code in src/getframes/spectral.py
223 224 225 226 | |
from_flux_density(wavelength_nm, photon_flux_density)
classmethod
¶
An absolute SED: photon_flux_density in photons/s/m^2/nm.
Unlike :meth:from_arrays, the absolute scale is meaningful: integrated over
a band it yields a photon rate, so a source carrying this as flux_sed has
its brightness set by the spectrum itself (no magnitude needed). Wavelengths
and flux may be plain arrays (nm and photons/s/m^2/nm) or astropy.units
quantities, which are converted.
Source code in src/getframes/spectral.py
228 229 230 231 232 233 234 235 236 237 238 | |
flat(wavelength_min_nm=_DEFAULT_WL_MIN_NM, wavelength_max_nm=_DEFAULT_WL_MAX_NM)
classmethod
¶
A flat photon spectrum (equal photons per unit wavelength).
The neutral default: with a flat SED the effective QE is simply the
bandpass-weighted mean of QE(lambda).
Source code in src/getframes/spectral.py
240 241 242 243 244 245 246 247 248 249 250 251 252 | |
blackbody(temperature_k, wavelength_min_nm=_DEFAULT_WL_MIN_NM, wavelength_max_nm=_DEFAULT_WL_MAX_NM, n_samples=256)
classmethod
¶
A blackbody photon spectrum at temperature_k (relative units).
Photon spectral radiance ~ lambda**-4 / (exp(hc / lambda k T) - 1) --- the
Planck law expressed per photon rather than per unit energy. Good for giving
a star a colour (e.g. 5800 K for a sun-like source, 3500 K for a cool
M dwarf, 10000 K for a hot blue star).
Source code in src/getframes/spectral.py
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | |
power_law(index, reference_wavelength_nm=550.0, wavelength_min_nm=_DEFAULT_WL_MIN_NM, wavelength_max_nm=_DEFAULT_WL_MAX_NM, n_samples=64)
classmethod
¶
A power-law photon spectrum (lambda / lambda_ref)**index (relative).
Source code in src/getframes/spectral.py
278 279 280 281 282 283 284 285 286 287 288 289 | |
QE
dataclass
¶
Bases: Spectrum
A detector quantum-efficiency curve, QE(lambda) in [0, 1].
Source code in src/getframes/spectral.py
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | |
from_arrays(wavelength_nm, qe)
classmethod
¶
A QE curve sampled at wavelength_nm with values in [0, 1].
Source code in src/getframes/spectral.py
300 301 302 303 | |
constant(value, wavelength_min_nm=_DEFAULT_WL_MIN_NM, wavelength_max_nm=_DEFAULT_WL_MAX_NM)
classmethod
¶
A flat QE curve --- equivalent to the scalar quantum_efficiency.
Source code in src/getframes/spectral.py
305 306 307 308 309 310 311 312 313 314 315 316 | |
SpectralBandpass
dataclass
¶
A filter/optics transmission response T(lambda) in [0, 1].
Carries the spectral shape of a band, used to colour-weight the effective QE.
It does not replace a :class:~getframes.scene.photometry.Bandpass's scalar
photon zero point (which still sets the magnitude-to-photon conversion); it
refines the photon-to-electron step.
Source code in src/getframes/spectral.py
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | |
pivot_wavelength_nm
property
¶
The pivot wavelength: sqrt(int T dl / int T l^-2 dl) (nm).
mean_wavelength_nm
property
¶
The throughput-weighted mean wavelength (nm).
from_arrays(wavelength_nm, throughput)
classmethod
¶
A response curve sampled at wavelength_nm with throughput in [0, 1].
Source code in src/getframes/spectral.py
331 332 333 334 335 336 337 | |
from_file(path, **kwargs)
classmethod
¶
Load a two-column (wavelength, throughput) response from a text file.
Thin wrapper over :meth:Spectrum.from_file (same wavelength_to_nm,
delimiter, skiprows, usecols options); throughput must be in
[0, 1].
Source code in src/getframes/spectral.py
339 340 341 342 343 344 345 346 347 348 349 350 | |
from_product(*items)
classmethod
¶
Fold several transmission curves into one combined band response.
Each item is a :class:SpectralBandpass or a bare :class:Spectrum (e.g. a
:class:QE curve or an atmospheric-transmission curve); their pointwise
product over the common wavelength support becomes the new response. This is
how a real filter x QE x atmosphere transmission product is assembled.
Source code in src/getframes/spectral.py
352 353 354 355 356 357 358 359 360 361 362 363 364 365 | |
tophat(center_nm, width_nm, peak=1.0)
classmethod
¶
A flat-topped band of full width width_nm centred on center_nm.
Soft (one-sample) shoulders keep the curve continuous for integration.
Source code in src/getframes/spectral.py
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | |
johnson(band)
classmethod
¶
A tophat approximation of a Vega-system band.
One of Johnson-Cousins U B V R I or 2MASS J H Ks.
Source code in src/getframes/spectral.py
401 402 403 404 405 406 407 408 409 410 411 412 | |
overlap_integral(*spectra)
¶
Integrate the pointwise product of several spectra over their common range.
Returns 0.0 when the spectra do not overlap (the product is zero there).
Source code in src/getframes/spectral.py
171 172 173 174 175 176 177 178 179 180 181 182 | |
product(*spectra)
¶
Pointwise product of several spectra as a new :class:Spectrum.
The result is sampled on the union of the inputs' knots within their common wavelength support, where the product of piecewise-linear curves is exact --- outside that support at least one factor is zero. The natural way to fold a measured filter transmission, detector QE, and atmospheric transmission into a single response curve. Raises if the inputs do not overlap.
Source code in src/getframes/spectral.py
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | |
effective_qe(qe, bandpass, sed=None)
¶
Photon-weighted effective quantum efficiency a source sees through a band.
Computes int S T QE dl / int S T dl over the wavelength range common to the
SED, bandpass, and QE curve. sed defaults to a flat photon spectrum, giving
the bandpass-weighted mean QE. The result is a dimensionless number in
[0, 1] and is invariant to the absolute scale of both S and T.
Source code in src/getframes/spectral.py
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | |
Analysis helpers¶
getframes.analysis.apertures
¶
Lightweight photometry helpers used by the examples and for quick analysis.
These are intentionally minimal (pure NumPy, no extra dependencies). For serious
photometry on real pipelines, reach for photutils; these exist so the bundled
examples stay self-contained and readable.
aperture_sum(image, center, r, *, annulus=None)
¶
Background-subtracted sum within radius r of center = (x, y).
The background level is the median of a surrounding annulus (default: from
r + 2 to r + 5 pixels), scaled to the number of aperture pixels. Pass
annulus=(inner, outer) to control it, or annulus=(0, 0) to skip
background subtraction.
Source code in src/getframes/analysis/apertures.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
centroid(image, *, center=None, r=None, background=None, threshold=None)
¶
Intensity-weighted (thresholded) centroid (x, y) of image.
This is a calibrated centre-of-gravity estimator suitable for a real-time controller: subtract a background, subtract a noise-floor threshold, clip the remaining negative weights, optionally restrict to a window, then take first moments. With scalar arguments it reduces to the plain background-subtracted centroid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
center
|
tuple[float, float] | None
|
If both are given, only pixels within radius |
None
|
r
|
tuple[float, float] | None
|
If both are given, only pixels within radius |
None
|
background
|
float | NDArray[floating[Any]] | None
|
Level subtracted before weighting, so the pedestal doesn't bias the
centroid. A scalar, or a per-pixel array (e.g. a master sky+dark frame of
the same shape as |
None
|
threshold
|
float | NDArray[floating[Any]] | None
|
Optional noise floor subtracted after the background and before clipping,
so pixels that are only noise do not pull the centroid. A scalar, or a
per-pixel array (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
(x, y):
|
Sub-pixel centroid. Returns the geometric centre if there is no positive signal after background and threshold subtraction. |
Source code in src/getframes/analysis/apertures.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | |
matched_filter_centroid(image, template, *, background=None)
¶
Centroid image by cross-correlating it with a reference template.
This is useful for compact, low-SNR spots such as Shack--Hartmann wavefront-
sensor images. The returned (x, y) is the template's intensity centroid
shifted by the peak of the full, linear cross-correlation. A three-point
parabolic fit along each axis refines the integer correlation peak to sub-pixel
precision.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
NDArray[floating[Any] | integer[Any]]
|
Non-empty 2-D arrays. They need not have the same shape, although the template normally contains the expected spot at its reference position. |
required |
template
|
NDArray[floating[Any] | integer[Any]]
|
Non-empty 2-D arrays. They need not have the same shape, although the template normally contains the expected spot at its reference position. |
required |
background
|
float | None
|
Constant level subtracted from |
None
|
Returns:
| Type | Description |
|---|---|
(x, y):
|
Estimated absolute centroid in the image's pixel-coordinate system. |
Notes
The method assumes approximately white pixel noise. For strongly non-uniform detector noise, pre-whiten the image and template before calling this helper.
Source code in src/getframes/analysis/apertures.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
getframes.analysis.ptc
¶
Photon transfer curve (PTC): characterise a camera from synthetic flats.
The PTC is the standard way to measure a detector's conversion gain. This module
generates flat pairs at a range of light levels, builds the variance-vs-mean
curve, and fits the gain --- turning the workflow in
examples/06_photon_transfer_curve.py into a one-liner.
PTCResult
dataclass
¶
The outcome of :func:photon_transfer_curve.
Attributes:
| Name | Type | Description |
|---|---|---|
mean_adu, variance_adu2 |
The measured photon transfer curve: per-level mean signal and noise variance, both in ADU. |
|
gain_e_per_adu |
float
|
Conversion gain fitted from the shot-noise-limited region (slope = 1/gain). |
read_noise_e |
float
|
Read noise measured from a pair of bias frames. |
full_well_adu |
float | None
|
Mean signal at which the variance peaks (onset of saturation), or |
Source code in src/getframes/analysis/ptc.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
photon_transfer_curve(camera, levels, exposure=1.0, *, temperature=None, seed=0)
¶
Measure a photon transfer curve for camera over the given flux levels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
Camera
|
The camera to characterise. |
required |
levels
|
NDArray[float64]
|
Incident photon rates (photons/s/pixel) to sample, ascending. Span from a few electrons up past saturation to capture the full curve. |
required |
exposure
|
float
|
Exposure time for each flat, in seconds. |
1.0
|
temperature
|
float | None
|
Sensor temperature; defaults to the camera's operating temperature. |
None
|
seed
|
int
|
Base seed; each flat uses a distinct derived seed for reproducibility. |
0
|
Source code in src/getframes/analysis/ptc.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
getframes.analysis.characterize
¶
Detector characterisation from frame stacks --- real or simulated.
:mod:~getframes.analysis.ptc characterises a simulated camera by driving it.
This module works the other way round: hand it stacks of frames that already
exist --- raw data off a real detector, or output from :class:~getframes.Camera
--- and it measures the detector parameters back out. The result carries a
:meth:DarkCharacterization.to_config so a real camera can be turned into a
:class:~getframes.CameraConfig and then simulated.
The two entry points mirror the two standard bench measurements:
characterize_dark
Dark stacks at several exposure times. Returns conversion gain, read noise
(including its per-pixel distribution), dark current, bias offset and DSNU.
characterize_flat
Flat-field stacks at several illumination levels. Returns conversion gain,
read noise, full well, PRNU and linearity.
Measuring gain from darks alone works because dark current is a Poisson process, so thermally generated charge is a perfectly good charge source for a photon transfer curve. For a dark frame::
mean_ADU(t) = bias + D*t/g
var_ADU(t) = RN_ADU**2 + D*t/g**2
so the slope of variance against mean is 1/g and the dark rate D cancels.
Fitting per pixel makes it immune to DSNU, and fitting a slope across exposures
absorbs the bias pedestal and the read noise into the two intercepts. The
assumption this rests on is that the dark charge is Poisson (Fano factor 1);
:attr:DarkCharacterization.fano_factor reports the consistency check.
All inputs are in ADU; all returned electron quantities are in electrons.
StackStats
dataclass
¶
Per-pixel temporal statistics of one stack of frames, in ADU.
This is the raw material every characterisation is built from: for each pixel, its mean and variance through the stack. Both are full-resolution maps, so detector structure (DSNU, per-pixel read noise, hot pixels) is preserved rather than averaged away.
Attributes:
| Name | Type | Description |
|---|---|---|
mean_adu, variance_adu2 |
Per-pixel temporal mean (ADU) and unbiased variance (ADU^2), each shaped like one frame. |
|
n_frames |
int
|
Number of frames combined. |
exposure_s |
float | None
|
Exposure time of the stack in seconds, or |
half_variance_adu2 |
tuple[NDArray[float64], NDArray[float64]] | None
|
Per-pixel variance of the even- and odd-indexed frames separately, when
|
Source code in src/getframes/analysis/characterize.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | |
shape
property
¶
Frame shape (height, width).
temporal_repeatability
property
¶
Split-half correlation of the per-pixel variance map, in [-1, 1].
Splits the stack into even- and odd-indexed frames, computes each half's per-pixel temporal variance, and correlates the two maps across pixels.
This separates fixed per-pixel noise structure from sampling scatter. A detector whose pixels genuinely differ in read noise --- every sCMOS --- gives a high correlation, because the same pixels are noisy in both halves. A detector with uniform noise gives ~0, because all that differs between halves is chi-squared sampling noise. Real back-illuminated sCMOS measures 0.89--0.94.
The correlation is computed with the most extreme 1% of pixels excluded.
A cosmic ray lands in one half only and inflates that pixel's variance by
orders of magnitude, so on a long-exposure stack a handful of such pixels
dominate the covariance and drive a plain Pearson correlation to zero:
real 60 s Marana darks score 0.006 unclipped against 0.93 clipped. Use
:meth:repeatability for explicit control.
Requires split=True in :func:stack_statistics.
fixed_variance_fraction
property
¶
Fraction of the variance map's spatial spread that is fixed structure.
The observed spatial variance of a variance map is the real pixel-to-pixel
structure plus the chi-squared scatter of estimating a variance from a
finite stack, 2 * <v>**2 / (n - 1). Subtracting the latter leaves the
fraction that is genuine detector structure, in [0, 1].
repeatability(*, clip_percentile=99.0)
¶
:attr:temporal_repeatability with the outlier cut exposed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clip_percentile
|
float
|
Pixels whose variance in either half exceeds this percentile are
excluded before correlating. |
99.0
|
Source code in src/getframes/analysis/characterize.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
DarkCharacterization
dataclass
¶
What a set of dark stacks says about a detector.
Scalars are the median over pixels; the *_map arrays give the per-pixel
values behind them.
Attributes:
| Name | Type | Description |
|---|---|---|
gain_e_per_adu |
float
|
Conversion gain from the per-pixel dark photon transfer curve. |
read_noise_e |
float
|
Median per-pixel read noise, taken from the shortest stack with its dark contribution removed. It therefore includes any exposure-independent common-mode term (frame-to-frame pedestal wander, for instance), which is what a bench measurement would also report. Supply a short enough exposure that read noise dominates it. |
dark_current_e_per_s |
float
|
Median per-pixel dark current, from the slope of mean against exposure. |
bias_offset_adu |
float
|
Median pedestal, from the intercept of mean against exposure. |
dark_current_nonuniformity |
float
|
Robust relative spread (IQR/1.349 over the median) of the per-pixel dark
current --- DSNU, comparable to
:attr: |
read_noise_nonuniformity |
float
|
Log-normal width implied by the read-noise inter-quartile range,
comparable to
:attr: |
read_noise_rts_fraction |
float
|
Fraction of pixels whose read noise exceeds three times the median --- the random-telegraph-signal tail. Around 0.005 on real sCMOS, against ~1e-4 for a pure log-normal. |
hot_pixel_fraction |
float
|
Fraction of pixels whose dark current exceeds ten times the median. |
fano_factor |
float
|
Consistency check on the Poisson assumption the gain fit relies on:
|
exposures_s |
NDArray[float64]
|
The exposure times used, ascending. |
read_noise_map_e, dark_current_map_e_per_s, bias_map_adu |
Per-pixel maps behind the scalars above. |
Source code in src/getframes/analysis/characterize.py
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | |
to_config(name, **overrides)
¶
Build a :class:~getframes.CameraConfig from the measured parameters.
Everything darks can measure is filled in: resolution, gain, bias, read noise (with its non-uniformity and RTS tail), dark current and DSNU. Parameters darks cannot see --- full well, bit depth, pixel pitch, QE --- take documented placeholder defaults that you should override.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name for the resulting config. |
required |
**overrides
|
Any
|
Any :class: |
{}
|
Notes
dark_current_ref_temp_c defaults to 20 C because the stacks carry no
temperature. Set it to the temperature the darks were taken at, or the
config's temperature scaling will be wrong.
Source code in src/getframes/analysis/characterize.py
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | |
FlatCharacterization
dataclass
¶
What a set of flat-field stacks says about a detector.
Attributes:
| Name | Type | Description |
|---|---|---|
gain_e_per_adu |
float
|
Conversion gain from the shot-noise-limited part of the photon transfer
curve (slope of variance against mean is |
read_noise_e |
float
|
Read noise from the faintest stack with its shot-noise term removed. Only
as good as that level is faint; prefer
:attr: |
full_well_adu, full_well_e |
Mean level at which the temporal variance peaks, or |
|
prnu |
float
|
Photo-response non-uniformity: the robust relative pixel-to-pixel spread of response, measured from the highest unsaturated level with the shot noise subtracted off. |
nonlinearity |
float | None
|
Fractional departure of the mean-versus-exposure (or versus level)
response from a straight line, as a fraction of full scale. |
mean_adu, variance_adu2 |
The photon transfer curve itself: per-level mean signal above bias and temporal variance, both in ADU. |
|
levels |
NDArray[float64]
|
The level labels supplied, ascending. |
Source code in src/getframes/analysis/characterize.py
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | |
stack_statistics(frames, *, exposure_s=None, split=False)
¶
Per-pixel temporal mean and variance of a stack of frames.
Frames are consumed one at a time through a Welford accumulator, so an iterator or generator over a stack far larger than memory works fine --- only a handful of frame-sized float64 arrays are ever held.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
Iterable[FrameLike]
|
Any iterable of 2-D frames: NumPy arrays, :class: |
required |
exposure_s
|
float | None
|
Exposure time to label the stack with. Required by
:func: |
None
|
split
|
bool
|
Also accumulate the even- and odd-indexed frames separately, enabling
:attr: |
False
|
Returns:
| Type | Description |
|---|---|
StackStats
|
Per-pixel mean and variance in ADU. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than two frames are supplied (variance is undefined), or if
|
Source code in src/getframes/analysis/characterize.py
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
characterize_dark(stacks)
¶
Measure a detector from dark stacks at several exposure times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stacks
|
Mapping[float, StackStats] | Sequence[StackStats]
|
Either a mapping of |
required |
Returns:
| Type | Description |
|---|---|
DarkCharacterization
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than two distinct exposures are supplied, if the stacks disagree on frame shape, or if any stack lacks an exposure time. |
Notes
The gain comes from a per-pixel regression of temporal variance against
temporal mean, whose slope is 1/gain regardless of that pixel's own dark
current and read noise. Taking the median over pixels makes it robust to
hot pixels and to the read-noise tail. See the module docstring for why
darks suffice, and check :attr:DarkCharacterization.fano_factor before
trusting the result.
Source code in src/getframes/analysis/characterize.py
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | |
characterize_flat(stacks, *, bias_adu=0.0, saturation_fraction=0.9)
¶
Measure a detector from flat-field stacks at several illumination levels.
This is the classical photon transfer curve, computed from stacks you already
have rather than by driving a simulated camera (for that, see
:func:~getframes.analysis.photon_transfer_curve).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stacks
|
Mapping[float, StackStats] | Sequence[StackStats]
|
A mapping of |
required |
bias_adu
|
float
|
Bias pedestal to subtract from the mean levels before fitting. Take it
from :attr: |
0.0
|
saturation_fraction
|
float
|
Fraction of the peak-variance level above which points are excluded from the gain fit, keeping it in the shot-noise-limited region. |
0.9
|
Returns:
| Type | Description |
|---|---|
FlatCharacterization
|
|
Notes
Because these are stacks, the variance used is the per-pixel temporal variance averaged over the array, which is already free of fixed-pattern (PRNU) noise --- no frame differencing is needed. PRNU is then measured separately from the spatial spread of the time-averaged flat.
Source code in src/getframes/analysis/characterize.py
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | |
Datasets & scale¶
getframes.dataset
¶
Scalable raw + ground-truth dataset generation (roadmap phase 1.6).
The library's reason to exist is paired data: a realistic raw frame and the
noise-free signal it was drawn from. :func:pairs turns a camera and a stream of
:class:~getframes.scene.scene.Scene objects into a reproducible sequence of
{"raw": ADU, "truth": electrons} pairs — training data for denoising,
deconvolution, or calibration networks — and streams it to disk in float32
without ever holding the whole set in memory.
:func:random_star_fields is a convenience generator of random star-field scenes
to feed it, but any iterable of scenes (matching the camera's resolution) works.
import getframes as gf cam = gf.Camera.from_preset("andor_ikon_m934", precision="float32") scenes = gf.dataset.random_star_fields(n=4, shape=cam.resolution, seed=0) ds = gf.dataset.pairs(camera=cam, scenes=scenes, exposure=10.0, seed=1) pair = next(iter(ds)) sorted(pair) ['raw', 'truth']
RandomStarFields
¶
A reproducible, re-iterable stream of random star-field :class:Scene objects.
Each scene is a field of uniformly placed point sources with magnitudes drawn
uniformly from mag_range and an optional uniform sky. The number of stars per
field is fixed (int) or drawn per field from a (low, high) range. The
stream is deterministic for a given seed (each field gets its own derived
seed) and can be iterated more than once.
Construct via :func:random_star_fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
Number of scenes in the stream. |
required |
shape
|
tuple[int, int]
|
Scene size |
required |
optics
|
Telescope | None
|
The :class: |
None
|
psf
|
Telescope | None
|
The :class: |
None
|
n_stars
|
int | tuple[int, int]
|
Stars per field — a fixed count, or a |
(20, 200)
|
mag_range
|
tuple[float, float]
|
|
(16.0, 22.0)
|
sky_mag_arcsec2
|
float | None
|
Optional uniform sky surface brightness (mag/arcsec^2); |
21.0
|
seed
|
int | None
|
Base seed; field |
None
|
Source code in src/getframes/dataset.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
PairDataset
¶
A lazy, reproducible sequence of raw + truth pairs (see :func:pairs).
Iterating yields {"raw": ADU, "truth": electrons} dicts, one per input
scene, each cast to :attr:dtype. The stream is single-pass when its scenes are
a one-shot iterator; pass a re-iterable scene source (e.g.
:class:RandomStarFields) to iterate more than once. Materialise to disk with
:meth:to_npz or into stacked arrays with :meth:to_arrays.
Source code in src/getframes/dataset.py
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | |
to_npz(directory, *, prefix='pair', compress=False)
¶
Write each pair to {directory}/{prefix}_{i:06d}.npz and return the paths.
Each archive holds raw (ADU) and truth (electrons) arrays in
:attr:dtype. Streams pair by pair, so the whole set is never resident in
memory. compress uses :func:numpy.savez_compressed.
Source code in src/getframes/dataset.py
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | |
to_arrays()
¶
Stack the whole dataset into (raw, truth) arrays of shape (N, H, W).
Convenient for small sets; holds everything in memory, unlike :meth:to_npz.
Source code in src/getframes/dataset.py
241 242 243 244 245 246 247 248 249 250 251 252 253 | |
random_star_fields(n, shape, *, optics=None, psf=None, n_stars=(20, 200), mag_range=(16.0, 22.0), sky_mag_arcsec2=21.0, seed=None)
¶
Build a reproducible :class:RandomStarFields stream of n star-field scenes.
A convenience source of scenes for :func:pairs; see :class:RandomStarFields
for the parameters.
Source code in src/getframes/dataset.py
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
pairs(*, camera, scenes, exposure, temperature=None, dtype=np.float32, seed=None)
¶
Build a :class:PairDataset of raw + truth pairs from a camera and scenes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera
|
Camera
|
The :class: |
required |
scenes
|
Iterable[Scene]
|
Any iterable of :class: |
required |
exposure
|
float
|
Integration time in seconds for every frame. |
required |
temperature
|
float | None
|
Sensor temperature (deg C); defaults to the camera's. |
None
|
dtype
|
DTypeLike
|
Storage dtype for the |
float32
|
seed
|
int | None
|
Base seed; frame |
None
|
Source code in src/getframes/dataset.py
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | |
Command line¶
getframes.cli
¶
The getframes command-line interface (roadmap phase 1.6).
A thin wrapper that turns a TOML configuration file into frames or an ML dataset, so an experiment is a file you can share and run without writing Python. Three subcommands:
getframes presets— list the built-in camera presets.getframes generate config.toml -o frame.fits— generate one frame (or a short series) of a given type (dark/bias/flat/light).getframes dataset config.toml -o train/— stream raw + truth pairs to disk.
See :func:main. Run getframes --help for the full usage.
build_parser()
¶
Construct the getframes argument parser.
Source code in src/getframes/cli.py
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
main(argv=None)
¶
Entry point for the getframes command. Returns a process exit code.
Source code in src/getframes/cli.py
207 208 209 210 211 212 213 214 215 | |
Noise models¶
getframes.noise
¶
Physical noise models that turn a :class:CameraConfig into pixel values.
The models here are deliberately small, composable, and well-documented so that the physics is auditable. Each function takes a configuration, exposure, and a seeded backend-native generator, and returns electrons or ADU on that backend.
Signal chain (:func:simulate_frame)
- Mean photo signal:
(photon_rate + background) * t_exp * QEelectrons, modulated per pixel by photo-response non-uniformity (PRNU). - Mean dark signal:
D(T) * t_expelectrons (temperature-scaled), modulated by dark-signal non-uniformity (DSNU) and hot pixels, plus detector glow (uniform, or edge-concentrated viadetector_glow_edge_scale_px). - Shot noise: the total electrons are Poisson-distributed about that mean.
- Clock-induced charge (EMCCD) adds a small Poisson term.
- Cosmic rays (single pixels or extended tracks).
- Charge-transport artifacts: blooming along saturated columns, CCD charge-transfer inefficiency (CTI), and inter-pixel capacitance (IPC).
- Detector nonlinearity (single-parameter or polynomial).
- EM register / avalanche multiplication with its stochastic excess noise.
- kTC/reset noise and read noise: Gaussian in electrons, at the output amplifier. The per-pixel read-noise RMS is a fixed sensor property (sCMOS), including an optional random-telegraph-signal (RTS) tail population.
- Conversion to ADU via (optionally per-amplifier) gain, plus the bias pedestal and any structured-bias pattern; dead pixels/columns read as defects.
- Saturation at full well / ADC range and quantisation to integers.
A dark frame is simply the special case photon_rate = 0.
FixedPatternMaps
¶
Bases: NamedTuple
Device-resident, immutable detector structure cached by :class:Camera.
Source code in src/getframes/noise.py
74 75 76 77 78 79 80 81 82 83 84 | |
DetectorWorkspace
¶
Reusable private scratch storage for repeated detector simulations.
A workspace is lazy: its arrays are allocated only when a compatible call to
:func:simulate_frame or :meth:getframes.Camera.expose needs them. It may
be reused sequentially, but not concurrently. Returned frame and truth
arrays never alias workspace storage; only an explicit caller-owned out
array is returned without a copy.
One workspace binds to the detector shape, working dtype, backend, and CUDA device of its first use. Construct a separate workspace for a different camera geometry or execution device.
Source code in src/getframes/noise.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
SimulationResult
¶
Bases: NamedTuple
The output of :func:simulate_frame: the digitised frame plus ground truth.
Source code in src/getframes/noise.py
1143 1144 1145 1146 1147 1148 1149 | |
charge_diffusion_kernel(fwhm_px, *, oversampling)
¶
Return a flux-normalized lateral charge-diffusion kernel.
The detector diffusion profile is represented by a circular Gaussian whose
full width at half maximum is fwhm_px native pixels. Each returned tap is
the Gaussian probability integrated over one focal-plane sample cell, rather
than a point sample, and the finite four-sigma support is renormalized to unit
sum. The kernel is intended for an oversampled focal-plane irradiance before
native detector pixels collect charge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fwhm_px
|
float
|
Lateral diffusion FWHM in native detector pixels. Zero returns an identity
|
required |
oversampling
|
int
|
Focal-plane samples per native detector pixel. A nonzero width must span at least one sample at FWHM so the configured detector property cannot silently collapse to a numerical no-op. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Odd, square, symmetric |
Source code in src/getframes/noise.py
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | |
apply_charge_diffusion(values, fwhm_px, *, oversampling, backend=None)
¶
Diffuse an oversampled irradiance map before pixel-area integration.
values is a two-dimensional irradiance or photon-rate map, or a batch of
such maps, sampled at oversampling cells per native detector pixel. The
returned map has the same shape and dtype. A zero width leaves values
untouched. Charge that diffuses off the supplied map is lost at its edge.
Use this before summing focal-plane samples into native pixels. It accepts CPU NumPy and optional GPU CuPy arrays; the public kernel itself remains a portable NumPy array for callers that use another convolution implementation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Any
|
Two-dimensional irradiance or photon-rate map, or a leading batch of maps, on the oversampled focal-plane grid. |
required |
fwhm_px
|
float
|
Gaussian lateral charge-diffusion FWHM in native detector pixels. |
required |
oversampling
|
int
|
Number of focal-plane grid samples per native detector pixel. |
required |
backend
|
ArrayBackend | None
|
Array backend containing |
None
|
Returns:
| Type | Description |
|---|---|
array
|
Diffused array on the same backend, with the input shape and dtype. |
Source code in src/getframes/noise.py
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | |
fixed_pattern_maps(config, *, backend=None, float_dtype=DEFAULT_FLOAT_DTYPE)
¶
Build all repeatable per-pixel detector maps once on the selected device.
Source code in src/getframes/noise.py
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | |
dark_signal_map(config, exposure_s, temperature_c, float_dtype=DEFAULT_FLOAT_DTYPE, *, backend=None, fixed_patterns=None)
¶
Per-pixel mean dark signal in electrons, including fixed-pattern structure.
This is the noise-free expectation per pixel; shot noise is applied separately.
The fixed-pattern structure (DSNU and hot pixels) is deterministic for a given
sensor (keyed on :attr:~getframes.config.CameraConfig.fixed_pattern_seed), so
it repeats across frames and can be calibrated out with a master dark. A uniform
detector-glow term (detector_glow_e_per_s) is added on top, also
exposure-scaled and dark-removable.
float_dtype selects the working precision (float64 exact default, or
float32 for the memory-light fast path).
Source code in src/getframes/noise.py
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | |
photo_signal_map(config, photon_rate, exposure_s, background_photon_rate, quantum_efficiency=None, float_dtype=DEFAULT_FLOAT_DTYPE, *, backend=None, fixed_patterns=None, out=None)
¶
Per-pixel mean photo-generated signal in electrons (noise-free).
Converts an incident photon rate (photons/s/pixel, plus an additive
background) to photoelectrons via the quantum efficiency, then imprints a
fixed multiplicative PRNU pattern. photon_rate may be a scalar (uniform
illumination) or a 2-D array matching the sensor resolution.
The PRNU pattern is deterministic for a given sensor (keyed on
:attr:~getframes.config.CameraConfig.fixed_pattern_seed), so it repeats across
frames and is removable with a master flat.
quantum_efficiency overrides config.quantum_efficiency when given. The
spectral path uses this with a pre-multiplied (already-photoelectron) map and
quantum_efficiency = 1.0. float_dtype selects the working precision
(float64 default, or float32 for the memory-light fast path).
Source code in src/getframes/noise.py
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | |
apply_gain_stage(electrons, gain, excess_noise_factor, rng, *, backend=None)
¶
Apply a stochastic multiplication stage (EM register or APD avalanche).
A single model covers both EMCCDs and avalanche photodiodes, parameterised by
the mean gain G and the excess noise factor F. For n input
electrons the multiplied output is drawn from a Gamma distribution:
.. math::
\text{out} \sim \mathrm{Gamma}(\text{shape}=n\alpha,\ \text{scale}=\theta),
\quad \alpha = \frac{1}{F^2 - 1}, \quad \theta = G\,(F^2 - 1).
Then :math:E[\text{out}] = nG and, with Poisson input of mean :math:\mu, the
total output variance is :math:G^2 F^2 \mu --- i.e. the model reproduces the
requested excess noise factor exactly. Special cases:
F = sqrt(2)givesalpha = 1--- the classic EMCCDGamma(n, G)model.F -> 1is noiseless multiplication (deterministicn * G).
Pixels with zero input electrons produce zero output.
Source code in src/getframes/noise.py
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | |
apply_em_gain(electrons, em_gain, rng, *, backend=None)
¶
Backwards-compatible EMCCD multiplication (F = sqrt(2) gain stage).
Thin wrapper over :func:apply_gain_stage; prefer that for new code.
Source code in src/getframes/noise.py
615 616 617 618 619 620 621 622 623 624 625 626 | |
apply_nonlinearity(electrons, config, *, backend=None)
¶
Bend the charge response near full well (detector nonlinearity).
Two models, both deterministic (no randomness):
- Polynomial (when
config.nonlinearity_coeffsis set): withu = q / full_welland coefficients(c1, c2, ...), the response multiplier is1 + c1 u + c2 u**2 + ..., so an arbitrary measured curve or look-up can be reproduced. - Single-parameter (the default):
q -> q * (1 - nonlinearity * q / full_well), a smooth, monotonic compression so a pixel near full well reads slightly low.
The polynomial model takes precedence when both are configured.
Source code in src/getframes/noise.py
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | |
apply_blooming(electrons, full_well_e, *, backend=None)
¶
Bleed charge above full well along columns (CCD blooming).
Charge exceeding full_well_e in a pixel floods symmetrically into the
vacant pixels of the same column (axis=0): half the excess sweeps toward
higher rows and half toward lower rows, each filling successive pixels up to
full well until the charge is absorbed or runs off the array edge. Deterministic
and charge-conserving except for charge that bleeds off the top/bottom edge.
Source code in src/getframes/noise.py
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | |
apply_cti(electrons, cti, *, backend=None)
¶
Smear charge by charge-transfer inefficiency (CTI) during readout.
A first-order, charge-conserving model: the readout register is row 0, so a
pixel r rows away undergoes r transfers and defers a fraction
cti * r of its charge into the trailing pixel one row farther from the
register (axis=0), producing the characteristic CTI tail. Charge deferred
past the final row is lost into overscan. Deterministic.
Source code in src/getframes/noise.py
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | |
apply_ipc(electrons, coupling, *, backend=None)
¶
Couple a fraction of each pixel into its four neighbours (inter-pixel capacitance).
Convolves with the charge-conserving 3x3 kernel whose centre is
1 - 4*coupling and whose four edge-adjacent taps are coupling each
(corners zero). Models the capacitive crosstalk of CMOS / IR hybrid arrays.
Charge coupling past the array boundary is lost. Deterministic.
Source code in src/getframes/noise.py
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | |
add_cosmic_rays(electrons, config, exposure_s, rng, *, backend=None)
¶
Deposit cosmic-ray charge bursts into random pixels.
The number of hits is Poisson with mean rate * area * exposure; each hit
carries a broad charge burst of order ten thousand electrons. When
config.cosmic_ray_track_length_px is zero the charge lands in a single
pixel; when positive, each hit draws an exponential track length and a random
in-plane direction (a glancing muon) and spreads its charge evenly along the
track --- the extended morphology a real rejection pipeline must handle.
Source code in src/getframes/noise.py
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | |
digitize(electrons, config, rng, *, backend=None, fixed_patterns=None, reset_noise_e=None, correlated_read_noise_e=None, common_mode_adu=None, avalanche_input_noise_e=None, out=None, _output_slices=None, _out_validated=False)
¶
Add read/reset noise, convert electrons to ADU, then saturate and quantise.
Read noise is referenced to the sensor output amplifier. When
read_noise_nonuniformity is set (sCMOS), each pixel gets its own read-noise
RMS drawn from a log-normal distribution about read_noise_e. Hybrid arrays
can additionally carry fixed interleaved-channel and edge noise scales.
Detector-depth structure is folded in here: dead pixels/columns collect no charge; kTC/reset noise adds a per-pixel Gaussian; amplifier/channel layouts apply fixed gain, offset, and noise differences; and structured/edge bias rides on the flat pedestal. Nondestructive ramps may inject their shared reset draw, their shared correlated read-noise draw, and correlated common-mode pedestal explicitly.
Source code in src/getframes/noise.py
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | |
frame_electrons(config, mean_electrons, rng, exposure_s=0.0, *, backend=None, fixed_patterns=None)
¶
Apply shot noise, CIC, cosmic rays, nonlinearity, and any gain stage.
Takes the noise-free expected electrons per pixel and returns a realised
electron frame prior to read noise and digitisation. exposure_s is needed
only to scale the cosmic-ray rate. The working dtype follows mean_electrons
(float64 exact, or float32 for the memory-light fast path).
Source code in src/getframes/noise.py
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 | |
block_sum(array, factor)
¶
Sum an array into factor x factor super-pixel blocks (both dims divisible).
Source code in src/getframes/noise.py
1216 1217 1218 1219 1220 1221 1222 1223 1224 | |
simulate_frame(config, photon_rate, exposure_s, *, temperature_c, background_photon_rate=0.0, quantum_efficiency=None, extra_electrons=0.0, binning=1, binning_mode='digital', rng=None, seed=None, float_dtype=DEFAULT_FLOAT_DTYPE, backend=None, fixed_patterns=None, _dark_signal=None, workspace=None, out=None, _workspace_claimed=False, _preserve_truth=True, _output_slices=None, _out_validated=False)
¶
Simulate one frame end-to-end, returning ADU and the noise-free truth.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CameraConfig
|
The detector configuration. |
required |
photon_rate
|
PhotonRate
|
Incident photon rate in photons/s/pixel, as a scalar (uniform) or a 2-D
array. Use |
required |
exposure_s
|
float
|
Integration time in seconds ( |
required |
temperature_c
|
float
|
Sensor temperature in degrees Celsius. |
required |
background_photon_rate
|
PhotonRate
|
Additive background (sky/thermal) photon rate in photons/s/pixel. |
0.0
|
quantum_efficiency
|
float | None
|
Overrides |
None
|
extra_electrons
|
PhotonRate
|
Additive noise-free signal already in electrons (scalar or 2-D array), injected before shot noise and the gain stage. Used to carry latent charge from image persistence across the frames of an observation; it is real charge in the well, so it picks up shot noise and any EM/avalanche gain. |
0.0
|
binning
|
int
|
Combine |
1
|
binning_mode
|
str
|
How the binning combines charge relative to the read amplifier. |
'digital'
|
rng
|
Any | None
|
Provide an existing generator, or a seed to build a fresh one. |
None
|
seed
|
Any | None
|
Provide an existing generator, or a seed to build a fresh one. |
None
|
float_dtype
|
DTypeLike
|
Working floating-point precision of the per-pixel arrays: |
DEFAULT_FLOAT_DTYPE
|
workspace
|
DetectorWorkspace | None
|
Optional reusable :class: |
None
|
out
|
Any | None
|
Optional C-contiguous, writable backend-native |
None
|
Source code in src/getframes/noise.py
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 | |
generate_dark_frame(config, exposure_s, temperature_c, rng=None, seed=None, *, backend=None, fixed_patterns=None, _dark_signal=None)
¶
End-to-end dark frame in ADU (the photon_rate = 0 case of simulate_frame).
Source code in src/getframes/noise.py
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 | |
dark_frame_electrons(config, exposure_s, temperature_c, rng, *, backend=None)
¶
Electron-domain dark frame prior to digitisation (kept for convenience).
Source code in src/getframes/noise.py
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | |