@@ -2251,7 +2251,8 @@ def unwrap2d(self, conncomp=False, conncomp_size=1000, conncomp_gap=None,
22512251 """
22522252 Unwrap phase using GPU-accelerated IRLS algorithm (L¹ norm).
22532253
2254- Expects Batches with [BatchWrap (phase), BatchUnit (weight, optional)].
2254+ Expects Batches with [BatchWrap or BatchComplex (phase), BatchUnit (weight, optional)].
2255+ If the first element is BatchComplex, .angle() is called automatically.
22552256
22562257 Parameters
22572258 ----------
@@ -2291,8 +2292,12 @@ def unwrap2d(self, conncomp=False, conncomp_size=1000, conncomp_gap=None,
22912292 phase = self [0 ]
22922293 weight = self [1 ] if len (self ) >= 2 and isinstance (self [1 ], BatchUnit ) else None
22932294
2295+ # Auto-convert complex phase to wrapped phase
2296+ if isinstance (phase , BatchComplex ):
2297+ phase = phase .angle ()
2298+
22942299 if not isinstance (phase , BatchWrap ):
2295- raise TypeError (f"First element must be BatchWrap, got { type (phase ).__name__ } " )
2300+ raise TypeError (f"First element must be BatchWrap or BatchComplex , got { type (phase ).__name__ } " )
22962301
22972302 # Delegate to BatchWrap.unwrap2d
22982303 return phase .unwrap2d (weight = weight , conncomp = conncomp , conncomp_size = conncomp_size ,
@@ -2304,7 +2309,8 @@ def unwrap2d_chunk(self, overlap=None, device='auto', debug=False, **kwargs):
23042309 """
23052310 Unwrap phase per spatial chunk with overlap using IRLS algorithm.
23062311
2307- Expects Batches with [BatchWrap (phase), BatchUnit (weight, optional)].
2312+ Expects Batches with [BatchWrap or BatchComplex (phase), BatchUnit (weight, optional)].
2313+ If the first element is BatchComplex, .angle() is called automatically.
23082314
23092315 Unlike unwrap2d() which requires a single spatial chunk, this method
23102316 unwraps each spatial chunk independently with overlap margins.
@@ -2337,8 +2343,12 @@ def unwrap2d_chunk(self, overlap=None, device='auto', debug=False, **kwargs):
23372343 phase = self [0 ]
23382344 weight = self [1 ] if len (self ) >= 2 and isinstance (self [1 ], BatchUnit ) else None
23392345
2346+ # Auto-convert complex phase to wrapped phase
2347+ if isinstance (phase , BatchComplex ):
2348+ phase = phase .angle ()
2349+
23402350 if not isinstance (phase , BatchWrap ):
2341- raise TypeError (f"First element must be BatchWrap, got { type (phase ).__name__ } " )
2351+ raise TypeError (f"First element must be BatchWrap or BatchComplex , got { type (phase ).__name__ } " )
23422352
23432353 unwrapped = phase .unwrap2d_chunk (weight = weight , overlap = overlap ,
23442354 device = device , debug = debug , ** kwargs )
@@ -2350,7 +2360,8 @@ def unwrap1d(self, device='auto', debug=False, **kwargs):
23502360 """
23512361 1D temporal phase unwrapping using IRLS optimization.
23522362
2353- Expects Batches with [BatchWrap (phase), BatchUnit (weight, optional)].
2363+ Expects Batches with [BatchWrap or BatchComplex (phase), BatchUnit (weight, optional)].
2364+ If the first element is BatchComplex, .angle() is called automatically.
23542365
23552366 Parameters
23562367 ----------
@@ -2368,17 +2379,24 @@ def unwrap1d(self, device='auto', debug=False, **kwargs):
23682379
23692380 Examples
23702381 --------
2371- >>> phase, corr = stack.pairs(baseline.tolist()).phasediff(wavelength=30).angle()
2382+ >>> # With explicit .angle()
2383+ >>> phase, corr = mintfcorr.detrend1d().angle()
23722384 >>> unwrapped, corr = Batches([phase, corr]).unwrap1d()
2385+ >>> # Or directly from complex phase (angle applied automatically)
2386+ >>> unwrapped, corr = mintfcorr.detrend1d().unwrap1d()
23732387 """
23742388 if len (self ) < 1 :
23752389 raise ValueError ("unwrap1d() requires Batches with at least 1 element: [phase]" )
23762390
23772391 phase = self [0 ]
23782392 weight = self [1 ] if len (self ) >= 2 and isinstance (self [1 ], BatchUnit ) else None
23792393
2394+ # Auto-convert complex phase to wrapped phase
2395+ if isinstance (phase , BatchComplex ):
2396+ phase = phase .angle ()
2397+
23802398 if not isinstance (phase , BatchWrap ):
2381- raise TypeError (f"First element must be BatchWrap, got { type (phase ).__name__ } " )
2399+ raise TypeError (f"First element must be BatchWrap or BatchComplex , got { type (phase ).__name__ } " )
23822400
23832401 # Delegate to BatchWrap.unwrap1d
23842402 unwrapped = phase .unwrap1d (weight = weight , device = device , debug = debug , ** kwargs )
@@ -2588,6 +2606,31 @@ def lstsq(self, device='auto', cumsum=True, debug=False):
25882606 elements = [result ] + list (self [1 :])
25892607 return Batches (elements )
25902608
2609+ def displacement_los (self , transform ):
2610+ """
2611+ Convert phase to line-of-sight displacement (meters).
2612+
2613+ Applies Batch.displacement_los() to the first element.
2614+
2615+ Parameters
2616+ ----------
2617+ transform : Batch or Stack
2618+ Transform batch or Stack providing radar_wavelength.
2619+
2620+ Returns
2621+ -------
2622+ Batches
2623+ Batches with [displacement Batch] preserving other elements.
2624+
2625+ Examples
2626+ --------
2627+ >>> disp, corr = mintfcorr.detrend1d().unwrap1d().lstsq().displacement_los(stack.transform())
2628+ """
2629+ data = self [0 ]
2630+ result = data .displacement_los (transform )
2631+ elements = [result ] + list (self [1 :])
2632+ return Batches (elements )
2633+
25912634 def regression1d_baseline (self , * args , ** kwargs ):
25922635 raise NotImplementedError ("Batches.regression1d_baseline() is removed. Use Batches.detrend1d() or Batch.trend1d() instead." )
25932636
0 commit comments