PsrSigSim / PsrSigSim

The first version of our pulsar signal simulator.
MIT License
20 stars 21 forks source link

proposed API change #32

Closed paulthebaker closed 4 years ago

paulthebaker commented 6 years ago

the basic workflow looks like this:

sig = pss.Signal(Nt=10000)
psr = pss.Pulsar(sig)
psr.make_pulses()
gbt = pss.telescope.GBT()
out = gbt.observe(sig, system='Lband_GUPPI', noise=True)

There are a few things that I think could be more intuitive.

In keeping with the modularity of the simulation, a pulsar (or ism, etc) should be initialized totally independent of any signal. Once initialized, it operates on a signal, modifying it.

As a Signal instance passes through Pulsar or ISM methods, it is imbued with some of those objects' metadata (rather than the pulsar gaining a bunch of properties directly from the signal as happens now). For example make_pulses() is how a pulsar interacts with a signal, so that method should take the Signal object as input.

We've also discussed elsewhere (#1) the desire to create an optimal empty signal for a particular observation (including Telescope, Backend, etc.). The Telescope could output a Signal instance or it could produce a keyword argument dictionary that is passed to Signal.

The prebuilt telescopes are currently clunky to use (try fold()), because they carry multiple receivers and backends that the user must keep straight. It would be better for a Telescope instance to be just one system.

For example:

gbt_Lband = pss.telescope.GBT(receiver='Lband', backend='GUPPI')
sig = gbt_Lband.init_signal(Tobs)

or

gbt_Lband = telescope.GBT(receiver='Lband', backend='GUPPI')
kwargs = gbt_Lband.sig_dict()  # only telescope params!
sig = pss.Signal(Tobs, kwargs)

Another consideration is making all of the modules operate on a signal in the same way. This makes things easier on the user. It also will make it easier if we ever want to overload the + operator for the modules.

The simple way

psr = pss.Pulsar()
ism = pss.ISM()

psr.make_pulses(sig)
ism.disperse(sig)

or we make class factories like enterprise

psr = pss.Pulsar()  # just makes pulses
disp = pss.ism.dispersion()
scint = pss.ism.scintilation()

sim = psr + dsp + scint
sim(sig)

Finally we observe with the telescope:

out = gbt_Lband.observe(sig, noise=True)

This stuff is pretty abstract, but setting some design goals can help us as we move toward a more user friendly system. If we want to move the code to the nanograv github and use continuous integration, that is a good opportunity to go back and rethink the design of the simulation with experience.

paulthebaker commented 6 years ago

During a PSS call we discussed changes.

Currently the signal class uses int datatypes anticipating the telescope. We should switch to keeping floating point for physical simulation and have the A2D transform to int8 or int16.

We should initialize a signal with:

and one of:

Currently, we simulate at baseband. Should we simulate at radio-frequency instead/too?

paulthebaker commented 6 years ago

Is there a big advantage to simulating filterbank data directly, when you expect a filterbank observation?

Could we make the signal always work in either real radio frequency or basebanded radio frequency? The signal can have real, physical units. Then it gets digitized at the telescope, as a voltage. We can FFT and bin the signal for a filterbank or just leave it as voltage. (the min freq would have to be chosen appropriately for any future telescope you wish to use)

This would cut down on memory as the signal will only ever need the two polarization channels instead of many frequency channels. It will also regularize all of the methods that act on a Signal object.

Hazboun6 commented 6 years ago

Let me first address the filterbank signal. There are a few things that are definitely difficult to simulate right now in the baseband signal.

  1. Profile Evolution in Frequency: I am not sure how to change the template at different frequencies , especially if those changes do not have a straight forward frequency dependence.
  2. Scintillation: The scintillation simulation requires a fresnel integral with the phase screen at every given frequency to get a dynamic spectrum which can then be used to simulate the scintillation.
  3. Scatter broadening: The current simulation of this only works for the filterbank data.

Some of these can be done with baseband data, but others we might have to invent. I'm not sure how to do the scintillation simulation without separating out the different frequencies in some way. Especially since the scintillation changes over the course of an observation. If it was the same you could use a passband filter.

Besides the physical effects, I'm not sure that we save anything by starting at baseband. There is a basic conservation of information. If we start at baseband we have to sample at a much higher rate in order to get a realistic number/channel width of frequency bins once we take a spectrogram. Forgetting about factors of two, it's basically the same amount of data and THEN you have to perform the running FFT on top of that. I think it's basically a wash.

As for a radio frequency signal, I think this is something that people might want to use, but then we will be dealing with huge arrays that we'll have to carry around and down convert. My thought is that we should have that signal type in mind, but focus on the two that we have been developing until we see a real use for the RF signal.