Пример #1
0
    def calcNFGainIPLoss(self, coldfile_cal, hotfile_cal, coldfile, hotfile,
                         ENR2dB, ENR12dB, iplossfile):

        # don't base noise figure on gain anymore after NF has been set this way
        self.resistive = False
        # import measurement data
        rbw, f_nf, p_hot = yf.loadcsv(hotfile)
        _, _, p_cold = yf.loadcsv(coldfile)
        _, fcal, cal_hot = yf.loadcsv(hotfile_cal)
        _, _, cal_cold = yf.loadcsv(coldfile_cal)
        # convert to Watts
        p_cold = dBm_to_W(p_cold)
        p_hot = dBm_to_W(p_hot)
        cal_cold = dBm_to_W(cal_cold)
        cal_hot = dBm_to_W(cal_hot)

        # input loss
        f2, sp = vna.loadcsv(iplossfile)
        iploss = np.abs(sp[:, 2])
        iploss = np.interp(f_nf, f2, iploss)

        # smooth data
        if self.navg > 1:
            p_cold, trim = self.smooth(p_cold)
            p_hot, _ = self.smooth(p_hot)
            cal_cold, _ = self.smooth(cal_cold)
            cal_hot, _ = self.smooth(cal_hot)
            iploss, _ = self.smooth(iploss)
            f_nf = f_nf[trim:-trim]
            fcal = fcal[trim:-trim]

        # make sure calibration frequency space is the same as DUT measurement
        if len(fcal) != len(f_nf):
            cal_cold = np.interp(f_nf, fcal, cal_cold)
            cal_hot = np.interp(f_nf, fcal, cal_hot)

        # convert input loss to db
        iploss = 20 * np.log10(iploss)

        # calculate equivalent noise temperature
        nf, gain = yf.yfactor_cal_ipLoss(cal_cold, cal_hot, p_cold, p_hot,
                                         ENR2dB, ENR12dB, iploss)
        self.Teq = (10**(nf / 10) - 1) * 290
        # interpolate
        self.gain = np.interp(self.fspace, f_nf, gain)
        self.Teq = np.interp(self.fspace, f_nf, self.Teq)
        # convert to noise figure in dB
        F = self.Teq / 290 + 1
        self.nf = 10 * np.log10(F)
Пример #2
0
 def calcNF(self, coldfile, hotfile, ENR_dB):
     # don't base noise figure on gain anymore after NF has been set this way
     self.resistive = False
     # import measurement data
     rbw, f_nf, p_hot = yf.loadcsv(hotfile)
     _, _, p_cold = yf.loadcsv(coldfile)
     # convert to Watts
     p_cold = dBm_to_W(p_cold)
     p_hot = dBm_to_W(p_hot)
     # smooth data
     if self.navg > 1:
         p_cold, trim = self.smooth(p_cold)
         p_hot, _ = self.smooth(p_hot)
         f_nf = f_nf[trim:-trim]
     # calculate equivalent noise temperature
     _, self.Teq = yf.yfactor_W(p_cold, p_hot, ENR_dB)
     # interpolate
     self.Teq = np.interp(self.fspace, f_nf, self.Teq)
     # convert to noise figure in dB
     F = self.Teq / 290 + 1
     self.nf = 10 * np.log10(F)
Пример #3
0
 def calcNFgainCal(self, coldfile, hotfile, ENR_dB, T_SA):
     # don't base noise figure on gain anymore after NF has been set this way
     self.resistive = False
     # import measurement data
     rbw, f_nf, p_hot = yf.loadcsv(hotfile)
     _, _, p_cold = yf.loadcsv(coldfile)
     # convert to Watts
     p_cold = dBm_to_W(p_cold)
     p_hot = dBm_to_W(p_hot)
     # smooth data
     if self.navg > 1:
         p_cold, trim = self.smooth(p_cold)
         p_hot, _ = self.smooth(p_hot)
         f_nf = f_nf[trim:-trim]
     # interpolate
     p_cold = np.interp(self.fspace, f_nf, p_cold)
     p_hot = np.interp(self.fspace, f_nf, p_hot)
     T_SA = np.interp(self.fspace, f_nf, T_SA)
     # calculate noise figure
     self.nf = yf.yfactor_cal_W2(p_cold, p_hot, T_SA, self.gain, ENR_dB)
     self.Teq = (10**(self.nf / 10) - 1) * 290
