One approach then would be to ensure this never happens, i.e., add a
small epsilon to each input stream, and make epsilon small enough to not
sufficiently impact the results for "typical" input values. Normalizing
the conjugate product will then give you the cosine as the real value,
as you mentioned. Or, you could just divide the abs value into the real
value of the product, and avoid the extra calculation of the normed
imaginary part which you are going to throw away.
Thanks for the replies guys. The above is the approach I went with.
It seems to work well, and gave a further BER improvement to my GMSK demod experiments.
For those interested, here is how I'm using it in the context of GMSK demod:
self.kc = gr.kludge_copy(gr.sizeof_gr_complex)
self.delay = gr.delay(gr.sizeof_gr_complex, 2*self._samples_per_symbol) #2T delay
self.conj = gr.conjugate_cc()
self.mult = gr.multiply_cc()
self.c2mag = gr.complex_to_mag()
self.safety_add = gr.add_const_ff(0.0000001)
self.c2f = gr.complex_to_float
()
self.rescaler = gr.divide_ff()
self.sub = gr.add_const_ff(-self._decision_threshold)
samp_per_sec = samples_per_symbol * sym_per_sec
pre_cr_filt_bw = sym_per_sec*pre_cr_filt_bt
pre_cr_filt_taps = gr.firdes.low_pass(1.0, samp_per_sec, pre_cr_filt_bw, pre_cr_filt_tr*samp_per_sec, gr.firdes.WIN_HAMMING)
self.pre_cr_filt = gr.fir_filter_fff(1, pre_cr_filt_taps)
# the clock recovery block tracks the symbol clock and resamples as needed.
# the output of the block is a stream of soft symbols (float)
self.clock_recovery = gr.clock_recovery_mm_ff(self._omega, self._gain_omega,
self._mu, self._gain_mu,
self._omega_relative_limit)
# slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
self.slicer = gr.binary_slicer_fb()
[...]
# Connect & Initialize base class
self.connect(self, self.kc, self.delay, self.conj, (self.mult, 0))
self.connect
(self.kc, (self.mult, 1))
self.connect(self.mult, self.c2f, (self.rescaler, 0))
self.connect(self.mult, self.c2mag, self.safety_add, (self.rescaler, 1))
self.connect(self.rescaler, self.pre_cr_filt
, self.sub, self.clock_recovery, self.slicer, self)