U
    f»{j¬ ã                   @   sb  d dl mZmZ d dlmZ d dlmZ d dlmZ	 d dl
ZddlmZ ddlmZ dd	lmZ dd
lmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z* ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1m2Z2 ddl3m4Z4m5Z5m6Z6m7Z7m8Z8 ddl9m:Z:m;Z; ddl<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZF ddlGmHZHmIZI ddlJmKZKmLZL e=ddddddœdd„ƒZMe=dŽd'd(„ƒZNe=d�d)d*„ƒZOd�d+d,„ZPd-d.„ ZQd/d0„ ZRd1d2„ ZSe=d‘d3d4„ƒZTd5d6„ ZUd7d8„ ZVd9d:„ ZWd;d<„ ZXd=d>„ ZYd?d@„ ZZe=d’dAdB„ƒZ[e=d“dCdD„ƒZ\dEdF„ Z]dGdH„ Z^dIdJ„ Z_dKdL„ Z`dMdN„ ZadOdP„ ZbdQdR„ ZcdSejd ZedTdU„ Zfd”dWdX„ZgdYdZ„ Zhd[d\„ Zid]d^„ Zjd_d`„ Zkdadb„ Zldcdd„ Zmdedf„ Zndgdh„ Zod•didj„Zpdkdl„ Zqdmdn„ Zresddo�Ztdpdq„ Zudrds„ Zvdtdu„ Zwdvdw„ Zxdxdy„ Zyd–dzd{„Zzd|d}„ Z{d~d„ Z|d€d�„ Z}d—d‚dƒ„Z~e=d˜dˆd‰„ƒZdŠd‹„ Z€e=d™dŒd�„ƒZ�dS )šé    )ÚCounterÚOrderedDict)Úpartial)Ú	factorial)ÚpathNé   )Ú__version__)Ú_annotations_starts_stops)Ú_check_origin)Ú_str_to_frameÚ
_get_transÚ	TransformÚapply_transÚ_find_vector_rotationÚ_cart_to_sphÚ_get_n_momentsÚ_sph_to_cart_partialsÚ_deg_ord_idxÚ_average_quatsÚ_sh_complex_to_realÚ_sh_real_to_complexÚ
_sh_negateÚquat_to_rotÚrot_to_quat)Ú_concatenate_coilsÚ_prep_meg_channelsÚ_create_meg_coils)Ú_normalize_vectors)ÚFIFFÚFWD)Ú_simplify_infoÚInfo)Ú	_read_ctc)Ú_generate_meas_idÚ	DATE_NONE)Ú_loc_to_coil_transÚ_coil_trans_to_locÚBaseRawÚRawArrayÚ
Projection)Ú
pick_typesÚ	pick_info)
ÚverboseÚloggerÚ_clean_namesÚwarnÚ
_time_maskÚ_plÚ_check_optionÚ_ensure_intÚ_validate_typeÚuse_log_level)Ú	_safe_svdÚbincount)Ú_get_T1T2_mag_indsÚfix_mag_coil_typesÚfrom_rawÚkeepF)ÚbadsÚannotationsÚ	meas_dateÚemit_warningr,   c          
      C   sÈ  t | tdd� t |tdd� t |tdd� td|dddgd� t |td	d� td	|dddgd� t |td
d� td
|ddgd� |  ¡ }~ |dkrž|jd }n8|dkrÄtt|jd |jd  ƒƒ}n|dkrÖ|jd }dd„ |D ƒ}||jd< |jd |jd< | ¡ }| 	|¡ |j
 j|j|j 7  _|j|_|dk�rª|j
}	|dk�r^|	 t t|	ƒ¡¡ |	 |j
j|j
j|j
j|j
j¡ |jd
 dk�rž|	 j|j8  _| |	|¡ |dk�rÄ| |jd
 ¡ |S )a¼
  Prepare an empty-room recording for Maxwell filtering.

    Empty-room data by default lacks certain properties that are required to
    ensure running :func:`~mne.preprocessing.maxwell_filter` will process the
    empty-room recording the same way as the experimental data. This function
    preconditions an empty-room raw data instance accordingly so it can be used
    for Maxwell filtering. Please see the ``Notes`` section for details.

    Parameters
    ----------
    raw_er : instance of Raw
        The empty-room recording. It will not be modified.
    raw : instance of Raw
        The experimental recording, typically this will be the reference run
        used for Maxwell filtering.
    bads : 'from_raw' | 'union' | 'keep'
        How to populate the list of bad channel names to be injected into
        the empty-room recording. If ``'from_raw'`` (default) the list of bad
        channels will be overwritten with that of ``raw``. If ``'union'``, will
        use the union of bad channels in ``raw`` and ``raw_er``. Note that
        this may lead to additional bad channels in the empty-room in
        comparison to the experimental recording. If ``'keep'``, don't alter
        the existing list of bad channels.

        .. note::
           Non-MEG channels are silently dropped from the list of bads.
    annotations : 'from_raw' | 'union' | 'keep'
        Whether to copy the annotations over from ``raw`` (default),
        use the union of the annotations, or to keep them unchanged.
    meas_date : 'keep' | 'from_raw'
        Whether to transfer the measurement date from ``raw`` or to keep
        it as is (default). If you intend to manually transfer annotations
        from ``raw`` **after** running this function, you should set this to
        ``'from_raw'``.
    %(emit_warning)s
        Unlike :meth:`raw.set_annotations <mne.io.Raw.set_annotations>`, the
        default here is ``False``, as empty-room recordings are often shorter
        than raw.
    %(verbose)s

    Returns
    -------
    raw_er_prepared : instance of Raw
        A copy of the passed empty-room recording, ready for Maxwell filtering.

    Notes
    -----
    This function will:

    * Compile the list of bad channels according to the ``bads`` parameter.
    * Inject the device-to-head transformation matrix from the experimental
      recording into the empty-room recording.
    * Set the following properties of the empty-room recording to match the
      experimental recording:

      * Montage
      * ``raw.first_time`` and ``raw.first_samp``

    * Adjust annotations according to the ``annotations`` parameter.
    * Adjust the measurement date according to the ``meas_date`` parameter.

    .. versionadded:: 1.1
    Úraw_er)ÚitemÚtypesZ	item_nameÚrawr<   r:   Úunionr;   )Z	parameterÚvalueZallowed_valuesr=   r>   c                 S   s   g | ]}|  d ¡r|‘qS )ÚMEG)Ú
startswith)Ú.0Úch_name© rJ   úX/var/www/html/bwave/python/venv/lib/python3.8/site-packages/mne/preprocessing/maxwell.pyÚ
<listcomp>�   s    
ÿz4maxwell_filter_prepare_emptyroom.<locals>.<listcomp>Ú
dev_head_tN)r4   r'   Ústrr2   ÚcopyÚinfoÚsortedÚsetZget_montageZset_montager=   ÚonsetZ
first_timeZ_cropped_sampÚdeleteÚnpÚarangeÚlenÚappendÚdurationÚdescriptionÚch_namesZset_annotationsZset_meas_date)
r@   rC   r<   r=   r>   r?   r,   Zraw_er_preparedZmontageZer_annotrJ   rJ   rK   Ú maxwell_filter_prepare_emptyroom,   sn    D þ þ þÿ



ÿ

ü
r\   Úautoé   é   ç\�Âõ(\ï?ÚheadÚinÚerrorTç      Y@©ÚedgeZbad_acq_skiprJ   c                 C   sb   t  d¡ t| |||||||||	|
||||||||d�}t| f|Ž}t|f|d Ž t  d¡ |S )u   Maxwell filter data using multipole moments.

    Parameters
    ----------
    raw : instance of mne.io.Raw
        Data to be filtered.

        .. warning:: It is critical to mark bad channels in
                     ``raw.info['bads']`` prior to processing in order to
                     prevent artifact spreading. Manual inspection and use
                     of :func:`~find_bad_channels_maxwell` is recommended.
    %(origin_maxwell)s
    %(int_order_maxwell)s
    %(ext_order_maxwell)s
    %(calibration_maxwell_cal)s
    %(cross_talk_maxwell)s
    st_duration : float | None
        If not None, apply spatiotemporal SSS with specified buffer duration
        (in seconds). MaxFilterâ„¢'s default is 10.0 seconds in v2.2.
        Spatiotemporal SSS acts as implicitly as a high-pass filter where the
        cut-off frequency is 1/st_duration Hz. For this (and other) reasons,
        longer buffers are generally better as long as your system can handle
        the higher memory usage. To ensure that each window is processed
        identically, choose a buffer length that divides evenly into your data.
        Any data at the trailing edge that doesn't fit evenly into a whole
        buffer window will be lumped into the previous buffer.
    st_correlation : float
        Correlation limit between inner and outer subspaces used to reject
        ovwrlapping intersecting inner/outer signals during spatiotemporal SSS.
    %(coord_frame_maxwell)s
    %(destination_maxwell_dest)s
    %(regularize_maxwell_reg)s
    %(ignore_ref_maxwell)s
    %(bad_condition_maxwell_cond)s
    %(head_pos_maxwell)s

        .. versionadded:: 0.12
    %(st_fixed_maxwell_only)s
    %(mag_scale_maxwell)s

        .. versionadded:: 0.13
    %(skip_by_annotation_maxwell)s

        .. versionadded:: 0.17
    %(extended_proj_maxwell)s
    %(verbose)s

    Returns
    -------
    raw_sss : instance of mne.io.Raw
        The raw data with Maxwell filtering applied.

    See Also
    --------
    mne.preprocessing.annotate_amplitude
    mne.preprocessing.find_bad_channels_maxwell
    mne.chpi.filter_chpi
    mne.chpi.read_head_pos
    mne.epochs.average_movements

    Notes
    -----
    .. versionadded:: 0.11

    Some of this code was adapted and relicensed (with BSD form) with
    permission from Jussi Nurminen. These algorithms are based on work
    from :footcite:`TauluKajola2005` and :footcite:`TauluSimola2006`.
    It will likely use multiple CPU cores, see the :ref:`FAQ <faq_cpu>`
    for more information.

    .. warning:: Maxwell filtering in MNE is not designed or certified
                 for clinical use.

    Compared to the MEGIN MaxFilterâ„¢ software, the MNE Maxwell filtering
    routines currently provide the following features:

    .. table::
       :widths: auto

       +-----------------------------------------------------------------------------+-----+-----------+
       | Feature                                                                     | MNE | MaxFilter |
       +=============================================================================+=====+===========+
       | Maxwell filtering software shielding                                        | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Bad channel reconstruction                                                  | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Cross-talk cancellation                                                     | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Fine calibration correction (1D)                                            | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Fine calibration correction (3D)                                            | âœ“   |           |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Spatio-temporal SSS (tSSS)                                                  | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Coordinate frame translation                                                | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Regularization using information theory                                     | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Movement compensation (raw)                                                 | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Movement compensation (:func:`epochs <mne.epochs.average_movements>`)       | âœ“   |           |
       +-----------------------------------------------------------------------------+-----+-----------+
       | :func:`cHPI subtraction <mne.chpi.filter_chpi>`                             | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Double floating point precision                                             | âœ“   |           |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Seamless processing of split (``-1.fif``) and concatenated files            | âœ“   |           |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Automatic bad channel detection (:func:`~find_bad_channels_maxwell`)        | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Head position estimation (:func:`~mne.chpi.compute_head_pos`)               | âœ“   | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Certified for clinical use                                                  |     | âœ“         |
       +-----------------------------------------------------------------------------+-----+-----------+
       | Extended external basis (eSSS)                                              | âœ“   |           |
       +-----------------------------------------------------------------------------+-----+-----------+

    Epoch-based movement compensation is described in :footcite:`TauluKajola2005`.

    Use of Maxwell filtering routines with non-Neuromag systems is currently
    **experimental**. Worse results for non-Neuromag systems are expected due
    to (at least):

    * Missing fine-calibration and cross-talk cancellation data for
      other systems.
    * Processing with reference sensors has not been vetted.
    * Regularization of components may not work well for all systems.
    * Coil integration has not been optimized using Abramowitz/Stegun
      definitions.

    .. note:: Various Maxwell filtering algorithm components are covered by
              patents owned by MEGIN. These patents include, but may not be
              limited to:

              - US2006031038 (Signal Space Separation)
              - US6876196 (Head position determination)
              - WO2005067789 (DC fields)
              - WO2005078467 (MaxShield)
              - WO2006114473 (Temporal Signal Space Separation)

              These patents likely preclude the use of Maxwell filtering code
              in commercial applications. Consult a lawyer if necessary.

    Currently, in order to perform Maxwell filtering, the raw data must not
    have any projectors applied. During Maxwell filtering, the spatial
    structure of the data is modified, so projectors are discarded (unless
    in ``st_only=True`` mode).

    References
    ----------
    .. footbibliography::
    zMaxwell filtering raw data)rC   ÚoriginÚ	int_orderÚ	ext_orderÚcalibrationÚ