Пример #4
0
    def timeDomainResponseWC(self, t, vin):
        if len(self.OIP3) == 0:
            self.calcCascade()

        # calculate power series gain coefficients from gain / OIP3

        # for now, use the worst case OIP3
        # TODO: take into account the OIP3 varying over frequency
        roi = (np.where((self.components[0].fspace >= 1300)
                        & (self.components[0].fspace <= 1720)))[0]
        oip3 = min(self.OIP3[roi])
        gain = min(self.G[roi])

        print('worst case OIP3: ', oip3)
        print('worst case gain: ', gain)

        Z0 = 50
        a1 = 10**(gain / 20)
        a3 = -2 * a1**3 / (3 * Z0 * yf.dBm_to_W(oip3))

        # calculate nonlinear response
        dt = min(np.diff(t))
        Fs = 1 / dt
        NFFT = len(vin)
        fmin = -1 / (2 * dt)
        fmax = 1 / (2 * dt)
        f = np.linspace(0, fmax, int(NFFT / 2))
        df = Fs / NFFT

        S_in = psd_1sided(vin, Fs, NFFT)
        S_in = S_in[int(len(vin) / 2):]

        p_tot = sum(S_in) * df
        p_tot_dbm = 10 * np.log10(1000 * p_tot)
        print("total input power (dBm): ", p_tot_dbm)

        vout3 = a3 * vin**3

        vout = a1 * vin + vout3
        S_out = psd_1sided(vout, Fs, NFFT)
        S_out = S_out[int(len(vin) / 2):]

        S3 = psd_1sided(vout3, Fs, NFFT)
        S3 = S3[int(len(vin) / 2):]

        peak_psd = 10 * np.log10(1000 * max(S_out))
        p_tot = sum(S_out) * df
        p_tot_dbm = 10 * np.log10(1000 * p_tot)
        print("total output power (dBm): ", p_tot_dbm)

        return f, S_out, S3, S_in
Пример #5
0
    def timeDomainResponse(self, t, vin):
        if len(self.OIP3) == 0:
            self.calcCascade()

        fspace = self.components[0].fspace

        # calculate power series gain coefficients from gain / OIP3

        a1f = 10**(self.G / 20)
        # TODO: use direct a3 measurements if available
        a3_est = -2 * 10**(1.5 * self.G / 10) / (3 * dBm_to_W(self.OIP3) * 50)
        a3f = a3_est

        # calculate nonlinear response
        dt = min(np.diff(t))
        Fs = 1 / dt
        NFFT = len(vin)
        fmin = -1 / (2 * dt)
        fmax = 1 / (2 * dt)
        f = np.linspace(0, fmax, int(NFFT / 2))
        df = Fs / NFFT

        S_in = psd_1sided(vin, Fs, NFFT)
        S_in = S_in[int(len(vin) / 2):]

        p_tot = sum(S_in) * df
        p_tot_dbm = 10 * np.log10(1000 * p_tot)
        print("total input power (dBm): ", p_tot_dbm)

        vout1, vout3 = timeDomainVoltage(vin, a1f, a3f, Fs, fspace)

        ## debug:
        # ~ plt.figure()
        # ~ plt.title('a3 voltage gain from component')
        # ~ plt.plot(fspace, a3f)

        # ~ plt.figure()
        # ~ plt.plot(ff, vin_f, label='input fft')
        # ~ plt.plot(ff, vin_f*A1f, label='output linear')
        # ~ plt.plot(ff, fft(vin**3)*A3f, label='output 3rd order')
        # ~ plt.plot(ff, A3f, label='a3 gain')
        # ~ plt.xlabel("frequency (Hz)")
        # ~ plt.ylabel("V/sqrt(Hz)")
        # ~ plt.legend()

        # ~ S_out_lin = psd_1sided(vout1, Fs, NFFT)
        # ~ S_out_lin = S_out_lin[int(len(vin)/2):]

        S3 = psd_1sided(vout3, Fs, NFFT)
        S3 = S3[int(len(vin) / 2):]

        # ~ plt.figure()
        # ~ plt.plot(f, 30+10*np.log10(S_in), label='input psd')
        # ~ plt.plot(f, 30+10*np.log10(S_out_lin), label='linear output psd')
        # ~ plt.plot(f, 30+10*np.log10(S3), label='3rd order output psd')
        # ~ plt.legend()

        #plt.show()

        # sum 1st and 3rd order outputs
        vout = vout1 + vout3

        S_out = psd_1sided(vout, Fs, NFFT)
        S_out = S_out[int(len(vin) / 2):]

        peak_psd = 10 * np.log10(1000 * max(S_out))
        p_tot = sum(S_out) * df
        p_tot_dbm = 10 * np.log10(1000 * p_tot)
        print("total output power (dBm): ", p_tot_dbm)

        return f, S_out, S3, S_in
