5G/NR - Carrier Bandwith Part

 

 

 

BWP (BandWidth Part) in a Nutshell

 

  • What is it ?  BWP is a mechanism to configure/divide a whole channel band into multiple segments and switch among the subbands depending on situation
  • BWPs can overlap in terms of frequency span and location
  • Minimum bandwidth of a BWP should be equal or larger than SSB Bandwidth
  • It is not mandatory for every BWP should transmit SSB
  • Max number of BWP that can configured is 4, but only one of them can be active at a specific time.
  • Each DL BWP should have at least one CORESET with UE Specific Search Space (USS)
  • In Primary DL BWP, there should be at least one CORESET with Common Search Space (CSS)
  • There are roughly 3 ways of BWP switching : Timer based, DCI based, RRC Based
  • It would require a certain amount of time to switch between BWPs and the minimum switching time is up to UE capability which should be informed to network via UE capability Information.

BWP(Carrier Bandwidth Part) in Detail

This page is about another new concept in NR called BWP(BandWidth Part).  BWP is a part of the total channel bandwidth configured for a cell that is used for a UE at a specific moment of operation.  Usually a cell configures multiple BWPs out of the total channel bandwidth and select a specific one at each moment of operation. I think the purpose and concept of BWP is very similar to NarrowBand in LTE M1.

 

Definition of BWP

According to 38.211 4.4.5, A carrier bandwidth part is defined as follows :

Carrier Bandwidth Part is a contiguous set of physical resource blocks,selected from a contiguous subset of the common resource blocks for a given numerology(u) on a given carrier. It can be illustrated as below.

This single sentence from the specification is short, but almost every word in it is carrying weight. So before looking at the illustration, let me take the definition apart word by word, because each part answers a different question about what a BWP actually is.

  • "a contiguous set of physical resource blocks" - a BWP cannot have holes in it. You are not allowed to build one BWP out of RB 0 to 9 plus RB 50 to 59. It has to be one single unbroken block of spectrum. This restriction is not an accident : it is exactly what allows the UE to narrow its receiver down to just that block, and that is where most of the power saving benefit of BWP comes from.
  • "selected from a contiguous subset of the common resource blocks" - this is where the two different resource block numbering systems come from. The common resource blocks (CRB) are the absolute grid that runs across the whole carrier, and a BWP is carved out of that grid. Inside the BWP, however, the resource blocks are renumbered from 0 as physical resource blocks (PRB). So a BWP is fully described by just two numbers : where it starts in CRB terms, and how many resource blocks long it is.
  • "for a given numerology (u)" - this is the most important part of the definition and it is the easiest one to read past. Each BWP carries its own numerology, i.e, its own subcarrier spacing and cyclic prefix. Two BWPs on the same carrier can use 15 kHz and 60 kHz spacing respectively. This is what makes BWP much more than a simple 'use a narrower band' feature - switching BWP can also mean switching the whole frame structure the UE is working with.
  • "on a given carrier" - a BWP belongs to one carrier (one serving cell). If the UE is doing carrier aggregation, every serving cell has its own independent set of BWPs and its own active BWP.

It is just as useful to notice what the definition does not say. It says nothing about where the SSB sits, and it says nothing about BWPs having to be next to each other. In fact BWPs are allowed to overlap, and in real configurations they very often do - a wide BWP for high throughput and a narrow BWP for power saving are commonly placed on top of each other, sharing the same piece of spectrum.

The two numbers mentioned above - the starting point and the length - are not just a way of talking. They are literally what gets signalled to the UE, packed into a single RRC field called locationAndBandwidth. How those two numbers are squeezed into one value is described later on this page in How BWP location and bandwidth is specified in RRC.

NOTE : Maximum 4 BWP can be specified in DL and UL. Following illustration is only an example showing the case of 3 BWP. (NOTE : CRB in this illustration stands for Carrier Resource Block which is numbered from the one end through the other end of Carrier Band (this is a kind of global resource block), the PRB stands for Physical Resource Block is the resource blocks numbered within each BWP).

 

It is worth walking through this illustration slowly, because almost every symbol that appears later on this page is already in it.

  • Start at the very bottom. The green block marked CRB0 is where the common resource block grid begins, and the arrow underneath it points at Point A. Everything else in the picture is measured from here. Point A is the origin of the coordinate system, and it is shared by the network and the UE.
  • Each of the three bandwidth parts is then described by exactly the two numbers mentioned above. N(start,BWP i) is how far the BWP begins from CRB0, counted in common resource blocks, and N(size,BWP i) is how many resource blocks it contains. Notice that all three start arrows on the left are drawn from the same place - they are all measured from CRB0, not from the BWP below.
  • Look at the numbering inside each of the blue blocks. Every BWP starts again at PRB0 and counts up to its own PRB N. So there are three different resource blocks in this picture that are all called 'PRB0'. This is exactly why the picture carries two separate labels at the bottom : "PRB 0 within a carrier bandwidth" pointing at the first block of BWP 0, and "PRB 0 in Reference Resource Block" pointing at CRB0.
  • The blue arrow on the far right is the carrier bandwidth, i.e, the whole channel the cell is operating on. The BWPs live inside it, and none of them has to fill it.

The consequence of all this is a point that confuses many people when they first read a log : the same physical piece of spectrum has more than one name. One resource block is 'CRB 63' in the absolute grid, but it may be 'PRB 3' while BWP 1 is active and 'PRB 20' while BWP 2 is active. Which name is correct depends entirely on which BWP is active at that moment. The arithmetic that converts between the two is exactly what the Mapping between nCRB and nPRB section below is about.

NOTE : One more consequence of the numerology part of the definition is easy to overlook. Because each BWP can have a different subcarrier spacing, a resource block is not the same width in Hz in every BWP. A resource block is always 12 subcarriers, but 12 subcarriers at 15 kHz is 180 kHz while 12 subcarriers at 60 kHz is 720 kHz. So a BWP of 50 resource blocks can be four times wider than another BWP of 50 resource blocks on the very same carrier. Whenever you compare BWP sizes, always check the numerology before comparing the numbers.

Point A indicates a common reference point for resource block grids and is obtained from the following higher-layer parameters as described in 38.211 - 4.4.4.2:

  • PRB-index-DL-common for a PCell downlink represents the frequency offset between point A and the lowest subcarrier of the lowest resource block of the SS/PBCH block used by the UE for initial cell selection;
  • PRB-index-UL-common for a PCell uplink in paired spectrum represents the frequency offset between point A and the frequency location based on ARFCN of the uplink indicated in SIB1;
  • PRB-index-UL-common for a PCell uplink in unpaired spectrum represents the frequency offset between point A and the lowest subcarrier of the lowest resrouce block of the SS/PBCH block used by the UE for initial cell selection;
  • PRB-index-DL-Dedicated for an SCell downlink represents the frequency offset between point A and the frequency location based on ARFCN in the higher-layer SCell configuration;
  • PRB-index-UL-Dedicated for an SCell uplink represents the frequency offset between point A and the frequency location based on ARFCN in the higher-layer SCell configuration;
  • PRB-index-SUL-common for a supplementary uplink represents the frequency offset between point A and the frequency location based on ARFCN in the higher-layer SUL configuration.

Carrier Bandwidth Part allocation for DL and UL

The previous section explained what a BWP is. This section is about the rules that the network has to obey when it actually configures them. The rules are listed separately for downlink and uplink because they are not identical, but the two lists share the same backbone, so it is worth understanding that backbone first.

Almost everything in the two lists below comes out of one pair of numbers :

    up to four bandwidth parts can be configured, but only one of them can be active at any moment.

The distinction between those two words is the single most important idea in this section, so let me spell it out.

  • Configured means the BWP has been written into the UE's RRC configuration. The UE knows its start point, its size, its numerology, its CORESETs and so on - but it is not using it. Think of it as a preset that has been stored but not selected.
  • Active means this is the one the UE is actually working on right now. Exactly one downlink BWP and exactly one uplink BWP are active per serving cell at any instant.

This separation is what makes the whole feature practical. Because all four BWPs are configured in advance, moving from one to another does not need an RRC reconfiguration - it only needs a couple of bits in a DCI, or a timer expiring. That is why BWP switching can happen in a few slots rather than in tens of milliseconds.

NOTE : The 'four' in the lists below counts the dedicated BWPs. As the RRC section further down this page mentions, BWP-Id 0 is reserved for the initial BWP, so the dedicated ones carry IDs 1 to 4 and sit alongside it. The different roles a BWP can play - initial, first active, default and ordinary - are described in the BWP types section.

The second thing that runs through both lists is the rule that the UE does not receive or transmit anything outside the active BWP. It is easy to read that as a restriction on the UE, but it is better read the other way round : it is a permission for the UE to stop listening everywhere else. That permission is what allows the UE to narrow its receiver down to the active BWP and save a significant amount of power, and without it the whole BWP concept would give no benefit at all.

The same rule immediately explains the CORESET requirements in the downlink list, which otherwise look like arbitrary bookkeeping. If the UE only listens inside the active BWP, then anything the network wants to say to it has to be sent inside that BWP - including the message that tells it to switch to another one. A downlink BWP with no CORESET in it would therefore be a trap : the UE would move in, stop hearing the network, and have no way of being told to come back. Hence every DL BWP must carry at least one CORESET with a UE specific search space, and on the primary carrier at least one BWP must also carry a common search space so that broadcast and paging type signalling still has somewhere to land.

The SSB requirement in the list works the same way. A BWP has to be at least as wide as the SS Block, but it does not have to contain one. If the active DL BWP happens not to contain the SSB, the UE simply cannot perform SSB based synchronisation and measurement while it is there, which is something the network has to plan around.

Finally, a word about how the downlink and uplink lists relate to each other, because this depends on the duplex mode :

  • In FDD (paired spectrum) the downlink and the uplink are on different frequencies, so the DL BWPs and the UL BWPs are configured and switched independently of each other.
  • In TDD (unpaired spectrum) they are not independent. A DL BWP and an UL BWP that share the same bwp-Id are treated as a pair, and the UE expects both of them to have the same centre frequency. Switching one therefore switches the other as well - which makes sense, since a TDD radio cannot be tuned to two different places at the same time.

With that in mind, the detailed rules are as follows.

< Downlink >

  • A UE can be configured with up to four carrier bandwidth parts
  • The bandwidth of each BW should be equal or greater than SS Block BW, but it may or may not contain SS Block.
  • Only one carrier bandwidth part can be active at a given time
  • The UE is not expected to receive PDSCH, PDCCH, CSI-RS, or TRS outside an active bandwidth part.
  • Each DL BWP include at least one CORESET with UE Specific Search Space (USS).
  • In primary carrier, at least one of the configured DL BWPs includes one CORESET with common search space (CSS)

< Uplink >

  • A UE can be configured with up to four carrier bandwidth parts
  • Only one carrier bandwidth part can be active at a given time
  • If a UE is configured with a supplementary uplink
    • The UE can in addition be configured with up to four carrier bandwidth parts in the supplementary uplink
    • Only one carrier bandwidth part can be active at a given time
  • The UE shall not transmit PUSCH or PUCCH outside an active bandwidth part.

Mapping between nCRB and nPRB

nCRB indicates a resource block location in common resource block, nPRB indicates a resource block within a specific carrier bandwidth part. In other words, you can think of nCRB is a position in an absolute (reference) coordinate system and nPRB is a position in a relative coordinate system. The relationship between nCRB and nPRB is defined as follows (38.211 v2.0.0 - 4.4.4.4).

This is probably the simplest formula in the whole of 38.211 - it is one addition - but it is worth slowing down on, because it is used constantly and because getting it backwards is a very common source of confusion when reading a log.

Read the formula as a coordinate translation : take the local address, add the place where the local map begins, and you get the global address. An everyday version of the same arithmetic is a page number in a book. If a chapter starts on page 120 and you are on page 7 of that chapter, then you are on page 127 of the book. n(PRB) is the page within the chapter, N(start,BWP) is where the chapter begins, and n(CRB) is the page in the book.

Three details in the formula are worth pointing out explicitly.

  • It only runs in one direction as written. The formula converts PRB into CRB. Going the other way is just a subtraction, n(PRB) = n(CRB) - N(start,BWP), but that result is only meaningful if the resource block actually falls inside the BWP, i.e, if the answer lies between 0 and N(size,BWP) - 1. If it does not, the question simply has no answer, because that resource block is not part of the BWP at all.
  • N(start,BWP) is measured from CRB 0, which is Point A - not from the BWP below it and not from the edge of the carrier. This is the same starting arrow that appeared in the illustration in the Definition of BWP section.
  • The subscript i (the BWP index) is doing real work. There is a different N(start) for every configured BWP, so the very same n(PRB) translates into a different n(CRB) depending on which BWP happens to be active. That is not a side effect of the formula ; it is the whole point of it.

This can be illustrated as an example shown below.

The illustration works through one example for each of the three bandwidth parts, and if you read the three labels on the left together the pattern becomes obvious.

  • For PRB0 of BWP 0 the label reads n(CRB) = 0 + N(start,BWP 0). The PRB index contributes nothing here because it is zero, so the answer is just the starting offset of that BWP.
  • For PRB1 of BWP 1 it reads n(CRB) = 1 + N(start,BWP 1). One step up inside the BWP means one step up in the common grid as well.
  • For PRB N3 of BWP 2 it reads n(CRB) = N3 + N(start,BWP 2). Same rule again, this time at the top edge of the BWP.

So nothing else enters the calculation. The index inside the BWP contributes, the start of the BWP contributes, and that is all.

Before putting real numbers into this, it is worth being clear about what a scheduling DCI actually carries, because this is the exact point where many people get the wrong picture. A DCI does not carry only a BWP index, and it does not carry a CRB number either. In DCI format 1_1 (downlink) and 0_1 (uplink) there are two separate fields working together :

  • Bandwidth part indicator (0, 1 or 2 bits) - this says which BWP. It is 0 bits if there is nothing to choose from, 1 bit for two configured BWPs and 2 bits for three or four.
  • Frequency domain resource assignment, usually shortened to FDRA - this says which resource blocks inside that BWP. For a Type 1 (contiguous) allocation it is a single coded number called RIV which packs together the starting resource block and the length ; for a Type 0 allocation it is a bitmap of resource block groups.

So the BWP indicator on its own would never be enough. It tells the UE where to tune, but not where inside that band its data is sitting. The FDRA answers that second question, and it counts from the start of the BWP, not from Point A - which is precisely why the nCRB / nPRB conversion above is needed at all.

NOTE : The fallback formats DCI 1_0 and 0_0 have no bandwidth part indicator field at all. They carry only an FDRA, which is interpreted against whatever BWP is already active. That is the reason a fallback DCI can never trigger a BWP switch - there is simply no field in it to say so.

Now let us put some real values in. Suppose the three BWPs start at CRB 0, CRB 40 and CRB 80, and in each case the FDRA decodes to a starting resource block of 3.

Active BWP

N(start,BWP)

Start RB decoded from the FDRA

Which resource block that really is

BWP 0

0

PRB 3

CRB 3

BWP 1

40

PRB 3

CRB 43

BWP 2

80

PRB 3

CRB 83

The FDRA decodes to the same starting resource block in all three rows, and yet the UE ends up transmitting or receiving on three completely different pieces of spectrum. A PRB number on its own means nothing. It only means something once you also know which BWP was active at that moment. This is the single most useful thing to carry away from this section, and it is the reason a resource allocation in a log can look wrong until you check which BWP the UE was on.

