I have a 30-seconds wav audio file with a sample rate of 44100Hz, obviously this array of samples is a 1D array, and so when I modulate it in AM (Amplitude Modulation) I get back a 1D array, but I want it to return a 2D array of complex values, I don't really know how can you generate the real and imaginary part from one value and so I ended up here.

Here is my code:

SAMPLE_FOR = 30 # in seconds
samplerate, data = scipy.io.wavfile.read(r'Recording.wav')
data = data[0:int(samplerate*SAMPLE_FOR)]
fm = generateSignalFM(data,time)

def generateSignalAM(slc,t):
    samples,time_vec = SamplerateConversion(slc)
    w = low_cut_filter(samples,176400,22050)

    TWO_PI = 2 * np.pi
    carrier_hz = 20000
    ac = 0.5

    carrier = np.sin(TWO_PI * carrier_hz * time_vec)
    envelope = (1.0 + ac * w)
    modulated = envelope * carrier
    return modulated

And FM signal code:

def generateSignalFM(samples,t, fc=None, b=.3):

    w = low_cut_filter(samples,fs,22050)

    N = len(w)
    if fc is None:
        fc = 75000 

    x0 = w[:N]
    # ensure it's [-.5, .5] so diff(phi) is b*[-pi, pi]
    x0 /= (2*np.abs(x0).max())

    # generate phase
    phi0 = 2*np.pi * fc * time_vec
    phi1 = 2*np.pi * b * np.cumsum(x0)
    phi = phi0 + phi1
    diffmax  = np.abs(np.diff(phi)).max()
    # `b` correction
    if diffmax >= np.pi:
        diffmax0 = np.abs(np.diff(phi0)).max()
        diffmax1 = np.abs(np.diff(phi1)).max()
        phi1 *= ((np.pi - diffmax0) / diffmax1)
        phi = phi0 + phi1

    # modulate
    x = np.cos(phi)
    return x

1 Answer 1


If the signal is a real audio waveform that only has AM components, the baseband equivalent waveform will be real unless the carrier has a phase offset. If the intention is to model the effect of carrier phase offset, this can be accomplished by multiplying the baseband waveform with $e^{j\phi}$ for a given carrier offset $\phi$ resulting in a complex signal.

If the intention is to make an analytic signal (positive half spectrum only), the relationship is given by:

$$X(\omega) \Leftrightarrow x(t) = I(t)+jQ(t)$$

Where $x(t)$ is the complex analytic signal, $I(t)$ is the original real waveform, and $Q(t)$ is the Hilbert Transform of $I(t)$. $X(\omega$) is the Fourier Transform of $x(t)$ and will have positive frequency components only.

The analytic waveform can be created directly with the OP's code by changing the carrier from a real carrier as given by

carrier = np.sin(TWO_PI * carrier_hz * time_vec)

To a complex analytic signal carrier as given by:

carrier = np.exp(1j * TWO_PI * carrier_hz * time_vec)

This is because $e^{j\omega t}$ is the analytic signal for $\cos(\omega t)$. Compare the following given by Euler's equation to the general relationship previously given above for the real signal $I(t)$ and its analytic signal $x(t)$:

$$ e^{j\omega t} = \cos(\omega t) + j\sin(\omega t)$$

Here, $e^{j\omega t}$ is the analytic signal, $\cos(\omega t)$ is the original real carrier, and $\sin(\omega t)$ is the Hilbert transform of $\cos(\omega t)$.

  • $\begingroup$ Thank you, this did work for me and the code addition was very useful to understand, however I was trying to change my FM function to compute complex numbers as well and I don't understand how to use your solution there. do you mind taking a look? I added it to my post $\endgroup$ Commented Sep 3, 2021 at 23:22
  • $\begingroup$ @yarinCohen yes also very simple- instead of using $\cos(\phi)$ which is a real function, use $e^{j\phi)$ $\endgroup$ Commented Sep 4, 2021 at 0:40
  • 1
    $\begingroup$ So I change: x = np.cos(phi) To: x = np.exp(1j / phi) ? $\endgroup$ Commented Sep 4, 2021 at 1:48
  • $\begingroup$ is it normal that I get divide by zero errors and not a number errors back? $\endgroup$ Commented Sep 4, 2021 at 11:10
  • 1
    $\begingroup$ That is not a division symbol but a mathjax code to print the symbol phi. For your python code you would use np.exp(1j * phi). $\endgroup$ Commented Sep 4, 2021 at 11:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.