Пример #6
0
    def timeDomainStepByStepV(self, t, vin):
        fspace = self.components[0].fspace

        plot = False
        if plot:
            plt.figure()
            plt.title('component nonlinear contributions')

        #set up frequency space
        dt = min(np.diff(t))
        Fs = 1 / dt
        NFFT = len(vin)
        fmin = -1 / (2 * dt)
        fmax = 1 / (2 * dt)
        f = np.linspace(0, fmax, int(NFFT / 2))
        df = Fs / NFFT

        S_in = psd_1sided(vin, Fs, NFFT)
        S_in = S_in[int(len(vin) / 2):]

        Vout = vin
        #v1sum = np.zeros(len(vin))
        v3sum = np.zeros(len(vin))
        vout3 = np.zeros(len(vin))

        oip3_hi = 100  # number to use for linear components (dBm)
        iip3_w = 10**((oip3_hi - 30) / 10)

        for c in self.components:
            # calculate power series gain coefficients from this component's gain/OIP3
            a1f = 10**(c.gain / 20)

            if len(c.oip3) == 0:
                #c_oip3 = oip3_hi
                a3_est = [
                ]  # just set a3 to zero since we're modeling these devices as linear
            else:
                #c_oip3 = c.oip3
                a3_est = -2 * 10**(1.5 * c.gain / 10) / (3 * dBm_to_W(c.oip3) *
                                                         50)

            a3f = a3_est

            # Vout is fed back in to the next component
            vout1, vout3 = timeDomainVoltage(Vout, a1f, a3f, Fs, fspace)

            Vout = vout1 + vout3
            #v1sum = v1sum + vout1
            v3sum = v3sum + vout3

            if plot and (c.name != '') and (len(c.oip3) != 0):
                S3 = psd_1sided(vout3, Fs, NFFT)
                S3 = S3[int(len(vin) / 2):]

                S1 = psd_1sided(vout1, Fs, NFFT)
                S1 = S1[int(len(vin) / 2):]

                plt.plot(f * 1e-6,
                         30 + 10 * np.log10(S3),
                         ':',
                         label='3rd order (after ' + c.name + ')')
                plt.plot(f * 1e-6,
                         30 + 10 * np.log10(S1),
                         label='linear (after ' + c.name + ')')

        if plot:
            plt.plot(f * 1e-6, 30 + 10 * np.log10(S_in), label='input')
            plt.legend(loc="upper right")
            plt.xlabel("frequency (MHz)")
            plt.ylabel("dBm/Hz")

        S_out = psd_1sided(Vout, Fs, NFFT)
        S_out = S_out[int(len(vin) / 2):]

        S3 = psd_1sided(v3sum, Fs, NFFT)
        S3 = S3[int(len(vin) / 2):]

        return f, S_out, S3, S_in, Vout
