@@ -240,7 +240,7 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
240240 Itr = ev .Itr
241241 whichDM = mp .est .probe .whichDM
242242
243- # # Reset "ev" if not using a Kalman filter.
243+ # # Reset "ev" if not using a Kalman filter.
244244 # if mp.estimator != 'pwp-kf':
245245 # # ev = falco.config.Object()
246246 # ev.dm1 = falco.config.Object()
@@ -293,12 +293,12 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
293293
294294 # Store the initial DM commands
295295 if np .any (mp .dm_ind == 1 ):
296- DM1Vnom = mp .dm1 .V
296+ DM1Vnom = mp .dm1 .V . copy ()
297297 else :
298298 DM1Vnom = np .zeros ((mp .dm1 .Nact , mp .dm1 .Nact ))
299299
300300 if np .any (mp .dm_ind == 2 ):
301- DM2Vnom = mp .dm2 .V
301+ DM2Vnom = mp .dm2 .V . copy ()
302302 else :
303303 DM2Vnom = np .zeros ((mp .dm2 .Nact , mp .dm2 .Nact ))
304304
@@ -323,7 +323,9 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
323323 for k in range (Npairs - 1 ):
324324 probePhaseVec = np .append (probePhaseVec , probePhaseVec [- 1 ]- (Npairs - 1 ))
325325 probePhaseVec = np .append (probePhaseVec , probePhaseVec [- 1 ]+ Npairs )
326+ # print(f'probePhaseVec = {probePhaseVec}')
326327 probePhaseVec = probePhaseVec * np .pi / (Npairs )
328+ print (f'probePhaseVec = { probePhaseVec } ' )
327329
328330 # Only for square probe region centered on the star
329331 if mp .estimator in ('pairwise' , 'pairwise-square' , 'pwp-bp-square' ):
@@ -378,8 +380,8 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
378380
379381 # Measure current contrast level average
380382 # Reset DM commands to the unprobed state:
381- mp .dm1 .V = DM1Vnom
382- mp .dm2 .V = DM2Vnom
383+ mp .dm1 .V = DM1Vnom . copy ()
384+ mp .dm2 .V = DM2Vnom . copy ()
383385 # Separate out image values at DH pixels and delta DM voltage settings
384386 Iplus = np .zeros ((mp .Fend .corr .Npix , Npairs ))
385387 Iminus = np .zeros ((mp .Fend .corr .Npix , Npairs ))
@@ -391,7 +393,7 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
391393 # Compute probe shapes and take probed images:
392394
393395 # Take initial, unprobed image (for unprobed DM settings).
394- whichImage = 1
396+ whichImage = 0
395397 I0 = falco .imaging .get_sbp_image (mp , iSubband )
396398 I0vec = I0 [mp .Fend .corr .maskBool ] # Vectorize the dark hole
397399
@@ -402,9 +404,9 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
402404 # Store values for first image and its DM commands
403405 ev .imageArray [:, :, whichImage , iSubband ] = I0
404406 if np .any (mp .dm_ind == 1 ):
405- ev .dm1 .Vall [:, :, whichImage , iSubband ] = mp .dm1 .V
407+ ev .dm1 .Vall [:, :, whichImage , iSubband ] = mp .dm1 .V . copy ()
406408 if np .any (mp .dm_ind == 2 ):
407- ev .dm2 .Vall [:, :, whichImage , iSubband ] = mp .dm2 .V
409+ ev .dm2 .Vall [:, :, whichImage , iSubband ] = mp .dm2 .V . copy ()
408410
409411 # Compute the average Inorm in the scoring and correction regions
410412 ev .corr = falco .config .Object ()
@@ -502,7 +504,7 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
502504 ampSq [ampSq < 0 ] = 0 # If probe amplitude is zero, set amp = 0
503505 amp = np .sqrt (ampSq ) # E-field amplitudes, dimensions: [mp.Fend.corr.Npix, Npairs]
504506 isnonzero = np .all (amp , 1 )
505- zAll = ((Iplus - Iminus )/ 4 ).T # Measurement vector, dimensions: [Npairs,mp.Fend.corr.Npix]
507+ zAll = ((Iplus - Iminus )/ 4 ).T # Measurement vector, dimensions: [Npairs, mp.Fend.corr.Npix]
506508 ampSq2Dcube = np .zeros ((mp .Fend .Neta , mp .Fend .Nxi , mp .est .probe .Npairs ))
507509 for iProbe in range (Npairs ): # Display the actual probe intensity
508510 ampSq2D = np .zeros ((mp .Fend .Neta , mp .Fend .Nxi ))
@@ -544,9 +546,9 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
544546
545547 # For unprobed field based on model:
546548 if np .any (mp .dm_ind == 1 ):
547- mp .dm1 .V = DM1Vnom
549+ mp .dm1 .V = DM1Vnom . copy ()
548550 if np .any (mp .dm_ind == 2 ):
549- mp .dm2 .V = DM2Vnom
551+ mp .dm2 .V = DM2Vnom . copy ()
550552
551553 E0 = falco .model .compact (mp , modvar )
552554 E0vec = E0 [mp .Fend .corr .maskBool ]
@@ -578,8 +580,8 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
578580 dphdm = np .zeros ((mp .Fend .corr .Npix , Npairs )) # phases
579581 for iProbe in range (Npairs ):
580582 dphdm [:, iProbe ] = np .arctan2 (
581- np .imag (dEplus [:, iProbe ]) - np . imag ( dEminus [:, iProbe ]),
582- np .real (dEplus [:, iProbe ]) - np . real ( dEminus [:, iProbe ]))
583+ np .imag (dEplus [:, iProbe ] - dEminus [:, iProbe ]),
584+ np .real (dEplus [:, iProbe ] - dEminus [:, iProbe ]))
583585
584586 # Batch process the measurements to estimate the electric field in the
585587 # dark hole. Done pixel by pixel.
@@ -592,30 +594,55 @@ def pairwise_probing(mp, ev, jacStruct=np.array([])):
592594
593595 Eest = np .zeros ((mp .Fend .corr .Npix ,), dtype = complex )
594596 zerosCounter = 0 # number of zeroed-out dark hole pixels
597+ partialCounter = 0 # number of pixels with >=2 but <Npairs usable probe pairs.
595598 for ipix in range (mp .Fend .corr .Npix ):
596599
597600 if mp .est .flagUseJac :
598601 dE = dEplus [ipix , :].T
599602 H = np .array ([np .real (dE ), np .imag (dE )])
603+ Epix = np .linalg .pinv (H ) @ zAll [:, ipix ] # Batch processing
600604 else :
605+ allProbeInds = np .arange (Npairs , dtype = int )
606+ goodProbeInds = allProbeInds [amp [ipix , :] > 0 ]
607+ NpairsGood = len (goodProbeInds )
608+
601609 H = np .zeros ([Npairs , 2 ]) # Observation matrix
602- # Leave Eest for a pixel as zero if any probe amp is 0
603- if isnonzero [ipix ] == 1 :
604- for iProbe in range (Npairs ):
605- H [iProbe , :] = amp [ipix , iProbe ] * \
606- np .array ([np .cos (dphdm [ipix , iProbe ]),
607- np .sin (dphdm [ipix , iProbe ])])
608- else :
610+
611+ # If <2 probe pairs had good measurements, can't do pinv. Leave Eest as zero.
612+ if NpairsGood < 2 :
613+ zerosCounter = zerosCounter + 1
614+ Epix = np .zeros ((2 , 1 ))
609615 zerosCounter += 1
610616
611- Epix = np .linalg .pinv (H ) @ zAll [:, ipix ] # Batch processing
617+ # Otherwise, use the 2+ good probe pair measurements for that pixel
618+ else :
619+ for iProbe in range (Npairs ):
620+ H [iProbe , :] = amp [ipix , iProbe ] * np .array ([
621+ np .cos (dphdm [ipix , iProbe ]), np .sin (dphdm [ipix , iProbe ])])
622+
623+ Epix = np .linalg .pinv (H [goodProbeInds , :]) @ zAll [goodProbeInds , ipix ] # Batch processing
624+
625+ # Record how many pixels didn't use all the probe pairs
626+ if NpairsGood < Npairs :
627+ partialCounter = partialCounter + 1
628+
629+ # # Leave Eest for a pixel as zero if any probe amp is 0
630+ # if isnonzero[ipix] == 1:
631+ # for iProbe in range(Npairs):
632+ # H[iProbe, :] = amp[ipix, iProbe] * \
633+ # np.array([np.cos(dphdm[ipix, iProbe]),
634+ # np.sin(dphdm[ipix, iProbe])])
635+
612636 Eest [ipix ] = Epix [0 ] + 1j * Epix [1 ]
613637
614638 # If estimate is too bright, the estimate was probably bad.
615639 Eest [np .abs (Eest )** 2 > mp .est .Ithreshold ] = 0.0
616640
617641 print ('%d of %d pixels were given zero probe amplitude.' %
618642 (zerosCounter , mp .Fend .corr .Npix ))
643+ if Npairs > 2 : # Only possible for Npairs > 2
644+ print ('%d of %d pixels threw out at least one probe pair.' %
645+ (partialCounter , mp .Fend .corr .Npix ))
619646
620647 # Initialize the state and state covariance estimates for the
621648 # Kalman filter. The state is the real and imag parts of the
0 commit comments