Hello!
Thank you for the repository access, I am finding Pyxel to be an incredibly useful tool and wanted to share a small change I have made while using it.
I have been attempting to use Pyxel to generate data that matches results I am getting off of a lab CMOS image sensor. The built in pipeline works exactly as needed, however the charge_generation.photoelectrons.simple_conversion model appears to be suppressing noise, changing the $Noise = \sqrt{Signal}$ shot noise relationship expected at that point in the detector.
The current modification I have made is to models.charge_generation.photoelectrons.simple_conversion (line 35):
detector_charge[slice(0, photon_rows), slice(0, photon_cols)] = (
ph.array * ch.qe * ch.eta
)
changing it to (in a fresh function):
detector_charge[slice(0, photon_rows), slice(0, photon_cols)] = (
ph.array * ch.qe * ch.eta
)
This changes the calculation from a linear multiplication to binomial sampling, which primarily changes the noise in the output pixel values. Considering the contributions to the output noise by the input noise ($Noise_{in}$) and the noise of the charge generation model ($Noise_{model}$) (I have taken the signal to be the mean pixel value):

$Noise_{out}^2 = (Noise_{in}.Gain_{model})^2 + Noise_{model}^2$

For linear multiplication:

$Noise_{out}^2 = (\sqrt{Signal_{in}}.QE)^2 + 0^2$

$Noise_{out}^2 = (\sqrt{Signal_{out}}.\sqrt{QE})^2$

$Noise_{out} = \sqrt{Signal_{out}} .\sqrt{QE}$

Which is less than expected (when QE<1), however for binomial sampling:

$Noise_{out}^2 = (\sqrt{Signal_{in}}.QE)^2 + Noise_{charge generation}^2$

$= Signal_{in}.QE^2 + np(1p)$ < the variance of the binomial distribution

( $QE$ is the probability of success, $p$, and $Signal_{in}$(in photons) is the number of trials, $n$, of the binomial distribution)

$= Signal_{in}.QE^2 + Signal_{in}.QE(1QE)$

$= Signal_{in}.QE^2 + Signal_{in}.QE  Signal_{in}.QE^2$

$= Signal_{in}.QE=$

$Noise_{out} = \sqrt{Signal_{in}.QE} = \sqrt{Signal_{out}}$

Which matches the expected signal to noise relationship. Making this change has resulted in excellent agreement between the Pyxel outputs and my lab data. For example the plot below includes three sets of PTC data, two generated by Pyxel, with this modification ('Binomial Charge Generation') and without ('Linear Charge Generation'), alongside PTC data points captured from the lab sensor ('Experimental Results'). The plot demonstrates the lower noise seen in the output data using the linear charge_generation model. Both simulation runs were made with the parametric_ptc.yaml example script with changes to the detector values to match the lab sensor, the simulation was completed with a QE of 60%.
I am aware that numpy.random.binomial will break when (ch.qe * ch.eta
) > 1, or when any elements of ph.array
are not ints. I have stopped the latter from crashing the program by using the numpy.random.default_rng.binomial function, but the change is less elegant.