cross_talkÚst_durationÚst_correlationÚcoord_frameÚdestinationÚ
regularizeÚ
ignore_refÚbad_conditionÚhead_posÚst_fixedÚst_onlyÚ	mag_scaleÚskip_by_annotationÚextended_projÚupdate_kwargsú[done])r-   rP   Ú_prep_maxwell_filterÚ_run_maxwell_filterÚ_update_sss_info)rC   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   r,   ÚparamsÚraw_sssrJ   rJ   rK   Úmaxwell_filter·   s6     !
           ø	
r€   c           5         sV  t | tdƒ t| ƒ t|
ƒ t|ƒ}|dks4|dkr@td| ƒ‚td|ddgƒ |dkr\dnd	}t|	| j|ƒ}|d k	rºt|ƒ}t|ƒ}t	t
|| jd
  ƒƒ}d|  k r°dksºn tdƒ‚td|ddddgƒ | jd d krì|dkrìtdƒ‚|�r|d k�rtdƒ‚t||| || jd
 ƒ}t| j| |d k	| �o8|d k	| �oF|d k	d� | j ¡ ‰tˆ|||ƒ\}}}}}t||||ˆƒ\}}t |ttfdƒ ‡fdd„|| D ƒ}t|ƒdk�rptƒ }t|ƒD ]Œ\}} d|f }!t | t|!ƒ | d d ‰ tt|ƒtˆ ƒ ƒ}"|"�rtd|!d |"¡f ƒ‚‡ fdd„|D ƒ}#| | d d d d …|#f ¡ �qÄt |¡}t d t|ƒf ¡ tƒ }$|d k	�rštˆ||ƒ\}}$| d¡ t |ˆ|dd!�}|dk�rÒˆd d k	�rÒt!ˆd |ƒ}%n|}%t|||$|||d"�}&~~~$|%j"d	d#� ‡fd$d„|D ƒ}'t#||'ƒ\}(})|)|&d%< ~)t|%|dd&�}*t$ˆ|ƒ}+t%|*|+||ƒ},||*d'< ||*d< ~|,| },|d k	�rÞd(ˆd d) d d*…d*f |d) d d*…d*f   }-t &t 't(|-ƒ¡¡}.|.d+k�rÞt)d,d d-d.„ |-D ƒ¡|.f ƒ tƒ }/|d k	�r<|�rüt*j+}0nt*j,}0|/j-|0||ˆd
  d/� t d0|/d1  ¡ |�r6d2nd3}1n.t.t/t	t
d4ˆd
  ƒƒdƒt| j0ƒƒ}d }d5}1|/|&d6< ~~/| j1|d dd7�|d< ˆd d k	�rð|d d k	�rðt t2ˆd d) d d*…d d*…f ƒˆd d) d d*…d*f t 3d*¡g¡}2nd }2t4t5|+||
|*||||||||d8�}3|&j-| '¡ ||d9� t|||||1|(||2||||ˆ|3|,|&d:�}4|4S );NrC   ç        ç      ð?z%Need 0 < st_correlation <= 1., got %srn   ra   ÚmegTFÚsfreqé   z(st_correlation must be between 0. and 1.rr   rc   ÚwarningÚignorerP   rM   z…coord_frame cannot be "head" because info["dev_head_t"] is None; if this is an empty room recording, consider using coord_frame="meg"z/st_duration must not be None if st_only is True)ÚsssÚtsssrj   Úctcrx   c                    s   g | ]}ˆ d  | ‘qS ©r[   rJ   ©rH   Úc©rP   rJ   rK   rL   ¦  s     z(_prep_maxwell_filter.<locals>.<listcomp>r   zextended_proj[%d]ÚdataÚ	col_namesz=%s channel names were missing some good MEG channel names:
%sz, c                    s   g | ]}ˆ   |¡‘qS rJ   ©Úindex©rH   Úname)Ú	got_namesrJ   rK   rL   ²  s     z<    Extending external SSS basis using %d projection vectors)Zdisp)rg   rn   Ússs_calrh   ri   rx   )Úwritec                    s   g | ]}ˆ d  | ‘qS r‹   rJ   )rH   ÚprŽ   rJ   rK   rL   Ò  s     Ússs_ctc)rg   rh   ri   ri   éè  Útransr_   g      9@z2Head position change is over 25 mm (%s) = %0.1f mmc                 s   s   | ]}d | V  qdS )z%0.1fNrJ   )rH   ÚxrJ   rJ   rK   Ú	<genexpr>é  s     z'_prep_maxwell_filter.<locals>.<genexpr>)ÚjobZ	subspcorrÚbuflenz2    Processing data using tSSS with st_duration=%srŸ   ÚbeforeÚafterg      $@ÚneverÚmax_st)Zuse_rounding)Ú	all_coilsÚcalrp   Úexprq   Ú
coil_scaleÚ
grad_picksÚ	mag_picksÚ	good_maskÚmag_or_finerr   rv   )Únchanru   Úrecon_trans)rw   rl   rm   ru   Úst_whenrŠ   r§   Úthis_pos_quatÚ	meg_picksrª   r¨   rs   rP   Ú_get_this_decomp_transÚS_reconry   )6r4   r'   Ú_check_usableÚ_check_regularizeÚfloatÚ
ValueErrorr2   Ú_check_destinationrP   ÚintÚroundÚRuntimeErrorÚ
_check_posÚ_check_inforO   Ú_get_mf_picks_fix_magsÚ_get_coil_scaleÚlistÚtuplerW   Ú	enumerater)   rQ   rR   ÚjoinrX   rU   Úconcatenater-   ÚdictÚ_update_sensor_geometryÚfillr
   r   ZsetflagsÚ_read_cross_talkÚ_prep_mf_coilsÚ_trans_sss_basisÚsqrtÚsumÚ_sqr/   r   ZFIFFV_SSS_JOB_TPROJZFIFFV_SSS_JOB_STÚupdateÚminÚmaxÚtimesZtime_as_indexr   Úzerosr   Ú_get_decomp)5rC   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   Úreconstructr,   Ú
head_framer­   r°   r©   r¨   rª   r«   r§   Z
good_namesZextended_proj_ÚpiÚprojrA   ÚmissingÚidxr–   Zorigin_headry   Zmeg_ch_namesrŠ   r™   r¦   r¤   r²   ÚdiffÚdistr£   rž   r®   r¯   r±   r~   rJ   )r•   rP   rK   r{   h  sP   ÿ
ÿ
ÿþ
ÿ    ÿ
þ"
ÿ
  ÿ
   ý

ÿ
ÿ

ÿÿÿý       ú  ÿ         ùr{   c           A      C   sf  ||d dd�\}}}}}|j | ¡ d� |d k	rF||
 d d …|
f }|d d k	oZ| oZ|}t| |||ƒ\}}|d }~ |s„t|ƒ t||dd�\}}||  ¡ }d|  k rº|d	 ksÔn td
|| || f ƒ‚tƒ tƒ  }} t||ƒD �]\}!}"t	 
|!|"d |¡}#t|#ƒdk�r&t	 |#|"gg¡}#|#d |"k�r¢|"|#d< |#d |#d  }$|d k	�r¢t|#ƒdk�r¢|$|k�rˆt d|$| | f ¡ nt d|$| || f ¡ t|#ƒdk�s´t‚|#d |!k�rÐ|#d |"k�sÔt‚| |#d d… ¡ |  |#dd … ¡ ~#qìt||ƒ}tt	 t	 tt|ƒdƒ¡¡ƒd }%t dt|ƒt|ƒf ¡ tt|| ƒƒD �]\}&\}'}(|'|(k�rl�qP|(|' |k})|j|'|(… }*dt|*ddg ƒ }+|+d|&d t|ƒf  d|% d ¡7 }+|j|	|
 |'|(…f },|j|	|'|(…f }-|d k	�rü| |,¡},t	 t|ƒ|(|' f¡}.t||'|(|ƒ}/t|/d ƒ}0|d k	�r"|, ¡ }1|dk�r`t	 t|	ƒ|(|' f¡}2nÂ|/d }3|3d k	�rŽ||3|*d d�\}4}5}6}5}7n|| }4}6|}7t	 t	 |4d d …d |7…f |6d |7… ¡|1¡}2|1t	 t	 |4d d …|7d …f |6|7d … ¡|1¡8 }1|1|28 }1|�r