Пример #7
0
    def intermodEstimate(self, rfiList, t):

        #set up frequency space
        dt = min(np.diff(t))
        Fs = 1 / dt
        fmin = -1 / (2 * dt)
        fmax = 1 / (2 * dt)
        fnl = np.linspace(0, fmax, int(len(t) / 2))
        df = Fs / len(t)

        rfi_freq = np.zeros(len(rfiList))
        rfi_bw = np.zeros(len(rfiList))
        rfi_pow = np.zeros(len(rfiList))
        for ix in range(len(rfi_freq)):
            rfi_freq[ix] = rfiList[ix].fc
            rfi_bw[ix] = rfiList[ix].bw
            rfi_pow[ix] = rfiList[ix].power

        rfi_freq = np.concatenate((-np.array(rfi_freq), np.array(rfi_freq)))
        rfi_bw = np.concatenate((-np.array(rfi_bw), np.array(rfi_bw)))
        rfi_pow = dBm_to_W(np.array(rfi_pow))
        rfi_pow = np.concatenate((rfi_pow, rfi_pow))
        n = len(rfi_freq)

        # initialize output spectrum (input state)	(1-sided spectrum)
        VSDout = np.zeros(int(len(t) / 2))
        #S_out_est = np.ones(int(len(t)/2)) * dBm_to_W(-200)
        # rfi source input power
        for ix in range(len(rfi_freq)):
            if rfi_freq[ix] > 0:
                rng_fund = (
                    np.where((fnl >= rfi_freq[ix] - rfi_bw[ix] / 2)
                             & (fnl <= rfi_freq[ix] + rfi_bw[ix] / 2)))[0]
                VSDout[rng_fund] = np.sqrt(2 * 50 * rfi_pow[ix] /
                                           np.abs(rfi_bw[ix]))
                #S_out_est[rng_fund] = rfi_pow[ix]/np.abs(rfi_bw[ix])

        plot = False
        if plot:
            plt.figure()
            plt.title('component contributions, estimate')

        for c in self.components:
            # calculate power series gain coefficients from this component's gain/OIP3
            a1f = 10**(c.gain / 20)

            # apply gain to whole spectrum in this case
            # it's ok that this is also affecting the fundamental before that's applied to IM power calculation,
            # because that calculation is using the array of RFI powers anyway (not the voltage spectrum)
            a1 = np.interp(fnl, c.fspace * 1e6, a1f)
            VSDout = VSDout * a1

            if len(c.oip3) == 0:
                #c_oip3 = oip3_hi
                a3_est = [
                ]  # just set a3 to zero since we're modeling these devices as linear

                #S_out_est = S_out_est*a1**2
            else:
                #c_oip3 = c.oip3
                a3_est = -2 * 10**(1.5 * c.gain / 10) / (3 * dBm_to_W(c.oip3) *
                                                         50)

                a3f = a3_est

                # for every combination of 3 rfi sources
                for i1 in range(n):
                    for i2 in range(n):
                        for i3 in range(n):
                            # sum frequency
                            fsum = rfi_freq[i1] + rfi_freq[i2] + rfi_freq[i3]
                            # calculate power for positive frequencies
                            if fsum > 0:
                                a3 = np.interp(fsum, c.fspace * 1e6, a3f)
                                P = (
                                    50 / 2 * a3
                                )**2 * rfi_pow[i1] * rfi_pow[i2] * rfi_pow[i3]
                                # calculate bandwidth
                                BW = np.abs(rfi_bw[i1] + rfi_bw[i2] +
                                            rfi_bw[i3])

                                # modify output spectrum
                                rng_im = (
                                    np.where((fnl >= fsum - BW / 2)
                                             & (fnl <= fsum + BW / 2)))[0]
                                VSDout[rng_im] = VSDout[rng_im] + np.sqrt(
                                    2 * 50 * P / BW)
                                #S_out_est[rng_im] = S_out_est[rng_im] + P/np.abs(BW)

                if plot and (c.name != '') and (len(c.oip3) != 0):
                    Sp = VSDout**2 / (2 * 50) + dBm_to_W(-300)
                    plt.plot(fnl * 1e-6,
                             30 + 10 * np.log10(Sp),
                             '--',
                             label='output after ' + c.name)

                # calculate fundamental gain from this component and update plot
                # ~ for ix in range(len(rfi_freq)):
                # ~ if rfi_freq[ix] > 0:
                # ~ a1 = np.interp(rfi_freq[ix], c.fspace*1e6, a1f)
                # ~ rng_fund = (np.where((fnl >= rfi_freq[ix]-rfi_bw[ix]/2) & (fnl <= rfi_freq[ix]+rfi_bw[ix]/2)))[0]
                # ~ VSDout[rng_fund] = VSDout[rng_fund]*a1
                #S_out_est[rng_fund] = S_out_est[rng_fund]*a1**2

            # update rfi source power with component gain
            for ix in range(len(rfi_freq)):
                a1 = np.interp(rfi_freq[ix], c.fspace * 1e6, a1f)
                rfi_pow[ix] = rfi_pow[ix] * a1**2

        # find peak regions for plotting (max intermod?)

        if plot:
            plt.legend(loc='upper right')

        S_out_est = VSDout**2 / (2 * 50) + dBm_to_W(-300)

        return fnl, S_out_est