Communications Eye Diagram and Q-Factor procedures
PHaigh
I searched high and low to find a function for Igor that plots an eye diagram and/or Q-factor for a communications engineer. Maybe I was missing something obvious but I couldn't find any. Therefore I wrote the following code - I hope that it saves others a little time. In order to obtain the best results, the first element of the amplitude vector wave must be the first sample of the bit. The eye diagram will look poor unless this condition is met.
Many thanks,
Paul
/////////////////////////////////////////////////////////////////////////////////////////////
// Eye Diagram generation procedure for Igor Pro. //
// Author: Paul Anthony Haigh, Northumbria University //
// Contact: paul.haigh@northumbria.ac.uk //
/////////////////////////////////////////////////////////////////////////////////////////////
#pragma rtGlobals=1 // Use modern global access method.
Function EyeDiagram(amplitude_vector,time_vector,nsamp)
//Declare Parameters
wave/Z amplitude_vector
wave time_vector
variable nsamp
// KillWave to avoid cross contamination of waves
killwaves/Z tvect_EyeDiagram
killwaves/Z amplitude_EyeDiagram
//Declare local variables
variable osamp
variable niterations
variable zeroed_iterations
variable i,j
variable amp_size
variable req_size
variable time_size
variable tsamp
// Generate new waves
Make/D/N=(numpnts(amplitude_vector))/O amplitude_EyeDiagram
amplitude_EyeDiagram=amplitude_vector // Copy amplitude_vector to avoid modification of original signal
DeletePoints 0, ceil(nsamp/2), amplitude_EyeDiagram // Offset to centre of the bit - ensures a full 1-0 and 0-1 transition is displayed
osamp=2*nsamp; // Oversamp (osamp) by two (hence why offsetting by half a bit)
niterations=numpnts(time_vector)/osamp
Make/D/N=(niterations+nsamp)/O tvect_EyeDiagram
tsamp=time_vector[2]-time_vector[1] // Find sampling interval for time vector
for(i=0;i<=niterations;i+=1)
for(j=0;j!=osamp+1;j+=1)
tvect_EyeDiagram[i*osamp+j]=j+1 // Generate the time vector
endfor
endfor
tvect_EyeDiagram=tvect_EyeDiagram*tsamp // Convert to bit rate relative time
// Insert zeros and convert them to NaNs to ensure no overlapping of bits
zeroed_iterations=niterations+niterations/osamp
for (i=0;i<=zeroed_iterations;i+=osamp+1)
InsertPoints i, 1, tvect_EyeDiagram
InsertPoints i, 1, amplitude_EyeDiagram
if (tvect_EyeDiagram[i]==0)
tvect_EyeDiagram[i]=NaN
if (amplitude_EyeDiagram[i]==0)
amplitude_EyeDiagram[i]=NaN
endif
endif
endfor
// Create conditions for variable sizes
req_size=zeroed_iterations
time_size=numpnts(tvect_EyeDiagram)
amp_size=numpnts(amplitude_EyeDiagram)
// Ensure waves are the same size using variable size conditions
if (amp_size!=req_size)
DeletePoints req_size, amp_size-req_size, amplitude_EyeDiagram
if (time_size!=req_size)
DeletePoints req_size, time_size-req_size, tvect_EyeDiagram
endif
endif
Display amplitude_EyeDiagram vs tvect_EyeDiagram
ModifyGraph tick=2,mirror=1,fStyle=1,fSize=14,standoff=0,width=425.197,height=283.465,lsize=2,rgb=(0,0,0)
Qfactor(amplitude_vector,nsamp)
end
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
// Qfactor calculation procedure for Igor Pro. //
// Author: Paul Anthony Haigh, Northumbria University //
// Contact: paul.haigh@northumbria.ac.uk //
/////////////////////////////////////////////////////////////////////////////////////////////
// Declare function and dependent variables
Function Qfactor(amplitude_vector,nsamp)
wave/Z amplitude_vector
variable nsamp
// KillWave to avoid cross contamination of waves
killwaves/Z amplitude_Qfactor
killwaves/Z amplitude_Qfactor_downsamp
killwaves/Z upper_vect
killwaves/Z lower_vect
killwaves/Z Q_factor
// Generate new waves
Make/D/N=(numpnts(amplitude_vector))/O amplitude_Qfactor
Make/D/N=(numpnts(amplitude_vector)/nsamp)/O amplitude_Qfactor_downsamp
// Procedure variables
variable i,j,k,q,ii,jj
variable mean_upper
variable mean_lower
variable std_upper
variable std_lower
variable Q_factor
amplitude_Qfactor=amplitude_vector // Copy amplitude_vector to avoid modification of original signal
WaveStats /M=1/Q/Z amplitude_Qfactor // Get WaveStats to find V_avg
amplitude_Qfactor=amplitude_Qfactor-V_avg // Make data bi-polar
// Downsample in the centre of the signal - data must start from the 0-1 or 1-0 transition. Change the first condition to select a different bit.
for (j=ceil(nsamp/2);j<=floor(numpnts(amplitude_Qfactor)/nsamp);j+=nsamp)
amplitude_Qfactor_downsamp[k]=amplitude_Qfactor[j]
k+=1
endfor
WaveStats /M=1/Q/Z amplitude_Qfactor_downsamp // Update WaveStats to find new V_avg
// Calculate mean and standard deviation of both levels
ii=0
jj=0
Make/D/N=(numpnts(amplitude_Qfactor_downsamp))/O upper_vect // Generate new vectors for each level
Make/D/N=(numpnts(amplitude_Qfactor_downsamp))/O lower_vect
// Sort downsampled data into the two new vectors
for (q=0;q<=numpnts(amplitude_Qfactor_downsamp);q+=1)
if (amplitude_Qfactor_downsamp[q]>=V_avg && amplitude_Qfactor_downsamp[q]!=0)
upper_vect[ii]=amplitude_Qfactor_downsamp[q]
ii+=1
elseif (amplitude_Qfactor_downsamp[q]<V_avg && amplitude_Qfactor_downsamp[q]!=0)
lower_vect[jj]=amplitude_Qfactor_downsamp[q]
jj+=1
endif
endfor
// Remove all points that follow the data to avoid corruption of the WaveStats
DeletePoints ii, numpnts(amplitude_Qfactor_downsamp), upper_vect
DeletePoints jj, numpnts(amplitude_Qfactor_downsamp), lower_vect
WaveStats /M=1/Q/Z upper_vect // Find V_avg of upper_vect
mean_upper=V_avg // Assign to a variable
WaveStats /M=2/Q/Z upper_vect // Find V_sdev of upper_vect
std_upper=V_sdev // Assign to a variable
KillVariables/Z V_avg // Remove variables to ensure no cross contamination
KillVariables/Z V_sdev
WaveStats /M=1/Q/Z lower_vect // Find V_avg of lower_vect
mean_lower=V_avg // Assign to a variable
WaveStats /M=2/Q/Z lower_vect // Find V_sdev of lower_vect
std_lower=V_sdev // Assign to a variable
KillVariables/Z V_avg // Remove variables to ensure no cross contamination
KillVariables/Z V_sdev
// Calculate Q-Factor and print
Q_factor=(mean_upper-mean_lower)/(std_upper+std_lower)
printf "Q-Factor = %g\r", Q_factor
// KillWaves to ensure no cross contamination
KillWaves/Z upper_vect
KillWaves/Z lower_vect
End
// Eye Diagram generation procedure for Igor Pro. //
// Author: Paul Anthony Haigh, Northumbria University //
// Contact: paul.haigh@northumbria.ac.uk //
/////////////////////////////////////////////////////////////////////////////////////////////
#pragma rtGlobals=1 // Use modern global access method.
Function EyeDiagram(amplitude_vector,time_vector,nsamp)
//Declare Parameters
wave/Z amplitude_vector
wave time_vector
variable nsamp
// KillWave to avoid cross contamination of waves
killwaves/Z tvect_EyeDiagram
killwaves/Z amplitude_EyeDiagram
//Declare local variables
variable osamp
variable niterations
variable zeroed_iterations
variable i,j
variable amp_size
variable req_size
variable time_size
variable tsamp
// Generate new waves
Make/D/N=(numpnts(amplitude_vector))/O amplitude_EyeDiagram
amplitude_EyeDiagram=amplitude_vector // Copy amplitude_vector to avoid modification of original signal
DeletePoints 0, ceil(nsamp/2), amplitude_EyeDiagram // Offset to centre of the bit - ensures a full 1-0 and 0-1 transition is displayed
osamp=2*nsamp; // Oversamp (osamp) by two (hence why offsetting by half a bit)
niterations=numpnts(time_vector)/osamp
Make/D/N=(niterations+nsamp)/O tvect_EyeDiagram
tsamp=time_vector[2]-time_vector[1] // Find sampling interval for time vector
for(i=0;i<=niterations;i+=1)
for(j=0;j!=osamp+1;j+=1)
tvect_EyeDiagram[i*osamp+j]=j+1 // Generate the time vector
endfor
endfor
tvect_EyeDiagram=tvect_EyeDiagram*tsamp // Convert to bit rate relative time
// Insert zeros and convert them to NaNs to ensure no overlapping of bits
zeroed_iterations=niterations+niterations/osamp
for (i=0;i<=zeroed_iterations;i+=osamp+1)
InsertPoints i, 1, tvect_EyeDiagram
InsertPoints i, 1, amplitude_EyeDiagram
if (tvect_EyeDiagram[i]==0)
tvect_EyeDiagram[i]=NaN
if (amplitude_EyeDiagram[i]==0)
amplitude_EyeDiagram[i]=NaN
endif
endif
endfor
// Create conditions for variable sizes
req_size=zeroed_iterations
time_size=numpnts(tvect_EyeDiagram)
amp_size=numpnts(amplitude_EyeDiagram)
// Ensure waves are the same size using variable size conditions
if (amp_size!=req_size)
DeletePoints req_size, amp_size-req_size, amplitude_EyeDiagram
if (time_size!=req_size)
DeletePoints req_size, time_size-req_size, tvect_EyeDiagram
endif
endif
Display amplitude_EyeDiagram vs tvect_EyeDiagram
ModifyGraph tick=2,mirror=1,fStyle=1,fSize=14,standoff=0,width=425.197,height=283.465,lsize=2,rgb=(0,0,0)
Qfactor(amplitude_vector,nsamp)
end
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
// Qfactor calculation procedure for Igor Pro. //
// Author: Paul Anthony Haigh, Northumbria University //
// Contact: paul.haigh@northumbria.ac.uk //
/////////////////////////////////////////////////////////////////////////////////////////////
// Declare function and dependent variables
Function Qfactor(amplitude_vector,nsamp)
wave/Z amplitude_vector
variable nsamp
// KillWave to avoid cross contamination of waves
killwaves/Z amplitude_Qfactor
killwaves/Z amplitude_Qfactor_downsamp
killwaves/Z upper_vect
killwaves/Z lower_vect
killwaves/Z Q_factor
// Generate new waves
Make/D/N=(numpnts(amplitude_vector))/O amplitude_Qfactor
Make/D/N=(numpnts(amplitude_vector)/nsamp)/O amplitude_Qfactor_downsamp
// Procedure variables
variable i,j,k,q,ii,jj
variable mean_upper
variable mean_lower
variable std_upper
variable std_lower
variable Q_factor
amplitude_Qfactor=amplitude_vector // Copy amplitude_vector to avoid modification of original signal
WaveStats /M=1/Q/Z amplitude_Qfactor // Get WaveStats to find V_avg
amplitude_Qfactor=amplitude_Qfactor-V_avg // Make data bi-polar
// Downsample in the centre of the signal - data must start from the 0-1 or 1-0 transition. Change the first condition to select a different bit.
for (j=ceil(nsamp/2);j<=floor(numpnts(amplitude_Qfactor)/nsamp);j+=nsamp)
amplitude_Qfactor_downsamp[k]=amplitude_Qfactor[j]
k+=1
endfor
WaveStats /M=1/Q/Z amplitude_Qfactor_downsamp // Update WaveStats to find new V_avg
// Calculate mean and standard deviation of both levels
ii=0
jj=0
Make/D/N=(numpnts(amplitude_Qfactor_downsamp))/O upper_vect // Generate new vectors for each level
Make/D/N=(numpnts(amplitude_Qfactor_downsamp))/O lower_vect
// Sort downsampled data into the two new vectors
for (q=0;q<=numpnts(amplitude_Qfactor_downsamp);q+=1)
if (amplitude_Qfactor_downsamp[q]>=V_avg && amplitude_Qfactor_downsamp[q]!=0)
upper_vect[ii]=amplitude_Qfactor_downsamp[q]
ii+=1
elseif (amplitude_Qfactor_downsamp[q]<V_avg && amplitude_Qfactor_downsamp[q]!=0)
lower_vect[jj]=amplitude_Qfactor_downsamp[q]
jj+=1
endif
endfor
// Remove all points that follow the data to avoid corruption of the WaveStats
DeletePoints ii, numpnts(amplitude_Qfactor_downsamp), upper_vect
DeletePoints jj, numpnts(amplitude_Qfactor_downsamp), lower_vect
WaveStats /M=1/Q/Z upper_vect // Find V_avg of upper_vect
mean_upper=V_avg // Assign to a variable
WaveStats /M=2/Q/Z upper_vect // Find V_sdev of upper_vect
std_upper=V_sdev // Assign to a variable
KillVariables/Z V_avg // Remove variables to ensure no cross contamination
KillVariables/Z V_sdev
WaveStats /M=1/Q/Z lower_vect // Find V_avg of lower_vect
mean_lower=V_avg // Assign to a variable
WaveStats /M=2/Q/Z lower_vect // Find V_sdev of lower_vect
std_lower=V_sdev // Assign to a variable
KillVariables/Z V_avg // Remove variables to ensure no cross contamination
KillVariables/Z V_sdev
// Calculate Q-Factor and print
Q_factor=(mean_upper-mean_lower)/(std_upper+std_lower)
printf "Q-Factor = %g\r", Q_factor
// KillWaves to ensure no cross contamination
KillWaves/Z upper_vect
KillWaves/Z lower_vect
End
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More