|-n|,}8t|8|2|1||0|+|)ƒ |�r2|dk�rêt|/d d… Ž D �]¤\}9}:};}|9d k	�rt||9|*|: d�\}}}}}t	 |d |… |,d d …|:|;…f ¡}<|�s$|dk�rÄ|j|d |… dd�}=|<}>nD|dk�sÒt‚|}=t	 ||d … |,d d …|:|;…f ¡}?t	 |<|?f¡}>t	 |=|>¡|-d d …|:|;…f< t|ƒdk�rT|d d …t	j f |.d d …|:|;…f< |dk�rB|1d d …|:|;…f }@t	 |d d …d |…f |<¡|2d d …|:|;…f< |@t	 t	 |d d …|d …f ||d … ¡|@¡8 }@|@|2d d …|:|;…f 8 }@�qB|dk�r
t|-|2|1||0|+|)ƒ n0|dk�r:|d d k	�r:t d|0t|0ƒ|+f ¡ |-|j|	|'|(…f< |.|j||'|(…f< �qP|S )NrM   r�   ©Út)Úreg_momentsr   r„   T©Úinvertr‚   z`st_duration (%0.1fs) must be between 0 and the longest contiguous duration of the data (%0.1fs).r…   éÿÿÿÿéþÿÿÿr   z}    Spatiotemporal window did not fit evenly intocontiguous data segment. %0.2f seconds were lumped into the previous window.zq    Contiguous data segment of duration %0.2f seconds is too short to be processed with tSSS using duration %0.2fz    Processing %s data chunk%sz%8.3f - %8.3f secz(#%d/%d)é   r¡   é   rb   ©ZaxisÚorigr¢   z(        Used % 2d head position%s for %s)!rÍ   rO   Ú_copy_preload_add_channelsÚ_remove_meg_projsr	   rÏ   r¶   r¿   ÚziprU   rV   rW   rÃ   r-   rP   ÚAssertionErrorÚextendrÎ   r¸   ÚfloorÚlog10r1   rÁ   rÐ   rÀ   ÚrjustÚ_dataÚdotÚemptyÚ_trans_starts_stops_quatsÚ_do_tSSSÚtakeÚnewaxis)ArC   rw   rl   rm   ru   r®   rŠ   r§   r¯   r°   rª   r¨   rs   rP   r±   r²   ry   rÓ   rO   ÚS_decompÚS_decomp_fullÚ	pS_decomprÝ   Ún_use_inÚadd_channelsr   Ú	pos_picksr„   ÚonsetsÚendsZ	max_sampsÚstartsÚstopsrS   ÚendZ	read_limsZ
n_last_bufZn_sigÚiiÚstartÚstopÚ
tsss_validZ	rel_timesÚt_strÚ	orig_dataZout_meg_dataZout_pos_dataZ	t_s_s_q_aÚn_positionsÚresidÚorig_in_dataÚ	avg_transZS_decomp_stÚ_ZpS_decomp_stZn_use_in_stÚprocr›   Ú	rel_startÚrel_stopZmm_inrÖ   ÚmultZmm_outZrel_resid_datarJ   rJ   rK   r|     s0   ÿ   ÿ  ÿ
ÿþ
ýÿýÿ 
"ÿ
&

ÿ


ÿ

ÿþ
ÿÿ
  ÿÿ
 ÿÿ
ÿ
ÿ
ÿÿ
ÿ
ÿþ

  ÿÿr|   c                    sð   t |tƒrÆ|dkrtd| ƒ‚t|ƒdt| ƒfkrFd}t d| ¡ n€t‡fdd„| D ƒdƒ‰ ‡ fd	d
„|D ƒ}t|ƒdksŒt|ƒd dkrœtdt|ƒ ƒ‚t|ƒd }d| }t d|d| f ¡ t	|ƒ}t
 t| ƒdf¡}|||< ||fS )z"Get the magnetometer scale factor.r]   z-mag_scale must be a float or "auto", got "%s"r   rd   zA    Setting mag_scale=%0.2f because only one coil type is presentc                    s   g | ]}ˆ d  | ‘qS )ÚchsrJ   ©rH   ÚpickrŽ   rJ   rK   rL   Ú  s   ÿz#_get_coil_scale.<locals>.<listcomp>Zaccuratec                    s   h | ]}ˆ | d  ’qS )ÚbaserJ   r  ©ÚcoilsrJ   rK   Ú	<setcomp>Ü  s     z"_get_coil_scale.<locals>.<setcomp>r…   zdCould not automatically determine mag_scale, could not find one proper gradiometer distance from: %sr‚   zB    Setting mag_scale=%0.2f based on gradiometer distance %0.2f mmrš   )Ú
isinstancerN   r¶   rW   r-   rP   r   r¿   rº   rµ   rU   Úones)r°   r©   r¨   rv   rP   Z	grad_baser§   rJ   )r  rP   rK   r¾   Í  s:    
ÿÿÿÿý
ÿr¾   c                    st   t ˆ jdg d�}‡ fdd„|D ƒ‰tƒ }ˆ jd D ],}t‡fdd„|d d	 D ƒƒs2| |¡ q2ˆ j|dd
d� dS )z:Remove inplace existing MEG projectors (assumes inactive).T©rƒ   Úexcludec                    s   g | ]}ˆ j | ‘qS rJ   r‹   )rH   rÕ   )ÚinstrJ   rK   rL   ï  s     z%_remove_meg_projs.<locals>.<listcomp>Zprojsc                 3   s   | ]}|ˆ kV  qd S ©NrJ   rŒ   )Úmeg_channelsrJ   rK   r�   ò  s     z$_remove_meg_projs.<locals>.<genexpr>r�   r�   F)Zremove_existingr,   N)r*   rP   r¿   ÚanyrX   Zadd_proj)r  r°   Znon_meg_projrÖ   rJ   )r  r  rK   rç   ì  s    rç   c                 C   s¸   | dkr|d S |st dƒ‚t| tƒr8t| ddƒd }nTt| tƒrH| }nDt | t¡} | jdkrft	dƒ‚t 
d	¡}| |dd
…d
f< tdd|ƒ}|jdks |jdkr´t d|j|jf ƒ‚|S )z Triage our reconstruction trans.NrM   z>destination can only be set if using the head coordinate framerƒ   ra   r   ©r_   z4destination must be a 3-element vector, str, or Nonerã   r_   z
MEG devicez=Destination transform is not MEG device -> head, got %s -> %s)rº   r  rN   r   r   rU   Úarrayrµ   Úshaper¶   ÚeyeZto_strZfrom_str)ro   rP   rÔ   r­   rJ   rJ   rK   r·   ÷  s*    



ÿÿr·   c                 C   sf  t | d|ddd�dd… \}}t|ƒ}t|ƒdkr’t| ddg d�}t| ddg d�}t ||¡}t|ddd… |ddd… ƒD ]\}	}
| |	|
¡ q|t|ƒ}t d	d
„ |D ƒ¡}t dd
„ |D ƒ¡}t dd
„ |D ƒ¡}||dd…tj	f 9 }~t 
dd
„ |D ƒ¡}t t t|ƒ¡|¡}t dgt |¡f¡}dd„ tt|dd… |dd… ƒƒD ƒ}||||||fS )z7Get all coil integration information loaded and sorted.F)rÔ   rq   Z
do_pickingr,   Nr   r   T©rƒ   Úref_megr  rà   c                 S   s   g | ]}|d  ‘qS ©ÚrmagrJ   ©rH   ZcoilrJ   rJ   rK   rL   &  s     z"_prep_mf_coils.<locals>.<listcomp>c                 S   s   g | ]}|d  ‘qS )ZcosmagrJ   r&  rJ   rJ   rK   rL   '  s     c                 S   s   g | ]}|d  ‘qS ©ÚwrJ   r&  rJ   rJ   rK   rL   (  s     c                 S   s   g | ]}t |d  ƒ‘qS r$  ©rW   r&  rJ   rJ   rK   rL   +  s     c                 S   s    i | ]\}\}}|t ||ƒ“qS rJ   )Úslice)rH   r   r  r  rJ   rJ   rK   Ú
<dictcomp>.  s   
ÿ z"_prep_mf_coils.<locals>.<dictcomp>r…   )r   Ú_get_mag_maskrW   r*   rU   Úsearchsortedrè   ÚinsertrÃ   rô   r  ÚrepeatrV   ZcumsumrÁ   )rP   rq   r,   r  Z
comp_coilsZmag_maskr°   Z	ref_picksÚinsertsrØ   Z	comp_coilÚn_coilsÚrmagsÚcosmagsÚwsÚn_intÚbinsZbdZ	slice_maprJ   rJ   rK   rÈ     s:       þþ
&ÿrÈ   c                 C   sR  t jt  | d ||g¡Ž }t  || t¡}tƒ }tƒ }tƒ }tƒ }	tƒ }
tdt|ƒƒD �]<}|dk r°d}t|ƒdkr„| d |d  n|}|| }||kršqV| d¡ |	 |¡ nr| d ||  | }|t|ƒd krÞ|| }n| d ||d   | }| | d ||  ¡ |	 | d ||  ¡ d|k�s0t	‚||k �s>t	‚||| k�sPt	‚|||…  
¡ �rft	‚d|||…< | |¡ | |¡ |
 || ¡ qV| ¡ �s¤t	‚|dk�r´d}n�t  |
¡}
t  |	¡}	|
|
 ¡  t¡ }
t|	dd…dd…f |
ƒ}t  |
|	dd…dd…f ¡}t  t  t|ƒ|dd…t jf g¡d	d	d	d
ggg¡}||||	|fS )z!Get all trans and limits we need.r…   rà   r   Nr   Tr_   é   r�   r‚   )rU   rV   r-  rÑ   Úboolr¿   ÚrangerW   rX   ré   r  Úallr  rË   Úastyperµ   r   rï   ZvstackZhstackr   rô   )Úposr  r  Zthis_pos_dataZpos_idxÚusedr›   Z
rel_startsZ	rel_stopsZquatsÚweightsÚtir  r  r	  Zavg_quatZavg_trJ   rJ   rK   rñ   3  sV     






þrñ   c           	      C   s–   |st  | jd df¡}nt  |¡ t|||ƒ}d|jd t|jd dƒ|f }|dkrn|d|t|dƒf 7 }t |¡ | t  t  | |¡|j	¡8 } dS )z@Compute and apply SSP-like projection vectors based on min corr.r…   r   z;        Projecting %2d intersecting tSSS component%s for %sú z (across %2d position%s)N)
rU   rð   r   Zasarray_chkfiniteÚ_overlap_projectorr1   r-   rP   rï   ÚT)	Z
clean_datar  r  rm   r  r  r  Zt_projÚmsgrJ   rJ   rK   rò   g  s    
ÿÿ
rò   c           	   	      sä  |r|   ¡ } | j ¡ � |d | jd< W 5 Q R X |�r tjtjtjtjtjtj	tj
tjtjg	‰ t| jƒtˆ ƒ t| jƒf}t |tj¡}d}| jr¼t |d ¡ | j|dt| jƒ…< || _n@t |d ¡ tdƒ� |  |dt| jƒ… ¡ W 5 Q R X || _| jdk�st‚t| jƒ‰‡ ‡fdd	„ttˆ ƒƒD ƒ}| jd  |¡ | j ¡  | j ¡  | jj| jd
 t| jƒfk�sxt‚t t| jƒt|ƒ t| jƒ¡}| |fS |�rÐ| j�sÆt d¡ | jdd� n
t d¡ | t  g t!¡fS dS )z;Load data for processing and (maybe) add cHPI pos channels.r  z0    Appending head position result channels and zcopying original raw dataNzloading raw data from diskFTc                    sL   g | ]D}t d |d  |d ˆ| d dddˆ | tjdtjt d¡d�‘qS )zCHPI%03dr…   rà   r‚   ç-Cëâ6?é   )rI   ZlognoZscannoZunit_mulr9  ÚunitÚkindrn   r¥   Ú	coil_typeÚloc)rÄ   r   ZFIFFV_COORD_UNKNOWNr   ZCOIL_UNKNOWNrU   rÑ   ©rH   r   ©ÚkindsÚoffrJ   rK   rL   ‘  s   ü
      ýz._copy_preload_add_channels.<locals>.<listcomp>r¬   z    Loading raw data from disk©r,   z    Using loaded raw data)"rO   rP   Ú_unlockr   ZFIFFV_QUAT_1ZFIFFV_QUAT_2ZFIFFV_QUAT_3ZFIFFV_QUAT_4ZFIFFV_QUAT_5ZFIFFV_QUAT_6ZFIFFV_HPI_GZFIFFV_HPI_ERRZFIFFV_HPI_MOVrW   r[   rÐ   rU   rÑ   Úfloat64Zpreloadr-   rî   r5   Z_preload_dataré   r9  rê   Z_update_redundantZ_check_consistencyr   rV   Ú	load_datar  r¸   )	rC   rù   rO   rP   Z	out_shapeZout_datarC  Zchpi_chsrú   rJ   rK  rK   ræ   y  sV        þ
"

û

"ÿ

ræ   c                 C   s²  t | tjdfdƒ | dkr*dt dg¡gS |s6tdƒ‚|sBtdƒ t| tjƒsVtdƒ‚| jdksn| j	d d	krvtd
ƒ‚| dd…df }t 
|t |¡¡s tdƒ‚t||jd d|d� ¡ sÐtd|d |jf ƒ‚t tj| dd…dd…f d dd�¡ ¡ }|dk�rtd|f ƒ t t|ƒddf¡}d|dd…ddf< | dd…dd…f |dd…dd…df< t| dd…dd…f ƒ|dd…dd…dd…f< |||j | dd…dd…f g} | S )zCCheck for a valid pos array and transform it to a more usable form.Nrs   rà   z0positions can only be used if coord_frame="head"z-st_fixed=False is untested, use with caution!zpos must be an ndarrayr   r…   é
   z%pos must be an array of shape (N, 10)r   z.Time points must unique and in ascending ordergü©ñÒMbP?)ZtminZtmaxr„   z[Head position time points must be greater than first sample offset, but found %0.4f < %0.4frã   é   rä   r‚   z}Found a distance greater than 1 m (%0.3g m) from the device origin, positions may be invalid and Maxwell filtering could failr_   )r4   rU   Úndarrayr  r¶   r/   r  Ú	TypeErrorÚndimr   Zarray_equalÚuniquer0   Z_first_timer:  rÊ   rË   rÏ   rÑ   rW   r   )r<  rÔ   rC   rt   r„   rÜ   Zmax_distZdev_head_tsrJ   rJ   rK   r»   ©  s>    ÿ
þ,
þ&. r»   c               
   C   s¾  ddl m} t||| ||||||ƒ	}||	 }| dd¡}t|ƒdk�rðd}d}|j||	  }|tjj|dd� }t|d ƒ}|j	d |k�r|d	d	…|d	…f  
¡ }|tjj|dd� }|j||d
�}|j	d |j	d ksÞt‚|t |t |j|¡¡8 }t tjj||d	… dd�¡}nt tjj|d	|… dd�¡}tjj|dd�|k}tt | ¡d |j	d  ƒ}t d|j	d | ¡ f ¡ |tjj|dd�|  }tj||gdd�}|j	d �röt |dd|j	d ffd¡}|||	|j	d  d	…f< ntƒ }~t||||
||d�\}}}|j|dd�}t| 
¡ ƒ\}}|d |d  }|dk�rŽ|dk�rŽd| }|dk�rpt|ƒ‚n|dk�r„t|ƒ n
t |¡ |||	 j9 }|||	  }|| }|||||fS )z6Get a decomposition matrix and pseudoinverse matrices.r   ©Úlinalgrx   rJ   rD  rä   rh   r…   N)Úrcondz    Reducing %d -> %drà   )r   r   ZconstantrÛ   r‡   ç     @�@z*Matrix is badly conditioned: %0.0f >= 1000rc   r†   )ÚscipyrY  Ú_get_s_decompÚgetrW   rB  rU   Únormr   r   rO   Zorthré   rï   Úmeanr¿   Úwherer-   ÚdebugrË   rÃ   ÚpadÚ_regularizeró   Ú_col_norm_pinvrº   r/   rP   ) r›   r¤   r¥   rp   r¦   rq   r§   r¨   r©   rª   r«   rr   rÜ   rv   rY  rö   rõ   rx   rZ  Zthreshr5  ZS_extZ
S_ext_orthÚscaleÚmaskÚextended_removerÝ   rø   r÷   ZsingZcondrC  rJ   rJ   rK   rÒ   Í  sˆ           þÿ ÿ þ     ÿ




rÒ   c	                 C   sv   t | |||ƒ}	|dk	rrt| ||||ƒ}
t|ƒdkrJ|	|dd…f  |
7  < t|ƒdkrr|	|dd…f  |d   < |	S )zGet S_decomp.Nr   Úmag_cals)rÉ   Ú_sss_basis_pointrW   )r¦   r¤   r›   r§   r¥   rq   r¨   r©   rv   rõ   Z	grad_calsrJ   rJ   rK   r]    s    r]  c              
   C   sö   |d |d  }}t |ƒ}	|jd |	 }
d| }| dk	rNt|||||ƒ\}}ng }t||||ƒ}t t |	¡|¡}t t |	|jd ¡|¡}t|ƒ}t|ƒ}t ||f¡}|j	|dd�}| dk	sÈ||
krìt
 d|| |	|
 |||	||
f ¡ |||fS )z"Regularize a decomposition matrix.rh   ri   r…   z%8.3fNrä   zE        Using %s/%s harmonic components for %s  (%s/%s in, %s/%s out))r   r   Ú_regularize_inÚ_regularize_outrU   Ú	setdiff1drV   rW   rÃ   ró   r-   rP   )rp   r¦   rõ   r«   rh  rÜ   r,   rh   ri   Ún_inÚn_outr  Ú
in_removesÚout_removesZreg_in_momentsZreg_out_momentsrø   Z	n_use_outrÝ   rJ   rJ   rK   rd  )  sD        ÿ
ÿÿ   ÿþrd  c                 C   sæ  t | dd�}t|ƒdkr$t| dd� | }t| d|g d�}tt| ƒ|ƒ}~ t t|ƒt¡}	d|	t|d|dd�< t	||gƒ 
¡ }
|
|	 
¡ kr¢tdt|
ƒ|	 
¡ f ƒ‚dd	„ |d D ƒ}t|ƒdkrÊd
| }nd}t |¡ |ràdnd}t|d|g d�}|rüdnd}t|d|g d�}t|ƒt|ƒ t|d ƒk�s2t‚t t|ƒt¡}d||< t dd	„ |d D ƒ¡}d||d@ tjk< tjtjtjg}d|t ||¡< dt|ƒt|ƒf }t|ƒ| 
¡  }|dk�rÎ|d| 7 }t |¡ ||||	|fS )z7Pick types for Maxwell filtering and fix magnetometers.T)Zuse_calr   r"  r…   r<   zBNumber of requested bases (%s) exceeds number of good sensors (%s)c                 S   s   g | ]}|‘qS rJ   rJ   ©rH   ÚchrJ   rJ   rK   rL   ]  s     z*_get_mf_picks_fix_mags.<locals>.<listcomp>z,    Bad MEG channels being reconstructed: %sz    No bad MEG channelsFÚmagÚgradr[   c                 S   s   g | ]}|d  ‘qS )rH  rJ   rr  rJ   rJ   rK   rL   n  s     r  iÿÿ  z3    Processing %s gradiometers and %s magnetometersz, (of which %s are actually KIT gradiometers))r8   rW   r9   r*   r+   r    rU   rÑ   r8  r   rË   r¶   rN   r-   rP   ré   r  r   ZFIFFV_COIL_KIT_GRADZFIFFV_COIL_CTF_GRADZFIFFV_COIL_CTF_REF_GRADZFIFFV_COIL_CTF_OFFDIAG_REF_GRADZin1d)rP   rh   ri   rq   r,   Zmag_inds_T1T2Úrefr°   Zmeg_inforª   Zn_basesZreconsrC  r#  r©   r¨   r«   Z
coil_typesZ	ctf_gradsZn_kitrJ   rJ   rK   r½   J  sR    ÿ

"þÿ

r½   c                 C   s&   | dks"t | tƒr| dks"tdƒ‚dS )zEnsure regularize is valid.N)rb   zregularize must be None or "in")r  rN   r¶   )rp   rJ   rJ   rK   r´   ~  s    ÿr´   c                 C   s,   | j rtdƒ‚| j}|dkr(td| ƒ‚dS )zEnsure our data are clean.z>Projectors cannot be applied to data during Maxwell filtering.)r   NzdMaxwell filter cannot be done on compensated channels, but data have been compensated with grade %s.N)rÖ   rº   Zcompensation_grade)r  Zcurrent_comprJ   rJ   rK   r³   …  s    þr³   c                 C   s^   t  t j| |  dd�¡}| | } t| fddit—Ž\}}}|| }t  |jd | |j¡|fS )zmCompute the pinv with column-normalization to stabilize calculation.

    Note: will modify/overwrite x.
    r   rä   Úfull_matricesFr‚   )rU   rÊ   rË   r6   Úcheck_disablerï   rB  )rœ   r_  ÚuÚsÚvrJ   rJ   rK   re  ‘  s
    re  c                 C   s   | |  S )zSquare quickly.rJ   ©rœ   rJ   rJ   rK   rÌ   �  s    rÌ   c                 C   s   t  | ¡ ¡ stdƒ‚dS )zEnsure data is finite.z data contains non-finite numbersN)rU   Úisfiniter:  rº   )r�   rJ   rJ   rK   Ú_check_finite¢  s    r~  c                 C   sN   t  d| d dt j  ¡}| dkrJ|t  t||  ƒtt||  ƒƒ ¡9 }|S )z5Compute normalization factor for spherical harmonics.r   r‚   rã   r   )rU   rÊ   rÕ   r   rµ   )ÚorderÚdegreer_  rJ   rJ   rK   Ú_sph_harm_norm¨  s    ÿr�  c                 C   sh   t  dd„ | D ƒ¡}t  dd„ | D ƒ¡}t  dd„ | D ƒ¡}t  t  t| ƒ¡dd„ | D ƒ¡}||||fS )z7Concatenate MEG coil parameters for spherical harmoncs.c                 S   s   g | ]}|d  ‘qS )Zr0_exeyrJ   r&  rJ   rJ   rK   rL   µ  s     z*_concatenate_sph_coils.<locals>.<listcomp>c                 S   s   g | ]}|d  ‘qS r'  rJ   r&  rJ   rJ   rK   rL   ¶  s     c                 S   s6   g | ].}t  |d  t jdd…f t|d ƒdf¡‘qS )ZezNr%  r…   )rU   Ztilerô   rW   r&  rJ   rJ   rK   rL   ·  s   þÿc                 S   s   g | ]}t |d  ƒ‘qS r$  r)  r&  rJ   rJ   rK   rL   »  s     )rU   rÃ   r/  rV   rW   )r  ÚrsÚwcoilsÚezsr6  rJ   rJ   rK   Ú_concatenate_sph_coils³  s    
þÿr…  gH¯¼šò×š>c                 C   s   t  dd„ | D ƒ¡S )z)Get the coil_scale for Maxwell filtering.c                 S   s   g | ]}|d  t jk‘qS )Z
coil_class)r   Z	COILC_MAGr&  rJ   rJ   rK   rL   Ä  s     z!_get_mag_mask.<locals>.<listcomp>)rU   r  r  rJ   rJ   rK   r,  Â  s    r,  Ústandardc           .      C   sê  ddl m} | d | d  }}| d }d| ks2t‚|dkr„t|ƒ\}}	}
}||8 }t|ƒj\}}}|	|
dd…tjf 9 }	~~
tj}nHt	|ƒ\}}}}||8 }t|ƒj\}}}||dd…tjf 9 }~~tj
}~t||gƒ\}}t t|ƒ|| f|¡}|dd…d|…f }|dd…|d…f }t t|ƒd	f¡}||t|ƒ< td	t||ƒd	 ƒD �]t}t|d	 ƒD �]^}tƒ }tƒ }|||||ƒ}t||ƒ}d
| | t t |d¡¡ }| t |¡ t d
| | ¡ t||t |¡ƒ } ||k�r<| |¡ t||d    }!|!|d  |  }"|!| }#|!|  }$| t|||"|#|$ƒ¡ ||k�r’| |¡ t||d	   }%|%| | }"|%| }#|%|  }$| t|||"|#|$ƒ¡ t||ƒD �] \}&}'|dk�r@t|'|ƒg}(|g})|dk�rð|( tt|'|ƒ| ƒ¡ |) | ¡ t|(|)ƒD ]B\}*}+t d|*|	¡}*t  ||*t|ƒ¡},|, |&dd…t!||+ƒf< �qún|t d|'|¡}'t  ||'j"t|ƒ¡d
t  ||'j#t|ƒ¡  }-|- |&dd…t!||ƒf< |dk�rœt|-|ƒ |&dd…t!|| ƒf< �qœ�qb�qP||9 }|dk�ræt$|||ƒ}|S )zECompute SSS basis using non-optimized (but more readable) algorithms.r   )Úsph_harmrh   ri   rg   rx   r†  Nr…   y              ð?ç¼‰Ø—²Òœ<r   r‚   zij,ij->i)%Úscipy.specialr‡  ré   r   r   rB  rU   rô   rP  r…  Ú
complex128r   rð   rW   r  r,  r9  rÏ   r¿   r�  ÚsinÚmaximumr¦   Ú_alegendre_derivÚcosrX   Ú_mu_0r   rè   r   r   Zeinsumr7   r   ÚrealÚimagÚ_bases_complex_to_real).r¦   r  rv   Úmethodr‡  rh   ri   rg   r2  r3  r4  r6  ZradÚazZpolZout_typer‚  rƒ  r„  rn  ro  ÚS_totÚS_inÚS_outr§   r€  r  ZS_in_outZgrads_in_outZsphZsph_normZ	az_factorZ
pol_factorZin_normZg_radZg_azZg_polZout_normZspcÚgradsZgrads_pos_negZorders_pos_negÚgrZooÚvalsr{  rJ   rJ   rK   Ú_sss_basis_basicÇ  s¤    
 ÿ


  ÿ


  ÿ

 ÿÿ

ÿ"
r›  c           (      C   sœ  |dd… \}}}}| d | d  }}t ||gƒ\}}	|| d  }t||ƒ}
t||
ƒ}t |dd…df |dd…df ¡}t tj|| dd�¡}t |dd…df |dd…df  |dd…df |dd…df   ¡}|dd…d	f | }t d
||  ¡}|dk}| ¡ }d
||< d
||< |dd…df | }d
||< |dd…df | }d||< | ¡ }d
||  }t |||	 ftj	¡}|dd…d|…f }|dd…|d…f }t
|
d ƒD �]à}||k�rÌ||9 }||k�rÞ||9 }dt d	| d tj ¡ }|dk�rÐt|dƒ}||k�rp||d  || d  | }| || d  | }t|||||d||||ƒ
|dd…|f< ||k�rÐ| | || d  | }| || d  | }t|||||d||||ƒ
|dd…|f< t
d|d ƒD �]²}|| } t | ¡}!t | ¡}"|t || d ||  ¡ }|t d	¡ }#t||ƒ}|#|| |  |" }$|#| |! || |  }%|# || |d  || || d  || |d     |" }&||k�r |d |$ | }|%||  }'d|'|< |&d	|  }t||||||'||||ƒ
|dd…|f< ||k�r^| |$ | }|%| | }'d|'|< |&| d }t||||||'||||ƒ
|dd…|f< t|| ƒ}|#|| |  |! }$|#| |" || |  }%|#|| |d  || || d  || |d     |! }&||k�r4|d  |$ | }|%||  }'d|'|< |&d	|  }t||||||'||||ƒ
|dd…|f< ||k�rÞ||$ | }|%| | }'d|'|< |&| d }t||||||'||||ƒ
|dd…|f< �qÞ�q´|S )aß  Compute SSS basis for given conditions.

    Parameters
    ----------
    exp : dict
        Must contain the following keys:

            origin : ndarray, shape (3,)
                Origin of the multipolar moment space in meters
            int_order : int
                Order of the internal multipolar moment space
            ext_order : int
                Order of the external multipolar moment space

    coils : list
        List of MEG coils. Each should contain coil information dict specifying
        position, normals, weights, number of integration points and channel
        type. All coil geometry must be in the same coordinate frame
        as ``origin`` (``head`` or ``meg``).

    Returns
    -------
    bases : ndarray, shape (n_coils, n_mult_moments)
        Internal and external basis sets as a single ndarray.

    Notes
    -----
    Does not incorporate magnetometer scaling factor or normalize spaces.

    Adapted from code provided by Jukka Nenonen.
    Nrã   rh   ri   rg   r…   r   rä   r   r‚   rˆ  r�   gH¯¼šò×Š>ç       @)r   rÏ   Ú_tabular_legendrerU   Zarctan2rÊ   rË   rO   rð   rP  r9  rÕ   r   Ú_integrate_pointsr‹  rŽ  )(r¦   r¤   r2  r3  r6  r1  rh   ri   rn  ro  Z	max_orderÚLÚphiÚr_nZr_xyÚcos_polÚsin_polZz_onlyZ
sin_pol_nzÚcos_azÚsin_azZr_nn2Zr_nn1r•  r–  r—  r€  r  rØ   Úb_rÚb_polr  Zord_phiZ	sin_orderZ	cos_orderÚfactorZr_factZaz_factZpol_factÚb_azrJ   rJ   rK   Ú
_sss_basis-  s:    

$F




        þ
        þ


ÿÿþ
        þ
        þÿÿþ
        þ
        þrª  c
                 C   s2   t | ||||||ƒj}
|
| jdd�}
t||
|	ƒS )z%Integrate points in spherical coords.r…   rä   )Ú_sp_to_cartrB  rË   r7   )r¤  r¥  r¢  r£  r¦  r©  r§  r3  r6  r1  r˜  rJ   rJ   rK   rž  ¿  s    rž  c           
      C   sb  t  t j| |  dd�¡}| dd…df | }tƒ }t|d ƒD ] }| t  |d t| ƒf¡¡ q>d|d d< t  |j	¡}d}t  d| d|  ¡}t|d ƒD ]¾}||| |< || | 9 }|d7 }||k rô|d| d  || |  ||d  |< |dkržt|d ƒD ]R}	|d| d  ||d  |	  ||	 d ||d  |	   ||	  || |	< �qqž|S )z(Compute associated Legendre polynomials.r…   rä   Nr   r‚   r   rœ  )
rU   rÊ   rË   r¿   r9  rX   rÑ   rW   r  r   )
ÚrZnindr¡  rœ   rŸ  r€  ZpnnZfactZsx2r  rJ   rJ   rK   r�  Ç  s6    (ÿ
ÿþýr�  c                 C   sp   t  d|j ¡}||  | ||  |  ||  |d< || | || |  | |  |d< || ||  |d< |S )z&Convert spherical coords to cartesian.r  r   r…   r   )rU   rð   r   )r¤  r¥  r¢  r£  r¦  r©  r§  ÚoutrJ   rJ   rK   r«  á  s
    $$r«  c                 C   s€   t  t| ƒt¡}t  |¡}td| d ƒD ]N}t|d ƒD ]<} t|| ƒ}|||< | ||< t||  ƒ}|||< |  ||< q8q(||fS )z3Get the set of degrees used in our basis functions.r…   )rU   rÑ   r   r¸   Z
zeros_liker9  r   )r  ÚdegreesÚordersr€  r   rJ   rJ   rK   Ú_get_degrees_ordersê  s    

r°  c                 C   sn   ddl m} | dkst‚| | || ||ƒ ||  ||  d  t d||  ¡ || d ||ƒ  d||   S )a«  Compute the derivative of the associated Legendre polynomial at a value.

    Parameters
    ----------
    order : int
        Order of spherical harmonic. (Usually) corresponds to 'm'.
    degree : int
        Degree of spherical harmonic. (Usually) corresponds to 'l'.
    val : float
        Value to evaluate the derivative at.

    Returns
    -------
    dPlm : float
        Associated Legendre function derivative
    r   )Úlpmvr‚   r…   )r‰  r±  ré   rU   rÊ   )r  r€  Úvalr±  rJ   rJ   rK   r�  û  s    
ÿÿþ
þr�  c                 C   s<  t ||gƒ\}}| dd…d|…f }| dd…|d…f }t | jtj¡}|dd…d|…f }|dd…|d…f }	t||g||	g||gƒD ]®\}
}}td|d ƒD ]”}t|d ƒD ]‚}t||ƒ}t|| ƒ}t|
dd…|f |ƒ|dd…|f< |dkr°|d dk�rdnd}|t|
dd…|f | ƒ |dd…|f< q°q qˆ|S )z,Convert complex spherical harmonics to real.Nr…   r   r   rà   )	r   rU   rð   r   rP  rè   r9  r   r   )Zcomplex_totrh   ri   rn  ro  Z
complex_inZcomplex_outÚreal_totÚreal_inÚreal_outÚcompr�  Ú	exp_orderÚdegr  Úidx_posÚidx_negr  rJ   rJ   rK   r’    s,    þ
" ÿr’  c                 C   s   t ||gƒ\}}| dd…d|…f }| dd…|d…f }t | jtj¡}|dd…d|…f }|dd…|d…f }	t||g||	g||gƒD ]’\}
}}td|d ƒD ]x}t|d ƒD ]f}t||ƒ}t|| ƒ}t|
dd…|f |
dd…|f g|ƒ}||dd…|f< t	||ƒ|dd…|f< q°q qˆ|S )z,Convert real spherical harmonics to complex.Nr…   )
r   rU   rð   r   rŠ  rè   r9  r   r   r   )r³  rh   ri   rn  ro  r´  rµ  Zcomp_totZcomp_inZcomp_outr�  r¶  r·  r¸  r  r¹  rº  Z	this_comprJ   rJ   rK   Ú_bases_real_to_complex,  s,    þ
ÿÿr»  c           	      C   sh   | d D ]Z}dd|fdd|fdd|fdd	|ffD ]0\}}}|s@q0t |d
 | ƒdkr0td| ƒ‚q0qdS )z7Ensure that Maxwell filtering has not been applied yet.Úproc_historyZSSSÚsss_infoZtSSSr£   zfine calibrationr–   zcross-talk cancellationr™   Úmax_infor   zBMaxwell filtering %s step has already been applied, cannot reapplyN)rW   rº   )	rP   rˆ   r‰   rj   rŠ   ZentrC  ÚkeyZdoingrJ   rJ   rK   r¼   C  s    ýÿr¼   c                 C   s*  t ||gƒ\}}| j ¡ � d| jd< W 5 Q R X t || t|ƒ ¡ d¡}d||	< t|||| d¡tj	t 
|d|… ¡t| |d�}t|d�}|
r¬|jtƒ tƒ tƒ d	� n:|j|||d	� t| jƒ | j ¡ � || jd
< W 5 Q R X tƒ }| j ¡ �* | jd  dt||tdt dd�¡ W 5 Q R X dS )a‰  Update info inplace after Maxwell filtering.

    Parameters
    ----------
    raw : instance of mne.io.Raw
        Data to be filtered
    origin : array-like, shape (3,)
        Origin of internal and external multipolar moment space in head coords
        (in meters)
    int_order : int
        Order of internal component of spherical expansion
    ext_order : int
        Order of external component of spherical expansion
    nchan : int
        Number of sensors
    sss_ctc : dict
        The cross talk information.
    sss_cal : dict
        The calibration information.
    max_st : dict
        The tSSS information.
    reg_moments : ndarray | slice
        The moments that were used.
    st_only : bool
        Whether tSSS only was performed.
    recon_trans : instance of Transformation
        The reconstruction trans.
    extended_proj : ndarray
        Extended external bases.
    FZ	maxshieldZint32r…   Zfloat32N)Zin_orderZ	out_orderr¬   rg   rž   ZnfreeÚframeÚ
components)r£   )r½  r–   r™   rM   r¼  r   zmne-python v%sÚ )r¾  Úblock_idÚdateZcreatorZexperimenter)r   rP   rO  rU   rÑ   rW   r;  rÄ   r   ZFIFFV_SSS_JOB_FILTERrË   r   rÍ   Ú_reset_meg_badsr#   r.  r$   r   )rC   rg   rh   ri   r¬   rn   r™   r–   r£   rÝ   ru   r­   rx   rn  ro  rÁ  Zsss_info_dictZmax_info_dictrÃ  rJ   rJ   rK   r}   Q  s>    ! û
ÿ
   þr}   c                    s.   t ˆ dg d�‰‡ ‡fdd„ˆ d D ƒˆ d< dS )zReset MEG bads.Tr  c                    s"   g | ]}ˆ d    |¡ˆkr|‘qS r‹   r‘   )rH   Úbad©rP   r°   rJ   rK   rL   ’  s    ÿz#_reset_meg_bads.<locals>.<listcomp>r<   N)r*   rŽ   rJ   rÇ  rK   rÅ  �  s    rÅ  )Zcheck_finitec                 C   st   t | fddit—Ždd… \}}| j\}}t t¡j}t||ƒt |¡ | }tj	||kt
d�}|dd…d|…f S )z(Create a slightly more efficient 'orth'.rw  FNr   )Zdtype)r6   rx  r   rU   Zfinforµ   ÚepsrÏ   ZamaxrË   r¸   )ÚAry  rz  ÚMÚNrÈ  ZtolÚnumrJ   rJ   rK   Ú_orth_overwrite™  s     
rÍ  c                 C   s  ddl m} tj | ¡}|dkr$dn|}t| | jƒ} tj |¡}|dkrNdn|}t|| jƒ}| jd dks||jd dkr�t | jd df¡S |j| fdddœt	—Žd j}|j|fdddœt	—Žd }t 
||¡}~t|fdd	it	—Ždd
… \}}	~||k}
~|	|
 j}	t 
||	¡}|S )zACalculate projector for removal of subspace intersection in tSSS.r   rX  r‚   r…   TZeconomic)Zoverwrite_aÚmoderw  FN)r\  rY  rU   r_  rÍ  rB  r   rð   Zqrrx  rï   r6   )Zdata_intZdata_resZcorrrY  ÚnZQ_intZQ_resZC_matZS_intersectZVh_intersectZintersect_maskZV_principalrJ   rJ   rK   rA  ¤  sL     ÿÿÿ ÿÿÿÿÿ
rA  c           
         s  ddl m} t|tdfƒ t|tƒs<t t|ƒ¡}||ƒ}nd}t 	d|› �¡ t
| d dd�‰ tƒ }tƒ }t|d ƒD ].\}}|ˆ kr”| |¡ qxˆ  |¡}|||< qxt| dg d	�}	t|ƒt|	ƒkrôtd
tt‡ fdd„|	D ƒt|d ƒ ƒƒ ƒ‚t|ƒ�rtdt|ƒ|f ƒ ||ˆ fS )Nr…   )Úread_fine_calibrationz	path-likerÄ   z    Using fine calibration r[   T©Zremove_whitespacer  z@Not all MEG channels found in fine calibration file, missing:
%sc                    s   h | ]}ˆ | ’qS rJ   rJ   r  r‹   rJ   rK   r  ê  s     z!_prep_fine_cal.<locals>.<setcomp>z#Found cal channel%s not in data: %s)Z	_fine_calrÐ  r4   rÄ   r  ÚopÚbasenamerN   r-   rP   r.   r   r¿   rÁ   rX   r’   r*   rW   rº   rQ   rR   r/   r1   )
rP   Úfine_calrÐ  ÚextraÚinfo_to_calr×   Úcir”   Úoir°   rJ   r‹   rK   Ú_prep_fine_calÔ  s6    




ÿÿÿ
rÙ  c              
      sr  t | ˆƒ\‰‰}t| ddd�}t| ddd�}t ‡‡fdd„|D ƒ¡j}|jd dkrltd	d
|jd   ƒ‚t ‡‡fdd„|D ƒ¡}t| t|ƒ|d�}t	|||d�}	t
ƒ }
t t| d ƒt¡}t
ƒ }t
ƒ }d}ˆ ¡ D �]Ú\}}|| rît‚d||< | d | }tˆd |  d¡ d¡ƒ}| ||d g¡ t|d ƒdd…dd…f }ˆd |  ¡ }t|ƒdd…dd…f ‰ t ‡ fdd„tdƒD ƒ¡dk�ræ|�sªt d¡ d}t|dd…df ˆ dd…df ƒ}t ||¡j ¡ |dd…< t|ƒdd…dd…f }t|ƒ t|d ƒdd…dd…f }t|ƒ |
 tj|| dd�¡ ||k�rbdˆd | d g}nˆd | d d g}| t ||g¡¡ |dd… |d dd…< |d! tjksØt‚qØt| ddd�}||   ¡ �sÖt‚|t !t "t|ƒ¡|¡  #¡ �rút‚t	t |¡t |¡d"�}t |
¡}
t $|
d#d|
¡ t %t &|
¡|
¡ t d$t '|
¡t (|
¡t t )|
¡¡f ¡ |	|fS )%z8Replace sensor geometry information and reorder cal_chs.ru  rJ   r  rt  c                    s   g | ]}ˆ d  ˆ|  ‘qS ©Úimb_calsrJ   )rH   Úgi©rÔ  rÖ  rJ   rK   rL   ø  s   ÿz+_update_sensor_geometry.<locals>.<listcomp>r   )r   r…   r_   z*Must have 1 (x) or 3 (x, y, z) point-like z magnetometers. Currently have %ic                    s   g | ]}ˆ d  ˆ|  ‘qS rÚ  rJ   )rH   ÚmirÝ  rJ   rK   rL   þ  s   ÿ)Ún_typesrq   )Úgrad_imbalancesÚgrad_coilsetsri  r  FTr[   rF   Ú0rH  rI  Nr_   Zlocsc              
      s6   g | ].}t  t  ˆ d d …|f ˆ d d …df ¡¡‘qS )Nr   )rU   Úabsrï   rJ  )Úcal_coil_rotrJ   rK   rL     s   ÿr   g�íµ ÷Æ°>z*        Adjusting non-orthogonal EX and EYrä   r‚   rÛ  r�   rn   )Ú	cal_corrsÚ	cal_chansg      ð¿uP           Adjusted coil positions by (Î¼ Â± Ïƒ): %0.1fÂ° Â± %0.1fÂ° (max: %0.1fÂ°))*rÙ  r*   rU   r  rB  r   r¶   Ú_get_grad_point_coilsetsrW   rÄ   r¿   rÑ   r8  Úitemsré   r¸   ÚlstriprX   r%   rO   rÏ   r9  r-   rP   r   rï   Zravelr   rË   rÃ   r   ZFIFFV_COORD_DEVICEr:  rm  rV   r  ZclipZrad2degZarccosr`  Ústdrã  )rP   rÔ  rq   r[   r¨   r©   rà  ri  rá  rj   Z	ang_shiftr=  rå  ræ  Zadjust_loggedrØ  r×  Zinfo_chZch_numZch_coil_rotZcal_locZ
this_transZv1Zv2rÕ  r°   r–   rJ   )rä  rÔ  rÖ  rK   rÅ   ñ  sš    ÿ
ÿÿÿ  ÿ ÿÿÿ
 ÿ