NOTE : Be careful with the phrase 'the same DCI' here. What is the same in the three rows above is the decoded result - start at resource block 3 of the active BWP. The raw bits are not necessarily the same, because the RIV value is calculated using the size of the BWP, so two BWPs of different sizes will encode 'start at RB 3' as different numbers, and the field will not even be the same length. The next two bullets are about exactly that.

Two practical consequences follow from this, and both of them catch people out.

  • The size of the FDRA field changes with the BWP. The number of bits the field needs depends on how many resource blocks the BWP contains, so switching to a BWP of a different size does not only move the frequency, it can also change the length of the DCI itself. This creates an obvious chicken and egg problem when a DCI is the thing ordering the switch : the UE has to decode the DCI before it knows it is being moved. 3GPP solves it by fixing the size of the DCI according to the currently active BWP, while interpreting the fields according to the newly indicated one, padding or truncating the FDRA field as needed. It is also one of the reasons a BWP switch takes a measurable amount of time rather than happening instantly.
  • The CRB grid itself depends on the numerology. Common resource blocks are numbered from 0 upwards separately for each subcarrier spacing, with CRB 0 of every grid lined up on Point A. So 'CRB 43' in a 15 kHz grid and 'CRB 43' in a 30 kHz grid are not the same frequency - the second one is twice as far from Point A. Since each BWP carries its own numerology, you have to know the subcarrier spacing before a CRB number can be turned into a frequency.

Putting the last point together, the full chain from a scheduling grant to an actual frequency runs like this : the DCI gives you n(PRB) ; adding N(start,BWP) gives you n(CRB) ; multiplying by the resource block width for that numerology (12 subcarriers x the subcarrier spacing) gives you the offset in Hz from Point A ; and adding the absolute frequency of Point A, which the network signals as absoluteFrequencyPointA, finally gives you a real frequency in MHz.

BWP types

There are several different types of BWPs : Initial BWP, firstActiveBWP, Default BWP and (regular) BWPs. These are defined in RRC message as follows. Regarding the role of each BWP, refer to the diagram in this section and RRC parameter description in this section.

There is one idea that makes this whole section much easier, and it is the thing that trips people up most often here. These are not four different kinds of object. There is only one kind of object - a bandwidth part - and 'initial', 'first active' and 'default' are roles that a bandwidth part plays.

The roles are assigned simply by pointing an ID at a BWP. That means one and the same BWP can hold several roles at once : it is perfectly normal for BWP #1 to be the first active BWP and the default BWP at the same time, and for BWP #0 to be the initial BWP and the default BWP at the same time. So when a document says 'the default BWP', it is not describing a special sort of BWP - it is describing whichever BWP the defaultDownlinkBWP-Id happens to be pointing at.

With that in mind, the four terms line up like this.

Term

What it is in RRC

What it is for

Initial BWP

initialDownlinkBWP / initialUplinkBWP. Always BWP-Id 0.

The BWP the UE lives in before it has any dedicated configuration - this is where initial access happens, and it is derived from the cell's broadcast information. It always exists, and it is the safety net the UE can always fall back to.

(regular) BWP

The entries of downlinkBWP-ToAddModList / uplinkBWP-ToAddModList, carrying BWP-Id 1 to 4.

The ordinary working bandwidth parts that the network defines for this particular UE. These are the ones the UE is switched between during normal operation.

First active BWP

firstActiveDownlinkBWP-Id / firstActiveUplinkBWP-Id. A BWP-Id value, not a BWP.

Answers the question "which BWP should be active the moment this configuration takes effect ?". For an SpCell that is when the RRC reconfiguration is applied ; for an SCell it is when the SCell is activated by MAC. If it is absent, the reconfiguration does not force any BWP switch.

Default BWP

defaultDownlinkBWP-Id. Again a BWP-Id value, not a BWP.

Answers the question "where should the UE go when nothing is happening ?". When the bwp-InactivityTimer expires the UE falls back to this one. If the field is absent, the initial BWP is used as the default.

So two of the four are actual configurations, and two of them are just pointers. Keeping that separation in your head is most of the battle.

NOTE : Notice that there is a defaultDownlinkBWP-Id but no defaultUplinkBWP-Id. The 'fall back when idle' behaviour is defined on the downlink only. In TDD that is not a problem, because a DL BWP and the UL BWP with the same ID are paired and switch together anyway ; in FDD the uplink simply has no inactivity fallback of its own.

< BWP configuration in ENDC RRCReconfig >

Reading this tree from the top, a few things are worth pointing out.

  • The initial BWP appears twice, and this is not a mistake. Once under spCellConfigCommon, which is the cell specific part that every UE in the cell shares, and once under spCellConfigDedicated, which is the UE specific part for the same BWP #0. This common plus dedicated split is exactly what the second illustration below is about.
  • The orange comment on the right of the figure points at the real difference between BWP #0 and the rest : the initial BWP has no bwp-Id field at all. It does not need one, because the specification simply declares that the initial BWP is ID 0. The four entries in downlinkBWP-ToAddModList, on the other hand, each carry their own bwp-Id, which is what the other pointers refer to.
  • The green and yellow arrows are the 'roles are just pointers' idea drawn out. firstActiveDownlinkBWP-id and defaultDownlinkBWP-id sit at the bottom of the list and each of them selects one of the BWPs above - and notice that the arrows reach the initial BWP as well, not only BWP[1] to BWP[4]. That is how BWP #0 can be made the default.
  • Look at the uplink branch at the bottom and compare it with the downlink branch. It has InitialUplinkBWP, uplinkBWP-ToAddModList and firstActiveUplinkBWP-id - but no default. This is the same asymmetry mentioned in the note above, now visible in the structure itself.

Using the basic types and configuration structure as shown above, you can take various options of BWP configuration as shown below.

Source : A Primer on Bandwidth Parts in 5G New Radio

This second illustration is more interesting than it first looks, so it is worth decoding. Every BWP in the picture is built out of up to four blocks, and the legend at the bottom tells you what they are : BWP-DownlinkCommon and BWP-UplinkCommon are the cell specific parameters, while BWP-Downlink and BWP-Uplink are the UE specific (dedicated) ones. The two options differ in one single thing : whether BWP #0 gets the dedicated blocks or not.

  • Option 1 : BWP #0 has only the Common blocks. It is a usable BWP, but it has no dedicated configuration of its own.
  • Option 2 : BWP #0 has the Common blocks and the dedicated blocks, so it looks exactly like any other BWP.

Now look at the red numbers at the right hand end of each row, because that is where the consequence shows up. In Option 1 the network may go on adding BWPs up to #4, but in Option 2 only up to #3. At first sight that looks arbitrary. The reason is the sentence in the RRC description of initialDownlinkBWP further down this page : if any of the optional (dedicated) IEs are present in the initial BWP, then the UE counts BWP #0 as an RRC configured BWP from the UE capability point of view ; if they are absent, it does not.

Since the UE can only support four configured BWPs in total, the arithmetic is simply :

  • Option 1 - BWP #0 does not count, so the four slots are #1, #2, #3 and #4.
  • Option 2 - BWP #0 does count, so it takes one of the four slots and only #1, #2 and #3 are left.

Which option to use is therefore a real trade off rather than a matter of taste.

  • Option 1 gives you one more usable BWP, but BWP #0 is then limited. With no dedicated configuration there is no UE specific search space in it, so the UE can only be scheduled there with the fallback DCI formats - and as explained earlier, DCI format 1_0 has no bandwidth part indicator. That means getting out of BWP #0 needs an RRC reconfiguration rather than a quick DCI based switch.
  • Option 2 makes BWP #0 a first class citizen that can be switched into and out of by DCI just like any other BWP, at the cost of one BWP slot.

One last practical remark. In both options the illustration says the network should configure the first one or two BWPs and may configure the rest 'consecutively'. In real commercial networks it is very common to see only BWP #0, or BWP #0 plus one dedicated BWP. Four fully configured BWPs with active switching between them is much rarer than the amount of specification text devoted to it would suggest.

RRC Parameters for BandwidthPart Configuration

Everything described so far - the start and the size of a BWP, its numerology, the four configured BWPs, the first active one, the default one and the inactivity timer - has to be written down somewhere and sent to the UE. This section is that 'somewhere' : the ASN.1 of TS 38.331.

A raw ASN.1 dump is hard to read cold, so it is worth having the shape of it in your head before you start. The BWP configuration is not one flat structure. It is a nest of containers, and it hangs off ServingCellConfig, which means the whole thing exists once per serving cell.

ServingCellConfig                                     <-- one instance per serving cell
 |
 |-- initialDownlinkBWP --------> BWP-DownlinkDedicated      (the dedicated part of BWP #0)
 |-- downlinkBWP-ToAddModList --> BWP-Downlink  (1..4)
 |                                 |-- bwp-Id
 |                                 |-- bwp-Common -----> BWP-DownlinkCommon
 |                                 |                      |-- genericParameters --> BWP
 |                                 |-- bwp-Dedicated --> BWP-DownlinkDedicated
 |-- downlinkBWP-ToReleaseList
 |-- firstActiveDownlinkBWP-Id ... a BWP-Id, i.e, just a pointer
 |-- defaultDownlinkBWP-Id ....... a BWP-Id, i.e, just a pointer
 |-- bwp-InactivityTimer
 |
 |-- uplinkConfig --------------> UplinkConfig
 |                                 |-- initialUplinkBWP ------> BWP-UplinkDedicated
 |                                 |-- uplinkBWP-ToAddModList -> BWP-Uplink (1..4)
 |                                 |       (same three part structure as BWP-Downlink above)
 |                                 |-- uplinkBWP-ToReleaseList
 |                                 |-- firstActiveUplinkBWP-Id
 |
 |-- supplementaryUplink -------> UplinkConfig     (a second, independent set for SUL)

Three things in that tree are worth pointing out, because once you see them the ASN.1 below stops looking arbitrary.

  • Every BWP is built from three parts. BWP-Downlink is nothing more than an identity (bwp-Id) plus a common part plus a dedicated part, and BWP-Uplink has exactly the same shape. Once you have understood one of them you have understood all four.
  • The frequency itself is buried three levels down. The thing that actually says where the BWP is and how wide it is - locationAndBandwidth, subcarrierSpacing, cyclicPrefix - lives in the little IE called simply BWP, which is reached as BWP-Downlink > bwp-Common > genericParameters. It is easy to hunt for it at the top level and not find it. Everything else in the tree is either an identifier, a pointer, or channel configuration that happens to be per BWP.
  • Common and dedicated mean cell specific and UE specific. The Common parts hold what every UE in the cell must agree on and they line up with what is broadcast in system information ; the Dedicated parts hold what belongs to this one UE. This is exactly the split that Option 1 and Option 2 in the BWP types section were about.

Two conventions of 38.331 also show up all over the listing below and are worth knowing, because they are not specific to BWP.

  • ToAddModList and ToReleaseList - RRC does not resend the whole configuration every time. It sends a delta : the entries in downlinkBWP-ToAddModList are added or modified, the IDs listed in downlinkBWP-ToReleaseList are deleted, and any BWP that is mentioned in neither list is simply left exactly as it was. This is why you can add one BWP without disturbing the other three.
  • The -- Need and -- Cond comments on the right - these are not documentation, they are normative. They tell the UE what to do when a field is absent from a message.

Comment

Means

What the UE does if the field is not in the message

-- Need M

Maintain

Keeps whatever value it already had. The field is stored, so leaving it out is the way of saying "no change".

-- Need N

No action

Nothing. These are one shot fields that are not stored at all - their presence triggers a single action and that is the end of it.

-- Need R

Release

Releases the current value. Here, leaving the field out is not harmless - it actively removes the configuration.

-- Need S

Specified

Whatever the field description says. defaultDownlinkBWP-Id is a good example : the text tells you that if it is absent the UE uses the initial BWP as the default.

-- Cond xxx

Conditional

Whether the field may or must be present depends on a condition, which is written out in a small table underneath the IE in the specification. For example bwp-Common is Cond SetupOtherBWP, i.e, it is only there when a BWP other than the initial one is being set up.

NOTE : In the listing below, ServingCellConfig and UplinkConfig are shown only down to their BWP related fields. Both of them have grown very large across Release 16 to 19, and the rest of their content belongs to other topics. The BWP IEs themselves are shown in full, including all of the release extension groups, so that you can see which fields came in with which release - the -r16, -r17, -r18 and -r19 suffixes tell you that directly.

Following is based on 38.331 v19.2.0 (Release 19)

ServingCellConfig ::=               SEQUENCE {
    tdd-UL-DL-ConfigurationDedicated    TDD-UL-DL-ConfigDedicated                                                OPTIONAL,   -- Cond TDD
    initialDownlinkBWP                  BWP-DownlinkDedicated                                                    OPTIONAL,   -- Need M
    downlinkBWP-ToReleaseList           SEQUENCE (SIZE (1..maxNrofBWPs)) OF BWP-Id                               OPTIONAL,   -- Need N
    downlinkBWP-ToAddModList            SEQUENCE (SIZE (1..maxNrofBWPs)) OF BWP-Downlink                         OPTIONAL,   -- Need N
    firstActiveDownlinkBWP-Id           BWP-Id                                                                   OPTIONAL,   -- Cond SyncAndCellAdd
    bwp-InactivityTimer                 ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30,
                                                    ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500,
                                                    ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8,
                                                    spare7, spare6, spare5, spare4, spare3, spare2, spare1 }    OPTIONAL,   --Need R
    defaultDownlinkBWP-Id               BWP-Id                                                                  OPTIONAL,   -- Need S
    uplinkConfig                        UplinkConfig                                                            OPTIONAL,   -- Need M
    supplementaryUplink                 UplinkConfig                                                            OPTIONAL,   -- Need M
    pdcch-ServingCellConfig             SetupRelease { PDCCH-ServingCellConfig }                                OPTIONAL,   -- Need M
    pdsch-ServingCellConfig             SetupRelease { PDSCH-ServingCellConfig }                                OPTIONAL,   -- Need M
    csi-MeasConfig                      SetupRelease { CSI-MeasConfig }                                         OPTIONAL,   -- Need M
    sCellDeactivationTimer              ENUMERATED {ms20, ms40, ms80, ms160, ms200, ms240,
                                                    ms320, ms400, ms480, ms520, ms640, ms720,
                                                    ms840, ms1280, spare2,spare1}       OPTIONAL,   -- Cond ServingCellWithoutPUCCH
    crossCarrierSchedulingConfig        CrossCarrierSchedulingConfig                                            OPTIONAL,   -- Need M
    tag-Id                              TAG-Id,
    dummy1                              ENUMERATED {enabled}                                                    OPTIONAL,   -- Need R
    pathlossReferenceLinking            ENUMERATED {spCell, sCell}                                              OPTIONAL,   -- Cond SCellOnly
    servingCellMO                       MeasObjectId                                                            OPTIONAL,   -- Cond MeasObject
    ...          -- remaining fields and the r16/r17/r18/r19 extensions are not BWP related
}

maxNrofBWPs                             INTEGER ::= 4       -- Maximum number of BWPs per serving cell

BWP-Id ::=                          INTEGER (0..maxNrofBWPs)

UplinkConfig ::=                    SEQUENCE {
    initialUplinkBWP                    BWP-UplinkDedicated                                                     OPTIONAL,   -- Need M
    uplinkBWP-ToReleaseList             SEQUENCE (SIZE (1..maxNrofBWPs)) OF BWP-Id                              OPTIONAL,   -- Need N
    uplinkBWP-ToAddModList              SEQUENCE (SIZE (1..maxNrofBWPs)) OF BWP-Uplink                          OPTIONAL,   -- Need N
    firstActiveUplinkBWP-Id             BWP-Id                                                                  OPTIONAL,   -- Cond SyncAndCellAdd
    pusch-ServingCellConfig             SetupRelease { PUSCH-ServingCellConfig }                                OPTIONAL,   -- Need M
    carrierSwitching                    SetupRelease { SRS-CarrierSwitching }                                   OPTIONAL,   -- Need M
    ...          -- remaining r16/r18 extensions are not BWP related
}

