From 13d64488802fba70b1ebbd754e4b3d484c50b5e5 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Wed, 10 Apr 2019 09:57:37 -0400 Subject: [PATCH 01/71] Initial release of PulseStreamer Driver Module PulseStreamerMaster module and Seqcommand added to branch. --- .../PulseStreamerMaster.m | 804 ++++++++++++++++++ .../+PulseStreamerMaster/seqCommand.m | 30 + 2 files changed, 834 insertions(+) create mode 100644 Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m create mode 100644 Modules/+Drivers/+PulseStreamerMaster/seqCommand.m diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m new file mode 100644 index 000000000..4b6a0665f --- /dev/null +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -0,0 +1,804 @@ + +classdef PulseStreamerMaster < Modules.Driver + % PulseStreamerMaster is located in in CommandCenter > Modules > + % +Drivers > +PulseStreamer + % The PulseStreamerMaster class is a driver module class which + % builds and uploads pulse sequences to the Swabian Pulse Streamer and, + % optionally, runs them. Pulse sequences can also be run or halted + % using hardware or software triggers. + % + % The PulseStreamerMaster module require the Matlab Toolbox for the + % Pusle Streamer (provided by Swabian). + % + % The constructor of this class accepts two inputs upon instantiation: + % the IP address of the hardware and a pulse sequence instruction set + % written in JSON format. An example of the JSON instruction set format + % is given below: + % + % { + % "name":"MyPulseSequence", + % "units":"ns", + % "forever":false, + % "channels":["channel1","MW Switch","","channel4"], + % "sequence":[ + % {"flags":[0,0,0,1],"duration":0,"instruction":"CONTINUE","data":null}, + % {"flags":[0,1,1,0],"duration":1,"instruction":"LOOP","data":2}, + % {"flags":[0,0,0,1],"duration":18,"instruction":"CONTINUE","data":null}, + % {"flags":[0,1,0,1],"duration":19,"instruction":"END_LOOP","data":null}, + % {"flags":[0,0,0,1],"duration":20,"instruction":"CONTINUE","data":null}, + % ] + % } + % + % Here "name", "units", and "channels" are human readable descriptors. + % The "forever" field is a boolean that specifies whether or not to + % loop the pulse sequence indefinitely. + % + % The sequence is defined by four fields: + % 1. flags: an array of boolean states for the relevant channels. + % 2. duration: the duration of the pulse for the associated states. + % 3. data: the span of the loop, i.e., the numer of loop interations. + % 4. instruction: determines the action to be performed. + % i. CONTINUE: run the associated line of instructions + % ii. LOOP: run the associated line of instructions and all + % the instructions between LOOP and END_LOOP for 'data' + % iterations. + % iii. END_LOOP: terminate the loop and run the associated + % instructions. + % + % The above defines a simple programming language (an example + % of a domain specific language) to describe pulse sequences. + % + % Typical workflow for running a pulse sequence: + % 1. Initialize instructions and communication to Pulse Streamer + % 2. Build pulse sequence from JSON string + % 3. Load pulse sequence into Pulsestreamer + % 4. Run pulse sequence (optional, since this can be done through + % software or hardware triggers). + % 5. Halt pulse sequence (optional). + % 6. Delete function to deallocate resources for the Pulse Streamer Master object. + % + % Example Code: + % ip = '192.168.11.2'; + % filename = 'JSON_sequence.js'; + % json = fileread(filename); + % PSM = PulseStreamerMaster(ip); + % PSM.build(json); + % PSM.load(); + % PSM.run(); + % PSM.delete(); + + + properties(SetAccess=private,SetObservable) + % physical IP address of Pulse Streamer hardware + ipAddress='192.168.11.2'; + end + + properties(SetAccess=private) + % Object that provides the interface to the + % Pulse Streamer hardware. this object provides access run, halt + % and trigger operation, and plotting features for the Pulse + % Streamer. + PS; + % + builder; %PusleSequenceBuilder object used to build pulse sequences. + + triggerStart; + triggerMode; + % string containing pulse sequence instruction set in JSON format + json; + % A fully unrolled sequence of instructions. By "unrolled", we + % mean that all loops at all depths have been written out as an + % iteration by iteration sequence of instructions. Note: the + % recursive algorithm we use to unroll the loops requires that + % the cmd object be passed by reference; that is, we pass the + % actual object, not a copy of it. + cmd = Drivers.PulseStreamerMaster.seqCommand(); + map = Drivers.PulseStreamerMaster.seqCommand(); + sequence = []; + seq_meta = []; + finalState; + end + + methods(Static) + function obj = instance() + mlock; + persistent Object + if isempty(Object) || ~isvalid(Object) + Object = Drivers.PulseStreamerMaster.PulseStreamerMaster(); + end + obj = Object; + end + end + + methods(Access={?Drivers.PulseStreamerMaster.PulseStreamerMaster}) + + function obj = PulseStreamerMaster(ip) + % Constructor for this class. + % ip: IP address of hardware + % json: string containing instructions in JSON format + % + % Workflow for constructor: + % 1. set obj.ipAddress to ip address and obj.json to json string + % 2. instantiate a PulseStreamer object as the property obj.PS. + % The PulseStreamer class is provided by Swabain. It + % contains stream, trigger, ForceFinal, and start methods which + % enable the loading, running and halting of pulse sequences. + % 3. instantiate a PSSequenceBuidler object as the property + % obj.builder. PSSequenceBuilder is also provided by Swabian. + % It contains a builder method for building pulse sequences + % in the format required by the PulseStreamer class. + + switch nargin + case 0 + ip = obj.ipAddress; + end + + obj.PS = PulseStreamer.PulseStreamer(ip); + obj.triggerStart = PulseStreamer.TriggerStart.SOFTWARE(); + obj.triggerMode = PulseStreamer.TriggerRearm.AUTO(); + obj.sequence = obj.PS.createSequence(); + obj.PS.reset(); + obj.map.command(:)=[]; + obj.cmd.command(:)=[]; + % initialize final state to 0V for all channels. + obj.finalState= PulseStreamer.OutputState.ZERO; + end + + end + + methods(Access=public) + function build(obj,json) + % This method converts the instructions in the obj.json to a + % PulseStreamer sequence object. Meta data for the sequence is + % reported in the seq_meta output. Its structure is as follows + % + % seq_meta: + % seq_meta.channels : 1X8 (channels 0-7). Order of channels + % is as follows. + % ['Ch0', 'Ch1', 'Ch2', 'Ch3', + % 'Ch4', 'Ch5', 'Ch6', 'Ch7'] + % Label for each channel is determined by channel field + % E.G. seq_meta.channels = ['532nm', + % 'Res_Repump','MW1','MW2', + % 'MW3','ORES','1050nm',''] + % Ch0 -> 532nm + % Ch0 -> Res_Repump + % Ch0 -> MW1 + % Ch0 -> MW2 + % Ch0 -> MW3 + % Ch0 -> ORES + % Ch0 -> 1050nm + % + % + % seq_meta.units: time units for pulse durations + % seq_meta.name: label for sequence. + % seq_meta.forever: boolean indicating whether to + % repeat sequence indefinitely until explicitly halted. + % + % The build method workflow is as follows: + % 1. Determine if json input is a string or a json file name + % (a name with extension .js). If it is the name of a JSON + % file, open the file and reads the entire contents into + % a single string and replace the obj.json with that + % string; otherwise, we assume this is a string in JSON + % format. + % 2. Parse JSON string into + % a. json_seq: a cell array of maps (i.e., a list of + % dictionaries) + % b. seq_meta: the remaining meta data for the + % sequnece + % 3. Build instruction tree recursively from json_seq using + % the decodeInstructions method. + % 4. Unroll the instruction tree recurrsivley into a 1D cell + % array of maps, where each map contains the duration and + % channel flags for that step in the pulse sequence. + % 5. Initialize pulse_train, a cell array of dimension + % C{num_channels}{1}{length(map_list),2} + % 6. Fill the cell array with pulse sequence data. + % 7. Distribute pulse sequence data for each channel and + % set digital channels of ???pulsestrerer???. + % 8. Build pulse sequence object. + DEBUG = 0; + + obj.json = json; + depth = 0; % depth of recursion + index = 1; % index into cell array of intructions + pulse_trains = {}; % initialize pulse_train cell array + + % Test if obj.json is a file. If a file name, read + % file and replace obj.json with the file contents as a + % single string + if strcmp(obj.json(end-2:end),'.js') + obj.json = fileread(obj.json); + elseif strcmp(obj.json(end-3:end),'.txt') + %write error checking in the future. + end + + % convert obj.json into a list (actually a cell array) of + % ordered maps (json_seq) describing the pulse sequence and + % seq_meta + [json_seq,obj] = obj.readJSON(); + + %debugging issues if this class cannot inherit from the handle + %class. + if DEBUG > 0 + fprintf('output from readJSON is: \n'); + fprintf('PSM.seq_meta is: \n'); + disp(obj.seq_meta); + end + + % expand list of instructions into a tree or instructions + % recurrsively. The result is contained in the object obj.cmd. + % obj.cmd is passed throughout the code by reference (via a + % handle). + [index] = obj.decodeInstructions(json_seq, obj.cmd); + + % unroll the instruction tree and all loops recursively + % into a properly ordered cell array of maps. Each map contains + % the instructions for a pulse sequence step (duration and flag + % fields). + obj.unroll_tree(obj.cmd,obj.map); + + % ------------------------- + % BUILD PULSE TRAINS + % A pulse train is a list + % comprising an alternating + % sequence of duration + % followed by flag, that is, + % channel state, 0 (low) or + % 1 (high). + % ------------------------- + % initialize pulse_trains (a cell array), to be filled with + % an alternating sequence of duration and flag, using the + % unrolled instructions in map.command. + ch_train = cell(length(obj.map.command),2); + + for kk = 1:1:length(obj.seq_meta.channels) + pulse_trains{end+1} = {ch_train}; + end + + % fill pulse trains + for ii = 1:1:length(obj.map.command) + % for each channel fill the pulse duration and flag + % (channel state) into the pulse_trains cell array. + flags = obj.map.command{ii}('flag'); + duration = obj.map.command{ii}('duration'); + for jj = 1:1:length(obj.seq_meta.channels) + state = flags(jj); + pulse_trains{jj}{1}{ii,1} = duration; + pulse_trains{jj}{1}{ii,2} = state; + + end + end + + % Build the digital pattern (a sequence of duration, + % channel state pairs in that order) for each channel. + for kk = 1:1:length(obj.seq_meta.channels) + ch = kk-1; + digitalPattern = pulse_trains{kk}{1}; + obj.sequence.setDigital(ch, digitalPattern); + end + end + + function plot(obj) + %plot the sequence + obj.sequence.plot(); + end + + + function load(obj,repeats) + % The load method converts the sequence object to the properly + % formated 64 bit string and uploads this to the xilinx chip in the + % pulse streamer via an eithernet connection managed by a hardware + % server. + + switch nargin + case 1 + repeats = 1; + end + + start = obj.triggerStart;%initialize the trigger to be software defined + mode = obj.triggerMode; % initialize the trigger to be rearmed after each run. + obj.PS.setTrigger(start, mode); % set triggers + + if obj.seq_meta.forever == 1 + runs =-1; %run until halt() is called + else + runs = repeats; + end + + % upload sequence to hardware, but do not run the sequence. + obj.PS.stream(obj.sequence,runs,obj.finalState); + end + + + function run(obj) + % starts the sequence if the sequence was uploaded with the + % PSStart.Software option + obj.PS.startNow(); + end + + function halt(obj) + % Interrupt the sequence and set the final state of the + % hardware. This method does not modify the final state if + % the sequence has already finished. This method also releases + % the hardware resources of the Pulse Streamer and, therefore, + % allows for faster upload sequence during next call of + % "stream" method. + obj.PS.forceFinal() + end + + function [index] = decodeInstructions(obj, json_seq, cmd, depth, index) + % NOTE: we shall use list and cell array interchangeably. + % NOTE: cmd is the variable in which data is appended to it upon + % recursion. To ensure the cmd is appropriately appended the + % property obj.cmd is passed to decodeInstructor when this function + % is called. Whereas in the recursive step within this defintion + % the local variable cmd is passed to decodeInstructions. + % Decode instruction takes in a cell array of maps (json_seq), + % where each map contains the information in a single line of the + % JSON string and builds a tree structure that describes the + % program to be executed that yields ultimately the pulse + % sequences. This method handles arbitrary sequences of nested + % LOOP, END_LOOP, and CONTINUE instructions. The method is called + % recursively for each loop instruction. + + % When DEBUG = 0 then report the length cmd.command, the recursion depth, + % the index of the current instuction line and the instruction. + DEBUG = 0; + + if DEBUG > 0 + %a = length(json_seq); + %fprintf('length of JSON string %i\n\n',a); + %fprintf('number of args %i\n\n',nargin); + end + + % When DEBUG = 0 notify user they have entered the + % decodeInstructions method. + if DEBUG > 0 + fprintf('Enter decodeInstructions function\n'); + end + + % default values for recurrsion depth and instruction index + switch nargin + case 3 + depth = 0; + index = 1; + end + + % When the index has reached or surpassed the number of + % instructions then exit decodeInstructions and return values. + if index >= length(json_seq) + return; + end + + % get current instruction + instruction = json_seq{index}('instruction'); + + % Prior to any recursive calls to decodeInstructions create an + % empty cell array (similar to a list in python) when the + % instruction is a LOOP. + + % NOTE: we shall use list and cell array interchangeably. + + depth = depth + 1; + if depth == 1 + % create empty list only if first instruction is a LOOP + if strcmp(instruction, 'LOOP') + cmd.append(Drivers.PulseStreamerMaster.seqCommand()); + end + % The number of nested loops should never exceed 10 since + % the pulse blaster has a maximum allowable nesting depth of 8. + elseif depth > 10 + return + end + + + % if the last element of cmd is a list, then get that list + % otherwise use the list cmd directly. this takes into + % account the cases where CONTINUEs may not reside within + % LOOPs. + c_cmd = cmd; + + % verify cmd isn not empty, otherwise you will keep nesting lists + % unwantedly + if length(cmd.command) > 0 + % Is the last element in cmd a cell array of maps + if isa(cmd.command{end}, 'Drivers.PulseStreamerMaster.seqCommand') + c_cmd = cmd.command{end}; + end + end + + %Debugging: report the length of cmd.command to track its growth + if DEBUG > 0 + fprintf('CMD length is: %i\n\n',length(cmd.command)) + end + + % add the instruction at index in the JSON file to the + % current list of instructions + c_cmd.append(json_seq{index}); + + %Debugging: report recursion depth, current instruction and + %instruction index. + if DEBUG > 0 + fprintf('depth = %5d\tinstruction: %s, %d\n',depth,instruction,index); + end + + % loop over the instructions in the json list + while index < length(json_seq) + index = index + 1; % IMPORTANT: remember to increment index into json list + + % get instruction type + instruction = json_seq{index}('instruction'); + + %Debugging: report recursion depth, current instruction and + %instruction index. + if DEBUG > 0 + fprintf('depth = %5d\tinstruction: %s, %d\n', depth,instruction,index); + end + + % Decide what to do depending on instruction type + if strcmp(instruction,'END_LOOP') + c_cmd.append(json_seq{index}); + % we must return in order that decodeInstructions + % terminates so that the decoder can continue to + % the next json instruction + return % Important, this is a terminating case + % for the recursion + + elseif strcmp(instruction,'LOOP') + % since this is a loop, create a new empty list to + % receive the instructions for this loop. + % IMPORTANT: the value of index can change within + % decodeInstructions, so we must return it + c_cmd.append(Drivers.PulseStreamerMaster.seqCommand) + + %Debugging: report current instruction data. + if DEBUG > 0 + fprintf('In loop current command is\n') + disp(c_cmd(end)) + end + index = obj.decodeInstructions(json_seq,c_cmd(end),depth,index); + + %Debugging: report current index. + if DEBUG > 0 + fprintf('index %d\n', index); + end + + elseif strcmp(instruction,'CONTINUE') + %since this is a continue statement we will simply + %append the instruction data to the cmd.(remember c_cmd + %is handle for cmd). + c_cmd.append(json_seq{index}); + + else + error('** error decoding JSON file\n') + + end + end + end + + + function unroll_tree(obj,cmd,map,depth) + % unroll_tree rolls all the instructions in the instruction + % tree into a 1 dimensional cell array of maps. + % NOTE: cmd and map are the variables in which data is appended to each + % upon recursion. To ensure the cmd and map are appropriately appended the + % property obj.cmd and obj.map are passed to unroll_tree when this function + % is called. Whereas in the recursive step within this defintion + % the local variables cmd.command{c} and map are passed to decodeInstructions. + + DEBUG = 0; + %DEBUGGING: reprot when unroll_tree function has been called. + if DEBUG>0 + fprintf('\n\nIn unroll_tree\n'); + end + + %Default values for map and depth. + switch nargin + case 3 + depth = 0; + end + + % Debugging: grow/ concatentate a string of tabs every time + % unroll_tree recurses. Proves pretty printing to ilustrate + % loop nesting. + if DEBUG > 0 + tab = ''; + for i=1:1:depth + tab = strcat('...',tab); + end + end + + % loop over top level instructions of abstract syntax tree, + % here called cmd + for c = 1:1:length(cmd.command) + % if current instruction is a list of instructions, then + % loop over those instructions + + % Debugging: Confirm tht execute_loop should be ran. + if DEBUG > 1 + fprintf('Condition to enter execute loop true? '); + disp(isa(cmd.command{c},'Drivers.PulseStreamerMaster.seqCommand')) + end + + if isa(cmd.command{c},'Drivers.PulseStreamerMaster.seqCommand') + obj.execute_loop(cmd.command{c},map,depth); + else + % this is not a list, but a map + + % Debugging: report recursion depth, current instruction and + %i nstruction index. + if DEBUG > 0 + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + cmd.command{c}('instruction'), ... + cmd.command{c}('duration'), ... + cmd.command{c}('flag').'); + end + + obj.map.append(cmd.command{c}); + + end + end + end + + + function printTree(obj, cmd, depth) + % Print the Tree of instructions + + % Default arguments + switch nargin + case 2 + depth = 0; + end + + % track recurrsion depths + %kick out printTree if recurrsion depth exceeds 10 + depth = depth + 1; + if depth == 1 + fprintf('\n'); + elseif depth > 10 + return + end + fprintf('depth: %i\n' , depth); + + tab = ''; + for i=1:depth + + tab = strcat('...',tab); + end + + % Loop acrous length of cmd cell array (list). If a list is found then + % printTree of that list. Please note that the seqCommand is a + % hadnle class which allows for the concatenation of any item + % type (i.e. itis analogous to a list). + for ii = 1:1:length(cmd.command) + c = cmd.command{ii}; + if isa(c,'Drivers.PulseStreamerMaster.seqCommand') + obj.printTree(c,depth); + else + % Otherwise the current intstruction is a map + % print is and the depth layer, flags and index. + fprintf('%s%s: duration = %i, flags = %i %i %i %i, data = %d\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').', ... + c('data')); + end + end + end + + function map = execute_loop(obj,cmd,map,depth) + + DEBUG = 0; + + if DEBUG > 1 + fprintf('\n\nIn execute_loop\n'); + end + + % Default arguments + switch nargin + case 2 + map = Drivers.PulseStreamerMaster.seqCommand(); + depth = 0; + case 3 + depth = 0; + end + + %increment recurssion depth and return if depth exceeds 10. + depth = depth+1; + + if depth > 10 + return; + end + + if DEBUG > 0 + tab = ''; + for i=1:depth + tab = strcat('...',tab); + end + end + + %current loop instruction. By default if this function is + %executed then the first instruction in the list is LOOP. + c = cmd.command{1}; + + % LOOP instruction + %Debugging: Report instruction in loop + if DEBUG > 0 + fprintf('%s%s: duration = %i, flags = %i %i %i %i, data = %d\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').', ... + c('data')); + + end + + %error handling + if ~strcmp(c('instruction'),'LOOP') + error('Expected LOOP instruction, but found %s\n', c('instruction')) + end + + %Debugging: Current map to concatenate + if DEBUG > 1 + fprintf('Current map to be appended: '); + disp(c) + end + + %append current map + map.append(cmd.command{1}); + + %Debugging: Display updated list of instruction maps + if DEBUG > 1 + fprintf('Current list of maps: '); + disp(map) + end + + % Implement loop + loop_cmd = cmd.command; + span = c('data'); %number of times to increment loop + + for ii = 1:1:span + % loop over instructions for current loop + % excluding the LOOP and END_LOOP instructions + + if DEBUG > 1 + disp(length(loop_cmd)) + end + + %skip 1 and last instruction set since these are not looped + %over (i.e. the instructions on LOOP and END_LOOP are + %always ran before and after the curret loop, respectively. + %Loop over remainging instructions. + for jj = 2:1:(length(loop_cmd)-1) + + if DEBUG > 1 + fprintf('current jj: '); + disp(jj) + end + + %if an instruction within this loop is LOOP then + %recurse into execute_loop. + if isa(loop_cmd{jj},'Drivers.PulseStreamerMaster.seqCommand') + + if DEBUG > 1 + fprintf('current loop instruction: '); + disp(loop_cmd{jj}) + end + obj.execute_loop(loop_cmd{jj},map,depth); + % continue to next instruction for this loop + continue + end + % Otherwise current instruction must be a CONTINUE + % so just execute it + c = loop_cmd{jj}; + + %append map of continue instruction. + map.append(c); + + % Debugging: report recursion depth, current instruction and + % instruction index. + if DEBUG > 0 + + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').'); + end + + %If instruction is not CONTINUE then throw error. + if ~strcmp(c('instruction'),'CONTINUE') + error('Expected CONTINUE instruction, but found %s\n', ... + c('instruction')) + end + end + end + + % END_LOOP instruction is last instruction in list of loop + % instructions + c = cmd.command{end}; + + % append map of continue instruction. + map.append(c); + + % Debugging: report recursion depth, current instruction and + % instruction index. + if DEBUG > 0 + + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').'); + end + + %Throw error last instruction in loop is not 'END_LOOP' + if ~strcmp(c('instruction'),'END_LOOP') + error('Expected END_LOOP instruction, but found %s\n', ... + c('instruction')) + end + + %Debugging: Notify when exiting execute_loop + if DEBUG > 0 + fprintf('\n\nExiting execute_loop\n'); + end + end + + function [json_seq,obj] = readJSON(obj) + % readJSON converts the json string stored in obj.json into a cell + % array of maps, where each field in the map correspond to the + % fields in the json string sequence field. The remaining data in + % the obj.json string is store in seq_meta: a structure data type + % which houses the channels, units name and forever fields for the + % pulse sequence. + + DEBUG = 0; + + % convert json string into a structure + json_total = jsondecode(obj.json); + json_struct = json_total.sequence; + + %initialize the json_seq cell array and fill each element in + %array with map for each instruction line. + json_seq = cell(1,length(json_struct)); + for i=1:1:length(json_struct) + cells = struct2cell(json_struct(i)); + key_labels = {'flag','duration','instruction','data'}; + json_seq{i} = containers.Map(key_labels,cells); + end + + %return remaining human readabl fields (channels, units, name, + %forever) to seq_meta + seq_metadata.channels = json_total.channels; + seq_metadata.units = json_total.units; + seq_metadata.name = json_total.name; + seq_metadata.forever = json_total.forever; + + obj.seq_meta = seq_metadata; + + if DEBUG>0 + fprintf('seq_meta output of readJSON: \n'); + disp(obj.seq_meta); + end + end + + + end + + methods + + % Destructor method. Clears object properties. + function delete(obj) + if obj.PS.isStreaming() == 1 + obj.halt() + elseif obj.PS.hasSequence() == 1 + obj.halt() + end + end + end +end + diff --git a/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m b/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m new file mode 100644 index 000000000..24b71e40e --- /dev/null +++ b/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m @@ -0,0 +1,30 @@ +classdef seqCommand < handle + properties + command={}; + %appended_value = {}; + + end + + + + methods + + function obj = seqCommand() + obj.command(:) = []; + end + + function append(obj,appended_value) + obj.command{end+1} = appended_value; + end + + function delete(obj) + %fprintf("I'm a sequence command and that's ok. I'm about to be deleted.\n") + end + + function element = end_array(obj) + element = obj.command{end}; + end + + end + +end From 3d1d43fd093ba212707c676c9e77297d2c22f725 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Wed, 10 Apr 2019 09:57:37 -0400 Subject: [PATCH 02/71] Initial release of PulseStreamer Driver Module PulseStreamerMaster module and Seqcommand added to branch. --- .../PulseStreamerMaster.m | 804 ++++++++++++++++++ .../+PulseStreamerMaster/seqCommand.m | 30 + 2 files changed, 834 insertions(+) create mode 100644 Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m create mode 100644 Modules/+Drivers/+PulseStreamerMaster/seqCommand.m diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m new file mode 100644 index 000000000..4b6a0665f --- /dev/null +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -0,0 +1,804 @@ + +classdef PulseStreamerMaster < Modules.Driver + % PulseStreamerMaster is located in in CommandCenter > Modules > + % +Drivers > +PulseStreamer + % The PulseStreamerMaster class is a driver module class which + % builds and uploads pulse sequences to the Swabian Pulse Streamer and, + % optionally, runs them. Pulse sequences can also be run or halted + % using hardware or software triggers. + % + % The PulseStreamerMaster module require the Matlab Toolbox for the + % Pusle Streamer (provided by Swabian). + % + % The constructor of this class accepts two inputs upon instantiation: + % the IP address of the hardware and a pulse sequence instruction set + % written in JSON format. An example of the JSON instruction set format + % is given below: + % + % { + % "name":"MyPulseSequence", + % "units":"ns", + % "forever":false, + % "channels":["channel1","MW Switch","","channel4"], + % "sequence":[ + % {"flags":[0,0,0,1],"duration":0,"instruction":"CONTINUE","data":null}, + % {"flags":[0,1,1,0],"duration":1,"instruction":"LOOP","data":2}, + % {"flags":[0,0,0,1],"duration":18,"instruction":"CONTINUE","data":null}, + % {"flags":[0,1,0,1],"duration":19,"instruction":"END_LOOP","data":null}, + % {"flags":[0,0,0,1],"duration":20,"instruction":"CONTINUE","data":null}, + % ] + % } + % + % Here "name", "units", and "channels" are human readable descriptors. + % The "forever" field is a boolean that specifies whether or not to + % loop the pulse sequence indefinitely. + % + % The sequence is defined by four fields: + % 1. flags: an array of boolean states for the relevant channels. + % 2. duration: the duration of the pulse for the associated states. + % 3. data: the span of the loop, i.e., the numer of loop interations. + % 4. instruction: determines the action to be performed. + % i. CONTINUE: run the associated line of instructions + % ii. LOOP: run the associated line of instructions and all + % the instructions between LOOP and END_LOOP for 'data' + % iterations. + % iii. END_LOOP: terminate the loop and run the associated + % instructions. + % + % The above defines a simple programming language (an example + % of a domain specific language) to describe pulse sequences. + % + % Typical workflow for running a pulse sequence: + % 1. Initialize instructions and communication to Pulse Streamer + % 2. Build pulse sequence from JSON string + % 3. Load pulse sequence into Pulsestreamer + % 4. Run pulse sequence (optional, since this can be done through + % software or hardware triggers). + % 5. Halt pulse sequence (optional). + % 6. Delete function to deallocate resources for the Pulse Streamer Master object. + % + % Example Code: + % ip = '192.168.11.2'; + % filename = 'JSON_sequence.js'; + % json = fileread(filename); + % PSM = PulseStreamerMaster(ip); + % PSM.build(json); + % PSM.load(); + % PSM.run(); + % PSM.delete(); + + + properties(SetAccess=private,SetObservable) + % physical IP address of Pulse Streamer hardware + ipAddress='192.168.11.2'; + end + + properties(SetAccess=private) + % Object that provides the interface to the + % Pulse Streamer hardware. this object provides access run, halt + % and trigger operation, and plotting features for the Pulse + % Streamer. + PS; + % + builder; %PusleSequenceBuilder object used to build pulse sequences. + + triggerStart; + triggerMode; + % string containing pulse sequence instruction set in JSON format + json; + % A fully unrolled sequence of instructions. By "unrolled", we + % mean that all loops at all depths have been written out as an + % iteration by iteration sequence of instructions. Note: the + % recursive algorithm we use to unroll the loops requires that + % the cmd object be passed by reference; that is, we pass the + % actual object, not a copy of it. + cmd = Drivers.PulseStreamerMaster.seqCommand(); + map = Drivers.PulseStreamerMaster.seqCommand(); + sequence = []; + seq_meta = []; + finalState; + end + + methods(Static) + function obj = instance() + mlock; + persistent Object + if isempty(Object) || ~isvalid(Object) + Object = Drivers.PulseStreamerMaster.PulseStreamerMaster(); + end + obj = Object; + end + end + + methods(Access={?Drivers.PulseStreamerMaster.PulseStreamerMaster}) + + function obj = PulseStreamerMaster(ip) + % Constructor for this class. + % ip: IP address of hardware + % json: string containing instructions in JSON format + % + % Workflow for constructor: + % 1. set obj.ipAddress to ip address and obj.json to json string + % 2. instantiate a PulseStreamer object as the property obj.PS. + % The PulseStreamer class is provided by Swabain. It + % contains stream, trigger, ForceFinal, and start methods which + % enable the loading, running and halting of pulse sequences. + % 3. instantiate a PSSequenceBuidler object as the property + % obj.builder. PSSequenceBuilder is also provided by Swabian. + % It contains a builder method for building pulse sequences + % in the format required by the PulseStreamer class. + + switch nargin + case 0 + ip = obj.ipAddress; + end + + obj.PS = PulseStreamer.PulseStreamer(ip); + obj.triggerStart = PulseStreamer.TriggerStart.SOFTWARE(); + obj.triggerMode = PulseStreamer.TriggerRearm.AUTO(); + obj.sequence = obj.PS.createSequence(); + obj.PS.reset(); + obj.map.command(:)=[]; + obj.cmd.command(:)=[]; + % initialize final state to 0V for all channels. + obj.finalState= PulseStreamer.OutputState.ZERO; + end + + end + + methods(Access=public) + function build(obj,json) + % This method converts the instructions in the obj.json to a + % PulseStreamer sequence object. Meta data for the sequence is + % reported in the seq_meta output. Its structure is as follows + % + % seq_meta: + % seq_meta.channels : 1X8 (channels 0-7). Order of channels + % is as follows. + % ['Ch0', 'Ch1', 'Ch2', 'Ch3', + % 'Ch4', 'Ch5', 'Ch6', 'Ch7'] + % Label for each channel is determined by channel field + % E.G. seq_meta.channels = ['532nm', + % 'Res_Repump','MW1','MW2', + % 'MW3','ORES','1050nm',''] + % Ch0 -> 532nm + % Ch0 -> Res_Repump + % Ch0 -> MW1 + % Ch0 -> MW2 + % Ch0 -> MW3 + % Ch0 -> ORES + % Ch0 -> 1050nm + % + % + % seq_meta.units: time units for pulse durations + % seq_meta.name: label for sequence. + % seq_meta.forever: boolean indicating whether to + % repeat sequence indefinitely until explicitly halted. + % + % The build method workflow is as follows: + % 1. Determine if json input is a string or a json file name + % (a name with extension .js). If it is the name of a JSON + % file, open the file and reads the entire contents into + % a single string and replace the obj.json with that + % string; otherwise, we assume this is a string in JSON + % format. + % 2. Parse JSON string into + % a. json_seq: a cell array of maps (i.e., a list of + % dictionaries) + % b. seq_meta: the remaining meta data for the + % sequnece + % 3. Build instruction tree recursively from json_seq using + % the decodeInstructions method. + % 4. Unroll the instruction tree recurrsivley into a 1D cell + % array of maps, where each map contains the duration and + % channel flags for that step in the pulse sequence. + % 5. Initialize pulse_train, a cell array of dimension + % C{num_channels}{1}{length(map_list),2} + % 6. Fill the cell array with pulse sequence data. + % 7. Distribute pulse sequence data for each channel and + % set digital channels of ???pulsestrerer???. + % 8. Build pulse sequence object. + DEBUG = 0; + + obj.json = json; + depth = 0; % depth of recursion + index = 1; % index into cell array of intructions + pulse_trains = {}; % initialize pulse_train cell array + + % Test if obj.json is a file. If a file name, read + % file and replace obj.json with the file contents as a + % single string + if strcmp(obj.json(end-2:end),'.js') + obj.json = fileread(obj.json); + elseif strcmp(obj.json(end-3:end),'.txt') + %write error checking in the future. + end + + % convert obj.json into a list (actually a cell array) of + % ordered maps (json_seq) describing the pulse sequence and + % seq_meta + [json_seq,obj] = obj.readJSON(); + + %debugging issues if this class cannot inherit from the handle + %class. + if DEBUG > 0 + fprintf('output from readJSON is: \n'); + fprintf('PSM.seq_meta is: \n'); + disp(obj.seq_meta); + end + + % expand list of instructions into a tree or instructions + % recurrsively. The result is contained in the object obj.cmd. + % obj.cmd is passed throughout the code by reference (via a + % handle). + [index] = obj.decodeInstructions(json_seq, obj.cmd); + + % unroll the instruction tree and all loops recursively + % into a properly ordered cell array of maps. Each map contains + % the instructions for a pulse sequence step (duration and flag + % fields). + obj.unroll_tree(obj.cmd,obj.map); + + % ------------------------- + % BUILD PULSE TRAINS + % A pulse train is a list + % comprising an alternating + % sequence of duration + % followed by flag, that is, + % channel state, 0 (low) or + % 1 (high). + % ------------------------- + % initialize pulse_trains (a cell array), to be filled with + % an alternating sequence of duration and flag, using the + % unrolled instructions in map.command. + ch_train = cell(length(obj.map.command),2); + + for kk = 1:1:length(obj.seq_meta.channels) + pulse_trains{end+1} = {ch_train}; + end + + % fill pulse trains + for ii = 1:1:length(obj.map.command) + % for each channel fill the pulse duration and flag + % (channel state) into the pulse_trains cell array. + flags = obj.map.command{ii}('flag'); + duration = obj.map.command{ii}('duration'); + for jj = 1:1:length(obj.seq_meta.channels) + state = flags(jj); + pulse_trains{jj}{1}{ii,1} = duration; + pulse_trains{jj}{1}{ii,2} = state; + + end + end + + % Build the digital pattern (a sequence of duration, + % channel state pairs in that order) for each channel. + for kk = 1:1:length(obj.seq_meta.channels) + ch = kk-1; + digitalPattern = pulse_trains{kk}{1}; + obj.sequence.setDigital(ch, digitalPattern); + end + end + + function plot(obj) + %plot the sequence + obj.sequence.plot(); + end + + + function load(obj,repeats) + % The load method converts the sequence object to the properly + % formated 64 bit string and uploads this to the xilinx chip in the + % pulse streamer via an eithernet connection managed by a hardware + % server. + + switch nargin + case 1 + repeats = 1; + end + + start = obj.triggerStart;%initialize the trigger to be software defined + mode = obj.triggerMode; % initialize the trigger to be rearmed after each run. + obj.PS.setTrigger(start, mode); % set triggers + + if obj.seq_meta.forever == 1 + runs =-1; %run until halt() is called + else + runs = repeats; + end + + % upload sequence to hardware, but do not run the sequence. + obj.PS.stream(obj.sequence,runs,obj.finalState); + end + + + function run(obj) + % starts the sequence if the sequence was uploaded with the + % PSStart.Software option + obj.PS.startNow(); + end + + function halt(obj) + % Interrupt the sequence and set the final state of the + % hardware. This method does not modify the final state if + % the sequence has already finished. This method also releases + % the hardware resources of the Pulse Streamer and, therefore, + % allows for faster upload sequence during next call of + % "stream" method. + obj.PS.forceFinal() + end + + function [index] = decodeInstructions(obj, json_seq, cmd, depth, index) + % NOTE: we shall use list and cell array interchangeably. + % NOTE: cmd is the variable in which data is appended to it upon + % recursion. To ensure the cmd is appropriately appended the + % property obj.cmd is passed to decodeInstructor when this function + % is called. Whereas in the recursive step within this defintion + % the local variable cmd is passed to decodeInstructions. + % Decode instruction takes in a cell array of maps (json_seq), + % where each map contains the information in a single line of the + % JSON string and builds a tree structure that describes the + % program to be executed that yields ultimately the pulse + % sequences. This method handles arbitrary sequences of nested + % LOOP, END_LOOP, and CONTINUE instructions. The method is called + % recursively for each loop instruction. + + % When DEBUG = 0 then report the length cmd.command, the recursion depth, + % the index of the current instuction line and the instruction. + DEBUG = 0; + + if DEBUG > 0 + %a = length(json_seq); + %fprintf('length of JSON string %i\n\n',a); + %fprintf('number of args %i\n\n',nargin); + end + + % When DEBUG = 0 notify user they have entered the + % decodeInstructions method. + if DEBUG > 0 + fprintf('Enter decodeInstructions function\n'); + end + + % default values for recurrsion depth and instruction index + switch nargin + case 3 + depth = 0; + index = 1; + end + + % When the index has reached or surpassed the number of + % instructions then exit decodeInstructions and return values. + if index >= length(json_seq) + return; + end + + % get current instruction + instruction = json_seq{index}('instruction'); + + % Prior to any recursive calls to decodeInstructions create an + % empty cell array (similar to a list in python) when the + % instruction is a LOOP. + + % NOTE: we shall use list and cell array interchangeably. + + depth = depth + 1; + if depth == 1 + % create empty list only if first instruction is a LOOP + if strcmp(instruction, 'LOOP') + cmd.append(Drivers.PulseStreamerMaster.seqCommand()); + end + % The number of nested loops should never exceed 10 since + % the pulse blaster has a maximum allowable nesting depth of 8. + elseif depth > 10 + return + end + + + % if the last element of cmd is a list, then get that list + % otherwise use the list cmd directly. this takes into + % account the cases where CONTINUEs may not reside within + % LOOPs. + c_cmd = cmd; + + % verify cmd isn not empty, otherwise you will keep nesting lists + % unwantedly + if length(cmd.command) > 0 + % Is the last element in cmd a cell array of maps + if isa(cmd.command{end}, 'Drivers.PulseStreamerMaster.seqCommand') + c_cmd = cmd.command{end}; + end + end + + %Debugging: report the length of cmd.command to track its growth + if DEBUG > 0 + fprintf('CMD length is: %i\n\n',length(cmd.command)) + end + + % add the instruction at index in the JSON file to the + % current list of instructions + c_cmd.append(json_seq{index}); + + %Debugging: report recursion depth, current instruction and + %instruction index. + if DEBUG > 0 + fprintf('depth = %5d\tinstruction: %s, %d\n',depth,instruction,index); + end + + % loop over the instructions in the json list + while index < length(json_seq) + index = index + 1; % IMPORTANT: remember to increment index into json list + + % get instruction type + instruction = json_seq{index}('instruction'); + + %Debugging: report recursion depth, current instruction and + %instruction index. + if DEBUG > 0 + fprintf('depth = %5d\tinstruction: %s, %d\n', depth,instruction,index); + end + + % Decide what to do depending on instruction type + if strcmp(instruction,'END_LOOP') + c_cmd.append(json_seq{index}); + % we must return in order that decodeInstructions + % terminates so that the decoder can continue to + % the next json instruction + return % Important, this is a terminating case + % for the recursion + + elseif strcmp(instruction,'LOOP') + % since this is a loop, create a new empty list to + % receive the instructions for this loop. + % IMPORTANT: the value of index can change within + % decodeInstructions, so we must return it + c_cmd.append(Drivers.PulseStreamerMaster.seqCommand) + + %Debugging: report current instruction data. + if DEBUG > 0 + fprintf('In loop current command is\n') + disp(c_cmd(end)) + end + index = obj.decodeInstructions(json_seq,c_cmd(end),depth,index); + + %Debugging: report current index. + if DEBUG > 0 + fprintf('index %d\n', index); + end + + elseif strcmp(instruction,'CONTINUE') + %since this is a continue statement we will simply + %append the instruction data to the cmd.(remember c_cmd + %is handle for cmd). + c_cmd.append(json_seq{index}); + + else + error('** error decoding JSON file\n') + + end + end + end + + + function unroll_tree(obj,cmd,map,depth) + % unroll_tree rolls all the instructions in the instruction + % tree into a 1 dimensional cell array of maps. + % NOTE: cmd and map are the variables in which data is appended to each + % upon recursion. To ensure the cmd and map are appropriately appended the + % property obj.cmd and obj.map are passed to unroll_tree when this function + % is called. Whereas in the recursive step within this defintion + % the local variables cmd.command{c} and map are passed to decodeInstructions. + + DEBUG = 0; + %DEBUGGING: reprot when unroll_tree function has been called. + if DEBUG>0 + fprintf('\n\nIn unroll_tree\n'); + end + + %Default values for map and depth. + switch nargin + case 3 + depth = 0; + end + + % Debugging: grow/ concatentate a string of tabs every time + % unroll_tree recurses. Proves pretty printing to ilustrate + % loop nesting. + if DEBUG > 0 + tab = ''; + for i=1:1:depth + tab = strcat('...',tab); + end + end + + % loop over top level instructions of abstract syntax tree, + % here called cmd + for c = 1:1:length(cmd.command) + % if current instruction is a list of instructions, then + % loop over those instructions + + % Debugging: Confirm tht execute_loop should be ran. + if DEBUG > 1 + fprintf('Condition to enter execute loop true? '); + disp(isa(cmd.command{c},'Drivers.PulseStreamerMaster.seqCommand')) + end + + if isa(cmd.command{c},'Drivers.PulseStreamerMaster.seqCommand') + obj.execute_loop(cmd.command{c},map,depth); + else + % this is not a list, but a map + + % Debugging: report recursion depth, current instruction and + %i nstruction index. + if DEBUG > 0 + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + cmd.command{c}('instruction'), ... + cmd.command{c}('duration'), ... + cmd.command{c}('flag').'); + end + + obj.map.append(cmd.command{c}); + + end + end + end + + + function printTree(obj, cmd, depth) + % Print the Tree of instructions + + % Default arguments + switch nargin + case 2 + depth = 0; + end + + % track recurrsion depths + %kick out printTree if recurrsion depth exceeds 10 + depth = depth + 1; + if depth == 1 + fprintf('\n'); + elseif depth > 10 + return + end + fprintf('depth: %i\n' , depth); + + tab = ''; + for i=1:depth + + tab = strcat('...',tab); + end + + % Loop acrous length of cmd cell array (list). If a list is found then + % printTree of that list. Please note that the seqCommand is a + % hadnle class which allows for the concatenation of any item + % type (i.e. itis analogous to a list). + for ii = 1:1:length(cmd.command) + c = cmd.command{ii}; + if isa(c,'Drivers.PulseStreamerMaster.seqCommand') + obj.printTree(c,depth); + else + % Otherwise the current intstruction is a map + % print is and the depth layer, flags and index. + fprintf('%s%s: duration = %i, flags = %i %i %i %i, data = %d\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').', ... + c('data')); + end + end + end + + function map = execute_loop(obj,cmd,map,depth) + + DEBUG = 0; + + if DEBUG > 1 + fprintf('\n\nIn execute_loop\n'); + end + + % Default arguments + switch nargin + case 2 + map = Drivers.PulseStreamerMaster.seqCommand(); + depth = 0; + case 3 + depth = 0; + end + + %increment recurssion depth and return if depth exceeds 10. + depth = depth+1; + + if depth > 10 + return; + end + + if DEBUG > 0 + tab = ''; + for i=1:depth + tab = strcat('...',tab); + end + end + + %current loop instruction. By default if this function is + %executed then the first instruction in the list is LOOP. + c = cmd.command{1}; + + % LOOP instruction + %Debugging: Report instruction in loop + if DEBUG > 0 + fprintf('%s%s: duration = %i, flags = %i %i %i %i, data = %d\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').', ... + c('data')); + + end + + %error handling + if ~strcmp(c('instruction'),'LOOP') + error('Expected LOOP instruction, but found %s\n', c('instruction')) + end + + %Debugging: Current map to concatenate + if DEBUG > 1 + fprintf('Current map to be appended: '); + disp(c) + end + + %append current map + map.append(cmd.command{1}); + + %Debugging: Display updated list of instruction maps + if DEBUG > 1 + fprintf('Current list of maps: '); + disp(map) + end + + % Implement loop + loop_cmd = cmd.command; + span = c('data'); %number of times to increment loop + + for ii = 1:1:span + % loop over instructions for current loop + % excluding the LOOP and END_LOOP instructions + + if DEBUG > 1 + disp(length(loop_cmd)) + end + + %skip 1 and last instruction set since these are not looped + %over (i.e. the instructions on LOOP and END_LOOP are + %always ran before and after the curret loop, respectively. + %Loop over remainging instructions. + for jj = 2:1:(length(loop_cmd)-1) + + if DEBUG > 1 + fprintf('current jj: '); + disp(jj) + end + + %if an instruction within this loop is LOOP then + %recurse into execute_loop. + if isa(loop_cmd{jj},'Drivers.PulseStreamerMaster.seqCommand') + + if DEBUG > 1 + fprintf('current loop instruction: '); + disp(loop_cmd{jj}) + end + obj.execute_loop(loop_cmd{jj},map,depth); + % continue to next instruction for this loop + continue + end + % Otherwise current instruction must be a CONTINUE + % so just execute it + c = loop_cmd{jj}; + + %append map of continue instruction. + map.append(c); + + % Debugging: report recursion depth, current instruction and + % instruction index. + if DEBUG > 0 + + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').'); + end + + %If instruction is not CONTINUE then throw error. + if ~strcmp(c('instruction'),'CONTINUE') + error('Expected CONTINUE instruction, but found %s\n', ... + c('instruction')) + end + end + end + + % END_LOOP instruction is last instruction in list of loop + % instructions + c = cmd.command{end}; + + % append map of continue instruction. + map.append(c); + + % Debugging: report recursion depth, current instruction and + % instruction index. + if DEBUG > 0 + + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... + tab, ... + c('instruction'), ... + c('duration'), ... + c('flag').'); + end + + %Throw error last instruction in loop is not 'END_LOOP' + if ~strcmp(c('instruction'),'END_LOOP') + error('Expected END_LOOP instruction, but found %s\n', ... + c('instruction')) + end + + %Debugging: Notify when exiting execute_loop + if DEBUG > 0 + fprintf('\n\nExiting execute_loop\n'); + end + end + + function [json_seq,obj] = readJSON(obj) + % readJSON converts the json string stored in obj.json into a cell + % array of maps, where each field in the map correspond to the + % fields in the json string sequence field. The remaining data in + % the obj.json string is store in seq_meta: a structure data type + % which houses the channels, units name and forever fields for the + % pulse sequence. + + DEBUG = 0; + + % convert json string into a structure + json_total = jsondecode(obj.json); + json_struct = json_total.sequence; + + %initialize the json_seq cell array and fill each element in + %array with map for each instruction line. + json_seq = cell(1,length(json_struct)); + for i=1:1:length(json_struct) + cells = struct2cell(json_struct(i)); + key_labels = {'flag','duration','instruction','data'}; + json_seq{i} = containers.Map(key_labels,cells); + end + + %return remaining human readabl fields (channels, units, name, + %forever) to seq_meta + seq_metadata.channels = json_total.channels; + seq_metadata.units = json_total.units; + seq_metadata.name = json_total.name; + seq_metadata.forever = json_total.forever; + + obj.seq_meta = seq_metadata; + + if DEBUG>0 + fprintf('seq_meta output of readJSON: \n'); + disp(obj.seq_meta); + end + end + + + end + + methods + + % Destructor method. Clears object properties. + function delete(obj) + if obj.PS.isStreaming() == 1 + obj.halt() + elseif obj.PS.hasSequence() == 1 + obj.halt() + end + end + end +end + diff --git a/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m b/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m new file mode 100644 index 000000000..24b71e40e --- /dev/null +++ b/Modules/+Drivers/+PulseStreamerMaster/seqCommand.m @@ -0,0 +1,30 @@ +classdef seqCommand < handle + properties + command={}; + %appended_value = {}; + + end + + + + methods + + function obj = seqCommand() + obj.command(:) = []; + end + + function append(obj,appended_value) + obj.command{end+1} = appended_value; + end + + function delete(obj) + %fprintf("I'm a sequence command and that's ok. I'm about to be deleted.\n") + end + + function element = end_array(obj) + element = obj.command{end}; + end + + end + +end From 4c6713018aede700118866baaf48aa132fe1040a Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 7 Jun 2019 08:59:16 -0400 Subject: [PATCH 03/71] imported CWAVE driver --- Modules/+Drivers/cwave.m | 711 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 Modules/+Drivers/cwave.m diff --git a/Modules/+Drivers/cwave.m b/Modules/+Drivers/cwave.m new file mode 100644 index 000000000..83de8c42a --- /dev/null +++ b/Modules/+Drivers/cwave.m @@ -0,0 +1,711 @@ +classdef cwave < Modules.Driver + %UNTITLED2 Summary of this class goes here + % Detailed explanation goes here + + properties(SetAccess = immutable) + ip = '192.168.11.3'; + %password = 457; %457 gives engineering access. 111 gives full superuser access. Not recommended...why? + end + + properties + target_wavelength = 615.000001; % Target Wavelength + all_shutters = 'open'; + shg_shutter = 'close'; + lsr_shutter = 'open'; + opo_stepper_stat = 0; + opo_temp_stat = false(1); + shg_stepper_stat = false(1); + shg_temp_stat = false(1); + thin_etalon_stat = false(1); + opo_lock_stat = false(1); + shg_lock_stat = false(1); + etalon_lock_stat = false(1); + laser_emission_stat = false(1); + ref_temp_stat = false(1); + end + + properties(Constant,Hidden) + % constants for C library + Pathx64 = 'C:\Program Files (x86)\Hübner\C-WAVE Control\MatlabControl\x64\'; + Pathx86 = 'C:\Program Files (x86)\Hübner\C-WAVE Control\MatlabControl\x86\'; + LibraryName = 'CWAVE_DLL'; % alias for library + LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll + LibraryHeader = 'CWAVE_DLL.h'; + OS_64bit = 'win64'; + ComputerArch = 'arch'; + ConnectCwave = 'cwave_connect'; + DLL_Version= 'DLL_Version'; + DLL_identity = 1; + Admin = 'admin_elevate'; + UpdateStatus = 'cwave_updatestatus'; + Get_IntValue = 'get_intvalue'; + Get_floatValue = 'get_floatvalue'; + Set_IntValue = 'set_intvalue'; + Set_FloatValue = 'set_floatvalue'; + Is_Ready = 'is_ready'; + SetCommand = 'set_command'; + LaserPower = 'get_photodiode_laser'; + OPO_Power = 'get_photodiode_opo'; + SHG_Power = 'get_photodiode_shg'; + StatusReport = 'get_statusbits'; + LaserStatus = 'get_status_laser'; + Reference_TempStatus = 'get_status_temp_ref'; + OPO_TempStatus = 'get_status_temp_opo'; + SHG_TempStatus = 'get_status_temp_shg'; + OPO_LockStatus = 'get_status_lock_opo'; + SHG_LockStatus = 'get_status_lock_shg'; + Etalon_LockStatus = 'get_status_lock_etalon'; + WLM_PID_Optimize = 'WLM_PID_Compute'; + Ext_SetCommand = 'ext_set_command'; + ExtGet_IntValue = 'ext_get_intvalue'; + ExtGet_FloatValue = 'ext_get_floatvalue'; + ShutterSHG = 'shtter_shg'; + ShutterLaser = 'shtter_las'; + Open = 'open'; + Close = 'close'; + StopOptimization = 'opt_stop'; + CoarseTune = 'coarse'; + FineTune = 'fine'; + Disconnect = 'cwave_disconnect'; + RefCavity_Piezo = 'x'; + ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; + ThickEtalon_Piezo = 'thicketa_rel'; + RefCavityPiezo_maxBit = 65535/100; + Laser_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + Laser_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + OPO_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + OPO_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + SHG_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + SHG_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + end + + %% Signleton Method + methods(Static) + function obj = instance(ip) + mlock; + persistent Objects + if isempty(Objects) + Objects = Drivers.cwave.empty(1,0); + end + for i = 1:length(Objects) + if isvalid(Objects(i)) && isequal({ip},Objects(i).singleton_id) + obj = Objects(i); + return + end + end + obj = Drivers.cwave(ip); + obj.singleton_id = {ip}; + Objects(end+1) = obj; + end + end + + %% Constructor Method + methods(Access=private) + function obj = cwave() + obj.dll_ver = load_cwave_dll(obj); %load dll for cwave + obj.status = cwave_connect(); %connect cwave + % open all internal and output shutters in cwave system + obj.shutter_lsr(); + obj.shutter_shg(); + %obj.initialize_shutters; + end + end + + %% Methods accessible to user + methods + + function dll_ver = load_cwave_dll(obj) + % load DLL + if (~libisloaded(obj.LibraryName)) + if (strcmp(computer(obj.ComputerArch), obj.OS_64bit)) + %Change file path to full file path. Do not use relative + %file path. Also all strings should be switched to constant + %properties + %loadlibrary('x64/CWAVE_DLL', obj.LibraryHeader); + path = fullfile(obj.Pathx64 ,obj.LibraryFilePath); % 64bit + [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + else + %loadlibrary('x86/CWAVE_DLL', obj.LibraryHeader); + path = fullfile(obj.Pathx86 ,obj.LibraryFilePath); % 32bit + [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + end + end + if (libisloaded(obj.LibraryName)) + %% return dll version + dll_ver = obj.dll_version(); + if (dll_ver ~= obj.DLL_identity) + assert(dll_ver == obj.DLL_version, ['CWAVE DLL library not loaded, DLL version ' dll_ver ' not equal to ' obj.DLL_version]); + end + end + end + + function [varargout] = LibraryFunction(obj,FunctionName,varargin) + % use this function to call arbitrary library functions from + % CWAVE DLL. Checks for error, and returns all but status + + nargs = Base.libnargout(obj.LibraryName,FunctionName); + if nargs < 2 + varargout = ''; + status = calllib(obj.LibraryName,FunctionName,varargin{:}); + else + [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); + end + obj.CheckErrorStatus(status); + end + + function CheckErrorStatus(obj,status,FunctionName) + %edit cases TBD. Need to sort out string to report and + %flag/status for each function + inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... + obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; + if(ismember(FunctionName, inversion_condition)) + status = ~status; + end + switch FunctionName + case obj.ConnectCwave + % 0=connection failed, 1==connection successful + assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed']); + case obj.DLL_Version + assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); + case obj.Admin + % 0==admin rights granted, 1=no admin rights granted + assert(admin_status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); + case obj.UpdateStatus + % 0==update succeeded, 1=update failed + assert(measure_status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); + case obj.Set_IntValue + % 0== integer value set, 1= integer value not set + assert(measure_status == 0, ['CWAVE Error: Int value not set']); + case obj.Is_Ready + % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing + assert(optimize_status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); + case obj.Set_FloatValue + % 0==update succeeded, 1=update failed + assert(measure_status == 0, ['CWAVE Error: float value not set']); + case obj.SetCommand + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); + case obj.LaserPower + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: Laser power not within standard operating range.']); + case obj.OPO_Power + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: OPO power not within standard operating range.']); + case obj.SHG_Power + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: SHG power not within standard operating range.']); + case obj.StatusReport + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: All elements are not stable and/or locked.']); + case obj.LaserStatus + % 0=update failed, 1==update succeeded + assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); + case obj.Reference_TempStatus + % 0=referance temperature stabilized, 1==reference temperature not at setpoint + assert(ref_temp_status == 0, ['Reference temperature not at setpoint']); + case obj.OPO_TempStatus + % 0=referance temperature stabilized, 1==reference temperature not at setpoint + assert(opo_temp_status == 0, ['OPO temperature not at setpoint']); + case obj.SHG_TempStatus + % 0=SHG temperature stabilized, 1==SHG temperature not at setpoint + assert(shg_temp_status == 0, ['SHG temperature not at setpoint']); + case obj.OPO_LockStatus + % 0=OPO lock stabilized, 1==OPO not locked to reference cavity. Still optimizing + assert(opo_lock_status == 0, ['OPO not locked to reference cavity. Optimization still in progress']); + case obj.SHG_LockStatus + % 0=SHG lock stabilized, 1==SHG not locked to reference cavity. Still optimizing + assert(shg_lock_status == 0, ['SHG not locked to reference cavity. Optimization still in progress']); + case obj.Etalon_LockStatus + % 0=etalon lock stabilized, 1==etalon not locked to reference cavity. Still optimizing + assert(etalon_lock_status == 0, ['etalon not locked to reference cavity. Optimization still in progress']); + case obj.WLM_PID_Optimize + case obj.Ext_SetCommand + % 0=command executed correctly, 1==error command not executed by external module + assert(etalon_lock_status == 1, ['Command not executed by external module. Check that it is on.']); + end + end + + function [status] = cwave_connect(obj) + %Description: Connects to the C-Wave. This function has to be executed once during runtime. + %Arguments: ipAddress is the IP address of the CWAVE as string in the format 123.123.123.123 + %Returns: int value, 1 means connection failed, 0 means successfully connected. + %Logic inverted from original DLL status bit by LibraryFunction. + %% connect to device + status = LibraryFunction(obj.LibraryName, obj.ConnectCwave, obj.ip); + % mitigate bug in DLL, first connection attempt might fail -> retry + if (status == 0) + status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, obj.ip); + end + end + + function [status,dllVer] = dll_version(obj) + %Description: Reads version of the DLL + %Returns: Returns an integer value with the version of the DLL + % also return status bit (0 = correct dll version, 1 = + % incorrect dll version). + dllVer = calllib(obj.LibraryName, obj.DLL_Version); + if( dllVer ~= obj.DLL_identity) + status = 1; + else + status = 0; + end + disp(['C-WAVE DLL loaded. Version: ' num2str(dllVer)]); + obj.CheckErrorStatus(obj,status,obj.DLL_Version); + end + + function admin_status = admin_elevate(obj,password) + %Description: Grants admin rights to the user to access advanced commands. + %Arguments: password is the password as string. + %Returns: Returns an integer value. 1 means no admin rights, 0 means admin rights + admin_status = LibraryFunction(obj.LibraryName,obj.Admin,password); + end + + function measure_status = cwave_updatestatus(obj) + %Description: Manually updates status info (photodiode values, temperatures, statusbits) in the library. + %This function is automatically executed on demand, so there is usually no need to execute it manually. + %Returns: Returns status int value. 0 means update succeeded, 1 means update failed. + measure_status = LibraryFunction(obj.LibraryName,obj.UpdateStatus); + end + + function intvalue = get_intvalue(cmd) + %Description: Reads the value of an integer parameter. + %Arguments: Parameter as string. See parameter list for valid parameters. + %Returns: Returns the requested integer value. + + %% INT PARAMETER LIST + % Name Type Valid range Read / Write Description + %% topo_set Int 20000-170000 RW Setpoint of the OPO temperature in mK + % topo_is Int 20000-170000 R Current OPO temperature in mK + %% tshg_set Int 20000-170000 RW Setpoint of the SHG temperature in mK + % tshg_is1 Int 20000-170000 R Current SHG1 temperature in mK + %% tshg_is2 Int 20000-170000 R Current SHG2 temperature in mK + % tref_set Int 20000-170000 RW Setpoint of the reference temperature in mK + %% tref_is Int 20000-170000 R Current reference temperature in mK + % shtter_las Int 0, 1 RW Laser shutter position. 1 means open, 0 closed + %% shtter_shg Int 0, 1 RW SHG shutter position. 1 means open, 0 closed + % shtter_las_out Int 0, 1 RW Laser output shutter position. 1 means open, 0 closed + %% shtter_opo_out Int 0, 1 RW OPO output shutter position. 1 means open, 0 closed + % shtter_shg_out Int 0, 1 RW SHG output shutter position. 1 means open, 0 closed + %% laser_en Int 0, 1 RW Enable internal pump laser. 0 disabled, 1 enabled + % monout_sel Int 0-12 RW Select Signal at monitor 1 output. + % 0: Error Signal OPO + % 1: Error Signal SHG + % 2: Error Signal Etalon + % 4: Piezo OPO + % 5: Piezo SHG + % 6: Piezo Etalon + % 7: Piezo Reference + % 9: Pump laser power + % 11: SHG power + % 12: OPO power + %% monout2_sel Int 0-12 RW Select Signal at monitor 2 output. See Monitor 1 for details. + % regopo_on Int 0-2 RW OPO regulator mode. + % 0: off + % 1: scan + % 2: regulate + %% regshg_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on + % regeta_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on + %% regopo_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + %% Should not need to be touched. + % regshg_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + % Should not need to be touched. + %% regeta_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + %% Should not need to be touched. + % reghsg_threshold Int 0-4095 RW SHG power threshold above which SHG regulator is active. + % Needed to select proper mode. Is set automatically, + % usually no user input required. + %% opo_lambda Int 45000-130000 W Wavelength setpoint of the C-Wave in nm*100. + % opo_rlambda Int -100-100 W Execute relative wavelength step (fundamental wavelength!) + % in nm*100. Maximum step is 1 nm. + %% thicketa_rel Int -100-100 W Execute relative wavelength step of the thick etalon only + %% (fundamental wavelength!) in nm*100. Maximum step is 1 nm. + % thicketa_rel_hr Int -1000...1000 W Same as thicketa_rel but resolution is 1 pm + + %% WAVELENGTH STABILIZATION PARAMETERS + % Name Type Valid range Default Description + %% WLM_pid_p Int 0-100000 0 Proportional constant of the wavelength regulator. + %% Not needed for many applications + % WLM_pid_i Int 0-100000 500 Integral constant for wavelength regulator + %% WLM_pid_direction Int -1, 0, 1 -1 Direction of the regulator. Does not have to be changed + %% in most cases. + % WLM_bigsteps Int 0, 1 1 Allow the regulator to do big wavelength steps, e. g. completely + % re-dial a wavelength if the setpoint is too far away from the + % current output wavelength. + %% WLM_etalonsteps Int 0, 1 1 Allow the regulator to touch the thick etalon to reach + %% the desired wavelength. + % WLM_piezosteps Int 0, 1 1 Allow the regulator to move the cavity piezo to reach + % the desired wavelength. + %% WLM_regout Int 0-65535 0 Regulator output, good for checking if it works + + %% Read value of integer parameter + % no error status bit is returned so calllib is used. + intvalue = calllib(obj.LibraryName,obj.Get_IntValue,cmd); + end + + function floatvalue = get_floatvalue(cmd) + %Description: Reads the value of an floating point parameter. + %Arguments: Parameter as string. See parameter list for valid parameters. + %Returns: Returns the requested floating point value. + + %% INT PARAMETER LIST + % Name Type Valid range Read / Write Description + %% laser_pow Double 0?1.5 RW Laser power of internal pump laser in W + + %% WAVELENGTH STABILIZATION PARAMETERS + % Name Type Valid range Default Description + %% WLM_pid_setpoint Double 450?1300 Desired wavelength in nm. + % WLM_targetdeviation Double 0?1 0.01 Desired maximum deviation from the setpoint in nm. + % The minimum value depends on the used wavemeter resolution. + % Smaller values give higher accuracy but may require longer + % time or manual input. Larger values result in faster settling + % but a less accurate output wavelength. + + %% Read value of float parameter + floatvalue = calllib(obj.LibraryName,obj.Get_floatValue,cmd); + end + + function status = set_intvalue( cmd,value) + % Description: Sets the value of an integer parameter. + % Arguments: cmd is the Parameter as string. See parameter list + % for valid parameters. value is the desired new value of the parameter. + % Returns: Returns 0 (1 before inversion) if the new value was set correctly. + % Returns 1 (-1 before inversion) if an error occurred. + %% Wrightable Int Parameters are listed above in get_intvalue function comments + %% Wrightable Wavelength stabilization parameters are listed above in get_intvalue function comments + status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value);\ + end + + function optimize_status = is_ready(obj) + %Description: Checks if all C-Wave routines have finished and the C-Wave produces the desired output + %Arguments: none + %Returns: Returns an integer value. 0 means no errors, C-Wave is ready. 1 means C-Wave is still in optimization + %% Check if optimization is complete + optimize_status = LibraryFunction(obj.LibraryName, obj.Is_Ready); + end + + function status = set_floatvalue(cmd,value) + % Description: Sets the value of an floating point parameter. + % Arguments: cmd is the Parameter as string. See parameter list + % for valid parameters. value is the desired new value of the parameter. + % Returns: Returns 0 (1 before inversion) if the new value was set correctly. + % Returns 1 (-1 before inversion) if an error occurred. + %% Wrightable Int Parameters are listed above in get_floatvalue function comments + %% Wrightable Wavelength stabilization parameters are listed above in get_floatvalue function comments + status = LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); + end + + function status = set_command(cmd) + % Description: Executes a command which has no numerical argument. + % Arguments: cmd is the command as string. See the command list for reference. + % Returns: Returns 0 (1 before inversion) if the new command was executed correctly. Returns 1 (-1 before inversion) + % if an error occurred. + %% Parameter Name Description + % opt_tempshg Re-optimize SHG temperature by doing a temperature search. + % This command is automatically executed each time a new wavelength is selected. + %% regeta_catch Try to re-lock thick etalon to prevent multimode operation. + %% If SHG output is required, a successive SHG temperature search may be required. + % opt_stop Stop all optimizations. Usefull for full manual control of the C-Wave. + %% Set Command + status = LibraryFunction(obj.LibraryName, obj.SetCommand,cmd); + end + + function [status,laser_power] = get_photodiode_laser(obj) + % Description: Reads the current laser power (what unit??) + % Arguments: none + % Returns: Returns the laser photodiode value + %% Read laser power + laser_power = calllib(obj.LibraryName,obj.LaserPower); + if( laser_power > obj.Laser_MaxPower || laser_power < obj.Laser_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.LaserPower) + end + + function [status,opo_power] = get_photodiode_opo(obj) + % Description: Reads the current OPO infrared power + % Arguments: none + % Returns: Returns the infrared output power in mW + %% Read IR opo power + opo_power = calllib(obj.LibraryName,obj.OPO_Power); + if (opo_power > obj.OPO_MaxPower || opo_power < obj.OPO_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.OPO_Power); + end + + function [shg_power] = get_photodiode_shg(obj) + % Description: Reads the current (second harmonic generator) SHG visible power + % Arguments: none + % Returns: Returns the visible output power in mW + %% Read SHG power + shg_power = calllib(obj.LibraryName, obj.SHG_Power); + if (shg_power > obj.SHG_MaxPower || opo_power < obj.OPO_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.SHG_Power); + end + + function status = get_statusbits(obj) + % Description: Reads the current status of the C-Wave + % Arguments: none + % Returns: Returns an 16-bit integer value. Each bit corresponds to the + % status of one component. 0 means, the component is ready for operation, + % 1 means the component is not yet stable. Current valid bits from LSB to MSB are: + % 0 OPO stepper + % 1 OPO temperature + % 2 SHG stepper + % 3 SHG temperature + % 4 Thin etalon + % 5 OPO lock + % 6 SHG lock + % 7 Etalon lock + % 8 Laser emission (inverted) + % 9 Reference temperature + % Poll cwave status + cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib + status_vector = de2bi(cwave_status); + obj.opo_stepper_stat = status_vector(1); + obj.opo_temp_stat = status_vector(2); + obj.shg_stepper_stat = status_vector(3); + obj.shg_temp_stat = status_vector(4); + obj.thin_etalon_stat = status_vector(5); + obj.opo_lock_stat = status_vector(6); + obj.shg_lock_stat = status_vector(7); + obj.etalon_lock_stat = status_vector(8); + obj.laser_emission_stat = ~status_vector(9); + obj.ref_temp_stat = status_vector(10); + if(cwave_status ~=0) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.StatusReport) + end + + function WLM_PID_Compute(wl_measured) + % Description: This function executes automatic wavelength regulation of the + % C-Wave if the current output wavelength is measured by an external wavemeter + % and monitored back into the C-Wave by this function. See WLM parameters for + % details. The C-Wave is automatically adapted to the new wavelength measurement + % each time this function is executed. To disable the automatic wavelength + % regulation just do not execute this function. + % Arguments: measurement is the current measured wavelength in nm. You can + % provide fundamental or SHG measurement. However, measuring the fundamental + % wavelength will be more reliable for complete automation. + % Returns: none + LibraryFunction(obj.LibraryName,obj.WLM_PID_Optimize,wl_measured); % suggest change to callib + end + + function shutter_lsr(obj) + %open or close internal pump laser shutter + if strcmp(obj.lsr_shutter, obj.Open) + ret = set_intvalue(obj.ShutterLaser,1); + assert(ret == 1, 'Opening pump laser shutter failed'); + elseif strcmp(obj.lsr_shutter, obj.Close) + ret = set_intvalue(obj.ShutterLaser,0); + assert(ret == 0, 'Closing pump laser shutter failed'); + end + end + + function shutter_shg(obj) + %open or close SHG shutter + if strcmp(obj.shg_shutter, obj.Open) + ret = set_intvalue(obj.ShutterSHG,1); + assert(ret == 1, 'Opening SHG shutter failed'); + elseif strcmp(shg.lsr_shutter, obj.Close) + ret = set_intvalue(obj.ShutterSHG,0); + assert(ret == 0, 'Closing SHG shutter failed'); + end + end + + function status = getStatus(obj) + % poll connection status if CWAVE + % Function Call currently not avialable waiting DLL file info + % from Hubner + status = obj.cwave_connect(ipAddr); + end + + function status = delete(obj) + %Delete instance of CWAVE object. + %Disconnect CWAVE + obj.disconnect_cwave(); + %clean up loaded library from memory + unloadlibrary(obj.LibraryName); + status = libisloaded(obj.LibraryName); + if status + assert(status==1, 'CWAVE Library still in memory!'); + end + end + + function disconnect_cwave(obj) + % Probably easiset if using a disconnect function to disconnect + % CWAVE + LibraryFunction(obj.LibraryName,obj.Disconnect); + end + + function set_target_wavelength(obj,resolution) + %set target wavelength with either a coarse 0.01 nm resolution + %or a fine resolution determined by wavemeter and internal PID + %of CWAVE. + res_ret = ismemeber(resolution, {ob.CoarseTune; obj.FineTune}); + %res_ret = res_ret(1) || res_ret(2); + assert(res_ret==1, 'Resolution must be either "coarse" or "fine"'); + + if(strcmp(resolution,ob.CoarseTune)) + ret = obj.set_intvalue('opo_lambda',round(obj.target_wavelength*100)); + assert(ret == 1, 'Setting target wavelength failed'); + disp(['Target wavelength set: ' num2str(round(obj.target_wavelength*100)/100) 'nm']); + % IMPORTANT: wait one second before starting to poll for ready + pause(1); + elseif(strcmp(resolution,obj.FineTune)) + obj.WLM_PID_Compute(obj.target_wavelength); + pause(1); + end + end + + function flag = abort_tune(obj) + %Stops optimization of wavelength tuning. + flag = obj.set_command(obj.StopOptimization); + assert(flag==1, 'Optimization has not stopped'); + end + + function piezo = tune_ref_cavity(obj,piezo_percent) + %Piezo voltage is passed a a percentage of the total range + %Total range is 0-65535 + %Convert from percentage to integer + peizo_voltage = round(piezo_percent*obj.Piezo_maxBit); + + flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.RefCavity_Piezo,peizo_voltage); + if (flag == 1) + piezo = piezo_percent; + elseif (flag == -1) + piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); + piezo = piezo_voltage/obj.Piezo_maxBit; + end + end + + function piezo = tune_thick_etalon(obj,relative_wl_pm) + %Piezo voltage is passed a a percentage of the total range + %Total range is 0-65535 + %Convert from percentage to integer + flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); + if (flag == 1) + piezo = piezo_percent; + elseif (flag == -1) + piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); + piezo = piezo_voltage/obj.Piezo_maxBit; + end + end + end + + %Methods I will likey never use + methods + function initialize_shutters(obj) + %Open or close all shutters + %Our CWAVE only has internal pump laser and SHG shutters + if strcmp(obj.all_shutters,obj.Open) + ret_lsr = set_intvalue(obj.ShutterLaser,1); + assert(ret_lsr == 1, 'Opening pump laser shutter failed'); + ret_shg = set_intvalue(obj.ShutterSHG,1); + assert(ret_shg == 1, 'Opening shg shutter failed'); + elseif strcmp(obj.all_shutters,obj.Close) + ret_lsr = set_intvalue(obj.ShutterLaser,0); + assert(ret_lsr == 1, 'Closing pump laser shutter failed'); + ret_shg = set_intvalue(obj.ShutterSHG,0); + assert(ret_shg == 1, 'Closing shg shutter failed'); ] + end + end + + function [status] = ext_set_command(cmd) + % Description: Sends a command to the external module. + % Arguments: cmd is the command as string. See the documentation of the external module for valid commands. + % Returns: Returns 1 if the new command was executed correctly. Returns -1 if an error occurred. + %% external commands for WS8-10 High Finesse wavemeter + %% set command for external module (i.e. the wavemeter) + status = LibraryFunction(obj.LibraryName,obj.Ext_SetCommand,cmd); + end + + function [ext_intvalue] = ext_get_intvalue(cmd) + % Description: Reads the value of an integer parameter from the external module. + % Arguments: Parameter as string. See documentation of external module for valid parameters. + % Returns: Returns the requested integer value. + %% Table of allowing integer paramters for high finesse WS8-10 wavemeter + ext_intvalue = calllib(obj.LibraryName, obj.ExtGet_IntValue,cmd); + end + + function [ext_floatvalue] = ext_get_floatvalue(cmd) + % Description: Reads the value of an floating point parameter from the external module. + % Arguments: Parameter as string. See documentation of external module for valid parameters. + % Returns: Returns the requested floating point value. + %% Table of allowable float parameters for High Finesse WS8-10 wavemeter + ext_floatvalue = calllib(obj.LibraryName, obj.ExtGet_FloatValue, cmd); + end + + function [laser_status] = get_status_laser(obj) + % Description: Reads the current status of the pump laser. + % Arguments: none + % Returns: Returns 0 (1 before inversion) if the pump laser is active and the laser shutter is open. + % Returns 1 (0 before inversion) if no or not sufficient laser power is available. + laser_status = LibraryFunction(obj.LibraryName,obj.LaserStatus); + end + + function [ref_temp_status] = get_status_temp_ref(obj) + % Description: Reads the current status of the reference temperature. + % Arguments: none + % Returns: Returns 0 if the reference temperature is stable. + % Returns 1 if the reference temperature is not at setpoint. + %% Poll temperature status + ref_temp_status = LibraryFunction(obj.LibraryName, obj.Reference_TempStatus); + end + + function [opo_temp_status] = get_status_temp_opo(obj) + % Description: Reads the current status of the OPO temperature. + % Arguments: none + % Returns: Returns 0 if the OPO temperature is stable. + % Returns 1 if the OPO temperature is not at setpoint. + %% Poll OPO Temperature Status + opo_temp_status = LibraryFunction(obj.LibraryName, obj.OPO_TempStatus); + end + + function [shg_temp_status] = get_status_temp_shg(obj) + % Description: Reads the current status of the SHG temperature. + % Arguments: none + % Returns: Returns 0 if the SHG temperature is stable. + % Returns 1 if the SHG temperature is not at setpoint. + %% Poll SHG temperature Status + shg_temp_status = LibraryFunction(obj.LibraryName, obj.SHG_TempStatus); + end + + function [opo_lock_status] = get_status_lock_opo(obj) + % Description: Reads the current status of the OPO lock. + % Arguments: none + % Returns: Returns 0 if the OPO is locked to the reference cavity and + % produces stable output. Returns 1 if optimization is still in progress. + %% Poll opo_lock_status...What exactly is the OPO lock? + opo_lock_status = LibraryFunction(obj.LibraryName, obj.OPO_LockStatus); + end + + function [shg_lock_status] = get_status_lock_shg(obj) + % Description: Reads the current status of the SHG lock. + % Arguments: none + % Returns: Returns 0 if the SHG cavity is locked and produces stable output. + % Returns 1 if optimization is still in progress. + shg_lock_status = LibraryFunction(obj.LibraryName, obj.SHG_LockStatus); + end + + function [etalon_lock_status] = get_status_lock_etalon(obj) + % Description: Reads the current status of the etalon lock. + % Arguments: none + % Returns: Returns 0 if the etalon is locked. Returns 1 if optimization is still in progress. + etalon_lock_status = LibraryFunction(obj.LibraryName, obj.Etalon_LockStatus); + end + end + +end + From fb3b47d560cb929a18bf984b5ca2ece7cb665620 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 13 Jun 2019 15:50:12 -0400 Subject: [PATCH 04/71] skeleton code for CWave source, testing mixin --- .../PulseStreamerMaster.m | 28 +- Modules/+Drivers/CWave.m | 730 ++++++++++++++++++ Modules/+Sources/CWave.m | 93 +++ Modules/+Sources/ConnectableMixin_invisible.m | 19 + 4 files changed, 856 insertions(+), 14 deletions(-) create mode 100644 Modules/+Drivers/CWave.m create mode 100644 Modules/+Sources/CWave.m create mode 100644 Modules/+Sources/ConnectableMixin_invisible.m diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index 4b6a0665f..f437bbd42 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -68,10 +68,7 @@ % PSM.delete(); - properties(SetAccess=private,SetObservable) - % physical IP address of Pulse Streamer hardware - ipAddress='192.168.11.2'; - end + % ipAddress='192.168.11.2'; properties(SetAccess=private) % Object that provides the interface to the @@ -100,13 +97,21 @@ end methods(Static) - function obj = instance() + function obj = instance(ip) mlock; - persistent Object - if isempty(Object) || ~isvalid(Object) - Object = Drivers.PulseStreamerMaster.PulseStreamerMaster(); + persistent Objects + if isempty(Objects) || ~isvalid(Objects) + Object = Drivers.PulseStreamerMaster.PulseStreamerMaster.empty(1,0); end - obj = Object; + [~,resolvedIP] = resolvehost(ip); + for i = 1:length(Objects) + if isvalid(Objects(i)) && isequal(resolvedIP,Objects(i).singleton_id) + error('%s driver is already instantiated!',mfilename) + end + end + obj = Drivers.PulseStreamerMaster.PulseStreamerMaster(ip); + obj.singleton_id = resolvedIP; + Objects(end+1) = obj; end end @@ -128,11 +133,6 @@ % It contains a builder method for building pulse sequences % in the format required by the PulseStreamer class. - switch nargin - case 0 - ip = obj.ipAddress; - end - obj.PS = PulseStreamer.PulseStreamer(ip); obj.triggerStart = PulseStreamer.TriggerStart.SOFTWARE(); obj.triggerMode = PulseStreamer.TriggerRearm.AUTO(); diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m new file mode 100644 index 000000000..9000dc465 --- /dev/null +++ b/Modules/+Drivers/CWave.m @@ -0,0 +1,730 @@ +classdef CWave < Modules.Driver + %CWave connects with host machine to control cwave laser + % + % for fine-tuning best used with a wavemeter feedback loop + + properties(SetAccess = immutable) + %ip = '192.168.11.3'; + %password = 457; %457 gives engineering access. 111 gives full superuser access. Not recommended...why? + end + + properties + target_wavelength = 615.000001; % Target Wavelength + all_shutters = 'open'; + shg_shutter = 'close'; + lsr_shutter = 'open'; + opo_stepper_stat = 0; + opo_temp_stat = false(1); + shg_stepper_stat = false(1); + shg_temp_stat = false(1); + thin_etalon_stat = false(1); + opo_lock_stat = false(1); + shg_lock_stat = false(1); + etalon_lock_stat = false(1); + laser_emission_stat = false(1); + ref_temp_stat = false(1); + end + + properties(Constant,Hidden) + % constants for C library + Pathx64 = 'C:\Program Files (x86)\H�bner\C-WAVE Control\MatlabControl\x64\'; + Pathx86 = 'C:\Program Files (x86)\H�bner\C-WAVE Control\MatlabControl\x86\'; + LibraryName = 'CWAVE_DLL'; % alias for library + LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll + LibraryHeader = 'CWAVE_DLL.h'; + OS_64bit = 'win64'; + ComputerArch = 'arch'; + ConnectCwave = 'cwave_connect'; + DLL_Version= 'DLL_Version'; + DLL_identity = 1; + Admin = 'admin_elevate'; + UpdateStatus = 'cwave_updatestatus'; + Get_IntValue = 'get_intvalue'; + Get_floatValue = 'get_floatvalue'; + Set_IntValue = 'set_intvalue'; + Set_FloatValue = 'set_floatvalue'; + Is_Ready = 'is_ready'; + SetCommand = 'set_command'; + LaserPower = 'get_photodiode_laser'; + OPO_Power = 'get_photodiode_opo'; + SHG_Power = 'get_photodiode_shg'; + StatusReport = 'get_statusbits'; + LaserStatus = 'get_status_laser'; + Reference_TempStatus = 'get_status_temp_ref'; + OPO_TempStatus = 'get_status_temp_opo'; + SHG_TempStatus = 'get_status_temp_shg'; + OPO_LockStatus = 'get_status_lock_opo'; + SHG_LockStatus = 'get_status_lock_shg'; + Etalon_LockStatus = 'get_status_lock_etalon'; + WLM_PID_Optimize = 'WLM_PID_Compute'; + WLM_PID_Setpoint = 'WLM_pid_setpoint'; % valid range 450 - 1300 (nm), double + WLM_BigSteps = 'WLM_bigsteps'; + WLM_PiezoSteps = 'WLM_piezosteps' + Ext_SetCommand = 'ext_set_command'; + ExtGet_IntValue = 'ext_get_intvalue'; + ExtGet_FloatValue = 'ext_get_floatvalue'; + ShutterSHG = 'shtter_shg'; + ShutterLaser = 'shtter_las'; + Open = 'open'; + Close = 'close'; + StopOptimization = 'opt_stop'; + CoarseTune = 'coarse'; + FineTune = 'fine'; + Disconnect = 'cwave_disconnect'; + RefCavity_Piezo = 'x'; + ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; + ThickEtalon_Piezo = 'thicketa_rel'; + RefCavityPiezo_maxBit = 65535/100; + Laser_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + Laser_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + OPO_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + OPO_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + SHG_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) + SHG_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + end + %% Signleton Method + methods(Static) + function obj = instance(ip) + mlock; + persistent Objects + if isempty(Objects) + Objects = Drivers.CWave.empty(1,0); + end + for i = 1:length(Objects) + if isvalid(Objects(i)) && isequal({ip},Objects(i).singleton_id) + obj = Objects(i); + return + end + end + obj = Drivers.CWave(ip); + obj.singleton_id = {ip}; + Objects(end+1) = obj; + end + end + + %% Constructor Method + methods(Access=private) + function obj = CWave() + obj.dll_ver = load_cwave_dll(obj); %load dll for cwave + obj.status = cwave_connect(); %connect cwave + % open all internal and output shutters in cwave system + obj.shutter_lsr(); + obj.shutter_shg(); + %obj.initialize_shutters; + ret = obj.set_intvalue(WLM_BigSteps, 0); + assert(ret == 1, 'Turning off large steps in PID failed'); + end + end + + %% Methods accessible to user + methods + + function dll_ver = load_cwave_dll(obj) + % load DLL + if (~libisloaded(obj.LibraryName)) + if (strcmp(computer(obj.ComputerArch), obj.OS_64bit)) + %Change file path to full file path. Do not use relative + %file path. Also all strings should be switched to constant + %properties + %loadlibrary('x64/CWAVE_DLL', obj.LibraryHeader); + path = fullfile(obj.Pathx64 ,obj.LibraryFilePath); % 64bit + [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + else + %loadlibrary('x86/CWAVE_DLL', obj.LibraryHeader); + path = fullfile(obj.Pathx86 ,obj.LibraryFilePath); % 32bit + [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + end + end + if (libisloaded(obj.LibraryName)) + %% return dll version + dll_ver = obj.dll_version(); + if (dll_ver ~= obj.DLL_identity) + assert(dll_ver == obj.DLL_version, ['CWAVE DLL library not loaded, DLL version ' dll_ver ' not equal to ' obj.DLL_version]); + end + end + end + + function [varargout] = LibraryFunction(obj,FunctionName,varargin) + % use this function to call arbitrary library functions from + % CWAVE DLL. Checks for error, and returns all bit status + + nargs = Base.libnargout(obj.LibraryName,FunctionName); + if nargs < 2 + varargout = ''; + status = calllib(obj.LibraryName,FunctionName,varargin{:}); + else + [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); + end + obj.CheckErrorStatus(status); + end + + function CheckErrorStatus(obj,status,FunctionName) + %edit cases TBD. Need to sort out string to report and + %flag/status for each function + inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... + obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; + if(ismember(FunctionName, inversion_condition)) + status = ~status; + end + switch FunctionName + case obj.ConnectCwave + % 0=connection failed, 1==connection successful + assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed']); + case obj.DLL_Version + assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); + case obj.Admin + % 0==admin rights granted, 1=no admin rights granted + assert(admin_status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); + case obj.UpdateStatus + % 0==update succeeded, 1=update failed + assert(measure_status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); + case obj.Set_IntValue + % 0== integer value set, 1= integer value not set + assert(measure_status == 0, ['CWAVE Error: Int value not set']); + case obj.Is_Ready + % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing + assert(optimize_status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); + case obj.Set_FloatValue + % 0==update succeeded, 1=update failed + assert(measure_status == 0, ['CWAVE Error: float value not set']); + case obj.SetCommand + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); + case obj.LaserPower + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: Laser power not within standard operating range.']); + case obj.OPO_Power + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: OPO power not within standard operating range.']); + case obj.SHG_Power + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: SHG power not within standard operating range.']); + case obj.StatusReport + % 0=update succeeded, 1=update failed + assert(status == 0, ['CWAVE Error: All elements are not stable and/or locked.']); + case obj.LaserStatus + % 0=update failed, 1==update succeeded + assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); + case obj.Reference_TempStatus + % 0=referance temperature stabilized, 1==reference temperature not at setpoint + assert(ref_temp_status == 0, ['Reference temperature not at setpoint']); + case obj.OPO_TempStatus + % 0=referance temperature stabilized, 1==reference temperature not at setpoint + assert(opo_temp_status == 0, ['OPO temperature not at setpoint']); + case obj.SHG_TempStatus + % 0=SHG temperature stabilized, 1==SHG temperature not at setpoint + assert(shg_temp_status == 0, ['SHG temperature not at setpoint']); + case obj.OPO_LockStatus + % 0=OPO lock stabilized, 1==OPO not locked to reference cavity. Still optimizing + assert(opo_lock_status == 0, ['OPO not locked to reference cavity. Optimization still in progress']); + case obj.SHG_LockStatus + % 0=SHG lock stabilized, 1==SHG not locked to reference cavity. Still optimizing + assert(shg_lock_status == 0, ['SHG not locked to reference cavity. Optimization still in progress']); + case obj.Etalon_LockStatus + % 0=etalon lock stabilized, 1==etalon not locked to reference cavity. Still optimizing + assert(etalon_lock_status == 0, ['etalon not locked to reference cavity. Optimization still in progress']); + case obj.WLM_PID_Optimize + case obj.Ext_SetCommand + % 0=command executed correctly, 1==error command not executed by external module + assert(etalon_lock_status == 1, ['Command not executed by external module. Check that it is on.']); + end + end + + function [status] = cwave_connect(obj) + %Description: Connects to the C-Wave. This function has to be executed once during runtime. + %Arguments: ipAddress is the IP address of the CWAVE as string in the format 123.123.123.123 + %Returns: int value, 0 means connection failed, 1 means successfully connected. + %Logic inverted from original DLL status bit by LibraryFunction. + %% connect to device + status = LibraryFunction(obj.LibraryName, obj.ConnectCwave, obj.ip); + % mitigate bug in DLL, first connection attempt might fail -> retry + if (status == 0) + status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, obj.ip); + end + end + + function [status,dllVer] = dll_version(obj) + %Description: Reads version of the DLL + %Returns: Returns an integer value with the version of the DLL + % also return status bit (0 = correct dll version, 1 = + % incorrect dll version). + dllVer = calllib(obj.LibraryName, obj.DLL_Version); + if( dllVer ~= obj.DLL_identity) + status = 1; + else + status = 0; + end + disp(['C-WAVE DLL loaded. Version: ' num2str(dllVer)]); + obj.CheckErrorStatus(obj,status,obj.DLL_Version); + end + + function admin_status = admin_elevate(obj,password) + %Description: Grants admin rights to the user to access advanced commands. + %Arguments: password is the password as string. + %Returns: Returns an integer value. 1 means no admin rights, 0 means admin rights + admin_status = LibraryFunction(obj.LibraryName,obj.Admin,password); + end + + function measure_status = cwave_updatestatus(obj) + %Description: Manually updates status info (photodiode values, temperatures, statusbits) in the library. + %This function is automatically executed on demand, so there is usually no need to execute it manually. + %Returns: Returns status int value. 0 means update succeeded, 1 means update failed. + measure_status = LibraryFunction(obj.LibraryName,obj.UpdateStatus); + end + + function intvalue = get_intvalue(cmd) + %Description: Reads the value of an integer parameter. + %Arguments: Parameter as string. See parameter list for valid parameters. + %Returns: Returns the requested integer value. + + %% INT PARAMETER LIST + % Name Type Valid range Read / Write Description + %% topo_set Int 20000-170000 RW Setpoint of the OPO temperature in mK + % topo_is Int 20000-170000 R Current OPO temperature in mK + %% tshg_set Int 20000-170000 RW Setpoint of the SHG temperature in mK + % tshg_is1 Int 20000-170000 R Current SHG1 temperature in mK + %% tshg_is2 Int 20000-170000 R Current SHG2 temperature in mK + % tref_set Int 20000-170000 RW Setpoint of the reference temperature in mK + %% tref_is Int 20000-170000 R Current reference temperature in mK + % shtter_las Int 0, 1 RW Laser shutter position. 1 means open, 0 closed + %% shtter_shg Int 0, 1 RW SHG shutter position. 1 means open, 0 closed + % shtter_las_out Int 0, 1 RW Laser output shutter position. 1 means open, 0 closed + %% shtter_opo_out Int 0, 1 RW OPO output shutter position. 1 means open, 0 closed + % shtter_shg_out Int 0, 1 RW SHG output shutter position. 1 means open, 0 closed + %% laser_en Int 0, 1 RW Enable internal pump laser. 0 disabled, 1 enabled + % monout_sel Int 0-12 RW Select Signal at monitor 1 output. + % 0: Error Signal OPO + % 1: Error Signal SHG + % 2: Error Signal Etalon + % 4: Piezo OPO + % 5: Piezo SHG + % 6: Piezo Etalon + % 7: Piezo Reference + % 9: Pump laser power + % 11: SHG power + % 12: OPO power + %% monout2_sel Int 0-12 RW Select Signal at monitor 2 output. See Monitor 1 for details. + % regopo_on Int 0-2 RW OPO regulator mode. + % 0: off + % 1: scan + % 2: regulate + %% regshg_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on + % regeta_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on + %% regopo_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + %% Should not need to be touched. + % regshg_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + % Should not need to be touched. + %% regeta_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. + %% Should not need to be touched. + % reghsg_threshold Int 0-4095 RW SHG power threshold above which SHG regulator is active. + % Needed to select proper mode. Is set automatically, + % usually no user input required. + %% opo_lambda Int 45000-130000 W Wavelength setpoint of the C-Wave in nm*100. + % opo_rlambda Int -100-100 W Execute relative wavelength step (fundamental wavelength!) + % in nm*100. Maximum step is 1 nm. + %% thicketa_rel Int -100-100 W Execute relative wavelength step of the thick etalon only + %% (fundamental wavelength!) in nm*100. Maximum step is 1 nm. + % thicketa_rel_hr Int -1000...1000 W Same as thicketa_rel but resolution is 1 pm + + %% WAVELENGTH STABILIZATION PARAMETERS + % Name Type Valid range Default Description + %% WLM_pid_p Int 0-100000 0 Proportional constant of the wavelength regulator. + %% Not needed for many applications + % WLM_pid_i Int 0-100000 500 Integral constant for wavelength regulator + %% WLM_pid_direction Int -1, 0, 1 -1 Direction of the regulator. Does not have to be changed + %% in most cases. + % WLM_bigsteps Int 0, 1 1 Allow the regulator to do big wavelength steps, e. g. completely + % re-dial a wavelength if the setpoint is too far away from the + % current output wavelength. + %% WLM_etalonsteps Int 0, 1 1 Allow the regulator to touch the thick etalon to reach + %% the desired wavelength. + % WLM_piezosteps Int 0, 1 1 Allow the regulator to move the cavity piezo to reach + % the desired wavelength. + %% WLM_regout Int 0-65535 0 Regulator output, good for checking if it works + + %% Read value of integer parameter + % no error status bit is returned so calllib is used. + intvalue = calllib(obj.LibraryName,obj.Get_IntValue,cmd); + end + + function floatvalue = get_floatvalue(cmd) + %Description: Reads the value of an floating point parameter. + %Arguments: Parameter as string. See parameter list for valid parameters. + %Returns: Returns the requested floating point value. + + %% INT PARAMETER LIST + % Name Type Valid range Read / Write Description + %% laser_pow Double 0?1.5 RW Laser power of internal pump laser in W + + %% WAVELENGTH STABILIZATION PARAMETERS + % Name Type Valid range Default Description + %% WLM_pid_setpoint Double 450?1300 Desired wavelength in nm. + % WLM_targetdeviation Double 0?1 0.01 Desired maximum deviation from the setpoint in nm. + % The minimum value depends on the used wavemeter resolution. + % Smaller values give higher accuracy but may require longer + % time or manual input. Larger values result in faster settling + % but a less accurate output wavelength. + + %% Read value of float parameter + floatvalue = calllib(obj.LibraryName,obj.Get_floatValue,cmd); + end + + function status = set_intvalue( cmd,value) + % Description: Sets the value of an integer parameter. + % Arguments: cmd is the Parameter as string. See parameter list + % for valid parameters. value is the desired new value of the parameter. + % Returns: Returns 0 (1 before inversion) if the new value was set correctly. + % Returns 1 (-1 before inversion) if an error occurred. + %% Writable Int Parameters are listed above in get_intvalue function comments + %% Writable Wavelength stabilization parameters are listed above in get_intvalue function comments + status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value);\ + end + + function optimize_status = is_ready(obj) + %Description: Checks if all C-Wave routines have finished and the C-Wave produces the desired output + %Arguments: none + %Returns: Returns an integer value. 0 means no errors, C-Wave is ready. 1 means C-Wave is still in optimization + %% Check if optimization is complete + optimize_status = LibraryFunction(obj.LibraryName, obj.Is_Ready); + end + + function status = set_floatvalue(cmd,value) + % Description: Sets the value of an floating point parameter. + % Arguments: cmd is the Parameter as string. See parameter list + % for valid parameters. value is the desired new value of the parameter. + % Returns: Returns 0 (1 before inversion) if the new value was set correctly. + % Returns 1 (-1 before inversion) if an error occurred. + %% Writable Int Parameters are listed above in get_floatvalue function comments + %% Writable Wavelength stabilization parameters are listed above in get_floatvalue function comments + status = LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); + end + + function status = set_command(cmd) + % Description: Executes a command which has no numerical argument. + % Arguments: cmd is the command as string. See the command list for reference. + % Returns: Returns 0 (1 before inversion) if the new command was executed correctly. Returns 1 (-1 before inversion) + % if an error occurred. + %% Parameter Name Description + % opt_tempshg Re-optimize SHG temperature by doing a temperature search. + % This command is automatically executed each time a new wavelength is selected. + %% regeta_catch Try to re-lock thick etalon to prevent multimode operation. + %% If SHG output is required, a successive SHG temperature search may be required. + % opt_stop Stop all optimizations. Usefull for full manual control of the C-Wave. + %% Set Command + status = LibraryFunction(obj.LibraryName, obj.SetCommand,cmd); + end + + function [status,laser_power] = get_photodiode_laser(obj) + % Description: Reads the current laser power (what unit??) + % Arguments: none + % Returns: Returns the laser photodiode value + %% Read laser power + laser_power = calllib(obj.LibraryName,obj.LaserPower); + if( laser_power > obj.Laser_MaxPower || laser_power < obj.Laser_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.LaserPower) + end + + function [status,opo_power] = get_photodiode_opo(obj) + % Description: Reads the current OPO infrared power + % Arguments: none + % Returns: Returns the infrared output power in mW + %% Read IR opo power + opo_power = calllib(obj.LibraryName,obj.OPO_Power); + if (opo_power > obj.OPO_MaxPower || opo_power < obj.OPO_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.OPO_Power); + end + + function [shg_power] = get_photodiode_shg(obj) + % Description: Reads the current (second harmonic generator) SHG visible power + % Arguments: none + % Returns: Returns the visible output power in mW + %% Read SHG power + shg_power = calllib(obj.LibraryName, obj.SHG_Power); + if (shg_power > obj.SHG_MaxPower || opo_power < obj.OPO_MinPower) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.SHG_Power); + end + + function status = get_statusbits(obj) + % Description: Reads the current status of the C-Wave + % Arguments: none + % Returns: Returns an 16-bit integer value. Each bit corresponds to the + % status of one component. 0 means, the component is ready for operation, + % 1 means the component is not yet stable. Current valid bits from LSB to MSB are: + % 0 OPO stepper + % 1 OPO temperature + % 2 SHG stepper + % 3 SHG temperature + % 4 Thin etalon + % 5 OPO lock + % 6 SHG lock + % 7 Etalon lock + % 8 Laser emission (inverted) + % 9 Reference temperature + % Poll cwave status + cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib + status_vector = de2bi(cwave_status); + obj.opo_stepper_stat = status_vector(1); + obj.opo_temp_stat = status_vector(2); + obj.shg_stepper_stat = status_vector(3); + obj.shg_temp_stat = status_vector(4); + obj.thin_etalon_stat = status_vector(5); + obj.opo_lock_stat = status_vector(6); + obj.shg_lock_stat = status_vector(7); + obj.etalon_lock_stat = status_vector(8); + obj.laser_emission_stat = ~status_vector(9); + obj.ref_temp_stat = status_vector(10); + if(cwave_status ~=0) + status = 1; + else + status = 0; + end + obj.CheckErrorStatus(obj,status,obj.StatusReport) + end + + function WLM_PID_Compute(wl_measured) + % Description: This function executes automatic wavelength regulation of the + % C-Wave if the current output wavelength is measured by an external wavemeter + % and monitored back into the C-Wave by this function. See WLM parameters for + % details. The C-Wave is automatically adapted to the new wavelength measurement + % each time this function is executed. To disable the automatic wavelength + % regulation just do not execute this function. + % Arguments: measurement is the current measured wavelength in nm. You can + % provide fundamental or SHG measurement. However, measuring the fundamental + % wavelength will be more reliable for complete automation. + % Returns: none + LibraryFunction(obj.LibraryName,obj.WLM_PID_Optimize,wl_measured); % suggest change to callib + end + + function shutter_lsr(obj) + %open or close internal pump laser shutter + if strcmp(obj.lsr_shutter, obj.Open) + ret = set_intvalue(obj.ShutterLaser,1); + assert(ret == 1, 'Opening pump laser shutter failed'); + elseif strcmp(obj.lsr_shutter, obj.Close) + ret = set_intvalue(obj.ShutterLaser,0); + assert(ret == 0, 'Closing pump laser shutter failed'); + end + end + + function shutter_shg(obj) + %open or close SHG shutter + if strcmp(obj.shg_shutter, obj.Open) + ret = set_intvalue(obj.ShutterSHG,1); + assert(ret == 1, 'Opening SHG shutter failed'); + elseif strcmp(shg.lsr_shutter, obj.Close) + ret = set_intvalue(obj.ShutterSHG,0); + assert(ret == 0, 'Closing SHG shutter failed'); + end + end + + function status = getStatus(obj) + % poll connection status if CWAVE + % Function Call currently not avialable waiting DLL file info + % from Hubner + status = obj.cwave_connect(ipAddr); + end + + function status = delete(obj) + %Delete instance of CWAVE object. + %Disconnect CWAVE + obj.disconnect_cwave(); + %clean up loaded library from memory + unloadlibrary(obj.LibraryName); + status = libisloaded(obj.LibraryName); + if status + assert(status==1, 'CWAVE Library still in memory!'); + end + end + + function disconnect_cwave(obj) + % Probably easiset if using a disconnect function to disconnect + % CWAVE + LibraryFunction(obj.LibraryName,obj.Disconnect); + end + + %{ + function set_target_wavelength(obj) + %set target wavelength with a coarse 0.01 nm resolution + ret = obj.set_intvalue('opo_lambda',round(obj.target_wavelength*100)); + assert(ret == 1, 'Setting target wavelength failed'); + disp(['Target wavelength set: ' num2str(round(obj.target_wavelength*100)/100) 'nm']); + % IMPORTANT: wait one second before starting to poll for ready + pause(1); + end + %} + + function set_target_wavelength(obj, setpoint) + % set the target wavelength to fine tune toward + ret = obj.set_intvalue(WLM_PID_Setpoint, round(setpoint*100)); + assert(ret == 1, 'Setting setpoint wavelength failed'); + disp(['Setpoint wavelength set: ' num2str(round(setpoint*100)/100) 'nm']); + % IMPORTANT: wait one second before starting to poll for ready + pause(1); + end + + function fine_tune(obj, measured_wavelength) + % fine tune based on wavemeter measurement + ret = obj.set_intvalue(WLM_PiezoSteps, 1); + assert(ret == 1, 'Turning on cavity piezo in PID failed'); + obj.WLM_PID_Compute(measured_wavelength); + end + + function coarse_tune(obj, measured_wavelength) + % coarse tune based on wavemeter measurement + ret = obj.set_intvalue(WLM_PiezoSteps, 0); + assert(ret == 1,'Turning off cavity piezo in PID failed'); + obj.WLM_PID_Compute(measured_wavelength); + end + + function flag = abort_tune(obj) + %Stops optimization of wavelength tuning. + flag = obj.set_command(obj.StopOptimization); + assert(flag==1, 'Optimization has not stopped'); + end + + function piezo = tune_ref_cavity(obj,piezo_percent) + %Piezo voltage is passed a a percentage of the total range + %Total range is 0-65535 + %Convert from percentage to integer + peizo_voltage = round(piezo_percent*obj.Piezo_maxBit); + + flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.RefCavity_Piezo,peizo_voltage); + if (flag == 1) + piezo = piezo_percent; + elseif (flag == -1) + piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); + piezo = piezo_voltage/obj.Piezo_maxBit; + end + end + + function piezo = tune_thick_etalon(obj,relative_wl_pm) + %Piezo voltage is passed a a percentage of the total range + %Total range is 0-65535 + %Convert from percentage to integer + flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); + if (flag == 1) + piezo = piezo_percent; + elseif (flag == -1) + piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); + piezo = piezo_voltage/obj.Piezo_maxBit; + end + end + end + + %Methods I will likey never use + methods + function initialize_shutters(obj) + %Open or close all shutters + %Our CWAVE only has internal pump laser and SHG shutters + if strcmp(obj.all_shutters,obj.Open) + ret_lsr = set_intvalue(obj.ShutterLaser,1); + assert(ret_lsr == 1, 'Opening pump laser shutter failed'); + ret_shg = set_intvalue(obj.ShutterSHG,1); + assert(ret_shg == 1, 'Opening shg shutter failed'); + elseif strcmp(obj.all_shutters,obj.Close) + ret_lsr = set_intvalue(obj.ShutterLaser,0); + assert(ret_lsr == 1, 'Closing pump laser shutter failed'); + ret_shg = set_intvalue(obj.ShutterSHG,0); + assert(ret_shg == 1, 'Closing shg shutter failed'); ] + end + end + + function [status] = ext_set_command(cmd) + % Description: Sends a command to the external module. + % Arguments: cmd is the command as string. See the documentation of the external module for valid commands. + % Returns: Returns 1 if the new command was executed correctly. Returns -1 if an error occurred. + %% external commands for WS8-10 High Finesse wavemeter + %% set command for external module (i.e. the wavemeter) + status = LibraryFunction(obj.LibraryName,obj.Ext_SetCommand,cmd); + end + + function [ext_intvalue] = ext_get_intvalue(cmd) + % Description: Reads the value of an integer parameter from the external module. + % Arguments: Parameter as string. See documentation of external module for valid parameters. + % Returns: Returns the requested integer value. + %% Table of allowing integer paramters for high finesse WS8-10 wavemeter + ext_intvalue = calllib(obj.LibraryName, obj.ExtGet_IntValue,cmd); + end + + function [ext_floatvalue] = ext_get_floatvalue(cmd) + % Description: Reads the value of an floating point parameter from the external module. + % Arguments: Parameter as string. See documentation of external module for valid parameters. + % Returns: Returns the requested floating point value. + %% Table of allowable float parameters for High Finesse WS8-10 wavemeter + ext_floatvalue = calllib(obj.LibraryName, obj.ExtGet_FloatValue, cmd); + end + + function [laser_status] = get_status_laser(obj) + % Description: Reads the current status of the pump laser. + % Arguments: none + % Returns: Returns 0 (1 before inversion) if the pump laser is active and the laser shutter is open. + % Returns 1 (0 before inversion) if no or not sufficient laser power is available. + laser_status = LibraryFunction(obj.LibraryName,obj.LaserStatus); + end + + function [ref_temp_status] = get_status_temp_ref(obj) + % Description: Reads the current status of the reference temperature. + % Arguments: none + % Returns: Returns 0 if the reference temperature is stable. + % Returns 1 if the reference temperature is not at setpoint. + %% Poll temperature status + ref_temp_status = LibraryFunction(obj.LibraryName, obj.Reference_TempStatus); + end + + function [opo_temp_status] = get_status_temp_opo(obj) + % Description: Reads the current status of the OPO temperature. + % Arguments: none + % Returns: Returns 0 if the OPO temperature is stable. + % Returns 1 if the OPO temperature is not at setpoint. + %% Poll OPO Temperature Status + opo_temp_status = LibraryFunction(obj.LibraryName, obj.OPO_TempStatus); + end + + function [shg_temp_status] = get_status_temp_shg(obj) + % Description: Reads the current status of the SHG temperature. + % Arguments: none + % Returns: Returns 0 if the SHG temperature is stable. + % Returns 1 if the SHG temperature is not at setpoint. + %% Poll SHG temperature Status + shg_temp_status = LibraryFunction(obj.LibraryName, obj.SHG_TempStatus); + end + + function [opo_lock_status] = get_status_lock_opo(obj) + % Description: Reads the current status of the OPO lock. + % Arguments: none + % Returns: Returns 0 if the OPO is locked to the reference cavity and + % produces stable output. Returns 1 if optimization is still in progress. + %% Poll opo_lock_status...What exactly is the OPO lock? + opo_lock_status = LibraryFunction(obj.LibraryName, obj.OPO_LockStatus); + end + + function [shg_lock_status] = get_status_lock_shg(obj) + % Description: Reads the current status of the SHG lock. + % Arguments: none + % Returns: Returns 0 if the SHG cavity is locked and produces stable output. + % Returns 1 if optimization is still in progress. + shg_lock_status = LibraryFunction(obj.LibraryName, obj.SHG_LockStatus); + end + + function [etalon_lock_status] = get_status_lock_etalon(obj) + % Description: Reads the current status of the etalon lock. + % Arguments: none + % Returns: Returns 0 if the etalon is locked. Returns 1 if optimization is still in progress. + etalon_lock_status = LibraryFunction(obj.LibraryName, obj.Etalon_LockStatus); + end + end + +end + diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m new file mode 100644 index 000000000..a32a13fb6 --- /dev/null +++ b/Modules/+Sources/CWave.m @@ -0,0 +1,93 @@ +classdef CWave < Modules.Source & Sources.TunableLaser_invisible & Sources.ConnectableMixin_invisible + %Cwave controls all aspects of the cwave laser which powers AOM + % and the PulseStreamer which triggers AOM + % + % Wavemeter used for tuning and scanning of laser + % + % The cwave is continuously operated and used to control + % an AOM whose on/off state is controlled by the + % PulseStreamer. + % + % The laser tuning is controlled by the methods required by the + % TunableLaser_invisible superclass. + + properties(SetObservable,SetAccess=private) + source_on = false; + end + + properties(SetObservable,AbortSet) + resonator_percent = 0; + tuning = false; + end + + properties(SetAccess=private) + PulseStreamer %hardware handle + wavemeter + cwaveHandle + end + + methods(Access=private) + function obj = CWave() + obj.loadPrefs; + end + function err = connect_driver(obj,propname,drivername,varargin) + err = []; + if ~isempty(obj.(propname)) + delete(obj.(propname)); %remove any old connection + end + if ischar(varargin{1}) && strcmpi(varargin{1},obj.no_server) %first input is always an ip address + obj.(propname) = []; + else + try + obj.(propname) = Drivers.(drivername).instance(varargin{:}); + catch err + obj.(propname) = []; + end + end + end + end + + methods + function TuneSetpoint(obj,setpoint) + %TuneSetpoint Sets the wavemeter setpoint + % frequency = desired setpoint in THz or nm + + %check if in range + end + + function TuneCoarse(obj, target) + %TuneCoarse moves the laser to the target frequency + % + % It assumes the laser is close enough to not require + % changing of the OPO temperature to reach the target. + % + % First it achieves accuracy to within a picometer by + % changing the thick etalon piezo, then adjusts with + % the cavity piezo. + % + % target = frequency in THz + end + + function TunePercent(obj, ppercent) + %TunePercent sets the cavity piezo percentage + % + % ppercent = desired piezo percentage from 1 to 100 + end + + function on(obj) + %{ + assert(~isempty(obj.PulseStreamer),'No IP set!') + if ~obj.diode_on + obj.activate; + end + obj.PulseStreamer.lines(obj.PBline) = true; + obj.source_on = true; + %} + end + function off(obj) + %{ + assert(~isempty(obj.PulseStreamer),'No IP set!') + obj.source_on = false; + obj.PulseStreamer.lines(obj.PBline) = false; + %} + end diff --git a/Modules/+Sources/ConnectableMixin_invisible.m b/Modules/+Sources/ConnectableMixin_invisible.m new file mode 100644 index 000000000..ef5449b1d --- /dev/null +++ b/Modules/+Sources/ConnectableMixin_invisible.m @@ -0,0 +1,19 @@ +classdef(Abstract) ConnectableMixin + methods(Acces=private) + function err = connect_driver(obj,propname,drivername,varargin) + err = []; + if ~isempty(obj.(propname)) + delete(obj.(propname)); %remove any old connection + end + if ischar(varargin{1}) && strcmpi(varargin{1},'No Server') %first input is always an ip address + obj.(propname) = []; + else + try + obj.(propname) = Drivers.(drivername).instance(varargin{:}); + catch err + obj.(propname) = []; + end + end + end + end +end \ No newline at end of file From 4e1e5f215b3b787af6572f551a8bea0a77b89c41 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 17 Jun 2019 15:39:00 -0400 Subject: [PATCH 05/71] added script for testing cwave driver --- Modules/+Drivers/CWave.m | 4 +- Modules/+Drivers/cwave.m | 711 ---------------------------- Modules/+Drivers/cwave_testscript.m | 31 ++ Modules/+Sources/CWave.m | 83 ++-- 4 files changed, 80 insertions(+), 749 deletions(-) delete mode 100644 Modules/+Drivers/cwave.m create mode 100644 Modules/+Drivers/cwave_testscript.m diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 9000dc465..dbf40a2b3 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -3,10 +3,10 @@ % % for fine-tuning best used with a wavemeter feedback loop - properties(SetAccess = immutable) + %properties(SetAccess = immutable) %ip = '192.168.11.3'; %password = 457; %457 gives engineering access. 111 gives full superuser access. Not recommended...why? - end + %end properties target_wavelength = 615.000001; % Target Wavelength diff --git a/Modules/+Drivers/cwave.m b/Modules/+Drivers/cwave.m deleted file mode 100644 index 83de8c42a..000000000 --- a/Modules/+Drivers/cwave.m +++ /dev/null @@ -1,711 +0,0 @@ -classdef cwave < Modules.Driver - %UNTITLED2 Summary of this class goes here - % Detailed explanation goes here - - properties(SetAccess = immutable) - ip = '192.168.11.3'; - %password = 457; %457 gives engineering access. 111 gives full superuser access. Not recommended...why? - end - - properties - target_wavelength = 615.000001; % Target Wavelength - all_shutters = 'open'; - shg_shutter = 'close'; - lsr_shutter = 'open'; - opo_stepper_stat = 0; - opo_temp_stat = false(1); - shg_stepper_stat = false(1); - shg_temp_stat = false(1); - thin_etalon_stat = false(1); - opo_lock_stat = false(1); - shg_lock_stat = false(1); - etalon_lock_stat = false(1); - laser_emission_stat = false(1); - ref_temp_stat = false(1); - end - - properties(Constant,Hidden) - % constants for C library - Pathx64 = 'C:\Program Files (x86)\Hübner\C-WAVE Control\MatlabControl\x64\'; - Pathx86 = 'C:\Program Files (x86)\Hübner\C-WAVE Control\MatlabControl\x86\'; - LibraryName = 'CWAVE_DLL'; % alias for library - LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll - LibraryHeader = 'CWAVE_DLL.h'; - OS_64bit = 'win64'; - ComputerArch = 'arch'; - ConnectCwave = 'cwave_connect'; - DLL_Version= 'DLL_Version'; - DLL_identity = 1; - Admin = 'admin_elevate'; - UpdateStatus = 'cwave_updatestatus'; - Get_IntValue = 'get_intvalue'; - Get_floatValue = 'get_floatvalue'; - Set_IntValue = 'set_intvalue'; - Set_FloatValue = 'set_floatvalue'; - Is_Ready = 'is_ready'; - SetCommand = 'set_command'; - LaserPower = 'get_photodiode_laser'; - OPO_Power = 'get_photodiode_opo'; - SHG_Power = 'get_photodiode_shg'; - StatusReport = 'get_statusbits'; - LaserStatus = 'get_status_laser'; - Reference_TempStatus = 'get_status_temp_ref'; - OPO_TempStatus = 'get_status_temp_opo'; - SHG_TempStatus = 'get_status_temp_shg'; - OPO_LockStatus = 'get_status_lock_opo'; - SHG_LockStatus = 'get_status_lock_shg'; - Etalon_LockStatus = 'get_status_lock_etalon'; - WLM_PID_Optimize = 'WLM_PID_Compute'; - Ext_SetCommand = 'ext_set_command'; - ExtGet_IntValue = 'ext_get_intvalue'; - ExtGet_FloatValue = 'ext_get_floatvalue'; - ShutterSHG = 'shtter_shg'; - ShutterLaser = 'shtter_las'; - Open = 'open'; - Close = 'close'; - StopOptimization = 'opt_stop'; - CoarseTune = 'coarse'; - FineTune = 'fine'; - Disconnect = 'cwave_disconnect'; - RefCavity_Piezo = 'x'; - ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; - ThickEtalon_Piezo = 'thicketa_rel'; - RefCavityPiezo_maxBit = 65535/100; - Laser_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - Laser_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) - OPO_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - OPO_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) - SHG_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - SHG_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) - end - - %% Signleton Method - methods(Static) - function obj = instance(ip) - mlock; - persistent Objects - if isempty(Objects) - Objects = Drivers.cwave.empty(1,0); - end - for i = 1:length(Objects) - if isvalid(Objects(i)) && isequal({ip},Objects(i).singleton_id) - obj = Objects(i); - return - end - end - obj = Drivers.cwave(ip); - obj.singleton_id = {ip}; - Objects(end+1) = obj; - end - end - - %% Constructor Method - methods(Access=private) - function obj = cwave() - obj.dll_ver = load_cwave_dll(obj); %load dll for cwave - obj.status = cwave_connect(); %connect cwave - % open all internal and output shutters in cwave system - obj.shutter_lsr(); - obj.shutter_shg(); - %obj.initialize_shutters; - end - end - - %% Methods accessible to user - methods - - function dll_ver = load_cwave_dll(obj) - % load DLL - if (~libisloaded(obj.LibraryName)) - if (strcmp(computer(obj.ComputerArch), obj.OS_64bit)) - %Change file path to full file path. Do not use relative - %file path. Also all strings should be switched to constant - %properties - %loadlibrary('x64/CWAVE_DLL', obj.LibraryHeader); - path = fullfile(obj.Pathx64 ,obj.LibraryFilePath); % 64bit - [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); - else - %loadlibrary('x86/CWAVE_DLL', obj.LibraryHeader); - path = fullfile(obj.Pathx86 ,obj.LibraryFilePath); % 32bit - [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); - end - end - if (libisloaded(obj.LibraryName)) - %% return dll version - dll_ver = obj.dll_version(); - if (dll_ver ~= obj.DLL_identity) - assert(dll_ver == obj.DLL_version, ['CWAVE DLL library not loaded, DLL version ' dll_ver ' not equal to ' obj.DLL_version]); - end - end - end - - function [varargout] = LibraryFunction(obj,FunctionName,varargin) - % use this function to call arbitrary library functions from - % CWAVE DLL. Checks for error, and returns all but status - - nargs = Base.libnargout(obj.LibraryName,FunctionName); - if nargs < 2 - varargout = ''; - status = calllib(obj.LibraryName,FunctionName,varargin{:}); - else - [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); - end - obj.CheckErrorStatus(status); - end - - function CheckErrorStatus(obj,status,FunctionName) - %edit cases TBD. Need to sort out string to report and - %flag/status for each function - inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... - obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; - if(ismember(FunctionName, inversion_condition)) - status = ~status; - end - switch FunctionName - case obj.ConnectCwave - % 0=connection failed, 1==connection successful - assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed']); - case obj.DLL_Version - assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); - case obj.Admin - % 0==admin rights granted, 1=no admin rights granted - assert(admin_status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); - case obj.UpdateStatus - % 0==update succeeded, 1=update failed - assert(measure_status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); - case obj.Set_IntValue - % 0== integer value set, 1= integer value not set - assert(measure_status == 0, ['CWAVE Error: Int value not set']); - case obj.Is_Ready - % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing - assert(optimize_status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); - case obj.Set_FloatValue - % 0==update succeeded, 1=update failed - assert(measure_status == 0, ['CWAVE Error: float value not set']); - case obj.SetCommand - % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); - case obj.LaserPower - % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: Laser power not within standard operating range.']); - case obj.OPO_Power - % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: OPO power not within standard operating range.']); - case obj.SHG_Power - % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: SHG power not within standard operating range.']); - case obj.StatusReport - % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: All elements are not stable and/or locked.']); - case obj.LaserStatus - % 0=update failed, 1==update succeeded - assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); - case obj.Reference_TempStatus - % 0=referance temperature stabilized, 1==reference temperature not at setpoint - assert(ref_temp_status == 0, ['Reference temperature not at setpoint']); - case obj.OPO_TempStatus - % 0=referance temperature stabilized, 1==reference temperature not at setpoint - assert(opo_temp_status == 0, ['OPO temperature not at setpoint']); - case obj.SHG_TempStatus - % 0=SHG temperature stabilized, 1==SHG temperature not at setpoint - assert(shg_temp_status == 0, ['SHG temperature not at setpoint']); - case obj.OPO_LockStatus - % 0=OPO lock stabilized, 1==OPO not locked to reference cavity. Still optimizing - assert(opo_lock_status == 0, ['OPO not locked to reference cavity. Optimization still in progress']); - case obj.SHG_LockStatus - % 0=SHG lock stabilized, 1==SHG not locked to reference cavity. Still optimizing - assert(shg_lock_status == 0, ['SHG not locked to reference cavity. Optimization still in progress']); - case obj.Etalon_LockStatus - % 0=etalon lock stabilized, 1==etalon not locked to reference cavity. Still optimizing - assert(etalon_lock_status == 0, ['etalon not locked to reference cavity. Optimization still in progress']); - case obj.WLM_PID_Optimize - case obj.Ext_SetCommand - % 0=command executed correctly, 1==error command not executed by external module - assert(etalon_lock_status == 1, ['Command not executed by external module. Check that it is on.']); - end - end - - function [status] = cwave_connect(obj) - %Description: Connects to the C-Wave. This function has to be executed once during runtime. - %Arguments: ipAddress is the IP address of the CWAVE as string in the format 123.123.123.123 - %Returns: int value, 1 means connection failed, 0 means successfully connected. - %Logic inverted from original DLL status bit by LibraryFunction. - %% connect to device - status = LibraryFunction(obj.LibraryName, obj.ConnectCwave, obj.ip); - % mitigate bug in DLL, first connection attempt might fail -> retry - if (status == 0) - status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, obj.ip); - end - end - - function [status,dllVer] = dll_version(obj) - %Description: Reads version of the DLL - %Returns: Returns an integer value with the version of the DLL - % also return status bit (0 = correct dll version, 1 = - % incorrect dll version). - dllVer = calllib(obj.LibraryName, obj.DLL_Version); - if( dllVer ~= obj.DLL_identity) - status = 1; - else - status = 0; - end - disp(['C-WAVE DLL loaded. Version: ' num2str(dllVer)]); - obj.CheckErrorStatus(obj,status,obj.DLL_Version); - end - - function admin_status = admin_elevate(obj,password) - %Description: Grants admin rights to the user to access advanced commands. - %Arguments: password is the password as string. - %Returns: Returns an integer value. 1 means no admin rights, 0 means admin rights - admin_status = LibraryFunction(obj.LibraryName,obj.Admin,password); - end - - function measure_status = cwave_updatestatus(obj) - %Description: Manually updates status info (photodiode values, temperatures, statusbits) in the library. - %This function is automatically executed on demand, so there is usually no need to execute it manually. - %Returns: Returns status int value. 0 means update succeeded, 1 means update failed. - measure_status = LibraryFunction(obj.LibraryName,obj.UpdateStatus); - end - - function intvalue = get_intvalue(cmd) - %Description: Reads the value of an integer parameter. - %Arguments: Parameter as string. See parameter list for valid parameters. - %Returns: Returns the requested integer value. - - %% INT PARAMETER LIST - % Name Type Valid range Read / Write Description - %% topo_set Int 20000-170000 RW Setpoint of the OPO temperature in mK - % topo_is Int 20000-170000 R Current OPO temperature in mK - %% tshg_set Int 20000-170000 RW Setpoint of the SHG temperature in mK - % tshg_is1 Int 20000-170000 R Current SHG1 temperature in mK - %% tshg_is2 Int 20000-170000 R Current SHG2 temperature in mK - % tref_set Int 20000-170000 RW Setpoint of the reference temperature in mK - %% tref_is Int 20000-170000 R Current reference temperature in mK - % shtter_las Int 0, 1 RW Laser shutter position. 1 means open, 0 closed - %% shtter_shg Int 0, 1 RW SHG shutter position. 1 means open, 0 closed - % shtter_las_out Int 0, 1 RW Laser output shutter position. 1 means open, 0 closed - %% shtter_opo_out Int 0, 1 RW OPO output shutter position. 1 means open, 0 closed - % shtter_shg_out Int 0, 1 RW SHG output shutter position. 1 means open, 0 closed - %% laser_en Int 0, 1 RW Enable internal pump laser. 0 disabled, 1 enabled - % monout_sel Int 0-12 RW Select Signal at monitor 1 output. - % 0: Error Signal OPO - % 1: Error Signal SHG - % 2: Error Signal Etalon - % 4: Piezo OPO - % 5: Piezo SHG - % 6: Piezo Etalon - % 7: Piezo Reference - % 9: Pump laser power - % 11: SHG power - % 12: OPO power - %% monout2_sel Int 0-12 RW Select Signal at monitor 2 output. See Monitor 1 for details. - % regopo_on Int 0-2 RW OPO regulator mode. - % 0: off - % 1: scan - % 2: regulate - %% regshg_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on - % regeta_on Int 0-2 RW SHG regulator mode. Mode description see regopo_on - %% regopo_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. - %% Should not need to be touched. - % regshg_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. - % Should not need to be touched. - %% regeta_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. - %% Should not need to be touched. - % reghsg_threshold Int 0-4095 RW SHG power threshold above which SHG regulator is active. - % Needed to select proper mode. Is set automatically, - % usually no user input required. - %% opo_lambda Int 45000-130000 W Wavelength setpoint of the C-Wave in nm*100. - % opo_rlambda Int -100-100 W Execute relative wavelength step (fundamental wavelength!) - % in nm*100. Maximum step is 1 nm. - %% thicketa_rel Int -100-100 W Execute relative wavelength step of the thick etalon only - %% (fundamental wavelength!) in nm*100. Maximum step is 1 nm. - % thicketa_rel_hr Int -1000...1000 W Same as thicketa_rel but resolution is 1 pm - - %% WAVELENGTH STABILIZATION PARAMETERS - % Name Type Valid range Default Description - %% WLM_pid_p Int 0-100000 0 Proportional constant of the wavelength regulator. - %% Not needed for many applications - % WLM_pid_i Int 0-100000 500 Integral constant for wavelength regulator - %% WLM_pid_direction Int -1, 0, 1 -1 Direction of the regulator. Does not have to be changed - %% in most cases. - % WLM_bigsteps Int 0, 1 1 Allow the regulator to do big wavelength steps, e. g. completely - % re-dial a wavelength if the setpoint is too far away from the - % current output wavelength. - %% WLM_etalonsteps Int 0, 1 1 Allow the regulator to touch the thick etalon to reach - %% the desired wavelength. - % WLM_piezosteps Int 0, 1 1 Allow the regulator to move the cavity piezo to reach - % the desired wavelength. - %% WLM_regout Int 0-65535 0 Regulator output, good for checking if it works - - %% Read value of integer parameter - % no error status bit is returned so calllib is used. - intvalue = calllib(obj.LibraryName,obj.Get_IntValue,cmd); - end - - function floatvalue = get_floatvalue(cmd) - %Description: Reads the value of an floating point parameter. - %Arguments: Parameter as string. See parameter list for valid parameters. - %Returns: Returns the requested floating point value. - - %% INT PARAMETER LIST - % Name Type Valid range Read / Write Description - %% laser_pow Double 0?1.5 RW Laser power of internal pump laser in W - - %% WAVELENGTH STABILIZATION PARAMETERS - % Name Type Valid range Default Description - %% WLM_pid_setpoint Double 450?1300 Desired wavelength in nm. - % WLM_targetdeviation Double 0?1 0.01 Desired maximum deviation from the setpoint in nm. - % The minimum value depends on the used wavemeter resolution. - % Smaller values give higher accuracy but may require longer - % time or manual input. Larger values result in faster settling - % but a less accurate output wavelength. - - %% Read value of float parameter - floatvalue = calllib(obj.LibraryName,obj.Get_floatValue,cmd); - end - - function status = set_intvalue( cmd,value) - % Description: Sets the value of an integer parameter. - % Arguments: cmd is the Parameter as string. See parameter list - % for valid parameters. value is the desired new value of the parameter. - % Returns: Returns 0 (1 before inversion) if the new value was set correctly. - % Returns 1 (-1 before inversion) if an error occurred. - %% Wrightable Int Parameters are listed above in get_intvalue function comments - %% Wrightable Wavelength stabilization parameters are listed above in get_intvalue function comments - status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value);\ - end - - function optimize_status = is_ready(obj) - %Description: Checks if all C-Wave routines have finished and the C-Wave produces the desired output - %Arguments: none - %Returns: Returns an integer value. 0 means no errors, C-Wave is ready. 1 means C-Wave is still in optimization - %% Check if optimization is complete - optimize_status = LibraryFunction(obj.LibraryName, obj.Is_Ready); - end - - function status = set_floatvalue(cmd,value) - % Description: Sets the value of an floating point parameter. - % Arguments: cmd is the Parameter as string. See parameter list - % for valid parameters. value is the desired new value of the parameter. - % Returns: Returns 0 (1 before inversion) if the new value was set correctly. - % Returns 1 (-1 before inversion) if an error occurred. - %% Wrightable Int Parameters are listed above in get_floatvalue function comments - %% Wrightable Wavelength stabilization parameters are listed above in get_floatvalue function comments - status = LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); - end - - function status = set_command(cmd) - % Description: Executes a command which has no numerical argument. - % Arguments: cmd is the command as string. See the command list for reference. - % Returns: Returns 0 (1 before inversion) if the new command was executed correctly. Returns 1 (-1 before inversion) - % if an error occurred. - %% Parameter Name Description - % opt_tempshg Re-optimize SHG temperature by doing a temperature search. - % This command is automatically executed each time a new wavelength is selected. - %% regeta_catch Try to re-lock thick etalon to prevent multimode operation. - %% If SHG output is required, a successive SHG temperature search may be required. - % opt_stop Stop all optimizations. Usefull for full manual control of the C-Wave. - %% Set Command - status = LibraryFunction(obj.LibraryName, obj.SetCommand,cmd); - end - - function [status,laser_power] = get_photodiode_laser(obj) - % Description: Reads the current laser power (what unit??) - % Arguments: none - % Returns: Returns the laser photodiode value - %% Read laser power - laser_power = calllib(obj.LibraryName,obj.LaserPower); - if( laser_power > obj.Laser_MaxPower || laser_power < obj.Laser_MinPower) - status = 1; - else - status = 0; - end - obj.CheckErrorStatus(obj,status,obj.LaserPower) - end - - function [status,opo_power] = get_photodiode_opo(obj) - % Description: Reads the current OPO infrared power - % Arguments: none - % Returns: Returns the infrared output power in mW - %% Read IR opo power - opo_power = calllib(obj.LibraryName,obj.OPO_Power); - if (opo_power > obj.OPO_MaxPower || opo_power < obj.OPO_MinPower) - status = 1; - else - status = 0; - end - obj.CheckErrorStatus(obj,status,obj.OPO_Power); - end - - function [shg_power] = get_photodiode_shg(obj) - % Description: Reads the current (second harmonic generator) SHG visible power - % Arguments: none - % Returns: Returns the visible output power in mW - %% Read SHG power - shg_power = calllib(obj.LibraryName, obj.SHG_Power); - if (shg_power > obj.SHG_MaxPower || opo_power < obj.OPO_MinPower) - status = 1; - else - status = 0; - end - obj.CheckErrorStatus(obj,status,obj.SHG_Power); - end - - function status = get_statusbits(obj) - % Description: Reads the current status of the C-Wave - % Arguments: none - % Returns: Returns an 16-bit integer value. Each bit corresponds to the - % status of one component. 0 means, the component is ready for operation, - % 1 means the component is not yet stable. Current valid bits from LSB to MSB are: - % 0 OPO stepper - % 1 OPO temperature - % 2 SHG stepper - % 3 SHG temperature - % 4 Thin etalon - % 5 OPO lock - % 6 SHG lock - % 7 Etalon lock - % 8 Laser emission (inverted) - % 9 Reference temperature - % Poll cwave status - cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib - status_vector = de2bi(cwave_status); - obj.opo_stepper_stat = status_vector(1); - obj.opo_temp_stat = status_vector(2); - obj.shg_stepper_stat = status_vector(3); - obj.shg_temp_stat = status_vector(4); - obj.thin_etalon_stat = status_vector(5); - obj.opo_lock_stat = status_vector(6); - obj.shg_lock_stat = status_vector(7); - obj.etalon_lock_stat = status_vector(8); - obj.laser_emission_stat = ~status_vector(9); - obj.ref_temp_stat = status_vector(10); - if(cwave_status ~=0) - status = 1; - else - status = 0; - end - obj.CheckErrorStatus(obj,status,obj.StatusReport) - end - - function WLM_PID_Compute(wl_measured) - % Description: This function executes automatic wavelength regulation of the - % C-Wave if the current output wavelength is measured by an external wavemeter - % and monitored back into the C-Wave by this function. See WLM parameters for - % details. The C-Wave is automatically adapted to the new wavelength measurement - % each time this function is executed. To disable the automatic wavelength - % regulation just do not execute this function. - % Arguments: measurement is the current measured wavelength in nm. You can - % provide fundamental or SHG measurement. However, measuring the fundamental - % wavelength will be more reliable for complete automation. - % Returns: none - LibraryFunction(obj.LibraryName,obj.WLM_PID_Optimize,wl_measured); % suggest change to callib - end - - function shutter_lsr(obj) - %open or close internal pump laser shutter - if strcmp(obj.lsr_shutter, obj.Open) - ret = set_intvalue(obj.ShutterLaser,1); - assert(ret == 1, 'Opening pump laser shutter failed'); - elseif strcmp(obj.lsr_shutter, obj.Close) - ret = set_intvalue(obj.ShutterLaser,0); - assert(ret == 0, 'Closing pump laser shutter failed'); - end - end - - function shutter_shg(obj) - %open or close SHG shutter - if strcmp(obj.shg_shutter, obj.Open) - ret = set_intvalue(obj.ShutterSHG,1); - assert(ret == 1, 'Opening SHG shutter failed'); - elseif strcmp(shg.lsr_shutter, obj.Close) - ret = set_intvalue(obj.ShutterSHG,0); - assert(ret == 0, 'Closing SHG shutter failed'); - end - end - - function status = getStatus(obj) - % poll connection status if CWAVE - % Function Call currently not avialable waiting DLL file info - % from Hubner - status = obj.cwave_connect(ipAddr); - end - - function status = delete(obj) - %Delete instance of CWAVE object. - %Disconnect CWAVE - obj.disconnect_cwave(); - %clean up loaded library from memory - unloadlibrary(obj.LibraryName); - status = libisloaded(obj.LibraryName); - if status - assert(status==1, 'CWAVE Library still in memory!'); - end - end - - function disconnect_cwave(obj) - % Probably easiset if using a disconnect function to disconnect - % CWAVE - LibraryFunction(obj.LibraryName,obj.Disconnect); - end - - function set_target_wavelength(obj,resolution) - %set target wavelength with either a coarse 0.01 nm resolution - %or a fine resolution determined by wavemeter and internal PID - %of CWAVE. - res_ret = ismemeber(resolution, {ob.CoarseTune; obj.FineTune}); - %res_ret = res_ret(1) || res_ret(2); - assert(res_ret==1, 'Resolution must be either "coarse" or "fine"'); - - if(strcmp(resolution,ob.CoarseTune)) - ret = obj.set_intvalue('opo_lambda',round(obj.target_wavelength*100)); - assert(ret == 1, 'Setting target wavelength failed'); - disp(['Target wavelength set: ' num2str(round(obj.target_wavelength*100)/100) 'nm']); - % IMPORTANT: wait one second before starting to poll for ready - pause(1); - elseif(strcmp(resolution,obj.FineTune)) - obj.WLM_PID_Compute(obj.target_wavelength); - pause(1); - end - end - - function flag = abort_tune(obj) - %Stops optimization of wavelength tuning. - flag = obj.set_command(obj.StopOptimization); - assert(flag==1, 'Optimization has not stopped'); - end - - function piezo = tune_ref_cavity(obj,piezo_percent) - %Piezo voltage is passed a a percentage of the total range - %Total range is 0-65535 - %Convert from percentage to integer - peizo_voltage = round(piezo_percent*obj.Piezo_maxBit); - - flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.RefCavity_Piezo,peizo_voltage); - if (flag == 1) - piezo = piezo_percent; - elseif (flag == -1) - piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); - piezo = piezo_voltage/obj.Piezo_maxBit; - end - end - - function piezo = tune_thick_etalon(obj,relative_wl_pm) - %Piezo voltage is passed a a percentage of the total range - %Total range is 0-65535 - %Convert from percentage to integer - flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); - if (flag == 1) - piezo = piezo_percent; - elseif (flag == -1) - piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); - piezo = piezo_voltage/obj.Piezo_maxBit; - end - end - end - - %Methods I will likey never use - methods - function initialize_shutters(obj) - %Open or close all shutters - %Our CWAVE only has internal pump laser and SHG shutters - if strcmp(obj.all_shutters,obj.Open) - ret_lsr = set_intvalue(obj.ShutterLaser,1); - assert(ret_lsr == 1, 'Opening pump laser shutter failed'); - ret_shg = set_intvalue(obj.ShutterSHG,1); - assert(ret_shg == 1, 'Opening shg shutter failed'); - elseif strcmp(obj.all_shutters,obj.Close) - ret_lsr = set_intvalue(obj.ShutterLaser,0); - assert(ret_lsr == 1, 'Closing pump laser shutter failed'); - ret_shg = set_intvalue(obj.ShutterSHG,0); - assert(ret_shg == 1, 'Closing shg shutter failed'); ] - end - end - - function [status] = ext_set_command(cmd) - % Description: Sends a command to the external module. - % Arguments: cmd is the command as string. See the documentation of the external module for valid commands. - % Returns: Returns 1 if the new command was executed correctly. Returns -1 if an error occurred. - %% external commands for WS8-10 High Finesse wavemeter - %% set command for external module (i.e. the wavemeter) - status = LibraryFunction(obj.LibraryName,obj.Ext_SetCommand,cmd); - end - - function [ext_intvalue] = ext_get_intvalue(cmd) - % Description: Reads the value of an integer parameter from the external module. - % Arguments: Parameter as string. See documentation of external module for valid parameters. - % Returns: Returns the requested integer value. - %% Table of allowing integer paramters for high finesse WS8-10 wavemeter - ext_intvalue = calllib(obj.LibraryName, obj.ExtGet_IntValue,cmd); - end - - function [ext_floatvalue] = ext_get_floatvalue(cmd) - % Description: Reads the value of an floating point parameter from the external module. - % Arguments: Parameter as string. See documentation of external module for valid parameters. - % Returns: Returns the requested floating point value. - %% Table of allowable float parameters for High Finesse WS8-10 wavemeter - ext_floatvalue = calllib(obj.LibraryName, obj.ExtGet_FloatValue, cmd); - end - - function [laser_status] = get_status_laser(obj) - % Description: Reads the current status of the pump laser. - % Arguments: none - % Returns: Returns 0 (1 before inversion) if the pump laser is active and the laser shutter is open. - % Returns 1 (0 before inversion) if no or not sufficient laser power is available. - laser_status = LibraryFunction(obj.LibraryName,obj.LaserStatus); - end - - function [ref_temp_status] = get_status_temp_ref(obj) - % Description: Reads the current status of the reference temperature. - % Arguments: none - % Returns: Returns 0 if the reference temperature is stable. - % Returns 1 if the reference temperature is not at setpoint. - %% Poll temperature status - ref_temp_status = LibraryFunction(obj.LibraryName, obj.Reference_TempStatus); - end - - function [opo_temp_status] = get_status_temp_opo(obj) - % Description: Reads the current status of the OPO temperature. - % Arguments: none - % Returns: Returns 0 if the OPO temperature is stable. - % Returns 1 if the OPO temperature is not at setpoint. - %% Poll OPO Temperature Status - opo_temp_status = LibraryFunction(obj.LibraryName, obj.OPO_TempStatus); - end - - function [shg_temp_status] = get_status_temp_shg(obj) - % Description: Reads the current status of the SHG temperature. - % Arguments: none - % Returns: Returns 0 if the SHG temperature is stable. - % Returns 1 if the SHG temperature is not at setpoint. - %% Poll SHG temperature Status - shg_temp_status = LibraryFunction(obj.LibraryName, obj.SHG_TempStatus); - end - - function [opo_lock_status] = get_status_lock_opo(obj) - % Description: Reads the current status of the OPO lock. - % Arguments: none - % Returns: Returns 0 if the OPO is locked to the reference cavity and - % produces stable output. Returns 1 if optimization is still in progress. - %% Poll opo_lock_status...What exactly is the OPO lock? - opo_lock_status = LibraryFunction(obj.LibraryName, obj.OPO_LockStatus); - end - - function [shg_lock_status] = get_status_lock_shg(obj) - % Description: Reads the current status of the SHG lock. - % Arguments: none - % Returns: Returns 0 if the SHG cavity is locked and produces stable output. - % Returns 1 if optimization is still in progress. - shg_lock_status = LibraryFunction(obj.LibraryName, obj.SHG_LockStatus); - end - - function [etalon_lock_status] = get_status_lock_etalon(obj) - % Description: Reads the current status of the etalon lock. - % Arguments: none - % Returns: Returns 0 if the etalon is locked. Returns 1 if optimization is still in progress. - etalon_lock_status = LibraryFunction(obj.LibraryName, obj.Etalon_LockStatus); - end - end - -end - diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m new file mode 100644 index 000000000..04c678219 --- /dev/null +++ b/Modules/+Drivers/cwave_testscript.m @@ -0,0 +1,31 @@ +import cwave.* + +cwave = instance('192.168.11.3') + +disp('status:') +disp(cwave.getStatus()) + +disp('ref temp:') +disp(cwave.get_status_temp_ref()) + +disp('shg temp:') +disp(cwave.get_status_temp_shg()) + +disp('opo temp:') +disp(cwave.get_status_temp_opo()) + +disp('OPO lock:') +disp(cwave.get_status_lock_opo()) + +disp('etalon lock:') +disp(cwave.get_status_lock_etalon()) + +disp('photodiode power:') +disp(cwave.get_photodiode_laser()) + +disp('current OPO infrared power:') +disp(cwave.get_photodiode_opo()) + +cwave.target_wavelength = 615.000001 +cwave.set_wavelength() + diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index a32a13fb6..6574712e6 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -18,6 +18,8 @@ properties(SetObservable,AbortSet) resonator_percent = 0; tuning = false; + cwave_ip = Sources.CWave.no_server; + pulseStreamer_ip = Sources.CWave.no_server; end properties(SetAccess=private) @@ -26,28 +28,28 @@ cwaveHandle end - methods(Access=private) - function obj = CWave() - obj.loadPrefs; - end - function err = connect_driver(obj,propname,drivername,varargin) - err = []; - if ~isempty(obj.(propname)) - delete(obj.(propname)); %remove any old connection - end - if ischar(varargin{1}) && strcmpi(varargin{1},obj.no_server) %first input is always an ip address - obj.(propname) = []; - else - try - obj.(propname) = Drivers.(drivername).instance(varargin{:}); - catch err - obj.(propname) = []; - end - end - end + properties(Constant,Hidden) + no_server = 'No Server'; % Message when not connected end methods + + % source methods + + function on(obj) + assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') + % TODO say something to PulseStreamer + obj.source_on = true; + + end + function off(obj) + assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') + % TODO say something to PulseStreamer + obj.source_on = false; + end + + % tunable laser methods + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % frequency = desired setpoint in THz or nm @@ -68,26 +70,35 @@ function TuneCoarse(obj, target) % target = frequency in THz end - function TunePercent(obj, ppercent) - %TunePercent sets the cavity piezo percentage + function TunePercent(obj, percent) + %TunePercent sets the resonator cavity piezo percentage % - % ppercent = desired piezo percentage from 1 to 100 + % percent = desired piezo percentage from 1 to 100 + assert(~isempty(obj.cwaveHandle)&&isobject(obj.cwaveHandle) && isvalid(obj.cwaveHandle),'no cwave handle') + assert(percent>=0 && percent<=100,'Target must be a percentage') + obj.resonator_percent = obj.cwaveHandle.tune_ref_cavity(percent) end - function on(obj) - %{ - assert(~isempty(obj.PulseStreamer),'No IP set!') - if ~obj.diode_on - obj.activate; + function GetPercent(obj) + % TODO get piezo percent from cwave + end + + % set methods + + function set.cwave_ip(obj,ip) + err = obj.connect_driver('cwaveHandle', cwave, ip); + if ~isempty(err) + obj.cwave_ip = obj.no_server; + rethrow(err) end - obj.PulseStreamer.lines(obj.PBline) = true; - obj.source_on = true; - %} + obj.cwave_ip = ip; end - function off(obj) - %{ - assert(~isempty(obj.PulseStreamer),'No IP set!') - obj.source_on = false; - obj.PulseStreamer.lines(obj.PBline) = false; - %} + + function set.pulseStreamer_ip(obj, ip) + err = obj.connect_driver('PulseStreamer', PulseStreamerMaster.PulseStreamerMaster, ip); + if ~isempty(err) + obj.pulseStreamer_ip = obj.no_server; + rethrow(err) + end + pulseStreamer_ip = ip; end From 5d11ecf27858cf6c5d253eab9fe8d708a0c6176f Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 18 Jun 2019 11:16:43 -0400 Subject: [PATCH 06/71] minor updates to cwave --- Modules/+Drivers/CWave.m | 34 ++++++++++++-------- Modules/+Drivers/cwave_testscript.m | 6 ++++ Modules/+Sources/CWave.m | 50 +++++++++++++++++++++++------ 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index dbf40a2b3..87bf436ce 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -554,7 +554,6 @@ function disconnect_cwave(obj) LibraryFunction(obj.LibraryName,obj.Disconnect); end - %{ function set_target_wavelength(obj) %set target wavelength with a coarse 0.01 nm resolution ret = obj.set_intvalue('opo_lambda',round(obj.target_wavelength*100)); @@ -563,13 +562,14 @@ function set_target_wavelength(obj) % IMPORTANT: wait one second before starting to poll for ready pause(1); end - %} - - function set_target_wavelength(obj, setpoint) + + function set_pid_target_wavelength(obj, setpoint) % set the target wavelength to fine tune toward - ret = obj.set_intvalue(WLM_PID_Setpoint, round(setpoint*100)); + typecheck = isa(setpoint, 'double') + assert(typecheck == 1, 'Setpoint must be double precision float') + ret = obj.set_intvalue(WLM_PID_Setpoint, setpoint); assert(ret == 1, 'Setting setpoint wavelength failed'); - disp(['Setpoint wavelength set: ' num2str(round(setpoint*100)/100) 'nm']); + disp(['Setpoint wavelength set: ' num2str(setpoint) 'nm']); % IMPORTANT: wait one second before starting to poll for ready pause(1); end @@ -577,14 +577,18 @@ function set_target_wavelength(obj, setpoint) function fine_tune(obj, measured_wavelength) % fine tune based on wavemeter measurement ret = obj.set_intvalue(WLM_PiezoSteps, 1); - assert(ret == 1, 'Turning on cavity piezo in PID failed'); + assert(ret == 1, 'Turning on cavity piezo during PID failed'); + ret = obj.set_intvalue(WLM_etalonsteps, 0); + assert(ret == 1, 'Turning off etalon steps during PID failed'); obj.WLM_PID_Compute(measured_wavelength); end function coarse_tune(obj, measured_wavelength) % coarse tune based on wavemeter measurement - ret = obj.set_intvalue(WLM_PiezoSteps, 0); - assert(ret == 1,'Turning off cavity piezo in PID failed'); + ret = obj.set_intvalue(WLM_PiezoSteps, 1); + assert(ret == 1,'Turning on cavity piezo during PID failed'); + ret = obj.set_intvalue(WLM_etalonsteps, 1); + assert(ret == 1, 'Turning on etalon steps during PID failed'); obj.WLM_PID_Compute(measured_wavelength); end @@ -593,6 +597,12 @@ function coarse_tune(obj, measured_wavelength) flag = obj.set_command(obj.StopOptimization); assert(flag==1, 'Optimization has not stopped'); end + + function piezo = get_ref_cavity_percent(obj) + % returns reference cavity piezo percent value + piezo_voltage = obj.get_intvalue(x); + piezo = piezo_voltage/obj.Piezo_maxBit; + end function piezo = tune_ref_cavity(obj,piezo_percent) %Piezo voltage is passed a a percentage of the total range @@ -604,8 +614,7 @@ function coarse_tune(obj, measured_wavelength) if (flag == 1) piezo = piezo_percent; elseif (flag == -1) - piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); - piezo = piezo_voltage/obj.Piezo_maxBit; + piezo = get_ref_cavity_percent(); end end @@ -617,8 +626,7 @@ function coarse_tune(obj, measured_wavelength) if (flag == 1) piezo = piezo_percent; elseif (flag == -1) - piezo_voltage = LibraryFunction(obj.LibraryName,obj.Get_IntValue); - piezo = piezo_voltage/obj.Piezo_maxBit; + piezo = get_ref_cavity_percent(); end end end diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index 04c678219..22984caf7 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -26,6 +26,12 @@ disp('current OPO infrared power:') disp(cwave.get_photodiode_opo()) +disp('current piezo percent:') +disp(cwave.get_ref_cavity_percent()) + cwave.target_wavelength = 615.000001 cwave.set_wavelength() +disp('new piezo percent:') +disp(cwave.get_ref_cavity_percent()) + diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 6574712e6..921f6fac4 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -13,6 +13,7 @@ properties(SetObservable,SetAccess=private) source_on = false; + locked = false; end properties(SetObservable,AbortSet) @@ -20,6 +21,8 @@ tuning = false; cwave_ip = Sources.CWave.no_server; pulseStreamer_ip = Sources.CWave.no_server; + wavemeter_ip = Sources.CWave.no_server; + wavemeter_channel = 1; % set to integer value end properties(SetAccess=private) @@ -50,24 +53,35 @@ function off(obj) % tunable laser methods + function tune(obj, setpoint, coarse) + assert(~isempty(cwaveHandle), 'no cwave handle') + cwaveHandle.set_pid_target_wavelength(setpoint); + wavelength = wavemeter.getWavelength(); + if coarse + cwaveHandle.coarse_tune(wavelength); + else + cwaveHandle.fine_tune(wavelength); + end + end + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint - % frequency = desired setpoint in THz or nm - - %check if in range + % setpoint = setpoint in nm + obj.tune(setpoint, false); end - function TuneCoarse(obj, target) + function TuneCoarse(obj, setpoint) %TuneCoarse moves the laser to the target frequency % - % It assumes the laser is close enough to not require - % changing of the OPO temperature to reach the target. + % It assumes the laser is already close enough to not + % require changing of the OPO temperature to reach the target. % % First it achieves accuracy to within a picometer by % changing the thick etalon piezo, then adjusts with % the cavity piezo. % - % target = frequency in THz + % setpoint = setpoint in nm + obj.tune(setpoint, true); end function TunePercent(obj, percent) @@ -79,8 +93,8 @@ function TunePercent(obj, percent) obj.resonator_percent = obj.cwaveHandle.tune_ref_cavity(percent) end - function GetPercent(obj) - % TODO get piezo percent from cwave + function piezo = GetPercent(obj) + piezo = cwaveHandle.get_ref_cavity_percent(); end % set methods @@ -102,3 +116,21 @@ function GetPercent(obj) end pulseStreamer_ip = ip; end + + function set.wavemeter_ip(obj, ip) + err = obj.connect_driver('Wavemeter', Wavemeter.Wavemeter, ip, obj.wavemeter_channel); + if ~isempty(err) + obj.wavemeter_ip = obj.no_server; + rethrow(err) + end + wavemeter_ip = ip; + end + + function set.wavemeter_channel(obj, channel) + assert(round(channel)==channel&&channel>0,'wavemeter_channel must be an integer greater than 0.') + obj.wavemeter_channel = channel + err = obj.connect_driver('wavemeter','Wavemeter',obj.wavemeter_ip,val); + if ~isempty(err) + rethrow(err) + end + end \ No newline at end of file From 70666e8db9a469c748d560d4010fca1ec6622e2e Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 18 Jun 2019 12:39:57 -0400 Subject: [PATCH 07/71] bug fixes in progress --- .../PulseStreamerMaster.m | 3 +- Modules/+Drivers/CWave.m | 41 +++++++++++-------- Modules/+Drivers/cwave_testscript.m | 4 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index f437bbd42..14f795853 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -101,7 +101,8 @@ mlock; persistent Objects if isempty(Objects) || ~isvalid(Objects) - Object = Drivers.PulseStreamerMaster.PulseStreamerMaster.empty(1,0); + Objects = Drivers.PulseStreamerMaster.PulseStreamerMaster.empty(1,0); + %changed from Object to Objects in above line end [~,resolvedIP] = resolvehost(ip); for i = 1:length(Objects) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 87bf436ce..8fcf05f03 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -9,6 +9,8 @@ %end properties + init_warnings + dll_ver target_wavelength = 615.000001; % Target Wavelength all_shutters = 'open'; shg_shutter = 'close'; @@ -27,8 +29,9 @@ properties(Constant,Hidden) % constants for C library - Pathx64 = 'C:\Program Files (x86)\H�bner\C-WAVE Control\MatlabControl\x64\'; - Pathx86 = 'C:\Program Files (x86)\H�bner\C-WAVE Control\MatlabControl\x86\'; + Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x64\'; + Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x86\'; + HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\'; LibraryName = 'CWAVE_DLL'; % alias for library LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll LibraryHeader = 'CWAVE_DLL.h'; @@ -36,7 +39,7 @@ ComputerArch = 'arch'; ConnectCwave = 'cwave_connect'; DLL_Version= 'DLL_Version'; - DLL_identity = 1; + DLL_identity = 20; Admin = 'admin_elevate'; UpdateStatus = 'cwave_updatestatus'; Get_IntValue = 'get_intvalue'; @@ -103,10 +106,10 @@ end %% Constructor Method - methods(Access=private) - function obj = CWave() + methods(Access={?Drivers.CWave}) + function obj = CWave(ip) obj.dll_ver = load_cwave_dll(obj); %load dll for cwave - obj.status = cwave_connect(); %connect cwave + obj.status = obj.cwave_connect(ip); %connect cwave % open all internal and output shutters in cwave system obj.shutter_lsr(); obj.shutter_shg(); @@ -128,18 +131,20 @@ %properties %loadlibrary('x64/CWAVE_DLL', obj.LibraryHeader); path = fullfile(obj.Pathx64 ,obj.LibraryFilePath); % 64bit - [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + hpath = fullfile(obj.HPath, obj.LibraryHeader); + [~,obj.init_warnings] = loadlibrary(path, hpath, 'alias',obj.LibraryName); else - %loadlibrary('x86/CWAVE_DLL', obj.LibraryHeader); + %loadlibrary('x86/CWAVE_DLL', obj.LibraryHeader); path = fullfile(obj.Pathx86 ,obj.LibraryFilePath); % 32bit - [~,obj.init_warnings] = loadlibrary(path, obj.LibraryHeader, 'alias',obj.LibraryName); + hpath = fullfile(obj.HPath, obj.LibraryHeader); + [~,obj.init_warnings] = loadlibrary(path, hpath, 'alias',obj.LibraryName); end end if (libisloaded(obj.LibraryName)) %% return dll version - dll_ver = obj.dll_version(); + [~,dll_ver] = obj.dll_version(); if (dll_ver ~= obj.DLL_identity) - assert(dll_ver == obj.DLL_version, ['CWAVE DLL library not loaded, DLL version ' dll_ver ' not equal to ' obj.DLL_version]); + assert(dll_ver == obj.DLL_identity, ['CWAVE DLL library not loaded, DLL version ' dll_ver ' not equal to ' obj.DLL_identity]); end end end @@ -230,16 +235,16 @@ function CheckErrorStatus(obj,status,FunctionName) end end - function [status] = cwave_connect(obj) + function [status] = cwave_connect(obj, ip) %Description: Connects to the C-Wave. This function has to be executed once during runtime. %Arguments: ipAddress is the IP address of the CWAVE as string in the format 123.123.123.123 %Returns: int value, 0 means connection failed, 1 means successfully connected. %Logic inverted from original DLL status bit by LibraryFunction. %% connect to device - status = LibraryFunction(obj.LibraryName, obj.ConnectCwave, obj.ip); + status = obj.LibraryFunction(obj.LibraryName, obj.ConnectCwave, ip); % mitigate bug in DLL, first connection attempt might fail -> retry if (status == 0) - status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, obj.ip); + status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, ip); end end @@ -249,13 +254,15 @@ function CheckErrorStatus(obj,status,FunctionName) % also return status bit (0 = correct dll version, 1 = % incorrect dll version). dllVer = calllib(obj.LibraryName, obj.DLL_Version); + disp('dllver:') + disp(dllVer) if( dllVer ~= obj.DLL_identity) status = 1; else status = 0; end disp(['C-WAVE DLL loaded. Version: ' num2str(dllVer)]); - obj.CheckErrorStatus(obj,status,obj.DLL_Version); + obj.CheckErrorStatus(status,obj.DLL_Version); end function admin_status = admin_elevate(obj,password) @@ -377,7 +384,7 @@ function CheckErrorStatus(obj,status,FunctionName) % Returns 1 (-1 before inversion) if an error occurred. %% Writable Int Parameters are listed above in get_intvalue function comments %% Writable Wavelength stabilization parameters are listed above in get_intvalue function comments - status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value);\ + status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value); end function optimize_status = is_ready(obj) @@ -645,7 +652,7 @@ function initialize_shutters(obj) ret_lsr = set_intvalue(obj.ShutterLaser,0); assert(ret_lsr == 1, 'Closing pump laser shutter failed'); ret_shg = set_intvalue(obj.ShutterSHG,0); - assert(ret_shg == 1, 'Closing shg shutter failed'); ] + assert(ret_shg == 1, 'Closing shg shutter failed'); end end diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index 22984caf7..71d100c16 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -1,6 +1,6 @@ -import cwave.* +%import Modules.Drivers.CWave.* -cwave = instance('192.168.11.3') +cwave = Drivers.CWave.instance('192.168.11.3'); disp('status:') disp(cwave.getStatus()) From 5e8dcfd524c1a901161f727228f15518787e62b1 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 18 Jun 2019 13:29:27 -0400 Subject: [PATCH 08/71] more fixes to cwave --- Modules/+Drivers/CWave.m | 87 +++++++++++++++-------------- Modules/+Drivers/cwave_testscript.m | 2 + 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 8fcf05f03..92efb162e 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -11,6 +11,8 @@ properties init_warnings dll_ver + ip + status target_wavelength = 615.000001; % Target Wavelength all_shutters = 'open'; shg_shutter = 'close'; @@ -89,6 +91,7 @@ methods(Static) function obj = instance(ip) mlock; + obj.ip = ip persistent Objects if isempty(Objects) Objects = Drivers.CWave.empty(1,0); @@ -114,8 +117,8 @@ obj.shutter_lsr(); obj.shutter_shg(); %obj.initialize_shutters; - ret = obj.set_intvalue(WLM_BigSteps, 0); - assert(ret == 1, 'Turning off large steps in PID failed'); + %ret = obj.set_intvalue(obj.WLM_BigSteps, 0); + %assert(ret == 1, 'Turning off large steps in PID failed'); end end @@ -149,10 +152,10 @@ end end - function [varargout] = LibraryFunction(obj,FunctionName,varargin) + function status = LibraryFunction(obj,FunctionName,varargin) % use this function to call arbitrary library functions from % CWAVE DLL. Checks for error, and returns all bit status - + nargs = Base.libnargout(obj.LibraryName,FunctionName); if nargs < 2 varargout = ''; @@ -160,7 +163,7 @@ else [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); end - obj.CheckErrorStatus(status); + obj.CheckErrorStatus(status, FunctionName); end function CheckErrorStatus(obj,status,FunctionName) @@ -179,19 +182,19 @@ function CheckErrorStatus(obj,status,FunctionName) assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); case obj.Admin % 0==admin rights granted, 1=no admin rights granted - assert(admin_status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); + assert(status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); case obj.UpdateStatus % 0==update succeeded, 1=update failed - assert(measure_status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); + assert(status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); case obj.Set_IntValue % 0== integer value set, 1= integer value not set - assert(measure_status == 0, ['CWAVE Error: Int value not set']); + assert(status == 0, ['CWAVE Error: Int value not set']); case obj.Is_Ready % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing - assert(optimize_status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); + assert(status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); case obj.Set_FloatValue % 0==update succeeded, 1=update failed - assert(measure_status == 0, ['CWAVE Error: float value not set']); + assert(status == 0, ['CWAVE Error: float value not set']); case obj.SetCommand % 0=update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); @@ -212,26 +215,26 @@ function CheckErrorStatus(obj,status,FunctionName) assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); case obj.Reference_TempStatus % 0=referance temperature stabilized, 1==reference temperature not at setpoint - assert(ref_temp_status == 0, ['Reference temperature not at setpoint']); + assert(status == 0, ['Reference temperature not at setpoint']); case obj.OPO_TempStatus % 0=referance temperature stabilized, 1==reference temperature not at setpoint - assert(opo_temp_status == 0, ['OPO temperature not at setpoint']); + assert(status == 0, ['OPO temperature not at setpoint']); case obj.SHG_TempStatus % 0=SHG temperature stabilized, 1==SHG temperature not at setpoint - assert(shg_temp_status == 0, ['SHG temperature not at setpoint']); + assert(status == 0, ['SHG temperature not at setpoint']); case obj.OPO_LockStatus % 0=OPO lock stabilized, 1==OPO not locked to reference cavity. Still optimizing - assert(opo_lock_status == 0, ['OPO not locked to reference cavity. Optimization still in progress']); + assert(status == 0, ['OPO not locked to reference cavity. Optimization still in progress']); case obj.SHG_LockStatus % 0=SHG lock stabilized, 1==SHG not locked to reference cavity. Still optimizing - assert(shg_lock_status == 0, ['SHG not locked to reference cavity. Optimization still in progress']); + assert(status == 0, ['SHG not locked to reference cavity. Optimization still in progress']); case obj.Etalon_LockStatus % 0=etalon lock stabilized, 1==etalon not locked to reference cavity. Still optimizing - assert(etalon_lock_status == 0, ['etalon not locked to reference cavity. Optimization still in progress']); + assert(status == 0, ['etalon not locked to reference cavity. Optimization still in progress']); case obj.WLM_PID_Optimize case obj.Ext_SetCommand % 0=command executed correctly, 1==error command not executed by external module - assert(etalon_lock_status == 1, ['Command not executed by external module. Check that it is on.']); + assert(status == 1, ['Command not executed by external module. Check that it is on.']); end end @@ -241,10 +244,10 @@ function CheckErrorStatus(obj,status,FunctionName) %Returns: int value, 0 means connection failed, 1 means successfully connected. %Logic inverted from original DLL status bit by LibraryFunction. %% connect to device - status = obj.LibraryFunction(obj.LibraryName, obj.ConnectCwave, ip); + status = obj.LibraryFunction(obj.ConnectCwave, ip); % mitigate bug in DLL, first connection attempt might fail -> retry if (status == 0) - status = LibraryFunction(obj.LibraryName,obj.ConnectCwave, ip); + status = LibraryFunction(obj.ConnectCwave, ip); end end @@ -376,7 +379,7 @@ function CheckErrorStatus(obj,status,FunctionName) floatvalue = calllib(obj.LibraryName,obj.Get_floatValue,cmd); end - function status = set_intvalue( cmd,value) + function status = set_intvalue(obj, cmd,value) % Description: Sets the value of an integer parameter. % Arguments: cmd is the Parameter as string. See parameter list % for valid parameters. value is the desired new value of the parameter. @@ -384,7 +387,7 @@ function CheckErrorStatus(obj,status,FunctionName) % Returns 1 (-1 before inversion) if an error occurred. %% Writable Int Parameters are listed above in get_intvalue function comments %% Writable Wavelength stabilization parameters are listed above in get_intvalue function comments - status = LibraryFunction(obj.LibraryName,obj.Set_IntValue,cmd, value); + status = obj.LibraryFunction(obj.Set_IntValue,cmd, value); end function optimize_status = is_ready(obj) @@ -392,7 +395,7 @@ function CheckErrorStatus(obj,status,FunctionName) %Arguments: none %Returns: Returns an integer value. 0 means no errors, C-Wave is ready. 1 means C-Wave is still in optimization %% Check if optimization is complete - optimize_status = LibraryFunction(obj.LibraryName, obj.Is_Ready); + optimize_status = obj.LibraryFunction(obj.LibraryName, obj.Is_Ready); end function status = set_floatvalue(cmd,value) @@ -403,7 +406,7 @@ function CheckErrorStatus(obj,status,FunctionName) % Returns 1 (-1 before inversion) if an error occurred. %% Writable Int Parameters are listed above in get_floatvalue function comments %% Writable Wavelength stabilization parameters are listed above in get_floatvalue function comments - status = LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); + status = obj.LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); end function status = set_command(cmd) @@ -418,7 +421,7 @@ function CheckErrorStatus(obj,status,FunctionName) %% If SHG output is required, a successive SHG temperature search may be required. % opt_stop Stop all optimizations. Usefull for full manual control of the C-Wave. %% Set Command - status = LibraryFunction(obj.LibraryName, obj.SetCommand,cmd); + status = obj.LibraryFunction(obj.SetCommand,cmd); end function [status,laser_power] = get_photodiode_laser(obj) @@ -432,7 +435,7 @@ function CheckErrorStatus(obj,status,FunctionName) else status = 0; end - obj.CheckErrorStatus(obj,status,obj.LaserPower) + obj.CheckErrorStatus(status,obj.LaserPower) end function [status,opo_power] = get_photodiode_opo(obj) @@ -446,7 +449,7 @@ function CheckErrorStatus(obj,status,FunctionName) else status = 0; end - obj.CheckErrorStatus(obj,status,obj.OPO_Power); + obj.CheckErrorStatus(status,obj.OPO_Power); end function [shg_power] = get_photodiode_shg(obj) @@ -460,7 +463,7 @@ function CheckErrorStatus(obj,status,FunctionName) else status = 0; end - obj.CheckErrorStatus(obj,status,obj.SHG_Power); + obj.CheckErrorStatus(status,obj.SHG_Power); end function status = get_statusbits(obj) @@ -497,7 +500,7 @@ function CheckErrorStatus(obj,status,FunctionName) else status = 0; end - obj.CheckErrorStatus(obj,status,obj.StatusReport) + obj.CheckErrorStatus(status,obj.StatusReport) end function WLM_PID_Compute(wl_measured) @@ -511,16 +514,16 @@ function WLM_PID_Compute(wl_measured) % provide fundamental or SHG measurement. However, measuring the fundamental % wavelength will be more reliable for complete automation. % Returns: none - LibraryFunction(obj.LibraryName,obj.WLM_PID_Optimize,wl_measured); % suggest change to callib + obj.LibraryFunction(obj.WLM_PID_Optimize,wl_measured); % suggest change to callib end function shutter_lsr(obj) %open or close internal pump laser shutter if strcmp(obj.lsr_shutter, obj.Open) - ret = set_intvalue(obj.ShutterLaser,1); + ret = obj.set_intvalue(obj.ShutterLaser,1); assert(ret == 1, 'Opening pump laser shutter failed'); elseif strcmp(obj.lsr_shutter, obj.Close) - ret = set_intvalue(obj.ShutterLaser,0); + ret = obj.set_intvalue(obj.ShutterLaser,0); assert(ret == 0, 'Closing pump laser shutter failed'); end end @@ -528,11 +531,11 @@ function shutter_lsr(obj) function shutter_shg(obj) %open or close SHG shutter if strcmp(obj.shg_shutter, obj.Open) - ret = set_intvalue(obj.ShutterSHG,1); + ret = obj.set_intvalue(obj.ShutterSHG,1); assert(ret == 1, 'Opening SHG shutter failed'); - elseif strcmp(shg.lsr_shutter, obj.Close) - ret = set_intvalue(obj.ShutterSHG,0); - assert(ret == 0, 'Closing SHG shutter failed'); + elseif strcmp(obj.shg_shutter, obj.Close) + ret = obj.set_intvalue(obj.ShutterSHG,0); + assert(ret == 1, 'Closing SHG shutter failed'); end end @@ -540,7 +543,7 @@ function shutter_shg(obj) % poll connection status if CWAVE % Function Call currently not avialable waiting DLL file info % from Hubner - status = obj.cwave_connect(ipAddr); + status = obj.cwave_connect(obj.ip); end function status = delete(obj) @@ -695,7 +698,7 @@ function initialize_shutters(obj) % Returns: Returns 0 if the reference temperature is stable. % Returns 1 if the reference temperature is not at setpoint. %% Poll temperature status - ref_temp_status = LibraryFunction(obj.LibraryName, obj.Reference_TempStatus); + ref_temp_status = obj.LibraryFunction(obj.Reference_TempStatus); end function [opo_temp_status] = get_status_temp_opo(obj) @@ -704,7 +707,7 @@ function initialize_shutters(obj) % Returns: Returns 0 if the OPO temperature is stable. % Returns 1 if the OPO temperature is not at setpoint. %% Poll OPO Temperature Status - opo_temp_status = LibraryFunction(obj.LibraryName, obj.OPO_TempStatus); + opo_temp_status = obj.LibraryFunction(obj.OPO_TempStatus); end function [shg_temp_status] = get_status_temp_shg(obj) @@ -713,7 +716,7 @@ function initialize_shutters(obj) % Returns: Returns 0 if the SHG temperature is stable. % Returns 1 if the SHG temperature is not at setpoint. %% Poll SHG temperature Status - shg_temp_status = LibraryFunction(obj.LibraryName, obj.SHG_TempStatus); + shg_temp_status = obj.LibraryFunction(obj.SHG_TempStatus); end function [opo_lock_status] = get_status_lock_opo(obj) @@ -722,7 +725,7 @@ function initialize_shutters(obj) % Returns: Returns 0 if the OPO is locked to the reference cavity and % produces stable output. Returns 1 if optimization is still in progress. %% Poll opo_lock_status...What exactly is the OPO lock? - opo_lock_status = LibraryFunction(obj.LibraryName, obj.OPO_LockStatus); + opo_lock_status = obj.LibraryFunction(obj.OPO_LockStatus); end function [shg_lock_status] = get_status_lock_shg(obj) @@ -730,14 +733,14 @@ function initialize_shutters(obj) % Arguments: none % Returns: Returns 0 if the SHG cavity is locked and produces stable output. % Returns 1 if optimization is still in progress. - shg_lock_status = LibraryFunction(obj.LibraryName, obj.SHG_LockStatus); + shg_lock_status = obj.LibraryFunction(obj.SHG_LockStatus); end function [etalon_lock_status] = get_status_lock_etalon(obj) % Description: Reads the current status of the etalon lock. % Arguments: none % Returns: Returns 0 if the etalon is locked. Returns 1 if optimization is still in progress. - etalon_lock_status = LibraryFunction(obj.LibraryName, obj.Etalon_LockStatus); + etalon_lock_status = obj.LibraryFunction(obj.Etalon_LockStatus); end end diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index 71d100c16..f4962d2fb 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -2,8 +2,10 @@ cwave = Drivers.CWave.instance('192.168.11.3'); +%{ disp('status:') disp(cwave.getStatus()) +%} disp('ref temp:') disp(cwave.get_status_temp_ref()) From efc552854db6845283c247be46eeb003528c734d Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 18 Jun 2019 14:12:48 -0400 Subject: [PATCH 09/71] more cwave fixes --- Modules/+Drivers/CWave.m | 16 ++++++++-------- Modules/+Drivers/cwave_testscript.m | 2 -- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 92efb162e..24a5b5b83 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -282,7 +282,7 @@ function CheckErrorStatus(obj,status,FunctionName) measure_status = LibraryFunction(obj.LibraryName,obj.UpdateStatus); end - function intvalue = get_intvalue(cmd) + function intvalue = get_intvalue(obj, cmd) %Description: Reads the value of an integer parameter. %Arguments: Parameter as string. See parameter list for valid parameters. %Returns: Returns the requested integer value. @@ -357,7 +357,7 @@ function CheckErrorStatus(obj,status,FunctionName) intvalue = calllib(obj.LibraryName,obj.Get_IntValue,cmd); end - function floatvalue = get_floatvalue(cmd) + function floatvalue = get_floatvalue(obj, cmd) %Description: Reads the value of an floating point parameter. %Arguments: Parameter as string. See parameter list for valid parameters. %Returns: Returns the requested floating point value. @@ -398,7 +398,7 @@ function CheckErrorStatus(obj,status,FunctionName) optimize_status = obj.LibraryFunction(obj.LibraryName, obj.Is_Ready); end - function status = set_floatvalue(cmd,value) + function status = set_floatvalue(obj, cmd,value) % Description: Sets the value of an floating point parameter. % Arguments: cmd is the Parameter as string. See parameter list % for valid parameters. value is the desired new value of the parameter. @@ -409,7 +409,7 @@ function CheckErrorStatus(obj,status,FunctionName) status = obj.LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); end - function status = set_command(cmd) + function status = set_command(obj, cmd) % Description: Executes a command which has no numerical argument. % Arguments: cmd is the command as string. See the command list for reference. % Returns: Returns 0 (1 before inversion) if the new command was executed correctly. Returns 1 (-1 before inversion) @@ -503,7 +503,7 @@ function CheckErrorStatus(obj,status,FunctionName) obj.CheckErrorStatus(status,obj.StatusReport) end - function WLM_PID_Compute(wl_measured) + function WLM_PID_Compute(obj, wl_measured) % Description: This function executes automatic wavelength regulation of the % C-Wave if the current output wavelength is measured by an external wavemeter % and monitored back into the C-Wave by this function. See WLM parameters for @@ -632,7 +632,7 @@ function coarse_tune(obj, measured_wavelength) %Piezo voltage is passed a a percentage of the total range %Total range is 0-65535 %Convert from percentage to integer - flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); + flag = obj.LibraryFunction(obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); if (flag == 1) piezo = piezo_percent; elseif (flag == -1) @@ -665,7 +665,7 @@ function initialize_shutters(obj) % Returns: Returns 1 if the new command was executed correctly. Returns -1 if an error occurred. %% external commands for WS8-10 High Finesse wavemeter %% set command for external module (i.e. the wavemeter) - status = LibraryFunction(obj.LibraryName,obj.Ext_SetCommand,cmd); + status = obj.LibraryFunction(obj.Ext_SetCommand,cmd); end function [ext_intvalue] = ext_get_intvalue(cmd) @@ -689,7 +689,7 @@ function initialize_shutters(obj) % Arguments: none % Returns: Returns 0 (1 before inversion) if the pump laser is active and the laser shutter is open. % Returns 1 (0 before inversion) if no or not sufficient laser power is available. - laser_status = LibraryFunction(obj.LibraryName,obj.LaserStatus); + laser_status = obj.LibraryFunction(obj.LaserStatus); end function [ref_temp_status] = get_status_temp_ref(obj) diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index f4962d2fb..d779cded0 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -1,5 +1,3 @@ -%import Modules.Drivers.CWave.* - cwave = Drivers.CWave.instance('192.168.11.3'); %{ From 8398fc8f52397fff3fc46f147f47d6ba778e5cfa Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 18 Jun 2019 14:13:19 -0400 Subject: [PATCH 10/71] fixes --- Modules/+Drivers/CWave.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 92efb162e..2baf2ab90 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -152,13 +152,13 @@ end end - function status = LibraryFunction(obj,FunctionName,varargin) + function [status,varargout] = LibraryFunction(obj,FunctionName,varargin) % use this function to call arbitrary library functions from % CWAVE DLL. Checks for error, and returns all bit status nargs = Base.libnargout(obj.LibraryName,FunctionName); if nargs < 2 - varargout = ''; + varargout = {}; status = calllib(obj.LibraryName,FunctionName,varargin{:}); else [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); @@ -610,7 +610,7 @@ function coarse_tune(obj, measured_wavelength) function piezo = get_ref_cavity_percent(obj) % returns reference cavity piezo percent value - piezo_voltage = obj.get_intvalue(x); + piezo_voltage = obj.get_intvalue('x'); piezo = piezo_voltage/obj.Piezo_maxBit; end From b07963261d8cbd89b7309ef64136a72c5583c24b Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 18 Jun 2019 15:32:12 -0400 Subject: [PATCH 11/71] fixed abort --- Modules/+Drivers/CWave.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 06dca799b..b788826e1 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -561,7 +561,7 @@ function shutter_shg(obj) function disconnect_cwave(obj) % Probably easiset if using a disconnect function to disconnect % CWAVE - LibraryFunction(obj.LibraryName,obj.Disconnect); + obj.LibraryFunction(obj.Disconnect); end function set_target_wavelength(obj) From e4155ce8da1c4cfefd8a84d8d3d448e522d62500 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 18 Jun 2019 15:32:50 -0400 Subject: [PATCH 12/71] testing --- Modules/+Drivers/CWave.m | 2 +- Modules/+Drivers/cwave_testscript.m | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 06dca799b..189b0d739 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -91,7 +91,6 @@ methods(Static) function obj = instance(ip) mlock; - obj.ip = ip persistent Objects if isempty(Objects) Objects = Drivers.CWave.empty(1,0); @@ -103,6 +102,7 @@ end end obj = Drivers.CWave(ip); + obj.ip = ip; obj.singleton_id = {ip}; Objects(end+1) = obj; end diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index d779cded0..9da930b7e 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -13,6 +13,9 @@ disp('opo temp:') disp(cwave.get_status_temp_opo()) +cwave.delete() + +cwave.abort_tune() disp('OPO lock:') disp(cwave.get_status_lock_opo()) From e24482db2677bd83f45c7ea647b2f3b2a849acce Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Wed, 19 Jun 2019 15:35:13 -0400 Subject: [PATCH 13/71] first test of cwave driver complete --- Modules/+Drivers/CWave.m | 12 ++++++++---- Modules/+Drivers/cwave_testscript.m | 22 +++++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 68a1102dc..427b36734 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -79,7 +79,7 @@ RefCavity_Piezo = 'x'; ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; ThickEtalon_Piezo = 'thicketa_rel'; - RefCavityPiezo_maxBit = 65535/100; + Piezo_maxBit = 65535/100; Laser_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) Laser_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) OPO_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) @@ -157,7 +157,11 @@ % CWAVE DLL. Checks for error, and returns all bit status nargs = Base.libnargout(obj.LibraryName,FunctionName); - if nargs < 2 + if nargs == 0 + varargout = {}; + status = []; + calllib(obj.LibraryName, FunctionName, varargin{:}); + elseif nargs < 2 varargout = {}; status = calllib(obj.LibraryName,FunctionName,varargin{:}); else @@ -395,7 +399,7 @@ function CheckErrorStatus(obj,status,FunctionName) %Arguments: none %Returns: Returns an integer value. 0 means no errors, C-Wave is ready. 1 means C-Wave is still in optimization %% Check if optimization is complete - optimize_status = obj.LibraryFunction(obj.LibraryName, obj.Is_Ready); + optimize_status = obj.LibraryFunction(obj.Is_Ready); end function status = set_floatvalue(obj, cmd,value) @@ -406,7 +410,7 @@ function CheckErrorStatus(obj,status,FunctionName) % Returns 1 (-1 before inversion) if an error occurred. %% Writable Int Parameters are listed above in get_floatvalue function comments %% Writable Wavelength stabilization parameters are listed above in get_floatvalue function comments - status = obj.LibraryFunction(obj.LibraryName, obj.Set_FloatValue,cmd, value); + status = obj.LibraryFunction(obj.Set_FloatValue,cmd, value); end function status = set_command(obj, cmd) diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index 9da930b7e..c0c0cf1c2 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -1,10 +1,12 @@ +clear CWave; +clc; + cwave = Drivers.CWave.instance('192.168.11.3'); %{ disp('status:') disp(cwave.getStatus()) %} - disp('ref temp:') disp(cwave.get_status_temp_ref()) @@ -13,15 +15,17 @@ disp('opo temp:') disp(cwave.get_status_temp_opo()) -cwave.delete() -cwave.abort_tune() +%failed status=1, 'optimization has not stopped' +%cwave.abort_tune() -disp('OPO lock:') -disp(cwave.get_status_lock_opo()) +%failed status=1, 'opo not locked, optimization still in progress' +%disp('OPO lock:') +%disp(cwave.get_status_lock_opo()) -disp('etalon lock:') -disp(cwave.get_status_lock_etalon()) +%failed status=1, 'etalon not locked, optimization still in progress' +%disp('etalon lock:') +%disp(cwave.get_status_lock_etalon()) disp('photodiode power:') disp(cwave.get_photodiode_laser()) @@ -32,8 +36,8 @@ disp('current piezo percent:') disp(cwave.get_ref_cavity_percent()) -cwave.target_wavelength = 615.000001 -cwave.set_wavelength() +cwave.target_wavelength = 615.000001; +cwave.set_target_wavelength() disp('new piezo percent:') disp(cwave.get_ref_cavity_percent()) From f3e75b07699122ed6dff45ca9bcd2e3259c3328e Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 20 Jun 2019 09:46:39 -0400 Subject: [PATCH 14/71] wavemeter and cwave tests --- Modules/+Drivers/CWave.m | 2 ++ Modules/+Drivers/cwave_testscript.m | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 427b36734..d9e50730c 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -489,6 +489,8 @@ function CheckErrorStatus(obj,status,FunctionName) % Poll cwave status cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib status_vector = de2bi(cwave_status); + disp('status_vector:') + disp(status_vector) obj.opo_stepper_stat = status_vector(1); obj.opo_temp_stat = status_vector(2); obj.shg_stepper_stat = status_vector(3); diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index c0c0cf1c2..72782cf84 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -2,11 +2,15 @@ clc; cwave = Drivers.CWave.instance('192.168.11.3'); +wavemeter = Drivers.Wavemeter.Wavemeter.instance('0.0.0.0') % IP address of wavemeter? + +disp('wavemeter:') +disp(wavemeter.getWavelength()) + -%{ disp('status:') -disp(cwave.getStatus()) -%} +disp(cwave.get_statusbits()) + disp('ref temp:') disp(cwave.get_status_temp_ref()) @@ -36,8 +40,8 @@ disp('current piezo percent:') disp(cwave.get_ref_cavity_percent()) -cwave.target_wavelength = 615.000001; -cwave.set_target_wavelength() +%cwave.target_wavelength = 615.000001; +%cwave.set_target_wavelength() disp('new piezo percent:') disp(cwave.get_ref_cavity_percent()) From bcc7a597cce2dcb04ae0fb41973f38b2c7fde6d4 Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 20 Jun 2019 09:49:58 -0400 Subject: [PATCH 15/71] debugging status function --- Modules/+Drivers/CWave.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index d9e50730c..3f15cefd6 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -488,6 +488,8 @@ function CheckErrorStatus(obj,status,FunctionName) % 9 Reference temperature % Poll cwave status cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib + disp('cwavestatus') + disp(cwave_status) status_vector = de2bi(cwave_status); disp('status_vector:') disp(status_vector) From af214c528beafce15f6695a64e102406b6b9dfad Mon Sep 17 00:00:00 2001 From: Emma Date: Thu, 20 Jun 2019 12:48:37 -0400 Subject: [PATCH 16/71] changed error check inversion logic --- Modules/+Drivers/CWave.m | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 3f15cefd6..1f3a3645f 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -176,7 +176,11 @@ function CheckErrorStatus(obj,status,FunctionName) inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) - status = ~status; + if status == 1: + status = 0 + else + status = 1 + end end switch FunctionName case obj.ConnectCwave @@ -476,23 +480,19 @@ function CheckErrorStatus(obj,status,FunctionName) % Returns: Returns an 16-bit integer value. Each bit corresponds to the % status of one component. 0 means, the component is ready for operation, % 1 means the component is not yet stable. Current valid bits from LSB to MSB are: - % 0 OPO stepper - % 1 OPO temperature - % 2 SHG stepper - % 3 SHG temperature - % 4 Thin etalon - % 5 OPO lock - % 6 SHG lock - % 7 Etalon lock - % 8 Laser emission (inverted) - % 9 Reference temperature + % 1 OPO stepper + % 2 OPO temperature + % 3 SHG stepper + % 4 SHG temperature + % 5 Thin etalon + % 6 OPO lock + % 7 SHG lock + % 8 Etalon lock + % 9 Laser emission (inverted) + % 10 Reference temperature % Poll cwave status cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib - disp('cwavestatus') - disp(cwave_status) status_vector = de2bi(cwave_status); - disp('status_vector:') - disp(status_vector) obj.opo_stepper_stat = status_vector(1); obj.opo_temp_stat = status_vector(2); obj.shg_stepper_stat = status_vector(3); @@ -503,7 +503,8 @@ function CheckErrorStatus(obj,status,FunctionName) obj.etalon_lock_stat = status_vector(8); obj.laser_emission_stat = ~status_vector(9); obj.ref_temp_stat = status_vector(10); - if(cwave_status ~=0) + if(~all(status_vector(1:10) == 0)) + % there is an 11th bit with no documented hw meaning; should be ignored status = 1; else status = 0; From 4f4ac5a8a7bfcda6c1d8c55d157c099b56be5010 Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 24 Jun 2019 15:01:28 -0400 Subject: [PATCH 17/71] added cwave singleton, starting wavemeter integration --- Modules/+Drivers/CWave.m | 19 ++++++------ Modules/+Sources/CWave.m | 46 +++++++++++++++++++++++------ Modules/+Sources/cwave_testscript.m | 8 +++++ 3 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 Modules/+Sources/cwave_testscript.m diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 1f3a3645f..761515edb 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -176,12 +176,9 @@ function CheckErrorStatus(obj,status,FunctionName) inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) - if status == 1: - status = 0 - else - status = 1 - end - end + disp('status') + disp(status) + status = ~status; switch FunctionName case obj.ConnectCwave % 0=connection failed, 1==connection successful @@ -593,22 +590,24 @@ function set_pid_target_wavelength(obj, setpoint) pause(1); end - function fine_tune(obj, measured_wavelength) + function set_target_deviation(obj, target_dev) + obj.set_intvalue(obj.WLM_targetdeviation, target_dev); + end + + function fine_tune(obj) % fine tune based on wavemeter measurement ret = obj.set_intvalue(WLM_PiezoSteps, 1); assert(ret == 1, 'Turning on cavity piezo during PID failed'); ret = obj.set_intvalue(WLM_etalonsteps, 0); assert(ret == 1, 'Turning off etalon steps during PID failed'); - obj.WLM_PID_Compute(measured_wavelength); end - function coarse_tune(obj, measured_wavelength) + function coarse_tune(obj) % coarse tune based on wavemeter measurement ret = obj.set_intvalue(WLM_PiezoSteps, 1); assert(ret == 1,'Turning on cavity piezo during PID failed'); ret = obj.set_intvalue(WLM_etalonsteps, 1); assert(ret == 1, 'Turning on etalon steps during PID failed'); - obj.WLM_PID_Compute(measured_wavelength); end function flag = abort_tune(obj) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 921f6fac4..5d1cf8ceb 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -35,6 +35,22 @@ no_server = 'No Server'; % Message when not connected end + methods(Access=private) + function obj = CWave() + obj.loadPrefs; + end + + methods(Static) + function obj = instance() + mlock; + persistent Object + if isempty(Object) || ~isvalid(Object) + Object = Sources.CWave(); + end + obj = Object; + end + end + methods % source methods @@ -53,21 +69,32 @@ function off(obj) % tunable laser methods - function tune(obj, setpoint, coarse) + function tune(obj, setpoint) + tuning = true; assert(~isempty(cwaveHandle), 'no cwave handle') - cwaveHandle.set_pid_target_wavelength(setpoint); - wavelength = wavemeter.getWavelength(); - if coarse - cwaveHandle.coarse_tune(wavelength); - else - cwaveHandle.fine_tune(wavelength); + target_dev = 0.5; + measured_wavelength = wavemeter.getWavelength(); + mid_setpoint = measured_wavelength; + while round(target_dev, 5) > 0 + while abs(mid_setpoint - setpoint) > 2*target_dev + mid_setpoint = mid_setpoint + 2*target_dev; + cwave.set_target_deviation(target_dev); + cwaveHandle.set_pid_target_wavelength(mid_setpoint); + while abs(measured_wavelength - mid_setpoint) > target_dev + cwave.WLM_PID_Compute(measured_wavelength); + pause(0.001); + end + end + target_dev = target_dev/10; end + tuning = false; end function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in nm - obj.tune(setpoint, false); + cwaveHandle.fine_tune(); + obj.tune(setpoint); end function TuneCoarse(obj, setpoint) @@ -81,7 +108,8 @@ function TuneCoarse(obj, setpoint) % the cavity piezo. % % setpoint = setpoint in nm - obj.tune(setpoint, true); + cwaveHandle.coarse_tune(); + obj.tune(setpoint); end function TunePercent(obj, percent) diff --git a/Modules/+Sources/cwave_testscript.m b/Modules/+Sources/cwave_testscript.m new file mode 100644 index 000000000..f6a9b707a --- /dev/null +++ b/Modules/+Sources/cwave_testscript.m @@ -0,0 +1,8 @@ +cwave = Sources.CWave.instance() + +cwave.cwave_ip('192.168.11.3'); +cwave.wavemeter_ip('0.0.0.0'); + +cwave.wavemeter_channel(1); + +disp(cwave.GetPercent()) \ No newline at end of file From 501051654347162f60033a51aedbd51a7fce9b31 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 24 Jun 2019 16:34:08 -0400 Subject: [PATCH 18/71] cwave driver --- Modules/+Drivers/CWave.m | 10 +++++----- Modules/+Drivers/cwave_testscript.m | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 1f3a3645f..30b7c18a3 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -176,11 +176,11 @@ function CheckErrorStatus(obj,status,FunctionName) inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) - if status == 1: - status = 0 - else - status = 1 - end + disp('pre inversion') + disp(FunctionName) + disp('status') + disp(status) + status = ~status; end switch FunctionName case obj.ConnectCwave diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m index 72782cf84..18e495ef7 100644 --- a/Modules/+Drivers/cwave_testscript.m +++ b/Modules/+Drivers/cwave_testscript.m @@ -2,14 +2,17 @@ clc; cwave = Drivers.CWave.instance('192.168.11.3'); -wavemeter = Drivers.Wavemeter.Wavemeter.instance('0.0.0.0') % IP address of wavemeter? +wavemeter = Drivers.Wavemeter.instance('0.0.0.0', 1, 1); % IP address of wavemeter? disp('wavemeter:') disp(wavemeter.getWavelength()) +%cwave.abort_tune() + +%disp(cwave.get_status_temp_ref()) -disp('status:') -disp(cwave.get_statusbits()) +%disp('status:') +%disp(cwave.get_statusbits()) disp('ref temp:') disp(cwave.get_status_temp_ref()) @@ -21,7 +24,7 @@ disp(cwave.get_status_temp_opo()) %failed status=1, 'optimization has not stopped' -%cwave.abort_tune() +cwave.abort_tune() %failed status=1, 'opo not locked, optimization still in progress' %disp('OPO lock:') From 8e3ea39e7c6ed220f479fe1793c53b547a9d3f6e Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 24 Jun 2019 16:53:57 -0400 Subject: [PATCH 19/71] made cwave source compatible with TunableLaser --- Modules/+Sources/CWave.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 5d1cf8ceb..898cbc8b9 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -23,6 +23,11 @@ pulseStreamer_ip = Sources.CWave.no_server; wavemeter_ip = Sources.CWave.no_server; wavemeter_channel = 1; % set to integer value + % TODO fill in prefs all the way + show_prefs = {'tuning', 'cwave_ip', 'pulseStreamer_ip', 'wavemeter_ip'}; + readonly_prefs = {'tuning'}; + % TODO I have no idea what the cwave's range is + range = Sources.TunableLaser_invisible.c/[300, 1000] end properties(SetAccess=private) @@ -125,6 +130,11 @@ function TunePercent(obj, percent) piezo = cwaveHandle.get_ref_cavity_percent(); end + function freq = getFrequency(obj) + wavelength = wavemeter.getWavelength(); + freq = Sources.TunableLaser_invisible.c/wavelength + end + % set methods function set.cwave_ip(obj,ip) From 4267c11b8afde91dc816b25b81bb548e6c6a5294 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 24 Jun 2019 16:54:33 -0400 Subject: [PATCH 20/71] debugging --- Modules/+Sources/CWave.m | 6 ++++-- Modules/+Sources/ConnectableMixin_invisible.m | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 5d1cf8ceb..3ad4d1d3d 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -13,7 +13,6 @@ properties(SetObservable,SetAccess=private) source_on = false; - locked = false; end properties(SetObservable,AbortSet) @@ -38,6 +37,7 @@ methods(Access=private) function obj = CWave() obj.loadPrefs; + end end methods(Static) @@ -161,4 +161,6 @@ function TunePercent(obj, percent) if ~isempty(err) rethrow(err) end - end \ No newline at end of file + end + end +end \ No newline at end of file diff --git a/Modules/+Sources/ConnectableMixin_invisible.m b/Modules/+Sources/ConnectableMixin_invisible.m index ef5449b1d..c1e4a20a2 100644 --- a/Modules/+Sources/ConnectableMixin_invisible.m +++ b/Modules/+Sources/ConnectableMixin_invisible.m @@ -1,5 +1,5 @@ -classdef(Abstract) ConnectableMixin - methods(Acces=private) +classdef(Abstract) ConnectableMixin_invisible < handle + methods(Access=private) function err = connect_driver(obj,propname,drivername,varargin) err = []; if ~isempty(obj.(propname)) From 598e058732d42a5fefa780f38e8e147a79f5de3c Mon Sep 17 00:00:00 2001 From: Emma Date: Mon, 24 Jun 2019 16:56:39 -0400 Subject: [PATCH 21/71] changed cwave range permissions --- Modules/+Sources/CWave.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 913f6c84a..c091d9bad 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -15,6 +15,10 @@ source_on = false; end + properties(SetAccess=protected) + range = Sources.TunableLaser_invisible.c/[300, 1000] + end + properties(SetObservable,AbortSet) resonator_percent = 0; tuning = false; @@ -26,7 +30,6 @@ show_prefs = {'tuning', 'cwave_ip', 'pulseStreamer_ip', 'wavemeter_ip'}; readonly_prefs = {'tuning'}; % TODO I have no idea what the cwave's range is - range = Sources.TunableLaser_invisible.c/[300, 1000] end properties(SetAccess=private) From 584636adca70e7152e751d4840dab0a8c06c05dc Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 25 Jun 2019 08:53:48 -0400 Subject: [PATCH 22/71] debuggin cwave source --- +Base/Module.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/+Base/Module.m b/+Base/Module.m index f44e16a4d..3042263c8 100644 --- a/+Base/Module.m +++ b/+Base/Module.m @@ -208,7 +208,9 @@ function loadPrefs(obj) end end end + disp('for loop successful') end + disp('function returning') end function delete(obj) obj.savePrefs; From 5a4feb87414f3c0aaeac1539f3e11e2da50c3f33 Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 25 Jun 2019 08:56:54 -0400 Subject: [PATCH 23/71] more debugging cwave source --- +Base/Module.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/+Base/Module.m b/+Base/Module.m index 3042263c8..bf1901f21 100644 --- a/+Base/Module.m +++ b/+Base/Module.m @@ -184,7 +184,10 @@ function loadPrefs(obj) assert(ischar(obj.namespace),'Namespace must be a string!') if isprop(obj,'prefs') assert(iscell(obj.prefs),'Property "prefs" must be a cell array') + disp('number of prefs:') + disp(numel(obj.prefs)) for i = 1:numel(obj.prefs) + disp(i) if ~ischar(obj.prefs{i}) warning('MODULE:load_prefs','Error on loadPrefs (position %i): %s',i,'Must be a string!') continue @@ -197,7 +200,10 @@ function loadPrefs(obj) if isempty(pref)% Means it is the default value, and not set continue end + disp('length of prefs:') + disp(length(pref)) for j = 1:length(pref) + disp(j) temp(j) = eval(sprintf('%s.instance',pref{j})); % Grab instance(s) from string end pref = temp; From 836544f5f33d686a99f7e1878c378e9765a6f88b Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 25 Jun 2019 09:01:02 -0400 Subject: [PATCH 24/71] more debugging cwave source --- +Base/Module.m | 8 -------- Modules/+Sources/CWave.m | 5 ++++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/+Base/Module.m b/+Base/Module.m index bf1901f21..f44e16a4d 100644 --- a/+Base/Module.m +++ b/+Base/Module.m @@ -184,10 +184,7 @@ function loadPrefs(obj) assert(ischar(obj.namespace),'Namespace must be a string!') if isprop(obj,'prefs') assert(iscell(obj.prefs),'Property "prefs" must be a cell array') - disp('number of prefs:') - disp(numel(obj.prefs)) for i = 1:numel(obj.prefs) - disp(i) if ~ischar(obj.prefs{i}) warning('MODULE:load_prefs','Error on loadPrefs (position %i): %s',i,'Must be a string!') continue @@ -200,10 +197,7 @@ function loadPrefs(obj) if isempty(pref)% Means it is the default value, and not set continue end - disp('length of prefs:') - disp(length(pref)) for j = 1:length(pref) - disp(j) temp(j) = eval(sprintf('%s.instance',pref{j})); % Grab instance(s) from string end pref = temp; @@ -214,9 +208,7 @@ function loadPrefs(obj) end end end - disp('for loop successful') end - disp('function returning') end function delete(obj) obj.savePrefs; diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index c091d9bad..a8f290541 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,6 +16,7 @@ end properties(SetAccess=protected) + % TODO I have no idea what the cwave's range is range = Sources.TunableLaser_invisible.c/[300, 1000] end @@ -29,7 +30,6 @@ % TODO fill in prefs all the way show_prefs = {'tuning', 'cwave_ip', 'pulseStreamer_ip', 'wavemeter_ip'}; readonly_prefs = {'tuning'}; - % TODO I have no idea what the cwave's range is end properties(SetAccess=private) @@ -54,8 +54,11 @@ persistent Object if isempty(Object) || ~isvalid(Object) Object = Sources.CWave(); + disp('instantiated cwave') end + disp('assigning Object') obj = Object; + disp('function returning') end end From 7363cc1b202c56b5a8ad25a478d7695efd21d0e1 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 25 Jun 2019 09:05:44 -0400 Subject: [PATCH 25/71] debugging --- Modules/+Sources/CWave.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index c091d9bad..af6905c86 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,7 +16,7 @@ end properties(SetAccess=protected) - range = Sources.TunableLaser_invisible.c/[300, 1000] + range = Sources.TunableLaser_invisible.c./[300, 1000]; end properties(SetObservable,AbortSet) From a5cbb3d316def94907eb873a3a292779d74cfe80 Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 25 Jun 2019 09:33:24 -0400 Subject: [PATCH 26/71] debugging cwave --- Modules/+Sources/CWave.m | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 21c9d9313..936704c30 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -1,4 +1,4 @@ -classdef CWave < Modules.Source & Sources.TunableLaser_invisible & Sources.ConnectableMixin_invisible +classdef CWave < Modules.Source & Sources.TunableLaser_invisible %Cwave controls all aspects of the cwave laser which powers AOM % and the PulseStreamer which triggers AOM % @@ -46,6 +46,22 @@ function obj = CWave() obj.loadPrefs; end + + function err = connect_driver(obj,propname,drivername,varargin) + err = []; + if ~isempty(obj.(propname)) + delete(obj.(propname)); %remove any old connection + end + if ischar(varargin{1}) && strcmpi(varargin{1},'No Server') %first input is always an ip address + obj.(propname) = []; + else + try + obj.(propname) = Drivers.(drivername).instance(varargin{:}); + catch err + obj.(propname) = []; + end + end + end end methods(Static) From a04598d162eb77b0390978fb25579f2be893f4db Mon Sep 17 00:00:00 2001 From: Emma Batson Date: Tue, 25 Jun 2019 10:36:34 -0400 Subject: [PATCH 27/71] cwave source has basic functionality --- Modules/+Sources/CWave.m | 23 ++++++++++------------- Modules/+Sources/cwave_testscript.m | 3 ++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 936704c30..12ff47ccb 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -70,11 +70,8 @@ persistent Object if isempty(Object) || ~isvalid(Object) Object = Sources.CWave(); - disp('instantiated cwave') end - disp('assigning Object') obj = Object; - disp('function returning') end end @@ -135,7 +132,7 @@ function TuneCoarse(obj, setpoint) % the cavity piezo. % % setpoint = setpoint in nm - cwaveHandle.coarse_tune(); + obj.cwaveHandle.coarse_tune(); obj.tune(setpoint); end @@ -145,22 +142,22 @@ function TunePercent(obj, percent) % percent = desired piezo percentage from 1 to 100 assert(~isempty(obj.cwaveHandle)&&isobject(obj.cwaveHandle) && isvalid(obj.cwaveHandle),'no cwave handle') assert(percent>=0 && percent<=100,'Target must be a percentage') - obj.resonator_percent = obj.cwaveHandle.tune_ref_cavity(percent) + obj.resonator_percent = obj.cwaveHandle.tune_ref_cavity(percent); end function piezo = GetPercent(obj) - piezo = cwaveHandle.get_ref_cavity_percent(); + piezo = obj.cwaveHandle.get_ref_cavity_percent(); end function freq = getFrequency(obj) - wavelength = wavemeter.getWavelength(); - freq = Sources.TunableLaser_invisible.c/wavelength + wavelength = obj.wavemeter.getWavelength(); + freq = Sources.TunableLaser_invisible.c/wavelength; end % set methods function set.cwave_ip(obj,ip) - err = obj.connect_driver('cwaveHandle', cwave, ip); + err = obj.connect_driver('cwaveHandle', 'CWave', ip); if ~isempty(err) obj.cwave_ip = obj.no_server; rethrow(err) @@ -174,21 +171,21 @@ function TunePercent(obj, percent) obj.pulseStreamer_ip = obj.no_server; rethrow(err) end - pulseStreamer_ip = ip; + obj.pulseStreamer_ip = ip; end function set.wavemeter_ip(obj, ip) - err = obj.connect_driver('Wavemeter', Wavemeter.Wavemeter, ip, obj.wavemeter_channel); + err = obj.connect_driver('wavemeter', 'Wavemeter', ip, obj.wavemeter_channel); if ~isempty(err) obj.wavemeter_ip = obj.no_server; rethrow(err) end - wavemeter_ip = ip; + obj.wavemeter_ip = ip; end function set.wavemeter_channel(obj, channel) assert(round(channel)==channel&&channel>0,'wavemeter_channel must be an integer greater than 0.') - obj.wavemeter_channel = channel + obj.wavemeter_channel = channel; err = obj.connect_driver('wavemeter','Wavemeter',obj.wavemeter_ip,val); if ~isempty(err) rethrow(err) diff --git a/Modules/+Sources/cwave_testscript.m b/Modules/+Sources/cwave_testscript.m index 6e790d3b1..1a986ee5c 100644 --- a/Modules/+Sources/cwave_testscript.m +++ b/Modules/+Sources/cwave_testscript.m @@ -5,4 +5,5 @@ cwave.wavemeter_channel(1); -disp(cwave.GetPercent()) \ No newline at end of file +disp(cwave.GetPercent()) +disp(cwave.getFrequency()) \ No newline at end of file From 9920794de452539b40bad60daa7d5424b4290304 Mon Sep 17 00:00:00 2001 From: Emma Batson Date: Fri, 28 Jun 2019 16:58:23 -0400 Subject: [PATCH 28/71] TunePercent functions --- Modules/+Drivers/CWave.m | 6 +++--- Modules/+Sources/CWave.m | 12 ++++++------ Modules/+Sources/cwave_testscript.m | 9 ++++++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 9dc436b4e..7dc23fbbc 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -625,13 +625,13 @@ function coarse_tune(obj) %Piezo voltage is passed a a percentage of the total range %Total range is 0-65535 %Convert from percentage to integer - peizo_voltage = round(piezo_percent*obj.Piezo_maxBit); + piezo_voltage = round(piezo_percent*obj.Piezo_maxBit); - flag = LibraryFunction(obj.LibraryName,obj.Set_IntValue,obj.RefCavity_Piezo,peizo_voltage); + flag = obj.LibraryFunction(obj.Set_IntValue,obj.RefCavity_Piezo,piezo_voltage); if (flag == 1) piezo = piezo_percent; elseif (flag == -1) - piezo = get_ref_cavity_percent(); + piezo = obj.get_ref_cavity_percent(); end end diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 12ff47ccb..ea8a1412c 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -94,16 +94,16 @@ function off(obj) % tunable laser methods function tune(obj, setpoint) - tuning = true; - assert(~isempty(cwaveHandle), 'no cwave handle') + obj.tuning = true; + assert(~isempty(obj.cwaveHandle), 'no cwave handle') target_dev = 0.5; - measured_wavelength = wavemeter.getWavelength(); + measured_wavelength = obj.wavemeter.getWavelength(); mid_setpoint = measured_wavelength; while round(target_dev, 5) > 0 while abs(mid_setpoint - setpoint) > 2*target_dev mid_setpoint = mid_setpoint + 2*target_dev; cwave.set_target_deviation(target_dev); - cwaveHandle.set_pid_target_wavelength(mid_setpoint); + obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); while abs(measured_wavelength - mid_setpoint) > target_dev cwave.WLM_PID_Compute(measured_wavelength); pause(0.001); @@ -111,13 +111,13 @@ function tune(obj, setpoint) end target_dev = target_dev/10; end - tuning = false; + obj.tuning = false; end function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in nm - cwaveHandle.fine_tune(); + obj.cwaveHandle.fine_tune(); obj.tune(setpoint); end diff --git a/Modules/+Sources/cwave_testscript.m b/Modules/+Sources/cwave_testscript.m index 1a986ee5c..f9754ee45 100644 --- a/Modules/+Sources/cwave_testscript.m +++ b/Modules/+Sources/cwave_testscript.m @@ -5,5 +5,12 @@ cwave.wavemeter_channel(1); +disp('starting vals') disp(cwave.GetPercent()) -disp(cwave.getFrequency()) \ No newline at end of file +%disp(cwave.getFrequency()) + +cwave.TunePercent(10) + +disp('after tunepercent to 10') +disp(cwave.GetPercent()) +%disp(cwave.getFrequency()) \ No newline at end of file From 4f3faa22db27f7b8fb94d6c9aa1715ac4de3a4e4 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 30 Sep 2019 11:00:20 -0400 Subject: [PATCH 29/71] On/Off function added to Cwave source --- Modules/+Sources/CWave.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index ea8a1412c..ecb7a0682 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -30,6 +30,7 @@ % TODO fill in prefs all the way show_prefs = {'tuning', 'cwave_ip', 'pulseStreamer_ip', 'wavemeter_ip'}; readonly_prefs = {'tuning'}; + PSline = 1; % Index from 1 (Pulsestreamer has 8 digital out channels) end properties(SetAccess=private) @@ -82,6 +83,7 @@ function on(obj) assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') % TODO say something to PulseStreamer + obj.PulseStreamer.constant([obj.PSline],0,0) obj.source_on = true; end @@ -89,6 +91,7 @@ function off(obj) assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') % TODO say something to PulseStreamer obj.source_on = false; + obj.PulseStreamer.constant([],0,0) end % tunable laser methods From c5ba5af22daa404758b777c32fdcca74cb3dae01 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 30 Sep 2019 13:37:45 -0400 Subject: [PATCH 30/71] debugged status functions for CWave driver --- Modules/+Drivers/CWave.m | 58 +++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 7dc23fbbc..7d2b1ed7e 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -13,9 +13,9 @@ dll_ver ip status - target_wavelength = 615.000001; % Target Wavelength + target_wavelength = 0; % Target Wavelength all_shutters = 'open'; - shg_shutter = 'close'; + shg_shutter = 'open'; lsr_shutter = 'open'; opo_stepper_stat = 0; opo_temp_stat = false(1); @@ -52,6 +52,7 @@ SetCommand = 'set_command'; LaserPower = 'get_photodiode_laser'; OPO_Power = 'get_photodiode_opo'; + OptimizeSHG = 'opt_tempshg'; SHG_Power = 'get_photodiode_shg'; StatusReport = 'get_statusbits'; LaserStatus = 'get_status_laser'; @@ -64,10 +65,12 @@ WLM_PID_Optimize = 'WLM_PID_Compute'; WLM_PID_Setpoint = 'WLM_pid_setpoint'; % valid range 450 - 1300 (nm), double WLM_BigSteps = 'WLM_bigsteps'; + WLM_EtalonSteps = 'WLM_etalonsteps'; WLM_PiezoSteps = 'WLM_piezosteps' Ext_SetCommand = 'ext_set_command'; ExtGet_IntValue = 'ext_get_intvalue'; ExtGet_FloatValue = 'ext_get_floatvalue'; + RelockEtalon = 'reg_etacatch'; ShutterSHG = 'shtter_shg'; ShutterLaser = 'shtter_las'; Open = 'open'; @@ -113,9 +116,10 @@ function obj = CWave(ip) obj.dll_ver = load_cwave_dll(obj); %load dll for cwave obj.status = obj.cwave_connect(ip); %connect cwave + pause(1); % open all internal and output shutters in cwave system - obj.shutter_lsr(); - obj.shutter_shg(); + %obj.shutter_lsr(); + %obj.shutter_shg(); %obj.initialize_shutters; %ret = obj.set_intvalue(obj.WLM_BigSteps, 0); %assert(ret == 1, 'Turning off large steps in PID failed'); @@ -170,18 +174,21 @@ obj.CheckErrorStatus(status, FunctionName); end - function CheckErrorStatus(obj,status,FunctionName) + function status = CheckErrorStatus(obj,status,FunctionName) %edit cases TBD. Need to sort out string to report and %flag/status for each function inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) + if(status==-1) + status = 0; + end status = ~status; end switch FunctionName case obj.ConnectCwave % 0=connection failed, 1==connection successful - assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed']); + assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed. Disconnect Cwave from Hubner software.']); case obj.DLL_Version assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); case obj.Admin @@ -242,7 +249,7 @@ function CheckErrorStatus(obj,status,FunctionName) end end - function [status] = cwave_connect(obj, ip) + function status = cwave_connect(obj, ip) %Description: Connects to the C-Wave. This function has to be executed once during runtime. %Arguments: ipAddress is the IP address of the CWAVE as string in the format 123.123.123.123 %Returns: int value, 0 means connection failed, 1 means successfully connected. @@ -251,7 +258,7 @@ function CheckErrorStatus(obj,status,FunctionName) status = obj.LibraryFunction(obj.ConnectCwave, ip); % mitigate bug in DLL, first connection attempt might fail -> retry if (status == 0) - status = LibraryFunction(obj.ConnectCwave, ip); + status = obj.LibraryFunction(obj.ConnectCwave, ip); end end @@ -456,13 +463,13 @@ function CheckErrorStatus(obj,status,FunctionName) obj.CheckErrorStatus(status,obj.OPO_Power); end - function [shg_power] = get_photodiode_shg(obj) + function [status, shg_power] = get_photodiode_shg(obj) % Description: Reads the current (second harmonic generator) SHG visible power % Arguments: none % Returns: Returns the visible output power in mW %% Read SHG power shg_power = calllib(obj.LibraryName, obj.SHG_Power); - if (shg_power > obj.SHG_MaxPower || opo_power < obj.OPO_MinPower) + if (shg_power > obj.SHG_MaxPower || shg_power < obj.SHG_MinPower) status = 1; else status = 0; @@ -551,16 +558,37 @@ function shutter_shg(obj) status = obj.cwave_connect(obj.ip); end - function status = delete(obj) + function delete(obj) %Delete instance of CWAVE object. %Disconnect CWAVE obj.disconnect_cwave(); + + %clear public properties + obj.init_warnings = []; + obj.dll_ver = []; + obj.ip = []; + obj.status = []; + obj.target_wavelength = []; % Target Wavelength + obj.all_shutters = []; + obj.shg_shutter = []; + obj.lsr_shutter = []; + obj.opo_stepper_stat = []; + obj.opo_temp_stat = []; + obj.shg_stepper_stat = []; + obj.shg_temp_stat = []; + obj.thin_etalon_stat = []; + obj.opo_lock_stat = []; + obj.shg_lock_stat = []; + obj.etalon_lock_stat = []; + obj.laser_emission_stat = []; + obj.ref_temp_stat = []; + %clean up loaded library from memory unloadlibrary(obj.LibraryName); - status = libisloaded(obj.LibraryName); - if status - assert(status==1, 'CWAVE Library still in memory!'); - end + %status = libisloaded(obj.LibraryName); + %if status + % assert(status==1, 'CWAVE Library still in memory!'); + %end end function disconnect_cwave(obj) From ee1c59888cd68e2a03be24980130b9e51d28fd80 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 30 Sep 2019 14:24:16 -0400 Subject: [PATCH 31/71] debugged tuning functions --- Modules/+Drivers/CWave.m | 90 +++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 7d2b1ed7e..64cae6c27 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -116,8 +116,8 @@ function obj = CWave(ip) obj.dll_ver = load_cwave_dll(obj); %load dll for cwave obj.status = obj.cwave_connect(ip); %connect cwave - pause(1); - % open all internal and output shutters in cwave system + pause(1) + %open all internal and output shutters in cwave system %obj.shutter_lsr(); %obj.shutter_shg(); %obj.initialize_shutters; @@ -171,7 +171,7 @@ else [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); end - obj.CheckErrorStatus(status, FunctionName); + status = obj.CheckErrorStatus(status, FunctionName); end function status = CheckErrorStatus(obj,status,FunctionName) @@ -187,13 +187,13 @@ end switch FunctionName case obj.ConnectCwave - % 0=connection failed, 1==connection successful - assert(status == 0, ['CWAVE Error: Connecting to ' obj.ip ' failed. Disconnect Cwave from Hubner software.']); + % 0=connection successful, 1==connection failed + assert(status ==0, ['CWAVE Error: Connecting to ' obj.ip ' failed. Disconnect Cwave from Hubner software.']); case obj.DLL_Version assert(status == 0, ['CWAVE Error: Unauthorized CWAVE DLL version loaded']); case obj.Admin % 0==admin rights granted, 1=no admin rights granted - assert(status == 0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); + assert(status ==0, ['CWAVE Error: Admin Rights Not Granted. Incorrect password given']); case obj.UpdateStatus % 0==update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); @@ -587,7 +587,7 @@ function delete(obj) unloadlibrary(obj.LibraryName); %status = libisloaded(obj.LibraryName); %if status - % assert(status==1, 'CWAVE Library still in memory!'); + % assert(status==0, 'CWAVE Library still in memory!'); %end end @@ -608,9 +608,10 @@ function set_target_wavelength(obj) function set_pid_target_wavelength(obj, setpoint) % set the target wavelength to fine tune toward - typecheck = isa(setpoint, 'double') - assert(typecheck == 1, 'Setpoint must be double precision float') - ret = obj.set_intvalue(WLM_PID_Setpoint, setpoint); + typecheck = isa(setpoint, 'double'); + assert(typecheck == 1, 'Setpoint must be double precision float'); + + ret = obj.set_floatvalue(obj.WLM_PID_Setpoint, setpoint); assert(ret == 1, 'Setting setpoint wavelength failed'); disp(['Setpoint wavelength set: ' num2str(setpoint) 'nm']); % IMPORTANT: wait one second before starting to poll for ready @@ -618,34 +619,46 @@ function set_pid_target_wavelength(obj, setpoint) end function set_target_deviation(obj, target_dev) - obj.set_intvalue(obj.WLM_targetdeviation, target_dev); + obj.set_floatvalue(obj.WLM_targetdeviation, target_dev); end function fine_tune(obj) % fine tune based on wavemeter measurement - ret = obj.set_intvalue(WLM_PiezoSteps, 1); + ret = obj.set_intvalue(obj.WLM_PiezoSteps, 1); assert(ret == 1, 'Turning on cavity piezo during PID failed'); - ret = obj.set_intvalue(WLM_etalonsteps, 0); + % turn off etalon control + ret = obj.set_intvalue(obj.WLM_EtalonSteps, 0); assert(ret == 1, 'Turning off etalon steps during PID failed'); + %turn off big wavelength steps (OPO and SHG remain locked) + ret = obj.set_intvalue(obj.WLM_BigSteps, 0); + assert(ret == 1, 'Turning off big wavelength steps during PID failed'); end function coarse_tune(obj) % coarse tune based on wavemeter measurement - ret = obj.set_intvalue(WLM_PiezoSteps, 1); + % turn on reference cavity steps + ret = obj.set_intvalue(obj.WLM_PiezoSteps, 1); assert(ret == 1,'Turning on cavity piezo during PID failed'); - ret = obj.set_intvalue(WLM_etalonsteps, 1); + %turn on etalon steps + ret = obj.set_intvalue(obj.WLM_EtalonSteps, 1); assert(ret == 1, 'Turning on etalon steps during PID failed'); + %turn off big wavelength steps (OPO and SHG remain locked) + ret = obj.set_intvalue(obj.WLM_BigSteps, 0); + assert(ret == 1, 'Turning off big wavelength steps during PID failed'); end function flag = abort_tune(obj) + %currently the StopOptimization parameter is not recognized by + %the set_command function. Needs correction on Hubner's end %Stops optimization of wavelength tuning. flag = obj.set_command(obj.StopOptimization); - assert(flag==1, 'Optimization has not stopped'); + %assert(flag==1, 'Optimization has not stopped'); + %StopOptimization = 'opt_stop'; end function piezo = get_ref_cavity_percent(obj) % returns reference cavity piezo percent value - piezo_voltage = obj.get_intvalue('x'); + piezo_voltage = obj.get_intvalue(obj.RefCavity_Piezo); piezo = piezo_voltage/obj.Piezo_maxBit; end @@ -655,25 +668,34 @@ function coarse_tune(obj) %Convert from percentage to integer piezo_voltage = round(piezo_percent*obj.Piezo_maxBit); - flag = obj.LibraryFunction(obj.Set_IntValue,obj.RefCavity_Piezo,piezo_voltage); - if (flag == 1) - piezo = piezo_percent; - elseif (flag == -1) - piezo = obj.get_ref_cavity_percent(); - end + flag = obj.set_intvalue(obj.RefCavity_Piezo,piezo_voltage); + assert(flag ==0, 'Reference cavity not tuned.') + + piezo = obj.get_ref_cavity_percent(); + end + + function tune_thick_etalon(obj,relative_wl_pm) + %execute relative wavelength step of thick etalon in pm. + %Total range is -1000 to 1000 pm (type int) + + flag = obj.set_intvalue(obj.ThickEtalon_Piezo_hr,relative_wl_pm); + assert(flag==0, 'Relative tuning of etalon failed.'); + end + + function optimize_shg(obj) + %currently the OptimizeSHG parameter is not recognized by + %the set_command function. Needs correction on Hubner's end + flag = obj.set_command(obj.OptimizeSHG); + assert(flag == 0, 'SHG optimization failed.'); + end + + function relock_etalon(obj) + %currently the RelockEtalon parameter is not recognized by + %the set_command function. Needs correction on Hubner's end + flag = obj.set_command(obj.RelockEtalon); + assert(flag == 0, 'Etalon failed to relock.'); end - function piezo = tune_thick_etalon(obj,relative_wl_pm) - %Piezo voltage is passed a a percentage of the total range - %Total range is 0-65535 - %Convert from percentage to integer - flag = obj.LibraryFunction(obj.Set_IntValue,obj.ThickEtalon_Piezo_hr,relative_wl_pm); - if (flag == 1) - piezo = piezo_percent; - elseif (flag == -1) - piezo = get_ref_cavity_percent(); - end - end end %Methods I will likey never use From a188075098a1cebd9c62e0b5763e4500010a8481 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 7 Oct 2019 11:45:48 -0400 Subject: [PATCH 32/71] Corrected error flags in set_pid_target_wavelength --- Modules/+Drivers/CWave.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 64cae6c27..5f223e4c5 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -66,7 +66,8 @@ WLM_PID_Setpoint = 'WLM_pid_setpoint'; % valid range 450 - 1300 (nm), double WLM_BigSteps = 'WLM_bigsteps'; WLM_EtalonSteps = 'WLM_etalonsteps'; - WLM_PiezoSteps = 'WLM_piezosteps' + WLM_PiezoSteps = 'WLM_piezosteps'; + WLM_targetdeviation = 'WLM_targetdeviation'; Ext_SetCommand = 'ext_set_command'; ExtGet_IntValue = 'ext_get_intvalue'; ExtGet_FloatValue = 'ext_get_floatvalue'; @@ -612,7 +613,7 @@ function set_pid_target_wavelength(obj, setpoint) assert(typecheck == 1, 'Setpoint must be double precision float'); ret = obj.set_floatvalue(obj.WLM_PID_Setpoint, setpoint); - assert(ret == 1, 'Setting setpoint wavelength failed'); + assert(ret == 0, 'Setting setpoint wavelength failed'); disp(['Setpoint wavelength set: ' num2str(setpoint) 'nm']); % IMPORTANT: wait one second before starting to poll for ready pause(1); From ff06fae29fd01497fb5dca4bc80c034f02851a4c Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Tue, 8 Oct 2019 13:41:59 -0400 Subject: [PATCH 33/71] added running property --- .../+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index 14f795853..99128c6d5 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -78,7 +78,6 @@ PS; % builder; %PusleSequenceBuilder object used to build pulse sequences. - triggerStart; triggerMode; % string containing pulse sequence instruction set in JSON format @@ -95,7 +94,11 @@ seq_meta = []; finalState; end - + + properties(SetObservable,SetAccess=private,AbortSet) + running = 0; + end + methods(Static) function obj = instance(ip) mlock; From e353120412eff90c342fb30c24a3dacadae022a9 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Wed, 9 Oct 2019 15:26:39 -0400 Subject: [PATCH 34/71] addded opo piezo control and ccleaned up error handling --- Modules/+Drivers/CWave.m | 186 +++++++++++++++++++++++++++++---------- 1 file changed, 141 insertions(+), 45 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 5f223e4c5..701610f98 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -51,6 +51,7 @@ Is_Ready = 'is_ready'; SetCommand = 'set_command'; LaserPower = 'get_photodiode_laser'; + OPO_Lambda = 'opo_lambda'; OPO_Power = 'get_photodiode_opo'; OptimizeSHG = 'opt_tempshg'; SHG_Power = 'get_photodiode_shg'; @@ -80,7 +81,11 @@ CoarseTune = 'coarse'; FineTune = 'fine'; Disconnect = 'cwave_disconnect'; + RegOpo_On = 'regopo_on'; + RegOpo_Out = 'regopo_out'; + %%RegOpo_Set = 'regopo_set'; RefCavity_Piezo = 'x'; + SetRefOpoExtramp = 'set_regopo_extramp'; ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; ThickEtalon_Piezo = 'thicketa_rel'; Piezo_maxBit = 65535/100; @@ -172,13 +177,13 @@ else [status,varargout{1:nargs-1}] = calllib(obj.LibraryName,FunctionName,varargin{:}); end - status = obj.CheckErrorStatus(status, FunctionName); + status = obj.CheckErrorStatus(status, FunctionName,varargin{:}); end - function status = CheckErrorStatus(obj,status,FunctionName) + function status = CheckErrorStatus(obj,status,FunctionName,varargin) %edit cases TBD. Need to sort out string to report and %flag/status for each function - inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, ... + inversion_condition = {obj.ConnectCwave,obj.Admin,obj.UpdateStatus,obj.Set_IntValue, obj.SetRefOpoExtramp ... obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) if(status==-1) @@ -199,15 +204,56 @@ % 0==update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); case obj.Set_IntValue + switch cmd + case obj.RegOpo_Out + %0: integer value set, 1: integer value not set + assert(status==0,'OPO cavity not tuned'); + case obj.RefCavity_Piezo + %0: integer value set, 1: integer value not set + assert(status==0,'Reference cavity not tuned.'); + case obj.WLM_BigSteps + %0: integer value set, 1: integer value not set + assert(status==0,'Turning off big wavelength steps during PID failed'); + case obj.WLM_EtalonSteps + %0: integer value set, 1: integer value not set + assert(status==0,'Turning off etalon steps during PID failed'); + case obj.WLM_PiezoSteps + %0: integer value set, 1: integer value not set + assert(status==0,'Turning on cavity piezo during PID failed'); + case obj.OPO_Lambda + %0: integer value set, 1: integer value not set + assert(status==0,'Setting target wavelength failed'); + case obj.ShutterSHG + %0: integer value set, 1: integer value not set + assert(status==0,'SHG shutter failed') + case obj.ShutterLaser + %0: integer value set, 1: integer value not set + assert(status==0,'Laser shutter failed') + end % 0== integer value set, 1= integer value not set - assert(status == 0, ['CWAVE Error: Int value not set']); + assert(status == 0, 'CWAVE Error: Int value not set'); + case obj.SetRefOpoExtramp + assert(status == 0, 'Opo Piezo was not set to ramp.') case obj.Is_Ready % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing assert(status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); case obj.Set_FloatValue + switch varargin{1} + case obj.WLM_PID_Setpoint + % 0==update succeeded, 1=update failed + assert(ret == 0, 'Setting setpoint wavelength failed'); + end % 0==update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: float value not set']); case obj.SetCommand + switch varargin{1} + case obj.StopOptimization + assert(status == 0, 'Optimization has not stopped'); + case obj.OptimizeSHG + assert(status == 0, 'SHG optimization failed.'); + case obj.RelockEtalon + assert(status == 0, 'Etalon failed to relock.'); + end % 0=update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); case obj.LaserPower @@ -220,6 +266,28 @@ % 0=update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: SHG power not within standard operating range.']); case obj.StatusReport + if (obj.opo_stepper_stat == 1) + disp('Error OPO stepper not locked') + elif (obj.opo_temp_stat == 1) + disp('OPO temperature not locked') + elif (obj.shg_stepper_stat == 1) + disp('SHG stepper not locked') + elif (obj.shg_temp_stat == 1) + disp('SHG temp not locked') + elif (obj.thin_etalon_stat == 1) + disp('Thin etalon not locked') + elif (obj.opo_lock_stat == 1 && obj.get_intvalue(RegOPO_On) == 2) + disp('OPO cavity piezo not locked.') + elif (obj.shg_lock_stat == 1) + disp('SHG cavity piezo not locked') + elif (obj.etalon_lock_stat == 1) + disp('thick etalon not locked') + elif (obj.laser_emission_stat == 1) + disp('No Pump emission! Unshutter Millenia Edge!') + elif (obj.ref_temp_stat == 1) + disp('Reference cavity temperature is not locked!!!') + end + % 0=update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: All elements are not stable and/or locked.']); case obj.LaserStatus @@ -533,22 +601,18 @@ function WLM_PID_Compute(obj, wl_measured) function shutter_lsr(obj) %open or close internal pump laser shutter if strcmp(obj.lsr_shutter, obj.Open) - ret = obj.set_intvalue(obj.ShutterLaser,1); - assert(ret == 1, 'Opening pump laser shutter failed'); + obj.set_intvalue(obj.ShutterLaser,1); elseif strcmp(obj.lsr_shutter, obj.Close) - ret = obj.set_intvalue(obj.ShutterLaser,0); - assert(ret == 0, 'Closing pump laser shutter failed'); + obj.set_intvalue(obj.ShutterLaser,0); end end function shutter_shg(obj) %open or close SHG shutter if strcmp(obj.shg_shutter, obj.Open) - ret = obj.set_intvalue(obj.ShutterSHG,1); - assert(ret == 1, 'Opening SHG shutter failed'); + obj.set_intvalue(obj.ShutterSHG,1); elseif strcmp(obj.shg_shutter, obj.Close) - ret = obj.set_intvalue(obj.ShutterSHG,0); - assert(ret == 1, 'Closing SHG shutter failed'); + obj.set_intvalue(obj.ShutterSHG,0);; end end @@ -600,8 +664,7 @@ function disconnect_cwave(obj) function set_target_wavelength(obj) %set target wavelength with a coarse 0.01 nm resolution - ret = obj.set_intvalue('opo_lambda',round(obj.target_wavelength*100)); - assert(ret == 1, 'Setting target wavelength failed'); + obj.set_intvalue(obj.OPO_Lambda,round(obj.target_wavelength*100)); disp(['Target wavelength set: ' num2str(round(obj.target_wavelength*100)/100) 'nm']); % IMPORTANT: wait one second before starting to poll for ready pause(1); @@ -625,36 +688,26 @@ function set_target_deviation(obj, target_dev) function fine_tune(obj) % fine tune based on wavemeter measurement - ret = obj.set_intvalue(obj.WLM_PiezoSteps, 1); - assert(ret == 1, 'Turning on cavity piezo during PID failed'); + obj.set_intvalue(obj.WLM_PiezoSteps, 1); % turn off etalon control - ret = obj.set_intvalue(obj.WLM_EtalonSteps, 0); - assert(ret == 1, 'Turning off etalon steps during PID failed'); + obj.set_intvalue(obj.WLM_EtalonSteps, 0); %turn off big wavelength steps (OPO and SHG remain locked) - ret = obj.set_intvalue(obj.WLM_BigSteps, 0); - assert(ret == 1, 'Turning off big wavelength steps during PID failed'); + obj.set_intvalue(obj.WLM_BigSteps, 0); end function coarse_tune(obj) % coarse tune based on wavemeter measurement % turn on reference cavity steps - ret = obj.set_intvalue(obj.WLM_PiezoSteps, 1); - assert(ret == 1,'Turning on cavity piezo during PID failed'); + obj.set_intvalue(obj.WLM_PiezoSteps, 1); %turn on etalon steps - ret = obj.set_intvalue(obj.WLM_EtalonSteps, 1); - assert(ret == 1, 'Turning on etalon steps during PID failed'); + obj.set_intvalue(obj.WLM_EtalonSteps, 1); %turn off big wavelength steps (OPO and SHG remain locked) - ret = obj.set_intvalue(obj.WLM_BigSteps, 0); - assert(ret == 1, 'Turning off big wavelength steps during PID failed'); + obj.set_intvalue(obj.WLM_BigSteps, 0); end function flag = abort_tune(obj) - %currently the StopOptimization parameter is not recognized by - %the set_command function. Needs correction on Hubner's end %Stops optimization of wavelength tuning. flag = obj.set_command(obj.StopOptimization); - %assert(flag==1, 'Optimization has not stopped'); - %StopOptimization = 'opt_stop'; end function piezo = get_ref_cavity_percent(obj) @@ -663,40 +716,83 @@ function coarse_tune(obj) piezo = piezo_voltage/obj.Piezo_maxBit; end + function piezo = get_opo_cavity_percent(obj) + % returns reference cavity piezo percent value + piezo_voltage = obj.get_intvalue(obj.RegOpo_Out); + piezo = piezo_voltage/obj.Piezo_maxBit; + end + function piezo = tune_ref_cavity(obj,piezo_percent) %Piezo voltage is passed a a percentage of the total range %Total range is 0-65535 %Convert from percentage to integer piezo_voltage = round(piezo_percent*obj.Piezo_maxBit); - - flag = obj.set_intvalue(obj.RefCavity_Piezo,piezo_voltage); - assert(flag ==0, 'Reference cavity not tuned.') - + obj.set_intvalue(obj.RefCavity_Piezo,piezo_voltage); piezo = obj.get_ref_cavity_percent(); end function tune_thick_etalon(obj,relative_wl_pm) %execute relative wavelength step of thick etalon in pm. %Total range is -1000 to 1000 pm (type int) - - flag = obj.set_intvalue(obj.ThickEtalon_Piezo_hr,relative_wl_pm); - assert(flag==0, 'Relative tuning of etalon failed.'); + obj.set_intvalue(obj.ThickEtalon_Piezo_hr,relative_wl_pm); end function optimize_shg(obj) - %currently the OptimizeSHG parameter is not recognized by - %the set_command function. Needs correction on Hubner's end - flag = obj.set_command(obj.OptimizeSHG); - assert(flag == 0, 'SHG optimization failed.'); + obj.set_command(obj.OptimizeSHG); end function relock_etalon(obj) - %currently the RelockEtalon parameter is not recognized by - %the set_command function. Needs correction on Hubner's end - flag = obj.set_command(obj.RelockEtalon); - assert(flag == 0, 'Etalon failed to relock.'); + obj.set_command(obj.RelockEtalon); end + function piezo_percent = tune_opo_cavity(obj,val) + %Use for wider fsr tuning range ~ 20-40 GHz in the visible + %Piezo voltage is passed a a percentage of the total range + %Total range is 0-65535 + %Convert from percentage to integer + + if (get_regopo() ~= 4) + set_regopo(4); + end + piezo_voltage = round(val*obj.Piezo_maxBit); + obj.set_intvalue(obj.RegOpo_Out,piezo_voltage); + %assert(flag == 0, 'OPO cavity not tuned') + piezo_percent = obj.get_opo_cavity_percent(); + end + + function set_regopo(obj,val) + %val = OPO regulator mode. + %0: off + %1: scan + %2: regulate + %3: user ramp + %4: manual setpoint (by regopo_out) + obj.set_intvalue(obj.RegOpo_On,val) + end + + function mode = get_regopo(obj) + %read opo piezo votlage bit. + mode = obj.get_intvalue(obj.RegOpo_On); + end + + function status = set_regopo_extramp(obj, duration, mode, lowerLimit, upperLimit) + % Description: Configures the waveform to be output to the OPO?s + % thick etalon when control mode is set to ?user ramp? (regopo_on=3). + % Arguments: duration is the waveform's duration in milliseconds + % mode is the waveform's mode (0=sawtooth, 1=triangle) + % lowerLimit/upperLimit are the waveform?s start and endpoint in percent of full scale output + % Returns: Returns 0 if the new command was executed correctly. Returns 1 if an error occurred. + % DLL bugs: minimum ramp is 10%. Maximum ramp duration is 60000 ms. + status = obj.LibraryFunction(obj.SetRefOpoExtramp, duration, mode, lowerLimit, upperLimit); + end + + function opo_ramp_piezo(obj) + %ramp piezo with sawtooth or triangle waveform + obj.set_regopo(3); + end + + + end %Methods I will likey never use From 0a314dd9113b8ef1ef60fc7c8cf45899cd90637b Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 10 Oct 2019 00:50:53 -0400 Subject: [PATCH 35/71] TunePercent + tune updated in source CWave. --- Modules/+Drivers/CWave.m | 13 +-- Modules/+Sources/CWave.m | 204 ++++++++++++++++++++++++++++++--------- 2 files changed, 165 insertions(+), 52 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 701610f98..72fcbd61b 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -289,7 +289,7 @@ end % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: All elements are not stable and/or locked.']); + disp('CWAVE Warning: All elements are not stable and/or locked.'); case obj.LaserStatus % 0=update failed, 1==update succeeded assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); @@ -722,13 +722,12 @@ function coarse_tune(obj) piezo = piezo_voltage/obj.Piezo_maxBit; end - function piezo = tune_ref_cavity(obj,piezo_percent) + function tune_ref_cavity(obj,piezo_percent) %Piezo voltage is passed a a percentage of the total range %Total range is 0-65535 %Convert from percentage to integer piezo_voltage = round(piezo_percent*obj.Piezo_maxBit); - obj.set_intvalue(obj.RefCavity_Piezo,piezo_voltage); - piezo = obj.get_ref_cavity_percent(); + obj.set_intvalue(obj.RefCavity_Piezo,piezo_voltage); end function tune_thick_etalon(obj,relative_wl_pm) @@ -745,19 +744,15 @@ function relock_etalon(obj) obj.set_command(obj.RelockEtalon); end - function piezo_percent = tune_opo_cavity(obj,val) + function tune_opo_cavity(obj,val) %Use for wider fsr tuning range ~ 20-40 GHz in the visible %Piezo voltage is passed a a percentage of the total range %Total range is 0-65535 %Convert from percentage to integer - if (get_regopo() ~= 4) - set_regopo(4); - end piezo_voltage = round(val*obj.Piezo_maxBit); obj.set_intvalue(obj.RegOpo_Out,piezo_voltage); %assert(flag == 0, 'OPO cavity not tuned') - piezo_percent = obj.get_opo_cavity_percent(); end function set_regopo(obj,val) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index ecb7a0682..e3a7cb8ce 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,8 +16,8 @@ end properties(SetAccess=protected) - % TODO I have no idea what the cwave's range is - range = Sources.TunableLaser_invisible.c./[300, 1000]; + vis_range = Sources.TunableLaser_invisible.c./[450, 650]; + nir_range = Sources.TunableLaser_invisible.c./[900, 1300]; end properties(SetObservable,AbortSet) @@ -26,16 +26,35 @@ cwave_ip = Sources.CWave.no_server; pulseStreamer_ip = Sources.CWave.no_server; wavemeter_ip = Sources.CWave.no_server; - wavemeter_channel = 1; % set to integer value % TODO fill in prefs all the way - show_prefs = {'tuning', 'cwave_ip', 'pulseStreamer_ip', 'wavemeter_ip'}; - readonly_prefs = {'tuning'}; PSline = 1; % Index from 1 (Pulsestreamer has 8 digital out channels) + resonator_tune_speed = 0.5; % percent per step + etalon_lock; + etalon_percent; + opo_stepper; + opo_temp; + shg_stepper; + shg_temp; + thin_etalon; + opo_lock; + shg_lock; + pump_emission; + ref_temp; + wavelength_lock; + target_wavelength; + show_prefs = {'tuning','target_wavelength','wavelength_lock','etalon_lock',... + 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... + 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... + 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... + 'resonator_tune_speed'}; + readonly_prefs = {'tuning','etalon_lock','opo_stepper','opo_temp',... + 'shg_stepper', 'shg_temp','thin_etalon','opo_lock','shg_lock',... + 'pump_emission','ref_temp'}; end properties(SetAccess=private) - PulseStreamer %hardware handle - wavemeter + PulseStreamerHandle %hardware handle + wavemeterHandle cwaveHandle end @@ -81,47 +100,95 @@ % source methods function on(obj) - assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') - % TODO say something to PulseStreamer - obj.PulseStreamer.constant([obj.PSline],0,0) + assert(~isempty(obj.PulseStreamerHandle), 'No IP set for PulseStreamer!') + state = PulseStreamer.OutputState([obj.PSline],0,0); + obj.PulseStreamerHandle.PS.constant(state); obj.source_on = true; end function off(obj) - assert(~isempty(obj.PulseStreamer), 'No IP set for PulseStreamer!') - % TODO say something to PulseStreamer + assert(~isempty(obj.PulseStreamerHandle), 'No IP set for PulseStreamer!') obj.source_on = false; - obj.PulseStreamer.constant([],0,0) + state = PulseStreamer.OutputState([],0,0); + obj.PulseStreamerHandle.PS.constant(state); end % tunable laser methods - function tune(obj, setpoint) + function tune(obj, setpoint,target_dev) + % target in nm obj.tuning = true; + if setpoint < 899 + assert(target>=obj.c/max(obj.vis_range)&&target<=obj.c/min(obj.vis_range),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.vis_range)) + elseif setpoint >= 899 + assert(target>=obj.c/max(obj.nir_range)&&target<=obj.c/min(obj.nir_range),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.nir_range)) + end assert(~isempty(obj.cwaveHandle), 'no cwave handle') - target_dev = 0.5; - measured_wavelength = obj.wavemeter.getWavelength(); - mid_setpoint = measured_wavelength; - while round(target_dev, 5) > 0 - while abs(mid_setpoint - setpoint) > 2*target_dev - mid_setpoint = mid_setpoint + 2*target_dev; - cwave.set_target_deviation(target_dev); - obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); - while abs(measured_wavelength - mid_setpoint) > target_dev - cwave.WLM_PID_Compute(measured_wavelength); - pause(0.001); + err = []; + % The CWave is slow at tuning, so message is useful until a non-blocking operation exists + dlg = msgbox('Please wait while CWave tunes to target wavelength.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + obj.tuning = true; + + try + %target_dev = 0.5; + %measured_wavelength = obj.wavemeterHandle.getWavelength(); + %mid_setpoint = measured_wavelength; + %while round(target_dev, 5) > 0 + % while abs(mid_setpoint - setpoint) > 2*target_dev + % mid_setpoint = mid_setpoint + 2*target_dev; + % obj.cwaveHandle.set_target_deviation(target_dev); + % obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); + % while abs(measured_wavelength - mid_setpoint) > target_dev + % obj.cwaveHandle.WLM_PID_Compute(measured_wavelength); + % pause(0.001); + % end + % end + % target_dev = target_dev/10; + + + while round(target_dev, 5) > 0 + measured_wavelength = obj.wavemeterHandle.getWavelength(); + mid_setpoint = measured_wavelength; + direction = sign(setpoint-mid_setpoint); + while abs(mid_setpoint - setpoint) > 2*target_dev + mid_setpoint = mid_setpoint + direction*target_dev/5; + obj.cwaveHandle.set_target_deviation(target_dev); + obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); + while abs(measured_wavelength - mid_setpoint) > target_dev + obj.cwaveHandle.WLM_PID_Compute(measured_wavelength); + pause(0.001); + end end + target_dev = target_dev/10; end - target_dev = target_dev/10; + obj.tuning = false; + catch err end + delete(dlg) obj.tuning = false; + if ~isempty(err) + obj.locked = false; + obj.wavelength_lock = false; + obj.setpoint = NaN; + rethrow(err) + end + obj.setpoint = obj.c/target; + obj.locked = true; + obj.wavelength_lock = true; + obj.etalon_lock = true; % We don't know at this point anything about etalon if not locked end function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in nm obj.cwaveHandle.fine_tune(); - obj.tune(setpoint); + target_dev = 0.02; + obj.tune(setpoint,target_dev); end function TuneCoarse(obj, setpoint) @@ -136,24 +203,62 @@ function TuneCoarse(obj, setpoint) % % setpoint = setpoint in nm obj.cwaveHandle.coarse_tune(); - obj.tune(setpoint); + target_dev = 0.2; + obj.tune(setpoint,target_dev); end - function TunePercent(obj, percent) - %TunePercent sets the resonator cavity piezo percentage + function TunePercent(obj, target) + %TunePercent sets the resonator or the opo cavity piezo percentage + %ref cavity has fsr = 10GHz, opo cavity has fsr = 40 GHz + % For both cavties spectral drift for ~10 MHz steps is about 5-7 MHz % - % percent = desired piezo percentage from 1 to 100 + % percent = desired piezo percentage from 1 to 100 (float type) + %This is the OPO resonator assert(~isempty(obj.cwaveHandle)&&isobject(obj.cwaveHandle) && isvalid(obj.cwaveHandle),'no cwave handle') assert(percent>=0 && percent<=100,'Target must be a percentage') - obj.resonator_percent = obj.cwaveHandle.tune_ref_cavity(percent); + %set opo cavity to tuning mode + if (obj.cwaveHandle.get_regopo() ~= 4) + obj.cwaveHandle.set_regopo(4); + end + % tune at a limited rate per step + currentPercent = obj.GetPercent; + numberSteps = floor(abs(currentPercent-target)/obj.resonator_tune_speed); + direction = sign(target-currentPercent); + for i = 1:numberSteps + obj.cwaveHandle.tune_opo_cavity(currentPercent+(i)*direction*obj.resonator_tune_speed); + end + obj.cwaveHandle.tune_opo_cavity(target); + obj.resonator_percent = obj.GetPercent(); + obj.updateStatus(); % Get voltage of resonator + end + + function updateStatus(obj) + % Get status report from laser and update a few fields + + lock_status = obj.cwaveHandle.getStatus(); + obj.etalon_lock = obj.cwaveHandle.etalon_lock_stat; + obj.opo_stepper = obj.cwaveHandle.opo_stepper_stat; + obj.opo_temp = obj.cwaveHandle.opo_temp_stat; + obj.shg_stepper = obj.cwaveHandle.shg_stepper_stat; + obj.shg_temp = obj.cwaveHandle.shg_temp_stat; + obj.thin_etalon = obj.cwaveHandle.thin_etalon_stat; + obj.opo_lock = obj.cwaveHandle.opo_lock_stat; + obj.shg_lock = obj.cwaveHandle.shg_lock_stat; + obj.pump_emission = obj.cwaveHandle.laser_emission_stat; + obj.ref_temp = obj.cwaveHandle.ref_temp_stat; + obj.getWavelength; % This sets wavelength_lock + obj.tuning = ~lock_status; + obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; + % Overwrite getWavelength tuning status with EMM tuning state end function piezo = GetPercent(obj) - piezo = obj.cwaveHandle.get_ref_cavity_percent(); + piezo = obj.cwaveHandle.get_opo_cavity_percent(); + %piezo = obj.cwaveHandle.get_ref_cavity_percent(); end function freq = getFrequency(obj) - wavelength = obj.wavemeter.getWavelength(); + wavelength = obj.wavemeterHandle.getWavelength(); freq = Sources.TunableLaser_invisible.c/wavelength; end @@ -169,7 +274,7 @@ function TunePercent(obj, percent) end function set.pulseStreamer_ip(obj, ip) - err = obj.connect_driver('PulseStreamer', PulseStreamerMaster.PulseStreamerMaster, ip); + err = obj.connect_driver('PulseStreamerMaster', 'PulseStreamerMaster.PulseStreamerMaster', ip); if ~isempty(err) obj.pulseStreamer_ip = obj.no_server; rethrow(err) @@ -178,21 +283,34 @@ function TunePercent(obj, percent) end function set.wavemeter_ip(obj, ip) - err = obj.connect_driver('wavemeter', 'Wavemeter', ip, obj.wavemeter_channel); + err = obj.connect_driver('wavemeterHandle', 'Wavemeter1Ch', ip); if ~isempty(err) obj.wavemeter_ip = obj.no_server; rethrow(err) end obj.wavemeter_ip = ip; end - - function set.wavemeter_channel(obj, channel) - assert(round(channel)==channel&&channel>0,'wavemeter_channel must be an integer greater than 0.') - obj.wavemeter_channel = channel; - err = obj.connect_driver('wavemeter','Wavemeter',obj.wavemeter_ip,val); - if ~isempty(err) - rethrow(err) + + function tf = internal_call(obj) + tf = false; % Assume false, verify that true later + st = dbstack(2); % Exclude this method, and its caller + if ~isempty(st) + caller_class = strsplit(st(1).name,'.'); + caller_class = caller_class{1}; + this_class = strsplit(class(obj),'.'); + this_class = this_class{end}; + tf = strcmp(this_class,caller_class); end end + + function set.target_wavelength(obj,val) + if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN + if obj.internal_call; obj.target_wavelength = val; return; end + obj.tune(val); + end + + + + end end \ No newline at end of file From 37e5e9e4f52ccf895aea3edeb5e994e458fff471 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 10 Oct 2019 10:34:56 -0400 Subject: [PATCH 36/71] Updated dll directory. Fixed range pref --- Modules/+Drivers/CWave.m | 11 +++++++---- Modules/+Sources/CWave.m | 13 ++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 72fcbd61b..91b2f2f03 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -31,9 +31,12 @@ properties(Constant,Hidden) % constants for C library - Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x64\'; - Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x86\'; - HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\'; + %Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x64\'; + %Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x86\'; + %HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\'; + Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x64\'; + Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x86\'; + HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\'; LibraryName = 'CWAVE_DLL'; % alias for library LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll LibraryHeader = 'CWAVE_DLL.h'; @@ -41,7 +44,7 @@ ComputerArch = 'arch'; ConnectCwave = 'cwave_connect'; DLL_Version= 'DLL_Version'; - DLL_identity = 20; + DLL_identity = 22; Admin = 'admin_elevate'; UpdateStatus = 'cwave_updatestatus'; Get_IntValue = 'get_intvalue'; diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index e3a7cb8ce..a70890288 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,8 +16,7 @@ end properties(SetAccess=protected) - vis_range = Sources.TunableLaser_invisible.c./[450, 650]; - nir_range = Sources.TunableLaser_invisible.c./[900, 1300]; + range = [Sources.TunableLaser_invisible.c./[450, 650],Sources.TunableLaser_invisible.c./[900, 1300]]; end properties(SetObservable,AbortSet) @@ -119,11 +118,11 @@ function tune(obj, setpoint,target_dev) % target in nm obj.tuning = true; if setpoint < 899 - assert(target>=obj.c/max(obj.vis_range)&&target<=obj.c/min(obj.vis_range),... - sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.vis_range)) + assert(target>=obj.c/max(obj.range(1))&&target<=obj.c/min(obj.range(1)),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(1))) elseif setpoint >= 899 - assert(target>=obj.c/max(obj.nir_range)&&target<=obj.c/min(obj.nir_range),... - sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.nir_range)) + assert(target>=obj.c/max(obj.range(2))&&target<=obj.c/min(obj.range(2)),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(2))) end assert(~isempty(obj.cwaveHandle), 'no cwave handle') err = []; @@ -274,7 +273,7 @@ function updateStatus(obj) end function set.pulseStreamer_ip(obj, ip) - err = obj.connect_driver('PulseStreamerMaster', 'PulseStreamerMaster.PulseStreamerMaster', ip); + err = obj.connect_driver('PulseStreamerHandle', 'PulseStreamerMaster.PulseStreamerMaster', ip); if ~isempty(err) obj.pulseStreamer_ip = obj.no_server; rethrow(err) From 8825806c3fd0d139f3d72058f5fe8be94778c13e Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Wed, 16 Oct 2019 00:39:17 -0400 Subject: [PATCH 37/71] Cwave prefs update. PulseStreamer complies with pulsetimer_invisible --- .../PulseStreamerMaster.m | 61 +++++++---- Modules/+Drivers/CWave.m | 4 +- Modules/+Sources/CWave.m | 103 +++++++++++------- Modules/+Sources/cwave_testscript.m | 12 +- 4 files changed, 110 insertions(+), 70 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index 99128c6d5..2d4995435 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -141,7 +141,6 @@ obj.triggerStart = PulseStreamer.TriggerStart.SOFTWARE(); obj.triggerMode = PulseStreamer.TriggerRearm.AUTO(); obj.sequence = obj.PS.createSequence(); - obj.PS.reset(); obj.map.command(:)=[]; obj.cmd.command(:)=[]; % initialize final state to 0V for all channels. @@ -176,8 +175,10 @@ function build(obj,json) % % seq_meta.units: time units for pulse durations % seq_meta.name: label for sequence. - % seq_meta.forever: boolean indicating whether to - % repeat sequence indefinitely until explicitly halted. + % seq_meta.repeat: boolean indicating how many times the + % sequence will be repeated until explicitly halted. + % The value of -1 is reserved for infinite + % repetitions. % % The build method workflow is as follows: % 1. Determine if json input is a string or a json file name @@ -290,39 +291,43 @@ function plot(obj) end - function load(obj,repeats) + function load(obj,program) % The load method converts the sequence object to the properly % formated 64 bit string and uploads this to the xilinx chip in the % pulse streamer via an eithernet connection managed by a hardware % server. - switch nargin - case 1 - repeats = 1; - end - + build(obj,program); start = obj.triggerStart;%initialize the trigger to be software defined mode = obj.triggerMode; % initialize the trigger to be rearmed after each run. obj.PS.setTrigger(start, mode); % set triggers - if obj.seq_meta.forever == 1 - runs =-1; %run until halt() is called - else - runs = repeats; - end - % upload sequence to hardware, but do not run the sequence. - obj.PS.stream(obj.sequence,runs,obj.finalState); + obj.PS.stream(obj.sequence,obj.seq_meta.repeat,obj.finalState); end - function run(obj) + function start(obj) % starts the sequence if the sequence was uploaded with the % PSStart.Software option + +% % Get caller info +% a = dbstack('-completenames'); +% caller = strsplit(a(end).file,filesep); +% prefix = ''; +% for i = 1:numel(caller) +% if numel(caller{i}) && caller{i}(1)=='+' +% prefix = [prefix caller{i}(2:end) '.']; +% end +% end +% [~,name,~]=fileparts(caller{end}); +% caller = [prefix name]; obj.PS.startNow(); +% obj.running = caller; end - function halt(obj) + function stop(obj) + %stops the PulseStreamer % Interrupt the sequence and set the final state of the % hardware. This method does not modify the final state if % the sequence has already finished. This method also releases @@ -330,6 +335,13 @@ function halt(obj) % allows for faster upload sequence during next call of % "stream" method. obj.PS.forceFinal() + if obj.PS.isStreaming() == 1 + obj.PulseStreamerHandle.PS.constant(obj.finalState); + end + end + + function reset(obj) + obj.PS.reset(); end function [index] = decodeInstructions(obj, json_seq, cmd, depth, index) @@ -762,9 +774,12 @@ function printTree(obj, cmd, depth) DEBUG = 0; - % convert json string into a structure - json_total = jsondecode(obj.json); + % compile now pass a matlab structure equivalent to + % the old structure = jsondecode(json_pulse_sequence) + %json_total = jsondecode(obj.json); + json_total = obj.json; json_struct = json_total.sequence; + %initialize the json_seq cell array and fill each element in %array with map for each instruction line. @@ -780,7 +795,7 @@ function printTree(obj, cmd, depth) seq_metadata.channels = json_total.channels; seq_metadata.units = json_total.units; seq_metadata.name = json_total.name; - seq_metadata.forever = json_total.forever; + seq_metadata.repeat = json_total.repeat; obj.seq_meta = seq_metadata; @@ -798,9 +813,9 @@ function printTree(obj, cmd, depth) % Destructor method. Clears object properties. function delete(obj) if obj.PS.isStreaming() == 1 - obj.halt() + obj.stop() elseif obj.PS.hasSequence() == 1 - obj.halt() + obj.stop() end end end diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 91b2f2f03..b9006b719 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -207,7 +207,7 @@ % 0==update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: Measurement status of C-wave not updated']); case obj.Set_IntValue - switch cmd + switch varargin{1} case obj.RegOpo_Out %0: integer value set, 1: integer value not set assert(status==0,'OPO cavity not tuned'); @@ -244,7 +244,7 @@ switch varargin{1} case obj.WLM_PID_Setpoint % 0==update succeeded, 1=update failed - assert(ret == 0, 'Setting setpoint wavelength failed'); + assert(status == 0, 'Setting setpoint wavelength failed'); end % 0==update succeeded, 1=update failed assert(status == 0, ['CWAVE Error: float value not set']); diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index a70890288..b387f8a8c 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -14,34 +14,19 @@ properties(SetObservable,SetAccess=private) source_on = false; end - + properties(Constant,Hidden) + no_server = 'No Server'; % Message when not connected + end properties(SetAccess=protected) range = [Sources.TunableLaser_invisible.c./[450, 650],Sources.TunableLaser_invisible.c./[900, 1300]]; end - - properties(SetObservable,AbortSet) - resonator_percent = 0; - tuning = false; - cwave_ip = Sources.CWave.no_server; - pulseStreamer_ip = Sources.CWave.no_server; - wavemeter_ip = Sources.CWave.no_server; - % TODO fill in prefs all the way - PSline = 1; % Index from 1 (Pulsestreamer has 8 digital out channels) - resonator_tune_speed = 0.5; % percent per step - etalon_lock; - etalon_percent; - opo_stepper; - opo_temp; - shg_stepper; - shg_temp; - thin_etalon; - opo_lock; - shg_lock; - pump_emission; - ref_temp; - wavelength_lock; - target_wavelength; - show_prefs = {'tuning','target_wavelength','wavelength_lock','etalon_lock',... + properties + prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... + 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... + 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... + 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... + 'resonator_tune_speed'}; + show_prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... @@ -50,16 +35,41 @@ 'shg_stepper', 'shg_temp','thin_etalon','opo_lock','shg_lock',... 'pump_emission','ref_temp'}; end - + properties(SetObservable,GetObservable) + enabled = Prefs.Boolean(); + resonator_percent = Prefs.Double(0.00,'units','percent','min',0.00,'max',100.00); + tuning = Prefs.Boolean(false, 'help_text','This is a readonly string.','readonly',true); +% cwave_ip = Prefs.String('default',Sources.CWave.no_server,'allow_empty',true,'set',''); +% pulseStreamer_ip = Prefs.String(Sources.CWave.no_server,'allow_empty',false),'set',''; +% wavemeter_ip = Prefs.String(Sources.CWave.no_server,'allow_empty',false),'set',''; + PSline = Prefs.Integer('min',0,'help_text','indexed from 0'); % Index from 0 (Pulsestreamer has 8 digital out channels) + resonator_tune_speed = Prefs.Double(0.5,'units','percent','min',0.001,'max',1); % percent per step + etalon_lock = Prefs.Boolean('help_text','This is a readonly string.','readonly',true); + etalon_percent = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + opo_stepper = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + opo_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + shg_stepper = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + shg_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + thin_etalon = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + opo_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + shg_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + pump_emission = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + ref_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + wavelength_lock = Prefs.Boolean(); + %target_wavelength = Prefs.Double('default',NaN,'units','nm','min',450,'max',1300,'set','set_target_wavelength'); + cwave_ip = Sources.CWave.no_server; + pulseStreamer_ip = Sources.CWave.no_server; + wavemeter_ip = Sources.CWave.no_server; + target_wavelength; + end + properties(SetAccess=private) PulseStreamerHandle %hardware handle wavemeterHandle cwaveHandle end - properties(Constant,Hidden) - no_server = 'No Server'; % Message when not connected - end + methods(Access=private) function obj = CWave() @@ -111,6 +121,14 @@ function off(obj) state = PulseStreamer.OutputState([],0,0); obj.PulseStreamerHandle.PS.constant(state); end + function arm(obj) + obj.enabled = true; + end + function blackout(obj) + obj.off() + %possibly add code to depower switch (assuming it can be + %powered by nidaq) + end % tunable laser methods @@ -118,11 +136,11 @@ function tune(obj, setpoint,target_dev) % target in nm obj.tuning = true; if setpoint < 899 - assert(target>=obj.c/max(obj.range(1))&&target<=obj.c/min(obj.range(1)),... - sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(1))) + assert(setpoint>=obj.c/max(obj.range(1:2))&&setpoint<=obj.c/min(obj.range(1:2)),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(1:2))) elseif setpoint >= 899 - assert(target>=obj.c/max(obj.range(2))&&target<=obj.c/min(obj.range(2)),... - sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(2))) + assert(target>=obj.c/max(obj.range(3:4))&&target<=obj.c/min(obj.range(3:4)),... + sprintf('Wavelength must be in range [%g, %g] nm!!',obj.c./obj.range(3:4))) end assert(~isempty(obj.cwaveHandle), 'no cwave handle') err = []; @@ -214,7 +232,7 @@ function TunePercent(obj, target) % percent = desired piezo percentage from 1 to 100 (float type) %This is the OPO resonator assert(~isempty(obj.cwaveHandle)&&isobject(obj.cwaveHandle) && isvalid(obj.cwaveHandle),'no cwave handle') - assert(percent>=0 && percent<=100,'Target must be a percentage') + assert(target>=0 && target<=100,'Target must be a percentage') %set opo cavity to tuning mode if (obj.cwaveHandle.get_regopo() ~= 4) obj.cwaveHandle.set_regopo(4); @@ -245,9 +263,9 @@ function updateStatus(obj) obj.shg_lock = obj.cwaveHandle.shg_lock_stat; obj.pump_emission = obj.cwaveHandle.laser_emission_stat; obj.ref_temp = obj.cwaveHandle.ref_temp_stat; - obj.getWavelength; % This sets wavelength_lock + obj.setpoint = obj.c/obj.getWavelength; % This sets wavelength_lock obj.tuning = ~lock_status; - obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; + %obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; % Overwrite getWavelength tuning status with EMM tuning state end @@ -260,6 +278,11 @@ function updateStatus(obj) wavelength = obj.wavemeterHandle.getWavelength(); freq = Sources.TunableLaser_invisible.c/wavelength; end + + function wavelength = getWavelength(obj) + wavelength = obj.wavemeterHandle.getWavelength(); + end + % set methods @@ -308,8 +331,10 @@ function updateStatus(obj) obj.tune(val); end - - - + function delete(obj) + obj.cwaveHandle.delete() + obj.PulseStreamerHandle.delete() + obj.wavemeterHandle.delete() + end end end \ No newline at end of file diff --git a/Modules/+Sources/cwave_testscript.m b/Modules/+Sources/cwave_testscript.m index f9754ee45..d1c3fb92f 100644 --- a/Modules/+Sources/cwave_testscript.m +++ b/Modules/+Sources/cwave_testscript.m @@ -1,16 +1,16 @@ cwave = Sources.CWave.instance(); cwave.cwave_ip = '192.168.11.3'; -cwave.wavemeter_ip = '0.0.0.0'; +cwave.pulseStreamer_ip = '192.168.11.4'; +cwave.wavemeter_ip = '192.168.11.2'; -cwave.wavemeter_channel(1); disp('starting vals') disp(cwave.GetPercent()) -%disp(cwave.getFrequency()) - -cwave.TunePercent(10) +disp(cwave.getFrequency()) +%cwave.TunePercent(10) +cwave.TuneSetpoint(618.9488); disp('after tunepercent to 10') disp(cwave.GetPercent()) -%disp(cwave.getFrequency()) \ No newline at end of file +disp(cwave.getFrequency()) \ No newline at end of file From 19b37a961ec8edd5de7632bcb166c4c10dd78ec5 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:17:29 -0500 Subject: [PATCH 38/71] Tune range = 450-650nm with 4MHz res. updateStatus bugs fixed. --- Modules/+Sources/CWave.m | 215 ++++++++++++++++++++++++++++++--------- 1 file changed, 165 insertions(+), 50 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index b387f8a8c..2883262f8 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,7 +16,14 @@ end properties(Constant,Hidden) no_server = 'No Server'; % Message when not connected + MaxThickEtalonRange = 0.375; %nm end + properties(Hidden) + sOPO_power; + sSHG_power; + sPump_power; + end + properties(SetAccess=protected) range = [Sources.TunableLaser_invisible.c./[450, 650],Sources.TunableLaser_invisible.c./[900, 1300]]; end @@ -56,6 +63,15 @@ pump_emission = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); ref_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); wavelength_lock = Prefs.Boolean(); + OPO_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); + SHG_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); + Pump_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); + TempRef = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempOPO = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempSHG = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempRef_setpoint = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempOPO_setpoint = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempSHG_setpoint = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); %target_wavelength = Prefs.Double('default',NaN,'units','nm','min',450,'max',1300,'set','set_target_wavelength'); cwave_ip = Sources.CWave.no_server; pulseStreamer_ip = Sources.CWave.no_server; @@ -132,7 +148,8 @@ function blackout(obj) % tunable laser methods - function tune(obj, setpoint,target_dev) + % tunable laser methods + function tune(obj, setpoint,target_dev,coarse,lock) % target in nm obj.tuning = true; if setpoint < 899 @@ -151,37 +168,106 @@ function tune(obj, setpoint,target_dev) drawnow; obj.tuning = true; - try - %target_dev = 0.5; - %measured_wavelength = obj.wavemeterHandle.getWavelength(); - %mid_setpoint = measured_wavelength; - %while round(target_dev, 5) > 0 - % while abs(mid_setpoint - setpoint) > 2*target_dev - % mid_setpoint = mid_setpoint + 2*target_dev; - % obj.cwaveHandle.set_target_deviation(target_dev); - % obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); - % while abs(measured_wavelength - mid_setpoint) > target_dev - % obj.cwaveHandle.WLM_PID_Compute(measured_wavelength); - % pause(0.001); - % end - % end - % target_dev = target_dev/10; + try + obj.updateStatus; + if (coarse == true) + if (obj.sOPO_power | obj.sSHG_power | obj.sPump_power | obj.wavemeterHandle.getExposure == 2000) + detune = 2*obj.MaxThickEtalonRange; + disp(detune) + obj.wavemeterHandle.setExposureMode(false); %Manually set exposure + obj.wavemeterHandle.setExposure(1); %set to 1ms + else + detune = abs(setpoint-obj.getWavelength); + end + + if (detune > abs(obj.MaxEtalon_wl-obj.MinEtalon_wl)) | (detune > obj.MaxThickEtalonRange ) + % need to add warning option allowsing user to exit + % this is a very costly operation + dlg = questdlg('Target wavelength exceeds tuning etalon and OPO range (> 0.2 nm)! Tuning will be very slow. Do you wish to continue with tuning?', ... + 'Tuning Warning', ... + 'Continue Tuning','Abort','Abort'); + % Handle response + switch dlg + case 'Continue Tuning' + obj.cwaveHandle.target_wavelength = setpoint + 1; + obj.cwaveHandle.set_target_wavelength(); + pause(10); + obj.cwaveHandle.target_wavelength = setpoint; + obj.cwaveHandle.set_target_wavelength(); + while(1) + ret = obj.locked; + if (ret == true) + obj.updateStatus; + break; + else + obj.updateStatus; + pause(1); + end + end + obj.wavemeterHandle.setExposureMode(true); + obj.updateStatus; + case 'Abort' + return + end + elseif abs(setpoint-obj.getWavelength) < abs(obj.MaxEtalon_wl-obj.MinEtalon_wl) + abort = obj.centerThickEtalon; + if (abort ) + delete(dlg) + return + end + + if (lock == true) + while ( obj.cwaveHandle.get_regopo() ~= 2) + obj.cwaveHandle.set_regopo(2); + end + if (obj.cwaveHandle.get_ref_cavity_percent ~= 50) + obj.TuneRefPercent(50.0); + end + obj.etalon_pid(setpoint,obj.ThickEtalonTolerance); + %obj.etalon_pid(setpoint); + for i=1:2 + obj.WLM_tune(setpoint,target_dev) + end + elseif (lock == false) + while ( obj.cwaveHandle.get_regopo() ~= 4) + obj.cwaveHandle.set_regopo(4); + pause(1); + disp('regopo'); + obj.cwaveHandle.get_regopo + disp('end iteration') + end + if (obj.GetPercent() ~= 50) + obj.TunePercent(50); + end + obj.etalon_pid(setpoint); + for i=1:2 + obj.opo_pid(setpoint,target_dev); + end + end + obj.updateStatus; + end - - while round(target_dev, 5) > 0 - measured_wavelength = obj.wavemeterHandle.getWavelength(); - mid_setpoint = measured_wavelength; - direction = sign(setpoint-mid_setpoint); - while abs(mid_setpoint - setpoint) > 2*target_dev - mid_setpoint = mid_setpoint + direction*target_dev/5; - obj.cwaveHandle.set_target_deviation(target_dev); - obj.cwaveHandle.set_pid_target_wavelength(mid_setpoint); - while abs(measured_wavelength - mid_setpoint) > target_dev - obj.cwaveHandle.WLM_PID_Compute(measured_wavelength); - pause(0.001); - end - end - target_dev = target_dev/10; + elseif coarse == false + if (lock == true) + if (obj.cwaveHandle.get_ref_cavity_percent ~= 50) + obj.TuneRefPercent(50.0); + end + obj.cwaveHandle.set_regopo(2); + for i=1:2 + obj.WLM_tune(setpoint,target_dev) + end + else + if (obj.GetPercent() ~= 50) + obj.TunePercent(50); + end + %obj.set_regopo(4); + %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,4); + obj.cwaveHandle.set_regopo(4); + for i=1:2 + obj.opo_pid(setpoint,target_dev); + end + end + obj.updateStatus; end obj.tuning = false; catch err @@ -193,13 +279,12 @@ function tune(obj, setpoint,target_dev) obj.wavelength_lock = false; obj.setpoint = NaN; rethrow(err) + elseif (lock) + obj.wavelength_lock = true; end - obj.setpoint = obj.c/target; - obj.locked = true; - obj.wavelength_lock = true; - obj.etalon_lock = true; % We don't know at this point anything about etalon if not locked + obj.setpoint = setpoint; end - + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in nm @@ -249,22 +334,47 @@ function TunePercent(obj, target) obj.updateStatus(); % Get voltage of resonator end - function updateStatus(obj) + function updateStatus(obj) % Get status report from laser and update a few fields + tic + obj.locked = ~(obj.cwaveHandle.get_statusbits); + obj.etalon_lock = ~obj.cwaveHandle.etalon_lock_stat; + obj.opo_stepper_lock = ~obj.cwaveHandle.opo_stepper_stat; + obj.opo_temp_lock = ~obj.cwaveHandle.opo_temp_stat; + obj.shg_stepper_lock = ~obj.cwaveHandle.shg_stepper_stat; + obj.shg_temp_lock = ~obj.cwaveHandle.shg_temp_stat; + obj.thin_etalon_lock = ~obj.cwaveHandle.thin_etalon_stat; + obj.opo_lock = ~obj.cwaveHandle.opo_lock_stat; + obj.shg_lock = ~obj.cwaveHandle.shg_lock_stat; + obj.pump_emission = ~obj.cwaveHandle.laser_emission_stat; + obj.ref_temp_lock = ~obj.cwaveHandle.get_status_temp_ref; + + [obj.OPO_power,obj.sOPO_power] = obj.cwaveHandle.get_photodiode_opo; + [obj.SHG_power,obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; + [obj.Pump_power,obj.sPump_power] = obj.cwaveHandle.get_photodiode_laser; + obj.TempRef = obj.cwaveHandle.get_tref; + obj.TempOPO = obj.cwaveHandle.get_topo; + obj.TempSHG = obj.cwaveHandle.get_tshg; + obj.TempRef_setpoint = obj.cwaveHandle.get_tref_sp; + obj.TempOPO_setpoint = obj.cwaveHandle.get_topo_sp; + obj.TempSHG_setpoint = obj.cwaveHandle.get_tshg_sp; - lock_status = obj.cwaveHandle.getStatus(); - obj.etalon_lock = obj.cwaveHandle.etalon_lock_stat; - obj.opo_stepper = obj.cwaveHandle.opo_stepper_stat; - obj.opo_temp = obj.cwaveHandle.opo_temp_stat; - obj.shg_stepper = obj.cwaveHandle.shg_stepper_stat; - obj.shg_temp = obj.cwaveHandle.shg_temp_stat; - obj.thin_etalon = obj.cwaveHandle.thin_etalon_stat; - obj.opo_lock = obj.cwaveHandle.opo_lock_stat; - obj.shg_lock = obj.cwaveHandle.shg_lock_stat; - obj.pump_emission = obj.cwaveHandle.laser_emission_stat; - obj.ref_temp = obj.cwaveHandle.ref_temp_stat; - obj.setpoint = obj.c/obj.getWavelength; % This sets wavelength_lock - obj.tuning = ~lock_status; + regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... + & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; + + if(obj.locked | ((obj.cwaveHandle.get_regopo == 4) & regopo4_locked)) + obj.setpoint = obj.c/obj.getWavelength; % This sets wavelength_lock + end + + obj.tuning = ~(obj.locked); + + if (~obj.locked) + %replace below with dialog box + disp('CWAVE Warning: All elements are not stable and/or locked.'); + end + + toc + fprintf('toc %.8f\n',toc); %obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; % Overwrite getWavelength tuning status with EMM tuning state end @@ -331,6 +441,11 @@ function updateStatus(obj) obj.tune(val); end + function abort = centerThickEtalon(obj) + %add functionality later. This method will initialzie the + %etalon to the center of its tuning range. + end + function delete(obj) obj.cwaveHandle.delete() obj.PulseStreamerHandle.delete() From b4d6b33afb56cfbf745642fc104cf8f77c6b2c65 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:23:23 -0500 Subject: [PATCH 39/71] Updated TuneSetpoint, TuneCoarse, TuneRefPercent. --- Modules/+Sources/CWave.m | 123 ++++++++++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 14 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 2883262f8..1eb6e2e95 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -285,16 +285,25 @@ function tune(obj, setpoint,target_dev,coarse,lock) obj.setpoint = setpoint; end - function TuneSetpoint(obj,setpoint) + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint - % setpoint = setpoint in nm - obj.cwaveHandle.fine_tune(); - target_dev = 0.02; - obj.tune(setpoint,target_dev); + % setpoint = setpoint in THz + %obj.cwaveHandle.fine_tune(); + %cwave.cwaveHandle.setWLM_gains(20,150); + target_dev = 0.000001; + isLocked = true; + isCoarse = false; + user_speed = obj.resonator_tune_speed; + obj.resonator_tune_speed = 0.1; + obj.tune(obj.c/setpoint,target_dev,isCoarse, isLocked); + obj.resonator_tune_speed = user_speed; +% parfor i = 1:500 +% obj.tune(setpoint,target_dev,isCoarse); +% end end - function TuneCoarse(obj, setpoint) - %TuneCoarse moves the laser to the target frequency + function TuneCoarse(obj, setpoint) + %TuneCoarse moves the laser to the target frequency (THz) % % It assumes the laser is already close enough to not % require changing of the OPO temperature to reach the target. @@ -304,9 +313,30 @@ function TuneCoarse(obj, setpoint) % the cavity piezo. % % setpoint = setpoint in nm - obj.cwaveHandle.coarse_tune(); - target_dev = 0.2; - obj.tune(setpoint,target_dev); + %obj.cwaveHandle.setWLM_gains(20,150); + %obj.cwaveHandle.coarse_tune(); + + dlgs = questdlg('Tune with OPO Cavity (Open Loop) or Reference Cavity (Closed Loop)?', ... + 'Tuning Warning', ... + 'OPO Cavity','Reference Cavity','Reference Cavity'); + % Handle response + switch dlgs + case 'OPO Cavity' + isLocked = false; + obj.MaxEtalon = 50; %25; %25; + obj.MinEtalon = -50; %-1; %-25; + case 'Reference Cavity' + isLocked = true; + obj.MaxEtalon = 15; + obj.MinEtalon = -10; + end + target_dev = 0.000001; + isCoarse = true; + user_speed = obj.resonator_tune_speed; + obj.resonator_tune_speed = 0.1; + obj.tune( obj.c/setpoint,target_dev,isCoarse,isLocked); + obj.resonator_tune_speed = user_speed; + %include error checks for power and clamping end function TunePercent(obj, target) @@ -334,6 +364,35 @@ function TunePercent(obj, target) obj.updateStatus(); % Get voltage of resonator end + function wl = TuneRefPercent(obj, target) + %TunePercent sets the resonator or the opo cavity piezo percentage + %ref cavity has fsr = 10GHz, opo cavity has fsr = 40 GHz + % For both cavties spectral drift for ~10 MHz steps is about 5-7 MHz + % + % percent = desired piezo percentage from 1 to 100 (float type) + %This is the OPO resonator + assert(~isempty(obj.cwaveHandle)&&isobject(obj.cwaveHandle) && isvalid(obj.cwaveHandle),'no cwave handle') + assert(target>=0 && target<=100,'Target must be a percentage') + %set opo cavity to tuning mode + if (obj.cwaveHandle.get_regopo() ~= 2) + %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,4) + obj.cwaveHandle.set_regopo(2); + end + % tune at a limited rate per step + currentPercent = obj.GetPercent; + numberSteps = floor(abs(currentPercent-target)/obj.resonator_tune_speed); + direction = sign(target-currentPercent); + for i = 1:numberSteps + %tstart = tic; + obj.cwaveHandle.tune_ref_cavity(currentPercent+(i)*direction*obj.resonator_tune_speed); + wl(i) = obj.wavemeterHandle.getWavelength; + %telapsed(i+1) = toc(tstart); + end + obj.cwaveHandle.tune_ref_cavity(target); + obj.resonator_percent = obj.GetPercent(); + obj.updateStatus(); % Get voltage of resonator + end + function updateStatus(obj) % Get status report from laser and update a few fields tic @@ -436,10 +495,46 @@ function updateStatus(obj) end function set.target_wavelength(obj,val) - if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN - if obj.internal_call; obj.target_wavelength = val; return; end - obj.tune(val); - end + %edite 10/30/19 note sure why this is read only??? + %if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN + %if obj.internal_call; obj.target_wavelength = val; return; + %else + obj.target_wavelength = eval(val); + %end + if strcmp(val,''); return; end + %target_dev = 0.000001; + %isCoarse = true; + %isLocked = false; + + + %obj.tune(obj.target_wavelength,target_dev,isCoarse,isLocked); + obj.TuneCoarse(obj.c/obj.target_wavelength); + +% obj.centerThickEtalon; +% if abs(obj.target_wavelength-obj.getWavelength) > abs(obj.MaxEtalon_wl-obj.MinEtalon_wl) +% % need to add warning option allowsing user to exit +% % this is a very costly operation +% dlg = questdlg('Target wavelength exceeds tuning etalon and OPO range (> 0.2 nm)! Tuning will be very slow. Do you wish to continue with tuning?', ... +% 'Tuning Warning', ... +% 'Continue Tuning','Abort','Abort'); +% % Handle response +% switch answer +% case 'Tune' +% obj.cwaveHandle.target_wavelength = obj.target_wavelength + 1; +% obj.cwaveHandle.set_target_wavelength(); +% pause(30) +% obj.cwaveHandle.target_wavelength = obj.target_wavelength; +% obj.cwaveHandle.set_target_wavelength(); +% case 'Abort' +% return +% case 'Abort' +% return +% end +% %elseif abs(obj.target_wavelength-obj.getWavelength) < abs(obj.MaxEtalon-obj.MinEtalon) +% else +% obj.TuneCoarse(obj.target_wavelength); +% end + end function abort = centerThickEtalon(obj) %add functionality later. This method will initialzie the From 753e48d227c4c1edf21679f1e116a77e92261851 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:38:43 -0500 Subject: [PATCH 40/71] Added WLM_tune, etalon tune and set methods, updated centerThickEtalon --- Modules/+Sources/CWave.m | 89 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 1eb6e2e95..165a61a92 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -32,15 +32,16 @@ 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... - 'resonator_tune_speed'}; + 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep'}; show_prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... + 'MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep'... 'resonator_tune_speed'}; readonly_prefs = {'tuning','etalon_lock','opo_stepper','opo_temp',... 'shg_stepper', 'shg_temp','thin_etalon','opo_lock','shg_lock',... - 'pump_emission','ref_temp'}; + 'pump_emission','ref_temp','MidEtalon_wl'}; end properties(SetObservable,GetObservable) enabled = Prefs.Boolean(); @@ -76,7 +77,11 @@ cwave_ip = Sources.CWave.no_server; pulseStreamer_ip = Sources.CWave.no_server; wavemeter_ip = Sources.CWave.no_server; + EtalonStep=''; target_wavelength; + MinEtalon_wl = '0'; + MaxEtalon_wl = '.25'; + end properties(SetAccess=private) @@ -285,7 +290,29 @@ function tune(obj, setpoint,target_dev,coarse,lock) obj.setpoint = setpoint; end - function TuneSetpoint(obj,setpoint) + function WLM_tune(obj,setpoint,target_dev) + switch nargin + case 1 + target_dev = 0.000001; + end + obj.cwaveHandle.fine_tune(); + obj.cwaveHandle.setWLM_gains(obj.pWLM_gain,obj.iWLM_gain); + obj.cwaveHandle.set_target_deviation(target_dev); + obj.cwaveHandle.set_pid_target_wavelength(setpoint); + measured_wavelength = obj.wavemeterHandle.getWavelength(); + while abs(measured_wavelength - setpoint) > target_dev + obj.cwaveHandle.WLM_PID_Compute(measured_wavelength); + if obj.wavemeterHandle.getExposure() > 100 + delay = obj.wavemeterHandle.getExposure()/1000; %in seconds + pause(delay) + else + pause(0.0001) %(was 0.001 s) + end + measured_wavelength = obj.wavemeterHandle.getWavelength(); + end + end + + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in THz %obj.cwaveHandle.fine_tune(); @@ -537,10 +564,62 @@ function updateStatus(obj) end function abort = centerThickEtalon(obj) - %add functionality later. This method will initialzie the - %etalon to the center of its tuning range. + dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... + 'Centering Etalon Warning', ... + 'Yes, Continue Tuning','No, Abort','No, Abort'); + % Handle response + switch dlgs + case 'Yes, Continue Tuning' + + if abs(obj.MaxEtalon_wl-obj.MinEtalon_wl) > obj.MaxThickEtalonRange + dlgs2 = questdlg('Exiting Tuning. User Selected Etalon range exceeds thick etalon range. Difference bewteen MaxEtalon_wl and MinEtalon_wl should be less than 0.2 nm.', ... + 'Thick Etalon Range Warning', ... + 'Reselect MaxEtalon_wl and MinEtalon_wl','Reselect MaxEtalon_wl and MinEtalon_wl'); + abort = true; + return; + else + obj.MidEtalon_wl = obj.MinEtalon_wl + abs(obj.MaxEtalon_wl-obj.MinEtalon_wl)/2; + obj.etalon_pid(obj.MidEtalon_wl); + abort = false; + end + case 'No, Abort' + abort = true; + return; + end + end + function set.MaxEtalon_wl(obj,val) + a = eval(val); + obj.MaxEtalon_wl = a; + end + function set.MinEtalon_wl(obj,val) + a = eval(val); + obj.MinEtalon_wl = a; + end +% + function set.EtalonStep(obj,val) + obj.EtalonStep = eval(val); + %disp(val); + %obj.tune_etalon; + obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); + pause(obj.EtalonMeasureDelay); + %obj.updateStatus; + end + + function tune_etalon(obj) + obj.cwaveHandle.tune_thick_etalon(obj.EtalonStep); + %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); + end + + function set_regopo(obj,val) + obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,val); + end + + function val = get_regopo(obj) + val = obj.cwaveHandle.get_regopo; + end + function delete(obj) obj.cwaveHandle.delete() obj.PulseStreamerHandle.delete() From 0750bf6cd24b666e371418ebf3e2496ee0ab8d37 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:44:22 -0500 Subject: [PATCH 41/71] Added tune percent range: scan cavity to search for res manually --- Modules/+Sources/CWave.m | 98 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 165a61a92..d50406b37 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -32,13 +32,13 @@ 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... - 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep'}; + 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep','tunePercentRange'}; show_prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... 'MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep'... - 'resonator_tune_speed'}; + 'resonator_tune_speed', 'tunePercentRange'}; readonly_prefs = {'tuning','etalon_lock','opo_stepper','opo_temp',... 'shg_stepper', 'shg_temp','thin_etalon','opo_lock','shg_lock',... 'pump_emission','ref_temp','MidEtalon_wl'}; @@ -79,6 +79,7 @@ wavemeter_ip = Sources.CWave.no_server; EtalonStep=''; target_wavelength; + tunePercentRange = ''; MinEtalon_wl = '0'; MaxEtalon_wl = '.25'; @@ -619,6 +620,99 @@ function set_regopo(obj,val) function val = get_regopo(obj) val = obj.cwaveHandle.get_regopo; end + + function set.tunePercentRange(obj,val) + + obj.tunePercentRange = eval(val); + if (strcmp( val,'')) + return + end + + dlgs = questdlg('Tune with OPO Cavity (Open Loop) or Reference Cavity (Closed Loop)?', ... + 'Tuning Warning', ... + 'OPO Cavity','Reference Cavity','Reference Cavity'); + % Handle response + switch dlgs + case 'OPO Cavity' + isLocked = false; + case 'Reference Cavity' + isLocked = true; + end + + if (isLocked == true) + while ( obj.get_regopo() ~= 2) + obj.set_regopo(2); + pause(1); + disp('regopo'); + obj.get_regopo + disp('end iteration') + end + elseif (isLocked == false) + obj.set_regopo(4); + while ( obj.get_regopo() ~= 4) + obj.set_regopo(4); + pause(1); + disp('regopo'); + obj.get_regopo + disp('end iteration') + end + end + tuneRange = obj.tunePercentRange; + + %Tune to opo center + str1 = 'Please wait while cavity tunes to'; + str = strcat(str1, ' 50%.'); + dlg = msgbox(str,mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + if (isLocked == true) + obj.TuneRefPercent(50); + elseif (isLocked == false) + obj.TunePercent(50); + end + delete(dlg); + + %Tune to low end + str = strcat(str1, sprintf(' %.2f%%',tuneRange(1))); + dlg = msgbox(str,mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + if (isLocked == true) + obj.TuneRefPercent(tuneRange(1)); + elseif (isLocked == false) + obj.TunePercent(tuneRange(1)); + end + delete(dlg); + + %Tune to high end + str = strcat(str1, sprintf(' %.2f%%',tuneRange(2))); + dlg = msgbox(str,mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + if (isLocked == true) + obj.TuneRefPercent(tuneRange(2)); + elseif (isLocked == false) + obj.TunePercent(tuneRange(2)); + end + delete(dlg); + + %Tune back to center + str1 = 'Please wait while cavity tunes to'; + str = strcat(str1, ' 50%.'); + dlg = msgbox(str,mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + if (isLocked == true) + obj.TuneRefPercent(50.0); + elseif (isLocked == false) + obj.TunePercent(50.0); + end + delete(dlg); + end function delete(obj) obj.cwaveHandle.delete() From 4f8a615a41988b825a2810e876efe72edd38bacc Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:47:37 -0500 Subject: [PATCH 42/71] opo_pid control method introduced. --- Modules/+Sources/CWave.m | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index d50406b37..6696efa23 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -719,5 +719,89 @@ function delete(obj) obj.PulseStreamerHandle.delete() obj.wavemeterHandle.delete() end + + function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = opo_pid(obj,setpoint,tolerance) + i=0; + kp_slow = 200; + ki_slow = 1; + kd_slow = 0; + kp_fast = 1250;%1000; %.1; %kcr = 5510, Pcr = 6.748-3.3046 = 3.4434 + ki_fast = 1250; %200; %.4; + kd_fast = 0; + obj.windupGuardmax = obj.OPOwindupGuardmax; + obj.windupGuardmin = obj.OPOwindupGuardmin; + + if (obj.cwaveHandle.get_regopo ~= 4) + obj.cwaveHandle.set_regopo(4); + %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,4) + end + + curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. + ctrl = 0; + p_term = 0; + i_term = 0; + d_term = 0; + Error = []; + Dt = []; + IntError = []; + Control = []; + Measured = []; + while (abs(curr_error) > tolerance ) + tic + measured = obj.getWavelength(); + initial_percent = obj.GetPercent(); + if i == 0 + dt = 0; + prev_error = 0; + int_error = 0; + curr_error = setpoint - measured; + else + curr_error = setpoint - measured; + end + i=i+1; + + %slow control + if abs(curr_error) > 0.00125 + + [ctrl,prev_error,int_error,p_term,i_term,d_term] = obj.pid_update(curr_error,prev_error,int_error,kp_slow,ki_slow,kd_slow,dt); + if (initial_percent+ctrl < obj.MinPercent) + obj.TunePercent(obj.MinPercent); + elseif (initial_percent+ctrl > obj.MaxPercent) + obj.TunePercent(obj.MaxPercent); + else + obj.TunePercent(initial_percent+ctrl); + end + dt = toc; + %fast control + elseif abs(curr_error) > tolerance + j = 0; + if j == 0 + int_error = 0; + j = j+1; + end + + [ctrl,prev_error,int_error,p_term,i_term,d_term] = obj.pid_update(curr_error,prev_error,int_error,kp_fast,ki_fast,kd_fast,dt); + delay = obj.wavemeterHandle.getExposure()/1000 + 0.010; %in seconds + pause(delay) + if (initial_percent+ctrl < obj.MinPercent) + obj.cwaveHandle.tune_opo_cavity(obj.MinPercent); + elseif (initial_percent+ctrl > obj.MaxPercent) + obj.cwaveHandle.tune_opo_cavity(obj.MaxPercent); + else + obj.cwaveHandle.tune_opo_cavity(initial_percent+ctrl); + end + dt = toc; + end + + Dt(i) = dt; + Error(i) = curr_error; + IntError(i) = int_error; + Control(i) = ctrl; + Measured(i) = measured; + P_term(i) = p_term; + I_term(i) = i_term; + D_term(i) = d_term; + end + end end end \ No newline at end of file From 3b2e7b1962ebaeec73dda9a1b83f76c9fd58afe0 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:50:02 -0500 Subject: [PATCH 43/71] pid_update control method introduced. --- Modules/+Sources/CWave.m | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 6696efa23..edb686959 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -803,5 +803,46 @@ function delete(obj) D_term(i) = d_term; end end + + function [ctrl,prev_error,int_error,p_term,i_term,d_term] = pid_update(obj, curr_error,prev_error, int_error, kp,ki,kd,dt) + + % integration + int_error = int_error + (curr_error * dt); + + % integration windup guarding + if (int_error < obj.windupGuardmin) + int_error = obj.windupGuardmin; + saturation = 1; + elseif (int_error > obj.windupGuardmax) + int_error = obj.windupGuardmax; + saturation = 1; + else + saturation = 0; + end + + if ((sign(curr_error) == sign(prev_error)) && (saturation == 1)) + int_error = 0; + end + + % differentiation + if dt == 0 + int_error = 0; + diff = 0; + else + diff = ((curr_error - prev_error) / dt); + end + + % scaling + p_term = (kp * curr_error); + i_term = (ki * int_error); + d_term = (kd * diff); + + % summation of terms + ctrl = p_term + i_term + d_term; + + % save current error as previous error for next iteration + prev_error = curr_error; + end + %%%%%%%%%%%% end end \ No newline at end of file From 944bdf104b38742e4633b1a89f2e12a0a4f16f03 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:51:48 -0500 Subject: [PATCH 44/71] etalon_pid control method introduced. --- Modules/+Sources/CWave.m | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index edb686959..b4dfe52ee 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -804,6 +804,102 @@ function delete(obj) end end + function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = etalon_pid(obj,setpoint,tolerance,kp,ki,kd) + + obj.windupGuardmax = obj.EtaWindupGuardmax; + obj.windupGuardmin = obj.EtaWindupGuardmin; + + switch nargin + case 2 + tolerance = 0.005; + kp = 200; %was 500 on 11/6/19 noticed it has strong kick back sometimes when near edged of etalon. + ki = 100; + kd = 0; + case 3 + kp = 200; %was 500 on 11/6/19 noticed it has strong kick back sometimes + ki = 100; + kd = 0; + end + + i=0; + %if (obj.cwaveHandle.get_regopo ~= 4) + % obj.cwaveHandle.set_regopo(4); + % %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,4) + %end + + curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. + ctrl = 0; + p_term = 0; + i_term = 0; + d_term = 0; + Error = []; + Dt = []; + IntError = []; + Control = []; + Measured = []; + + while (abs(curr_error) > tolerance ) + tic + measured = obj.getWavelength(); + if i == 0 + dt = 0; + prev_error = 0; + int_error = 0; + curr_error = setpoint - measured; + else + curr_error = setpoint - measured; + end + i=i+1; + + if abs(curr_error) > tolerance %was elseif + j = 0; + if j == 0 + int_error = 0; + j = j+1; + end + + [ctrl,prev_error,int_error,p_term,i_term,d_term] = obj.pid_update(curr_error,prev_error,int_error,kp,ki,kd,dt); + if obj.wavemeterHandle.getExposure() > 25 % was 100 + delay = obj.wavemeterHandle.getExposure()/1000+0.025; %in seconds + pause(delay) + else + if (obj.get_regopo == 2) + pause(0.075) %(was 0.001 s) + elseif (obj.get_regopo == 4) + %pause(obj.wavemeterHandle.getExposure()/1000+0.025) + pause(0.001); %pause(0.025) + end + end + if (ctrl < obj.MinEtalon) + obj.cwaveHandle.tune_thick_etalon(obj.MinEtalon); + Control(i) = obj.MinEtalon; + elseif (ctrl > obj.LocalMinEtalon & ctrl < 0) + obj.cwaveHandle.tune_thick_etalon(obj.LocalMinEtalon); + Control(i) = obj.MinEtalon; + elseif (ctrl > obj.MaxEtalon) + obj.cwaveHandle.tune_thick_etalon(obj.MaxEtalon); + Control(i) = obj.MaxEtalon; + elseif (ctrl < obj.LocalMaxEtalon & ctrl > 0) + obj.cwaveHandle.tune_thick_etalon(obj.LocalMaxEtalon); + Control(i) = obj.LocalMaxEtalon; + else + obj.cwaveHandle.tune_thick_etalon(ctrl); + Control(i) = ctrl; + end + dt = toc; + + end + + Dt(i) = dt; + Error(i) = curr_error; + IntError(i) = int_error; + Measured(i) = measured; + P_term(i) = p_term; + I_term(i) = i_term; + D_term(i) = d_term; + end + end + function [ctrl,prev_error,int_error,p_term,i_term,d_term] = pid_update(obj, curr_error,prev_error, int_error, kp,ki,kd,dt) % integration From f04dc109fef52ed24bc51b8d0e212fbc337c3888 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:55:51 -0500 Subject: [PATCH 45/71] added etalon sstepper and powerStatus methods. --- Modules/+Sources/CWave.m | 153 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index b4dfe52ee..cc8fbf744 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -562,7 +562,160 @@ function updateStatus(obj) % else % obj.TuneCoarse(obj.target_wavelength); % end + end + + function [currentSHG_Power, powerSHG_status, total_step,exit] = EtalonStepper(obj ,step, delay_val) + %step etalon + direction = sign(step); + obj.cwaveHandle.tune_thick_etalon(step); + exit = false; + %correct for excessive stick-slip motion.... + i =1; + total_step = 0; + [currentSHG_Power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + while currentSHG_Power < obj.cwaveHandle.SHG_MinPower + if i == 1 + step = 5; + elseif i == 2 + step = 10; + elseif i == 3 + step = 15; + elseif i == 4 + step = 20; + elseif i == 5 + step = 25; + elseif i == 6 + step = 50; + elseif i > 6 + step = 50; + end + i = i+1; + if i >= 10 + return; + end + +% if currentSHG_Power < obj.cwaveHandle.SHG_MinPower + stepSize = -direction*step; + %sprintf('%i',stepSize); + %obj.EtalonStep = Stepsize; + obj.cwaveHandle.tune_thick_etalon(stepSize); + pause(delay_val); + total_step = stepSize + total_step; + exit = true; +% if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) +% wl_wm = obj.getWavelength; +% elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) +% wl_wm = NaN; +% end +% end + [currentSHG_Power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + end end + + function [wm_wl,wm_power,wm_exptime,SHG_power] = powerStatus(obj, tol,delay_val) + i = 0; + maxj_interation = 10; + MaxExposuretime = 1500; + obj.wavemeterHandle.setExposureMode(false); % manually set exposure + obj.wavemeterHandle.setExposure(1) % set exposure to 1 ms + obj.wavemeterHandle.setExposureMode(true); %sert exposure mode auto + prev_expTime = obj.wavemeterHandle.getExposure(); + curr_expTime = 100000*prev_expTime; + while ( curr_expTime <= (1-tol)*prev_expTime | curr_expTime >= (1+tol)*prev_expTime ) + i = i+1; + pause(delay_val) + if i > maxj_interation + obj.updateStatus + regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... + & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; + + regopo4_noEta_locked = obj.opo_stepper_lock & obj.opo_temp_lock... + & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; + + if (obj.cwaveHandle.get_regopo == 4) + [SHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + if( regopo4_locked == false) + dialog0 = msgbox('Error: CWave is not locked for regopo4. Refer to lock status to determine failing elements. Currently in OPO regulator mode 4.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog0); + error('CWave is not locked for regopo4. Refer to lock status to determine failing elements. Currently in OPO regulator mode 4.'); + elseif (regopo4_noEta_locked == true & obj.etalon_lock == false) + dialog1 = msgbox('Error: Etalon is not locked. Currently in OPO regulator mode 4.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog1); + error('Etalon is not locked. Currently in OPO regulator mode 4.'); + elseif (regopo4_locked == true & powerSHG_status == true) + dialog2 = msgbox('insufficient power from SHG.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog2); + disp('insufficient power from SHG.'); + end + end + + if (obj.cwaveHandle.get_regopo == 2) + if (obj.regopo4_locked == true & obj.etalon_lock == true & obj.shg_lock == false ) + dialog3 = msgbox('Error: SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog3); + error('SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') + elseif (obj.regopo4_locked == true & obj.etalon_lock == false & obj.shg_lock == true ) + dialog4 = msgbox('Error: Etalon cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + delete( dialog4); + error('Etalon cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') + elseif (obj.regopo4_locked == true & obj.etalon_lock == false & obj.shg_lock == false ) + dialog5 = msgbox('Error: Etalon and SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog5); + error('Etalon and SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') + end + end + + if( obj.wavemeterHandle.setExposure >= MaxExposuretime) + dialog6 = msgbox('Error: Dim emission. Check that light is well coupled into wave meter.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog6); + error('Dim emission. Check that light is well coupled into wave meter') + else + dialog7 = msgbox('Error: Large fluctuations in CWave power.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dialog7); + error('Large fluctuations in CWave power.') + end + + elseif ( (1+tol)*prev_expTime >= curr_expTime & curr_expTime >= (1-tol)*prev_expTime ) + [SHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + wm_exptime = obj.wavemeterHandle.getExposure(); + + if (powerSHG_status == false) + wm_wl = obj.getWavlength(); + wm_power = obj.wavemeterHandle.getPower(); + wm_exptime = obj.wavemeterHandle.getExposure(); + elseif (powerSHG_status == true) + wm_wl = NaN; + wm_power = NaN; + end + break; + end + end + end + function abort = centerThickEtalon(obj) dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... From 8e8f9c3f3073648cbb9353844a2b6a9c02ad8ae9 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 00:59:27 -0500 Subject: [PATCH 46/71] Updated centerThickEtalon to include autotune option. --- Modules/+Sources/CWave.m | 481 +++++++++++++++++++++++++++++++++------ 1 file changed, 416 insertions(+), 65 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index cc8fbf744..f3b079491 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -16,34 +16,60 @@ end properties(Constant,Hidden) no_server = 'No Server'; % Message when not connected + OPOwindupGuardmax= 2; %1.5 + OPOwindupGuardmin= -2; %-1.5 + EtaWindupGuardmax = 10000; %was 100 on 11/6/19 + EtaWindupGuardmin = -10000; % was -100 on 11/6/19 + MaxPercent = 99.5; % percent + MinPercent = 0.5; % percent MaxThickEtalonRange = 0.375; %nm + pWLM_gain = 10; %10; + iWLM_gain = 75 ; %75; + EtalonMeasureDelay = 1.5; %seconds + wmExposureTolerance = 0.05; % percent/100 + powerStatusDelay = 1; % seconds + timeoutSHG = 300; % seconds + timeoutThickEtalon = 300; %seconds + wmPower_min = 0; %units? end properties(Hidden) + MaxEtalon = 15; % in pm %maybe step these down to 15 look a little unstable when trying to ajdust thick etalon manually with 0.025nm steps + MinEtalon = -10;% in pm %maybe step this down to 15 + LocalMaxEtalon = 6; + LocalMinEtalon = -6; + windupGuardmax = 0; + windupGuardmin = 0; sOPO_power; sSHG_power; sPump_power; + ThickEtalonTolerance = 0.005; %nm end - properties(SetAccess=protected) range = [Sources.TunableLaser_invisible.c./[450, 650],Sources.TunableLaser_invisible.c./[900, 1300]]; end properties prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... - 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... - 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... - 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... - 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep','tunePercentRange'}; - show_prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... - 'opo_stepper','opo_temp','shg_stepper', 'shg_temp','thin_etalon',... - 'opo_lock','shg_lock','pump_emission','ref_temp','resonator_percent',... + 'opo_stepper_lock','opo_temp_lock','shg_stepper_lock', 'shg_temp_lock','thin_etalon_lock',... + 'opo_lock','shg_lock','pump_emission','ref_temp_lock','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... - 'MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','EtalonStep'... - 'resonator_tune_speed', 'tunePercentRange'}; - readonly_prefs = {'tuning','etalon_lock','opo_stepper','opo_temp',... - 'shg_stepper', 'shg_temp','thin_etalon','opo_lock','shg_lock',... - 'pump_emission','ref_temp','MidEtalon_wl'}; - end + 'resonator_tune_speed','tunePercentRange','MaxEtalon_wl','MinEtalon_wl',... + 'EtalonStep','MidEtalon_wl','OPO_power','SHG_power','Pump_power',... + 'TempRef','TempOPO', 'TempSHG','TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint'}; + show_prefs = {'target_wavelength','resonator_percent','EtalonStep','tunePercentRange',... + 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','tuning',... + 'enabled','wavelength_lock','etalon_lock','opo_stepper_lock','opo_temp_lock','shg_stepper_lock',... + 'shg_temp_lock','thin_etalon_lock','opo_lock','shg_lock','pump_emission','ref_temp_lock',... + 'etalon_percent','OPO_power','SHG_power','Pump_power','TempOPO','TempOPO_setpoint',... + 'TempSHG','TempSHG_setpoint','TempRef','TempRef_setpoint','PSline',... + 'pulseStreamer_ip','cwave_ip','wavemeter_ip'}; + readonly_prefs = {'tuning','etalon_lock','opo_stepper_lock','opo_temp_lock',... + 'shg_stepper_lock', 'shg_temp_lock','thin_etalon_lock','opo_lock','shg_lock',... + 'pump_emission','ref_temp_lock','MidEtalon_wl',... + 'OPO_power','SHG_power','Pump_power','TempRef','TempOPO', 'TempSHG',... + 'TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint'}; + end properties(SetObservable,GetObservable) + MidEtalon_wl = ''; enabled = Prefs.Boolean(); resonator_percent = Prefs.Double(0.00,'units','percent','min',0.00,'max',100.00); tuning = Prefs.Boolean(false, 'help_text','This is a readonly string.','readonly',true); @@ -54,15 +80,15 @@ resonator_tune_speed = Prefs.Double(0.5,'units','percent','min',0.001,'max',1); % percent per step etalon_lock = Prefs.Boolean('help_text','This is a readonly string.','readonly',true); etalon_percent = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - opo_stepper = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - opo_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - shg_stepper = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - shg_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - thin_etalon = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + opo_stepper_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + opo_temp_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + shg_stepper_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + shg_temp_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + thin_etalon_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); opo_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); shg_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); pump_emission = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); - ref_temp = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); + ref_temp_lock = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); wavelength_lock = Prefs.Boolean(); OPO_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); SHG_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); @@ -77,12 +103,11 @@ cwave_ip = Sources.CWave.no_server; pulseStreamer_ip = Sources.CWave.no_server; wavemeter_ip = Sources.CWave.no_server; + target_wavelength=''; + tunePercentRange = ''; %tunePercentRange = Prefs.DoubleArray(); EtalonStep=''; - target_wavelength; - tunePercentRange = ''; MinEtalon_wl = '0'; MaxEtalon_wl = '.25'; - end properties(SetAccess=private) @@ -90,12 +115,16 @@ wavemeterHandle cwaveHandle end - - methods(Access=private) function obj = CWave() obj.loadPrefs; + % while loop with poling to cehck that all drivers are loaded. + % if they are then run updateStatus and set initial conditions + % such as wavemeter continuous model alternatively set these to + % directly in the set.ip methods. + %obj.updateStatus; %updateStatus before cwave library loaded. + %can have it here. end function err = connect_driver(obj,propname,drivername,varargin) @@ -153,8 +182,6 @@ function blackout(obj) end % tunable laser methods - - % tunable laser methods function tune(obj, setpoint,target_dev,coarse,lock) % target in nm obj.tuning = true; @@ -313,6 +340,7 @@ function WLM_tune(obj,setpoint,target_dev) end end + function TuneSetpoint(obj,setpoint) %TuneSetpoint Sets the wavemeter setpoint % setpoint = setpoint in THz @@ -330,7 +358,7 @@ function TuneSetpoint(obj,setpoint) % end end - function TuneCoarse(obj, setpoint) + function TuneCoarse(obj, setpoint) %TuneCoarse moves the laser to the target frequency (THz) % % It assumes the laser is already close enough to not @@ -367,7 +395,7 @@ function TuneCoarse(obj, setpoint) %include error checks for power and clamping end - function TunePercent(obj, target) + function wl = TunePercent(obj, target) %TunePercent sets the resonator or the opo cavity piezo percentage %ref cavity has fsr = 10GHz, opo cavity has fsr = 40 GHz % For both cavties spectral drift for ~10 MHz steps is about 5-7 MHz @@ -378,6 +406,7 @@ function TunePercent(obj, target) assert(target>=0 && target<=100,'Target must be a percentage') %set opo cavity to tuning mode if (obj.cwaveHandle.get_regopo() ~= 4) + %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,4) obj.cwaveHandle.set_regopo(4); end % tune at a limited rate per step @@ -385,7 +414,10 @@ function TunePercent(obj, target) numberSteps = floor(abs(currentPercent-target)/obj.resonator_tune_speed); direction = sign(target-currentPercent); for i = 1:numberSteps + %tstart = tic; obj.cwaveHandle.tune_opo_cavity(currentPercent+(i)*direction*obj.resonator_tune_speed); + wl(i) = obj.wavemeterHandle.getWavelength; + %telapsed(i+1) = toc(tstart); end obj.cwaveHandle.tune_opo_cavity(target); obj.resonator_percent = obj.GetPercent(); @@ -421,7 +453,7 @@ function TunePercent(obj, target) obj.updateStatus(); % Get voltage of resonator end - function updateStatus(obj) + function updateStatus(obj) % Get status report from laser and update a few fields tic obj.locked = ~(obj.cwaveHandle.get_statusbits); @@ -522,12 +554,30 @@ function updateStatus(obj) end end - function set.target_wavelength(obj,val) - %edite 10/30/19 note sure why this is read only??? + %change to set_target_wavlength and make turn this into setmethod + %as defined in https://github.com/mwalsh161/CommandCenter/blob/dev/%2BBase/pref.m + %example of implementation: https://github.com/mwalsh161/CommandCenter/blob/dev/Modules/%2BImaging/debug.m#L55 + %f you're wondering where the set property is defined, it is in Base.pref - also worth reading until I get it onto the wiki to better understand what's happening: https://github.com/mwalsh161/CommandCenter/blob/dev/%2BBase/pref.m +% Matthew Feldman 5:16 PM +% Yea the latter. Thanks. But just for my own understanding the testSet method sets a value to a preference (even though there is only a print statemet in the body of the method)? Is this behavior explained in the pref.m link you just sent? +% Michael Walsh 5:25 PM +% it should be explained +% unlike MATLAB's set.prop methods, these set methods require you to return the value +% new messages +% so while testSet seems to only be doing an fprintf, the input val is returned as well +% function set.target_wavelength(obj,val) +% %if isnan(val.default); obj.target_wavelength = val; return; end % Short circuit on NaN +% if isnan(val.ui); obj.target_wavelength = val; return; end % Short circuit on NaN +% if obj.internal_call; obj.target_wavelength = val; return; end +% obj.tune(val); +% end + + function set.target_wavelength(obj,val) + %edite 10/30/19 note sure why this is read only??? %if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN %if obj.internal_call; obj.target_wavelength = val; return; %else - obj.target_wavelength = eval(val); + obj.target_wavelength = eval(val); %end if strcmp(val,''); return; end %target_dev = 0.000001; @@ -562,9 +612,9 @@ function updateStatus(obj) % else % obj.TuneCoarse(obj.target_wavelength); % end - end + end - function [currentSHG_Power, powerSHG_status, total_step,exit] = EtalonStepper(obj ,step, delay_val) + function [currentSHG_Power, powerSHG_status, total_step,exit] = EtalonStepper(obj ,step, delay_val) %step etalon direction = sign(step); obj.cwaveHandle.tune_thick_etalon(step); @@ -714,13 +764,12 @@ function updateStatus(obj) break; end end - end - - - function abort = centerThickEtalon(obj) + end + + function abort = centerThickEtalon(obj) dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... 'Centering Etalon Warning', ... - 'Yes, Continue Tuning','No, Abort','No, Abort'); + 'Yes, Continue Tuning','No, Please Autotune', 'No, Abort','No, Abort'); % Handle response switch dlgs case 'Yes, Continue Tuning' @@ -736,45 +785,344 @@ function updateStatus(obj) obj.etalon_pid(obj.MidEtalon_wl); abort = false; end + + case 'No, Please Autotune' + pstep = 25; + nstep = -25; + obj.updateStatus; + + PowerMeasureCondition_regopo2 = (obj.ref_temp_lock == true) & (obj.pump_emission == true) & ... + (obj.opo_lock == true) & (obj.thin_etalon_lock == true) & ... + (obj.shg_temp_lock == true) & (obj.shg_stepper_lock == true) & ... + (obj.opo_temp_lock == true) & (obj.opo_stepper_lock == true); + + PowerMeasureCondition_regopo4 = (obj.ref_temp_lock == true) & (obj.pump_emission == true) & ... + (obj.thin_etalon_lock == true) & (obj.shg_temp_lock == true) &... + (obj.shg_stepper_lock == true) & (obj.opo_temp_lock == true) & ... + (obj.opo_stepper_lock == true); + %(obj.etalon_lock == true) & (obj.shg_lock); + if (obj.cwaveHandle.get_regopo == 2 & PowerMeasureCondition_regopo2 == false) + obj.cwaveHandle.abort_tune; + error('Etalon not tunable. Check lock status of OPO elements.') + elseif (obj.cwaveHandle.get_regopo == 4 & PowerMeasureCondition_regopo4 == false) + obj.cwaveHandle.abort_tune; + error('Etalon not tunable. Check lock status of OPO elements.') + elseif (PowerMeasureCondition_regopo2 == true | PowerMeasureCondition_regopo4 | obj.locked) + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + if (currPower < obj.cwaveHandle.SHG_MinPower) + dlgs1 = questdlg('SHG power is very low (SHG is not lock)! Would you like to reoptimize SHG power?', ... + 'Yes, optimize SHG Power','No, retune etalon', 'No, Abort','No, Abort'); + % Handle response + switch dlgs1 + case 'Yes, optimize SHG Power' + % The CWave is slow at tuning, so message is useful until a non-blocking operation exists + dlgs2 = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + tic + obj.cwaveHandle.optimize_shg(); + while( (currPower < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) + obj.updateStatus; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + end + delete(dlgs2); + if(toc > obj.timeoutSHG) + dlgs3 = msgbox('Error: Re-optimizing of SHG timed out. Tune Manually.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs3); + obj.cwaveHandle.abort_tune; + error('Re-optimizing of SHG timed out. Tune Manually.') + end + case 'No, retune etalon' + % The CWave is slow at tuning, so message is useful until a non-blocking operation exists + dlgs4 = msgbox('Please wait while CWave relocks etalon.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + tic + obj.cwaveHandle.relock_etalon(); + while( (obj.etalon_lock == false) | toc <= obj.timeoutThickEtalon) + obj.updateStatus; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + end + delete(dlgs4); + if(toc > obj.timeoutThickEtalon) + dlgs5 = msgbox('Error: Retuning of thick etalon timed out. Tune Manually.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs5); + obj.cwaveHandle.abort_tune; + error('Retuning of thick etalon timed out. Tune Manually') + end + if (currPower < obj.cwaveHandle.SHG_MinPower | obj.shg_lock == false | obj.shg_temp_lock == false) + % The CWave is slow at tuning, so message is useful until a non-blocking operation exists + dlgs6 = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + tic + obj.cwaveHandle.optimize_shg(); + while( (currPower < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) + obj.updateStatus; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + end + delete(dlgs6); + if(toc > obj.obj.timeoutSHG) + dlgs7 = msgbox('Error: Re-optimizing of SHG timed out. Tune Manually.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs7); + obj.cwaveHandle.abort_tune; + error('Re-optimizing of SHG timed out. Tune Manually.') + end + end + case 'No, Abort' + abort = true; + return + end + + %prompt user to either manually + %tune first or to reset SHG + end + end + + j=0; + EtalonTotalStep = 0; + obj.updateStatus; + wm_exptime_c = wm_exptime_i; + wm_exptime_c = wm_exptime_i; + wm_lambda_c = wm_lambda_i; + + while ( (currPower > obj.cwaveHandle.SHG_MinPower) ) + obj.updateStatus; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [currPower, Status_powerSHG, EtalonTotalStep,exiting] = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); + pause(obj.EtalonMeasureDelay) + + disp('Enter +eta loop') + fprintf('Control power: %.8f\n',currPower); + fprintf('Initial Power: %.8f\n',powerSHG_i); + fprintf('lock status (1 is locked): %.8f\n',obj.locked); + fprintf('initial exposure: %.8f\n',wm_exptime_i); + fprintf('current exposure: %.8f\n',wm_exptime_c); + + if (currPower < obj.cwaveHandle.SHG_MinPower) + while(currPower < obj.cwaveHandle.SHG_MinPower) + direction = sign(EtalonTotalStep); + correction_step = direction*pstep; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [currPower, Status_powerSHG, EtalonTotalStep, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); + %obj.EtalonStep = nstep; + pause(obj.EtalonMeasureDelay) + obj.updateStatus; + end + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + %return; + else + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + obj.MaxEtalon_wl = sprintf('%.80f',wm_lambda_c); + %obj.MaxEtalon_wl = sprintf('%.80f',obj.getWavelength); + end +% if currPower > powerSHG_i +% powerSHG_i = currPower; +% wmPower_i = wmPower_c; +% end + %[wm_lambda,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + %currPower = obj.wavemeterHandle.getPower(); + %wm_exptime_c = obj.wavemeterHandle.getExposure(); + if ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) + del_wl = 1000*abs(wm_lambda_i-wl_lambda_c); % in pm + if (del_wl < EtalonTotalStep) + %maybe put obj.MaxEtalon_wl = + %sprintf('%.80f',wm_lambda_c); + %here + if wmPower_c < obj.wmPower_min + dlgs8 = msgbox('Error: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs3); + obj.cwaveHandle.abort_tune; + error('Re-optimizing of SHG timed out. Tune Manually.') + elseif (wmPower_c < wmPower_i/10 | wm_exptime_c > 10*wm_exptime_i) + dlgs9 = msgbox('Warning: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs3); + else + return; + end + elseif (del_wl > EtalonTotalStep) + currPower = -1; %renter loop + obj.MaxEtalon_wl = 'NaN'; + j = j+1; + elseif j>3 + dlgs10 = msgbox('Error: etalon stick. Reset manually.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete(dlgs10); + obj.cwaveHandle.abort_tune; + error('etalon stick. Reset etalon manually.') + %maybe replace error with + %dialog box to prompt user to + %adjust etalon mannually + + end + end + + end + + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + + k=0; + EtalonTotalStep = 0; + obj.updateStatus; + wm_exptime_c = wm_exptime_i; + wm_exptime_c = wm_exptime_i; + wm_lambda_c = wm_lambda_i; + + while ( currPower > obj.cwaveHandle.SHG_MinPower ) +% obj.updateStatus; +% %obj.EtalonStep = nstep; +% obj.cwaveHandle.tune_thick_etalon( +% sign = -1; +% +% %[currPower, powerSHG_status] = obj.EtalonStepper(sign,obj.EtalonMeasureDelay); +% pause(obj.EtalonMeasureDelay) + + obj.updateStatus; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [currPower, Status_powerSHG, EtalonTotalStep,exiting] = obj.EtalonStepper(nstep, obj.EtalonMeasureDelay); + pause(obj.EtalonMeasureDelay) + + disp('Enter -eta loop') + fprintf('Control power: %.8f\n',currPower); + fprintf('Initial Power: %.8f\n',powerSHG_i); + fprintf('lock status (1 is locked): %.8f\n',obj.locked); + fprintf('exposure initial: %.8f\n',wm_exptime_i); + fprintf('exposure control: %.8f\n',wm_exptime_c); + if (currPower < obj.cwaveHandle.SHG_MinPower) + while(currPower < obj.cwaveHandle.SHG_MinPower) +% %obj.EtalonStep = pstep; +% sign = 1; +% [currPower, powerSHG_status] = obj.EtalonStepper(sign,obj.EtalonMeasureDelay); +% pause(obj.EtalonMeasureDelay) +% obj.updateStatus; + + direction = sign(EtalonTotalStep); + correction_step = direction*pstep; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [currPower, Status_powerSHG, EtalonTotalStep, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); + %obj.EtalonStep = nstep; + pause(obj.EtalonMeasureDelay) + obj.updateStatus; + end + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + %return + else + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + obj.MinEtalon_wl = sprintf('%.80f',wm_lambda); + %obj.MinEtalon_wl = sprintf('%.80f',obj.getWavelength); + end + + +% if currPower > powerSHG_i +% powerSHG_i = currPower; +% end +% [wm_lambda,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(0.05,1); + %currPower = obj.wavemeterHandle.getPower(); + %wm_exptime_c = obj.wavemeterHandle.getExposure(); + if ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) + del_wl = 1000*abs(wm_lambda_i-wl_lambda_c); % in pm + if (del_wl < EtalonTotalStep) + %maybe put obj.MaxEtalon_wl = + %sprintf('%.80f',wm_lambda_c); + %here + if wmPower_c < obj.wmPower_min + dlgs11 = msgbox('Error: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs11); + obj.cwaveHandle.abort_tune; + error('Re-optimizing of SHG timed out. Tune Manually.') + elseif (wmPower_c < wmPower_i/10 | wm_exptime_c > 10*wm_exptime_i) + dlgs12 = msgbox('Warning: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete( dlgs12); + else + return; + end + elseif (del_wl > EtalonTotalStep) + currPower = -1; %renter loop + obj.MinEtalon_wl = 'NaN'; + k = k+1; + elseif k>3 + dlgs13 = msgbox('Error: etalon stick. Reset manually.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + %delete(findall(dlg,'tag','OKButton')); + drawnow; + %delete(dlgs13); + obj.cwaveHandle.abort_tune; + error('etalon stick. Reset etalon manually.') + %maybe replace error with + %dialog box to prompt user to + %adjust etalon mannually + + end + end + end +%%%%%%%%%%%%%%%%%%%%%%%% End of 'No, Please Autotune' case %%%%%%%%%%%%% + + case 'No, Abort' abort = true; - return; + return end - - end - - function set.MaxEtalon_wl(obj,val) + + end + + function set.MaxEtalon_wl(obj,val) a = eval(val); obj.MaxEtalon_wl = a; - end - function set.MinEtalon_wl(obj,val) + end + function set.MinEtalon_wl(obj,val) a = eval(val); obj.MinEtalon_wl = a; - end + end % - function set.EtalonStep(obj,val) + function set.EtalonStep(obj,val) obj.EtalonStep = eval(val); %disp(val); %obj.tune_etalon; obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); pause(obj.EtalonMeasureDelay); %obj.updateStatus; - end + end - function tune_etalon(obj) + function tune_etalon(obj) obj.cwaveHandle.tune_thick_etalon(obj.EtalonStep); %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); - end + end - function set_regopo(obj,val) + function set_regopo(obj,val) obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,val); - end + end - function val = get_regopo(obj) + function val = get_regopo(obj) val = obj.cwaveHandle.get_regopo; - end - - function set.tunePercentRange(obj,val) + end + + function set.tunePercentRange(obj,val) obj.tunePercentRange = eval(val); if (strcmp( val,'')) @@ -866,13 +1214,14 @@ function set_regopo(obj,val) end delete(dlg); end - - function delete(obj) - obj.cwaveHandle.delete() - obj.PulseStreamerHandle.delete() - obj.wavemeterHandle.delete() - end + function delete(obj) + obj.cwaveHandle.delete(); + obj.PulseStreamerHandle.delete(); + obj.wavemeterHandle.delete(); + end + + %%%%%%%%%%%% function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = opo_pid(obj,setpoint,tolerance) i=0; kp_slow = 200; @@ -957,7 +1306,7 @@ function delete(obj) end end - function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = etalon_pid(obj,setpoint,tolerance,kp,ki,kd) + function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = etalon_pid(obj,setpoint,tolerance,kp,ki,kd) obj.windupGuardmax = obj.EtaWindupGuardmax; obj.windupGuardmin = obj.EtaWindupGuardmin; @@ -1093,5 +1442,7 @@ function delete(obj) prev_error = curr_error; end %%%%%%%%%%%% + + end end \ No newline at end of file From 27dfbe50feabf81c07b38eaafac27c9f776b4949 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 01:04:42 -0500 Subject: [PATCH 47/71] Added setWLM_gains, updated CHeckErrorStatus, getStatus_bits. --- Modules/+Drivers/CWave.m | 143 ++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 46 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index b9006b719..449f4e34e 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -26,7 +26,8 @@ shg_lock_stat = false(1); etalon_lock_stat = false(1); laser_emission_stat = false(1); - ref_temp_stat = false(1); + ref_temp_stat = false(1); + CurrentLaserPWR; end properties(Constant,Hidden) @@ -44,8 +45,15 @@ ComputerArch = 'arch'; ConnectCwave = 'cwave_connect'; DLL_Version= 'DLL_Version'; - DLL_identity = 22; + DLL_identity = 22; %20; Admin = 'admin_elevate'; + TempRef = 'tref_is'; + TempOPO = 'topo_is'; + TempSHG1 = 'tshg_is1'; + TempSHG2 = 'tshg_is2'; + TempOPO_sp = 'topo_set'; + TempSHG_sp = 'tshg_set'; + TempRef_sp = 'tref_set'; UpdateStatus = 'cwave_updatestatus'; Get_IntValue = 'get_intvalue'; Get_floatValue = 'get_floatvalue'; @@ -72,6 +80,8 @@ WLM_EtalonSteps = 'WLM_etalonsteps'; WLM_PiezoSteps = 'WLM_piezosteps'; WLM_targetdeviation = 'WLM_targetdeviation'; + WLM_pid_p = 'WLM_pid_p'; + WLM_pid_i = 'WLM_pid_i'; Ext_SetCommand = 'ext_set_command'; ExtGet_IntValue = 'ext_get_intvalue'; ExtGet_FloatValue = 'ext_get_floatvalue'; @@ -92,12 +102,12 @@ ThickEtalon_Piezo_hr = 'thicketa_rel_hr'; ThickEtalon_Piezo = 'thicketa_rel'; Piezo_maxBit = 65535/100; - Laser_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - Laser_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) - OPO_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - OPO_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) - SHG_MaxPower = 1000000; %dummy value. value needs to be calibrated (testing needed) - SHG_MinPower = 0; %dummy value. value needs to be calibrated (testing needed) + Laser_MaxPower = 5000; %dummy value. value needs to be calibrated (testing needed) + Laser_MinPower = 1000; %dummy value. value needs to be calibrated (testing needed) + OPO_MaxPower = 10000; %dummy value. value needs to be calibrated (testing needed) + OPO_MinPower = 100; %dummy value. value needs to be calibrated (testing needed) + SHG_MaxPower = 10000; %dummy value. value needs to be calibrated (testing needed) + SHG_MinPower = 100; %was 100%dummy value. value needs to be calibrated (testing needed) end %% Signleton Method methods(Static) @@ -228,15 +238,15 @@ assert(status==0,'Setting target wavelength failed'); case obj.ShutterSHG %0: integer value set, 1: integer value not set - assert(status==0,'SHG shutter failed') + assert(status==0,'SHG shutter failed'); case obj.ShutterLaser %0: integer value set, 1: integer value not set - assert(status==0,'Laser shutter failed') + assert(status==0,'Laser shutter failed'); end % 0== integer value set, 1= integer value not set assert(status == 0, 'CWAVE Error: Int value not set'); case obj.SetRefOpoExtramp - assert(status == 0, 'Opo Piezo was not set to ramp.') + assert(status == 0, 'Opo Piezo was not set to ramp.'); case obj.Is_Ready % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing assert(status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); @@ -261,38 +271,41 @@ assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); case obj.LaserPower % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: Laser power not within standard operating range.']); + if (obj.CurrentLaserPWR > obj.Laser_MaxPower) + assert(status == 0,'CWAVE Error: Laser power not within standard operating range. Lower Power Immediately!!!'); + end + disp('CWAVE Warning: Laser power not within standard operating range.'); case obj.OPO_Power % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: OPO power not within standard operating range.']); + disp('CWAVE Warning: OPO power not within standard operating range.'); case obj.SHG_Power % 0=update succeeded, 1=update failed - assert(status == 0, ['CWAVE Error: SHG power not within standard operating range.']); + disp('CWAVE Warning: SHG power not within standard operating range.'); case obj.StatusReport if (obj.opo_stepper_stat == 1) - disp('Error OPO stepper not locked') + disp('Error OPO stepper not locked'); elif (obj.opo_temp_stat == 1) - disp('OPO temperature not locked') + disp('OPO temperature not locked'); elif (obj.shg_stepper_stat == 1) - disp('SHG stepper not locked') + disp('SHG stepper not locked'); elif (obj.shg_temp_stat == 1) - disp('SHG temp not locked') + disp('SHG temp not locked'); elif (obj.thin_etalon_stat == 1) - disp('Thin etalon not locked') + disp('Thin etalon not locked'); elif (obj.opo_lock_stat == 1 && obj.get_intvalue(RegOPO_On) == 2) - disp('OPO cavity piezo not locked.') + disp('OPO cavity piezo not locked.'); elif (obj.shg_lock_stat == 1) - disp('SHG cavity piezo not locked') + disp('SHG cavity piezo not locked'); elif (obj.etalon_lock_stat == 1) - disp('thick etalon not locked') + disp('thick etalon not locked'); elif (obj.laser_emission_stat == 1) - disp('No Pump emission! Unshutter Millenia Edge!') + disp('No Pump emission! Unshutter Millenia Edge!'); elif (obj.ref_temp_stat == 1) - disp('Reference cavity temperature is not locked!!!') + disp('Reference cavity temperature is not locked!!!'); end % 0=update succeeded, 1=update failed - disp('CWAVE Warning: All elements are not stable and/or locked.'); + %disp('CWAVE Warning: All elements are not stable and/or locked.'); case obj.LaserStatus % 0=update failed, 1==update succeeded assert(status == 0, ['Insufficient Laser power. Check that pump laser is active and that the laser shutter is open']); @@ -329,7 +342,7 @@ %% connect to device status = obj.LibraryFunction(obj.ConnectCwave, ip); % mitigate bug in DLL, first connection attempt might fail -> retry - if (status == 0) + if (status == 1) status = obj.LibraryFunction(obj.ConnectCwave, ip); end end @@ -472,7 +485,34 @@ %% Writable Wavelength stabilization parameters are listed above in get_intvalue function comments status = obj.LibraryFunction(obj.Set_IntValue,cmd, value); end - + + function tref = get_tref(obj) + tref = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempRef); + tref = tref/1000; % Celcius + end + function topo = get_topo(obj) + %topo = get_intvalue(obj.TempOPO); + topo = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempOPO); + topo = topo/1000; % Celcius + end + function tshg = get_tshg(obj) + t_shg1 = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempSHG1); %mk + t_shg2 = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempSHG2); %mk + tshg = (t_shg1 + t_shg2)/2000; %Celcius + end + function tref = get_tref_sp(obj) + tref = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempRef_sp); + tref= tref/1000; % Celcius + end + function topo = get_topo_sp(obj) + topo = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempOPO_sp); + topo = topo/1000; % Celcius + end + function tshg = get_tshg_sp(obj) + tshg = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempSHG_sp); + tshg = tshg/1000; % Celcius + end + function optimize_status = is_ready(obj) %Description: Checks if all C-Wave routines have finished and the C-Wave produces the desired output %Arguments: none @@ -507,26 +547,29 @@ status = obj.LibraryFunction(obj.SetCommand,cmd); end - function [status,laser_power] = get_photodiode_laser(obj) + function [laser_power,status] = get_photodiode_laser(obj) % Description: Reads the current laser power (what unit??) % Arguments: none % Returns: Returns the laser photodiode value %% Read laser power laser_power = calllib(obj.LibraryName,obj.LaserPower); + %laser_power = calllib('CWAVE_DLL','get_photodiode_laser'); if( laser_power > obj.Laser_MaxPower || laser_power < obj.Laser_MinPower) status = 1; else status = 0; end - obj.CheckErrorStatus(status,obj.LaserPower) + obj.CurrentLaserPWR = laser_power; + obj.CheckErrorStatus(status,obj.LaserPower); end - function [status,opo_power] = get_photodiode_opo(obj) + function [opo_power,status] = get_photodiode_opo(obj) % Description: Reads the current OPO infrared power % Arguments: none % Returns: Returns the infrared output power in mW %% Read IR opo power opo_power = calllib(obj.LibraryName,obj.OPO_Power); + %opo_power = calllib('CWAVE_DLL','get_photodiode_opo'); if (opo_power > obj.OPO_MaxPower || opo_power < obj.OPO_MinPower) status = 1; else @@ -535,7 +578,7 @@ obj.CheckErrorStatus(status,obj.OPO_Power); end - function [status, shg_power] = get_photodiode_shg(obj) + function [shg_power,status] = get_photodiode_shg(obj) % Description: Reads the current (second harmonic generator) SHG visible power % Arguments: none % Returns: Returns the visible output power in mW @@ -568,23 +611,24 @@ % Poll cwave status cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib status_vector = de2bi(cwave_status); - obj.opo_stepper_stat = status_vector(1); - obj.opo_temp_stat = status_vector(2); - obj.shg_stepper_stat = status_vector(3); - obj.shg_temp_stat = status_vector(4); - obj.thin_etalon_stat = status_vector(5); - obj.opo_lock_stat = status_vector(6); - obj.shg_lock_stat = status_vector(7); - obj.etalon_lock_stat = status_vector(8); - obj.laser_emission_stat = ~status_vector(9); - obj.ref_temp_stat = status_vector(10); - if(~all(status_vector(1:10) == 0)) + obj.opo_stepper_stat = boolean(status_vector(1)); + obj.opo_temp_stat = boolean(status_vector(2)); + obj.shg_stepper_stat = boolean(status_vector(3)); + obj.shg_temp_stat = boolean(status_vector(4)); + obj.thin_etalon_stat = boolean(status_vector(5)); + obj.opo_lock_stat = boolean(status_vector(6)); + obj.shg_lock_stat = boolean(status_vector(7)); + obj.etalon_lock_stat = boolean(status_vector(8)); + obj.laser_emission_stat = ~boolean(status_vector(9)); + %obj.ref_temp_stat = status_vector(10); %doesnt sense error bit + %sometimes + if(all([status_vector(1:8),~status_vector(9)] == 0)) % there is an 11th bit with no documented hw meaning; should be ignored - status = 1; - else status = 0; + else + status = 1; end - obj.CheckErrorStatus(status,obj.StatusReport) + obj.CheckErrorStatus(status,obj.StatusReport); end function WLM_PID_Compute(obj, wl_measured) @@ -615,10 +659,11 @@ function shutter_shg(obj) if strcmp(obj.shg_shutter, obj.Open) obj.set_intvalue(obj.ShutterSHG,1); elseif strcmp(obj.shg_shutter, obj.Close) - obj.set_intvalue(obj.ShutterSHG,0);; + obj.set_intvalue(obj.ShutterSHG,0); end end + %should this function still exist seems useless function status = getStatus(obj) % poll connection status if CWAVE % Function Call currently not avialable waiting DLL file info @@ -788,8 +833,14 @@ function opo_ramp_piezo(obj) %ramp piezo with sawtooth or triangle waveform obj.set_regopo(3); end + + function setWLM_gains(obj,p,i) + obj.set_intvalue(obj.WLM_pid_p,p) + obj.set_intvalue(obj.WLM_pid_i,i) + end + end From 6b18dc8292f97b2264b46a14c1d8ecc2f739e3a7 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 01:10:52 -0500 Subject: [PATCH 48/71] updated load, start, stop, reset in PulseStreamerMaster. --- .../+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index 2d4995435..f3de9fa8d 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -175,10 +175,8 @@ function build(obj,json) % % seq_meta.units: time units for pulse durations % seq_meta.name: label for sequence. - % seq_meta.repeat: boolean indicating how many times the - % sequence will be repeated until explicitly halted. - % The value of -1 is reserved for infinite - % repetitions. + % seq_meta.forever: boolean indicating whether to + % repeat sequence indefinitely until explicitly halted. % % The build method workflow is as follows: % 1. Determine if json input is a string or a json file name @@ -297,7 +295,7 @@ function load(obj,program) % pulse streamer via an eithernet connection managed by a hardware % server. - build(obj,program); + obj.build(program); start = obj.triggerStart;%initialize the trigger to be software defined mode = obj.triggerMode; % initialize the trigger to be rearmed after each run. obj.PS.setTrigger(start, mode); % set triggers @@ -322,6 +320,7 @@ function start(obj) % end % [~,name,~]=fileparts(caller{end}); % caller = [prefix name]; + obj.plot; obj.PS.startNow(); % obj.running = caller; end From 862cbd9f0a66360953f51d0f74935ec03626c5db Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Thu, 7 Nov 2019 10:31:41 -0500 Subject: [PATCH 49/71] Fixed instance method for PulseStreamerMaster. --- .../+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index f3de9fa8d..28a977074 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -103,20 +103,21 @@ function obj = instance(ip) mlock; persistent Objects - if isempty(Objects) || ~isvalid(Objects) + if isempty(Objects) %|| ~isvalid(Objects) Objects = Drivers.PulseStreamerMaster.PulseStreamerMaster.empty(1,0); %changed from Object to Objects in above line end [~,resolvedIP] = resolvehost(ip); for i = 1:length(Objects) if isvalid(Objects(i)) && isequal(resolvedIP,Objects(i).singleton_id) - error('%s driver is already instantiated!',mfilename) + obj = Objects(i); + return end end obj = Drivers.PulseStreamerMaster.PulseStreamerMaster(ip); obj.singleton_id = resolvedIP; Objects(end+1) = obj; - end + end end methods(Access={?Drivers.PulseStreamerMaster.PulseStreamerMaster}) From d35f30ec8b54b6d668557e2c57896da2907b7969 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 8 Nov 2019 12:35:08 -0500 Subject: [PATCH 50/71] Tune is continuously tunable,introduded reset_hystersis. --- Modules/+Drivers/CWave.m | 6 + Modules/+Sources/CWave.m | 562 +++++++++++++++++++-------------------- 2 files changed, 283 insertions(+), 285 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 449f4e34e..8c4f793c5 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -47,6 +47,7 @@ DLL_Version= 'DLL_Version'; DLL_identity = 22; %20; Admin = 'admin_elevate'; + OPO_rlambda = 'opo_rlambda'; TempRef = 'tref_is'; TempOPO = 'topo_is'; TempSHG1 = 'tshg_is1'; @@ -729,6 +730,11 @@ function set_pid_target_wavelength(obj, setpoint) % IMPORTANT: wait one second before starting to poll for ready pause(1); end + + function set_OPOrLambda(obj,val) + %set realtive wavlength shift for shifts 0.1 nm or greater. + obj.set_intvalue(obj.OPO_rLambda, val) + end function set_target_deviation(obj, target_dev) obj.set_floatvalue(obj.WLM_targetdeviation, target_dev); diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index f3b079491..bd7b5b43a 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -25,10 +25,12 @@ MaxThickEtalonRange = 0.375; %nm pWLM_gain = 10; %10; iWLM_gain = 75 ; %75; + EtalonStepperDelay = 0.1; % ms EtalonMeasureDelay = 1.5; %seconds - wmExposureTolerance = 0.05; % percent/100 + wmExposureTolerance = 0.99; %was 0.05 % percent/100 powerStatusDelay = 1; % seconds - timeoutSHG = 300; % seconds + timeoutAllElements = 300; + timeoutSHG = 95; % seconds timeoutThickEtalon = 300; %seconds wmPower_min = 0; %units? end @@ -43,6 +45,7 @@ sSHG_power; sPump_power; ThickEtalonTolerance = 0.005; %nm + midTuneTolerance = 0.1; end properties(SetAccess=protected) range = [Sources.TunableLaser_invisible.c./[450, 650],Sources.TunableLaser_invisible.c./[900, 1300]]; @@ -227,18 +230,105 @@ function tune(obj, setpoint,target_dev,coarse,lock) pause(10); obj.cwaveHandle.target_wavelength = setpoint; obj.cwaveHandle.set_target_wavelength(); - while(1) - ret = obj.locked; - if (ret == true) - obj.updateStatus; - break; - else - obj.updateStatus; - pause(1); + isCoarseTuned = false; + while( isCoarseTuned == false) + abort_tune = obj.is_cwaveReady(1); + isCoarseTuned = obj.locked; + if (isCoarseTuned == true) + return; + elseif (abort_tune == true) + + return; end end - obj.wavemeterHandle.setExposureMode(true); + %check if user has selected to exit + %tuning + if (abort_tune) + delete(dlg) + return + end + obj.wavemeterHandle.setExposureMode(true); %set exposure mode to automatic obj.updateStatus; + + if ( obj.locked == true & abs(setpoint-obj.getWavelength) > obj.midTuneTolerance ) + direction = sign(setpoint-obj.getWavelength); + while abs(setpoint-obj.getWavelength) > obj.midTuneTolerance % = 0.1 nm + control = direction*abs(setpoint-obj.getWavelength); + if abs(control) < 2.5*obj.OPOrLambdaFloor + control = direction*(obj.OPOrLambdaFloor); + end + obj.cwaveHandle.set_OPOrLambda(obj,floor(control)); + abort_tune = obj.is_cwaveReady(1,true); + %check if user has selected to exit + %tuning + if (abort_tune ) + break + end + [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + tic + while (( currSHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) + pause(1) + abort = obj.is_cwaveReady(1,false); + %check if user has selected to exit + %tuning + if (abort_tune ) + break + end + [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + timer = toc; + if timer > 2*obj.timeoutSHG + abort_tune = true; + break + end + end + end + %check if user has selected to exit + %tuning + if (abort_tune ) + delete(dlg) + %maybe I should have a error + %statement here + return + end + elseif (obj.locked == false) + error('Coarse tuning failed...Are you banging the table you fool. It is an OPO!') + elseif ( obj.locked == true & abs(setpoint-obj.getWavelength) < obj.midTuneTolerance & abs(setpoint-obj.getWavelength) > obj.ThickEtalonTolerance ) + abort = obj.centerThickEtalon; + if (abort ) + delete(dlg) + return + end + else + if (lock == true) + while ( obj.cwaveHandle.get_regopo() ~= 2) + obj.cwaveHandle.set_regopo(2); + end + if (obj.cwaveHandle.get_ref_cavity_percent ~= 50) + obj.TuneRefPercent(50.0); + end + obj.etalon_pid(setpoint,obj.ThickEtalonTolerance); + %obj.etalon_pid(setpoint); + for i=1:2 + obj.WLM_tune(setpoint,target_dev) + end + elseif (lock == false) + while ( obj.cwaveHandle.get_regopo() ~= 4) + obj.cwaveHandle.set_regopo(4); + pause(1); + disp('regopo'); + obj.cwaveHandle.get_regopo + disp('end iteration') + end + if (obj.GetPercent() ~= 50) + obj.TunePercent(50); + end + obj.etalon_pid(setpoint); + for i=1:2 + obj.opo_pid(setpoint,target_dev); + end + end + obj.updateStatus; + end case 'Abort' return end @@ -577,94 +667,33 @@ function updateStatus(obj) %if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN %if obj.internal_call; obj.target_wavelength = val; return; %else - obj.target_wavelength = eval(val); + obj.target_wavelength = eval(val); %end if strcmp(val,''); return; end - %target_dev = 0.000001; - %isCoarse = true; - %isLocked = false; - - - %obj.tune(obj.target_wavelength,target_dev,isCoarse,isLocked); obj.TuneCoarse(obj.c/obj.target_wavelength); - -% obj.centerThickEtalon; -% if abs(obj.target_wavelength-obj.getWavelength) > abs(obj.MaxEtalon_wl-obj.MinEtalon_wl) -% % need to add warning option allowsing user to exit -% % this is a very costly operation -% dlg = questdlg('Target wavelength exceeds tuning etalon and OPO range (> 0.2 nm)! Tuning will be very slow. Do you wish to continue with tuning?', ... -% 'Tuning Warning', ... -% 'Continue Tuning','Abort','Abort'); -% % Handle response -% switch answer -% case 'Tune' -% obj.cwaveHandle.target_wavelength = obj.target_wavelength + 1; -% obj.cwaveHandle.set_target_wavelength(); -% pause(30) -% obj.cwaveHandle.target_wavelength = obj.target_wavelength; -% obj.cwaveHandle.set_target_wavelength(); -% case 'Abort' -% return -% case 'Abort' -% return -% end -% %elseif abs(obj.target_wavelength-obj.getWavelength) < abs(obj.MaxEtalon-obj.MinEtalon) -% else -% obj.TuneCoarse(obj.target_wavelength); -% end end - function [currentSHG_Power, powerSHG_status, total_step,exit] = EtalonStepper(obj ,step, delay_val) + function [currentSHG_Power, powerSHG_status, exit] = EtalonStepper(obj ,step, delay_val) %step etalon - direction = sign(step); + %direction = sign(step); obj.cwaveHandle.tune_thick_etalon(step); +% while(obj.cwaveHandle.is_ready) +% pause(obj.EtalonStepperDelay); +% end + obj.is_cwaveReady(delay_val); + pause(obj.EtalonStepperDelay); exit = false; - %correct for excessive stick-slip motion.... - i =1; - total_step = 0; + %correct for excessive stick-slip motion....= [currentSHG_Power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; - while currentSHG_Power < obj.cwaveHandle.SHG_MinPower - if i == 1 - step = 5; - elseif i == 2 - step = 10; - elseif i == 3 - step = 15; - elseif i == 4 - step = 20; - elseif i == 5 - step = 25; - elseif i == 6 - step = 50; - elseif i > 6 - step = 50; - end - i = i+1; - if i >= 10 - return; - end - -% if currentSHG_Power < obj.cwaveHandle.SHG_MinPower - stepSize = -direction*step; - %sprintf('%i',stepSize); - %obj.EtalonStep = Stepsize; - obj.cwaveHandle.tune_thick_etalon(stepSize); - pause(delay_val); - total_step = stepSize + total_step; - exit = true; -% if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) -% wl_wm = obj.getWavelength; -% elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) -% wl_wm = NaN; -% end -% end - [currentSHG_Power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + if (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) + exit = true; end + end function [wm_wl,wm_power,wm_exptime,SHG_power] = powerStatus(obj, tol,delay_val) i = 0; - maxj_interation = 10; + max_interation = 10; MaxExposuretime = 1500; obj.wavemeterHandle.setExposureMode(false); % manually set exposure obj.wavemeterHandle.setExposure(1) % set exposure to 1 ms @@ -674,7 +703,7 @@ function updateStatus(obj) while ( curr_expTime <= (1-tol)*prev_expTime | curr_expTime >= (1+tol)*prev_expTime ) i = i+1; pause(delay_val) - if i > maxj_interation + if i > max_interation obj.updateStatus regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; @@ -685,18 +714,8 @@ function updateStatus(obj) if (obj.cwaveHandle.get_regopo == 4) [SHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; if( regopo4_locked == false) - dialog0 = msgbox('Error: CWave is not locked for regopo4. Refer to lock status to determine failing elements. Currently in OPO regulator mode 4.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog0); error('CWave is not locked for regopo4. Refer to lock status to determine failing elements. Currently in OPO regulator mode 4.'); elseif (regopo4_noEta_locked == true & obj.etalon_lock == false) - dialog1 = msgbox('Error: Etalon is not locked. Currently in OPO regulator mode 4.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog1); error('Etalon is not locked. Currently in OPO regulator mode 4.'); elseif (regopo4_locked == true & powerSHG_status == true) dialog2 = msgbox('insufficient power from SHG.',mfilename,'modal'); @@ -710,42 +729,17 @@ function updateStatus(obj) if (obj.cwaveHandle.get_regopo == 2) if (obj.regopo4_locked == true & obj.etalon_lock == true & obj.shg_lock == false ) - dialog3 = msgbox('Error: SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog3); error('SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') elseif (obj.regopo4_locked == true & obj.etalon_lock == false & obj.shg_lock == true ) - dialog4 = msgbox('Error: Etalon cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - delete(findall(dlg,'tag','OKButton')); - drawnow; - delete( dialog4); error('Etalon cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') elseif (obj.regopo4_locked == true & obj.etalon_lock == false & obj.shg_lock == false ) - dialog5 = msgbox('Error: Etalon and SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog5); error('Etalon and SHG cannot lock. Try retuning manually. Currently in OPO regulator mode 2.') end end if( obj.wavemeterHandle.setExposure >= MaxExposuretime) - dialog6 = msgbox('Error: Dim emission. Check that light is well coupled into wave meter.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog6); error('Dim emission. Check that light is well coupled into wave meter') else - dialog7 = msgbox('Error: Large fluctuations in CWave power.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dialog7); error('Large fluctuations in CWave power.') end @@ -761,10 +755,117 @@ function updateStatus(obj) wm_wl = NaN; wm_power = NaN; end - break; + return; end end end + + function abort = is_cwaveReady(obj,delay_val,SHG_tuning) + switch nargin + case 0 + delay_val = 1; + SHG_tuning = false; + case 1 + SHG_tuning = false; + end + + abort = false; + tic; + + while(obj.cwaveHandle.is_ready) + pause(delay_val); %in seconds + obj.udpateStatus; + time = toc; + if (time > obj.timeoutSHG & SHG_tuning == true & (obj.shg_lock == false | obj.shg_temp_lock == false) ) + dialog = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + obj.cwaveHandle.optimize_shg; + pause(5) + delete(dialog); +% dialog = questdlg('SHG not locked. Relock SHG?', ... +% 'Cwave Not Ready', ... +% 'Continue','No, Abort','No, Abort'); +% % Handle response +% switch dialog +% case 'Yes' +% obj.cwaveHandle.optimize_shg; +% case 'No, Abort' +% if toc > (obj.timeoutSHG + 15) +% obj.cwaveHandle.optimize_shg; +% else +% obj.cwaveHandle.abort_tune; +% abort = true; +% return; +% end +% end + elseif time > obj.timeoutAllElements + dialog = questdlg('Tuning Timed out. Continue or abort tuning?', ... + 'Cwave Not Ready', ... + 'Continue','Abort','Abort'); + % Handle response + switch dialog + case 'Continue' + tic; + case 'Abort' + obj.cwaveHandle.abort_tune; + abort = true; + return; + end + end + end + end + + function [wm_lambda_c,wmPower_c,wm_exptime_c,currPower, abort, exit] = reset_hysteresis(currPower) + i =1; + total_step = 0; + while(currPower < obj.cwaveHandle.SHG_MinPower) + %direction = sign(EtalonTotalStep); + %correction_step = direction*pstep; + correction_step = pstep; + [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [currPower, Status_powerSHG, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); + if exiting == true + exit = true; + end + %obj.EtalonStep = nstep; + abort = obj.is_cwaveReady(obj.EtalonStepperDelay,false); + pause(obj.EtalonStepperDelay) + obj.updateStatus; + + if i == 1 + correction_step = 5; + elseif i == 2 + correction_step = 10; + elseif i == 3 + correction_step = 15; + elseif i == 4 + correction_step = 20; + elseif i == 5 + correction_step = 23; + elseif i == 6 + correction_step = 25; + elseif i > 6 + correction_step = 25; + end + i = i+1; + if i >= 25 + error('Etalon hysteresis not reset'); + %return; + end + abort = obj.is_cwaveReady(obj.EtalonStepperDelay,false); + + %pause(delay_val); + total_step = correction_step + total_step; + if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) + %wm_lambda_c = obj.getWavelength; + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + end + end + end function abort = centerThickEtalon(obj) dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... @@ -828,11 +929,6 @@ function updateStatus(obj) end delete(dlgs2); if(toc > obj.timeoutSHG) - dlgs3 = msgbox('Error: Re-optimizing of SHG timed out. Tune Manually.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs3); obj.cwaveHandle.abort_tune; error('Re-optimizing of SHG timed out. Tune Manually.') end @@ -850,11 +946,6 @@ function updateStatus(obj) end delete(dlgs4); if(toc > obj.timeoutThickEtalon) - dlgs5 = msgbox('Error: Retuning of thick etalon timed out. Tune Manually.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs5); obj.cwaveHandle.abort_tune; error('Retuning of thick etalon timed out. Tune Manually') end @@ -872,11 +963,6 @@ function updateStatus(obj) end delete(dlgs6); if(toc > obj.obj.timeoutSHG) - dlgs7 = msgbox('Error: Re-optimizing of SHG timed out. Tune Manually.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs7); obj.cwaveHandle.abort_tune; error('Re-optimizing of SHG timed out. Tune Manually.') end @@ -892,7 +978,7 @@ function updateStatus(obj) end j=0; - EtalonTotalStep = 0; + %EtalonTotalStep = 0; obj.updateStatus; wm_exptime_c = wm_exptime_i; wm_exptime_c = wm_exptime_i; @@ -901,7 +987,7 @@ function updateStatus(obj) while ( (currPower > obj.cwaveHandle.SHG_MinPower) ) obj.updateStatus; [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, EtalonTotalStep,exiting] = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); + [currPower, Status_powerSHG, exiting] = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); pause(obj.EtalonMeasureDelay) disp('Enter +eta loop') @@ -912,41 +998,39 @@ function updateStatus(obj) fprintf('current exposure: %.8f\n',wm_exptime_c); if (currPower < obj.cwaveHandle.SHG_MinPower) - while(currPower < obj.cwaveHandle.SHG_MinPower) - direction = sign(EtalonTotalStep); - correction_step = direction*pstep; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, EtalonTotalStep, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); - %obj.EtalonStep = nstep; - pause(obj.EtalonMeasureDelay) - obj.updateStatus; - end - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - %return; + + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower, abort, exiting] = reset_hysteresis(currPower); + else [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); obj.MaxEtalon_wl = sprintf('%.80f',wm_lambda_c); - %obj.MaxEtalon_wl = sprintf('%.80f',obj.getWavelength); end -% if currPower > powerSHG_i -% powerSHG_i = currPower; -% wmPower_i = wmPower_c; -% end - %[wm_lambda,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - %currPower = obj.wavemeterHandle.getPower(); - %wm_exptime_c = obj.wavemeterHandle.getExposure(); - if ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) - del_wl = 1000*abs(wm_lambda_i-wl_lambda_c); % in pm - if (del_wl < EtalonTotalStep) + + del_wl = (wm_lambda_c-wl_lambda_i); % in nm + + if (currPower > obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false %not sure you need eixiting condition + continue; + elseif (currPower > obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + continue; + elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + continue; + elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false + currPower = 2*obj.cwaveHandle.SHG_MinPower; + %should force back to reset + %hysteris + continue; + elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == true + currPower = 2*obj.cwaveHandle.SHG_MinPower; + %should force back to reset + %hysteris + continue; + elseif ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) + + if (del_wl < 0) %maybe put obj.MaxEtalon_wl = %sprintf('%.80f',wm_lambda_c); %here if wmPower_c < obj.wmPower_min - dlgs8 = msgbox('Error: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs3); obj.cwaveHandle.abort_tune; error('Re-optimizing of SHG timed out. Tune Manually.') elseif (wmPower_c < wmPower_i/10 | wm_exptime_c > 10*wm_exptime_i) @@ -956,133 +1040,24 @@ function updateStatus(obj) drawnow; %delete( dlgs3); else - return; + obj.MinEtalon_wl = wm_lambda_c; end - elseif (del_wl > EtalonTotalStep) - currPower = -1; %renter loop + elseif (del_wl > 0) + currPower = 2*obj.cwaveHandle.SHG_MinPower; %renter loop obj.MaxEtalon_wl = 'NaN'; j = j+1; - elseif j>3 - dlgs10 = msgbox('Error: etalon stick. Reset manually.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete(dlgs10); + elseif j>2 obj.cwaveHandle.abort_tune; - error('etalon stick. Reset etalon manually.') + error('etalon is sticking. Reset etalon manually.') %maybe replace error with %dialog box to prompt user to %adjust etalon mannually - end - end - + end end - - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - - k=0; - EtalonTotalStep = 0; - obj.updateStatus; - wm_exptime_c = wm_exptime_i; - wm_exptime_c = wm_exptime_i; - wm_lambda_c = wm_lambda_i; - - while ( currPower > obj.cwaveHandle.SHG_MinPower ) -% obj.updateStatus; -% %obj.EtalonStep = nstep; -% obj.cwaveHandle.tune_thick_etalon( -% sign = -1; -% -% %[currPower, powerSHG_status] = obj.EtalonStepper(sign,obj.EtalonMeasureDelay); -% pause(obj.EtalonMeasureDelay) - - obj.updateStatus; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, EtalonTotalStep,exiting] = obj.EtalonStepper(nstep, obj.EtalonMeasureDelay); - pause(obj.EtalonMeasureDelay) - - disp('Enter -eta loop') - fprintf('Control power: %.8f\n',currPower); - fprintf('Initial Power: %.8f\n',powerSHG_i); - fprintf('lock status (1 is locked): %.8f\n',obj.locked); - fprintf('exposure initial: %.8f\n',wm_exptime_i); - fprintf('exposure control: %.8f\n',wm_exptime_c); - if (currPower < obj.cwaveHandle.SHG_MinPower) - while(currPower < obj.cwaveHandle.SHG_MinPower) -% %obj.EtalonStep = pstep; -% sign = 1; -% [currPower, powerSHG_status] = obj.EtalonStepper(sign,obj.EtalonMeasureDelay); -% pause(obj.EtalonMeasureDelay) -% obj.updateStatus; - - direction = sign(EtalonTotalStep); - correction_step = direction*pstep; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, EtalonTotalStep, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); - %obj.EtalonStep = nstep; - pause(obj.EtalonMeasureDelay) - obj.updateStatus; - end - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - %return - else - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - obj.MinEtalon_wl = sprintf('%.80f',wm_lambda); - %obj.MinEtalon_wl = sprintf('%.80f',obj.getWavelength); - end - - -% if currPower > powerSHG_i -% powerSHG_i = currPower; -% end -% [wm_lambda,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(0.05,1); - %currPower = obj.wavemeterHandle.getPower(); - %wm_exptime_c = obj.wavemeterHandle.getExposure(); - if ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) - del_wl = 1000*abs(wm_lambda_i-wl_lambda_c); % in pm - if (del_wl < EtalonTotalStep) - %maybe put obj.MaxEtalon_wl = - %sprintf('%.80f',wm_lambda_c); - %here - if wmPower_c < obj.wmPower_min - dlgs11 = msgbox('Error: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs11); - obj.cwaveHandle.abort_tune; - error('Re-optimizing of SHG timed out. Tune Manually.') - elseif (wmPower_c < wmPower_i/10 | wm_exptime_c > 10*wm_exptime_i) - dlgs12 = msgbox('Warning: Low Power reading from wavemeter. Check wavemeter coupling.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete( dlgs12); - else - return; - end - elseif (del_wl > EtalonTotalStep) - currPower = -1; %renter loop - obj.MinEtalon_wl = 'NaN'; - k = k+1; - elseif k>3 - dlgs13 = msgbox('Error: etalon stick. Reset manually.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - %delete(findall(dlg,'tag','OKButton')); - drawnow; - %delete(dlgs13); - obj.cwaveHandle.abort_tune; - error('etalon stick. Reset etalon manually.') - %maybe replace error with - %dialog box to prompt user to - %adjust etalon mannually - - end - end - end -%%%%%%%%%%%%%%%%%%%%%%%% End of 'No, Please Autotune' case %%%%%%%%%%%%% - + obj.MidEtalon_wl = obj.MinEtalon_wl + abs(obj.MaxEtalon_wl-obj.MinEtalon_wl)/2; + obj.etalon_pid(obj.MidEtalon_wl); + abort = false; case 'No, Abort' abort = true; @@ -1339,9 +1314,26 @@ function delete(obj) IntError = []; Control = []; Measured = []; - + exit = false; while (abs(curr_error) > tolerance ) tic + [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + if currSHG_power < obj.cwaveHandle.SHG_MinPower + while exit == false & currSHG_power < obj.cwaveHandle.SHG_MinPower + [wm_lambda_c,wmPower_c,wm_exptime_c, currSHG_power, abort, exit] = reset_hysteresis(currPower); + end + curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. + ctrl = 0; + p_term = 0; + i_term = 0; + d_term = 0; + Error = []; + Dt = []; + IntError = []; + Control = []; + Measured = []; + exit = false; + end measured = obj.getWavelength(); if i == 0 dt = 0; From 32e935cdeda5880f94ad360a52c0c388aa2da3f4 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 8 Nov 2019 15:56:55 -0500 Subject: [PATCH 51/71] MidTuneRange conditions added to tune method. --- Modules/+Sources/CWave.m | 60 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index bd7b5b43a..1ad0a1fb2 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -292,6 +292,58 @@ function tune(obj, setpoint,target_dev,coarse,lock) end elseif (obj.locked == false) error('Coarse tuning failed...Are you banging the table you fool. It is an OPO!') + elseif (abs(setpoint-obj.getWavelength) > obj.midTuneTolerance) + regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... + & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; + regOPO4_cond = regopo4_locked == true & obj.cwaveHandle.get_regopo == 4 & ... + abs(setpoint-obj.getWavelength) > obj.midTuneTolerance; + regOPO2_cond = robj.locked == true & obj.cwaveHandle.get_regopo == 2 & ... + abs(setpoint-obj.getWavelength) > obj.midTuneTolerance; + + obj.updateStatus; + if (regOPO2_cond | regOPO4_cond) + direction = sign(setpoint-obj.getWavelength); + while abs(setpoint-obj.getWavelength) > obj.midTuneTolerance % = 0.1 nm + control = direction*abs(setpoint-obj.getWavelength); + if abs(control) < 2.5*obj.OPOrLambdaFloor + control = direction*(obj.OPOrLambdaFloor); + end + obj.cwaveHandle.set_OPOrLambda(obj,floor(control)); + abort_tune = obj.is_cwaveReady(1,true); + %check if user has selected to exit + %tuning + if (abort_tune ) + break + end + [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + tic + while (( currSHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) + pause(1) + abort = obj.is_cwaveReady(1,false); + %check if user has selected to exit + %tuning + if (abort_tune ) + break + end + [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + timer = toc; + if timer > 2*obj.timeoutSHG + abort_tune = true; + break + end + end + end + %check if user has selected to exit + %tuning + if (abort_tune ) + delete(dlg) + %maybe I should have a error + %statement here + return + end + else + error('Coarse tuning failed...Are you banging the table you fool. It is an OPO!') + end elseif ( obj.locked == true & abs(setpoint-obj.getWavelength) < obj.midTuneTolerance & abs(setpoint-obj.getWavelength) > obj.ThickEtalonTolerance ) abort = obj.centerThickEtalon; if (abort ) @@ -302,6 +354,7 @@ function tune(obj, setpoint,target_dev,coarse,lock) if (lock == true) while ( obj.cwaveHandle.get_regopo() ~= 2) obj.cwaveHandle.set_regopo(2); + pause(0.1); end if (obj.cwaveHandle.get_ref_cavity_percent ~= 50) obj.TuneRefPercent(50.0); @@ -314,10 +367,7 @@ function tune(obj, setpoint,target_dev,coarse,lock) elseif (lock == false) while ( obj.cwaveHandle.get_regopo() ~= 4) obj.cwaveHandle.set_regopo(4); - pause(1); - disp('regopo'); - obj.cwaveHandle.get_regopo - disp('end iteration') + pause(0.1); end if (obj.GetPercent() ~= 50) obj.TunePercent(50); @@ -1319,7 +1369,7 @@ function delete(obj) tic [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; if currSHG_power < obj.cwaveHandle.SHG_MinPower - while exit == false & currSHG_power < obj.cwaveHandle.SHG_MinPower + while ( (exit == false) & (currSHG_power < obj.cwaveHandle.SHG_MinPower) ) [wm_lambda_c,wmPower_c,wm_exptime_c, currSHG_power, abort, exit] = reset_hysteresis(currPower); end curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. From ffee5d2e8b424da24d28f4140c57ac58dd5f5c47 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 8 Nov 2019 16:14:08 -0500 Subject: [PATCH 52/71] Initialize wavemeter to read wl in vac prior to tune method. --- Modules/+Sources/CWave.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 1ad0a1fb2..0562b85e1 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -186,6 +186,11 @@ function blackout(obj) % tunable laser methods function tune(obj, setpoint,target_dev,coarse,lock) + if (obj.wavemeterHandle.getResultMode ~= 0) + obj.wavemeterHandle.setResultMode(0); + % initialize into WavelengthVac mode. + % 'cReturnWavelengthVac' = 0 + end % target in nm obj.tuning = true; if setpoint < 899 @@ -369,6 +374,8 @@ function tune(obj, setpoint,target_dev,coarse,lock) obj.cwaveHandle.set_regopo(4); pause(0.1); end + % error tuning occure 11/08/19 + % somewhere between line 378-385 if (obj.GetPercent() ~= 50) obj.TunePercent(50); end From 2e84e2ad3c587b0b91615ebdb440f8ecc198fce3 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 8 Nov 2019 16:55:17 -0500 Subject: [PATCH 53/71] Corrected typos in etalon_pid. --- Modules/+Sources/CWave.m | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 0562b85e1..dac4cdfcf 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -914,14 +914,13 @@ function updateStatus(obj) abort = obj.is_cwaveReady(obj.EtalonStepperDelay,false); %pause(delay_val); - total_step = correction_step + total_step; - if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) + %total_step = correction_step + total_step; + %if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) %wm_lambda_c = obj.getWavelength; - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + %elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) + % [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); end - end end function abort = centerThickEtalon(obj) @@ -1374,10 +1373,11 @@ function delete(obj) exit = false; while (abs(curr_error) > tolerance ) tic - [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; - if currSHG_power < obj.cwaveHandle.SHG_MinPower - while ( (exit == false) & (currSHG_power < obj.cwaveHandle.SHG_MinPower) ) - [wm_lambda_c,wmPower_c,wm_exptime_c, currSHG_power, abort, exit] = reset_hysteresis(currPower); + obj.updateStatus; + obj.is_cwaveReady(0.1); + if obj.SHG_power < obj.cwaveHandle.SHG_MinPower + while ( (exit == false) & (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) ) + [wm_lambda_c,wmPower_c,wm_exptime_c, obj.SHG_power, abort, exit] = reset_hysteresis(obj.SHG_power); end curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. ctrl = 0; From 2b249c9a9608e692c29dfc6ca4de32fb80cd6684 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Fri, 8 Nov 2019 18:14:53 -0500 Subject: [PATCH 54/71] Correctted types and speed up reset_hyst, is_cwaveready, etalonStepper. --- Modules/+Sources/CWave.m | 158 +++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 82 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index dac4cdfcf..827c9f53a 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -269,9 +269,10 @@ function tune(obj, setpoint,target_dev,coarse,lock) if (abort_tune ) break end - [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + + obj.updateStatus; tic - while (( currSHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) + while (( obj.SHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) pause(1) abort = obj.is_cwaveReady(1,false); %check if user has selected to exit @@ -279,9 +280,10 @@ function tune(obj, setpoint,target_dev,coarse,lock) if (abort_tune ) break end - [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + obj.updateStatus; + %[currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; timer = toc; - if timer > 2*obj.timeoutSHG + if timer > obj.timeoutSHG abort_tune = true; break end @@ -320,9 +322,9 @@ function tune(obj, setpoint,target_dev,coarse,lock) if (abort_tune ) break end - [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + obj.updateStatus; tic - while (( currSHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) + while (( obj.SHG_power < obj.cwaveHandle.SHG_MinPower) ) % | powerSHG_status == false) pause(1) abort = obj.is_cwaveReady(1,false); %check if user has selected to exit @@ -330,7 +332,7 @@ function tune(obj, setpoint,target_dev,coarse,lock) if (abort_tune ) break end - [currSHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; + obj.updateStatus; timer = toc; if timer > 2*obj.timeoutSHG abort_tune = true; @@ -633,12 +635,6 @@ function updateStatus(obj) end obj.tuning = ~(obj.locked); - - if (~obj.locked) - %replace below with dialog box - disp('CWAVE Warning: All elements are not stable and/or locked.'); - end - toc fprintf('toc %.8f\n',toc); %obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; @@ -730,25 +726,23 @@ function updateStatus(obj) obj.TuneCoarse(obj.c/obj.target_wavelength); end - function [currentSHG_Power, powerSHG_status, exit] = EtalonStepper(obj ,step, delay_val) + function exit = EtalonStepper(obj ,step, delay_val) %step etalon %direction = sign(step); obj.cwaveHandle.tune_thick_etalon(step); -% while(obj.cwaveHandle.is_ready) -% pause(obj.EtalonStepperDelay); -% end - obj.is_cwaveReady(delay_val); - pause(obj.EtalonStepperDelay); + obj.is_cwaveReady(delay_val,false,false); %(no SHG reset, only update SHG power) + %pause(obj.EtalonStepperDelay); exit = false; %correct for excessive stick-slip motion....= - [currentSHG_Power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; - if (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) + [obj.SHG_power, obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; + %obj.updateStatus; + if (obj.SHG_power > obj.cwaveHandle.SHG_MinPower) exit = true; end end - function [wm_wl,wm_power,wm_exptime,SHG_power] = powerStatus(obj, tol,delay_val) + function [wm_wl,wm_power,wm_exptime] = powerStatus(obj, tol,delay_val) i = 0; max_interation = 10; MaxExposuretime = 1500; @@ -759,9 +753,10 @@ function updateStatus(obj) curr_expTime = 100000*prev_expTime; while ( curr_expTime <= (1-tol)*prev_expTime | curr_expTime >= (1+tol)*prev_expTime ) i = i+1; - pause(delay_val) + %obj.updateStatus; + %pause(delay_val) + obj.is_cwaveReady(delay_val,false,false) %try is_cwaveReady instead of updateStatus and pause. SHould be faster if i > max_interation - obj.updateStatus regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; @@ -769,7 +764,6 @@ function updateStatus(obj) & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; if (obj.cwaveHandle.get_regopo == 4) - [SHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; if( regopo4_locked == false) error('CWave is not locked for regopo4. Refer to lock status to determine failing elements. Currently in OPO regulator mode 4.'); elseif (regopo4_noEta_locked == true & obj.etalon_lock == false) @@ -801,7 +795,6 @@ function updateStatus(obj) end elseif ( (1+tol)*prev_expTime >= curr_expTime & curr_expTime >= (1-tol)*prev_expTime ) - [SHG_power, powerSHG_status] = obj.cwaveHandle.get_photodiode_shg; wm_exptime = obj.wavemeterHandle.getExposure(); if (powerSHG_status == false) @@ -817,13 +810,17 @@ function updateStatus(obj) end end - function abort = is_cwaveReady(obj,delay_val,SHG_tuning) + function abort = is_cwaveReady(obj,delay_val,SHG_tuning,allStatus) switch nargin case 0 delay_val = 1; SHG_tuning = false; + allStatus = true; case 1 SHG_tuning = false; + allStatus = true; + case 2 + allStatus = true; end abort = false; @@ -831,7 +828,11 @@ function updateStatus(obj) while(obj.cwaveHandle.is_ready) pause(delay_val); %in seconds - obj.udpateStatus; + if allStatus == true + obj.udpateStatus; + else + [obj.SHG_power, obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; + end time = toc; if (time > obj.timeoutSHG & SHG_tuning == true & (obj.shg_lock == false | obj.shg_temp_lock == false) ) dialog = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); @@ -841,22 +842,6 @@ function updateStatus(obj) obj.cwaveHandle.optimize_shg; pause(5) delete(dialog); -% dialog = questdlg('SHG not locked. Relock SHG?', ... -% 'Cwave Not Ready', ... -% 'Continue','No, Abort','No, Abort'); -% % Handle response -% switch dialog -% case 'Yes' -% obj.cwaveHandle.optimize_shg; -% case 'No, Abort' -% if toc > (obj.timeoutSHG + 15) -% obj.cwaveHandle.optimize_shg; -% else -% obj.cwaveHandle.abort_tune; -% abort = true; -% return; -% end -% end elseif time > obj.timeoutAllElements dialog = questdlg('Tuning Timed out. Continue or abort tuning?', ... 'Cwave Not Ready', ... @@ -874,15 +859,18 @@ function updateStatus(obj) end end - function [wm_lambda_c,wmPower_c,wm_exptime_c,currPower, abort, exit] = reset_hysteresis(currPower) + function [wm_lambda_c,wmPower_c,wm_exptime_c, abort, exit] = reset_hysteresis(obj,pstep) i =1; - total_step = 0; - while(currPower < obj.cwaveHandle.SHG_MinPower) + %total_step = 0; + obj.updateStatus; + while(obj.SHG_power < obj.cwaveHandle.SHG_MinPower) + %obj.is_cwaveReady(obj.EtalonStepperDelay,false,false); + %obj.updateStatus; %updatStatus is slow ~0.1-0.5 s long may need to replace with [obj.SHG_power,~] = obj.cwaveHandle.get_photodiode_shg %direction = sign(EtalonTotalStep); %correction_step = direction*pstep; correction_step = pstep; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, exiting] = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); + %[wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); %updateStatus called internally + exiting = obj.EtalonStepper(correction_step, obj.EtalonMeasureDelay); % update Status called internally. if exiting == true exit = true; end @@ -892,35 +880,35 @@ function updateStatus(obj) obj.updateStatus; if i == 1 - correction_step = 5; + correction_step = 15; elseif i == 2 - correction_step = 10; + correction_step = 20; elseif i == 3 - correction_step = 15; + correction_step = 25; elseif i == 4 - correction_step = 20; + correction_step = 50; elseif i == 5 - correction_step = 23; + correction_step = 75; elseif i == 6 - correction_step = 25; + correction_step = 100; elseif i > 6 - correction_step = 25; + correction_step = 100; end i = i+1; if i >= 25 error('Etalon hysteresis not reset'); %return; end - abort = obj.is_cwaveReady(obj.EtalonStepperDelay,false); + abort = obj.is_cwaveReady(obj.EtalonStepperDelay,false,false); %pause(delay_val); %total_step = correction_step + total_step; %if (currentSHG_Power >= obj.cwaveHandle.SHG_MinPower) %wm_lambda_c = obj.getWavelength; - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [wm_lambda_c,wmPower_c,wm_exptime_c] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); %elseif (currentSHG_Power < obj.cwaveHandle.SHG_MinPower) % [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - end + end end function abort = centerThickEtalon(obj) @@ -965,8 +953,8 @@ function updateStatus(obj) obj.cwaveHandle.abort_tune; error('Etalon not tunable. Check lock status of OPO elements.') elseif (PowerMeasureCondition_regopo2 == true | PowerMeasureCondition_regopo4 | obj.locked) - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - if (currPower < obj.cwaveHandle.SHG_MinPower) + [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) dlgs1 = questdlg('SHG power is very low (SHG is not lock)! Would you like to reoptimize SHG power?', ... 'Yes, optimize SHG Power','No, retune etalon', 'No, Abort','No, Abort'); % Handle response @@ -979,9 +967,11 @@ function updateStatus(obj) drawnow; tic obj.cwaveHandle.optimize_shg(); - while( (currPower < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) - obj.updateStatus; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + while( (obj.SHG_power < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) + %obj.updateStatus; + %updateStatus called + %in powerStatus + [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); end delete(dlgs2); if(toc > obj.timeoutSHG) @@ -998,14 +988,14 @@ function updateStatus(obj) obj.cwaveHandle.relock_etalon(); while( (obj.etalon_lock == false) | toc <= obj.timeoutThickEtalon) obj.updateStatus; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); end delete(dlgs4); if(toc > obj.timeoutThickEtalon) obj.cwaveHandle.abort_tune; error('Retuning of thick etalon timed out. Tune Manually') end - if (currPower < obj.cwaveHandle.SHG_MinPower | obj.shg_lock == false | obj.shg_temp_lock == false) + if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower | obj.shg_lock == false | obj.shg_temp_lock == false) % The CWave is slow at tuning, so message is useful until a non-blocking operation exists dlgs6 = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); textH = findall(dlg,'tag','MessageBox'); @@ -1013,9 +1003,9 @@ function updateStatus(obj) drawnow; tic obj.cwaveHandle.optimize_shg(); - while( (currPower < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) + while( (obj.SHG_power < obj.cwaveHandle.SHG_MinPower & obj.shg_lock == false & obj.etalon_lock == false) | toc <= obj.timeoutSHG) obj.updateStatus; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); end delete(dlgs6); if(toc > obj.obj.timeoutSHG) @@ -1039,11 +1029,11 @@ function updateStatus(obj) wm_exptime_c = wm_exptime_i; wm_exptime_c = wm_exptime_i; wm_lambda_c = wm_lambda_i; - - while ( (currPower > obj.cwaveHandle.SHG_MinPower) ) - obj.updateStatus; - [wm_lambda_i,wmPower_i,wm_exptime_i,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); - [currPower, Status_powerSHG, exiting] = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); + currPower = obj.SHG_power; + while ( ( currPower > obj.cwaveHandle.SHG_MinPower) ) + obj.updateStatus; %not sure that we need this. It would be useful to have but it slows things down. + [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + exiting = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); pause(obj.EtalonMeasureDelay) disp('Enter +eta loop') @@ -1053,34 +1043,37 @@ function updateStatus(obj) fprintf('initial exposure: %.8f\n',wm_exptime_i); fprintf('current exposure: %.8f\n',wm_exptime_c); - if (currPower < obj.cwaveHandle.SHG_MinPower) + if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower, abort, exiting] = reset_hysteresis(currPower); + [wm_lambda_c,wmPower_c,wm_exptime_c,abort, exiting] = reset_hysteresis(currPower); else - [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); + [wm_lambda_c,wmPower_c,wm_exptime_c] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); obj.MaxEtalon_wl = sprintf('%.80f',wm_lambda_c); end del_wl = (wm_lambda_c-wl_lambda_i); % in nm - if (currPower > obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false %not sure you need eixiting condition + if (obj.SHG_power > obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false %not sure you need eixiting condition + currPower = obj.SHG_power; continue; - elseif (currPower > obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + elseif (obj.SHG_power > obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + currPower = obj.SHG_power; continue; - elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + elseif (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) & (del_wl < 0) & exiting == false %not sure you need eixiting condition + currPower = obj.SHG_power; continue; - elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false + elseif (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == false currPower = 2*obj.cwaveHandle.SHG_MinPower; %should force back to reset %hysteris continue; - elseif (currPower < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == true + elseif (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) & (del_wl > 0) & exiting == true currPower = 2*obj.cwaveHandle.SHG_MinPower; %should force back to reset %hysteris continue; - elseif ( (currPower > obj.cwaveHandle.SHG_MinPower) & exiting == true) + elseif ( (obj.SHG_power > obj.cwaveHandle.SHG_MinPower) & exiting == true) if (del_wl < 0) %maybe put obj.MaxEtalon_wl = @@ -1097,6 +1090,7 @@ function updateStatus(obj) %delete( dlgs3); else obj.MinEtalon_wl = wm_lambda_c; + return; end elseif (del_wl > 0) currPower = 2*obj.cwaveHandle.SHG_MinPower; %renter loop From 5fce9abdd90c6bcef5c38b28dadde2b8322c5bd7 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Sun, 10 Nov 2019 17:18:44 -0500 Subject: [PATCH 55/71] added manual relative tuning step for 100 pm to 1 nm steps. --- Modules/+Sources/CWave.m | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 827c9f53a..b8b6f322d 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -56,9 +56,9 @@ 'opo_lock','shg_lock','pump_emission','ref_temp_lock','resonator_percent',... 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... 'resonator_tune_speed','tunePercentRange','MaxEtalon_wl','MinEtalon_wl',... - 'EtalonStep','MidEtalon_wl','OPO_power','SHG_power','Pump_power',... + 'EtalonStep','MidEtalon_wl','OPO_power','SHG_power','Pump_power','AllElementStep',... 'TempRef','TempOPO', 'TempSHG','TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint'}; - show_prefs = {'target_wavelength','resonator_percent','EtalonStep','tunePercentRange',... + show_prefs = {'target_wavelength','resonator_percent','AllElementStep','EtalonStep','tunePercentRange',... 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','tuning',... 'enabled','wavelength_lock','etalon_lock','opo_stepper_lock','opo_temp_lock','shg_stepper_lock',... 'shg_temp_lock','thin_etalon_lock','opo_lock','shg_lock','pump_emission','ref_temp_lock',... @@ -109,6 +109,7 @@ target_wavelength=''; tunePercentRange = ''; %tunePercentRange = Prefs.DoubleArray(); EtalonStep=''; + AllElementStep = ''; MinEtalon_wl = '0'; MaxEtalon_wl = '.25'; end @@ -1134,9 +1135,24 @@ function updateStatus(obj) %obj.updateStatus; end + function set.AllElementStep(obj,val) + if obj.cwaveHandle.is_ready + return + end + obj.AllElementStep = floor( eval(val) ); + obj.cwaveHandle.set_OPOrLambda(); + obj.is_cwaveReady(obj.EtalonStepperDelay,true); + end + + function tune_etalon(obj) + if obj.cwaveHandle.is_ready == true + return + end obj.cwaveHandle.tune_thick_etalon(obj.EtalonStep); %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); + % obj.updateStatus; + %obj.is_cwaveReady(obj.EtalonStepperDelay,false,false); end function set_regopo(obj,val) From c5f108d77529a3dbd2c3e78debe0b9573986955b Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 09:54:56 -0500 Subject: [PATCH 56/71] Added reorder_program to match expected program for load. --- .../PulseStreamerMaster.m | 138 +++++++++++------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m index 28a977074..1dbad79f6 100644 --- a/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m +++ b/Modules/+Drivers/+PulseStreamerMaster/PulseStreamerMaster.m @@ -1,5 +1,5 @@ - -classdef PulseStreamerMaster < Modules.Driver + +classdef PulseStreamerMaster < Modules.Driver & Drivers.PulseTimer_invisible % PulseStreamerMaster is located in in CommandCenter > Modules > % +Drivers > +PulseStreamer % The PulseStreamerMaster class is a driver module class which @@ -21,11 +21,11 @@ % "forever":false, % "channels":["channel1","MW Switch","","channel4"], % "sequence":[ - % {"flags":[0,0,0,1],"duration":0,"instruction":"CONTINUE","data":null}, + % {"flags":[0,0,0,1],"duration":0,"instruction":"CONTINUE","data":null}, % {"flags":[0,1,1,0],"duration":1,"instruction":"LOOP","data":2}, - % {"flags":[0,0,0,1],"duration":18,"instruction":"CONTINUE","data":null}, - % {"flags":[0,1,0,1],"duration":19,"instruction":"END_LOOP","data":null}, - % {"flags":[0,0,0,1],"duration":20,"instruction":"CONTINUE","data":null}, + % {"flags":[0,0,0,1],"duration":18,"instruction":"CONTINUE","data":null}, + % {"flags":[0,1,0,1],"duration":19,"instruction":"END_LOOP","data":null}, + % {"flags":[0,0,0,1],"duration":20,"instruction":"CONTINUE","data":null}, % ] % } % @@ -34,7 +34,7 @@ % loop the pulse sequence indefinitely. % % The sequence is defined by four fields: - % 1. flags: an array of boolean states for the relevant channels. + % 1. flags: an array of boolean states for the relevant . % 2. duration: the duration of the pulse for the associated states. % 3. data: the span of the loop, i.e., the numer of loop interations. % 4. instruction: determines the action to be performed. @@ -69,7 +69,12 @@ % ipAddress='192.168.11.2'; - + properties(Constant) + clk = 1000; % clock sampling rate + resolution = 3; % ns can be s low as 1 nd but output voltage is lower than 3.3V (TTL) so depending on uWave source trigger might be able to go down to 1ns + minDuration = 2; % ns (can go down to 1ns but output waveform will be distorted). + maxRepeats = 2^63-1; % positive integer value + end properties(SetAccess=private) % Object that provides the interface to the % Pulse Streamer hardware. this object provides access run, halt @@ -77,6 +82,7 @@ % Streamer. PS; % + pulseName; builder; %PusleSequenceBuilder object used to build pulse sequences. triggerStart; triggerMode; @@ -121,7 +127,7 @@ end methods(Access={?Drivers.PulseStreamerMaster.PulseStreamerMaster}) - + function obj = PulseStreamerMaster(ip) % Constructor for this class. % ip: IP address of hardware @@ -212,11 +218,11 @@ function build(obj,json) % Test if obj.json is a file. If a file name, read % file and replace obj.json with the file contents as a % single string - if strcmp(obj.json(end-2:end),'.js') - obj.json = fileread(obj.json); - elseif strcmp(obj.json(end-3:end),'.txt') - %write error checking in the future. - end +% if strcmp(obj.json(end-2:end),'.js') +% obj.json = fileread(obj.json); +% elseif strcmp(obj.json(end-3:end),'.txt') +% %write error checking in the future. +% end % convert obj.json into a list (actually a cell array) of % ordered maps (json_seq) describing the pulse sequence and @@ -242,7 +248,7 @@ function build(obj,json) % the instructions for a pulse sequence step (duration and flag % fields). obj.unroll_tree(obj.cmd,obj.map); - + % ------------------------- % BUILD PULSE TRAINS % A pulse train is a list @@ -271,14 +277,18 @@ function build(obj,json) state = flags(jj); pulse_trains{jj}{1}{ii,1} = duration; pulse_trains{jj}{1}{ii,2} = state; - + end end % Build the digital pattern (a sequence of duration, % channel state pairs in that order) for each channel. for kk = 1:1:length(obj.seq_meta.channels) - ch = kk-1; + %ch = kk-1; + %digitalPattern = pulse_trains{kk}{1}; + %obj.sequence.setDigital(ch, digitalPattern); + + ch = obj.seq_meta.channels{kk}; digitalPattern = pulse_trains{kk}{1}; obj.sequence.setDigital(ch, digitalPattern); end @@ -289,6 +299,23 @@ function plot(obj) obj.sequence.plot(); end + function program = reorder_program(obj,program) + [m,~] = size(program.sequence); + [~,n] = size(program.channels); + i = 1; + while i <= m + program.sequence(i).flags = transpose(program.sequence(i).flags); + i=i+1; + end + i=1; + while i <= n + program.channels{i}= int8(str2double(program.channels{i})); + i=i+1; + end + program.channels = transpose(program.channels); + obj.pulseName = program.name; + +end function load(obj,program) % The load method converts the sequence object to the properly @@ -296,6 +323,7 @@ function load(obj,program) % pulse streamer via an eithernet connection managed by a hardware % server. + program = obj.reorder_program(program); obj.build(program); start = obj.triggerStart;%initialize the trigger to be software defined mode = obj.triggerMode; % initialize the trigger to be rearmed after each run. @@ -321,7 +349,6 @@ function start(obj) % end % [~,name,~]=fileparts(caller{end}); % caller = [prefix name]; - obj.plot; obj.PS.startNow(); % obj.running = caller; end @@ -408,14 +435,14 @@ function reset(obj) elseif depth > 10 return end - - + + % if the last element of cmd is a list, then get that list % otherwise use the list cmd directly. this takes into % account the cases where CONTINUEs may not reside within % LOOPs. c_cmd = cmd; - + % verify cmd isn not empty, otherwise you will keep nesting lists % unwantedly if length(cmd.command) > 0 @@ -424,7 +451,7 @@ function reset(obj) c_cmd = cmd.command{end}; end end - + %Debugging: report the length of cmd.command to track its growth if DEBUG > 0 fprintf('CMD length is: %i\n\n',length(cmd.command)) @@ -439,11 +466,11 @@ function reset(obj) if DEBUG > 0 fprintf('depth = %5d\tinstruction: %s, %d\n',depth,instruction,index); end - + % loop over the instructions in the json list while index < length(json_seq) index = index + 1; % IMPORTANT: remember to increment index into json list - + % get instruction type instruction = json_seq{index}('instruction'); @@ -452,7 +479,7 @@ function reset(obj) if DEBUG > 0 fprintf('depth = %5d\tinstruction: %s, %d\n', depth,instruction,index); end - + % Decide what to do depending on instruction type if strcmp(instruction,'END_LOOP') c_cmd.append(json_seq{index}); @@ -461,39 +488,39 @@ function reset(obj) % the next json instruction return % Important, this is a terminating case % for the recursion - + elseif strcmp(instruction,'LOOP') % since this is a loop, create a new empty list to % receive the instructions for this loop. % IMPORTANT: the value of index can change within % decodeInstructions, so we must return it c_cmd.append(Drivers.PulseStreamerMaster.seqCommand) - + %Debugging: report current instruction data. if DEBUG > 0 fprintf('In loop current command is\n') disp(c_cmd(end)) end index = obj.decodeInstructions(json_seq,c_cmd(end),depth,index); - + %Debugging: report current index. if DEBUG > 0 fprintf('index %d\n', index); end - + elseif strcmp(instruction,'CONTINUE') %since this is a continue statement we will simply %append the instruction data to the cmd.(remember c_cmd %is handle for cmd). c_cmd.append(json_seq{index}); - + else error('** error decoding JSON file\n') - + end end end - + function unroll_tree(obj,cmd,map,depth) % unroll_tree rolls all the instructions in the instruction @@ -525,7 +552,7 @@ function unroll_tree(obj,cmd,map,depth) tab = strcat('...',tab); end end - + % loop over top level instructions of abstract syntax tree, % here called cmd for c = 1:1:length(cmd.command) @@ -558,7 +585,7 @@ function unroll_tree(obj,cmd,map,depth) end end end - + function printTree(obj, cmd, depth) % Print the Tree of instructions @@ -578,13 +605,13 @@ function printTree(obj, cmd, depth) return end fprintf('depth: %i\n' , depth); - + tab = ''; for i=1:depth - + tab = strcat('...',tab); end - + % Loop acrous length of cmd cell array (list). If a list is found then % printTree of that list. Please note that the seqCommand is a % hadnle class which allows for the concatenation of any item @@ -609,7 +636,7 @@ function printTree(obj, cmd, depth) function map = execute_loop(obj,cmd,map,depth) DEBUG = 0; - + if DEBUG > 1 fprintf('\n\nIn execute_loop\n'); end @@ -625,7 +652,7 @@ function printTree(obj, cmd, depth) %increment recurssion depth and return if depth exceeds 10. depth = depth+1; - + if depth > 10 return; end @@ -640,7 +667,7 @@ function printTree(obj, cmd, depth) %current loop instruction. By default if this function is %executed then the first instruction in the list is LOOP. c = cmd.command{1}; - + % LOOP instruction %Debugging: Report instruction in loop if DEBUG > 0 @@ -650,7 +677,7 @@ function printTree(obj, cmd, depth) c('duration'), ... c('flag').', ... c('data')); - + end %error handling @@ -666,21 +693,21 @@ function printTree(obj, cmd, depth) %append current map map.append(cmd.command{1}); - + %Debugging: Display updated list of instruction maps if DEBUG > 1 fprintf('Current list of maps: '); disp(map) end - + % Implement loop loop_cmd = cmd.command; span = c('data'); %number of times to increment loop - + for ii = 1:1:span % loop over instructions for current loop % excluding the LOOP and END_LOOP instructions - + if DEBUG > 1 disp(length(loop_cmd)) end @@ -690,7 +717,7 @@ function printTree(obj, cmd, depth) %always ran before and after the curret loop, respectively. %Loop over remainging instructions. for jj = 2:1:(length(loop_cmd)-1) - + if DEBUG > 1 fprintf('current jj: '); disp(jj) @@ -699,7 +726,7 @@ function printTree(obj, cmd, depth) %if an instruction within this loop is LOOP then %recurse into execute_loop. if isa(loop_cmd{jj},'Drivers.PulseStreamerMaster.seqCommand') - + if DEBUG > 1 fprintf('current loop instruction: '); disp(loop_cmd{jj}) @@ -714,18 +741,18 @@ function printTree(obj, cmd, depth) %append map of continue instruction. map.append(c); - + % Debugging: report recursion depth, current instruction and % instruction index. if DEBUG > 0 - + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... tab, ... c('instruction'), ... c('duration'), ... c('flag').'); end - + %If instruction is not CONTINUE then throw error. if ~strcmp(c('instruction'),'CONTINUE') error('Expected CONTINUE instruction, but found %s\n', ... @@ -733,7 +760,7 @@ function printTree(obj, cmd, depth) end end end - + % END_LOOP instruction is last instruction in list of loop % instructions c = cmd.command{end}; @@ -744,7 +771,7 @@ function printTree(obj, cmd, depth) % Debugging: report recursion depth, current instruction and % instruction index. if DEBUG > 0 - + fprintf('%s%s: duration = %i, flags = %i %i %i %i\n', ... tab, ... c('instruction'), ... @@ -786,10 +813,10 @@ function printTree(obj, cmd, depth) json_seq = cell(1,length(json_struct)); for i=1:1:length(json_struct) cells = struct2cell(json_struct(i)); - key_labels = {'flag','duration','instruction','data'}; + key_labels = {'flag','duration','instruction','notes','data'}; json_seq{i} = containers.Map(key_labels,cells); end - + %return remaining human readabl fields (channels, units, name, %forever) to seq_meta seq_metadata.channels = json_total.channels; @@ -805,7 +832,7 @@ function printTree(obj, cmd, depth) end end - + end methods @@ -820,4 +847,5 @@ function delete(obj) end end end + From 0696c7c4224524609a61bf1c67ed30c84e29e3ef Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 10:10:22 -0500 Subject: [PATCH 57/71] getStatusBits has refTemp, corrected typos in checkErrorStatus. --- Modules/+Drivers/CWave.m | 182 +++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 67 deletions(-) diff --git a/Modules/+Drivers/CWave.m b/Modules/+Drivers/CWave.m index 8c4f793c5..b4828d708 100644 --- a/Modules/+Drivers/CWave.m +++ b/Modules/+Drivers/CWave.m @@ -35,9 +35,12 @@ %Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x64\'; %Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\x86\'; %HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\MatlabControl\'; - Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x64\'; - Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x86\'; - HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\'; + %Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x64\'; + %Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\x86\'; + %HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v22\bin\'; + Pathx64 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v24\bin\x64\'; + Pathx86 = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v24\bin\x86\'; + HPath = 'C:\Program Files (x86)\Hubner\C-WAVE Control\C-WAVE SDK v24\bin\'; LibraryName = 'CWAVE_DLL'; % alias for library LibraryFilePath = 'CWAVE_DLL.dll'; % Path to dll LibraryHeader = 'CWAVE_DLL.h'; @@ -45,9 +48,9 @@ ComputerArch = 'arch'; ConnectCwave = 'cwave_connect'; DLL_Version= 'DLL_Version'; - DLL_identity = 22; %20; + DLL_identity = 24; %22; %20; Admin = 'admin_elevate'; - OPO_rlambda = 'opo_rlambda'; + OPO_rLambda = 'opo_rlambda'; TempRef = 'tref_is'; TempOPO = 'topo_is'; TempSHG1 = 'tshg_is1'; @@ -55,6 +58,8 @@ TempOPO_sp = 'topo_set'; TempSHG_sp = 'tshg_set'; TempRef_sp = 'tref_set'; + TempFPGA = 'temp_fpga'; + TempBase = 'temp_base'; UpdateStatus = 'cwave_updatestatus'; Get_IntValue = 'get_intvalue'; Get_floatValue = 'get_floatvalue'; @@ -108,7 +113,7 @@ OPO_MaxPower = 10000; %dummy value. value needs to be calibrated (testing needed) OPO_MinPower = 100; %dummy value. value needs to be calibrated (testing needed) SHG_MaxPower = 10000; %dummy value. value needs to be calibrated (testing needed) - SHG_MinPower = 100; %was 100%dummy value. value needs to be calibrated (testing needed) + SHG_MinPower = 25; %was 100%dummy value. value needs to be calibrated (testing needed) end %% Signleton Method methods(Static) @@ -201,9 +206,11 @@ obj.Set_FloatValue,obj.SetCommand,obj.LaserStatus, obj.Ext_SetCommand}; if(ismember(FunctionName, inversion_condition)) if(status==-1) - status = 0; + status = boolean(0); end - status = ~status; + status = boolean(~status); + else + status = boolean(status); end switch FunctionName case obj.ConnectCwave @@ -250,7 +257,27 @@ assert(status == 0, 'Opo Piezo was not set to ramp.'); case obj.Is_Ready % 0=C-wave is ready, Optimization has completed; 1==C-wave still optimizing - assert(status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); + if status == 1 + if obj.get_regopo == 2 + disp('CWAVE Warning: C-Wave not ready. Optimization still in progress.\n') + elseif obj.get_regopo == 4 + regOPO4 = ~(obj.opo_stepper_stat & obj.opo_temp_stat & obj.shg_stepper_stat & ... + obj.shg_temp_stat & obj.thin_etalon_stat & obj.etalon_lock_stat & ... + obj.laser_emission_stat & obj.ref_temp_stat); + %obj.opo_lock_stat; + %obj.shg_lock_stat; + [SHGpower, ~] = obj.get_photodiode_shg; + if regOPO4 == true & SHGpower > obj.SHG_MinPower % sSHGpower == false + status = 0; + %disp('CWAVE Warning: C-Wave ready (in RegOPO mode 4).\n'); + else + disp('CWAVE Warning: C-Wave not ready. Optimization still in progress.\n') + end + end + elseif status == 0 + disp('Cwave ready!\n'); + end + %assert(status == 0, ['CWAVE Error: C-Wave not ready. Optimization still in progress']); case obj.Set_FloatValue switch varargin{1} case obj.WLM_PID_Setpoint @@ -272,36 +299,48 @@ assert(status == 0, ['CWAVE Error: command not executed. Check that set_command input are valid.']); case obj.LaserPower % 0=update succeeded, 1=update failed - if (obj.CurrentLaserPWR > obj.Laser_MaxPower) + if (obj.CurrentLaserPWR > obj.Laser_MaxPower | status ==1) assert(status == 0,'CWAVE Error: Laser power not within standard operating range. Lower Power Immediately!!!'); + + %elseif status == 0 + % disp('CWAVE Announcement: Laser power within standard operating range.'); end - disp('CWAVE Warning: Laser power not within standard operating range.'); case obj.OPO_Power % 0=update succeeded, 1=update failed - disp('CWAVE Warning: OPO power not within standard operating range.'); + if status == 1 + error('CWAVE Warning: OPO power not within standard operating range.'); + %elseif status == 0 + % disp('CWAVE Announcement: OPO power in standard operating range.'); + end case obj.SHG_Power % 0=update succeeded, 1=update failed - disp('CWAVE Warning: SHG power not within standard operating range.'); + if status == 1 + disp('CWAVE Warning: SHG power not within standard operating range.'); + %elseif status == 0 + % disp('CWAVE Announcement: SHG power in standard operating range.'); + end case obj.StatusReport if (obj.opo_stepper_stat == 1) - disp('Error OPO stepper not locked'); - elif (obj.opo_temp_stat == 1) + disp('OPO stepper not locked') + elseif (obj.opo_temp_stat == 1) disp('OPO temperature not locked'); - elif (obj.shg_stepper_stat == 1) + elseif (obj.shg_stepper_stat == 1) disp('SHG stepper not locked'); - elif (obj.shg_temp_stat == 1) + elseif (obj.shg_temp_stat == 1) disp('SHG temp not locked'); - elif (obj.thin_etalon_stat == 1) + elseif (obj.thin_etalon_stat == 1) disp('Thin etalon not locked'); - elif (obj.opo_lock_stat == 1 && obj.get_intvalue(RegOPO_On) == 2) + elseif (obj.opo_lock_stat == 1 && obj.get_intvalue(obj.RegOpo_On) == 2) disp('OPO cavity piezo not locked.'); - elif (obj.shg_lock_stat == 1) + elseif (obj.shg_lock_stat == 1 && obj.get_intvalue(obj.RegOpo_On) == 2) disp('SHG cavity piezo not locked'); - elif (obj.etalon_lock_stat == 1) + %elseif (obj.opo_lock_stat == 1 && obj.shg_lock_stat == 1 && obj.get_intvalue(obj.RegOpo_On) == 4) + % disp('In RegOPO mode 4. OPO and SHG are not locked.'); + elseif (obj.etalon_lock_stat == 1) disp('thick etalon not locked'); - elif (obj.laser_emission_stat == 1) + elseif (obj.laser_emission_stat == 1) disp('No Pump emission! Unshutter Millenia Edge!'); - elif (obj.ref_temp_stat == 1) + elseif (obj.ref_temp_stat == 1) disp('Reference cavity temperature is not locked!!!'); end @@ -378,16 +417,16 @@ %Returns: Returns status int value. 0 means update succeeded, 1 means update failed. measure_status = LibraryFunction(obj.LibraryName,obj.UpdateStatus); end - + function intvalue = get_intvalue(obj, cmd) %Description: Reads the value of an integer parameter. %Arguments: Parameter as string. See parameter list for valid parameters. %Returns: Returns the requested integer value. %% INT PARAMETER LIST - % Name Type Valid range Read / Write Description - %% topo_set Int 20000-170000 RW Setpoint of the OPO temperature in mK - % topo_is Int 20000-170000 R Current OPO temperature in mK + % Name Type Valid range Read / Write Description + %% topo_set Int 20000-170000 RW Setpoint of the OPO temperature in mK + % topo_is Int 20000-170000 R Current OPO temperature in mK %% tshg_set Int 20000-170000 RW Setpoint of the SHG temperature in mK % tshg_is1 Int 20000-170000 R Current SHG1 temperature in mK %% tshg_is2 Int 20000-170000 R Current SHG2 temperature in mK @@ -423,18 +462,18 @@ % Should not need to be touched. %% regeta_set Int 0-65535 RW Setpoint of the OPO regulator. Mid-range values are normal. %% Should not need to be touched. - % reghsg_threshold Int 0-4095 RW SHG power threshold above which SHG regulator is active. + % reghsg_threshold Int 0-4095 RW SHG power threshold above which SHG regulator is active. % Needed to select proper mode. Is set automatically, % usually no user input required. %% opo_lambda Int 45000-130000 W Wavelength setpoint of the C-Wave in nm*100. % opo_rlambda Int -100-100 W Execute relative wavelength step (fundamental wavelength!) % in nm*100. Maximum step is 1 nm. - %% thicketa_rel Int -100-100 W Execute relative wavelength step of the thick etalon only + %% thicketa_rel Int -100-100 W Execute relative wavelength step of the thick etalon only %% (fundamental wavelength!) in nm*100. Maximum step is 1 nm. - % thicketa_rel_hr Int -1000...1000 W Same as thicketa_rel but resolution is 1 pm + % thicketa_rel_hr Int -1000...1000 W Same as thicketa_rel but resolution is 1 pm %% WAVELENGTH STABILIZATION PARAMETERS - % Name Type Valid range Default Description + % Name Type Valid range Default Description %% WLM_pid_p Int 0-100000 0 Proportional constant of the wavelength regulator. %% Not needed for many applications % WLM_pid_i Int 0-100000 500 Integral constant for wavelength regulator @@ -448,7 +487,7 @@ % WLM_piezosteps Int 0, 1 1 Allow the regulator to move the cavity piezo to reach % the desired wavelength. %% WLM_regout Int 0-65535 0 Regulator output, good for checking if it works - + %% Read value of integer parameter % no error status bit is returned so calllib is used. intvalue = calllib(obj.LibraryName,obj.Get_IntValue,cmd); @@ -458,20 +497,20 @@ %Description: Reads the value of an floating point parameter. %Arguments: Parameter as string. See parameter list for valid parameters. %Returns: Returns the requested floating point value. - + %% INT PARAMETER LIST - % Name Type Valid range Read / Write Description - %% laser_pow Double 0?1.5 RW Laser power of internal pump laser in W - + % Name Type Valid range Read / Write Description + %% laser_pow Double 0?1.5 RW Laser power of internal pump laser in W + %% WAVELENGTH STABILIZATION PARAMETERS - % Name Type Valid range Default Description - %% WLM_pid_setpoint Double 450?1300 Desired wavelength in nm. - % WLM_targetdeviation Double 0?1 0.01 Desired maximum deviation from the setpoint in nm. + % Name Type Valid range Default Description + %% WLM_pid_setpoint Double 450?1300 Desired wavelength in nm. + % WLM_targetdeviation Double 0?1 0.01 Desired maximum deviation from the setpoint in nm. % The minimum value depends on the used wavemeter resolution. % Smaller values give higher accuracy but may require longer % time or manual input. Larger values result in faster settling % but a less accurate output wavelength. - + %% Read value of float parameter floatvalue = calllib(obj.LibraryName,obj.Get_floatValue,cmd); end @@ -487,6 +526,14 @@ status = obj.LibraryFunction(obj.Set_IntValue,cmd, value); end + function tBase = get_tBase(obj) + tBase = calllib(obj.LibraryName, obj.Get_IntValue,obj.TempBase); + tBase = tBase/1000; %Celcius + end + function tFPGA = get_tFPGA(obj) + tFPGA = calllib(obj.LibraryName, obj.Get_IntValue,obj.TempFPGA); + tFPGA = tFPGA/1000; %Celcius + end function tref = get_tref(obj) tref = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempRef); tref = tref/1000; % Celcius @@ -513,7 +560,7 @@ tshg = calllib(obj.LibraryName,obj.Get_IntValue,obj.TempSHG_sp); tshg = tshg/1000; % Celcius end - + function optimize_status = is_ready(obj) %Description: Checks if all C-Wave routines have finished and the C-Wave produces the desired output %Arguments: none @@ -521,7 +568,7 @@ %% Check if optimization is complete optimize_status = obj.LibraryFunction(obj.Is_Ready); end - + function status = set_floatvalue(obj, cmd,value) % Description: Sets the value of an floating point parameter. % Arguments: cmd is the Parameter as string. See parameter list @@ -532,7 +579,7 @@ %% Writable Wavelength stabilization parameters are listed above in get_floatvalue function comments status = obj.LibraryFunction(obj.Set_FloatValue,cmd, value); end - + function status = set_command(obj, cmd) % Description: Executes a command which has no numerical argument. % Arguments: cmd is the command as string. See the command list for reference. @@ -563,7 +610,7 @@ obj.CurrentLaserPWR = laser_power; obj.CheckErrorStatus(status,obj.LaserPower); end - + function [opo_power,status] = get_photodiode_opo(obj) % Description: Reads the current OPO infrared power % Arguments: none @@ -599,16 +646,16 @@ % Returns: Returns an 16-bit integer value. Each bit corresponds to the % status of one component. 0 means, the component is ready for operation, % 1 means the component is not yet stable. Current valid bits from LSB to MSB are: - % 1 OPO stepper - % 2 OPO temperature - % 3 SHG stepper - % 4 SHG temperature - % 5 Thin etalon - % 6 OPO lock - % 7 SHG lock - % 8 Etalon lock - % 9 Laser emission (inverted) - % 10 Reference temperature + % 1 OPO stepper + % 2 OPO temperature + % 3 SHG stepper + % 4 SHG temperature + % 5 Thin etalon + % 6 OPO lock + % 7 SHG lock + % 8 Etalon lock + % 9 Laser emission (inverted) + % 10 Reference temperature % Poll cwave status cwave_status = calllib(obj.LibraryName, obj.StatusReport); %change to callib status_vector = de2bi(cwave_status); @@ -621,9 +668,9 @@ obj.shg_lock_stat = boolean(status_vector(7)); obj.etalon_lock_stat = boolean(status_vector(8)); obj.laser_emission_stat = ~boolean(status_vector(9)); - %obj.ref_temp_stat = status_vector(10); %doesnt sense error bit - %sometimes - if(all([status_vector(1:8),~status_vector(9)] == 0)) + obj.ref_temp_stat = obj.get_status_temp_ref; %doesnt sense error bit + %sometimes obj.Reference_TempStatus + if(all([status_vector(1:8),~status_vector(9),obj.ref_temp_stat] == 0)) % there is an 11th bit with no documented hw meaning; should be ignored status = 0; else @@ -733,13 +780,13 @@ function set_pid_target_wavelength(obj, setpoint) function set_OPOrLambda(obj,val) %set realtive wavlength shift for shifts 0.1 nm or greater. - obj.set_intvalue(obj.OPO_rLambda, val) + obj.set_intvalue(obj.OPO_rLambda, val); end - + function set_target_deviation(obj, target_dev) obj.set_floatvalue(obj.WLM_targetdeviation, target_dev); end - + function fine_tune(obj) % fine tune based on wavemeter measurement obj.set_intvalue(obj.WLM_PiezoSteps, 1); @@ -748,7 +795,7 @@ function fine_tune(obj) %turn off big wavelength steps (OPO and SHG remain locked) obj.set_intvalue(obj.WLM_BigSteps, 0); end - + function coarse_tune(obj) % coarse tune based on wavemeter measurement % turn on reference cavity steps @@ -763,7 +810,7 @@ function coarse_tune(obj) %Stops optimization of wavelength tuning. flag = obj.set_command(obj.StopOptimization); end - + function piezo = get_ref_cavity_percent(obj) % returns reference cavity piezo percent value piezo_voltage = obj.get_intvalue(obj.RefCavity_Piezo); @@ -884,7 +931,7 @@ function initialize_shutters(obj) %% Table of allowing integer paramters for high finesse WS8-10 wavemeter ext_intvalue = calllib(obj.LibraryName, obj.ExtGet_IntValue,cmd); end - + function [ext_floatvalue] = ext_get_floatvalue(cmd) % Description: Reads the value of an floating point parameter from the external module. % Arguments: Parameter as string. See documentation of external module for valid parameters. @@ -900,7 +947,7 @@ function initialize_shutters(obj) % Returns 1 (0 before inversion) if no or not sufficient laser power is available. laser_status = obj.LibraryFunction(obj.LaserStatus); end - + function [ref_temp_status] = get_status_temp_ref(obj) % Description: Reads the current status of the reference temperature. % Arguments: none @@ -918,7 +965,7 @@ function initialize_shutters(obj) %% Poll OPO Temperature Status opo_temp_status = obj.LibraryFunction(obj.OPO_TempStatus); end - + function [shg_temp_status] = get_status_temp_shg(obj) % Description: Reads the current status of the SHG temperature. % Arguments: none @@ -927,7 +974,7 @@ function initialize_shutters(obj) %% Poll SHG temperature Status shg_temp_status = obj.LibraryFunction(obj.SHG_TempStatus); end - + function [opo_lock_status] = get_status_lock_opo(obj) % Description: Reads the current status of the OPO lock. % Arguments: none @@ -936,7 +983,7 @@ function initialize_shutters(obj) %% Poll opo_lock_status...What exactly is the OPO lock? opo_lock_status = obj.LibraryFunction(obj.OPO_LockStatus); end - + function [shg_lock_status] = get_status_lock_shg(obj) % Description: Reads the current status of the SHG lock. % Arguments: none @@ -954,4 +1001,5 @@ function initialize_shutters(obj) end end + From 836064035c47bdec2c39bc7d40eb54e34d1d47ff Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 10:30:25 -0500 Subject: [PATCH 58/71] Adjusted PID parameters for etalon_pid. --- Modules/+Sources/CWave.m | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index b8b6f322d..1402c566c 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -1347,7 +1347,7 @@ function delete(obj) end end - function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = etalon_pid(obj,setpoint,tolerance,kp,ki,kd) + function [Control, Measured, Dt, IntError, Error, P_term,I_term,D_term] = etalon_pid(obj,setpoint,tolerance,kp,ki,kd) obj.windupGuardmax = obj.EtaWindupGuardmax; obj.windupGuardmin = obj.EtaWindupGuardmin; @@ -1355,11 +1355,11 @@ function delete(obj) switch nargin case 2 tolerance = 0.005; - kp = 200; %was 500 on 11/6/19 noticed it has strong kick back sometimes when near edged of etalon. + kp = 100; %was 500 on 11/6/19 noticed it has strong kick back sometimes when near edged of etalon. ki = 100; kd = 0; case 3 - kp = 200; %was 500 on 11/6/19 noticed it has strong kick back sometimes + kp = 100; %was 500 on 11/6/19 noticed it has strong kick back sometimes ki = 100; kd = 0; end @@ -1383,11 +1383,16 @@ function delete(obj) exit = false; while (abs(curr_error) > tolerance ) tic - obj.updateStatus; - obj.is_cwaveReady(0.1); + %obj.updateStatus; + obj.is_cwaveReady(0.01,false,false); if obj.SHG_power < obj.cwaveHandle.SHG_MinPower - while ( (exit == false) & (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) ) - [wm_lambda_c,wmPower_c,wm_exptime_c, obj.SHG_power, abort, exit] = reset_hysteresis(obj.SHG_power); + while ( ((exit == false) & (obj.SHG_power < obj.cwaveHandle.SHG_MinPower)) | curr_error < 0) + pause(1) + if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) + [wm_lambda_c,wmPower_c,wm_exptime_c, obj.SHG_power, abort, exit] = reset_hysteresis(obj.SHG_power); + else + break + end end curr_error = 2*tolerance; %arbitrary condidtion to start PID loop. ctrl = 0; @@ -1445,7 +1450,7 @@ function delete(obj) Control(i) = obj.LocalMaxEtalon; else obj.cwaveHandle.tune_thick_etalon(ctrl); - Control(i) = ctrl; + Control(i) = round(ctrl); end dt = toc; @@ -1460,7 +1465,7 @@ function delete(obj) D_term(i) = d_term; end end - + function [ctrl,prev_error,int_error,p_term,i_term,d_term] = pid_update(obj, curr_error,prev_error, int_error, kp,ki,kd,dt) % integration From 4c4628c2efd3e4b0e17c4ad9af36aa1556ac570e Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 10:38:56 -0500 Subject: [PATCH 59/71] Updated AllElementStep to include conditions for SHG optimization. --- Modules/+Sources/CWave.m | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 1402c566c..5b05791eb 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -1137,14 +1137,34 @@ function updateStatus(obj) function set.AllElementStep(obj,val) if obj.cwaveHandle.is_ready - return + [~,sSHGpower] = obj.cwaveHandle.get_photodiode_shg; + if obj.sSHG_power + dlg = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); + textH = findall(dlg,'tag','MessageBox'); + delete(findall(dlg,'tag','OKButton')); + drawnow; + obj.cwaveHandle.optimize_shg(); + while obj.cwaveHandle.is_ready + pause(1) + if ~obj.cwaveHandle.is_ready + delete(dlg) + break; + else + obj.updateStatus; + end + end + else + return + end end + + obj.AllElementStep = floor( eval(val) ); - obj.cwaveHandle.set_OPOrLambda(); - obj.is_cwaveReady(obj.EtalonStepperDelay,true); + obj.cwaveHandle.set_OPOrLambda(obj.AllElementStep); + obj.is_cwaveReady(0.001,true,false); + obj.updateStatus; end - - + function tune_etalon(obj) if obj.cwaveHandle.is_ready == true return From 59b5adc7ea2de1bbb2bdb759389dbac8c6da061f Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 10:54:21 -0500 Subject: [PATCH 60/71] Removed isCwave ready conditional statement from tune_etalon. --- Modules/+Sources/CWave.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 5b05791eb..2e2455446 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -1166,14 +1166,12 @@ function updateStatus(obj) end function tune_etalon(obj) - if obj.cwaveHandle.is_ready == true - return - end +% if obj.cwaveHandle.is_ready == true +% return +% end obj.cwaveHandle.tune_thick_etalon(obj.EtalonStep); - %obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); - % obj.updateStatus; - %obj.is_cwaveReady(obj.EtalonStepperDelay,false,false); end + function set_regopo(obj,val) obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,val); From 408d41e873316324d19f04869a8f866453cf99d9 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 11:04:44 -0500 Subject: [PATCH 61/71] using tune etalon with 10 ms pause in set.EtalonStep. --- Modules/+Sources/CWave.m | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 2e2455446..7abb4ef78 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -1128,11 +1128,9 @@ function updateStatus(obj) % function set.EtalonStep(obj,val) obj.EtalonStep = eval(val); - %disp(val); - %obj.tune_etalon; - obj.cwaveHandle.set_intvalue(obj.cwaveHandle.ThickEtalon_Piezo_hr,obj.EtalonStep); - pause(obj.EtalonMeasureDelay); - %obj.updateStatus; + obj.tune_etalon; + pause(0.010); + obj.updateStatus; end function set.AllElementStep(obj,val) From eec5847b5313f17009b84b4b959f5b3204bec0cf Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 11:18:10 -0500 Subject: [PATCH 62/71] added passes and condtional statement for resetting hysteresis. --- Modules/+Sources/CWave.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 7abb4ef78..8299672f0 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -912,7 +912,7 @@ function updateStatus(obj) end end - function abort = centerThickEtalon(obj) + function abort = centerThickEtalon(obj) dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... 'Centering Etalon Warning', ... 'Yes, Continue Tuning','No, Please Autotune', 'No, Abort','No, Abort'); @@ -936,7 +936,7 @@ function updateStatus(obj) pstep = 25; nstep = -25; obj.updateStatus; - + PowerMeasureCondition_regopo2 = (obj.ref_temp_lock == true) & (obj.pump_emission == true) & ... (obj.opo_lock == true) & (obj.thin_etalon_lock == true) & ... (obj.shg_temp_lock == true) & (obj.shg_stepper_lock == true) & ... @@ -1036,7 +1036,7 @@ function updateStatus(obj) [wm_lambda_i,wmPower_i,wm_exptime_i] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); exiting = obj.EtalonStepper(pstep, obj.EtalonMeasureDelay); pause(obj.EtalonMeasureDelay) - + disp('Enter +eta loop') fprintf('Control power: %.8f\n',currPower); fprintf('Initial Power: %.8f\n',powerSHG_i); @@ -1045,8 +1045,10 @@ function updateStatus(obj) fprintf('current exposure: %.8f\n',wm_exptime_c); if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) - - [wm_lambda_c,wmPower_c,wm_exptime_c,abort, exiting] = reset_hysteresis(currPower); + pause(1) + if (obj.SHG_power < obj.cwaveHandle.SHG_MinPower) + [wm_lambda_c,wmPower_c,wm_exptime_c,abort, exiting] = obj.reset_hysteresis(currPower); + end else [wm_lambda_c,wmPower_c,wm_exptime_c] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); @@ -1116,6 +1118,7 @@ function updateStatus(obj) end end + function set.MaxEtalon_wl(obj,val) a = eval(val); From c51e23be1e0609578247604844868f7b05b58051 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 11:27:22 -0500 Subject: [PATCH 63/71] added break and contine conditions to is_cwaveReady. --- Modules/+Sources/CWave.m | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 8299672f0..1be31c2e7 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -813,35 +813,39 @@ function updateStatus(obj) function abort = is_cwaveReady(obj,delay_val,SHG_tuning,allStatus) switch nargin - case 0 + case 1 delay_val = 1; SHG_tuning = false; allStatus = true; - case 1 + case 2 SHG_tuning = false; allStatus = true; - case 2 + case 3 allStatus = true; end abort = false; + time = 0; tic; while(obj.cwaveHandle.is_ready) pause(delay_val); %in seconds if allStatus == true - obj.udpateStatus; + obj.updateStatus; + %[obj.SHG_power, obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; else [obj.SHG_power, obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; end - time = toc; - if (time > obj.timeoutSHG & SHG_tuning == true & (obj.shg_lock == false | obj.shg_temp_lock == false) ) + time = time + toc; + if (time > obj.timeoutSHG & SHG_tuning == true & (obj.shg_lock == false | obj.shg_temp_lock == false | obj.sSHG_power == 0 ) ) dialog = msgbox('Please wait while CWave re-optimizes SHG power.',mfilename,'modal'); - textH = findall(dlg,'tag','MessageBox'); - delete(findall(dlg,'tag','OKButton')); + textH = findall(dialog,'tag','MessageBox'); + delete(findall(dialog,'tag','OKButton')); drawnow; obj.cwaveHandle.optimize_shg; - pause(5) + while(obj.cwaveHandle.is_ready) + pause(5) + end delete(dialog); elseif time > obj.timeoutAllElements dialog = questdlg('Tuning Timed out. Continue or abort tuning?', ... @@ -857,8 +861,21 @@ function updateStatus(obj) return; end end + + if (obj.cwaveHandle.get_regopo == 4) + regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... + & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; + if regopo4_locked == true & obj.sSHG_power == 0 + break; + end + elseif obj.cwaveHandle.getregopo == 2 & obj.locked == true + break; + else + continue; + end end end + function [wm_lambda_c,wmPower_c,wm_exptime_c, abort, exit] = reset_hysteresis(obj,pstep) i =1; From 369e13eb3ff06bba7c42b2541b34fe08bf5dff1c Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 11:58:13 -0500 Subject: [PATCH 64/71] updateStatus now now returns FPGA and Base temp of CWave. --- Modules/+Sources/CWave.m | 76 ++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 1be31c2e7..f97fed720 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -10,7 +10,7 @@ % % The laser tuning is controlled by the methods required by the % TunableLaser_invisible superclass. - + properties(SetObservable,SetAccess=private) source_on = false; end @@ -54,22 +54,22 @@ prefs = {'tuning','enabled','target_wavelength','wavelength_lock','etalon_lock',... 'opo_stepper_lock','opo_temp_lock','shg_stepper_lock', 'shg_temp_lock','thin_etalon_lock',... 'opo_lock','shg_lock','pump_emission','ref_temp_lock','resonator_percent',... - 'etalon_percent','PSline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... + 'etalon_percent','PBline','pulseStreamer_ip','cwave_ip','wavemeter_ip',... 'resonator_tune_speed','tunePercentRange','MaxEtalon_wl','MinEtalon_wl',... 'EtalonStep','MidEtalon_wl','OPO_power','SHG_power','Pump_power','AllElementStep',... - 'TempRef','TempOPO', 'TempSHG','TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint'}; - show_prefs = {'target_wavelength','resonator_percent','AllElementStep','EtalonStep','tunePercentRange',... + 'TempRef','TempOPO', 'TempSHG','TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint','TempBase','TempFPGA'}; %,'TempBase','TempFPGA' + show_prefs = {'TempBase','TempFPGA','target_wavelength','resonator_percent','AllElementStep','EtalonStep','tunePercentRange',... 'resonator_tune_speed','MidEtalon_wl','MaxEtalon_wl','MinEtalon_wl','tuning',... 'enabled','wavelength_lock','etalon_lock','opo_stepper_lock','opo_temp_lock','shg_stepper_lock',... 'shg_temp_lock','thin_etalon_lock','opo_lock','shg_lock','pump_emission','ref_temp_lock',... 'etalon_percent','OPO_power','SHG_power','Pump_power','TempOPO','TempOPO_setpoint',... - 'TempSHG','TempSHG_setpoint','TempRef','TempRef_setpoint','PSline',... - 'pulseStreamer_ip','cwave_ip','wavemeter_ip'}; + 'TempSHG','TempSHG_setpoint','TempRef','TempRef_setpoint','PBline',... + 'pulseStreamer_ip','cwave_ip','wavemeter_ip'}; % 'TempBase','TempFPGA', readonly_prefs = {'tuning','etalon_lock','opo_stepper_lock','opo_temp_lock',... 'shg_stepper_lock', 'shg_temp_lock','thin_etalon_lock','opo_lock','shg_lock',... - 'pump_emission','ref_temp_lock','MidEtalon_wl',... + 'pump_emission','ref_temp_lock','MidEtalon_wl','resonator_percent', ... 'OPO_power','SHG_power','Pump_power','TempRef','TempOPO', 'TempSHG',... - 'TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint'}; + 'TempRef_setpoint','TempOPO_setpoint', 'TempSHG_setpoint','TempBase','TempFPGA'}; % ,'TempBase','TempFPGA' end properties(SetObservable,GetObservable) MidEtalon_wl = ''; @@ -79,7 +79,7 @@ % cwave_ip = Prefs.String('default',Sources.CWave.no_server,'allow_empty',true,'set',''); % pulseStreamer_ip = Prefs.String(Sources.CWave.no_server,'allow_empty',false),'set',''; % wavemeter_ip = Prefs.String(Sources.CWave.no_server,'allow_empty',false),'set',''; - PSline = Prefs.Integer('min',0,'help_text','indexed from 0'); % Index from 0 (Pulsestreamer has 8 digital out channels) + PBline = Prefs.Integer('min',0,'help_text','indexed from 0'); % Index from 0 (Pulsestreamer has 8 digital out channels) resonator_tune_speed = Prefs.Double(0.5,'units','percent','min',0.001,'max',1); % percent per step etalon_lock = Prefs.Boolean('help_text','This is a readonly string.','readonly',true); etalon_percent = Prefs.Boolean( 'help_text','This is a readonly string.','readonly',true); @@ -96,6 +96,8 @@ OPO_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); SHG_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); Pump_power = Prefs.Double(0.0,'units','mW','min',0,'max',5000); + TempBase = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); + TempFPGA = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); TempRef = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); TempOPO = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); TempSHG = Prefs.Double(20.00,'units','Celcius','min',20,'max',170.00); @@ -119,6 +121,7 @@ wavemeterHandle cwaveHandle end + methods(Access=private) function obj = CWave() @@ -603,9 +606,17 @@ function TuneCoarse(obj, setpoint) obj.updateStatus(); % Get voltage of resonator end - function updateStatus(obj) + function updateStatus(obj) % Get status report from laser and update a few fields - tic + tic; + obj.TempBase = obj.cwaveHandle.get_tBase; + obj.TempFPGA = obj.cwaveHandle.get_tFPGA; + obj.TempRef = obj.cwaveHandle.get_tref; + obj.TempOPO = obj.cwaveHandle.get_topo; + obj.TempSHG = obj.cwaveHandle.get_tshg; + obj.TempRef_setpoint = obj.cwaveHandle.get_tref_sp; + obj.TempOPO_setpoint = obj.cwaveHandle.get_topo_sp; + obj.TempSHG_setpoint = obj.cwaveHandle.get_tshg_sp; obj.locked = ~(obj.cwaveHandle.get_statusbits); obj.etalon_lock = ~obj.cwaveHandle.etalon_lock_stat; obj.opo_stepper_lock = ~obj.cwaveHandle.opo_stepper_stat; @@ -616,28 +627,27 @@ function updateStatus(obj) obj.opo_lock = ~obj.cwaveHandle.opo_lock_stat; obj.shg_lock = ~obj.cwaveHandle.shg_lock_stat; obj.pump_emission = ~obj.cwaveHandle.laser_emission_stat; - obj.ref_temp_lock = ~obj.cwaveHandle.get_status_temp_ref; + obj.ref_temp_lock = ~obj.cwaveHandle.ref_temp_stat; + %obj.ref_temp_lock = ~obj.cwaveHandle.get_status_temp_ref; [obj.OPO_power,obj.sOPO_power] = obj.cwaveHandle.get_photodiode_opo; [obj.SHG_power,obj.sSHG_power] = obj.cwaveHandle.get_photodiode_shg; [obj.Pump_power,obj.sPump_power] = obj.cwaveHandle.get_photodiode_laser; - obj.TempRef = obj.cwaveHandle.get_tref; - obj.TempOPO = obj.cwaveHandle.get_topo; - obj.TempSHG = obj.cwaveHandle.get_tshg; - obj.TempRef_setpoint = obj.cwaveHandle.get_tref_sp; - obj.TempOPO_setpoint = obj.cwaveHandle.get_topo_sp; - obj.TempSHG_setpoint = obj.cwaveHandle.get_tshg_sp; + regopo4_locked = obj.etalon_lock & obj.opo_stepper_lock & obj.opo_temp_lock... & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; - - if(obj.locked | ((obj.cwaveHandle.get_regopo == 4) & regopo4_locked)) + + if( (obj.locked ) | ( (obj.cwaveHandle.get_regopo == 4 ... + & regopo4_locked & obj.sSHG_power == false))) obj.setpoint = obj.c/obj.getWavelength; % This sets wavelength_lock + else + obj.setpoint = NaN; end - + obj.tuning = ~(obj.locked); - toc - fprintf('toc %.8f\n',toc); + toc; + %fprintf('toc %.8f\n',toc); %obj.setpoint = obj.cwaveHandle.WLM_PID_Setpoint; % Overwrite getWavelength tuning status with EMM tuning state end @@ -698,24 +708,6 @@ function updateStatus(obj) end end - %change to set_target_wavlength and make turn this into setmethod - %as defined in https://github.com/mwalsh161/CommandCenter/blob/dev/%2BBase/pref.m - %example of implementation: https://github.com/mwalsh161/CommandCenter/blob/dev/Modules/%2BImaging/debug.m#L55 - %f you're wondering where the set property is defined, it is in Base.pref - also worth reading until I get it onto the wiki to better understand what's happening: https://github.com/mwalsh161/CommandCenter/blob/dev/%2BBase/pref.m -% Matthew Feldman 5:16 PM -% Yea the latter. Thanks. But just for my own understanding the testSet method sets a value to a preference (even though there is only a print statemet in the body of the method)? Is this behavior explained in the pref.m link you just sent? -% Michael Walsh 5:25 PM -% it should be explained -% unlike MATLAB's set.prop methods, these set methods require you to return the value -% new messages -% so while testSet seems to only be doing an fprintf, the input val is returned as well -% function set.target_wavelength(obj,val) -% %if isnan(val.default); obj.target_wavelength = val; return; end % Short circuit on NaN -% if isnan(val.ui); obj.target_wavelength = val; return; end % Short circuit on NaN -% if obj.internal_call; obj.target_wavelength = val; return; end -% obj.tune(val); -% end - function set.target_wavelength(obj,val) %edite 10/30/19 note sure why this is read only??? %if isnan(val); obj.target_wavelength = val; return; end % Short circuit on NaN @@ -742,7 +734,7 @@ function updateStatus(obj) end end - + function [wm_wl,wm_power,wm_exptime] = powerStatus(obj, tol,delay_val) i = 0; max_interation = 10; From b850c6752d00c6645ac0c039b59a5002c1b8b1a5 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 12:39:02 -0500 Subject: [PATCH 65/71] fixed typos. --- Modules/+Sources/CWave.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index f97fed720..5b4f5f5dd 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -122,7 +122,6 @@ cwaveHandle end - methods(Access=private) function obj = CWave() obj.loadPrefs; @@ -308,7 +307,7 @@ function tune(obj, setpoint,target_dev,coarse,lock) & obj.shg_stepper_lock & obj.shg_temp_lock & obj.thin_etalon_lock & obj.pump_emission; regOPO4_cond = regopo4_locked == true & obj.cwaveHandle.get_regopo == 4 & ... abs(setpoint-obj.getWavelength) > obj.midTuneTolerance; - regOPO2_cond = robj.locked == true & obj.cwaveHandle.get_regopo == 2 & ... + regOPO2_cond = obj.locked == true & obj.cwaveHandle.get_regopo == 2 & ... abs(setpoint-obj.getWavelength) > obj.midTuneTolerance; obj.updateStatus; From 6713101a2d32d8c367dac2409448f321965e2af2 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 12:48:40 -0500 Subject: [PATCH 66/71] fixed typos with PBline. --- Modules/+Sources/CWave.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 5b4f5f5dd..4805184ae 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -167,7 +167,7 @@ function on(obj) assert(~isempty(obj.PulseStreamerHandle), 'No IP set for PulseStreamer!') - state = PulseStreamer.OutputState([obj.PSline],0,0); + state = PulseStreamer.OutputState([obj.PBline],0,0); obj.PulseStreamerHandle.PS.constant(state); obj.source_on = true; From 38dcbe187a638c5b71eb83396af1e17d6c2e834a Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 13:07:03 -0500 Subject: [PATCH 67/71] Updated set.cwave_ip to updateStatus. --- Modules/+Sources/CWave.m | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 4805184ae..5bd119327 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -675,6 +675,14 @@ function updateStatus(obj) rethrow(err) end obj.cwave_ip = ip; + + while(1) + if libisloaded(obj.cwaveHandle.LibraryName) + obj.updateStatus; + break + end + pause(1); + end end function set.pulseStreamer_ip(obj, ip) @@ -866,7 +874,6 @@ function updateStatus(obj) end end end - function [wm_lambda_c,wmPower_c,wm_exptime_c, abort, exit] = reset_hysteresis(obj,pstep) i =1; @@ -1127,7 +1134,6 @@ function updateStatus(obj) end - function set.MaxEtalon_wl(obj,val) a = eval(val); obj.MaxEtalon_wl = a; @@ -1181,7 +1187,6 @@ function tune_etalon(obj) obj.cwaveHandle.tune_thick_etalon(obj.EtalonStep); end - function set_regopo(obj,val) obj.cwaveHandle.set_intvalue(obj.cwaveHandle.RegOpo_On,val); end @@ -1491,7 +1496,7 @@ function delete(obj) I_term(i) = i_term; D_term(i) = d_term; end - end + end function [ctrl,prev_error,int_error,p_term,i_term,d_term] = pid_update(obj, curr_error,prev_error, int_error, kp,ki,kd,dt) From 5aa7c1b8096e5f8501a9f31fe703982df7cffa35 Mon Sep 17 00:00:00 2001 From: Matthew Feldman Date: Mon, 18 Nov 2019 13:58:23 -0500 Subject: [PATCH 68/71] Cleaned up ta bs. Personal preferecne. --- Modules/+Sources/CWave.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/+Sources/CWave.m b/Modules/+Sources/CWave.m index 5bd119327..af999d59c 100644 --- a/Modules/+Sources/CWave.m +++ b/Modules/+Sources/CWave.m @@ -605,7 +605,7 @@ function TuneCoarse(obj, setpoint) obj.updateStatus(); % Get voltage of resonator end - function updateStatus(obj) + function updateStatus(obj) % Get status report from laser and update a few fields tic; obj.TempBase = obj.cwaveHandle.get_tBase; @@ -926,8 +926,8 @@ function updateStatus(obj) % [wm_lambda_c,wmPower_c,wm_exptime_c,currPower] = obj.powerStatus(obj.wmExposureTolerance, obj.powerStatusDelay); end end - - function abort = centerThickEtalon(obj) + + function abort = centerThickEtalon(obj) dlgs = questdlg('Is Min and Max range of Etalon correctly set? MaxEtalon_wl and MinEtalon_wl must be measured by autotune or manually by adjusting EtalonStep. If tuning manually MaxEtalon_wl and MinEtalon_wl in Cwave Source preferences', ... 'Centering Etalon Warning', ... 'Yes, Continue Tuning','No, Please Autotune', 'No, Abort','No, Abort'); From a1fef08379378723319871f4d76c3394475fdae6 Mon Sep 17 00:00:00 2001 From: Matthew Andre Feldman Date: Tue, 16 Mar 2021 15:18:51 -0400 Subject: [PATCH 69/71] Delete ConnectableMixin_invisible.m Superfluous source. --- Modules/+Sources/ConnectableMixin_invisible.m | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 Modules/+Sources/ConnectableMixin_invisible.m diff --git a/Modules/+Sources/ConnectableMixin_invisible.m b/Modules/+Sources/ConnectableMixin_invisible.m deleted file mode 100644 index c1e4a20a2..000000000 --- a/Modules/+Sources/ConnectableMixin_invisible.m +++ /dev/null @@ -1,19 +0,0 @@ -classdef(Abstract) ConnectableMixin_invisible < handle - methods(Access=private) - function err = connect_driver(obj,propname,drivername,varargin) - err = []; - if ~isempty(obj.(propname)) - delete(obj.(propname)); %remove any old connection - end - if ischar(varargin{1}) && strcmpi(varargin{1},'No Server') %first input is always an ip address - obj.(propname) = []; - else - try - obj.(propname) = Drivers.(drivername).instance(varargin{:}); - catch err - obj.(propname) = []; - end - end - end - end -end \ No newline at end of file From f0f7f3b2e1727dc7f601fb7bcc50ec467e388baa Mon Sep 17 00:00:00 2001 From: Matthew Andre Feldman Date: Tue, 16 Mar 2021 15:19:40 -0400 Subject: [PATCH 70/71] Delete cwave_testscript.m Test scripts shouldn't be on any branch. --- Modules/+Sources/cwave_testscript.m | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 Modules/+Sources/cwave_testscript.m diff --git a/Modules/+Sources/cwave_testscript.m b/Modules/+Sources/cwave_testscript.m deleted file mode 100644 index d1c3fb92f..000000000 --- a/Modules/+Sources/cwave_testscript.m +++ /dev/null @@ -1,16 +0,0 @@ -cwave = Sources.CWave.instance(); - -cwave.cwave_ip = '192.168.11.3'; -cwave.pulseStreamer_ip = '192.168.11.4'; -cwave.wavemeter_ip = '192.168.11.2'; - - -disp('starting vals') -disp(cwave.GetPercent()) -disp(cwave.getFrequency()) - -%cwave.TunePercent(10) -cwave.TuneSetpoint(618.9488); -disp('after tunepercent to 10') -disp(cwave.GetPercent()) -disp(cwave.getFrequency()) \ No newline at end of file From c573165e27c71e8fc96b76adacf84679a1529eff Mon Sep 17 00:00:00 2001 From: Matthew Andre Feldman Date: Tue, 16 Mar 2021 15:20:07 -0400 Subject: [PATCH 71/71] Delete cwave_testscript.m Test scripts shouldn't be on any branch. --- Modules/+Drivers/cwave_testscript.m | 51 ----------------------------- 1 file changed, 51 deletions(-) delete mode 100644 Modules/+Drivers/cwave_testscript.m diff --git a/Modules/+Drivers/cwave_testscript.m b/Modules/+Drivers/cwave_testscript.m deleted file mode 100644 index 18e495ef7..000000000 --- a/Modules/+Drivers/cwave_testscript.m +++ /dev/null @@ -1,51 +0,0 @@ -clear CWave; -clc; - -cwave = Drivers.CWave.instance('192.168.11.3'); -wavemeter = Drivers.Wavemeter.instance('0.0.0.0', 1, 1); % IP address of wavemeter? - -disp('wavemeter:') -disp(wavemeter.getWavelength()) - -%cwave.abort_tune() - -%disp(cwave.get_status_temp_ref()) - -%disp('status:') -%disp(cwave.get_statusbits()) - -disp('ref temp:') -disp(cwave.get_status_temp_ref()) - -disp('shg temp:') -disp(cwave.get_status_temp_shg()) - -disp('opo temp:') -disp(cwave.get_status_temp_opo()) - -%failed status=1, 'optimization has not stopped' -cwave.abort_tune() - -%failed status=1, 'opo not locked, optimization still in progress' -%disp('OPO lock:') -%disp(cwave.get_status_lock_opo()) - -%failed status=1, 'etalon not locked, optimization still in progress' -%disp('etalon lock:') -%disp(cwave.get_status_lock_etalon()) - -disp('photodiode power:') -disp(cwave.get_photodiode_laser()) - -disp('current OPO infrared power:') -disp(cwave.get_photodiode_opo()) - -disp('current piezo percent:') -disp(cwave.get_ref_cavity_percent()) - -%cwave.target_wavelength = 615.000001; -%cwave.set_target_wavelength() - -disp('new piezo percent:') -disp(cwave.get_ref_cavity_percent()) -