$
ÿ
ÿþrÅ   c                 C   s8  t t ddddgddddgddddgddddgg¡t ddddgddddgddddgddddgg¡t d¡d�}tƒ }t| dg d�}t|ƒdkr”|S tt| ƒ|ƒ}|d D ]}t	j
|d	< qªd
d„ |d D ƒ}dd|… D ]Z}	t|d ƒD ]8\}
}tt t||
 ƒ||	 ¡ƒdd… |d dd…< qè| t||ƒ¡ qØ|S )z)Get point-type coilsets for gradiometers.r   r…   r‚   rã   )rœ   ÚyÚzru  r  r  rH  c                 S   s   g | ]}|d    ¡ ‘qS )rI  )rO   rr  rJ   rJ   rK   rL   T  s     z,_get_grad_point_coilsets.<locals>.<listcomp>ZxyzNr_   rI  )rÄ   rU   r  r!  r¿   r*   rW   r+   r    r   ZFIFFV_COIL_POINT_MAGNETOMETERrÁ   r&   rï   r%   rX   rÈ   )rP   rß  rq   Z
_rotationsrá  r¨   Z	grad_infors  Z	orig_locsZrotr×  rJ   rJ   rK   rç  E  s.    00ý
þþrç  c           
      C   s^   d}t  |gt¡}t|d |d ƒD ]4\}}t| |||ƒ}	|	|dd…t jf 9 }	||	7 }q$|S )z=Compute multipolar moments for point-like mags (in fine cal).r�   rà  rá  N)rU   r  rµ   rè   rÉ   rô   )
