roseengineering / crystalweb

Measure a crystal using a Nanovna automatically
14 stars 3 forks source link

add ppm flag request, and "UnboundLocalError: local variable 'loss' referenced before assignment" #1

Open Joel-Mckay opened 3 years ago

Joel-Mckay commented 3 years ago

This is a great little utility, and perfect for sorting though bins of xtals. Any tips on the error would be helpful. =)

As far as I can tell, the NanoVNA-H does not have a ppm offset setting, and would require rebuilding the firmware to correct the error. Perhaps, I thought it would make sense to add the +-ppm offset to the xtal profile tool instead, but am unsure how well these devices vco are made.

Firmware: https://github.com/hugen79/NanoVNA-H.git NanoVNA-H_20210130.dfu

My 10MHz hc49 xtal scan example: 9.997225MHz series peak 10.017400MHz parallel dip

crystalweb Error seems to occur as peak scan window is narrowed a few times: scanning sample label X0... TITLE: X0 RL = 50.0 ohm fs = 9997132 Hz Rm = 30.44 ohm Traceback (most recent call last): File "/home/.../crystalweb_ladder_filter_designer/crystalweb/crystalweb.py", line 256, in main stray=args.stray, title=args.title) File "/home/.../crystalweb_ladder_filter_designer/crystalweb/crystalweb.py", line 185, in analyze_crystal sweep(fs - bw_df / 2, fs + bw_df / 2) TypeError: unsupported operand type(s) for /: 'NoneType' and 'int' And thus line 176 in crystalweb.py is never true: if not np.isnan(bw): bw_df = df

My test script to sort my parts bin:

`#!/bin/bash
#This xtal tester does scan steps needed to get a xtal filter design BOM
#
# apache 2.0 license
# 2021 Joel Mckay
# "Hello from VE7NTP" ;-)

#OS install:
# sudo /usr/bin/python3 -m pip install --upgrade pip
# sudo /usr/bin/python3 -m pip install --upgrade numpy

# Using the NanoVNA to design a crystal ladder filter 
xtalFreqMinHz="9900000"
xtalFreqHz="10000000"
xtalFreqMaxHz="10100000"
poles=4
testlotcount=20
mydev="/dev/ttyACM0"

#constants
mydir=$(pwd)
#todo: add GPSDO ppm offset correction at 10MHz
#this feature should be in the firmware, or added in the utils
nanovnaXtalPPMerror=90

#install deps
if [ ! -d $mydir/rffilter ]
then
    echo "install rffilter..."
    cd $mydir
    git clone --depth 1 https://github.com/roseengineering/rffilter.git
    chmod 750 $mydir/rffilter/rffilter.py
fi

if [ ! -d $mydir/crystalweb ]
then
    echo "install crystalweb..."
    cd $mydir
    git clone --depth 1 https://github.com/roseengineering/crystalweb.git
    chmod 750 $mydir/crystalweb/crystalweb.py
fi

if [ ! -d $mydir/logs ]
then
    mkdir -p $mydir/logs
fi

#calibrate xtal test jig part 1
echo ""
echo "===================================="
echo "measure test fixture stray capacitance?"
read -t 30 -n 1
if [ ! $? = 0 ] ; then
    exit ;
else
    echo "OK"
fi
cd $mydir/crystalweb
## $mydir/crystalweb/crystalweb.py  --fixture --device $mydev
cd $mydir

#calibrate xtal test jig part 2
echo ""
echo "===================================="
echo "measure test fixture loss?"
read -t 30 -n 1
if [ ! $? = 0 ] ; then
    exit ;
else
    echo "OK"
fi
cd $mydir/crystalweb
##$mydir/crystalweb/crystalweb.py  --loss --device $mydev
cd $mydir

#todo: add options to recall last inventory of unused xtals, or add new ones to the lot
echo ""
echo "===================================="
echo "Scan inserted xtal sample in socket?"
echo -ne ""  > $mydir/logs/log.csv
counter=0
cd $mydir/crystalweb
while [ $counter -lt $testlotcount ]
do
    read -t 300 -n 1
    if [ ! $? = 0 ] ; then
        exit ;
    else
        echo "scanning sample label X$counter..."
    fi

    $mydir/crystalweb/crystalweb.py --stray 1.1 --title X$counter --device $mydev --start $xtalFreqMinHz --stop $xtalFreqMaxHz >> $mydir/logs/log.csv
    counter=$((counter+1))

    if [ $counter -lt $testlotcount ]
    then
        echo "Inserted next xtal sample into socket?"
    fi
done
cd $mydir

#xtal selection
echo -ne ""  > $mydir/logs/xtals_unused.csv
echo -ne ""  > $mydir/logs/xtals.csv
sort --field-separator=',' --key 2 --numeric-sort $mydir/logs/log.csv >> $mydir/logs/xtals.csv

echo "XTAL,FS,CM,LM,RM,QU,CO"  > $mydir/xtal_BOM.csv
xtalparams=""
for selected in $(head -n $poles $mydir/logs/xtals.csv )
do
    xtalSeriesHz=$(echo "$selected" | cut -d',' -f2 )
    #todo: add skip to sorted index feq min match, and tale n closest xtal ids
    #if [ $xtalFreqMinHz -lt $xtalSeriesHz ]
    #then
        if [ "$xtalparams" == "" ]
        then
            xtalparams="$xtalSeriesHz"
        else
            xtalparams="$xtalparams,$xtalSeriesHz"
        fi
        #create part list for build
        echo "$selected" >> $mydir/xtal_BOM.csv
    #else 
    #log unused to remove parts from xtal inventory list?
        echo "$selected" >> $mydir/logs/xtals_unused.csv
    #fi
done

#calculate other schematic parts needed
echo ""
echo "====== Running rffilter on xtal_BOM.csv ======="
cd $mydir/rffilter
#todo: how to auto calculate this value
# --l 70e-3         resonator inductor values, can be given in common notation
$mydir/rffilter/rffilter.py --k chebyshev_0.5 --bw 2500 -n $poles  --l 70e-3  --crystal-mesh --f  "$xtalparams" | tee $mydir/xtal_filter.cir

echo "Done!"
exit 0

 #This filter is from an example in Steder's "Crystal Ladder Filters for All" paper in QEX.
./rffilter.py --g chebyshev_0.2 --n 8 --crystal-mesh --l 69.7e-3 --f 4913.57e3 --bw 2400 --ch 3.66e-12 | tee examples/xtal.cir
`
roseengineering commented 3 years ago

Thank you for the kind words. Sorry for the delay in responding.

I am glad crystalweb is working for you for batch quantification. Indeed batch use is why I designed it in the first place!

Regarding the issues you reported:

1) I fixed the first error you reported: the TypeError that gets thrown. So instead of crystalweb throwing an error now and breaking when it cannot find the series resonant frequency (line 176), it prints a gentle error message to the terminal.

2) I also added a --batch option to crystalweb making it repeat the measurement over and over, each time incrementing the part number and pausing before each measurement. (Use --part-number to continue an interrupted batch measurement)

3) As for your last issue, are you asking for an option like --ppm -100 which will adjust the frequency sweep range within the python code by multiplying it (but not the range sent to the firmware) by .9999?