BWP-Downlink ::=                    SEQUENCE {
    bwp-Id                              BWP-Id,
    bwp-Common                          BWP-DownlinkCommon                                         OPTIONAL,   -- Cond SetupOtherBWP
    bwp-Dedicated                       BWP-DownlinkDedicated                                      OPTIONAL,   -- Cond SetupOtherBWP
    ...
}

BWP-DownlinkCommon ::=              SEQUENCE {
    genericParameters                   BWP,
    pdcch-ConfigCommon                  SetupRelease { PDCCH-ConfigCommon }                                     OPTIONAL,   -- Need M
    pdsch-ConfigCommon                  SetupRelease { PDSCH-ConfigCommon }                                     OPTIONAL,   -- Need M
    ...
}

BWP-DownlinkDedicated ::=           SEQUENCE {
    pdcch-Config                        SetupRelease { PDCCH-Config }                                     OPTIONAL,   -- Need M
    pdsch-Config                        SetupRelease { PDSCH-Config }                                     OPTIONAL,   -- Need M
    sps-Config                          SetupRelease { SPS-Config }                                       OPTIONAL,   -- Need M
    radioLinkMonitoringConfig           SetupRelease { RadioLinkMonitoringConfig }                        OPTIONAL,   -- Need M
    ...,
    [[
    sps-ConfigToAddModList-r16          SPS-ConfigToAddModList-r16                                        OPTIONAL,   -- Need N
    sps-ConfigToReleaseList-r16         SPS-ConfigToReleaseList-r16                                       OPTIONAL,   -- Need N
    sps-ConfigDeactivationStateList-r16 SPS-ConfigDeactivationStateList-r16                               OPTIONAL,   -- Need R
    beamFailureRecoverySCellConfig-r16  SetupRelease {BeamFailureRecoveryRSConfig-r16}                    OPTIONAL,   -- Cond SCellOnly
    sl-PDCCH-Config-r16                 SetupRelease { PDCCH-Config }                                     OPTIONAL,   -- Need M
    sl-V2X-PDCCH-Config-r16             SetupRelease { PDCCH-Config }                                     OPTIONAL    -- Need M
    ]],
    [[
    preConfGapStatus-r17                BIT STRING (SIZE (maxNrofGapId-r17))                              OPTIONAL,   -- Cond PreConfigMG
    beamFailureRecoverySpCellConfig-r17 SetupRelease { BeamFailureRecoveryRSConfig-r16}                   OPTIONAL,   -- Cond SpCellOnly
    harq-FeedbackEnablingforSPSactive-r17 BOOLEAN                                                         OPTIONAL,   -- Need R
    cfr-ConfigMulticast-r17             SetupRelease { CFR-ConfigMulticast-r17 }                          OPTIONAL,   -- Need M
    dl-PPW-PreConfigToAddModList-r17    DL-PPW-PreConfigToAddModList-r17                                  OPTIONAL,   -- Need N
    dl-PPW-PreConfigToReleaseList-r17   DL-PPW-PreConfigToReleaseList-r17                                 OPTIONAL,   -- Need N
    nonCellDefiningSSB-r17              NonCellDefiningSSB-r17                                            OPTIONAL,   -- Need R
    servingCellMO-r17                   MeasObjectId                                                  OPTIONAL -- Cond MeasObject-NCD-SSB
    ]],
    [[
    tci-InDCI-r18                       SetupRelease {TCI-InDCI-r18}                                      OPTIONAL    -- Need M
    ]],
    [[
    sbfd-Config2-Reception-r19          ENUMERATED {enabled}                                              OPTIONAL,   -- Need S
    pathlossOffsetPRACH-DCI-1-0-r19     ENUMERATED { enabled }                                            OPTIONAL,   -- Need R
    prachAssociationDCI-1-0-r19         ENUMERATED { enabled }                                            OPTIONAL    -- Need R
    ]]
}

BWP-Uplink ::=                      SEQUENCE {
    bwp-Id                              BWP-Id,
    bwp-Common                          BWP-UplinkCommon                                            OPTIONAL,   -- Cond SetupOtherBWP
    bwp-Dedicated                       BWP-UplinkDedicated                                         OPTIONAL,   -- Cond SetupOtherBWP
    ...
}

BWP-UplinkCommon ::=                SEQUENCE {
    genericParameters                   BWP,
    rach-ConfigCommon                   SetupRelease { RACH-ConfigCommon }                                      OPTIONAL,   -- Need M
    pusch-ConfigCommon                  SetupRelease { PUSCH-ConfigCommon }                                     OPTIONAL,   -- Need M
    pucch-ConfigCommon                  SetupRelease { PUCCH-ConfigCommon }                                     OPTIONAL,   -- Need M
    ...,
    [[
    rach-ConfigCommonIAB-r16            SetupRelease { RACH-ConfigCommon }                                      OPTIONAL,   -- Need M
    useInterlacePUCCH-PUSCH-r16         ENUMERATED {enabled}                                                    OPTIONAL,   -- Need R
    msgA-ConfigCommon-r16               SetupRelease { MsgA-ConfigCommon-r16 }                                  OPTIONAL    -- Cond SpCellOnly2
    ]],
    [[
    enableRA-PrioritizationForSlicing-r17 BOOLEAN                                                    OPTIONAL, -- Cond RA-PrioSliceAI
    additionalRACH-ConfigList-r17       SetupRelease { AdditionalRACH-ConfigList-r17 }               OPTIONAL, -- Cond SpCellOnly2
    rsrp-ThresholdMsg3-r17              RSRP-Range                                                   OPTIONAL, -- Need R
    numberOfMsg3-RepetitionsList-r17    SEQUENCE (SIZE (4)) OF NumberOfMsg3-Repetitions-r17                  OPTIONAL,  -- Cond Msg3Rep
    mcs-Msg3-Repetitions-r17            SEQUENCE (SIZE (8)) OF INTEGER (0..31)                               OPTIONAL   -- Cond Msg3Rep
    ]],
    [[
    additionalRACH-perPCI-ToAddModList-r18   SEQUENCE (SIZE (1.. maxNrofAdditionalPRACHConfigs-r18)) OF  RACH-ConfigTwoTA-r18
                                                                                                             OPTIONAL, -- Cond 2TA-Only
    additionalRACH-perPCI-ToReleaseList-r18  SEQUENCE (SIZE (1.. maxNrofAdditionalPRACHConfigs-r18)) OF AdditionalPCIIndex-r17
                                                                                                             OPTIONAL,  -- Need N
    rsrp-ThresholdMsg1-RepetitionNum2-r18    RSRP-Range                                                      OPTIONAL,  -- Need R
    rsrp-ThresholdMsg1-RepetitionNum4-r18    RSRP-Range                                                      OPTIONAL,  -- Need R
    rsrp-ThresholdMsg1-RepetitionNum8-r18    RSRP-Range                                                      OPTIONAL,  -- Need R
    preambleTransMax-Msg1-Repetition-r18     ENUMERATED {n1, n2, n4, n6, n8, n10, n20, n50, n100, n200}      OPTIONAL   -- Cond Msg1Rep1
    ]],
    [[
    preambleTransMaxRO-Type-r19                  ENUMERATED {n1, n2, n4, n6, n8, n10, n20, n50, n100, n200}  OPTIONAL,  -- Need R
    sbfd-RO-Type-r19                             ENUMERATED {sbfd, non-sbfd}                                 OPTIONAL,  -- Need S
    sbfd-RSRP-ThresholdRO-Type-r19               RSRP-Range                                                  OPTIONAL,  -- Need S
    sbfd-RSRP-ThresholdRO-TypeUsage-r19          ENUMERATED {above,below}                                    OPTIONAL,  -- Need S
    sbfd-RSRP-ThresholdMsg1-RepetitionNum2-r19   RSRP-Range                                                  OPTIONAL,  -- Need R
    sbfd-RSRP-ThresholdMsg1-RepetitionNum4-r19   RSRP-Range                                                  OPTIONAL,  -- Need R
    sbfd-RSRP-ThresholdMsg1-RepetitionNum8-r19   RSRP-Range                                                  OPTIONAL,  -- Need R
    sbfd-RACH-Config-r19                         CHOICE {
        sbfd-RACH-SingleConfig-r19                   NULL,
        sbfd-RACH-DualConfig-r19                     SBFD-RACH-DualConfig-r19
    }                                                                                                        OPTIONAL  -- Need R
    ]]
}

BWP-UplinkDedicated ::=             SEQUENCE {
    pucch-Config                        SetupRelease { PUCCH-Config }                                           OPTIONAL,   -- Need M
    pusch-Config                        SetupRelease { PUSCH-Config }                                           OPTIONAL,   -- Need M
    configuredGrantConfig               SetupRelease { ConfiguredGrantConfig }                                  OPTIONAL,   -- Need M
    srs-Config                          SetupRelease { SRS-Config }                                             OPTIONAL,   -- Need M
    beamFailureRecoveryConfig           SetupRelease { BeamFailureRecoveryConfig }                              OPTIONAL,   -- Cond SpCellOnly
    ...,
    [[
    sl-PUCCH-Config-r16                 SetupRelease { PUCCH-Config }                                           OPTIONAL,   -- Need M
    cp-ExtensionC2-r16                  INTEGER (1..28)                                                         OPTIONAL,   -- Need R
    cp-ExtensionC3-r16                  INTEGER (1..28)                                                         OPTIONAL,   -- Need R
    useInterlacePUCCH-PUSCH-r16         ENUMERATED {enabled}                                                    OPTIONAL,   -- Need R

    pucch-ConfigurationList-r16         SetupRelease { PUCCH-ConfigurationList-r16 }                            OPTIONAL,   -- Need M
    lbt-FailureRecoveryConfig-r16       SetupRelease { LBT-FailureRecoveryConfig-r16 }                          OPTIONAL,   -- Need M
    configuredGrantConfigToAddModList-r16                 ConfiguredGrantConfigToAddModList-r16                 OPTIONAL,   -- Need N
    configuredGrantConfigToReleaseList-r16                ConfiguredGrantConfigToReleaseList-r16                OPTIONAL,   -- Need N
    configuredGrantConfigType2DeactivationStateList-r16   ConfiguredGrantConfigType2DeactivationStateList-r16   OPTIONAL    -- Need R
    ]],
    [[
    ul-TCI-StateList-r17                CHOICE {
        explicitlist                        SEQUENCE {
            ul-TCI-ToAddModList-r17             SEQUENCE (SIZE (1..maxUL-TCI-r17)) OF TCI-UL-State-r17          OPTIONAL,   -- Need N
            ul-TCI-ToReleaseList-r17            SEQUENCE (SIZE (1..maxUL-TCI-r17)) OF TCI-UL-StateId-r17        OPTIONAL    -- Need N
        },
        unifiedTCI-StateRef-r17         ServingCellAndBWP-Id-r17
    }                                                                                                           OPTIONAL,  -- Need R
    ul-powerControl-r17                Uplink-powerControlId-r17                                                OPTIONAL,  -- Cond NoTCI-PC
    pucch-ConfigurationListMulticast1-r17  SetupRelease { PUCCH-ConfigurationList-r16 }                         OPTIONAL,  -- Need M
    pucch-ConfigurationListMulticast2-r17  SetupRelease { PUCCH-ConfigurationList-r16 }                         OPTIONAL   -- Need M
    ]],
    [[
    pucch-ConfigMulticast1-r17          SetupRelease { PUCCH-Config }                                           OPTIONAL,  -- Need M
    pucch-ConfigMulticast2-r17          SetupRelease { PUCCH-Config }                                           OPTIONAL   -- Need M
    ]],
    [[
    pathlossReferenceRSToAddModList-r17     SEQUENCE (SIZE (1..maxNrofPathlossReferenceRSs-r17)) OF PathlossReferenceRS-r17
                                                                                                                OPTIONAL, -- Need N
    pathlossReferenceRSToReleaseList-r17    SEQUENCE (SIZE (1..maxNrofPathlossReferenceRSs-r17)) OF PathlossReferenceRS-Id-r17
                                                                                                                OPTIONAL  -- Need N
    ]],
    [[
    sbfd-Config2-Transmission-r19       ENUMERATED {enabled}                                                    OPTIONAL,   -- Need S
    sbfd-Config2-PUSCH-RB-Offset-r19    INTEGER(0..maxNrofPhysicalResourceBlocks-1)                             OPTIONAL,   -- Need R
    ul-Muting-NonSBFD-Symbol-r19        ENUMERATED {enabled}                                                    OPTIONAL,   -- Need S
    twoTA-Without-MultiDCI-MultiTRP-r19  ENUMERATED {enabled}                                                   OPTIONAL   -- Need R
    ]]
}

BWP ::=                             SEQUENCE {
    locationAndBandwidth                INTEGER (0..37949),
    subcarrierSpacing                   SubcarrierSpacing,
    cyclicPrefix                        ENUMERATED { extended }                                                 OPTIONAL    -- Need R
}