r¦   r›   r¥   rq   rv   r•  Zthis_csZimbr  ZS_addrJ   rJ   rK   rj  _  s    
rj  c                 C   s4   t | ƒ}|dko| ¡  }tt||d|  ƒƒ| S )z(Regularize out components based on norm.r   r_   )r   r  r¿   r9  )rh   ri   r«   rh  rn  Zremove_homogrJ   rJ   rK   rl  o  s    rl  c              
   C   sÂ  t | |gƒ\}}tt | d ¡ƒ\}}t| ƒ\}	}
||	 }t |¡}tt|ƒƒ}t| |||ƒ}tt 	t ||j
d ¡|¡ƒ}g }| ¡ }t tj|| dd�¡}|| }t |df¡}d}||9 }t|ƒD �]F}|j|| dd�}t|fddit—Ž\}}}~|ddg ||< |jd	t|ƒ… }||| d	d	…tjf  }t |d
 | |j¡}~~~||9 }|jdd�}||9 }||
| dk  d9  < |d9 }|| | }dt |d
 ¡ ¡  ||< | |t |¡ ¡ | | |d ¡¡ |dkrÊ||d |d … d| ¡  k  ¡ rÊ �qqÊt |¡}t |d| k¡d d }|d	|… }t|ƒD ]H\}}t dt || ƒ||df ||df  ||	| |
