Thanks to Fat32 I'm starting to understand ( I've realized my ignorance on this subject is huge ). I've spent some time to write some python code in order to understand. It helped to make me understand I hope it can be useful to others: import sys import os import math import argparse import itertools import subprocess import numpy as np def plot_samples(samples,name, unique = True): fp = open(name+".gnuplot","w") fp.write("set grid\n") if unique: fp.write("plot \""+name+".dat\" smooth unique\n") else: fp.write("plot \""+name+".dat\"\n") fp.close() fp = open(name+".dat","w") for sample in samples: fp.write(str(sample[0])+" "+str(sample[1])+"\n") fp.close() gnuplot_pid = subprocess.call(["/usr/bin/gnuplot","-persist",name+".gnuplot"]) def sawtooth_wave(amplitude = 1.0, sampling_freq = 5100.0,frequency = 50.0, num_of_periods = 10, num_harmonics = 50): if frequency * num_harmonics * 2 > sampling_freq: print("Warning the sampling frequency is less than twice the most high harmonic. This will lead to distortions") print("Max signal frequency : "+str(frequency)+" x "+str(num_harmonics)+" = "+str(frequency * num_harmonics)) print("Sampling frequency : "+str(sampling_freq)) sys.exit() #A/2 - A/pi * sum_k(-1^k * sin(2*pi*k*f*t)/k) num_samples = math.ceil(float(sampling_freq)/float(frequency)) cycle = num_of_periods * 1.0/float(frequency) time_axis = np.arange(0,cycle,1.0/float(sampling_freq)) samples = [] for t in time_axis: harmonics = 0 for k in range(1,num_harmonics): harmonics += math.pow(-1,k)*np.sin(2*np.pi*k*float(frequency)*t)/k samples.append([t, -amplitude/np.pi * harmonics]) return samples,len(time_axis) def parser(): parser = argparse.ArgumentParser(description='Shows some stuff') parser.add_argument('--frequency', default='50', type=int, help='Frequency of the tone in Hz (%(default)s)') parser.add_argument('--amplitude', default='1.0', type=float, help='Amplitude of the tone (%(default)s)') parser.add_argument('--sampling_freq', default='2400', type=float, help='Frequency of the sampling (%(default)s)') parser.add_argument('--carrier', default='2399', type=float, help='Frequency of the carrier (%(default)s)') parser.add_argument('--harmonic', default='20', type=int, help='Number of harmonics for the sawtooth (%(default)s)') return parser.parse_args() def get_fft(samples,sampling_freq): samples_f = np.fft.fft([i[1] for i in samples]) freqs = np.fft.fftfreq(len(samples)) * sampling_freq return [[f,np.absolute(i)/len(samples_f)] for i,f in zip(samples_f,freqs)] def __main__(): f2q1_8 = lambda v: (int((v * float(1 << 8)) + (-0.5 if (v < 0) else 0.5)) & 0x1FF) args = parser() samples,num_sample = sawtooth_wave(amplitude = args.amplitude, sampling_freq = args.sampling_freq, frequency = args.frequency, num_harmonics = args.harmonic) plot_samples(samples,"sawtooth") samples_f = get_fft(samples,args.sampling_freq) plot_samples(samples_f,"spectrum_sample") # I_Q components I_components = [[i[0],i[1] * np.cos(2*np.pi*args.carrier*i[0])] for i in samples] Q_components = [[i[0],i[1] * np.sin(2*np.pi*args.carrier*i[0]) * -1.0 ] for i in samples] plot_samples(I_components,"sawtooth_I") plot_samples(Q_components,"sawtooth_Q") I_components_f = get_fft(I_components,args.sampling_freq) plot_samples(I_components_f,"spectrum_sawtooth_I") Q_components_f = get_fft(Q_components,args.sampling_freq) plot_samples(Q_components_f,"spectrum_sawtooth_Q") # I_Q mixing sample_after = [[i[0], i[1] * np.cos(2*np.pi*args.carrier*i[0]) - q[1] * np.sin(2*np.pi*args.carrier*q[0])] for i,q in zip(I_components,Q_components)] plot_samples(sample_after,"sawtooth_after_decomposition") __main__()This piece of code basically create some samples of a sawtooth waveforms and print the I/Q waveforms/spectrum. At the moment the model miss the low pass filter and it's a concern because when I put together the I/Q i don't see any evident problem in the shape of the waveform. So I guess there is something I'm still missing. (责任编辑:) |