initialDownlinkBWP : The dedicated (UE-specific) configuration for the initial downlink bandwidth-part. As described in 38.331, this is the dedicated (UE-specific) configuration for the initial downlink bandwidth-part (i.e. DL BWP#0). If any of the optional IEs are configured within this IE, the UE considers the BWP#0 to be an RRC configured BWP (from UE capability viewpoint). Otherwise, the UE does not consider the BWP#0 as an RRC configured BWP (from UE capability viewpoint). Network always configures the UE with a value for this field if no other BWPs are configured. Network always configures the UE with a value for this field if no other BWPs are configured. If the dedicated part of initial UL/DL BWP configuration is absent, the initial BWP can be used but with some limitations. For example, changing to another BWP requires RRCReconfiguration since DCI format 1_0 doesn't support DCI-based switching.

firstActiveDownlinkBWP-Id : This is the BWP to be active right after the initial attach (or NR addition) is completed.

If configured for an SpCell, this field contains the ID of the DL BWP to be activated upon performing the reconfiguration in which it is received. If the field is absent, the RRC reconfiguration does not impose a BWP switch (corresponds to L1 parameter 'active-BWP-DL-Pcell'). If configuredfor an SCell, this field contains the ID of the downlink bandwidth part to be used upon MAC-activation of an  SCell. The initial bandwidth part is referred to by BWP-Id = 0

defaultDownlinkBWP-Id : This indicates the BWP that UE/NW automatically switches when there is no activity in current BWP until bwp-InactivityTimer. If this field is set to 0, it means the defaultDownlinkBWP is same as initialDownlinkBWP. ID of the downlink bandwidth part to be used upon expiry of the BWP inactivity timer. This field is UE specific. When the field is absent the UE uses the initial BWP as default BWP.

bwp-InactivityTimer : The duration in ms after which the UE falls back to the default Bandwidth Part. The value 0.5 ms is only applicable for carriers > 6 GHz. When the network releases the timer configuration, the UE stops the timer without swithching to the default BWP

initialUplinkBWP : If configured for an SpCell, this field contains the ID of the DL BWP to be activated upon performing the reconfiguration in which it is received. If the field is absent, the RRC reconfiguration does not impose a BWP switch (corresponds to L1 parameter 'active-BWP-UL-Pcell'). If configured for an SCell, this field contains the ID of the uplink bandwidth part to be used upon MAC-activation of an  SCell. The initial bandwidth part is referred to by BandiwdthPartId = 0

firstActiveUplinkBWP-Id : The dedicated (UE-specific) configuration for the initial uplink bandwidth-part.

BWP-Id :  An identifier for this bandwidth part. Other parts of the RRC configuration use the BWP-Id to associate themselves with a particular bandwidth part. The BWP ID=0 is always associated with the initial BWP and may hence not be used here (in other bandwidth parts).

The NW may trigger the UE to swtich UL or DL BWP using a DCI field. The four code points in that DCI field map to the RRC-configured

  • BWP-ID as follows: For up to 3 configured BWPs (in addition to the initial BWP) the DCI code point is equivalent to the BWP ID
    • (initial = 0, first dedicated = 1, ...). If the NW configures 4 dedicated bandwidth parts, they are identified by DCI code
    • points 0 to 3. In this case it is not possible to switch to the initial BWP using the DCI field.
    • Corresponds to L1 parameter 'UL-BWP-index' / 'DL-BWP-index'.

locationAndBandwidth : Frequency domain location and bandwidth of this bandwidth part. The value of the field shall be interpreted as resource indicator value (RIV). See here for the details

subcarrierSpacing : Subcarrier spacing to be used in this BWP for all channels and reference signals unless explicitly configured elsewhere. It corresponds to subcarrier spacing according to 38.211-Table 4.2-1. The value kHz15 corresponds to =0, kHz30 to =1, and so on. Only the values 15 or 30 kHz  (<6GHz), 60 or 120 kHz (>6GHz) are applicable.

How BWP are defined ?

As mentioned in Carrier Bandwidth Part allocation for DL and UL, maximum 4 BWPs can be defined in DL and UL. Each of BWP are configured by RRC messages as described in RRC Parameters for BandwidthPart Configuration.

That is the short answer. But 'defining a BWP' involves rather more than picking a start point and a width, and it is worth listing the whole set of decisions in one place, because they are spread over several different IEs in the ASN.1.

To define one bandwidth part, the network has to settle all of the following.

  • An identity - the bwp-Id. Values 1 to 4 for the dedicated ones ; 0 is reserved for the initial BWP and is assigned by the specification rather than signalled.
  • Where it sits and how wide it is - locationAndBandwidth, a single value that packs both numbers together. How that packing works is the subject of the next section.
  • Its numerology - subcarrierSpacing and cyclicPrefix. Remember that this is per BWP, so this is a real decision and not a formality.
  • Its cell specific channel configuration - the bwp-Common part. In the downlink that is PDCCH-ConfigCommon and PDSCH-ConfigCommon ; in the uplink it is RACH-ConfigCommon, PUSCH-ConfigCommon and PUCCH-ConfigCommon.
  • Its UE specific channel configuration - the bwp-Dedicated part. In the downlink that is PDCCH-Config (the CORESETs and search spaces), PDSCH-Config, SPS-Config and RadioLinkMonitoringConfig ; in the uplink it is PUCCH-Config, PUSCH-Config, ConfiguredGrantConfig, SRS-Config and BeamFailureRecoveryConfig.
  • What role it plays - whether some other field points at it as the first active or the default BWP. This is not part of the BWP itself, as explained in the BWP types section.

Look at how long that list is, and at what is on it. This leads to the point that is really worth taking away from this section :

    a BWP is not just a slice of spectrum. It is a complete, self contained radio configuration that happens to live on a slice of spectrum.

In NR, almost everything in the physical layer configuration is defined per BWP rather than per cell. Each BWP carries its own CORESETs, its own search spaces, its own DMRS and TCI configuration, its own PUCCH resources, its own SRS setup, its own configured grants. Two practical consequences follow, and both of them surprise people the first time.

  • Switching BWP does not only retune the radio - it swaps the whole physical layer configuration at the same time. That is the real reason a BWP switch costs a measurable amount of time rather than being instant, and it is why BWP switching delay deserves a section of its own.
  • When you look at an RRC configuration in a log, you will see PDSCH-Config, PUCCH-Config and friends appear once for every configured BWP. That is not the log repeating itself. Those are genuinely separate configurations, and they may well hold different values.

The network is not completely free when it makes these choices. The rules gathered from the earlier sections of this page are :

  • the BWP must be contiguous and must fit inside the carrier ;
  • a DL BWP must be at least as wide as the SS Block, although it does not have to contain one ;
  • every DL BWP needs at least one CORESET with a UE specific search space, and on the primary carrier at least one DL BWP must also carry a common search space ;
  • in TDD, a DL BWP and the UL BWP with the same bwp-Id form a pair and must share the same centre frequency.

When and where the definitions actually reach the UE

One more thing is worth knowing, because it explains why BWP #0 is special. The BWP definitions do not all arrive at once. They are built up in three steps as the UE works its way into the network.

  • Step 1 - from the MIB. Before the UE knows anything about bandwidth parts, it uses CORESET#0, whose frequency location comes from pdcch-ConfigSIB1 in the MIB. This is the first piece of downlink spectrum the UE can use at all, and strictly speaking it is not yet a BWP.
  • Step 2 - from SIB1. The common part of the initial BWP arrives here : initialDownlinkBWP (a BWP-DownlinkCommon) inside DownlinkConfigCommonSIB, and initialUplinkBWP (a BWP-UplinkCommon) inside UplinkConfigCommonSIB. 38.331 requires the network to choose the locationAndBandwidth of the initial DL BWP so that it contains the whole of CORESET#0. Note also a subtlety in the field description : the UE applies this locationAndBandwidth as soon as it reads it, but it keeps using CORESET#0 for PDCCH until RRCSetup, RRCResume or RRCReestablishment arrives.
  • Step 3 - from RRCSetup or RRCReconfiguration. Only now does ServingCellConfig appear, bringing the dedicated part of BWP #0 and, if the network wants them, the dedicated BWPs 1 to 4 with both their common and dedicated parts.

So the answer to "how are BWPs defined" is really a sequence rather than a single event. This is also the cleanest way to see why the initial BWP behaves differently from the others : BWP #0 is defined by the cell and is the same for everybody, while BWPs 1 to 4 are defined for one particular UE. A UE that has only read the broadcast information already has a working BWP #0 ; the other bandwidth parts do not exist for it until dedicated signalling creates them.

How BWP location and bandwidth is specified in RRC ?

The location (starting position and the bandwidth of a BWP is specified in RRC parameter called locationAndBandwidth and this parameter is specified as RIV that can be calculated according to the following specification.

< 38.213-12 Bandwidth part operation > states as follows :

    a first PRB and a number of contiguous PRBs by higher layer parameter locationAndBandwidth that is interpreted as RIV according to TS 38.214, setting , and the first PRB is a PRB offset relative to the PRB indicated by higher layer parameters offsetToCarrier and subcarrierSpacing

< 38.214-5.1.2.2.2 Downlink resource allocation type 1> defines RIV as follows :

Two questions come out of this formula almost immediately : why is the location and the bandwidth squeezed into one number instead of being sent as two separate fields, and why does the formula have two branches ? They have the same answer.

Think about which combinations of start and length are actually legal. A BWP must fit inside the carrier, so RB_start + L_RBs cannot be larger than the carrier. If the carrier has N resource blocks, then out of the N x N possible pairs only about half of them are valid - N(N+1)/2 to be exact. Sending two independent fields would therefore waste roughly one bit on combinations that can never occur. RIV is simply a way of numbering the valid pairs only, consecutively and with no gaps.

And that is where the two branches come from. The set of valid (start, length) pairs is triangular, not rectangular, because a long allocation cannot begin near the end of the carrier. Equation (1) numbers the short allocations in the obvious way. Equation (2) takes the long allocations and folds them into the space that the short ones left empty, by substituting the mirror image of the length (N - L + 1) and the mirror image of the start (N - 1 - RB_start). It is the same trick as cutting a triangle in half and flipping one half over so that the two halves fill a rectangle exactly.

The number 275, and where the ASN.1 range comes from

Now look again at the quote from 38.213 above. It does not say "use the size of this BWP" - it explicitly sets the N in the formula to 275, which is the largest number of resource blocks an NR carrier can have. This has two consequences that are worth being very clear about.

  • locationAndBandwidth is always computed with N = 275, whatever the real carrier bandwidth or subcarrier spacing happens to be. This is why every single line of the table below has 275 in it, even the 5 MHz cases.
  • It explains the odd looking range in the ASN.1. With N = 275 there are 275 x 276 / 2 = 37950 valid pairs, numbered 0 to 37949 - and INTEGER (0..37949) is exactly what the BWP IE says. That bound is not an arbitrary choice by somebody in 3GPP ; it is simply the count of legal combinations.

NOTE : The very same RIV formula is also used for the frequency domain resource assignment in DCI, but there it is evaluated with the actual size of the active BWP rather than with 275. Same arithmetic, different N. Mixing up the two is a classic source of wrong answers, so whenever you see an RIV, the first question to ask is which N it was built with.

Going the other way : RIV back to start and length

When you are reading a log you usually have the opposite problem - you have the locationAndBandwidth value and you want to know where the BWP is. The formula can be inverted in three lines. With N = 275 :

    L'       = floor(RIV / 275) + 1
    S'       = RIV mod 275

    if  L' + S' <= 275   ->   L_RBs = L'                RB_start = S'          (came from equation 1)
    else                 ->   L_RBs = 275 - L' + 2      RB_start = 275 - 1 - S' (came from equation 2)

The test in the middle is doing the un-folding. If the straightforward reading would produce an allocation that runs off the end of the carrier, then the value must have come from equation (2) and the mirror image has to be undone.

Two worked examples, using values from the table further down :

  • RIV = 2750 : L' = floor(2750/275) + 1 = 11, S' = 0. Since 11 + 0 is not larger than 275, this came from equation (1), so L_RBs = 11 and RB_start = 0. That is the 5 MHz row.
  • RIV = 3574 : L' = floor(3574/275) + 1 = 13, S' = 274. Now 13 + 274 = 287, which is larger than 275, so this one came from equation (2) : L_RBs = 275 - 13 + 2 = 264 and RB_start = 275 - 1 - 274 = 0. That is the 400 MHz FR2 row - and notice how a naive reading would have given you 13 resource blocks starting at 274, which is completely wrong.

Combining the two specification mentioned above, I would come up with some examples as shown below. All these examples are based on the assumption that RB_start = 0, BWP takes up the maximum RB for the specified channel bandwidth and subcarrierspacing = 30 Khz, FR1

CBW

max RB

Equation

RIV Calculation

locationAndBandwidth

5

11

(1)

275*(11-1)+0

2750

10

24

(1)

275*(24-1)+0

6325

15

38

(1)

275*(38-1)+0

10175

20

51

(1)

275*(51-1)+0

13750

25

65

(1)

275*(65-1)+0

17600

30

78

(1)

275*(78-1)+0

21175

40

106

(1)

275*(106-1)+0

28875

50

133

(1)

275*(133-1)+0

36300

60

162

(2)

275*(275-162+1)+(275-1-0)

31624

70

189

(2)

275*(275-189+1)+(275-1-0)

24199

80

217

(2)

275*(275-217+1)+(275-1-0)

16499

90

245

(2)

275*(275-245+1)+(275-1-0)

8799

100

273

(2)

275*(275-273+1)+(275-1-0)

1099

Following is the table that I calculated for subcarrier spacing  = 15 Khz  based on the assumption that RB_start = 0, BWP takes up the maximum RB for the specified channel bandwidth

CBW

max RB

Equation

RIV Calculation

locationAndBandwidth

5

25

(1)

275*(25-1)+0

6600

10

52

(1)

275*(52-1)+0

14025

15

79

(1)

275*(79-1)+0

21450

20

106

(1)

275*(106-1)+0

28875

25

133

(1)

275*(133-1)+0

36300

30

160

(2)

275*(275-160+1)+(275-1-0)

32174

40

216

(2)

275*(275-216+1)+(275-1-0)

16774

50

270

(2)

275*(275-270+1)+(275-1-0)

1924

Following is the table that I calculated for subcarrier spacing  = 120 Khz  based on the assumption that RB_start = 0, BWP takes up the maximum RB for the specified channel bandwidth

CBW

max RB

Equation

RIV Calculation

locationAndBandwidth

50

32

(1)

275*(32-1)+0

8525

100

66

(1)

275*(66-1)+0

17875

200

132

(1)

275*(132-1)+0

36025

400

264

(2)

275*(275-264+1)+(275-1-0)

3574

There is one thing in these tables that looks like a mistake on first reading, and it is worth pointing out because it is actually the folding at work. Follow the locationAndBandwidth column downwards in any of the tables. It rises as the channel bandwidth grows - 2750, 6325, 10175 and so on - and then, at the row where the Equation column flips from (1) to (2), it suddenly drops and keeps falling as the bandwidth continues to grow.

Nothing is wrong. The flip happens as soon as L_RBs - 1 becomes larger than floor(275/2) = 137, i.e, once the BWP occupies more than about half of the maximum carrier. From that point on the value is being written into the folded half of the numbering space, and it counts backwards. So :

    a bigger BWP does not mean a bigger locationAndBandwidth value.

If you are eyeballing a configuration and trying to guess the bandwidth from the size of the number, you will be wrong about half the time. Decode it properly with the three lines above.

One more trap : RB_start is not a CRB number

Look once more at the end of the sentence quoted from 38.213 at the top of this section : "the first PRB is a PRB offset relative to the PRB indicated by higher layer parameters offsetToCarrier and subcarrierSpacing".

This matters. The RB_start that comes out of the RIV is not counted from Point A. It is counted from the start of the carrier for that subcarrier spacing, and the carrier itself starts at an offset from Point A given by offsetToCarrier. So the position of the BWP in the common resource block grid is :

    N(start,BWP)   =   offsetToCarrier   +   RB_start

That N(start,BWP) is the same quantity used in the nCRB / nPRB mapping earlier on this page. If you take RB_start straight out of the RIV and use it as a CRB index, every frequency you calculate afterwards will be wrong by offsetToCarrier - and because offsetToCarrier is often not zero, this is a mistake that produces plausible looking but incorrect numbers.

A good habit when decoding a real configuration is therefore to finish with two sanity checks : that RB_start + L_RBs does not exceed the actual number of resource blocks in the carrier, and that the resulting BWP is at least as wide as the SS Block if it is a downlink BWP.

How a specific BWP is selected (BWP switching) ?

Even though multiple (max 4) BWPs can be defined in DL and UL, only one BWP can be active at each specific moment. It implies there is some mechainism to select a specific BWP as the active one. According to 38.321-5.15 Bandwidth Part (BWP) operation, BWP selection (or BWP switching) can be done by several different way

s as listed below.

  • By PDCCH (i.e, DCI) : A specific BWP can be activated by Bandwidth part indicator in DCI Format 0_1 (a UL Grant) and DCI Format 1_1 (a DL Schedule)
  • By the bwp-InactivityTimer : ServingCellConfig.bwp-InactivityTimer
  • By RRC signalling
  • By the MAC entity itself upon initiation of Random Access procedure  

NOTE : In the current version of 38.321 (5.15.1) the same sentence has one more trigger in it - the MAC entity also switches BWP upon detection of consistent LBT failure on the SpCell. That one came in with Release 16 and only applies to operation in shared spectrum.

These four (or five) mechanisms look like alternatives, but they are not really interchangeable. They differ in who starts them, in how fast they are, and in what they are for. Putting them side by side makes the picture much clearer.

Mechanism

Who decides

How fast

What it is really for

DCI (PDCCH)

Network

Fastest

The normal, everyday way. The scheduler decides that this UE now needs a wider (or narrower) BWP and says so in the same DCI that schedules the data. This is the one that makes BWP a dynamic feature rather than a configuration option.

bwp-InactivityTimer

UE (autonomously)

Fast

Power saving. Nobody sends anything ; the UE notices that nothing has happened for a while and falls back to the default BWP on its own. The network runs the same timer, so both sides stay in step without any signalling.

RRC signalling

Network

Slow

Used when the BWP set itself is being (re)configured - at cell addition, handover, or reconfiguration with sync. firstActiveDownlinkBWP-Id / firstActiveUplinkBWP-Id say which BWP is active once the new configuration is applied, and 38.321 states this happens without any PDCCH being received.

MAC, on Random Access

UE (autonomously)

Fast

A safety mechanism rather than an optimisation. If the UE has to do random access but the active UL BWP has no PRACH occasions in it, the UE cannot even start - so it moves itself somewhere it can. This is Case 1 below.

Two things are worth noticing in that table.

  • Two of the four are UE decisions. BWP switching is not purely network controlled. The UE moves itself on inactivity and on random access, which is why both sides have to implement exactly the same rules - if they disagree about which BWP is active, the UE is listening in one place while the network transmits in another, and the connection is effectively dead until something resets it.
  • The DCI that switches the BWP is usually also a scheduling DCI. The bandwidth part indicator lives inside DCI format 0_1 and 1_1, which are the formats that grant uplink and schedule downlink. So the switch is not a separate command - the network says "move to BWP 2, and by the way here is your data on BWP 2" in one shot. The frequency domain resource assignment in that same DCI is already interpreted against the new BWP.

 

With using the mechanisums listed above, a specific BWP become active depending on various situations in the call processing.The switching process can be summarized in illustration as follows. 

 

Reading this timeline from left to right, it walks through the whole life of a connection and shows which mechanism is in charge at each point.

  • The UE starts in the Initial BWP, because that is all it has - the dedicated BWPs do not exist for it yet.
  • When the initial attach completes, RRC has arrived, and the UE jumps to the First Active BWP. Notice there is no arrow labelled DCI at that point : this move comes from firstActiveDownlinkBWP-Id in the configuration itself.
  • Then comes the ordinary working phase - the run of green dashed lines marked DCI or RRC. The UE is moved between BWP n1 and BWP n2 as the scheduler sees fit, and this can happen many times.
  • Finally the traffic stops, nothing more is scheduled, and the bwp-InactivityTimer expires. No message is sent at all - the UE simply drops to the Default BWP by itself.

The vertical axis is worth a glance too : the boxes are drawn at different widths and different positions, which is a reminder that the BWPs need not be the same size and need not sit on top of each other.

 

Another well presented illustration of BWP change/adaptation is shown below :

 

Source : A Primer on Bandwidth Parts in 5G New Radio

This second illustration tells the same story but with real resource block counts, and it adds the part that happens before RRC connection - which is where the earlier picture starts.

  • Sync and MIB - the UE has only the SSB, 20 RBs wide. There is no BWP yet.
  • Acquire SIB1 - the UE uses CORESET#0, 24 RBs, whose position came from the MIB.
  • Random access - now the initial BWPs exist, taken from SIB1. In this example both DL BWP#0 and UL BWP#0 are 24 RBs, i.e, the initial DL BWP has been made exactly big enough to contain CORESET#0, which is what 38.331 requires.
  • RRC configuration applied - the UE moves to the first active BWPs, and here they are 270 RBs. This is the jump that matters : from 24 RBs to 270 RBs, more than ten times the bandwidth, in one step.
  • Inactivity timer expiry - the DL falls back to the default BWP, 52 RBs. Notice that the uplink does not move : it stays on UL BWP#1. This is the downlink only nature of the default BWP that was mentioned in the BWP types section, drawn out.

The numbers in this figure are a good illustration of why the feature exists at all. A UE that has nothing to do sits in 52 RBs rather than 270, and a UE that is only doing random access sits in 24. The receiver only has to be wide enough for the BWP it is actually in.

The bwp-InactivityTimer in a little more detail

Of the four mechanisms, the inactivity timer is the one that is easiest to list and hardest to picture, so it is worth spelling out how it actually behaves. The rules are in 38.321-5.15.1.

  • The timer does not always run. It only runs while the active DL BWP is not the default one. That makes sense - the timer exists to bring the UE back to the default BWP, so once it is there, there is nothing left to do. If defaultDownlinkBWP-Id was never configured, the initial BWP takes its place, and the timer runs whenever the UE is not on the initial BWP.
  • Activity restarts it. Receiving a PDCCH addressed to C-RNTI or CS-RNTI that carries a downlink assignment or an uplink grant restarts the timer, and so does sending or receiving a MAC PDU on a configured grant or configured assignment. In other words, any real scheduling activity keeps the UE where it is.
  • Random access suspends the logic. While a random access procedure is going on, the timer is not restarted by these events - only once the procedure has finished (or if there was none in the first place).
  • On expiry the UE switches by itself to the BWP given by defaultDownlinkBWP-Id, or to the initial BWP if that field is absent.
  • Being moved by a DCI also starts it. When a PDCCH switches the UE to a BWP that is not the default one, the timer is started or restarted at that moment - so the countdown begins as soon as the UE arrives.

NOTE : Because both the UE and the network run this timer independently and neither of them signals anything when it fires, the timer value is one of those parameters where a configuration mistake is punished harshly. The timing of the switch itself is a separate matter and is covered in BWP Switching Delay below.

NOTE : Release 16 added one more kind of BWP switching that is not in the list above - the dormant BWP, configured for an SCell with dormantBWP-Id. A UE moved into the dormant BWP of an SCell stops monitoring PDCCH there but keeps reporting CSI, so the SCell can be woken up again quickly without a full activation. Entering and leaving it is done by PDCCH, and 38.321 states the dormant BWP is not supported for an SpCell or for a PUCCH SCell.

Followings are some of the examples of BWP switching for specific cases based on the statement in 3GPP specification. If you have overall understanding as shown above, following description would sound clearer to you.

 

Case 1 :  Upon initiation of the Random Access procedure on a Serving Cell (based on 38.321 - 5.15)

    if PRACH occasions are not configured for the active UL BWP:

       For UL,set the active UL BWP = initialUplinkBWP;

       For DL,

             if the Serving Cell is a SpCell:

                set the active DL BWP = initialDownlinkBWP.

     

    if PRACH occasions are configured for the active UL BWP

       For UL,set the active UL BWP = the configured UL BWP

       For DL,

             if the Serving Cell is a SpCell:

                set the active DL BWP = DL BWP with the same bwp-Id as the active UL BWP.

     

    Perform RACH procedure with the active BWP selected as above.

     

NOTE : What if initialDownlinkBWP is not configured ? According to 38.213-12 Bandwidth part operation, it is stated as follows.

    an initial DL BWP is defined by a location and number of contiguous PRBs, starting from a PRB with the lowest index and ending at a PRB with the highest index among PRBs of a CORESET for Type0-PDCCH CSS set, and a SCS and a cyclic prefix for PDCCH reception in the CORESET for Type0-PDCCH CSS set ==> It mean that the initialDlBWP takes up the full RBs defined in FrequencyInfoDL (i.e, Full RB in the CBW)

 

Case 2 :  RrcReconfiguration /with sync (based on 38.331 - 5.3.5.5.2)   

    "Reconfiguration with sync" is a common mechanism of activing NR cell in NSA (i.e, Adding NR Cell to LTE cell). In this case, Active BWP for DL and UL is set to be as follows .

    • Active BWP for DL = firstActiveDownlinkBWP-Id
    • Active BWP for UL = firstActiveUplinkBWP-Id

 

Case 3 : DCI with Bandwidth part indicator is recieved

    Check if there is any on-going RACH procedure. If there is no on-going RACH procedure or RACH procedure is just completed by the received DCI (masked with C-RNTI).

      set the active BWP = the BWP specified by the DCI

 

NOTE : BWP-id for DL / UL in TDD (unpared spectrum). 38.213-12 Bandwidth part operation states as follows.

    For unpaired spectrum operation, a DL BWP from the set of configured DL BWPs with index provided by BWP-Id is linked with an UL BWP from the set of configured UL BWPs with index provided by BWP-Id when the DL BWP index and the UL BWP index are same. ==> Simply put, DL BWP id = UL BWP id

 

NOTE : Center Frequency of DL/UL BWP in TDD(unpared spectrum)

    For unpaired spectrum operation, a UE does not expect to receive a configuration where the center frequency for a DL BWP is different than the center frequency for an UL BWP when the BWP-Id of the DL BWP is same as the BWP-Id of the UL BWP ==> Simply put, Center frequency of DL BWP  = Center Frequency of UL BWP

BWP Switching Delay

Changing BWP (Switching BWP) is the process of changing huge set of configurations. So it would need at least a certain amount of time to complete the switching. This time delay can be illustrated as follows based on 38.133-8.6.2

It is worth being clear about why there is a delay, because it is not one single thing. Two quite different jobs have to finish before the UE can work on the new bandwidth part.

  • The radio has to be retuned. The new BWP is somewhere else in frequency and may use a different subcarrier spacing, so the RF front end has to move and settle. This is analogue hardware behaviour and it does not care how fast the digital clock is running.
  • The whole physical layer configuration has to be swapped. As described in How BWP are defined, a BWP carries its own CORESETs, search spaces, PUCCH resources, SRS setup and so on. All of that has to be torn down and rebuilt.

Two properties of this delay are worth remembering before looking at the diagrams.

  • It is normative, not implementation defined. 38.133 does not describe what a UE typically takes ; it sets an upper bound that the UE must meet. The value depends on the UE's own declared capability, which is why the tables have two columns.
  • The UE is deaf and mute while it lasts. 38.133 states that during T(BWPswitchDelay) the UE is not required to transmit uplink signals or receive downlink signals on the cell where the switch is happening. So this is not a soft transition - it is a real hole in the service, and that is exactly why a network cannot switch BWP casually.

Time Delay for DCI based BWP switching

This is the case where the switch was ordered by a PDCCH, i.e, by the bandwidth part indicator inside DCI format 1_1 or 0_1, as described in How a specific BWP is selected. It is by far the most common case in normal operation, so this is the delay that a scheduler has to live with every day.

The question that 38.133 has to answer here is narrower than it first looks. It is not "how long does a UE take to switch" in general - it is from exactly which moment does the clock start, and from exactly which slot may the new BWP be used. Both sides need the same answer down to the slot, because the network will begin transmitting on the new BWP the instant it believes the UE is ready. If the two disagree by even one slot, the network transmits into a UE that is still retuning and the transmission is simply lost.

There is also a scheduling consequence that is specific to the DCI case and does not arise with the timer. Remember that the DCI which switches the BWP is normally a scheduling DCI as well - it carries a downlink assignment or an uplink grant at the same time. But that assignment refers to the new BWP, and the UE cannot receive or transmit anything there until the switch has finished. So the network has to push the scheduled transmission far enough into the future, through the K0 or K2 timing value in the same DCI, that it lands after the switching delay has elapsed. In other words the delay below is not just a gap in service - it also sets a floor on how soon the first transmission on the new BWP can be scheduled.

Reading the timeline at the top of this figure :

  • The clock starts at the beginning of the DL slot in which the DCI is received - 38.133 calls it slot n. Note that it is the start of the slot, not the end of the DCI, so part of the budget is already gone by the time the UE has finished decoding the PDCCH.
  • After T(BWPswitchDelay) has elapsed, the UE must be able to receive PDSCH or transmit PUSCH on the new BWP, starting from the first DL or UL slot that occurs after the duration.
  • The one exception to the silence is the DCI itself : the UE is of course still receiving the PDCCH that ordered the switch.

The little Y at the left of the figure is an extra slot that is added only in one situation, and the two bullet points underneath the table explain when :

  • Y = 0 when the DCI arrives on the same serving cell as the one whose BWP is changing. This is the ordinary case.
  • Y = 1 when the DCI arrives on a different serving cell from the one that is switching, i.e, with cross carrier scheduling. The UE is granted one more slot, which is fair enough - the instruction has to cross from one carrier's processing chain to another's. In this case the specification also says that T(BWPswitchDelay) + Y follows the smaller SCS among the scheduling cell and the scheduled cells before and after the change.

NOTE : 38.133 adds a caveat that is easy to miss. The UE is not required to meet these requirements at all when the DCI based switch is between BWPs that lie in disjoint channel bandwidths, or in only partially overlapping ones. In other words, the guaranteed switching time assumes the two BWPs are reasonably close together. A configuration that makes the UE jump across the band is outside what the requirement covers.

Time Delay for Timer based BWP switching

This is the other case - the switch was not ordered by anybody. The bwp-InactivityTimer simply ran out, and the UE goes back to the default BWP on its own.

The interesting thing about this case is that no message is exchanged at all. In the DCI case there is a PDCCH that both sides can point at, so the reference point for the timing is obvious : the slot that carried the DCI. Here there is nothing to point at. The UE decides to switch because a timer expired inside it, and the network decides that the UE has switched because an identical timer expired inside the network. Nothing crosses the air interface to confirm it.

That is why the specification has to define the starting point differently, and rather more carefully. It cannot say "start counting from the slot with the DCI", so instead it says start counting from the next frame structure boundary after the timer expires. A boundary is something both sides can compute independently and agree on without talking, which is exactly what is needed here. Which boundary it is depends on the frequency range, and that is what the two coloured boxes in the illustration below are showing.

Once that starting slot has been established, everything from there on is identical to the DCI case - the same T(BWPswitchDelay) from the same Table 8.6.2-1, and the same silence while it lasts.

The timer case is almost the same, with one extra step at the front that explains the two coloured boxes marked FR1 and FR2 in the figure.

When the bwp-InactivityTimer expires, the UE does not start switching at that instant. It waits for the next boundary, and which boundary depends on the frequency range :

  • in FR1, slot n is the first slot of the DL subframe immediately after the timer expires - the green box labelled 'First slot' ;
  • in FR2, slot n is the first slot of the DL half subframe immediately after the timer expires - the blue box labelled 'First half subframe'.

From that slot n onwards, exactly the same T(BWPswitchDelay) applies as in the DCI case, and the UE is again neither transmitting nor receiving until it is over. So the total time from timer expiry to being usable again is a little longer than the table value alone : there is a short alignment wait first, then the switch itself.

Reading Table 8.6.2-1

Both figures quote the same table, so it is worth reading it once properly.

The two columns, Type 1 and Type 2, are not two kinds of switch - they are two kinds of UE. Which column applies depends on what the UE declared in its bwp-SwitchingDelay capability, which is covered in the UE Capability section below. Type 1 is the faster class ; Type 2 is roughly three times slower.

The table is written in slots, and that hides something interesting. If you convert the slot counts into milliseconds using the slot length in the same table, this is what comes out :

μ

SCS

Slot length

Type 1 (slots)

Type 1 in ms

Type 2 (slots)

Type 2 in ms

0

15 kHz

1 ms

1

1 ms

3

3 ms

1

30 kHz

0.5 ms

2

1 ms

5

2.5 ms

2

60 kHz

0.25 ms

3

0.75 ms

9

2.25 ms

3

120 kHz

0.125 ms

6

0.75 ms

18

2.25 ms

Look down the two 'in ms' columns. The slot counts grow steeply - 1, 2, 3, 6 and 3, 5, 9, 18 - but the actual time barely moves : roughly 1 ms or less for a Type 1 UE and around 2 to 3 ms for a Type 2 UE, whatever the numerology.

That is not a coincidence, and it is the most useful thing to take away from this table. The switching delay is fundamentally a hardware time - how long the synthesiser needs to settle and the configuration needs to be reloaded - and hardware does not get faster just because the subcarrier spacing went up. The slot count has to grow simply because the slots themselves got shorter. So do not read '18 slots' at 120 kHz as being dramatically worse than '3 slots' at 15 kHz ; in wall clock terms it is actually slightly better.

NOTE : Note 2 under the table covers the case where the switch also changes the subcarrier spacing. The delay is then determined by the smaller of the two SCS values, i.e, by the one with the longer slot - the pessimistic choice.

Two practical consequences follow from all of this.

  • The bwp-InactivityTimer should not be set too short. If it expires while traffic is still arriving in bursts, the UE keeps falling back to the default BWP and being pulled out again, and it pays the switching gap every single time. A timer that is slightly too aggressive can cost more throughput than the power saving is worth.
  • BWP switching and tight latency budgets do not mix well. A gap of 2 to 3 ms is very large next to a URLLC packet delay budget of a few milliseconds. This is one of the practical reasons why latency critical traffic tends to be kept on one BWP rather than being moved around.

RRC for BWP Switching

The RRC Parameters for BandwidthPart Configuration section listed everything needed to define a bandwidth part. This short section pulls out the handful of fields that decide the switching behaviour instead - not what a BWP is, but which one is used and when the UE moves between them.

There are only four of them, and each one answers a different question.

  • firstActiveDownlinkBWP-Id / firstActiveUplinkBWP-Id - "which BWP is active the moment this configuration is applied ?" This is the RRC based switch. Note that the uplink field lives inside UplinkConfig, not directly in ServingCellConfig, which is why the two are shown separately below.
  • bwp-InactivityTimer - "how long may nothing happen before the UE goes home by itself ?" This is the timer based switch.
  • defaultDownlinkBWP-Id - "where is home ?" The two work as a pair : the timer decides when, this field decides where. There is deliberately no uplink equivalent.

Notice what is not in this list. There is no RRC field for the DCI based switch, because that one is not configured at all - it is carried in the bandwidth part indicator of the DCI at the moment it is needed. And there is no field for the random access based switch either, since that behaviour is fixed by 38.321 rather than configured. So of the four switching mechanisms, only two have any RRC parameter behind them.

Following is based on 38.331 v19.2.0 (Release 19)

ServingCellConfig ::=               SEQUENCE {
    ...
    firstActiveDownlinkBWP-Id           BWP-Id                                                     OPTIONAL,   -- Cond SyncAndCellAdd
    bwp-InactivityTimer                 ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30,
                                                    ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500,
                                                    ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8,
                                                    spare7, spare6, spare5, spare4, spare3, spare2, spare1 }
                                                                                               OPTIONAL,   -- Need R
    defaultDownlinkBWP-Id               BWP-Id                                                     OPTIONAL,   -- Need S
    uplinkConfig                        UplinkConfig                                               OPTIONAL,   -- Need M
    ...,
    [[
    dormantBWP-Config-r16               SetupRelease { DormantBWP-Config-r16 }                 OPTIONAL,   -- Need M
    ...
    ]]
}

UplinkConfig ::=                    SEQUENCE {
    ...
    firstActiveUplinkBWP-Id             BWP-Id                                                     OPTIONAL,   -- Cond SyncAndCellAdd
    ...
}

DormantBWP-Config-r16 ::=          SEQUENCE {
    dormantBWP-Id-r16                      BWP-Id                                                  OPTIONAL,   -- Need M
    withinActiveTimeConfig-r16             SetupRelease { WithinActiveTimeConfig-r16 }             OPTIONAL,   -- Need M
    outsideActiveTimeConfig-r16            SetupRelease { OutsideActiveTimeConfig-r16 }            OPTIONAL    -- Need M
}

WithinActiveTimeConfig-r16 ::=         SEQUENCE {
   firstWithinActiveTimeBWP-Id-r16         BWP-Id                                                  OPTIONAL,   -- Need M
   dormancyGroupWithinActiveTime-r16       DormancyGroupID-r16                                     OPTIONAL    -- Need R
}

OutsideActiveTimeConfig-r16 ::=        SEQUENCE {
   firstOutsideActiveTimeBWP-Id-r16        BWP-Id                                                  OPTIONAL,   -- Need M
   dormancyGroupOutsideActiveTime-r16      DormancyGroupID-r16                                     OPTIONAL    -- Need R
}

DormancyGroupID-r16 ::=                INTEGER (0..4)

NOTE : Two things changed since the earlier version of this listing. The condition on the two firstActive fields is now Cond SyncAndCellAdd, and defaultDownlinkBWP-Id is marked Need S rather than Need M - which is the formal way of saying "if this field is absent, read the field description", and the field description is the one that tells you the initial BWP becomes the default. The bwp-InactivityTimer value list itself is unchanged.

The DormantBWP-Config-r16 block at the bottom is the Release 16 addition mentioned earlier. It is worth a quick look because it shows that dormancy is more than a single BWP id :

  • dormantBWP-Id-r16 is the BWP the SCell is put into when it is told to go dormant.
  • firstWithinActiveTimeBWP-Id-r16 and firstOutsideActiveTimeBWP-Id-r16 say which BWP to wake up into, and there are two of them because the answer differs depending on whether the UE is inside DRX Active Time or not.
  • DormancyGroupID-r16 lets several SCells be put to sleep and woken up together with one instruction, rather than one at a time.

Note also that this whole block sits in ServingCellConfig, which means it is per serving cell - and as 38.321 states, dormancy is not supported for an SpCell or for a PUCCH SCell.

UE Capability

Everything on this page so far has described what the specification allows. This section is about what a particular UE is actually willing to do, because BWP is not a single feature that a UE either supports or does not support. It is a set of graded capabilities, and a network has to read them before it configures anything.

The capabilities sit at two different levels, and the level tells you the scope :

  • Phy-ParametersCommon - these apply to the whole UE. This is where the switching speed is declared.
  • BandNR - these are declared per band. The same UE can therefore support four BWPs on one band and only two on another, which is entirely normal, because the hardware behind different bands is often different.

Between them, the fields below answer three separate questions.

  • How many BWPs, and may they differ in numerology ? - bwp-SameNumerology and bwp-DiffNumerology. Notice that supporting 4 BWPs and supporting 4 BWPs with different subcarrier spacings are two separate declarations. The second one is considerably harder for a UE, since it means the whole frame structure changes at the switch.
  • How fast can it switch ? - bwp-SwitchingDelay, which selects the Type 1 or Type 2 column of the table in the BWP Switching Delay section, plus the Release 16 fields that cover switching several carriers at once.
  • Must the BWP contain CORESET#0 and SSB ? - bwp-WithoutRestriction. Without this capability the network is not free to place a DL BWP anywhere it likes on the PCell.

The last one is worth pausing on, because it is the capability that most directly limits what a network can do in practice. A UE that does not report bwp-WithoutRestriction forces every UE specific DL BWP on the PCell to be wide enough to swallow CORESET#0 and the SSB - which quietly puts a floor under how narrow the power saving BWP can be.

Following is based on 38.331 v19.2.0 (Release 19)

Phy-ParametersCommon ::=            SEQUENCE {
    ...
    bwp-SwitchingDelay                  ENUMERATED {type1, type2}                   OPTIONAL,
    ...,
    [[
    -- R4 9-1: BWP switching on multiple CCs RRM requirements
    bwp-SwitchingMultiCCs-r16           CHOICE {
        type1-r16                           ENUMERATED {us100, us200},
        type2-r16                           ENUMERATED {us200, us400, us800, us1000}
    }                                                                               OPTIONAL
    ]],
    [[
    -- R4 6-3: Dormant BWP switching on multiple CCs RRM requirements
    bwp-SwitchingMultiDormancyCCs-r16   CHOICE {
        type1-r16                           ENUMERATED {us100, us200},
        type2-r16                           ENUMERATED {us200, us400, us800, us1000}
    }                                                                               OPTIONAL
    ]],
    ...
}

BandNR ::=                          SEQUENCE {
    ...
    bwp-WithoutRestriction              ENUMERATED {supported}                          OPTIONAL,
    bwp-SameNumerology                  ENUMERATED {upto2, upto4}                       OPTIONAL,
    bwp-DiffNumerology                  ENUMERATED {upto4}                              OPTIONAL,
    ...
}

NOTE : Compared with the earlier version of this listing, the ASN.1 of the four original fields is unchanged - what has been added is the second Release 16 group, bwp-SwitchingMultiDormancyCCs-r16, which is the dormancy counterpart of bwp-SwitchingMultiCCs-r16.

bwp-SwitchingMultiCCs-r16 : (According to 38.306) Indicates whether the UE supports an incremental delay for DCI and timer based active BWP switching on several carriers at the same time. type1-r16 gives the extra delay for a Type 1 UE and has the values 100us or 200us ; type2-r16 gives it for a Type 2 UE with the values 200us, 400us, 800us or 1000us. A UE reporting this feature must also support bwp-SwitchingDelay together with bwp-SameNumerology and/or bwp-DiffNumerology.

The word to notice there is incremental. This is not a replacement for the table in the switching delay section - it is an addition to it, paid once for the fact that more than one carrier is being switched at the same moment. So switching four carriers together is not four times the cost of switching one.

bwp-SwitchingMultiDormancyCCs-r16 : (According to 38.306) The same idea as above, but for dormant BWP switching - the incremental delay when several SCells are put into or taken out of their dormant BWP by a single instruction. The value ranges are identical. This is the capability behind the dormancy groups described in the RRC for BWP Switching section.

NOTE : The four descriptions below were written against an earlier version of 38.306. Three points have been added to the specification since then and they are worth knowing :

  • An uplink / downlink constraint that is not stated anywhere else on this page. The current text of both bwp-SameNumerology and bwp-DiffNumerology says : "Except for SUL, the UE only supports the same numerology for the active UL and DL BWP". So although each BWP carries its own subcarrier spacing, in practice the active DL BWP and the active UL BWP of a serving cell have to use the same one - the supplementary uplink being the only exception.
  • The reporting rule for bwp-SwitchingDelay is now conditional. It reads "It is mandatory to report type 1 or type 2 when bwp-SameNumerology or bwp-DiffNumerology is supported on at least one band", and it adds that the capability is optional for an NCR-MT. The older wording made the report unconditional.
  • RedCap changes the CORESET#0 rule. For a UE that reports supportOfRedCap-r17 or supportOfERedCap-r18, the UE specific DL BWP may not include the bandwidth of CORESET#0 and the SSB on the PCell - which is the opposite of the rule quoted in the descriptions below, and it exists precisely because a RedCap UE may be too narrowband to contain them.

bwp-SameNumerology : Indicates whether UE supports BWP adaptation (up to 2/4 BWPs) with the same numerology, via DCI and timer. For the UE capable of this feature, the bandwidth of a UE-specific RRC configured DL BWP includes the bandwidth of the CORESET#0 (if CORESET#0 is present) and SSB for PCell and PSCell (if configured). For SCell(s), the bandwidth of the UE-specific RRC configured DL BWP includes SSB, if there is SSB on SCell(s).

bwp-DiffNumerology : Indicates whether the UE supports BWP adaptation up to 4 BWPs with the different numerologies, via DCI and timer. For the UE capable of this feature, the bandwidth of a UE-specific RRC configured DL BWP includes the bandwidth of the CORESET#0 (if CORESET#0 is present) and SSB for PCell and PSCell (if configured). For SCell(s), the bandwidth of the UE-specific RRC configured DL BWP includes SSB, if there is SSB on SCell(s).

bwp-SwitchingDelay :  (According to 38.306) Defines whether the UE supports DCI and timer based active BWP switching delay type1 or type2 specified in clause 8.6.2 of TS 38.133. It is mandatory to report type 1 or type 2. This capability is not applicable to IAB-MT. See BWP Switching Delay section in this page for further details.

bwp-WithoutRestriction : (According to 38.306) Indicates support of BWP operation without bandwidth restriction. The Bandwidth restriction in terms of DL BWP for PCell and PSCell means that the bandwidth of a UE-specific RRC configured DL BWP may not include the bandwidth of CORESET #0 (if configured) and SSB. For SCell(s), it means that the bandwidth of DL BWP may not include SSB.

Why BWP ?

When I first saw the descriptions on BWP, I asked myself 'why we need this ? We already has pretty flexible mechanism of changing Bandwidth dynamically. Just by changing the number of RBs and starting RB, we can change the operation bandwidth. Then, why we still need another mechanism of restricting bandwidth ?'.

The purpose of BWP is more for UE rather than for Network, especially for low end UEs which cannot afford to such a wideband operation.

In most case, NR would operate in very wideband and there wouldn't be any issues for the network (gNB) and high end UEs to handle the full operating band, but we cannot expect every types of UE to be able to work with this kind of wideband. So we need another special mechanism to tell some UEs 'Hey... we are operating in this wide band, but you don't need to worry about covering the full band. this is a fraction of spectrum you only need to care'. This is how (and why) we came out with the new concept called BWP. It would remind you of NarrowBand in LTE M1. (Refer to Ref[1] if you want to know more detailed stories on various alternatives on NR Wideband operation).

Coming back to the question at the top

The question asked at the start of this section is a good one and it deserves a direct answer, because at first sight resource allocation really does look as if it already does the job. If the scheduler can give a UE 10 resource blocks out of 273, has it not already narrowed the bandwidth ?

No - and the reason is the single most important idea behind the whole feature :

    scheduling a UE narrowly is not the same as letting the UE operate narrowly.

Think about what a UE has to do when it is only ever scheduled on 10 resource blocks but the carrier is 100 MHz wide. It still has to keep its receiver open across the whole carrier, because :

  • it has no idea where the next grant will be - the scheduler is free to move it anywhere in the carrier from one slot to the next ;
  • it has to monitor PDCCH wherever the CORESET happens to sit ;
  • and the parts of the receive chain that actually cost power - the wideband analogue front end, the ADC sample rate, the FFT - are sized by the bandwidth the UE is prepared to receive, not by the bandwidth it happens to be given in one particular slot.

So a narrow allocation saves the network some resource blocks, but it saves the UE almost nothing. The UE is still paying the full price for a wideband receiver that is mostly idle.

What BWP adds is not a new way of allocating resources. It adds a standing promise. Configuring and activating a BWP is the network saying "for as long as this BWP is active, nothing at all will be sent to you outside this region - not data, not control, not reference signals". That is a promise the UE can actually act on, because it is valid over a period of time rather than for a single slot. Only then can the UE genuinely narrow its front end and turn its power consumption down.

This also explains a rule from much earlier on this page that can look like arbitrary bookkeeping - that the UE neither receives nor transmits anything outside the active BWP. Read as a restriction it seems pointless. Read as the promise that makes the narrowing possible, it is the whole point.

The full set of reasons

The low end UE argument above is the original motivation and it is still the clearest one, but by the time the feature was finished it was serving several purposes at once. In practice there are four.

Reason

What it means, and which part of the feature serves it

UE power saving

The dominant reason in real deployments. A UE with nothing to do sits in a narrow BWP and only opens up when there is traffic. This is what the default BWP and the bwp-InactivityTimer exist for - they have no other purpose.

UEs that cannot do wideband

The argument made above. A device whose maximum bandwidth is smaller than the carrier can still camp on that carrier and be served properly. This is what later became the basis of RedCap, and it is why the bwp-WithoutRestriction capability matters.

Different services on one carrier

Because each BWP carries its own numerology, moving a UE between BWPs can change the whole frame structure it works with. A carrier can therefore serve traffic that wants 15 kHz and traffic that wants 120 kHz without being split into separate carriers.

Moving UEs around inside the carrier

The network can steer UEs into a particular part of the band - to keep a region clear, to work around interference, or in shared spectrum to fit around what else is going on. This one is a genuine network side benefit rather than a UE one.

It is worth adding a word about the network side, because the section above says the purpose is more for the UE than for the network - which is true from the radio point of view but understates the deployment argument. Without BWP, an operator who wanted to serve narrowband devices on a wide carrier would have to deploy a separate narrow carrier for them. BWP means one wide carrier can serve everything, from a 100 MHz eMBB handset to a sensor that can only manage a few megahertz. That is a real saving in spectrum and in equipment, and it is not a UE benefit at all.

How this compares with LTE

The comparison with LTE-M NarrowBand made above is a good one, and the differences are instructive :

  • the LTE-M narrowband is fixed at 6 PRBs and hard-wired into the design, whereas a BWP is configurable in position, in size and in numerology ;
  • the LTE-M narrowband exists only for a specific low cost device category, whereas BWP applies to every NR UE including the most capable ones ;
  • and for an ordinary LTE UE there was no bandwidth adaptation at all - the UE simply had to handle the full cell bandwidth, all the time, whatever it was doing.

That last point is the real change. In LTE, cell bandwidth was something the UE had to cope with. In NR, the bandwidth a UE works in became something the network can adjust on the fly, per UE, in milliseconds.

NOTE : It is only fair to end with a reality check. The amount of specification devoted to BWP is much larger than the amount of BWP switching you will find in a live network. As mentioned in the BWP types section, many commercial deployments configure only BWP #0, or BWP #0 plus a single dedicated BWP, and never switch between them at all. The power saving competes with mechanisms that are cheaper to use, such as DRX and cross slot scheduling, and every switch costs the gap described in BWP Switching Delay. The feature matters most where the alternative does not exist - narrowband devices on wide carriers, and mixed numerology deployments.

BWP Configuration Examples

Everything up to this point has been definitions, formulas and ASN.1. This section is where it turns into something you can actually look at - real configurations taken from a running system, with real numbers in them.

These examples are worth more than they look, because a single configuration quietly touches almost every section of this page at once. When you open one, it is a good habit to walk through it in the following order rather than reading it top to bottom.

  • First find the carrier. Look for absoluteFrequencyPointA, offsetToCarrier and carrierBandwidth in scs-SpecificCarrierList. These tell you where the resource block grid begins and how many resource blocks the carrier has. Nothing else can be interpreted until you have these, because everything is measured from Point A.
  • Then decode the BWP. Take locationAndBandwidth and run it through the three lines in the RIV section. That gives you RB_start and the number of resource blocks. Remember that RB_start is relative to offsetToCarrier, not to Point A.
  • Check the numerology. The subcarrierSpacing next to it decides how wide a resource block actually is, so it is what turns a count of resource blocks into megahertz.
  • Then look at what has to fit inside. The CORESET and the SSB both live in the initial DL BWP, so their positions and widths are the constraint that the BWP had to be built around.

A good self test with any of these examples is to decode locationAndBandwidth by hand before reading the annotations, and then check whether your answer matches the resource block count that the channel bandwidth and subcarrier spacing imply. If the two agree, you have understood the RIV section properly. You should also find your value sitting in one of the rows of the table of worked RIV examples earlier on this page, since those rows cover exactly the case of a BWP filling the whole carrier.

It is also worth noticing what these examples tend to show about real networks, which is the point made at the end of the Why BWP section. Most of them configure the initial BWP and little else. The four BWP configurations with active switching between them, which take up most of the specification, are far less common in the field than the amount of text devoted to them would suggest.

Example 01 > Band78, CBW 20 Mhz

Following is an example configuration from Amarisoft. (NOTE : You may need additional knowledge about Coreset Bandwidth. Refer to this note for CORESET interpretation)

NOTE : CBW = 20 is just based on the Bandwidth specification : 38.101-1 Table 5.3.2-1: Maximum transmission bandwidth configuration NRB : FR1 . The physical bandwidth accupied by 51RB is 18.36 Mhz.

Let me now walk through this configuration in the order suggested at the top of this section, because every highlighted field in the listing can be turned into a number, and all of those numbers can be checked against each other.

Step 1 : where is the carrier ?

Three fields answer this, and they have to be read together.

  • absoluteFrequencyPointA = 632016. This is an NR-ARFCN, and it marks the absolute position of Common RB 0. Band 78 sits in the 3000 to 24250 MHz range, where the conversion is F = 3000 MHz + 15 kHz x (N - 600000). So 3000 + 0.015 x (632016 - 600000) = 3480.24 MHz, which is the value written next to Point A in the picture.
  • offsetToCarrier = 0. The carrier begins at Point A itself, so in this particular configuration CRB 0 and the first resource block of the carrier are the same thing. That is convenient but not typical - when offsetToCarrier is not zero, the two differ, which is the trap described in the RIV section.
  • subcarrierSpacing = kHz30 and carrierBandwidth = 51. So the carrier is 51 resource blocks wide at 30 kHz, i.e, 51 x 12 x 30 kHz = 18.36 MHz - which is the number in the NOTE above, and it agrees with 38.101-1 Table 5.3.2-1 for a 20 MHz channel at 30 kHz spacing. The remaining 1.64 MHz of the 20 MHz channel is guard band.

Step 2 : decode the BWP

The initial downlink BWP carries locationAndBandwidth = 13750. Running it through the three lines from the RIV section, with N fixed at 275 :

    L'  = floor(13750 / 275) + 1  =  50 + 1  =  51
    S'  = 13750 mod 275           =  0

    L' + S' = 51, which is not greater than 275   ->   this came from equation (1)

    L_RBs = 51        RB_start = 0

So the initial DL BWP is 51 resource blocks starting at RB 0 - in other words it covers the entire carrier. And since offsetToCarrier is 0, N(start,BWP) = 0 + 0 = 0, so the BWP begins at Point A as well.

This is worth pausing on as a cross check. The value 13750 is exactly the one in the CBW 20 / 51 RB row of the RIV example table earlier on this page, which was calculated as 275 x (51 - 1) + 0. Two completely different routes - a real configuration from a live system, and a hand calculation from the specification - arrive at the same number.

Step 3 : the CORESET

The CORESET is described by frequencyDomainResources = '111100000...'. This is a 45 bit bitmap in which each bit stands for a group of 6 resource blocks, not for one resource block. Four leading ones therefore mean 4 x 6 = 24 resource blocks, which is the figure written in the picture. In frequency terms that is 24 x 12 x 30 kHz = 8.64 MHz, and with duration 1 it occupies a single OFDM symbol.

Note that 24 resource blocks sit comfortably inside the 51 of the BWP, so the requirement that the initial DL BWP must contain the whole CORESET is satisfied - trivially so here, because the BWP is the whole carrier.

Step 4 : the SSB

absoluteFrequencySSB = 632256 converts the same way as Point A : 3000 + 0.015 x (632256 - 600000) = 3483.84 MHz. The SSB itself is always 20 resource blocks wide, so at 30 kHz it occupies 20 x 12 x 30 kHz = 7.2 MHz.

There is a detail here that catches people out. absoluteFrequencySSB does not point at the bottom edge of the SS block. 38.331 defines the SSB frequency as the position of subcarrier 0 of resource block 10 of the SS block, i.e, the middle of the 20 resource blocks. So to find the bottom edge you have to subtract 10 resource blocks :

    10 RB at 30 kHz   =  10 x 12 x 30 kHz  =  3.6 MHz

    SSB bottom edge   =  3483.84 - 3.6     =  3480.24 MHz

And 3480.24 MHz is Point A exactly. So in this configuration the SS block starts precisely at Common RB 0 and occupies CRB 0 to CRB 19. The same thing can be seen directly in the ARFCN numbers without converting to MHz at all : 632256 - 632016 = 240 raster steps, and 240 x 15 kHz = 3.6 MHz, which is the same 10 resource blocks.

Everything in one table

Item

In the configuration

What it works out to

Point A (CRB 0)

ARFCN 632016

3480.24 MHz

Carrier

offsetToCarrier 0, carrierBandwidth 51, SCS 30 kHz

Starts at Point A, 51 RB = 18.36 MHz inside a 20 MHz channel

Initial DL BWP

locationAndBandwidth 13750

RB_start = 0, 51 RB - the whole carrier

CORESET

frequencyDomainResources '1111 0000 ...', duration 1

4 x 6 = 24 RB = 8.64 MHz, 1 symbol

SSB

ARFCN 632256

Centre 3483.84 MHz, 20 RB = 7.2 MHz, occupying CRB 0 to 19

What this example does and does not show

Two observations are worth taking away from it.

  • This is the simplest possible BWP configuration. The BWP is the whole carrier, it starts at Point A, and it shares the carrier's numerology. Every constraint from earlier on this page is satisfied without anyone having to think about it - the BWP contains the CORESET, it is wider than the SSB, and it is contiguous. A configuration like this is a good baseline to compare more interesting ones against.
  • There is no BWP switching here at all. Look at what is missing from the listing : no downlinkBWP-ToAddModList, no firstActiveDownlinkBWP-Id, no defaultDownlinkBWP-Id, no bwp-InactivityTimer. Only the initial BWP is configured, so this UE will spend its whole connection on BWP #0 and none of the switching machinery described earlier is ever exercised. As mentioned in the Why BWP section, this is a great deal more typical of real deployments than the four BWP examples in the specification.

BWP Switching Operation Examples

The previous section showed what a BWP configuration looks like when it is sitting still. This section shows the configuration being used - real captures of a UE actually moving from one bandwidth part to another.

There are two examples, and between them they cover two of the four switching mechanisms described earlier : Example 1 is a switch triggered by DCI, and Example 2 is a switch triggered by RRC. The other two - the inactivity timer and the MAC entity acting on random access - are not shown here, and they are the harder ones to catch in a log for the reason given below.

Before going into either of them, there is one thing that makes reading a BWP switch in a log different from reading almost any other procedure :

    a BWP switch has no completion message. Nothing is ever sent to confirm that it happened.

There is no equivalent of an RRCReconfigurationComplete here. The UE is not asked to acknowledge the switch, and in the timer based case there is no message in either direction at all. So you cannot find a BWP switch by searching for it - you have to infer it, and that means looking at three separate things and putting them together.

  • The configuration - where the bandwidth parts were defined in the first place, and what their sizes and positions are. Without this the rest of the log cannot be interpreted at all, which is why both examples below start by showing SIB1 and the RRC reconfiguration rather than jumping straight to the switch.
  • The trigger - the thing that ordered the move. How visible this is depends entirely on the mechanism, which is the main practical difference between the two examples. An RRC trigger is an ordinary IE that you can read at a glance ; a DCI trigger is a couple of bits buried inside a downlink control message, and you only see it if your tool decodes DCI.
  • The evidence - the proof that the UE really moved. This is where the physical layer view matters more than the signalling view : after the switch, PDCCH and PDSCH simply start appearing somewhere else in frequency. That change of position is the only direct confirmation that the switch took effect, and it is why Example 1 includes a picture of the channels before and after rather than only the messages.

Keeping those three apart - configuration, trigger, evidence - is the most useful habit when working through these examples, and it is also the practical answer to the question "how do I check in a log whether BWP switching is actually being used in this network ?"

NOTE : If you want to see the contents of full log with Amarisoft Log viewer, go to LogAnalysis section and click on 'Sample Log' in this tutorial of Amarisoft TechAcademy.

Example 1 > BWP Switching by DCI

This is an example from Amari Callbox with a commercial UE showing the BWP switching triggered by DCI.

This example is worth working through slowly, because it is one of the few places where the whole chain can be checked end to end : the BWPs are defined in the RRC messages, the switch is ordered in a DCI, and the effect shows up in the physical layer log. The eight steps below are configuration ([1] and [2]), then before the switch ([3] and [4]), then the switch itself ([5] and [6]), then after the switch ([7] and [8]).

[1] and [2] in the following RRC log is the places where all the BWP is configured.

Following is the sequence of physical channels showing the PDCCH/PDSCH before and after BWP switching.

[1] SIB1

This is the cell level configuration, so it is where BWP #0 comes from. Three values are worth pulling out of it.

Check on this for full message.

  message c1: systemInformationBlockType1: {
    ....
    servingCellConfigCommon {
      downlinkConfigCommon {
        frequencyInfoDL {
          frequencyBandList {
            {
              freqBandIndicatorNR 78
            }
          },
          offsetToPointA 30,
          scs-SpecificCarrierList {
            {
              offsetToCarrier 0,
              subcarrierSpacing kHz30,
              carrierBandwidth 106
            }
          }
        },
        initialDownlinkBWP {    // DL BWP 0
          genericParameters {
            locationAndBandwidth 12928,
            subcarrierSpacing kHz30
          },
....
      },
      uplinkConfigCommon {
        frequencyInfoUL {
          scs-SpecificCarrierList {
            {
              offsetToCarrier 0,
              subcarrierSpacing kHz30,
              carrierBandwidth 106
            }
          }
        },
        initialUplinkBWP {    // UL BWP 0
          genericParameters {
            locationAndBandwidth 12928,
            subcarrierSpacing kHz30
          },
....
}
  • carrierBandwidth 106 at 30 kHz - the carrier is 106 x 12 x 30 kHz = 38.16 MHz, i.e, a 40 MHz channel. And offsetToCarrier 0 means the carrier starts at Point A, so a resource block index from the RIV is directly a CRB index here.
  • locationAndBandwidth 12928 - decoding it with N = 275 : L' = floor(12928/275) + 1 = 48, S' = 12928 - 12925 = 3, and 48 + 3 is not greater than 275, so this came from equation (1). That gives 48 resource blocks starting at RB 3, or 17.28 MHz.

So the initial BWP is not the whole carrier this time - it is a narrow window of 48 out of 106 resource blocks, sitting three resource blocks up from the bottom. That is the normal arrangement : the initial BWP only has to be big enough for CORESET#0 and the SSB. Note also that the uplink uses the same value, so UL BWP 0 is the same 48 resource blocks.

[2] RrcSetup

Now the dedicated configuration arrives and BWP #1 is created.

Check on this for full message.

{
  message c1: rrcSetup: {
    rrc-TransactionIdentifier 0,
    criticalExtensions rrcSetup: {
...
        spCellConfig {
          spCellConfigDedicated {
            initialDownlinkBWP {
...
            downlinkBWP-ToAddModList {
              {
                bwp-Id 1,
                bwp-Common {      // DL BWP 1
                  genericParameters {
                    locationAndBandwidth 28875,
                    subcarrierSpacing kHz30
                  },
...
                bwp-Dedicated {
                  pdcch-Config setup: {
...
                  },
                  pdsch-Config setup: {
...
            },
            firstActiveDownlinkBWP-Id 0,
            uplinkConfig {
              initialUplinkBWP {
                pucch-Config setup: {
..
                  },
...
              },
              uplinkBWP-ToAddModList {
                {
                  bwp-Id 1,
                  bwp-Common {
                    genericParameters {   // UL BWP 1
                      locationAndBandwidth 28875,
                      subcarrierSpacing kHz30
                    },
                    pusch-ConfigCommon setup: {
...
                    },
                    pucch-ConfigCommon setup: {
...
                    }
                  },
                  bwp-Dedicated {
                    pucch-Config setup: {
...
                      },
                      resourceToAddModList {
...
                    },
                    pusch-Config setup: {
...
              },
              firstActiveUplinkBWP-Id 0,
...
            },
....
          }
        }
      }
    }
  }
}
  • locationAndBandwidth 28875 for both DL BWP 1 and UL BWP 1 - decoding again with N = 275 : L' = floor(28875/275) + 1 = 106, S' = 0, so 106 resource blocks starting at RB 0. That is the entire carrier. You will find this exact value in the RIV example table earlier on this page, in the row for 106 RB.
  • firstActiveDownlinkBWP-Id 0 and firstActiveUplinkBWP-Id 0 - and this is the important one. The network has just defined a nice wide BWP 1, and then told the UE to stay on BWP 0 anyway.

That second point is what makes this a DCI example rather than an RRC one. If firstActiveDownlinkBWP-Id had been 1, the UE would have moved to BWP 1 the moment it applied this message and there would have been nothing left to see. Instead the wide BWP is configured but not activated, which is exactly the "configured versus active" distinction from the allocation section. The switch has to come later, from a DCI.

So at this point the UE is running on a 48 RB BWP while a 106 RB BWP sits ready and unused.

[3] PDCCH

From here on we are in the physical layer log, and this is where the switch actually happens. The field to watch in every one of these DCIs is bwp=.

Message: ss_id=2 cce_index=12 al=2 dci=1_1
Data:
    bwp=0
    rb_alloc=0x5f
    time_domain_rsc=0
    mcs1=21
    ndi1=0
    rv_idx1=3
    harq_process=10
    dai=0
    tpc_command=1
    pucch_rsc=0
    harq_feedback_timing=4
    antenna_ports=2
    srs_request=0
    dmrs_seq_init=0

[4] PDSCH

Message: harq=10 prb=3:48 symb=2:12 k1=4 nl=2 CW0: tb_len=8709 mod=8 rv_idx=3 cr=0.69 retx=3

These two lines belong together, and between them they show how a grant is expressed before the switch.

  • The DCI says bwp=0, so the UE is still on the narrow BWP, and rb_alloc=0x5f = 95.
  • That 95 is an RIV again - but this time it is decoded with the size of the active BWP, which is 48, and not with 275. This is the distinction flagged in the RIV section : same formula, different N. With N = 48 : L' = floor(95/48) + 1 = 2, S' = 95 - 48 = 47, and 2 + 47 = 49 which is greater than 48, so this came from equation (2) : L = 48 - 2 + 2 = 48 and RB_start = 48 - 1 - 47 = 0. The whole of BWP 0.
  • Now look at the PDSCH line : prb=3:48, i.e, 48 resource blocks starting at 3. The DCI said "start at 0" and the PDSCH appears at 3. That is not a contradiction - it is the nCRB / nPRB mapping in front of your eyes. n(CRB) = n(PRB) + N(start,BWP) = 0 + 3 = 3. The DCI counts from the start of the BWP ; the physical layer log prints the position in the carrier.

[5] PDCCH

Message: ss_id=2 cce_index=2 al=2 dci=0_1 k2=7
Data:
    bwp=1
    rb_alloc=0x139
    time_domain_rsc=0
    mcs=9
    ndi=1
    rv_idx=0
    harq_process=0
    dai=3
    tpc_command=1
    antenna_ports=0
    srs_request=0
    dmrs_seq_init=0
    ul_sch_indicator=1

Here is the switch, and notice which direction goes first. This is dci=0_1, an uplink grant, and it carries bwp=1. So the uplink is being moved to BWP 1.

rb_alloc=0x139 = 313, and from this DCI onwards it has to be decoded against the new BWP size of 106 : L' = floor(313/106) + 1 = 3, S' = 313 - 212 = 101, and 3 + 101 = 104 which is not greater than 106, so equation (1) applies : 3 resource blocks starting at RB 101. Hold on to that, because it reappears at step [8].

[6] PDCCH

Message: ss_id=4 cce_index=4 al=2 dci=1_1
Data:
    bwp=1
    rb_alloc=0xd3
    time_domain_rsc=0
    mcs1=23
    ndi1=0
    rv_idx1=0
    harq_process=0
    dai=0
    tpc_command=1
    pucch_rsc=0
    harq_feedback_timing=1
    antenna_ports=2
    srs_request=0
    dmrs_seq_init=0

And now the downlink follows : dci=1_1 with bwp=1. Note also that the search space has changed, from ss_id=2 in the earlier DCIs to ss_id=4 - a reminder that the CORESETs and search spaces belong to the BWP, so moving BWP means monitoring a different search space as well.

rb_alloc=0xd3 = 211, decoded with N = 106 : L' = floor(211/106) + 1 = 2, S' = 211 - 106 = 105, and 2 + 105 = 107 which is greater than 106, so equation (2) : L = 106 - 2 + 2 = 106, RB_start = 106 - 1 - 105 = 0. The whole of the new, wide BWP.

[7] PDSCH

Message: harq=0 prb=0:106 symb=2:12 k1=7 nl=2 CW0: tb_len=22026 mod=8 rv_idx=0 cr=0.83 retx=0

[8] PUSCH

Message: harq=0 prb=101:3 symb=0:14 CW0: tb_len=141 mod=4 rv_idx=0 cr=0.61 retx=0 crc=KO snr=-0.4 epre=-124.0 ta=8.8

The last two lines are the evidence that the switch really took effect, and both of them match the DCIs exactly.

  • [7] PDSCH prb=0:106 - 106 resource blocks starting at 0. Compare with [4], where the same UE was getting prb=3:48. The downlink has gone from 48 resource blocks to the full 106, and because BWP 1 starts at CRB 0 the PRB and CRB numbering now coincide.
  • [8] PUSCH prb=101:3 - 3 resource blocks starting at 101, which is exactly what the uplink grant in [5] decoded to. Note that RB 101 does not even exist inside the old BWP 0, which only ran from CRB 3 to CRB 50. This transmission is only possible because the uplink switched.

The whole example on one page

Step

What is in the log

What it means

[1]

locationAndBandwidth 12928

BWP 0 = 48 RB starting at CRB 3, out of a 106 RB carrier. The narrow initial BWP.

[2]

locationAndBandwidth 28875, firstActive...BWP-Id 0

BWP 1 = 106 RB starting at CRB 0 is configured but not activated. The UE stays on BWP 0.

[3][4]

bwp=0, rb_alloc=0x5f -> prb=3:48

Before the switch. All 48 RB of BWP 0, appearing at CRB 3 in the carrier.

[5]

dci=0_1, bwp=1

The uplink switch, carried inside an ordinary UL grant.

[6]

dci=1_1, bwp=1, ss_id=4

The downlink switch, carried inside an ordinary DL assignment, and monitored in a different search space.

[7][8]

prb=0:106 and prb=101:3

After the switch. The full 106 RB in the downlink, and an uplink transmission at a position that did not exist in the old BWP.

Three things are worth taking away from this example.

  • There is no BWP switch message. Steps [5] and [6] are ordinary scheduling DCIs that happen to carry a different bandwidth part indicator. Nothing announces the switch and nothing confirms it, which is the point made in the introduction to this section.
  • The uplink and the downlink switched separately. [5] moved the uplink and [6] moved the downlink, in two different DCIs. In a TDD cell they are paired and end up on the same bwp-Id, but they are still ordered independently.
  • Every number in the log checks against every other number. The RIV in the DCI, the PRB range in the PDSCH line and the BWP definition in the RRC message all agree, provided you decode the DCI RIV with the BWP size and remember to add N(start,BWP) when comparing with the physical layer log. If they do not agree in a log you are working on, one of those two steps is usually the reason.

Example 2 > BWP Switching by RRC

This is an example from Amari Callbox with Amari UEsim

The starting point of this example is exactly the same as Example 1 - the same band, the same 106 resource block carrier, the same two bandwidth parts with the same locationAndBandwidth values. That is what makes the pair useful : the configuration is identical and only the trigger is different. Everything you see differing below is a consequence of the switch being ordered by RRC instead of by a DCI.

[1] SIB1

Following is bwp related parts in SIB1. See this for the whole message.

{
  message c1: systemInformationBlockType1: {
   ...
    servingCellConfigCommon {
      downlinkConfigCommon {
        frequencyInfoDL {
          frequencyBandList {
            {
              freqBandIndicatorNR 78
            }
          },
          offsetToPointA 30,
          scs-SpecificCarrierList {
            {
              offsetToCarrier 0,
              subcarrierSpacing kHz30,
              carrierBandwidth 106
            }
          }
        },
        initialDownlinkBWP {
          genericParameters {
            locationAndBandwidth 12928,
            subcarrierSpacing kHz30
          },
          ...
      uplinkConfigCommon {
        frequencyInfoUL {
          scs-SpecificCarrierList {
            {
              offsetToCarrier 0,
              subcarrierSpacing kHz30,
              carrierBandwidth 106
            }
          }
        },
        initialUplinkBWP {
          genericParameters {
            locationAndBandwidth 12928,
            subcarrierSpacing kHz30
          },
          ...
}

Nothing new here. This is the same cell configuration as in Example 1 : carrierBandwidth 106 at 30 kHz, and locationAndBandwidth 12928 which decodes to 48 resource blocks starting at RB 3. So BWP 0 is again the narrow initial window, in both downlink and uplink.

[2] RrcSetup

Following is bwp related parameters in RrcSetup. See this for the whole message.

{
  message c1: rrcSetup: {
    rrc-TransactionIdentifier 0,
    criticalExtensions rrcSetup: {
      radioBearerConfig {
        ...
        spCellConfig {
          spCellConfigDedicated {
            initialDownlinkBWP {
              ....
            downlinkBWP-ToAddModList {
              {
                bwp-Id 1,
                bwp-Common {
                  genericParameters {
                    locationAndBandwidth 28875,
                    subcarrierSpacing kHz30
                  },
            ....
            firstActiveDownlinkBWP-Id 0,
             ....,
              uplinkBWP-ToAddModList {
                {
                  bwp-Id 1,
                  bwp-Common {
                    genericParameters {
                      locationAndBandwidth 28875,
                      subcarrierSpacing kHz30
                    },
            ....
            firstActiveUplinkBWP-Id 0,
}

Also the same as before. locationAndBandwidth 28875 gives 106 resource blocks starting at RB 0, the whole carrier, and firstActiveDownlinkBWP-Id 0 together with firstActiveUplinkBWP-Id 0 keeps the UE on BWP 0 for the time being.

So once again we arrive at the same situation : a wide BWP 1 configured and waiting, and the UE working in the narrow BWP 0. From here the two examples part company.

[3] RrcReconfiguration

{
  message c1: rrcReconfiguration: {
    rrc-TransactionIdentifier 0,
    criticalExtensions rrcReconfiguration: {
      nonCriticalExtension {
        masterCellGroup {
          cellGroupId 0,
          spCellConfig {
            spCellConfigDedicated {
              firstActiveDownlinkBWP-Id 1,
              uplinkConfig {
                firstActiveUplinkBWP-Id 1
              },
              tag-Id 0
            }
          }
        }
      }
    }
  }
}

This is the switch, and the contrast with Example 1 could hardly be sharper. Look at how little is in this message. There is no BWP being defined, no locationAndBandwidth, no channel configuration - almost the entire RRCReconfiguration consists of two fields :

  • firstActiveDownlinkBWP-Id 1
  • firstActiveUplinkBWP-Id 1

Both were 0 in the RrcSetup and both are now 1. That single change is the whole instruction. The bandwidth parts themselves were already configured back in step [2] and are not touched here at all - the network is simply moving the pointer.

Two things about this are worth noticing.

  • firstActiveDownlinkBWP-Id is being used as a switching command. The name suggests something that only matters at setup, and the field description talks about the BWP to activate when the reconfiguration is applied - but "when the reconfiguration is applied" is exactly what is happening here. Sending a reconfiguration whose only content is a new value of this field is how RRC based BWP switching is done.
  • The downlink and the uplink move together, in one message. Compare that with Example 1, where the uplink needed its own DCI and the downlink another one.

[4] PDCCH @ SFN = 334.3

Message: ss_id=2 cce_index=8 al=2 dci=1_1
Data:
    bwp=0
    rb_alloc=0x2f
    time_domain_rsc=0
    mcs1=9
    ndi1=1
    rv_idx1=0
    harq_process=0
    dai=0
    tpc_command=1
    pucch_rsc=0
    harq_feedback_timing=2
    antenna_ports=2
    srs_request=0
    dmrs_seq_init=0

This is the last downlink assignment before the switch : bwp=0, and it is monitored in ss_id=2.

rb_alloc=0x2f = 47, decoded against the active BWP size of 48 : L' = floor(47/48) + 1 = 1, S' = 47, and 1 + 47 = 48 which is not greater than 48, so equation (1) : 1 resource block starting at RB 47. Since BWP 0 begins at CRB 3, that single resource block is sitting at CRB 50 - the very top edge of the narrow BWP.

[5] PDCCH @ SFN = 360.5

Message: ss_id=4 cce_index=8 al=2 dci=1_1
Data:
    bwp=1
    rb_alloc=0x0
    time_domain_rsc=0
    mcs1=9
    ndi1=1
    rv_idx1=0
    harq_process=0
    dai=0
    tpc_command=1
    pucch_rsc=0
    harq_feedback_timing=4
    antenna_ports=2
    srs_request=0
    dmrs_seq_init=0

And this is the first assignment after the switch : bwp=1, and the search space has changed to ss_id=4, exactly as it did in Example 1 - the CORESETs and search spaces belong to the bandwidth part, so moving BWP means monitoring somewhere else.

rb_alloc=0x0 decodes trivially with N = 106 : L' = 1, S' = 0, giving 1 resource block starting at RB 0, which is CRB 0 because BWP 1 starts at the bottom of the carrier. So the UE has moved from CRB 50 to CRB 0 - two allocations of the same size, in two completely different places, and the only thing that changed in between was the value of a pointer in an RRC message.

NOTE : The two timestamps are worth a comment. SFN 334.3 means system frame 334, slot 3, and SFN 360.5 is frame 360, slot 5 - about 261 ms apart. It is tempting to read that as the cost of the switch, but it is not. This capture comes from a UE simulator with very little traffic, so the gap is mostly just the time until the next thing needed to be scheduled. The actual switching delay is the few slots described in BWP Switching Delay.

Example 1 and Example 2 side by side

Since the two examples start from an identical configuration, putting them next to each other isolates exactly what the choice of trigger changes.

 

Example 1 - by DCI

Example 2 - by RRC

What carries the switch

The bandwidth part indicator inside an ordinary scheduling DCI

An RRCReconfiguration containing little more than firstActive...BWP-Id

How visible it is in a log

Hard - a couple of bits, only visible if your tool decodes DCI

Easy - a named IE you can read at a glance

DL and UL

Ordered separately, one DCI each ([5] and [6])

Both in the same message

Speed

Fast - a few slots, no signalling round trip

Slow - a full RRC procedure

Typical use

Everyday traffic adaptation

At (re)configuration time, or when the BWP set itself changes

One qualification to something said in the introduction to this section. It was stated there that a BWP switch is never confirmed - and for the DCI and timer cases that is completely true. The RRC case is the partial exception : there is still no BWP specific confirmation, but the reconfiguration itself is an acknowledged procedure, so the RRCReconfigurationComplete that follows does at least tell you that the UE received and applied the message containing the new pointer. That is one more reason RRC based switching is the easier of the two to debug, even though it is far too slow to be the everyday mechanism.

Reference

[1] NR Wide Bandwidth Operations by Jeongho Jeon, Intel Corporation  

[2] Impact of Bandwidth Part (BWP) Switching on 5G NR System Performance (Fuad Abinader et al, IEEE)

[3] A Primer on Bandwidth Parts in 5G New Radio

[4] 5G NR BWP Types and BWP Operations

YouTube

[1] BandWidth Part (BWP): A 5G feature for improving spectrum flexibility and power savings

[2] 5G Course - 5G Bandwidth Parts (5G Initial BWP Active BWP Default BWP)