| f  ¡ �qLt d|| d||  | |f ¡ ||fS )z1Regularize basis set using idealized SNR measure.r…   r   rä   r   gê-�™—a=rw  Frà   Nr‚   g{®Gázd?g      à?rR  gffffffî?r`   zT            Condition %0.3f/%0.3f = %03.1f, Removing in component %s: l=%s, m=%+0.0fzH        Resulting information: %0.1f bits/sample (%0.1f%% of peak %0.1f)éd   )!r   Ú_compute_sphere_activation_inrU   rV   r°  rÑ   r¿   r9  rl  rm  r   rO   rÊ   rË   ró   r6   rx  rB  rW   rô   rï   Úlog2rX   ZargminÚpopr’   rÏ   r:  ra  rÁ   r-   rb  rÀ   )rh   ri   rõ   r«   rh  rn  ro  Za_lm_sqÚrho_ir®  r¯  ZI_totsZ
in_keepersrq  Zout_keepersZremove_orderZuse_normZeigsZ	noise_levr   Zthis_Sry  rz  r{  Z	eta_lm_sqZsnrr¾  Zlim_idxrp  ÚrirJ   rJ   rK   rk  v  st    ÿ
ÿÿ,
   ÿþ
ÿþrk  c                 C   sD   d}d}t |ƒ| |d|  d   t d|  d ƒ| d    }||fS )a�  Compute the "in" power from random currents in a sphere.

    Parameters
    ----------
    degrees : ndarray
        The degrees to evaluate.

    Returns
    -------
    a_power : ndarray
        The a_lm associated for the associated degrees (see
        :footcite:`KnuutilaEtAl1993`).
    rho_i : float
        The current density.

    References
    ----------
    .. footbibliography::
    g{®Gáz´?g4;”Ý’Õ£>r   rã   rœ  r‚   )rÌ   )r®  Zr_inrñ  Za_powerrJ   rJ   rK   rî  Ö  s    ÿÿrî  c                 C   s¤   |dk	r`t |tƒstdd|ƒ}t |d ¡ ¡ r4t‚t||d ƒt||d dd�f|d	d…  }t |tjƒsŽ|}t |d
 df¡}|||d < t	| |ƒ}||9 }|S )z8Compute SSS basis (optionally) using a dev<->head trans.Nrƒ   ra   r›   r   r…   F)Úmover   r_   rã   )
r  r   rU   Úisnanr  ré   r   rT  r  rª  )r¦   r¤   r›   r§   Úcsr•  rJ   rJ   rK   rÉ   ÿ  s     
ÿ
þ
rÉ   ç      @ç      @râ   ç      D@c           >         s  |dk	rŠˆj  d¡rbˆj d |krbˆj d |k r4dnd}dˆj d › d|› d|› d�}t  |¡ n(t  d	|› d
�¡ ˆ ¡  ¡ jd|d�‰t|ƒ}tˆ|dd�\}}~tƒ }tƒ }t	t
ˆj d | ƒƒ}t||ƒD ]N\}}|| |krÒt ||| d |¡}| |¡ || }||d< | |¡ qÒttˆdƒt|ƒƒ‰t  dt|ƒt|ƒ|ˆj d  f ¡ tˆg |||||	|
||||||d�‰~~~~~	~
~~~~~ˆd ˆd  ‰tˆd ƒtˆd ƒk�sÄt‚tˆd ƒtˆd ƒk�sât‚tƒ }tƒ }tddd�‰t ‡‡fdd„ˆD ƒ¡} tdt	dˆj d  d ƒƒ}!tƒ }"t t|ƒdf¡}#t ˆj¡}$t ˆ ¡ ¡}%t t|$ƒt|ƒftj¡}&tj|&tjd �}'t t|$ƒdftj¡}(tj|(tjd �})t t||ƒƒD �]j\}*\}+},d!}-ˆj!d|+|,d"d#�}.t"|.ˆd$ ˆj#|+ d%d"d&�‰ˆj$d!dg |+ˆj d   }/t  d'|*d ft%|/d!dg ƒ  ¡ |,|+ }0|0|0|!  }1ˆ !ˆd!|1¡}2|2j&d! d|!f|2_&tj'|2dd(� d¡}3|/d! |/d f|#|*dd…f< |3|&ˆ|*f< |  (dd¡|(ˆ< |3| k ‰ t )ˆ ¡d! ‰ ‡‡fd)d„ˆ D ƒ‰ | *ˆ ¡ |"tˆ ƒO }"t+|"ƒ‰ ‡ ‡fd*d„ˆD ƒ}4t|4ƒd!k�r^t  d+tˆ ƒd,›d-�¡ t,d.|/d! d/›d0�ƒ  �q.tƒ ‰t	t
ˆj$d ˆj d  ƒƒˆd1< t-dd2ƒD �]Ž}-tˆj d3 ƒtˆƒ@ tƒ k�s¶t‚‡ ‡‡‡fd4d„ˆd D ƒˆd dd…< |.ˆj.dd…< ˆ !|4¡}3t/d"ƒ� t0ˆfd5d"d6œˆ—Ž W 5 Q R X |-dk�rPtˆ ƒ�rPt  d7tˆ ƒd8 1ˆ ¡f ¡ |3ˆ !|4¡8 }3tj2|3dd(�}5t 3ˆd |4¡}6|5ˆd |6d!f 9 }5t 4|5¡t '|5¡ }7}8|5|7 |8 }9t 5|9¡}:|9|: };|9|'|4|*f< ||)|4< |;|k �rè �q ˆj|4|:  }<t 6d9|<|;f ¡ |4 7|:¡ ˆ 8|<¡ �qŽ| *ˆ¡ �qÀt+‡fd:d;„| 9¡ D ƒ‡fd<d=„d>�}t+‡fd?d;„| 9¡ D ƒ‡fd@d=„d>�}|$ˆd  }$|%ˆd  }%|&ˆd  }&|(ˆd  }(|'ˆd  }'|)ˆd  })t  dA|f ¡ t  dB|f ¡ t  dC¡ |�rt|$|%|#|&|(|'|)dD�}=|||=fS ||fS dS )EaŠ  Find bad channels using Maxwell filtering.

    Parameters
    ----------
    raw : instance of Raw
        Raw data to process.
    limit : float
        Detection limit for noisy segments (default is 7.). Smaller values will
        find more bad channels at increased risk of including good ones. This
        value can be interpreted as the standard score of differences between
        the original and Maxwell-filtered data. See the ``Notes`` section for
        details.

        .. note:: This setting only concerns *noisy* channel detection.
                  The limit for *flat* channel detection currently cannot be
                  controlled by the user. Flat channel detection is always run
                  before noisy channel detection.
    duration : float
        Duration of the segments into which to slice the data for processing,
        in seconds. Default is 5.
    min_count : int
        Minimum number of times a channel must show up as bad in a chunk.
        Default is 5.
    return_scores : bool
        If ``True``, return a dictionary with scoring information for each
        evaluated segment of the data. Default is ``False``.

        .. warning:: This feature is experimental and may change in a future
                     version of MNE-Python without prior notice. Please
                     report any problems and enhancement proposals to the
                     developers.

        .. versionadded:: 0.21
    %(origin_maxwell)s
    %(int_order_maxwell)s
    %(ext_order_maxwell)s
    %(calibration_maxwell_cal)s
    %(cross_talk_maxwell)s
    %(coord_frame_maxwell)s
    %(regularize_maxwell_reg)s
    %(ignore_ref_maxwell)s
    %(bad_condition_maxwell_cond)s
    %(head_pos_maxwell)s
    %(mag_scale_maxwell)s
    %(skip_by_annotation_maxwell)s
    h_freq : float | None
        The cutoff frequency (in Hz) of the low-pass filter that will be
        applied before processing the data. This defaults to ``40.``, which
        should provide similar results to MaxFilter. If you do not wish to
        apply a filter, set this to ``None``.
    %(extended_proj_maxwell)s
    %(verbose)s

    Returns
    -------
    noisy_chs : list
        List of bad MEG channels that were automatically detected as being
        noisy among the good MEG channels.
    flat_chs : list
        List of MEG channels that were detected as being flat in at least
        ``min_count`` segments.
    scores : dict
        A dictionary with information produced by the scoring algorithms.
        Only returned when ``return_scores`` is ``True``. It contains the
        following keys:

        - ``ch_names`` : ndarray, shape (n_meg,)
            The names of the MEG channels. Their order corresponds to the
            order of rows in the ``scores`` and ``limits`` arrays.
        - ``ch_types`` : ndarray, shape (n_meg,)
            The types of the MEG channels in ``ch_names`` (``'mag'``,
            ``'grad'``).
        - ``bins`` : ndarray, shape (n_windows, 2)
            The inclusive window boundaries (start and stop; in seconds) used
            to calculate the scores.
        - ``scores_flat`` : ndarray, shape (n_meg, n_windows)
            The scores for testing whether MEG channels are flat. These values
            correspond to the standard deviation of a segment.
            See the ``Notes`` section for details.
        - ``limits_flat`` : ndarray, shape (n_meg, 1)
            The score thresholds (in standard deviation) above which a segment
            was classified as "flat".
        - ``scores_noisy`` : ndarray, shape (n_meg, n_windows)
            The scores for testing whether MEG channels are noisy. These values
            correspond to the standard score of a segment.
            See the ``Notes`` section for details.
        - ``limits_noisy`` : ndarray, shape (n_meg, 1)
            The score thresholds (in standard scores) above which a segment was
            classified as "noisy".

        .. note:: The scores and limits for channels marked as ``bad`` in the
                  input data will be set to ``np.nan``.

    See Also
    --------
    annotate_amplitude
    maxwell_filter

    Notes
    -----
    All arguments after ``raw``, ``limit``, ``duration``, ``min_count``, and
    ``return_scores`` are the same as :func:`~maxwell_filter`, except that the
    following are not allowed in this function because they are unused:
    ``st_duration``, ``st_correlation``, ``destination``, ``st_fixed``, and
    ``st_only``.

    This algorithm, for a given chunk of data:

    1. Runs SSS on the data, without removing external components.
    2. Excludes channels as *flat* that have had low variability
       (standard deviation < 0.01 fT or fT/cm in a 30 ms window) in the given
       or any previous chunk.
    3. For each channel :math:`k`, computes the *range* or peak-to-peak
       :math:`d_k` of the difference between the reconstructed and original
       data.
    4. Computes the average :math:`\mu_d` and standard deviation
       :math:`\sigma_d` of the differences (after scaling magnetometer data
       to roughly match the scale of the gradiometer data using ``mag_scale``).
    5. Marks channels as bad for the chunk when
       :math:`d_k > \mu_d + \textrm{limit} \times \sigma_d`. Note that this
       expression can be easily transformed into
       :math:`(d_k - \mu_d) / \sigma_d > \textrm{limit}`, which is equivalent
       to :math:`z(d_k) > \textrm{limit}`, with :math:`z(d_k)` being the
       standard or z-score of the difference.

    Data are processed in chunks of the given ``duration``, and channels that
    are bad for at least ``min_count`` chunks are returned.

    Channels marked as *flat* in step 2 are excluded from all subsequent steps
    of noisy channel detection.

    This algorithm gives results similar to, but not identical with,
    MaxFilter. Differences arise because MaxFilter processes on a
    buffer-by-buffer basis (using buffer-size-dependent downsampling logic),
    uses different filtering characteristics, and possibly other factors.
    Channels that are near the ``limit`` for a given ``min_count`` are
    particularly susceptible to being different between the two
    implementations.

    .. versionadded:: 0.20
    NZlowpassZbelowzequal toz9The input data has already been low-pass filtered with a z Hz cutoff frequency, which is z the requested cutoff of z" Hz. Not applying low-pass filter.zApplying low-pass filter with z Hz cutoff frequency ...)Zl_freqÚh_freqTrÞ   r„   r…   rà   Ú	min_countz:Scanning for bad channels in %d interval%s (%0.1f sec) ...)rw   rg   rh   ri   rj   rk   rn   rp   rq   rr   rs   rv   rx   r°   rª   r§   gVçž¯Ò<g—ÔFFõg<)ru  rt  c                    s(   g | ] }|ˆd  krˆ d nˆ d ‘qS )r¨   ru  rt  rJ   r  )Úflat_limitsr~   rJ   rK   rL   ×  s   þ
ÿ
z-find_bad_channels_maxwell.<locals>.<listcomp>é   é   r[  r   )Z
fill_valuer   FrN  rP   r�   )Ú
first_samprO   r,   z#        Interval %3d: %8.3f - %8.3frä   c                    s   g | ]}ˆj ˆ |  ‘qS rJ   r‹   )rH   Z
chunk_flat)Úgood_meg_picksrC   rJ   rK   rL   	  s   ÿc                    s   g | ]}ˆj | ˆ kr|‘qS rJ   r‹   r  )Úchunk_flatsrC   rJ   rK   rL   	  s    ÿz            Flat (Z2dz): <all>z[All-flat segment detected, all channels will be marked as flat and processing will stop (t=z0.3fz“). Consider using annotate_amplitude before calling this function with skip_by_annotation="bad_flat" (or similar) to properly process all segments.rl   ée   r<   c                    s(   g | ] }ˆj | ˆjd  ˆ ˆ  k‘qS )r<   )r[   rP   r  )r   Úchunk_noisyÚ	chunk_rawrC   rJ   rK   rL   	  s   þÿrå   )rÓ   rO   z            Flat (%2d): %sr@  z            Bad:       %s %0.1fc                 3   s   | ]\}}|ˆ kr|V  qd S r  rJ   )rH   Úbr�   ©rú  rJ   rK   r�   B	  s      z,find_bad_channels_maxwell.<locals>.<genexpr>c                    s   ˆ j  | ¡S r  ©r[   r’   r|  ©rC   rJ   rK   Ú<lambda>C	  ó    z+find_bad_channels_maxwell.<locals>.<lambda>)r¿  c                 3   s   | ]\}}|ˆ kr|V  qd S r  rJ   )rH   Úfr�   r  rJ   rK   r�   D	  s      c                    s   ˆ j  | ¡S r  r  r|  r  rJ   rK   r  E	  r	  z    Static bad channels:  %sz    Static flat channels: %srz   )r[   Úch_typesr6  Úscores_flatZlimits_flatÚscores_noisyZlimits_noisy):rP   r^  r-   rO   rQ  Úfilterrµ   r	   r¿   r¸   r¹   rè   rU   rV   rê   rÎ   r3   rW   r1   r{   ré   r   rÄ   r  rÏ   rR   rð   r[   Zget_channel_typesÚfullÚnanZ	full_likerÁ   Úget_datar(   rþ  rÐ   rÀ   r   rê  Zreshapera  rÍ   rQ   r/   r9  rî   r5   r|   rÂ   Zptpr-  r`  Zargmaxrb  rð  rX   rè  )>rC   ÚlimitrY   rú  Zreturn_scoresrg   rh   ri   rj   rk   rn   rp   rq   rr   rs   rv   rw   rù  rx   r,   Zfreq_locrC  rû   rü   rý   rþ   ÚsteprS   rÿ   ÚssZ	noisy_chsZflat_chsZthese_limitsZ	flat_stepZ	all_flatsr6  r[   r  r  r  Zthresh_flatZthresh_noisyÚsir  r  Zn_iterr  rÜ   rÏ  Z	flat_stopr�   ÚdeltaZthese_picksZrange_Zcs_picksr`  rê  rì  rØ   Zmax_r”   ZscoresrJ   )r   r  r  rû  rÿ  rú  r~   rC   rK   Úfind_bad_channels_maxwell  sR      ÿ

ÿ        ú
ü   þÿÿ
ÿ
"ý

ÿ ÿÿÿ

ÿ

ÿ
ÿ
ú
r  c                    sê   t ƒ }d }| d k	rât| ƒ}|d ‰ |d ˆ krFtˆ dd�‰ t|dd�}ttt|ƒtˆ ƒ ƒƒ}t|ƒdkrvtd| ƒ‚tttˆ ƒt|ƒ ƒƒ}t|ƒdkr¦td| ƒ ‡ fdd„|D ƒ}|d	 | d d …|f }|d	 j	 
¡ |d	< ||fS )
NZproj_items_chsr   TrÑ  z-Missing MEG channels in cross-talk matrix:
%sz&Not all cross-talk channels in raw:
%sc                    s   g | ]}ˆ   |¡‘qS rJ   r‘   r“   ©Zctc_chsrJ   rK   rL   r	  s     z$_read_cross_talk.<locals>.<listcomp>Z	decoupler)rÄ   r"   r.   rQ   r¿   rR   rW   rº   r/   rB  Ztocsc)rk   r[   r™   rŠ   r×   Z	ctc_picksrJ   r  rK   rÇ   `	  s(    ÿrÇ   c                 C   s�   ddl m} t| tdƒ |t t| d ƒdf¡|  ¡ dd�}t 	d¡ t
||||||d	||||	|
d
�}|d | d dd�\}}}}}||||fS )a8  Compute the SSS basis for a given measurement info structure.

    Parameters
    ----------
    %(info_not_none)s
    %(origin_maxwell)s
    %(int_order_maxwell)s
    %(ext_order_maxwell)s
    %(calibration_maxwell_cal)s
    %(coord_frame_maxwell)s
    %(regularize_maxwell_reg)s
    %(ignore_ref_maxwell)s
    %(bad_condition_maxwell_cond)s
    %(mag_scale_maxwell)s
    %(extended_proj_maxwell)s
    %(verbose)s

    Returns
    -------
    S : ndarray, shape (n_meg, n_moments)
        The basis that can be used to reconstruct the data.
    pS : ndarray, shape (n_moments, n_good_meg)
        The (stabilized) pseudoinverse of the S array.
    reg_moments : ndarray, shape (n_moments,)
        The moments that were kept after regularization.
    n_use_in : int
        The number of kept moments that were in the internal space.

    Notes
    -----
    This outputs variants of :math:`\mathbf{S}` and :math:`\mathbf{S^\dagger}`
    from equations 27 and 37 of :footcite:`TauluKajola2005` with the coil scale
    for magnetometers already factored in so that the resulting denoising
    transform of the data to obtain :math:`\hat{\phi}_{in}` from equation
    38 would be::

        phi_in = S[:, :n_use_in] @ pS[:n_use_in] @ data_meg_good

    .. versionadded:: 0.23

    References
    ----------
    .. footbibliography::
    r   )r(   rP   r[   r…   FrN  zComputing Maxwell basisN)rC   rg   rh   ri   rj   rn   ro   rp   rq   rr   rv   rx   r±   rM   r�   rÛ   )Úior(   r4   r!   rU   rÑ   rW   rO   r-   rP   r{   )rP   rg   rh   ri   rj   rn   rp   rq   rr   rv   rx   r,   r(   rC   r~   r
  rö   r÷   rÝ   rø   rJ   rJ   rK   Úcompute_maxwell_basisy	  s.    2ÿ
       ûÿr  )r]   r^   r_   NNNr`   ra   Nrb   Frc   NTFrd   re   rJ   N)r]   r^   r_   NNNr`   ra   Nrb   Frc   NTFrd   re   rJ   rb   N)rb   T)TN)N)FN)rd   r†  )TTTT)Frd   )Nrd   )rö  r÷  râ   Fr]   r^   r_   NNra   rb   Frc   Nrd   re   rø  rJ   N)r]   r^   r_   Nra   rb   Trc   rd   rJ   N)‚Úcollectionsr   r   Ú	functoolsr   Úmathr   Úosr   rÒ  ÚnumpyrU   rÂ  r   r=   r	   Zbemr
   Z
transformsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Úforwardr   r   r   Zsurfacer   Zio.constantsr   r   Zio.meas_infor    r!   Zio.proc_historyr"   Zio.writer#   r$   r  r%   r&   r'   r(   r)   Zio.pickr*   r+   Úutilsr,   r-   r.   r/   r0   r1   r2   r3   r4   r5   Úfixesr6   r7   Zchannels.channelsr8   r9   r\   r€   r{   r|   r¾   rç   r·   rÈ   rñ   rò   ræ   r»   rÒ   r]  rd  r½   r´   r³   re  rÌ   r~  r�  r…  rÕ   r�  r,  r›  rª  rž  r�  r«  r°  r�  r’  r»  r¼   r}   rÅ  rÄ   rx  rÍ  rA  rÙ  rÅ   rç  rj  rl  rk  rî  rÉ   r  rÇ   r  rJ   rJ   rJ   rK   Ú<module>	   s@  D0   þ                            ú 1                                ø <   û
 /!40$K ÿ   ÿ3

f 	
>
0T
`)
                                ú  M             ü